Newer
Older
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
#!/usr/bin/env python3
"""
This module provides a set of reuseable functions
which provide the main app functionality.
We could even go a stage further and separate
database interactions from logic...
"""
# import modules from Python standard library
from bson.objectid import ObjectId
from datetime import datetime
import bcrypt
def login( db, form ):
""" Logs a user in if the Username and Password
submitted in a form match a record in database
Params:
db: handle to a database
form: FieldStorage object
Returns:
Dict
"""
# login status is false by default
status = False
try:
# get the username from the form
username = form['username'].value
# get the unhashed password sent in the form
pw = form['password'].value
except KeyError:
# a field must be missing from the form data
response = "I don't think you filled all the fields in..."
else:
# look for an account with the username
account = db.accounts.find_one({
"username":username,
})
# check if an account came back
if account is not None:
# compare the unhashed password from the form
# with the hashed version in the database
if bcrypt.checkpw( pw.encode('utf-8'), account['password'].encode('utf-8') ):
# if they match, output a personal greeting
# was this a DP student?
if account['username'] == "Sunday":
response = "What a good kitty. Now fill in the <a href='https://moduleevaluation.gold.ac.uk/surveyPrivacyStatement/Kf4iWgP74kSxYCxRA'>module feedback form</a> and you shall have some pie."
else:
response = "Hello {}!".format( account['name']['first'] )
status = True
else:
# if not, we know it was a wrong password
response = "Wrong password."
else:
# their username didn't match, so tell them that
response = "Sorry, I don't think I know you!"
# return a dict with the result and a message
return {"status":status,"msg":response}
def register_account( db, form ):
""" Registers a new user by inserting an account
in the accounts collection
Params:
db: handle to a database
form: FieldStorage object
Returns:
Dict
"""
# registration status false by default
status = False
try:
# get the username from the form
username = form['username'].value
# get the email from the form
email = form['email'].value
# get the unhashed password from the form
password = form['password'].value
except KeyError:
# a field must be missing from the form data
response = "I don't think you filled all the fields in..."
else:
# check if there is already an account with the email
# or username
result = db.accounts.find_one( { '$or': [
{ 'username' : username },
{ 'email': email }
]} )
# if so, send back a useful response
if result:
if email in result.values():
response = "Email address already registered."
else:
response = "Username taken."
# otherwise go ahead and make the account
else:
hashed_pw = bcrypt.hashpw( password.encode('utf-8'), bcrypt.gensalt() )
query = {
"username": username,
"password": hashed_pw.decode('utf-8'),
"is_admin": 0,
"created" : datetime.now().timestamp()
}
# make sure name fields aren't empty
# if they are, give them empty string values
if 'first' in form:
first = form['first'].value
else:
first = ""
if 'last' in form:
last = form['last'].value
else:
last = ""
# append name to query
query["name"] = { "first": first, "last": last }
# insert the account in the database
doc = db.accounts.insert( query )
if doc:
status = True
response = "New account registered. <a href='/cgi-bin/splash.py' title='login'>Click here</a> to go Log in!"
else:
response = "Problem registering your account. Please refresh the page to try again."
# return something useful...
return {'status': status, 'msg': response}
def latest_fluck( db ):
""" Returns details of the most recently flucked
cat in the database
Params:
db: handle to a database
Returns:
Dict
"""
# start with an empty dict
image = {}
# get details of last flucked cat
result = db.flucks.find({"is_flucked":1}).sort([('timestamp', -1)]).limit(1)
# get the associated image
for fluck in result:
result2 = db.images.find({"_id":fluck["image_id"]})
# if a doc was returned, put the bits we want in the image dict
for doc in result2:
image = {"url":doc["url"],"alt":doc["alt"]}
return image
def most_flucked( db ):
""" Returns details of the most flucked
cat in the database
Params:
db: handle to a database
Returns:
Dict
"""
# start with an empty dict
image = {}
# define a pipeline of operations to get most flucked image id
# from flucks collection
pipeline = [
{"$group": {"_id": "$image_id", "count": {"$sum": 1}}},
{"$sort": {"count":-1}},
{"$limit":1}
]
# apply pipeline of operations using aggregate
result = db.flucks.aggregate( pipeline )
# check if a result was returned
if result:
for fluck in result:
# get the associated image document
doc = db.images.find_one({"_id": fluck["_id"]})
# if a doc was returned, put the bits we want in the image dict
if doc:
image = {"url":doc["url"],"alt":doc["alt"]}
return image
def random_cat( db ):
""" Returns details of a random cat in the database
Params:
db: handle to a database
Returns:
Dict
"""
# start with an empty dict
image = {}
# get a random sample from images collection of size '1'
result = db.images.aggregate(
[{ '$sample': { 'size': 1 } }]
)
# if a result came back, do stuff with it...
if result:
# iterate through objects in the cursor (should only be 1)
for doc in result:
# put the bits we want in the image dict
image = {
'src': doc['url'],
'alt': doc['alt'],
'id': doc['_id']
}
return image
def count_flucks( db, img_id ):
""" Returns details of a random cat in the database
Params:
db: handle to a database
img_id: object id of an image document
Returns:
Dict
"""
# try to count flucks associated with image id
try:
num_flucks = db.flucks.find( {"image_id": img_id, "is_flucked":1} ).count()
# if img_id invalid, return false rather than crashing
except NameError:
return False
else:
return num_flucks
def insert_fluck( db, img_id, is_flucked ):
""" Inserts new fluck in flucks collection
based on form data
Params:
db: handle to a database
form: FieldStorage object
Returns:
Bool
"""
# try to insert a fluck
query = {
"image_id": ObjectId(img_id),
"is_flucked":is_flucked,
"timestamp":datetime.now().timestamp()
}
try:
result = db.flucks.insert( query )
# if img_id invalid, return something useful
except NameError:
return {'status': False, 'query': query}
# else return info about the inserted document
else:
return {'status': True, 'fluck_id': result}