/
server.py
435 lines (358 loc) · 13.4 KB
/
server.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
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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
#!/usr/bin/env python2.7
"""
Columbia W4111 Intro to databases
Example webserver
To run locally
python server.py
Go to http://localhost:8111 in your browser
A debugger such as "pdb" may be helpful for debugging.
Read about it online.
eugene wu 2015
"""
import smtplib
import os
import re
from sqlalchemy import *
from sqlalchemy.pool import NullPool
from utility import User, Equal, Post, Like, Contains, And, Or, Filter, Comment, GuessSetting, Table
from flask import Flask, request, render_template, g, redirect, Response, url_for, flash, session
from flask.ext.login import LoginManager, UserMixin, login_required, login_user, current_user, logout_user
tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
app = Flask(__name__, template_folder=tmpl_dir)
login_manager = LoginManager()
login_manager.init_app(app)
email = "cuadmirers16@gmail.com"
password = None
with open("cu_password.txt", "r") as f:
password = f.readlines()[0].replace("\n", "")
def send_guesser_mail(to, guess):
send_mail(to, "Guess what? You've correctly guessed %s! Maybe you guys should get in touch and see where things go ;)" % guess)
def send_guessed_mail(to, guesser):
send_mail(to, "Guess what? Looks like love might be in the air! User %s just guessed you and we know what that means ;)" % guesser)
def send_mail(recipient, TEXT):
TO = recipient if type(recipient) is list else [recipient]
SUBJECT = "Someone's got a crush!"
FROM = email
message = """\From: %s\nTo: %s\nSubject: %s\n\n%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)
try:
server = smtplib.SMTP("smtp.gmail.com", 587)
server.ehlo()
server.starttls()
server.login(email, password)
server.sendmail(FROM, TO, message)
server.close()
print 'successfully sent the mail'
print "Sent mail:"
print message
except BaseException as e:
print e
print "failed to send mail"
NUMBER_GUESSES = 3
#class User(UserMixin):
# # proxy for a database of users
# def __init__(self, username, password):
# self.id = username
# self.password = password
# @classmethod
# def get(cls, email):
# return User.select([Equal("email", email)])
#
# The following uses the sqlite3 database test.db -- you can use this for debugging purposes
# However for the project you will need to connect to your Part 2 database in order to use the
# data
#
# XXX: The URI should be in the format of:
#
# postgresql://USER:PASSWORD@w4111db1.cloudapp.net:5432/proj1part2
#
# For example, if you had username ewu2493, password foobar, then the following line would be:
#
# DATABASEURI = "postgresql://ewu2493:foobar@w4111db1.cloudapp.net:5432/proj1part2"
#
DATABASEURI = "sqlite:///test.db"
DATABASEURI = "postgresql://jjm2212:421@w4111db1.cloudapp.net:5432/proj1part2"
#
# This line creates a database engine that knows how to connect to the URI above
#
engine = create_engine(DATABASEURI)
#conn = engine.connect()
#
# START SQLITE SETUP CODE
#
# after these statements run, you should see a file test.db in your webserver/ directory
# this is a sqlite database that you can query like psql typing in the shell command line:
#
# sqlite3 test.db
#
# The following sqlite3 commands may be useful:
#
# .tables -- will list the tables in the database
# .schema <tablename> -- print CREATE TABLE statement for table
#
# The setup code should be deleted once you switch to using the Part 2 postgresql database
#
@app.before_request
def before_request():
"""
This function is run at the beginning of every web request
(every time you enter an address in the web browser).
We use it to setup a database connection that can be used throughout the request
The variable g is globally accessible
"""
try:
g.conn = engine.connect()
Table.connection = g.conn
except:
print "uh oh, problem connecting to database"
import traceback; traceback.print_exc()
g.conn = None
@app.teardown_request
def teardown_request(exception):
"""
At the end of the web request, this makes sure to close the database connection.
If you don't the database could run out of memory!
"""
try:
g.conn.close()
except Exception as e:
pass
@app.route('/', methods=["POST", "GET"])
def index(alert=None):
"""
User.create_table()
Post.create_table()
Comment.create_table()
GuessSetting.create_table()
Like.create_table()
"""
user = current_user
posts = Post.get_all([("pid", GuessSetting, "pid"), ("poster", User, "sid")])
posts = Post.prepare_view(user, posts)
return render_template("main.html", **{"posts": posts, "alert": alert})
@login_manager.user_loader
def load_user(email):
user = None
try:
user = User.select([Equal("email", "'%s'" % email)], [])
user = user[0] if user else None
except BaseException as e:
flash("Login failed")
print e
return user
@app.route('/login', methods=['GET', 'POST'])
def login():
email = request.form["email"]
password = request.form["password"]
user = User.select([Equal("email", "'%s'" % email)], [])
if (user and user[0].check_password(password)):
user = user[0]
user.authenticated = True
login_user(user)
else:
flash(u'Invalid login information')
return redirect("/")
@app.route('/comment', methods=['POST'])
def comment():
pid = int(request.json.get("pid"))
comment_body = request.json.get("comment_body")
user = current_user
if type(user.is_authenticated) == bool or not user.is_authenticated():
flash(u'Must be logged in to comment')
return redirect("/")
poster = user.sid
c = Comment(comment_body, poster, pid=pid)
c.save()
return redirect("/")
@app.route('/like', methods=['get'])
def like():
if type(current_user.is_authenticated) == bool or not current_user.is_authenticated():
flash(u'You must be logged in to like posts')
return redirect("/")
pid = int(request.args.get("pid"))
post = Post.select([Equal("pid", pid)], [])
filters = [Equal("pid", pid), Equal("sid", current_user.sid)]
filter = Filter.and_reduce(filters)
likes = Like.select(filter, [])
if not likes and post:
print("Like")
post = post[0]
post.like_count += 1
post.save()
l = Like(pid=pid, sid=current_user.sid)
l.save()
else:
flash("You can't like the same post twice")
return redirect("/")
@app.route('/guess', methods=['POST'])
def guess():
print("Guessing!")
print(request.json)
pid = int(request.json.get("pid"))
guess = request.json.get("guess", None)
post = Post.select([Equal("pid", pid)],
[("pid", GuessSetting, "pid"), ("poster", User, "sid")])[0]
gs = GuessSetting.select([Equal("gsid", post.gsid)], [])[0]
user = current_user
if not post.allow_guesses or not user.uni == post.tagged or gs.remaining < 1:
flash(u'Guessing not permitted')
return redirect("/")
gs.remaining -= 1
if guess is not None and guess == post.uni:
gs.matched = True
send_guessed_mail(post.email, user.uni)
send_guesser_mail(user.email, guess)
flash(u"You've found a match! You should go ahead and message them!")
print "MATCH!!!!! LOVE IS IN THE AIR"
else:
flash(u"Guess '%s' not matched :(" % guess)
gs.save()
return redirect("/")
@app.route('/search/user/<user>', methods=['GET'])
def search_user(user):
filters = []
user = user.replace("'", "")
if user != "":
filters.append(Equal("tagged", "'%s'" %user, GuessSetting.table))
posts = Post.select(filters, [("pid", GuessSetting, "pid"), ("poster", User, "sid")])
posts = Post.prepare_view(current_user, posts)
return render_template("main.html", **{"posts": posts})
@app.route('/search/id/<pid>', methods=['GET'])
def search_pid(pid):
filters = []
pid = pid.replace("'", "")
if pid != "":
filters.append(Equal("pid", pid))
posts = Post.select(filters, [("pid", GuessSetting, "pid"), ("poster", User, "sid")])
posts = Post.prepare_view(current_user, posts)
return render_template("main.html", **{"posts": posts})
@app.route('/search/tag/<tag>', methods=['GET'])
def search_tag(tag):
tag = tag.replace("'", "")
filters = []
if tag != "":
filters.append(Contains("tags", tag))
posts = Post.select(filters, [("pid", GuessSetting, "pid"), ("poster", User, "sid")])
posts = Post.prepare_view(current_user, posts)
return render_template("main.html", **{"posts": posts})
@app.route('/search', methods=['POST'])
def search():
text = request.json.replace("'", "")
pid = request.form.get("post_id", "").replace("'", "").replace(";", "")
contains = request.form.get("contains", "").replace("'", "").replace(";","")
tagged = request.form.get("tagged", "").replace("'", "").replace(";", "")
tags = request.form.get("tags", "").replace("'", "").replace(";", "")
filters = []
search_text = contains if contains != "" else text
if pid != "":
pid_filter = Equal("pid", int(pid))
filters.append(pid_filter)
if search_text != "" and search_text is not None:
filters.append(Contains("post_body", search_text))
if tagged != "" and tagged is not None:
filters.append(Contains("post_body", tagged))
for tag in [x for x in tags.split(",") if not x == ""]:
tag = tag.strip()
filters.append(Contains("tags", tag))
filters = Filter.and_reduce(filters)
posts = Post.select(filters, [("pid", GuessSetting, "pid"), ("poster", User, "sid")])
posts = Post.prepare_view(current_user, posts)
return render_template("main.html", **{"posts": posts})
@app.route('/own_posts', methods=['GET'])
@login_required
def own_posts():
filters = []
user = current_user
filters.append(Equal("poster", user.sid))
filters.append(Equal("is_anonymous", False))
filters = Filter.and_reduce(filters)
posts = Post.select(filters, [("pid", GuessSetting, "pid"), ("poster", User, "sid")])
posts = Post.prepare_view(user, posts)
return render_template("main.html", **{"posts": posts})
@app.route('/logout', methods=['GET'])
def logout():
logout_user()
flash(u'Successfully logged out')
return redirect("/")
@app.route('/faqs', methods=['GET'])
def faqs():
return render_template("faqs.html")
@app.route('/post', methods=['POST'])
def post():
post_body = request.form["post_body"]
is_anonymous = request.form.get("is_anonymous", None) == "on"
allow_guesses = request.form.get("allow_guesses", None) == "on"
user = current_user
if type(user.is_authenticated) == bool or not user.is_authenticated():
is_anonymous = True
allow_guesses = False
poster = tagged = None
if not is_anonymous or allow_guesses:
poster = user.sid
m = re.search(r"@([^_\W]+)", post_body)
if m:
tagged = m.group(1)
tags = re.findall(r"#([^_\W]+)", post_body)
tag_s = "" if tags else None
for tag in tags:
tag_s += "%s|" % tag
guesses = NUMBER_GUESSES if allow_guesses else 0
p = Post(post_body, approved=False, is_anonymous=is_anonymous, poster=poster, allow_guesses=allow_guesses, tags=tag_s)
p.save()
#like = Like(pid=p.pid, like_count=0)
#like.save(g.conn)
gs = GuessSetting(p.pid, tagged=tagged, num_guesses=guesses,
remaining=guesses)
if tagged is not None:
print tagged, p.pid
send_mail("%s@columbia.edu" % tagged, "Looks like someone admirers you! Checkout what they said at admirers.cloudapp.net/search/id/%s" % p.pid)
gs.save()
return redirect("/")
@app.route('/register', methods=['POST'])
def register():
email = request.form["email"]
if not "@columbia.edu" in email and not "@barnard.edu" in email:
flash(u'Invalid email address entered. Must use a valid CU or BU email')
return redirect("/")
try:
uni = email.split("@")[0]
first_name = request.form["first_name"]
last_name = request.form["last_name"]
raw_password = request.form["password"]
except:
flash("Invalid registration information. Ensure all fields are present.")
return redirect("/")
existing_user = User.select([Equal("email", "'%s'" % email)], [])
if existing_user:
flash("Account already created with that email..try logging in")
return redirect("/")
user = User(first_name, last_name, email, uni)
user.set_password(raw_password)
user.save()
login_user(user)
return redirect("/")
if __name__ == "__main__":
import click
@click.command()
@click.option('--debug', is_flag=True)
@click.option('--threaded', is_flag=True)
@click.argument('HOST', default='0.0.0.0')
@click.argument('PORT', default=8111, type=int)
def run(debug, threaded, host, port):
"""
This function handles command line parameters.
Run the server using
python server.py
Show the help text using
python server.py --help
"""
app.secret_key = 'super secret key'
#app.config['SESSION_TYPE'] = 'filesystem'
#session.init_app(app)
#sess = Session()
#sess.init_app(app)
debug=True
HOST, PORT = host, port
print "running on %s:%d" % (HOST, PORT)
app.run(host=HOST, port=PORT, debug=debug, threaded=threaded)
run()