-
Notifications
You must be signed in to change notification settings - Fork 5
/
places.go
159 lines (128 loc) · 4.09 KB
/
places.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package main
// @hipbot nearby <query>
// Get 4 nearest places that respond to <query>
// return an HTML list of places with a map
import (
"encoding/json"
"log"
"net/http"
"net/url"
"os"
"strings"
)
const (
GOOGLE_PLACES_ENDPOINT = "https://maps.googleapis.com/maps/api/place/nearbysearch/json"
GOOGLE_MAPS_ENDPOINT = "https://maps.googleapis.com/maps/api/staticmap"
)
var (
googlePlacesParams = "?location=" + latLngPair + "&sensor=false&rankby=distance"
googleMapsParams = "?center=" + latLngPair + "&zoom=15&size=600x200&sensor=false"
googleApiKey = os.Getenv("GOOGLE_API_KEY")
)
var quotaGuardStaticURL *url.URL
func init() {
envURL := os.Getenv("QUOTAGUARDSTATIC_URL")
var err error
quotaGuardStaticURL, err = url.ParseRequestURI(envURL)
if err != nil {
log.Println("DEBUG: env-url:", quotaGuardStaticURL)
panic("Error parsing quotaguard url:" + err.Error())
}
}
type Place struct {
Icon string `json:"icon"`
Name string `json:"name"`
OpenHours OpenHours `json:"opening_hours"`
Rating json.Number `json:"rating"`
Address string `json:"vicinity"`
Geometry Geometry `json:"geometry"`
}
type Geometry struct {
PlaceLocation PlaceLocation `json:"location"`
}
type PlaceLocation struct {
Lat json.Number `json:"lat"`
Lng json.Number `json:"lng"`
}
type OpenHours struct {
OpenNow bool `json:"open_now"`
}
type PlacesResponse struct {
Places []Place `json:"results"`
}
// Get 4 nearest places pertaining to <query>
// HTML response includes a MAP(!) with markers of the 4 locations
func places(query string) string {
additionalParams := "key=" + googleApiKey + "&keyword=" + url.QueryEscape(query)
fullQueryUrl := GOOGLE_PLACES_ENDPOINT + googlePlacesParams + "&" + additionalParams
// Sent GET request through proxy for static IP on heroku
// -> for use with QuotaGuard
transport := &http.Transport{Proxy: http.ProxyURL(quotaGuardStaticURL)}
client := &http.Client{Transport: transport}
res, err := client.Get(fullQueryUrl)
if err != nil {
log.Println("Error in HTTP GET:", err)
return "error"
}
defer res.Body.Close()
// Decode JSON response
decoder := json.NewDecoder(res.Body)
response := new(PlacesResponse)
decoder.Decode(response)
// Convert struct to a pretty HTML response with a map!
return htmlPlaces(response.Places, query)
}
// return HTML, including a static Google MAP with (blue) markers of the 4 locations
func htmlPlaces(places []Place, query string) string {
// Title
html := "<strong>Results for Nearby " + strings.Title(query) + "</strong><br>"
// Start unordered list
html += "<ul>"
// Initialize list of marker query params
markers := ""
// Only use the first 4 places
for i := range places {
if i > 3 {
break
}
// Bullet point for each place, includes name, address, rating (or "N/A"), open-now
html += "<li>" + places[i].Name + "<br>"
html += places[i].Address + "<br>"
html += "<em>Rating: " + stringRating(places[i].Rating) + "</em> | "
html += openNowHtml(places[i].OpenHours.OpenNow) + "<br></li>"
// Add marker for this place to the list
markers += "&markers=color:blue|label:" + alphabet(i) + "|" + NewLatLngPair(places[i].Geometry.PlaceLocation)
}
// End list
html += "</ul><br>"
// Add static Google map
html += "<img src='" + GOOGLE_MAPS_ENDPOINT + googleMapsParams + markers + "'>"
return html
}
// Return a string representation of the Google+ rating
// If no rating, return "N/A"
func stringRating(rating json.Number) string {
if len(rating) != 0 {
return string(rating)
} else {
return "N/A"
}
}
// Stringifies lat & lng and concatenates them together with a comma
func NewLatLngPair(location PlaceLocation) string {
return (string(location.Lat) + "," + string(location.Lng))
}
// Return a string representation the boolean "open_now"
// If open - "Open Now", if closed - "Closed"
func openNowHtml(isOpen bool) string {
if isOpen {
return "<strong>Open Now</strong>"
} else {
return "<strong>Closed</strong>"
}
}
// Maps an integer (0 - 6 ONLY) to an upper-case letter
func alphabet(i int) string {
alphab := [7]string{"A", "B", "C", "D", "E", "F", "G"}
return alphab[i]
}