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
        try:
57
            if len(i['who']) and len(i['what']) and len(i['where']) and\
58
               len(i['how']) and len(i['created']):
59
                pass
60
            else:
61
                return False
62
        except KeyError:
63
            return False
64
    return True
65
66
def getUsers():
67
    db = g.connection[app.config['DATABASE']]
68
    coll = db['sweet_users']
69
    users = []
70
    for i in coll.find():
71
        users.append(i['user'])
72
    return users
73
74
@app.before_request
75
def init_db():
76
    g.connection = Connection(app.config['DB_HOST'], app.config['DB_PORT'])
77
    db = g.connection[app.config['DATABASE']]
78
    g.collection = db[app.config["COLLECTION_NAME"]]
79
80
81
@app.teardown_request
82
def close_db(exception):
83
    g.connection.disconnect()
84
85
86
@app.errorhandler(404)
87
def page_not_found(e):
88
    return render_template('404.html'), 404
89
90
91
@app.errorhandler(500)
92
def internal_error(e):
93
    return render_template('500.html'), 500
94
95
@app.route('/')
96
def show_entries():
97
    print 'request:'
98
    print request.method
99
    res = g.collection.find().sort('_id',direction=-1)
100
    entries = make_list(res)
101
    return render_template('show_entries.html', entries=entries)
102
103
104
# TODO: understand if we really need the OPTIONS
105
@app.route('/sweets', methods=['POST', 'OPTIONS'])
106
@app.route('/add', methods=['POST', 'OPTIONS'])
107
def addSweets():
108
    print request.method
109
110
    if request.method == 'OPTIONS':
111
        response = make_response()
112
        response.status_code = 200
113
        response.headers['Access-Control-Allow-Origin'] = '*'
114
        response.headers['Access-Control-Max-Age'] = '20days'
115
        response.headers['Access-Control-Allow-Headers'] = 'Origin,\
116
                         X-Requested-With, Content-Type, Accept'
117
        return response
118
119
    response = make_response()
120
    response.headers['Access-Control-Allow-Origin'] = '*'
121
    response.headers['Access-Control-Allow-Headers'] = 'Origin,\
122
                     X-Requested-With, Content-Type, Accept'
123
    data = {}
124
    data_list = []
125
    # TODO: find a better way of handling reqeust sweets
126
    try:
127
        payload = json.loads(request.form['data'])
128
    except:
129
        try:
130
            payload = [{'who': request.form['who'], 'what': request.form['what'],
131
                    'where': request.form['where'], 'how': request.form['how']}]
132
        except:
133
            try:
134
                payload = request.json
135
            except:
136
                payload = json.loads(request.data)
137
138
139
    valid = validateSweet(payload)
140
    if not valid:
141
        response.status_code = 400
142
        response.data = "Bad or Malformed Request. Please check the validity\
143
        of your request"
144
        return response
145
    print 'swt payload rcvd..'
146
    print payload
147
    for i in payload:
148
        data = i
149
        id = g.collection.insert(i)
150
        data['permalink'] = app.config['URL'] + '/posts/' + str(ObjectId(id))
151
        data['id'] = str(ObjectId(id))
152
        del(data['_id'])
153
        print 'data', data
154
        data_list.append(data)
155
    response.data = json.dumps(data_list)
156
    print 'swt stored..'
157
    return response
158
159
160
@app.route('/login', methods=['GET', 'POST'])
161
def login():
162
    error = None
163
    if request.method == 'POST':
164
        if request.form['username'] != app.config['USERNAME']:
165
            error = 'Invalid username'
166
        elif request.form['password'] != app.config['PASSWORD']:
167
            error = 'Invalid password'
168
        else:
169
            session['logged_in'] = True
170
            flash('You were logged in')
171
            return redirect(url_for('show_entries'))
172
    return render_template('login.html', error=error)
173
174
175
@app.route('/sweets/q', methods=['GET'])
176
def searchSweets():
177
    response = make_response()
178
    response.status_code = 200
179
    response.headers['Access-Control-Allow-Origin'] = '*'
180
    response.headers['Access-Control-Max-Age'] = '20days'
181
    response.headers['Access-Control-Allow-Headers'] = 'Origin,\
182
                      X-Requested-With, Content-Type, Accept'
183
184
    args = request.args
185
186
    if args is None:
187
        reponse.status_code = 400
188
        return response
189
190
    params = {}
191
192
    if args.get('who'):
193
        params['who'] = args.get('who')
194
    if args.get('where'):
195
        params['where'] = args.get('where')
196
    if args.get('what'):
197
        params['what'] = args.get('what')
198
    if args.get('how'):
