-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapi.py
112 lines (99 loc) · 3.01 KB
/
api.py
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
import webapp2
from webapp2_extras import json
from google.appengine.ext import ndb
import logging
import math
class Location(ndb.Model):
loc = ndb.GeoPtProperty()
geohash = ndb.StringProperty()
name = ndb.StringProperty()
address = ndb.StringProperty()
notes = ndb.TextProperty()
L1_hashsize = 0.05
@classmethod
def make_geohash_L1(cls, lat, lon):
# round down to multiple of 0.05
lat = math.floor(float(lat)*20)/20
lon = math.floor(float(lon)*20)/20
if lat == -0.0:
lat = 0.0
if lon == -0.0:
lon = 0.0
return str(lat) + ":" + str(lon)
@classmethod
def query_bbox(cls, north, east, south, west):
# Let's not generate massive queries
if east > west + 1 or north > south + 1:
return []
squares = []
x = west
# generate the list of geohashes we need to find
while x <= east:
y = south
while y <= north:
squares.append(cls.make_geohash_L1(y, x))
y += cls.L1_hashsize
x += cls.L1_hashsize
result = []
if len(squares) > 0:
logging.info("squares:" + str(squares))
for loc in cls.query(Location.geohash.IN(squares)):
logging.info("loc:" + str(loc))
logging.info("{0} {1} {2} {3}".format(east,west,north,south))
# The geohash might return results just outside the search area
if loc.loc.lon <= east and loc.loc.lon >= west \
and loc.loc.lat <= north and loc.loc.lat >= south:
result.append(loc)
logging.info("result: " + str(result))
return result
class LocationAPI(webapp2.RequestHandler):
def post(self, arg):
loc = Location()
loc.loc = ndb.GeoPt(float(self.request.get('latitude')), float(self.request.get('longitude')))
loc.geohash = Location.make_geohash_L1(loc.loc.lat, loc.loc.lon)
loc.name = self.request.get('name')
loc.address = self.request.get('address')
loc.notes = self.request.get('notes')
loc.put()
def get(self,id):
if id == '':
# search requires parameters
west, south, east, north = [float(x) for x in self.request.get('bbox').split(',')]
# TODO: queries for large areas
data = []
for loc in Location.query_bbox(north, east, south, west):
data.append({"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [loc.loc.lon, loc.loc.lat]
},
"properties": {
"name": loc.name,
"address": loc.address,
"notes": loc.notes
}
})
else:
# client requested a specific location
key = ndb.Key(urlsafe=id)
loc = key.get()
data = [{"type": "Feature",
"id": id,
"geometry": {
"coordinates": [loc.loc.lon, loc.loc.lat]
},
"properties": {
"name": loc.name,
"address": loc.address,
"notes": loc.notes
}
}]
data = {"type": "FeatureCollection",
"features": data}
self.response.headers['Content-Type'] = 'application/json'
jsondata = json.encode(data)
logging.info("geojson: " + jsondata)
self.response.write(jsondata)
api = webapp2.WSGIApplication([
('/api/v1.0/locations/(.*)', LocationAPI)
], debug=True)