~zhangew401/yelp-scope/yelp-api-v3

« back to all changes in this revision

Viewing changes to src/yelp.go

  • Committer: Zhang Enwei
  • Date: 2016-06-02 22:44:42 UTC
  • Revision ID: enwei.zhang@canonical.com-20160602224442-e67l2xlqhav8fcdd
yelp api v3

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
import "C"
22
22
 
23
23
import (
24
 
        "encoding/json"
25
 
        "errors"
26
 
        "fmt"
27
 
        "io/ioutil"
28
 
        "log"
29
 
        "net/http"
30
 
        "net/url"
31
 
        "os"
32
 
        "sort"
33
 
        "strconv"
34
 
        "strings"
35
 
 
36
 
        "github.com/NOX73/go-oauth"
37
 
        "github.com/gosexy/gettext"
38
 
        "github.com/kellydunn/golang-geo"
39
 
        "launchpad.net/go-unityscopes/v2"
 
24
        "bytes"
 
25
        "encoding/json"
 
26
        "errors"
 
27
        "fmt"
 
28
        "io/ioutil"
 
29
        "log"
 
30
        "net/http"
 
31
        "net/url"
 
32
        "os"
 
33
        "strconv"
 
34
        "strings"
 
35
        "github.com/gosexy/gettext"
 
36
        "github.com/kellydunn/golang-geo"
 
37
        "launchpad.net/go-unityscopes/v2"
40
38
)
41
39
 
42
 
//      "github.com/NOX73/go-oauth"
43
 
//"launchpad.net/go-unityscopes/v2"
44
 
 
45
 
const searchCategoryTemplate = `{
46
 
  "schema-version": 1,
47
 
  "template": {
48
 
    "category-layout": "grid",
49
 
    "card-size": "medium",
50
 
    "collapsed-rows": 0
51
 
  },
52
 
  "components": {
53
 
    "title": "title",
54
 
    "art":  "art",
55
 
    "subtitle": "address",
56
 
    "attributes": "attributes"
57
 
  }
58
 
}`
59
 
 
60
 
const searchCategoryTemplate2 = `{
61
 
  "schema-version": 1,
62
 
  "template": {
63
 
    "category-layout": "grid",
64
 
    "card-size": "large",
65
 
    "card-layout": "horizontal",
66
 
    "collapsed-rows": 0
67
 
  },
68
 
  "components": {
69
 
    "title": "title",
70
 
    "mascot":  "art",
71
 
    "subtitle": "address",
72
 
    "attributes": "attributes"
73
 
  }
74
 
}`
75
 
 
76
40
const errorTemplate = `{
77
 
  "schema-version": 1,
78
 
  "template": {
79
 
    "category-layout": "grid",
80
 
    "card-size": "large",
81
 
    "card-layout": "horizontal",
82
 
    "collapsed-rows": 0
83
 
  },
84
 
  "components": {
85
 
    "title": "title",
86
 
    "subtitle": "subtitle"
87
 
  }
 
41
        "schema-version": 1,
 
42
        "template": {
 
43
                "category-layout": "grid",
 
44
                "card-size": "large",
 
45
                "card-layout": "horizontal",
 
46
                "collapsed-rows": 0
 
47
        },
 
48
        "components": {
 
49
                "title": "title",
 
50
                "subtitle": "subtitle"
 
51
        }
88
52
}`
89
53
 
 
54
type PriceFilter struct {
 
55
        using   bool //whether this is/is not an active filter
 
56
        unknown bool //include businesses that do not state a price range
 
57
        one     bool //inexpensive
 
58
        two     bool //moderate
 
59
        three   bool //pricey
 
60
        four    bool ///ultra high end
 
61
}
 
62
 
90
63
type YelpScope struct {
91
 
        BaseURI        string
92
 
        ConsumerKey    string
93
 
        Token          string
94
 
        ConsumerSecret string
95
 
        TokenSecret    string
96
 
        Dir            string
97
 
        Layout         string
98
 
        Settings       map[string]int
99
 
        Base           *scopes.ScopeBase
 
64
        BaseURI        string
 
65
        ClientId       string
 
66
        AccessToken    string
 
67
        ClientSecret   string
 
68
        Dir            string
 
69
        Layout         string
 
70
        Settings       map[string]int
 
71
        Base           *scopes.ScopeBase
100
72
}
101
73
 
102
74
type actionInfo struct {
103
 
        Id    string `json:"id"`
104
 
        Label string `json:"label"`
105
 
        Icon  string `json:"icon,omitempty"`
106
 
        Uri   string `json:"uri,omitempty"`
 
75
        Id    string `json:"id"`
 
76
        Label string `json:"label"`
 
77
        Icon  string `json:"icon,omitempty"`
 
78
        Uri   string `json:"uri,omitempty"`
107
79
}
108
80
 
109
81
type ratingInfo struct {
110
 
        Ratingiconempty string
111
 
        Ratingiconhalf  string
112
 
        Ratingiconfull  string
113
 
        reviews         []reviewInfo
 
82
        Ratingiconempty string
 
83
        Ratingiconhalf  string
 
84
        Ratingiconfull  string
 
85
        reviews         []reviewInfo
114
86
}
115
87
 
116
88
type reviewInfo struct {
117
 
        Rating float32 `json:"rating"`
118
 
        Author string  `json:"author"`
119
 
        Review string  `json:"review,omitempty"`
 
89
        Rating float32 `json:"rating"`
 
90
        Author string  `json:"author"`
 
91
        Review string  `json:"review,omitempty"`
120
92
}
121
93
 
122
94
type attributeInfo struct {
123
 
        Value string `json:"value,omitempty"`
124
 
        Icon  string `json:"icon,omitempty"`
 
95
        Value string `json:"value,omitempty"`
 
96
        Icon  string `json:"icon,omitempty"`
125
97
}
126
98
type location struct {
127
 
        Display_address []string `json:"display_address"`
128
 
        Coord           coord    `json:"coordinate"`
 
99
        City     string    `json:"city"`
 
100
        Country  string    `json:"country"`
 
101
        Address1 string    `json:"address1"`
 
102
        Address2 string    `json:"address2"`
 
103
        Address3 string    `json:"address3"`
 
104
        State    string    `json:"state"`
 
105
        Zip      string    `json:"zip_code"`
129
106
}
130
107
 
131
108
type coord struct {
132
 
        Latitude  float64 `json:"latitude"`
133
 
        Longitude float64 `json:"longitude"`
 
109
        Latitude  float64 `json:"latitude"`
 
110
        Longitude float64 `json:"longitude"`
 
111
}
 
112
 
 
113
type category struct {
 
114
        Alias  string `json:"alias"`
 
115
        Title  string `json:"title"`
134
116
}
135
117
 
136
118
type place struct {
137
 
        Name                  string     `json:"name"`
138
 
        Image_url             string     `json:"image_url"`
139
 
        Location              location   `json:"location"`
140
 
        Phone                 string     `json:"phone"`
141
 
        Rating                float32    `json:"rating"`
142
 
        Url                   string     `json:"mobile_url"`
143
 
        ID                    string     `json:"id"`
144
 
        RatingIcon            string     `json:"rating_img_url_large"`
145
 
        Cats                  [][]string `json:"categories"`
146
 
        ReviewCount           int        `json:"review_count"`
147
 
        RestaurantsPriceRange int        `json:"RestaurantsPriceRange2"`
148
 
        IsClosed              bool       `json:"is_closed"`
149
 
        Hours                 []string   `json:"hours"`
150
 
}
151
 
 
152
 
