1
# -*- coding: utf-8 -*-
2
"""
3
    swtr
4
    ~~~~~~
5
6
    http://swtr.us
7
8
    :license: BSD, see LICENSE for more details.
9
"""
10
from __future__ import with_statement
11
from pymongo import Connection
12
from bson.objectid import ObjectId
13
from bson.errors import InvalidId
14
from flask import Flask, request, session, g, redirect, url_for, abort, \
15
     render_template, flash, _app_ctx_stack, make_response, jsonify
16
from urllib import unquote_plus
17
import json
18
import conf
19
20
# TODO:
21
#    restify
22
#    APIs as follows:
23
#        GET /sweets/q -> query sweets
24
#                         args: who, where, what, how
25
#        GET /sweets/<id> -> get specific sweet
26
#        POST /sweets -> post sweets (one or a batch of)
27
#        OPTIONS /sweets - > CORS policy .. understand it better
28
#   classes!
29
#   sqlAlchemy
30
#   Postgres
31
32
# TODO: move this in a config file
33
# configuration
34
DATABASE = 'alipiBlog'
35
COLLECTION_NAME = 'posts'
36
DEBUG = True
37
SECRET_KEY = conf.SECRET_KEY
38
USERNAME = 'admin'
39
PASSWORD = 'default'
40
DB_PORT = 27017
41
DB_HOST = 'localhost'
42
URL = "http://localhost:5001"
43
44
# create our little application :)
45
# ^ ... It's going to be big now :P
46
app = Flask(__name__)
47
app.config.from_object(__name__)
48
app.config.from_envvar('FLASKR_SETTINGS', silent=True)
49
50
# Jinja filters
51
app.jinja_env.filters['len'] = len
52
53
54
def validateSweet(payload):
55
    for i in payload:
56
        print i
57
        try:
58
            if len(i['who']) and len(i['what']) and len(i['where']) and\
59
               len(i['how']) and len(i['created']):
60
                pass
61
            else:
62
                return False
63
        except KeyError:
64
            return False
65
    return True
66
67
def getUsers():
68
    db = g.connection[app.config['DATABASE']]
69
    coll = db['sweet_users']
70
    users = []
71
    for i in coll.find():
72
        users.append(i['user'])
73
    return users
74
75
@app.before_request
76
def init_db():
77
    g.connection = Connection(app.config['DB_HOST'], app.config['DB_PORT'])
78
    db = g.connection[app.config['DATABASE']]
79
    g.collection = db[app.config["COLLECTION_NAME"]]
80
81
82
@app.teardown_request
83
def close_db(exception):
84
    g.connection.disconnect()
85
86
87
@app.errorhandler(404)
88
def page_not_found(e):
89
    return render_template('404.html'), 404
90
91
92
@app.errorhandler(500)
93
def internal_error(e):
94
    return render_template('500.html'), 500
95
96
@app.route('/')
97
def show_entries():
98
    print 'request:'
99
    print request.method
100
    print session
101
    res = g.collection.find().sort('_id', direction=-1)
102
    entries = make_list(res)
103
    return render_template('show_entries.html', entries=entries)
104
105
106
# TODO: understand if we really need the OPTIONS
107
@app.route('/sweets', methods=['POST', 'OPTIONS'])
108
@app.route('/add', methods=['POST', 'OPTIONS'])
109
def addSweets():
110
    print request.method
111
112
    if request.method == 'OPTIONS':
113
        response = make_response()
114
        response.status_code = 200
115
        response.headers['Access-Control-Allow-Origin'] = '*'
116
        response.headers['Access-Control-Max-Age'] = '20days'
117
        response.headers['Access-Control-Allow-Headers'] = 'Origin,\
118
                         X-Requested-With, Content-Type, Accept'
119
        return response
120
121
    response = make_response()
122
    response.headers['Access-Control-Allow-Origin'] = '*'
123
    response.headers['Access-Control-Allow-Headers'] = 'Origin,\
124
                     X-Requested-With, Content-Type, Accept'
125
    data = {}
126
    data_list = []
127
    # TODO: find a better way of handling reqeust sweets
128
    try:
129
        payload = json.loads(request.form['data'])
