This repository was archived by the owner on Feb 27, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbackend.py
More file actions
executable file
·284 lines (227 loc) · 9.36 KB
/
backend.py
File metadata and controls
executable file
·284 lines (227 loc) · 9.36 KB
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
from flask import Flask
from flask import redirect
from flask import request
from flask import render_template
from flask import session
from flask import url_for
from flask import flash
import os
import json
from pymongo import MongoClient
from bson.objectid import ObjectId
from authlib.flask.client import OAuth
from six.moves.urllib.parse import urlencode
import googlemaps
from datetime import datetime
#CONSTANTS
JWT_PAYLOAD = 'jwt_payload'
PROFILE_KEY = 'profile'
client = MongoClient(os.environ.get('DATABASE_URL'))
db = client.unsheltereddb
app = Flask(__name__)
oauth = OAuth(app)
gmaps = None
try:
gmaps = googlemaps.Client(key=os.environ.get('MAPS_APIKEY'))
except ValueError as e:
gmaps = None
pass #ignore error
app.config['SECRET_KEY'] = os.environ['FLASK_SECRET_KEY']
base_url='https://' + 'unsheltered.auth0.com'
AUTH0_AUDIENCE = base_url + '/userinfo'
auth0 = oauth.register(
'auth0',
client_id = os.environ['AUTH0_CLIENT_ID'],
client_secret = os.environ['AUTH0_CLIENT_SECRET'],
api_base_url = base_url,
access_token_url = base_url + '/oauth/token',
authorize_url = base_url + '/authorize',
client_kwargs = {
'scope': 'openid profile',
},
)
def isLoggedIn():
# print('trolololol')
# print('profile' in session)
# print(session)
return ('profile' in session)
def getCurrentUserId():
return session[PROFILE_KEY]['user_id']
@app.context_processor
def injectLoginState():
return dict(loggedin=isLoggedIn())
# def requires_auth(f):
# @wraps(f)
# def decorated(*args, **kwargs):
# if not isLoggedIn():
# return redirect('/account')
# return f(*args, **kwargs)
# return decorated
@app.route('/')
def home():
return render_template('homepage.html', shelters=sortByBedsFree(getShelters()))
@app.route('/logincallback')
def callbackHandling():
auth0.authorize_access_token()
resp = auth0.get('userinfo')
userinfo = resp.json()
session[JWT_PAYLOAD] = userinfo
session[PROFILE_KEY] = {
'user_id': userinfo['sub'],
'name': userinfo['name'],
'picture': userinfo['picture']
}
flash('You were successfully logged in', 'alert-success')
return redirect('/account')
@app.route('/volunteer')
def volunteer():
return render_template('volunteer.html')
@app.route('/homelessrights')
def homelessRights():
return render_template('homelessRights.html')
@app.route('/about')
def about():
return render_template('about.html')
@app.route('/account', methods=['GET', 'POST'])
def account():
if request.method == 'GET':
if isLoggedIn():
return render_template(
'account.html',
shelters=getShelters({'owner': str(getCurrentUserId())})
)
# userinfo=session[PROFILE_KEY], #these are ost likely unnecessary
# userinfo_pretty=json.dumps(session[JWT_PAYLOAD], indent=4)
else:
return auth0.authorize_redirect(
redirect_uri=url_for('callbackHandling', _external=True),
audience=AUTH0_AUDIENCE
)
elif request.method == 'POST':
form = request.form
formData = {
'name': form.getlist('name')[0],
'owner': str(getCurrentUserId()),#potential security issue?
'capacity': int(form.getlist('capacity')[0]),
'bedsFree': int(form.getlist('bedsFree')[0]),
'streetAddress': form.getlist('streetaddress')[0],
'city': 'Portland',
'state': 'Oregon',
'zipcode': form.getlist('zipcode')[0],
'phoneNumber': form.getlist('phoneNumber')[0],
'emailAddress': form.getlist('emailAddress')[0],
'webURL': form.getlist('webURL')[0]
}
for field in form:
if field == 'delete':
print("deleting")
deleteShelter(ObjectId(str(form.getlist('shelter-id')[0])))
break
elif field == 'update':
if isFormDataValid(formData):
print("updating")
formData['_id'] = ObjectId(str(form.getlist('shelter-id')[0]))
updateShelter(formData)
break
elif field == 'submit':
if isFormDataValid(formData):
print("creating")
addShelter(formData)
break
return redirect('/account')
@app.route('/logout')
def logout():
session.clear()
params = {
'returnTo': url_for('home', _external=True),
'client_id': os.environ['AUTH0_CLIENT_ID']
}
flash('You were successfully logged out', 'alert-success')
return redirect(auth0.api_base_url + '/v2/logout?' + urlencode(params))
def getShelters(query=None):
allShelters = []
if query is None:
shelters = db.shelters.find()
else:
shelters = db.shelters.find(query)
for shelter in shelters:
if gmaps is not None:
shelter["mapURL"] = getMapURLForShelter(constructAddress(shelter), shelter['name'])
allShelters.append(shelter)
return allShelters
def sortByBedsFree(shelters):
return sorted(shelters, key=lambda shelter: shelter['bedsFree'], reverse=True)
def addShelter(shelter):
db.shelters.insert(shelter)
flash('Shelter Added!', 'alert-success')
def deleteShelter(id):
db.shelters.delete_one({ "_id": id })
flash('Shelter Deleted!', 'alert-success')
def updateShelter(shelterData):
shelterQuery={ '_id': shelterData['_id']}
shelter=getShelters({ '_id': shelterData['_id']})[0]
updateQuery={}
for key, value in shelterData.items():
if 'phoneNumber' not in shelter.keys():
shelter['phoneNumber'] = ''
if 'emailAddress' not in shelter.keys():
shelter['emailAddress'] = ''
if 'webURL' not in shelter.keys():
shelter['webURL'] = ''
if shelter[key] != value:
updateQuery[key] = value
if updateQuery == {}:
flash("Could not update this shelter. No information has changed", 'alert-danger')
return
updateQuery = { "$set": updateQuery }
db.shelters.update_one(shelterQuery, updateQuery)
flash('Shelter Updated!', 'alert-success')
def isFormDataValid(formData):
passed=True
if formData['bedsFree'] > formData['capacity']:
flash('Error: The number of beds available cannot be higher than the shelter capacity.', 'alert-danger')
passed=False
#if formData['phoneNumber'] == '':
#flash('Error: You must now enter a phone number.', 'alert-danger')
#passed=False
#removed address validation on form submit because it was incorrectly fetching
# if getNearestPlaceWithName(constructAddress(formData), formData['name']) == None:
# flash('Error: The address you provided could not be found in the Google Maps database.', 'alert-danger')
# passed=False
return passed
def getAddressPlace(address):
geocode_result = gmaps.geocode(address)#111 W Burnside St, Portland, OR
return geocode_result[0]["place_id"]
#((geocode_result[0]["geometry"]["location"]["lat"]), (geocode_result[0]["geometry"]["location"]["lng"]))
def constructAddress(shelterDict):
return shelterDict["streetAddress"]+", "+shelterDict["city"]+", "+shelterDict["state"]+" "+shelterDict["zipcode"]
def getLatLong(address):
location = gmaps.geocode(address)[0]["geometry"]["location"]#111 W Burnside St, Portland, OR
return (location['lat'], location['lng'])
def getNearestPlaceWithName(address, name):
coords = getLatLong(address)
places=gmaps.places_nearby(coords, keyword=name, rank_by='distance')#, type="lodging"
# location (string, dict, list, or tuple) – The latitude/longitude value for which you wish to obtain the closest, human-readable address.
# radius (int) – Distance in meters within which to bias results.
# region (string) – The region code, optional parameter. See more @ https://developers.google.com/places/web-service/search
# keyword (string) – A term to be matched against all content that Google has indexed for this place.
# name (string or list of strings) – One or more terms to be matched against the names of places.
# rank_by (string) – Specifies the order in which results are listed. Possible values are: prominence (default), distance
# type (string) – Restricts the results to places matching the specified type. The full list of supported types is available here: https://developers.google.com/places/supported_types
# Return type:
# result dict with the following keys: status: status code results: list of places html_attributions: set of attributions which must be displayed next_page_token: token for retrieving the next page of results
try:
placeID=places['results'][0]['place_id']
except IndexError:
return None
else:
return placeID
def getUrlFromPlaceID(placeID):
return "https://www.google.com/maps/place/?q=place_id:" + str(placeID)
def getMapURLForShelter(address, name):
placeID = getNearestPlaceWithName(address, name)
print(type(placeID))
if placeID == None:
placeID = getAddressPlace(address)
return getUrlFromPlaceID(placeID)
# print(getUrlFromPlaceID(getNearestPlaceWithName('22 SW 3rd Ave, Portland, OR 97204', 'Voodoo Doughnut')))