type cats struct {
153
 
        Cats []string
 
119
        Name                  string     `json:"name"`
 
120
        Location              coord      `json:"coordinates"`
 
121
        Rating                float32    `json:"rating"`
 
122
        Id                    string     `json:"id"`
 
123
        Cats                  []category `json:"categories"`
 
124
        ReviewCount           int        `json:"review_count"`
 
125
        Url                   string     `json:"url"`
154
126
}
155
127
 
156
128
type deptlist struct {
157
 
        Depts []dept `json:"data"`
 
129
        Depts []dept `json:"data"`
158
130
}
159
131
type dept struct {
160
 
        Name  string `json:"_name"`
161
 
        Label string `json:"label"`
162
 
        Subs  []dept `json:"subdepartments"`
 
132
        Name  string `json:"_name"`
 
133
        Label string `json:"label"`
 
134
        Subs  []dept `json:"subdepartments"`
163
135
}
164
136
 
165
137
type yelpError struct {
166
 
        Text string `json:"text"`
 
138
        Text string `json:"text"`
167
139
}
168
140
 
169
141
type yelpAnswer struct {
170
 
        Businesses []place   `json:"businesses"`
171
 
        Error      yelpError `json:"error"`
172
 
}
173
 
 
174
 
func (yl *YelpScope) buildUrl(params map[string]string) string {
175
 
        query := make(url.Values)
176
 
        for key, value := range params {
177
 
                query.Set(key, value)
178
 
        }
179
 
        return yl.BaseURI + query.Encode()
180
 
}
181
 
 
182
 
func (yl *YelpScope) get(params map[string]string, result interface{}) error {
183
 
        credentials := oauth.NewCredentials(yl.ConsumerKey, yl.Token, yl.ConsumerSecret, yl.TokenSecret)
184
 
        var client http.Client
185
 
        var method string = "GET"
186
 
        var url string = yl.buildUrl(params)
187
 
        req, _ := oauth.NewRequest(method, url, params, credentials)
188
 
 
189
 
        resp, _ := client.Do(req.HttpRequest())
190
 
        defer resp.Body.Close()
191
 
        decoder := json.NewDecoder(resp.Body)
192
 
        return decoder.Decode(result)
193
 
 
 
142
        Businesses []place   `json:"businesses"`
 
143
        Count      int64     `json:"total"`
 
144
}
 
145
 
 
146
type tokenResult struct {
 
147
        AccessToken string `json:"access_token"`
 
148
        TokenType   string `json:"token_type"`
 
149
        ExpiresIn   int64  `json:"expries_in"`
 
150
}
 
151
 
 
152
type business struct {
 
153
        ImageUrl   string   `json:"image_url"`
 
154
        Url        string   `json:"url"`
 
155
        Phone      string   `json:"phone"`
 
156
        Photos     []string `json:"photos"`
 
157
        Location   location `json:"location"`
 
158
 
 
159
}
 
160
 
 
161
type reviews struct {
 
162
        Reviews []review   `json:"reviews"`
 
163
}
 
164
 
 
165
type review struct {
 
166
        Url        string   `json:"url"`
 
167
        Text       string   `json:"text"`
 
168
        Rating     float32  `json:"rating"`
 
169
}
 
170
 
 
171
func (yl *YelpScope) buildUrl(params map[string]string, endpoint string) string {
 
172
        query := make(url.Values)
 
173
        for key, value := range params {
 
174
                query.Set(key, value)
 
175
        }
 
176
        return yl.BaseURI + endpoint + query.Encode()
 
177
}
 
178
 
 
179
func (yl *YelpScope) get(params map[string]string, endpoint string, result interface{}) error {
 
180
        var client http.Client
 
181
        var method string = "GET"
 
182
        var url string = yl.buildUrl(params, endpoint)
 
183
        log.Println("YELP scope uri:", url)
 
184
        req, _ := http.NewRequest(method, url, nil)
 
185
        log.Println("YELP enweitoken1:", strings.TrimSpace(yl.AccessToken))
 
186
        if len(strings.TrimSpace(yl.AccessToken)) == 0 {
 
187
                yl.getAccessToken()
 
188
        }
 
189
        log.Println("YELP enweitoken2:", yl.AccessToken)
 
190
        req.Header.Add("Authorization", "Bearer "+yl.AccessToken)
 
191
        resp, _ := client.Do(req)
 
192
        defer resp.Body.Close()
 
193
        decoder := json.NewDecoder(resp.Body)
 
194
        return decoder.Decode(result)
 
195
}
 
196
 
 
197
func (yl *YelpScope) getAccessToken() error {
 
198
        var client http.Client
 
199
        param := map[string]string{"grant_type": "client_credentials", "client_id": yl.ClientId, "client_secret": yl.ClientSecret}
 
200
        query := make(url.Values)
 
201
        for key, value := range param {
 
202
                query.Set(key, value)
 
203
        }
 
204
        req_body := bytes.NewBufferString(query.Encode())
 
205
        req, _ := http.NewRequest("POST", "https://api.yelp.com/oauth2/token", req_body)
 
206
        req.Header.Add("content-type", "application/x-www-form-urlencoded;charset=UTF-8")
 
207
        resp, err := client.Do(req)
 
208
        defer resp.Body.Close()
 
209
        if (err != nil) {
 
210
                log.Println("YELP scope getAccessToken error", err.Error())
 
211
                return err
 
212
        }
 
213
        var result tokenResult
 
214
        bodyBytes, err2 := ioutil.ReadAll(resp.Body)
 
215
        if err2 != nil {
 
216
                return err2
 
217
        }
 
218
        json.Unmarshal(bodyBytes, &result)
 
219
        yl.AccessToken = result.AccessToken
 
220
        return nil
194
221
}
195
222
 
196
223
func (yl *YelpScope) getDepts(result interface{}) error {
197
 
        deptfile, _ := os.Open(yl.Dir + "/depts.json")
198
 
        decoder := json.NewDecoder(deptfile)
199
 
        return decoder.Decode(result)
 
224
        deptfile, _ := os.Open(yl.Dir + "/depts.json")
 
225
        decoder := json.NewDecoder(deptfile)
 
226
        return decoder.Decode(result)
200
227
}
201
228
 
202
229
func (yl *YelpScope) getLayout() string {
203
 
        layoutfile, _ := ioutil.ReadFile(yl.Dir + "/layout.json")
204
 
        return string(layoutfile)
 
230
        layoutfile, _ := ioutil.ReadFile(yl.Dir + "/layout.json")
 
231
        return string(layoutfile)
205
232
}
206
233
 
207
234
func (yl *YelpScope) SetScopeBase(base *scopes.ScopeBase) {
208
 
        yl.Base = base
209
 
        if base != nil {
210
 
                gettext.SetLocale(gettext.LC_ALL, "")
211
 
                gettext.SetLocale(gettext.LC_NUMERIC, "C")
212
 
                gettext.BindTextdomain("yelp", yl.Base.ScopeDirectory()+"/locale/")
213
 
                gettext.Textdomain("yelp")
214
 
        }
 
235
        yl.Base = base
 
236
        if base != nil {
 
237
                gettext.SetLocale(gettext.LC_ALL, "")
 
238
                gettext.SetLocale(gettext.LC_NUMERIC, "C")
 
239
                gettext.BindTextdomain("yelp", yl.Base.ScopeDirectory()+"/locale/")
 
240
                gettext.Textdomain("yelp")
 
241
        }
215
242
}
216
243
 