130
    except:
131
        try:
132
            payload = [{'who': request.form['who'], 'what': request.form['what'],
133
                    'where': request.form['where'], 'how': request.form['how']}]
134
            print payload
135
        except:
136
            try:
137
                payload = request.json
138
            except:
139
                payload = json.loads(request.data)
140
141
    if type(payload) is dict:
142
        payload = [payload]
143
144
    valid = validateSweet(payload)
145
    if not valid:
146
        response.status_code = 400
147
        response.data = "Bad or Malformed Request. Please check the validity\
148
        of your request"
149
        return response
150
    print 'swt payload rcvd..'
151
    print payload
152
    for i in payload:
153
        data = i
154
        id = g.collection.insert(i)
155
        data['permalink'] = app.config['URL'] + '/posts/' + str(ObjectId(id))
156
        data['id'] = str(ObjectId(id))
157
        del(data['_id'])
158
        print 'data', data
159
        data_list.append(data)
160
    response.data = json.dumps(data_list)
161
    print 'swt stored..'
162
    return response
163
164
165
@app.route('/login', methods=['GET', 'POST'])
166
def login():
167
    error = None
168
    if request.method == 'POST':
169
        db = g.connection[app.config['DATABASE']]
170
        collection = db['sweet_users']
171
        for i in collection.find():
172
            if i['user'] == request.form['username'] and i['key'] == request.form['password']:
173
                session['logged_in'] = True
174
                session['username'] = request.form['username']
175
                flash('You were logged in')
176
                res = g.collection.find({'who': request.form['username']})
177
178
                if res.count() < 1:
179
                    return render_template('show_entries.html', entries=[])
180
                swt_list = []
181
                for swt in res:
182
                    _id = swt['_id']
183
                    del(swt['_id'])
184
                    swt['id'] = str(_id)
185
                    swt_list.append(swt)
186
                return render_template('show_entries.html', entries=swt_list)
187
            else:
188
                pass
189
190
        if request.form['username'] != app.config['USERNAME']:
191
            error = 'Invalid username'
192
        elif request.form['password'] != app.config['PASSWORD']:
193
            error = 'Invalid password'
194
        else:
195
            session['logged_in'] = True
196
            session['isAdmin'] = True
197
            flash('You were logged in')
198
            return redirect(url_for('show_entries'))
199
    return render_template('login.html', error=error)
200
201
202
@app.route('/sweets/q', methods=['GET'])
203
def searchSweets():
204
    response = make_response()
205
    response.status_code = 200
206
    response.headers['Access-Control-Allow-Origin'] = '*'
207
    response.headers['Access-Control-Max-Age'] = '20days'
208
    response.headers['Access-Control-Allow-Headers'] = 'Origin,\
209
                      X-Requested-With, Content-Type, Accept'
210
211
    args = request.args
212
213
    if args is None:
214
        reponse.status_code = 400
215
        return response
216
217
    params = {}
218
219
    if args.get('who'):
220
        params['who'] = args.get('who')
221
    if args.get('where'):
222
        params['where'] = args.get('where')
223
    if args.get('what'):
224
        params['what'] = args.get('what')
225
    if args.get('how'):
226
        params['how'] = args.get('how')
227
228
    res = g.collection.find(params)
229
230
    if res.count() < 1:
231
        response.status_code = 404
232
        response.data = 'Not Found'
233
        return response
234
235
    swt_list = []
236
    for swt in res:
237
        _id = swt['_id']
238
        del(swt['_id'])
239
        swt['id'] = str(_id)
240
        swt_list.append(swt)
241
242
    response.data = json.dumps(swt_list)
243
    return response
244
245
246
@app.route('/sweets/<post_id>', methods=['GET'])
247
@app.route('/query/<post_id>',methods=['GET'])
248
def return_database_entry(post_id):
249
    try:
250
        res = g.collection.find_one({'_id':ObjectId(post_id)})
251
        if(res):
252
            res['blog'] = url_for('show_specific_entry', post_id = str(res['_id']))
253
            del(res['_id'])
254
            return jsonify(res)
255
            # entries = make_list(res)
256
            # return render_template('show_posts.html', entries=res, str=str)