199
        params['how'] = args.get('how')
200
201
    res = g.collection.find(params)
202
203
    if res.count() < 1:
204
        response.status_code = 404
205
        response.data = 'Not Found'
206
        return response
207
208
    swt_list = []
209
    for swt in res:
210
        _id = swt['_id']
211
        del(swt['_id'])
212
        swt['id'] = str(_id)
213
        swt_list.append(swt)
214
215
    response.data = json.dumps(swt_list)
216
    return response
217
218
219
@app.route('/sweets/<post_id>', methods=['GET'])
220
@app.route('/query/<post_id>',methods=['GET'])
221
def return_database_entry(post_id):
222
    try:
223
        res = g.collection.find_one({'_id':ObjectId(post_id)})
224
        if(res):
225
            res['blog'] = url_for('show_specific_entry', post_id = str(res['_id']))
226
            del(res['_id'])
227
            return jsonify(res)
228
            # entries = make_list(res)
229
            # return render_template('show_posts.html', entries=res, str=str)
230
        else:
231
            abort(404)
232
    except InvalidId:
233
        abort(404)
234
235
236
237
@app.route('/posts/<post_id>',methods=['GET'])
238
def show_specific_entry(post_id):
239
    try:
240
        res = g.collection.find({'_id':ObjectId(post_id)})
241
        if(res.count() > 0):
242
            #entries = make_list(res)
243
            entries = []
244
            for i in res:
245
                _id = i['_id']
246
                del(i['_id'])
247
                i['id'] = _id
248
                entries.append(i)
249
            return render_template('show_posts.html', entries=entries, str=str)
250
        else:
251
            abort(404)
252
    except InvalidId:
253
        abort(404)
254
255
256
@app.route('/posts/delete/', methods=['POST'])
257
def delete_post():
258
    try:
259
        g.collection.remove({'_id':ObjectId(request.form['post_id'])})
260
        return jsonify(status='ok')
261
    except:
262
        abort(500)
263
264
@app.route('/logout')
265
def logout():
266
    session.pop('logged_in', None)
267
    flash('You were logged out')
268
    return redirect(url_for('show_entries'))
269
270
@app.route('/serveUser')
271
def serveUser():
272
    if "logged_in" in session:
273
        #print session["logged_in"]
274
        session['key'] = conf.SECRET_KEY
275
        return render_template('user.html')
276
    else:
277
        return render_template('login.html', error=None)
278
279
@app.route('/user/', methods=['POST', 'GET'])
280
@app.route('/user/<user_id>', methods=['GET'])
281
def user(user_id='all'):
282
    if request.method == 'POST':
283
        response = make_response()
284
        db = g.connection[app.config['DATABASE']]
285
        collection = db['sweet_users']
286
287
        # check if user already exists
288
        if request.form['user'] in getUsers():
289
            #print 'user already exists!'
290
            flash('User already exists!')
291
            return redirect(url_for('serveUser'))
292
293
        # else insert new user
294
        collection.insert({'user': request.form['user'],
295
                           'key': request.form['key']})
296
        response.status_code = 200
297
        response.data = 'User added.'
298
        return response
299
300
    elif request.method == 'GET':
301
        db = g.connection[app.config['DATABASE']]
302
        collection = db['sweet_users']
303
        users = []
304
        if user_id == 'all':
305
            users = getUsers()
306
        else:
307
            user = collection.find_one({'user': user_id})
308
            if user:
309
                users.append(user['user'])
310
            else:
311
                abort(404)
312
        return render_template("users.html", users=users)
313
314
315
@app.route('/authenticate', methods=['POST','GET'])
316
def authenticate():
317
    if request.method == "POST":
318
        response = make_response()
319
        db = g.connection[app.config['DATABASE']]
320
        collection = db['sweet_users']
321
        for i in collection.find():
322
            if i['user'] == request.form['user'] and i['key'] == request.form['hash']:
323
                response.status_code = 200
324
                response.headers['Access-Control-Allow-Origin'] = '*'
325
                return response
326
            else:
327
                pass
328
        response.status_code = 403
329
        response.headers['Access-Control-Allow-Origin'] = '*'
330
        return response
331
    elif request.method == "GET":
332
        return app.send_static_file("sweet-authenticate.js")
333
334
335
def make_list(res):
336
    entries = []
337
    for row in res:
338
        d = row
339
        d['id'] = str(row['_id'])
340
        try:
341
            if d['who'] in getUsers() or d['author'] in getUsers():
342
                d['registered'] = True
343
        except KeyError:
344
            pass
345
        entries.append(d)
346
    return entries
347
348
if __name__ == '__main__':
349
    app.run(debug=True, port=5001)