217
244
func KmtoMi(km float64) float64 {
218
 
        return km * 0.621371
219
 
}
220
 
 
221
 
type RatingFilter struct {
222
 
        using     bool //whether this is/is not an active filter
223
 
        one       bool
224
 
        oneFive   bool
225
 
        two       bool
226
 
        twoFive   bool
227
 
        three     bool
228
 
        threeFive bool
229
 
        four      bool
230
 
        fourFive  bool
231
 
        five      bool
232
 
        fiveFive  bool
233
 
}
234
 
type PriceFilter struct {
235
 
        using   bool //whether this is/is not an active filter
236
 
        unknown bool //include businesses that do not state a price range
237
 
        one     bool //inexpensive
238
 
        two     bool //moderate
239
 
        three   bool //pricey
240
 
        four    bool ///ultra high end
 
245
        return km * 0.621371
241
246
}
242
247
 
243
248
func (yl *YelpScope) Search(q *scopes.CannedQuery, metadata *scopes.SearchMetadata, reply *scopes.SearchReply, cancelled <-chan bool) error {
244
 
        query := q.QueryString()
245
 
        loc := metadata.Location()
246
 
 
247
 
        locale := metadata.Locale()
248
 
        langstring := strings.Split(locale, "_")
249
 
        distunit := "km"
250
 
        if langstring[1] == "US" {
251
 
                distunit = "mi"
252
 
        }
253
 
        minDistanceLabel := "0 km"
254
 
        var maxDistance float64
255
 
        maxDistance = 30 //km
256
 
        var maxDistanceLabel string
257
 
        maxDistanceLabel = "30 km"
258
 
        if distunit == "mi" {
259
 
                minDistanceLabel = "0 mi"
260
 
                maxDistance = 20
261
 
                maxDistanceLabel = "20 mi"
262
 
        }
263
 
 
264
 
        var numResultsDefault float64
265
 
        numResultsDefault = 40
266
 
        numResultsFilter := scopes.NewValueSliderFilter("sliderResults", 10, 300, numResultsDefault,
267
 
                scopes.ValueSliderLabels{
268
 
                        MinLabel:    "10",
269
 
                        MaxLabel:    "300",
270
 
                        ExtraLabels: nil,
271
 
                })
272
 
        //Translators: This is the maximum number of Yelp results to display
273
 
        numResultsFilter.Title = gettext.Gettext("Max results")
274
 
 
275
 
        // distances in code always use km.
276
 
        // slider gui uses mi (miles) in US
277
 
        // When in US, the slider value is coverted to km on retrieval
278
 
        var distanceDefault float64
279
 
        distanceDefault = 5
280
 
        distanceFilter := scopes.NewValueSliderFilter("distance", 0, maxDistance, distanceDefault,
281
 
                scopes.ValueSliderLabels{
282
 
                        MinLabel:    minDistanceLabel,
283
 
                        MaxLabel:    maxDistanceLabel,
284
 
                        ExtraLabels: nil,
285
 
                })
286
 
        distanceFilter.Title = gettext.Gettext("Distance")
287
 
 
288
 
        curSymb := C.GoString(C.localeconv().currency_symbol)
289
 
        priceOneLabel := curSymb
290
 
        priceTwoLabel := curSymb + curSymb
291
 
        priceThreeLabel := curSymb + curSymb + curSymb
292
 
        priceFourLabel := curSymb + curSymb + curSymb + curSymb
293
 
 
294
 
        filterState := q.FilterState()
295
 
 
296
 
        var ratingDefault float64
297
 
        ratingDefault = 0
298
 
        ratingFilter := scopes.NewValueSliderFilter("rating", 0, 5, ratingDefault,
299
 
                scopes.ValueSliderLabels{
300
 
                        MinLabel:    "0",
301
 
                        MaxLabel:    "5",
302
 
                        ExtraLabels: nil,
303
 
                })
304
 
        ratingFilter.Title = gettext.Gettext("Lowest rating")
305
 
 
306
 
        priceFilter := scopes.NewOptionSelectorFilter("priceFilter", gettext.Gettext("Price range"), true)
307
 
        priceFilter.AddOption("onePrice", priceOneLabel, false)
308
 
        priceFilter.AddOption("twoPrice", priceTwoLabel, false)
309
 
        priceFilter.AddOption("threePrice", priceThreeLabel, false)
310
 
        priceFilter.AddOption("fourPrice", priceFourLabel, false)
311
 
 
312
 
        //chnage to Switch filter when it moves from experimental namespace
313
 
        openFilter := scopes.NewOptionSelectorFilter("openFilter", gettext.Gettext("Open"), false)
314
 
        openFilter.AddOption("isOpen", gettext.Gettext("Is open"), false)
315
 
 
316
 
        filters := []scopes.Filter{priceFilter, ratingFilter, openFilter, distanceFilter, numResultsFilter}
317
 
 
318
 
        errP := reply.PushFilters(filters, q.FilterState())
319
 
        if errP != nil {
320
 
                return errors.New("yelp scope: cannot push filters. Error: " + errP.Error())
321
 
        }
322
 
 
323
 
        //chnage to Switch filter when it moves from experimental namespace
324
 
        //currentOpenFilter := openFilter.IsOn(filterState)
325
 
        currentOpenFilter := false
326
 
        if openFilter.HasActiveOption(filterState) {
327
 
                for _, option := range openFilter.ActiveOptions(filterState) {
328
 
                        if option == "isOpen" {
329
 
                                currentOpenFilter = true
330
 
                        }
331
 
                }
332
 
        }
333
 
        var currentPriceFilter PriceFilter
334
 
        currentPriceFilter.using = false
335
 
        if priceFilter.HasActiveOption(filterState) {
336
 
                for _, option := range priceFilter.ActiveOptions(filterState) {
337
 
                        switch option {
338
 
                        case "unknown":
339
 
                                currentPriceFilter.unknown = true
340
 
                                currentPriceFilter.using = true
341
 
                        case "onePrice":
342
 
                                currentPriceFilter.one = true
343
 
                                currentPriceFilter.using = true
344
 
                        case "twoPrice":
345
 
                                currentPriceFilter.two = true
346
 
                                currentPriceFilter.using = true
347
 
                        case "threePrice":
348
 
                                currentPriceFilter.three = true
349
 
                                currentPriceFilter.using = true
350
 
                        case "fourPrice":
351
 
                                currentPriceFilter.four = true
352
 
                                currentPriceFilter.using = true
353
 
                        }
354
 
                }
355
 
        }
356
 
 
357
 
        //setup locale, scope directory, layout, distance units, etc
358
 
        yl.Dir = yl.Base.ScopeDirectory()
359
 
        yl.Layout = yl.getLayout()
360
 
 
361
 
        //get all the departments setup
362
 
        rootDept, err := scopes.NewDepartment("", q, gettext.Gettext("Everything"))
363
 
        if err != nil {
364
 
                return err
365
 
        }
366
 
        var deptlist1 deptlist
367
 
        err = yl.getDepts(&deptlist1)
368
 
        for _, v := range deptlist1.Depts {
369
 
                newdept, _ := scopes.NewDepartment(v.Label, q, gettext.Gettext(v.Name))
370
 
                rootDept.AddSubdepartment(newdept)
371
 
                if len(v.Subs) != 0 {
372
 
                        for _, s := range v.Subs {
373
 
                                newdept2, _ := scopes.NewDepartment(s.Label, q, gettext.Gettext(s.Name))
374
 
                                newdept.AddSubdepartment(newdept2)
375
 
                        }
376
 
                }
377
 
        }
378
 
        reply.RegisterDepartments(rootDept)
379
 
 
380
 
        numResults_f := numResultsFilter.Value(filterState)
381
 
 
382
 
        //log.Printf("==== Yelp. num reuslts value: %v\n", numResults_f)
383
 
 
384
 
        //log.Printf("=== YELP. num results: %v\n", numResults_f)
385
 
        // determine number of times to call yelp api to get the number of results we want
386
 
        numResults := int(numResults_f)
387
 
        var iters_f float64
388
 
        var iters int
389
 
        iters_f = numResults_f / 20
390
 
        iters_s := strconv.FormatFloat(iters_f, 'f', 1, 64)
391
 
        parts := strings.Split(iters_s, ".")
392
 
        iters, _ = strconv.Atoi(parts[0])
393
 
        itersDec, _ := strconv.Atoi(parts[1])
394
 
        if itersDec > 0 {
395
 
                iters++
396
 
        }
397
 
 
398
 
        var answers yelpAnswer
399
 
 
400
 
        //if loc is nil, there's nothing we can search for
401
 
        if loc != nil {
402
 
                ll := fmt.Sprintf("%v,%v", loc.Latitude, loc.Longitude)
403
 
                remainingResults := numResults
404
 
                offset := 0
405
 
                for i := 0; i < iters; i++ {
406
 
                        var response yelpAnswer
407
 
                        offset = i * 20
408
 
                        offset_s := strconv.Itoa(offset)
409
 
                        limit := "20"
410
 
                        if remainingResults < 20 {
411
 
                                limit = strconv.Itoa(remainingResults)
412
 
                        }
413
 
                        queryParams := map[string]string{"ll": ll, "cc": langstring[1], "lang": langstring[0], "limit": limit, "offset": offset_s}
414
 
                        if len(q.DepartmentID()) > 0 {
415
 
                                queryParams["category_filter"] = q.DepartmentID()
416
 
                        }
417
 
                        if len(query) > 0 {
418
 
                                queryParams["term"] = query
419
 
                        }
420
 
                        // call to the web api
421
 
                        if err := yl.get(queryParams, &response); err != nil {
422
 
                                return err
423
 
                        }
424
 
                        if response.Error.Text != "" {
425
 
                                log.Println(response.Error.Text)
426
 
                        }
427
 
                        remainingResults = remainingResults - 20
428
 
                        answers.Businesses = append(answers.Businesses, response.Businesses...)
429
 
                }
430
 
 
431
 
                //sort answers into answersByDistanceName
432
 
                //var keys []string
433
 
                var distanceKeys []float64
434
 
                var places map[float64]map[string]place // distance key, names string
435
 
                places = make(map[float64]map[string]place)
436
 
                point1 := geo.NewPoint(loc.Latitude, loc.Longitude)
437
 
                for _, p := range answers.Businesses {
438
 
                        //get distance
439
 
                        var dist float64
440
 
                        if p.Location.Coord.Latitude != 0 && p.Location.Coord.Longitude != 0 {
441
 
                                point2 := geo.NewPoint(p.Location.Coord.Latitude, p.Location.Coord.Longitude)
442
 
                                dist = point1.GreatCircleDistance(point2)
443
 
                        }
444
 
                        if distunit == "mi" {
445
 
                                dist = KmtoMi(dist)
446
 
                        }
447
 
                        //dist_s := strconv.FormatFloat(dist, 'f', 2, 64)
448
 
                        //key := dist_s + "_" + place.Name
449
 
 
450
 
                        if _, ok := places[dist]; !ok {
451
 
                                places[dist] = make(map[string]place)
452
 
                                distanceKeys = append(distanceKeys, dist)
453
 
                        }
454
 
                        places[dist][p.Name] = p
455
 
 
456
 
                }
457
 
                sort.Float64s(distanceKeys)
458
 
 
459
 
                //create new category with no title
460
 
                cat := reply.RegisterCategory("places", "", "", yl.Layout)
461
 
                if query != "" {
462
 
                        //This block creates a category with a title containing the number of results
463
 
                        length := len(answers.Businesses)
464
 
                        lenstring := fmt.Sprintf("%v results from Yelp", length)
465
 
                        cat = reply.RegisterCategory("places_with_len", lenstring, lenstring, yl.Layout)
466
 
                }
467
 
 
468
 
                rating := ratingFilter.Value(filterState)
469
 
 
470
 
                //log.Printf("=== Yelp rating filter value: %v\n", rating)
471
 
                distanceD := distanceFilter.Value(filterState)
472
 
 
473
 
                //log.Printf("=== Yelp distance filter value: %v\n", distanceD)
474
 
                if distunit == "mi" {
475
 
                        distanceD = distanceD * 1.60934
476
 
                }
477
 
                //log.Printf("=== Yelp distance after conversion: %v\n", distanceD)
478
 
 
479
 
                pushed := 0
480
 
                excludedRating := 0
481
 
                excludedPrice := 0
482
 
                excludedDistance := 0
483
 
                excludedOpen := 0
484
 
                for _, key := range distanceKeys {
485
 
                        for _, place := range places[key] {
486
 
 
487
 
                                //log.Printf("=== YELP res. idx: %v name: %q is_closed: %v, distance filter: %v\n", idx, place.Name, place.IsClosed, distanceD)
488
 
 
489
 
                                //if distance greater than sliderFilter value, don't show
490
 
                                if place.Rating < float32(rating) {
491
 
                                        excludedRating++
492
 
                                        //log.Printf("=== YELP. EXCLUDED by place distance: %v, \n", distKm)
493
 
                                        continue
494
 
                                }
495
 
                                // don't show results for business that are closed when user filters by Open
496
 
                                if currentOpenFilter {
497
 
                                        if place.IsClosed {
498
 
                                                //log.Printf("=== YELP. EXCLUDED by IsClosed. name: %v", place.Name)
499
 
                                                excludedOpen++
500
 
                                                continue
501
 
                                        }
502
 
                                }
503
 
 
504
 
                                result := scopes.NewCategorisedResult(cat)
505
 
                                //add price to result if not 0 (unknown)
506
 
                                switch place.RestaurantsPriceRange {
507
 
                                case 1:
508
 
                                        result.Set("price", curSymb)
509
 
                                case 2:
510
 
                                        result.Set("price", curSymb+curSymb)
511
 
                                case 3:
512
 
                                        result.Set("price", curSymb+curSymb+curSymb)
513
 
                                case 4:
514
 
                                        result.Set("price", curSymb+curSymb+curSymb+curSymb)
515
 
                                }
516
 
 
517
 
                                //if price option filter(s), continue if no match
518
 
                                if currentPriceFilter.using {
519
 
                                        showResult := false
520
 
                                        switch place.RestaurantsPriceRange {
521
 
                                        case 0: // indicates the business has no stated price range
522
 
                                                if currentPriceFilter.unknown {
523
 
                                                        showResult = true
524
 
                                                }
525
 
                                        case 1:
526
 
                                                if currentPriceFilter.one {
527
 
                                                        showResult = true
528
 
                                                }
529
 
                                        case 2:
530
 
                                                if currentPriceFilter.two {
531
 
                                                        showResult = true
532
 
                                                }
533
 
                                        case 3:
534
 
                                                if currentPriceFilter.three {
535
 
                                                        showResult = true
536
 
                                                }
537
 
                                        case 4:
538
 
                                                if currentPriceFilter.four {
539
 
                                                        showResult = true
540
 
                                                }
541
 
                                        }
542
 
                                        if !showResult {
543
 
                                                excludedPrice++
544
 
                                                //log.Printf("=== YELP. EXCLUDED by price. name: %v", place.Name)
545
 
                                                continue
546
 
                                        }
547
 
                                }
548
 
 
549
 
                                result.SetURI(place.Url)
550
 
                                //setup a point object of where we are
551
 
                                point1 := geo.NewPoint(loc.Latitude, loc.Longitude)
552
 
                                //and a point object of where the business is, iff yelp doesn't pass us 0,0
553
 
                                var distKm float64
554
 
                                dist2 := ""
555
 
                                if place.Location.Coord.Latitude != 0 && place.Location.Coord.Longitude != 0 {
556
 
                                        point2 := geo.NewPoint(place.Location.Coord.Latitude, place.Location.Coord.Longitude)
557
 
                                        distKm = point1.GreatCircleDistance(point2)
558
 
                                        if distunit == "mi" {
559
 
                                                dist2 = fmt.Sprintf("%.2f %v", KmtoMi(distKm), distunit)
560
 
                                        } else {
561
 
                                                dist2 = fmt.Sprintf("%.2f %v", distKm, distunit)
562
 
                                        }
563
 
                                }
564
 
                                //log.Printf("=== YELP. distance place: %v, filter km: %v\n", distKm, distanceD)
565
 
 
566
 
                                //if distance greater than sliderFilter value, don't show
567
 
                                if distKm > distanceD {
568
 
                                        excludedDistance++
569
 
                                        //log.Printf("=== YELP. EXCLUDED by place distance: %v, \n", distKm)
570
 
                                        continue
571
 
                                }
572
 
                                priceLabel := ""
573
 
                                switch place.RestaurantsPriceRange {
574
 
                                case 1:
575
 
                                        priceLabel = ", " + priceOneLabel
576
 
                                case 2:
577
 
                                        priceLabel = ", " + priceTwoLabel
578
 
                                case 3:
579
 
                                        priceLabel = ", " + priceThreeLabel
580
 
                                case 4:
581
 
                                        priceLabel = ", " + priceFourLabel
582
 
                                }
583
 
                                attr := dist2 + priceLabel
584
 
                                atts := []attributeInfo{
585
 
                                        attributeInfo{Value: attr},
586
 
                                        attributeInfo{Value: fmt.Sprintf("(%v)", place.ReviewCount), Icon: place.RatingIcon},
587
 
                                }
588
 
 
589
 
                                result.Set("attributes", atts)
590
 
                                result.Set("summary", dist2)
591
 
                                result.SetTitle(place.Name)
592
 
                                if place.Image_url == "" {
593
 
                                        result.SetArt(yl.Dir + "/images/yelp.png")
594
 
                                } else {
595
 
                                        // replacing the ms with ls gives a higher resolution picture
596
 
                                        result.SetArt(strings.Replace(place.Image_url, "ms.jpg", "o.jpg", 1))
597
 
                                }
598
 
                                var catstringlist []string
599
 
                                for _, thecat := range place.Cats {
600
 
                                        catstringlist = append(catstringlist, thecat[0])
601
 
                                }
602
 
                                catstring := strings.Join(catstringlist, ", ")
603
 
                                result.Set("rate", place.Rating)
604
 
                                result.Set("address", catstring)
605
 
                                result.Set("phone", place.Phone)
606
 
                                result.Set("streetaddress1", place.Location.Display_address[0])
607
 
                                addstring := strings.Join(place.Location.Display_address[1:], " ")
608
 
                                result.Set("streetaddress2", addstring)
609
 
                                baseurl := fmt.Sprintf("http://m.here.com/#action=search&params={\"query\":\"%v %v\"}", place.Location.Display_address[0], addstring)
610
 
                                result.Set("coords", baseurl)
611
 
                                if err := reply.Push(result); err != nil {
612
 
                                        log.Printf("==== YELP. error pushing result: %q\n", err.Error())
613
 
                                        return err
614
 
                                }
615
 
                                pushed++
616
 
                        }
617
 
                }
618
 
                log.Printf("=== YELP. results: %v, pushed results: %v, excluded by rating: %v, price: %v, by open: %v, by distance: %v\n", len(answers.Businesses), pushed, excludedRating, excludedPrice, excludedOpen, excludedDistance)
619
 
        } else {
620
 
                cat := reply.RegisterCategory("noloc", "", "", errorTemplate)
621
 
                result := scopes.NewCategorisedResult(cat)
622
 
                result.SetTitle(gettext.Gettext("No location found"))
623
 
                result.Set("subtitle", gettext.Gettext("Please make sure location is enabled"))
624
 
                result.SetURI("")
625
 
                if err := reply.Push(result); err != nil {
626
 
                        return err
627
 
                }
628
 
        }
629
 
        return nil
 
249
        query := q.QueryString()
 
250
        loc := metadata.Location()
 
251
 
 
252
        locale := metadata.Locale()
 
253
        langstring := strings.Split(locale, "_")
 
254
        log.Println("enweilocale", locale)
 
255
        distunit := "km"
 
256
        if langstring[1] == "US" {
 
257
                distunit = "mi"
 
258
        }
 
259
        minDistanceLabel := "0 km"
 
260
        var maxDistance float64
 
261
        maxDistance = 40 //km
 
262
        var maxDistanceLabel string
 
263
        maxDistanceLabel = "40 km"
 
264
        if distunit == "mi" {
 
265
                minDistanceLabel = "0 mi"
 
266
                maxDistance = 25
 
267
                maxDistanceLabel = "25 mi"
 
268
        }
 
269
 
 
270
        var numResultsDefault float64
 
271
        numResultsDefault = 40
 
272
        numResultsFilter := scopes.NewValueSliderFilter("sliderResults", 10, 300, numResultsDefault,
 
273
                scopes.ValueSliderLabels{
 
274
                        MinLabel:    "10",
 
275
                        MaxLabel:    "300",
 
276
                        ExtraLabels: nil,
 
277
                })
 
278
        //Translators: This is the maximum number of Yelp results to display
 
279
        numResultsFilter.Title = gettext.Gettext("Max results")
 
280
 
 
281
        // distances in code always use km.
 
282
        // slider gui uses mi (miles) in US
 
283
        // When in US, the slider value is coverted to km on retrieval
 
284
        var distanceDefault float64
 
285
        distanceDefault = 5
 
286
        distanceFilter := scopes.NewValueSliderFilter("distance", 0, maxDistance, distanceDefault,
 
287
                scopes.ValueSliderLabels{
 
288
                        MinLabel:    minDistanceLabel,
 
289
                        MaxLabel:    maxDistanceLabel,
 
290
                        ExtraLabels: nil,
 
291
                })
 
292
        distanceFilter.Title = gettext.Gettext("Distance")
 
293
 
 
294
        curSymb := C.GoString(C.localeconv().currency_symbol)
 
295
        priceOneLabel := curSymb
 
296
        priceTwoLabel := curSymb + curSymb
 
297
        priceThreeLabel := curSymb + curSymb + curSymb
 
298
        priceFourLabel := curSymb + curSymb + curSymb + curSymb
 
299
 
 
300
        filterState := q.FilterState()
 
301
 
 
302
        var ratingDefault float64
 
303
        ratingDefault = 0
 
304
        ratingFilter := scopes.NewValueSliderFilter("rating", 0, 5, ratingDefault,
 
305
                scopes.ValueSliderLabels{
 
306
                        MinLabel:    "0",
 
307
                        MaxLabel:    "5",
 
308
                        ExtraLabels: nil,
 
309
                })
 
310
        ratingFilter.Title = gettext.Gettext("Lowest rating")
 
311
 
 
312
        priceFilter := scopes.NewOptionSelectorFilter("priceFilter", gettext.Gettext("Price range"), false)
 
313
        priceFilter.AddOption("onePrice", priceOneLabel, false)
 
314
        priceFilter.AddOption("twoPrice", priceTwoLabel, false)
 
315
        priceFilter.AddOption("threePrice", priceThreeLabel, false)
 
316
        priceFilter.AddOption("fourPrice", priceFourLabel, false)
 
317
 
 
318
        //chnage to Switch filter when it moves from experimental namespace
 
319
        openFilter := scopes.NewOptionSelectorFilter("openFilter", gettext.Gettext("Open"), false)
 
320
        openFilter.AddOption("isOpen", gettext.Gettext("Is open"), false)
 
321
 
 
322
        filters := []scopes.Filter{priceFilter, ratingFilter, openFilter, distanceFilter, numResultsFilter}
 
323
 
 
324
        errP := reply.PushFilters(filters, q.FilterState())
 
325
        if errP != nil {
 
326
                return errors.New("yelp scope: cannot push filters. Error: " + errP.Error())
 
327
        }
 
328
 
 
329
        //change to Switch filter when it moves from experimental namespace
 
330
        //currentOpenFilter := openFilter.IsOn(filterState)
 
331
        currentOpenFilter := false
 
332
        if openFilter.HasActiveOption(filterState) {
 
333
                for _, option := range openFilter.ActiveOptions(filterState) {
 
334
                        if option == "isOpen" {
 
335
                                currentOpenFilter = true
 
336
                        }
 
337
                }
 
338
        }
 
339
 
 
340
        var currentPriceFilter PriceFilter
 
341
        currentPriceFilter.using = false
 
342
        if priceFilter.HasActiveOption(filterState) {
 
343
                for _, option := range priceFilter.ActiveOptions(filterState) {
 
344
                        switch option {
 
345
                        case "unknown":
 
346
                                currentPriceFilter.unknown = true
 
347
                                currentPriceFilter.using = true
 
348
                        case "onePrice":
 
349
                                currentPriceFilter.one = true
 
350
                                currentPriceFilter.using = true
 
351
                        case "twoPrice":
 
352
                                currentPriceFilter.two = true
 
353
                                currentPriceFilter.using = true
 
354
                        case "threePrice":
 
355
                                currentPriceFilter.three = true
 
356
                                currentPriceFilter.using = true
 
357
                        case "fourPrice":
 
358
                                currentPriceFilter.four = true
 
359
                                currentPriceFilter.using = true
 
360
                        }
 
361
                }
 
362
        }
 
363
 
 
364
        rating := ratingFilter.Value(filterState)
 
365
        log.Printf("=== Yelp rating filter value: %v\n", rating)
 
366
        //setup locale, scope directory, layout, distance units, etc
 
367
        yl.Dir = yl.Base.ScopeDirectory()
 
368
        yl.Layout = yl.getLayout()
 
369
 
 
370
        //get all the departments setup
 
371
        rootDept, err := scopes.NewDepartment("", q, gettext.Gettext("Everything"))
 
372
        if err != nil {
 
373
                return err
 
374
        }
 
375
        var deptlist1 deptlist
 
376
        err = yl.getDepts(&deptlist1)
 
377
        for _, v := range deptlist1.Depts {
 
378
                newdept, _ := scopes.NewDepartment(v.Label, q, gettext.Gettext(v.Name))
 
379
                rootDept.AddSubdepartment(newdept)
 
380
                if len(v.Subs) != 0 {
 
381
                        for _, s := range v.Subs {
 
382
                                newdept2, _ := scopes.NewDepartment(s.Label, q, gettext.Gettext(s.Name))
 
383
                                newdept.AddSubdepartment(newdept2)
 
384
                        }
 
385
                }
 
386
        }
 
387
        reply.RegisterDepartments(rootDept)
 
388
 
 
389
        numResults_f := numResultsFilter.Value(filterState)
 
390
 
 
391
        //log.Printf("==== Yelp. num reuslts value: %v\n", numResults_f)
 
392
 
 
393
        //log.Printf("=== YELP. num results: %v\n", numResults_f)
 
394
        // determine number of times to call yelp api to get the number of results we want
 
395
        numResults := int(numResults_f)
 
396
        var iters_f float64
 
397
        var iters int
 
398
        iters_f = numResults_f / 20
 
399
        iters_s := strconv.FormatFloat(iters_f, 'f', 1, 64)
 
400
        parts := strings.Split(iters_s, ".")
 
401
        iters, _ = strconv.Atoi(parts[0])
 
402
        itersDec, _ := strconv.Atoi(parts[1])
 
403
        if itersDec > 0 {
 
404
                iters++
 
405
        }
 
406
        yl.getAccessToken()
 
407
/*
 
408
        var token tokenResult
 
409
        if err := yl.getAccessToken(&token); err != nil {
 
410
                return err
 
411
        }
 
412
        log.Println("AccessToken:", token.AccessToken)
 
413
        yl.AccessToken = token.AccessToken*/
 
414
        var answers yelpAnswer
 
415
 
 
416
        //if loc is nil, there's nothing we can search for
 
417
        if loc != nil {
 
418
                distanceD := distanceFilter.Value(filterState)
 
419
 
 
420
                //log.Printf("=== Yelp distance filter value: %v\n", distanceD)
 
421
                if distunit == "mi" {
 
422
                        distanceD = distanceD * 1.60934
 
423
                }
 
424
                //log.Printf("=== Yelp distance after conversion: %v\n", distanceD)
 
425
                //if price option filter(s), continue if no match
 
426
                var priceFilterStr string
 
427
                var priceFilterSet []string
 
428
                if currentPriceFilter.using {
 
429
                       if currentPriceFilter.one {
 
430
                            priceFilterSet = append(priceFilterSet, "1")
 
431
                       }
 
432
                       if currentPriceFilter.two {
 
433
                            priceFilterSet = append(priceFilterSet, "2")
 
434
                       }
 
435
                       if currentPriceFilter.three {
 
436
                            priceFilterSet = append(priceFilterSet, "3")
 
437
                       }
 
438
                       if currentPriceFilter.four {
 
439
                            priceFilterSet = append(priceFilterSet, "4")
 
440
                       }
 
441
                       priceFilterStr = strings.Join(priceFilterSet, ", ")
 
442
                }
 
443
 
 
444
                queryParams := map[string]string{"latitude": strconv.FormatFloat(loc.Latitude, 'f', 4, 64), "longitude": strconv.FormatFloat(loc.Longitude, 'f', 4, 64), "locale": locale, "limit": strconv.Itoa(numResults), "offset": "0"}
 
445
                if len(q.DepartmentID()) > 0 {
 
446
                        queryParams["categories"] = q.DepartmentID()
 
447
                }
 
448
                if len(query) > 0 {
 
449
                        queryParams["term"] = query
 
450
                }
 
451
                if priceFilterStr != "" {
 
452
                        queryParams["pricing_filter"] = priceFilterStr
 
453
                }
 
454
                if currentOpenFilter {
 
455
                        queryParams["open_now_filter"] = "true"
 
456
                }
 
457
                //queryParams["sort_by"] = sortBy
 
458
                // call to the web api
 
459
                if err := yl.get(queryParams, "search?", &answers); err != nil {
 
460
                        return err
 
461
                }
 
462
 
 
463
 
 
464
                //create new category with no title
 
465
                cat := reply.RegisterCategory("places", "", "", yl.Layout)
 
466
                if query != "" {
 
467
                        //This block creates a category with a title containing the number of results
 
468
                        length := len(answers.Businesses)
 
469
                        lenstring := fmt.Sprintf("%v results from Yelp", length)
 
470
                        cat = reply.RegisterCategory("places_with_len", lenstring, lenstring, yl.Layout)
 
471
                }
 
472
 
 
473
                for _, p := range answers.Businesses {
 
474
                        log.Println("new result", p.Name)
 
475
                        if p.Rating < float32(rating) {
 
476
                                log.Println("rating ignore")
 
477
                                continue
 
478
                        }
 
479
                        //setup a point object of where we are
 
480
                        point1 := geo.NewPoint(loc.Latitude, loc.Longitude)
 
481
                        //and a point object of where the business is, iff yelp doesn't pass us 0,0
 
482
                        var distKm float64
 
483
                        dist2 := ""
 
484
                        if p.Location.Latitude != 0 && p.Location.Longitude != 0 {
 
485
                                point2 := geo.NewPoint(p.Location.Latitude, p.Location.Longitude)
 
486
                                distKm = point1.GreatCircleDistance(point2)
 
487
                                if distunit == "mi" {
 
488
                                        dist2 = fmt.Sprintf("%.2f %v", KmtoMi(distKm), distunit)
 
489
                                } else {
 
490
                                        dist2 = fmt.Sprintf("%.2f %v", distKm, distunit)
 
491
                                }
 
492
                        }
 
493
                        //if distance greater than sliderFilter value, don't show
 
494
                        if distKm > distanceD {
 
495
                                log.Printf("=== YELP. EXCLUDED by place distance: %v, \n", distKm)
 
496
                                continue
 
497
                        }
 
498
 
 
499
                        result := scopes.NewCategorisedResult(cat)
 
500
                        result.SetURI(p.Url)
 
501
                        result.Set("summary", dist2)
 
502
                        result.Set("id", p.Id)
 
503
                        var imageName string
 
504
                        if p.Rating < 1 {
 
505
                                imageName = "stars_large_0.png"
 
506
                        } else if p.Rating >= 1 && p.Rating < 2 {
 
507
                                imageName = "stars_large_1.png"
 
508
                        } else if p.Rating >= 2 && p.Rating < 2.5 {
 
509
                                imageName = "stars_large_2.png"
 
510
                        } else if p.Rating >= 2.5 && p.Rating < 3 {
 
511
                                imageName = "stars_large_2_half.png"
 
512
                        } else if p.Rating >= 3 && p.Rating < 3.5 {
 
513
                                imageName = "stars_large_3.png"
 
514
                        } else if p.Rating >= 3.5 && p.Rating < 4 {
 
515
                                imageName = "stars_large_3_half.png"
 
516
                        } else if p.Rating >= 4 && p.Rating < 4.5 {
 
517
                                imageName = "stars_large_4.png"
 
518
                        } else if p.Rating >= 4.5 && p.Rating < 5 {
 
519
                                imageName = "stars_large_4_half.png"
 
520
                        } else if p.Rating >= 5 {
 
521
                                imageName = "stars_large_5.png"
 
522
                        }
 
523
                        atts := []attributeInfo{
 
524
                                attributeInfo{Value: dist2},
 
525
                                attributeInfo{Value: fmt.Sprintf("(%v)", p.ReviewCount), Icon: yl.Dir + "/images/" + imageName},
 
526
                        }
 
527
                        result.Set("attributes", atts)
 
528
                        result.SetTitle(p.Name)
 
529
                       // if busi.ImageUrl == "" {
 
530
                                result.SetArt(yl.Dir + "/images/yelp.png")
 
531
                      //  } else {
 
532
                                // replacing the ms with ls gives a higher resolution picture
 
533
                       //         result.SetArt(busi.ImageUrl)
 
534
                      //  }
 
535
                        var catstringlist []string
 
536
                        for _, thecat := range p.Cats {
 
537
                                catstringlist = append(catstringlist, thecat.Title)
 
538
                        }
 
539
 
 
540
                        catstring := strings.Join(catstringlist, ", ")
 
541
                        result.Set("rate", p.Rating)
 
542
                        result.Set("category", catstring)
 
543
 
 
544
                        log.Println("push result")
 
545
                        if err := reply.Push(result); err != nil {
 
546
                                log.Printf("==== YELP. error pushing result: %q\n", err.Error())
 
547
                                return err
 
548
                        }
 
549
                }
 
550
        } else {
 
551
                cat := reply.RegisterCategory("noloc", "", "", errorTemplate)
 
552
                result := scopes.NewCategorisedResult(cat)
 
553
                result.SetTitle(gettext.Gettext("No location found"))
 
554
                result.Set("subtitle", gettext.Gettext("Please make sure location is enabled"))
 
555
                result.SetURI("")
 
556
                if err := reply.Push(result); err != nil {
 
557
                        return err
 
558
                }
 
559
        }
 
560
        return nil
630
561
}
631
562
 