257
        else:
258
            abort(404)
259
    except InvalidId:
260
        abort(404)
261
262
263
264
@app.route('/posts/<post_id>', methods=['GET', 'POST'])
265
def show_specific_entry(post_id):
266
    if request.method == 'GET':
267
        try:
268
            res = g.collection.find({'_id': ObjectId(post_id)})
269
            if(res.count() > 0):
270
                #entries = make_list(res)
271
                entries = []
272
                for i in res:
273
                    _id = i['_id']
274
                    del(i['_id'])
275
                    i['id'] = _id
276
                    entries.append(i)
277
                return render_template('show_posts.html', entries=entries, str=str)
278
            else:
279
                abort(404)
280
        except InvalidId:
281
            abort(404)
282
    else:
283
        how = {}
284
        for item in request.form:
285
            how[item] = request.form[item]
286
        try:
287
            g.collection.update({'_id': ObjectId(post_id)},
288
                                {"$set": {'how': how}})
289
            return redirect(url_for('show_specific_entry', post_id=post_id))
290
        except:
291
            abort(404)
292
293
@app.route('/posts/delete/', methods=['POST'])
294
def delete_post():
295
    try:
296
        g.collection.remove({'_id': ObjectId(request.form['post_id'])})
297
        return jsonify(status='ok')
298
    except:
299
        abort(500)
300
301
@app.route('/logout')
302
def logout():
303
    session.pop('logged_in', None)
304
    session.pop('username', None)
305
    session.pop('isAdmin', None)
306
    flash('You were logged out')
307
    return redirect(url_for('show_entries'))
308
309
@app.route('/serveUser')
310
def serveUser():
311
    if "logged_in" in session:
312
        #print session["logged_in"]
313
        session['key'] = conf.SECRET_KEY
314
        return render_template('user.html')
315
    else:
316
        return render_template('login.html', error=None)
317
318
@app.route('/user/', methods=['POST', 'GET'])
319
@app.route('/user/<user_id>', methods=['GET'])
320
def user(user_id='all'):
321
    if request.method == 'POST':
322
        response = make_response()
323
        db = g.connection[app.config['DATABASE']]
324
        collection = db['sweet_users']
325
326
        # check if user already exists
327
        if request.form['user'] in getUsers():
328
            #print 'user already exists!'
329
            flash('User already exists!')
330
            return redirect(url_for('serveUser'))
331
332
        # else insert new user
333
        collection.insert({'user': request.form['user'],
334
                           'key': request.form['key']})
335
        response.status_code = 200
336
        response.data = 'User added.'
337
        return response
338
339
    elif request.method == 'GET':
340
        db = g.connection[app.config['DATABASE']]
341
        collection = db['sweet_users']
342
        users = []
343
        if user_id == 'all':
344
            users = getUsers()
345
        else:
346
            user = collection.find_one({'user': user_id})
347
            if user:
348
                users.append(user['user'])
349
            else:
350
                abort(404)
351
        return render_template("users.html", users=users)
352
353
354
@app.route('/authenticate', methods=['POST', 'GET'])
355
def authenticate():
356
    if request.method == "POST":
357
        response = make_response()
358
        db = g.connection[app.config['DATABASE']]
359
        collection = db['sweet_users']
360
        for i in collection.find():
361
            if i['user'] == request.form['user'] and i['key'] == request.form['hash']:
362
                response.status_code = 200
363
                response.headers['Access-Control-Allow-Origin'] = '*'
364
                return response
365
            else:
366
                pass
367
        response.status_code = 403
368
        response.headers['Access-Control-Allow-Origin'] = '*'
369
        return response
370
    elif request.method == "GET":
371
        return app.send_static_file("sweet-authenticate.js")
372
373
374
def make_list(res):
375
    entries = []
376
    for row in res:
377
        d = row
378
        d['id'] = str(row['_id'])
379
        try:
380
            if d['who'] in getUsers() or d['author'] in getUsers():
381
                d['registered'] = True
382
        except KeyError:
383
            pass
384
        entries.append(d)
385
    return entries
386
387
if __name__ == '__main__':
388
    app.run(debug=True, port=5001)