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
    if args['where'] is None:
191
        reponse.status_code = 400
192
        return response
193
194
    res = g.collection.find(args)
195
196
    if res.count() < 1:
197
        response.status_code = 404
198
        return response
199
200
    swt_list = []
201
    for swt in res:
202
        _id = swt['_id']
203
        del(swt['_id'])
204
        swt['id'] = str(_id)
205
        swt_list.append(swt)
206
207
    response.data = json.dumps(swt_list)
208
    return response
209
210
211
@app.route('/sweets/<post_id>', methods=['GET'])
212
@app.route('/query/<post_id>',methods=['GET'])
213
def return_database_entry(post_id):
214
    try:
215
        res = g.collection.find_one({'_id':ObjectId(post_id)})
216
        if(res):
217
            res['blog'] = url_for('show_specific_entry', post_id = str(res['_id']))
218
            del(res['_id'])
219
            return jsonify(res)
220
            # entries = make_list(res)
221
            # return render_template('show_posts.html', entries=res, str=str)
222
        else:
223
            abort(404)
224
    except InvalidId:
225
        abort(404)
226
227
228
229
@app.route('/posts/<post_id>',methods=['GET'])
230
def show_specific_entry(post_id):
231
    try:
232
        res = g.collection.find({'_id':ObjectId(post_id)})
233
        if(res.count() > 0):
234
            #entries = make_list(res)
235
            entries = []
236
            for i in res:
237
                _id = i['_id']
238
                del(i['_id'])
239
                i['id'] = _id
240
                entries.append(i)
241
            return render_template('show_posts.html', entries=entries, str=str)
242
        else:
243
            abort(404)
244
    except InvalidId:
245
        abort(404)
246
247
248
@app.route('/posts/delete/', methods=['POST'])
249
def delete_post():
250
    try:
251
        g.collection.remove({'_id':ObjectId(request.form['post_id'])})
252
        return jsonify(status='ok')
253
    except:
254
        abort(500)
255
256
@app.route('/logout')
257
def logout():
258
    session.pop('logged_in', None)
259
    flash('You were logged out')
260
    return redirect(url_for('show_entries'))
261
262
@app.route('/serveUser')
263
def serveUser():
264
    if "logged_in" in session:
265
        #print session["logged_in"]
266
        session['key'] = conf.SECRET_KEY
267
        return render_template('user.html')
268
    else:
269
        return render_template('login.html', error=None)
270
271
@app.route('/user/', methods=['POST', 'GET'])
272
@app.route('/user/<user_id>', methods=['GET'])
273
def user(user_id='all'):
274
    if request.method == 'POST':
275
        response = make_response()
276
        db = g.connection[app.config['DATABASE']]
277
        collection = db['sweet_users']
278
279
        # check if user already exists
280
        if request.form['user'] in getUsers():
281
            #print 'user already exists!'
282
            flash('User already exists!')
283
            return redirect(url_for('serveUser'))
284
285
        # else insert new user
286
        collection.insert({'user': request.form['user'],
287
                           'key': request.form['key']})
288
        response.status_code = 200
289
        response.data = 'User added.'
290
        return response
291
292
    elif request.method == 'GET':
293
        db = g.connection[app.config['DATABASE']]
294
        collection = db['sweet_users']
295
        users = []
296
        if user_id == 'all':
297
            users = getUsers()
298
        else:
299
            user = collection.find_one({'user': user_id})
300
            if user:
301
                users.append(user['user'])
302
            else:
303
                abort(404)
304
        return render_template("users.html", users=users)
305
306
307
@app.route('/authenticate', methods=['POST','GET'])
308
def authenticate():
309
    if request.method == "POST":
310
        response = make_response()
311
        db = g.connection[app.config['DATABASE']]
312
        collection = db['sweet_users']
313
        for i in collection.find():
314
            if i['user'] == request.form['user'] and i['key'] == request.form['hash']:
315
                response.status_code = 200
316
                response.headers['Access-Control-Allow-Origin'] = '*'
317
                return response
318
            else:
319
                pass
320
        response.status_code = 403
321
        response.headers['Access-Control-Allow-Origin'] = '*'
322
        return response
323
    elif request.method == "GET":
324
        return app.send_static_file("sweet-authenticate.js")
325
326
327
def make_list(res):
328
    entries = []
329
    for row in res:
330
        d = row
331
        d['id'] = str(row['_id'])
332
        try:
333
            if d['who'] in getUsers() or d['author'] in getUsers():
334
                d['registered'] = True
335
        except KeyError:
336
            pass
337
        entries.append(d)
338
    return entries
339
340
if __name__ == '__main__':
341
    app.run(debug=True, port=5001)