632
563
func (yl *YelpScope) Preview(result *scopes.Result, metadata *scopes.ActionMetadata, reply *scopes.PreviewReply, cancelled <-chan bool) error {
633
 
        header := scopes.NewPreviewWidget("header", "header")
634
 
        header.AddAttributeMapping("title", "title")
635
 
        header.AddAttributeMapping("subtitle", "address")
636
 
        var rate float32
637
 
        var coords string
638
 
        if err := result.Get("rate", &rate); err != nil {
639
 
                return err
640
 
        }
641
 
        var phone string
642
 
        if err := result.Get("phone", &phone); err != nil {
643
 
                return err
644
 
        }
645
 
        if err := result.Get("coords", &coords); err != nil {
646
 
                return err
647
 
        }
648
 
        art := scopes.NewPreviewWidget("art", "image")
649
 
        art.AddAttributeMapping("source", "art")
650
 
 
651
 
        buttons := []actionInfo{
652
 
                actionInfo{Id: "view", Label: gettext.Gettext("View on Yelp"), Icon: "/usr/share/icons/unity-icon-theme/places/svg/service-yelpplaces.svg"},
653
 
                actionInfo{Id: "map", Label: gettext.Gettext("Show on Map"), Uri: coords},
654
 
                actionInfo{Id: "phone", Label: gettext.Gettext("Call"), Uri: fmt.Sprintf("tel:///%v", phone), Icon: "theme://phone"},
655
 
        }
656
 
        reviews := []reviewInfo{
657
 
                reviewInfo{Rating: rate, Author: ""},
658
 
        }
659
 
 
660
 
        ratings := scopes.NewPreviewWidget("ratings", "reviews")
661
 
        ratings.AddAttributeValue("rating-icon-empty", yl.Dir+"/images/empty.png")
662
 
        ratings.AddAttributeValue("rating-icon-half", yl.Dir+"/images/half.png")
663
 
        ratings.AddAttributeValue("rating-icon-full", yl.Dir+"/images/full.png")
664
 
        ratings.AddAttributeValue("reviews", reviews)
665
 
        actions := scopes.NewPreviewWidget("actions", "actions")
666
 
        actions.AddAttributeValue("actions", buttons)
667
 
 
668
 
        addressheader := scopes.NewPreviewWidget("addressheader", "header")
669
 
        addressheader.AddAttributeMapping("title", "streetaddress1")
670
 
        addressheader.AddAttributeMapping("subtitle", "streetaddress2")
671
 
 
672
 
        var price string
673
 
        if err := result.Get("price", &price); err == nil {
674
 
                priceWidget := scopes.NewPreviewWidget("price", "text")
675
 
                priceWidget.AddAttributeValue("text", "<b>"+gettext.Gettext("Price")+"</b>: "+price)
676
 
                return reply.PushWidgets(art, header, ratings, addressheader, priceWidget, actions)
677
 
        }
678
 
 
679
 
        return reply.PushWidgets(art, header, ratings, addressheader, actions)
 
564
        header := scopes.NewPreviewWidget("header", "header")
 
565
        header.AddAttributeMapping("title", "title")
 
566
        header.AddAttributeMapping("subtitle", "category")
 
567
        var rate float32
 
568
        if err := result.Get("rate", &rate); err != nil {
 
569
                return err
 
570
        }
 
571
        var id string
 
572
        if err := result.Get("id", &id); err != nil {
 
573
                return err
 
574
        }
 
575
        var busi business
 
576
        if err := yl.get(map[string]string{}, id, &busi); err != nil {
 
577
                return err
 
578
        }
 
579
        art := scopes.NewPreviewWidget("art", "gallery")
 
580
        art.AddAttributeValue("sources", busi.Photos)
 
581
 
 
582
        result.Set("streetaddress1", busi.Location.Address1)
 
583
        var addstring string
 
584
        if busi.Location.Address2 != "" {
 
585
                addstring += busi.Location.Address2
 
586
        }
 
587
        if busi.Location.Address3 != "" {
 
588
                addstring += " "
 
589
                addstring += busi.Location.Address3
 
590
        }
 
591
        if busi.Location.City != "" {
 
592
                addstring += " "
 
593
                addstring += busi.Location.City
 
594
        }
 
595
        if busi.Location.Zip != "" {
 
596
                addstring += " "
 
597
                addstring += busi.Location.Zip
 
598
        }
 
599
        if busi.Location.Country != "" {
 
600
                addstring += " "
 
601
                addstring += busi.Location.Country
 
602
        }
 
603
 
 
604
        baseurl := fmt.Sprintf("http://m.here.com/#action=search&params={\"query\":\"%v %v\"}",  busi.Location.Address1, addstring)
 
605
        var buttons []actionInfo
 
606
        if busi.Phone == "" {
 
607
                buttons = []actionInfo{
 
608
                        actionInfo{Id: "view", Label: gettext.Gettext("View on Yelp"), Icon: "/usr/share/icons/unity-icon-theme/places/svg/service-yelpplaces.svg"},
 
609
                        actionInfo{Id: "map", Label: gettext.Gettext("Show on Map"), Uri: baseurl},
 
610
                }
 
611
        } else {
 
612
                buttons = []actionInfo{
 
613
                        actionInfo{Id: "view", Label: gettext.Gettext("View on Yelp"), Icon: "/usr/share/icons/unity-icon-theme/places/svg/service-yelpplaces.svg"},
 
614
                        actionInfo{Id: "map", Label: gettext.Gettext("Show on Map"), Uri: baseurl},
 
615
                        actionInfo{Id: "phone", Label: gettext.Gettext("Call"), Uri: fmt.Sprintf("tel:///%v", busi.Phone), Icon: "theme://phone"},
 
616
                }
 
617
        }
 
618
 
 
619
        var res reviews
 
620
        if err := yl.get(map[string]string{}, id + "/reviews", &res); err != nil {
 
621
                return err
 
622
        }
 
623
        reviews := []reviewInfo{}
 
624
        for _, review := range res.Reviews {
 
625
                reviews = append(reviews, reviewInfo{Rating: review.Rating, Author: "", Review: review.Text})
 
626
        }
 
627
 
 
628
        ratings := scopes.NewPreviewWidget("ratings", "reviews")
 
629
        ratings.AddAttributeValue("rating-icon-empty", yl.Dir+"/images/empty.png")
 
630
        ratings.AddAttributeValue("rating-icon-half", yl.Dir+"/images/half.png")
 
631
        ratings.AddAttributeValue("rating-icon-full", yl.Dir+"/images/full.png")
 
632
        ratings.AddAttributeValue("reviews", reviews)
 
633
 
 
634
        actions := scopes.NewPreviewWidget("actions", "actions")
 
635
        actions.AddAttributeValue("actions", buttons)
 
636
 
 
637
        addressheader := scopes.NewPreviewWidget("addressheader", "header")
 
638
        addressheader.AddAttributeValue("title", busi.Location.Address1)
 
639
        addressheader.AddAttributeValue("subtitle", addstring)
 
640
 
 
641
        return reply.PushWidgets(art, header, ratings, addressheader, actions)
680
642
}
681
643
 
 
644
var clientid = ""
 
645
var clientsecret = ""
 
646
 
682
647
func main() {
683
 
        log.Println("Starting yelp scope")
684
 
        scope := &YelpScope{
685
 
                BaseURI:        "http://api.yelp.com/v2/search?",
686
 
                ConsumerKey:    "2lUxf_XzPiZ-e8jJfn4JbA",
687
 
                Token:          "yhS5hXf3ES_ChYsg_FWFqmNoDucBUu-0",
688
 
                ConsumerSecret: "rQvoNZMcf3-CG-4OgIA2McFynLU",
689
 
                TokenSecret:    "gFgW9giUF-sMqYfFEVa2JIJTCfY",
690
 
                Dir:            "",
691
 
                Layout:         "",
692
 
        }
693
 
        if err := scopes.Run(scope); err != nil {
694
 
                log.Fatalln(err)
695
 
        }
 
648
        log.Println("Starting yelp scope")
 
649
        scope := &YelpScope{
 
650
                BaseURI:        "https://api.yelp.com/v3/business/",
 
651
                ClientId:       clientid,
 
652
                AccessToken:    "",//"9DSPv4a_pu4Qyt9FQe1jDfL-jzO_4g5s6HKpwTxHR2sHgzfzPIHb0XbH2xYQ5n2ojKxxJji8kGNKodFP60l4sKtjUZLu8P59l8Pzeof9aaWDat96lm1VzdhkOfQ-V3Yx",
 
653
                ClientSecret:   clientsecret,
 
654
                Dir:            "",
 
655
                Layout:         "",
 
656
        }
 
657
        if err := scopes.Run(scope); err != nil {
 
658
                log.Fatalln(err)
 
659
        }
696
660
}