1
#!/usr/bin/python
2
3
# Mouchak Server -
4
# A Flask Application (http://flask.pocoo.org/)
5
6
import flask
7
import pymongo
8
import bson
9
import conf
10
import os
11
from werkzeug import secure_filename
12
13
PLUGIN_UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__))
14
                                    + '/static/user_plugins')
15
PLUGIN_ALLOWED_EXTENSIONS = set(['js', 'css'])
16
17
FILE_UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)) +
18
                                  '/static/uploads')
19
20
app = flask.Flask(__name__)
21
22
23
24
dbClient = pymongo.MongoClient()
25
db = dbClient[conf.DB]
26
siteContent = db['content']
27
siteMenu = db['menu']
28
if siteMenu.find_one() == None:
29
    siteMenu.insert({'customMenu': False, 'menuOrder': [], 'html': ''})
30
31
32
# handy reference to otherwise long name
33
bson.ObjId = bson.objectid.ObjectId
34
35
36
def getContent():
37
    content = []
38
    for i in siteContent.find():
39
        objId = bson.ObjId(i['_id'])
40
        del(i['_id'])
41
        i['id'] = str(objId)
42
        content.append(i)
43
44
    menu = siteMenu.find_one()
45
    objId = bson.ObjId(menu['_id'])
46
    del(menu['_id'])
47
    menu['id'] = str(objId)
48
49
    return {'content': content, 'menu': menu}
50
51
52
def allowed_file(filename):
53
    return '.' in filename and \
54
            filename.rsplit('.', 1)[1] in PLUGIN_ALLOWED_EXTENSIONS
55
56
57
@app.errorhandler(404)
58
def pageNotFound(e):
59
    return flask.render_template('404.html'), 404
60
61
62
@app.route('/', methods=['GET'])
63
def index():
64
    return flask.render_template('index.html', content=getContent(),
65
                                 title=conf.SITE_TITLE, footer=conf.SITE_FOOTER)
66
67
68
@app.route('/edit', methods=['GET'])
69
def edit():
70
    if "logged_in" in flask.session:
71
        flask.session['key'] = conf.SECRET_KEY
72
        return flask.render_template('editor.html', content=getContent(),
73
                                     title=conf.SITE_TITLE)
74
    else:
75
        return flask.redirect(flask.url_for('login'))
76
77
78
@app.route('/page', methods=['POST'])
79
def insertPage():
80
    newpage = flask.request.json
81
    print newpage
82
    res = siteContent.insert(newpage)
83
    _id = bson.ObjId(res)
84
    newpage['id'] = str(_id)
85
    del(newpage['_id'])
86
    print newpage
87
    # FIXME: handle errors
88
    #return flask.jsonify(status='ok', page=newpage)
89
    return flask.jsonify(newpage)
90
91
92
@app.route('/page/<_id>', methods=['PUT', 'DELETE'])
93
def updatePage(_id):
94
    if flask.request.method == 'PUT':
95
        changedPage = flask.request.json
96
        print changedPage
97
        print '======='
98
        res = siteContent.update({'_id': bson.ObjId(_id)},
99
                                changedPage)
100
        print res
101
        if res['err'] == None:
102
            print changedPage
103
            #return flask.jsonify(status='ok', page=changedPage)
104
            return flask.jsonify(changedPage)
105
106
    elif flask.request.method == 'DELETE':
107
        delPage = flask.request.url
108
        print delPage
109
        print _id
110
        res = siteContent.remove({'_id': bson.ObjId(_id)})
111
        print res
112
        if res['err'] == None:
113
            return flask.jsonify(status='ok')
114
        else:
115
            return flask.jsonify(error=res['err'], status='error')
116
117
118
@app.route('/menu', methods=['POST'])
119
def insertMenu():
120
    #newmenu = flask.request.json
121
    #print newmenu
122
    #res = siteMenu.insert(newmenu)
123
    #print res
124
    #return flask.jsonify(status='success')#, content=getContent())
125
    return '200 OK'
126
127
128
@app.route('/menu/<_id>', methods=['PUT'])
129
def updateMenu(_id):
130
    if flask.request.method == 'PUT':
131
        changedMenu = flask.request.json
132
        print "changed menu:"
133
        print changedMenu
134
        res = siteMenu.update({'_id': bson.ObjId(_id)}, changedMenu)
135
        print res
136
        #return flask.jsonify(status='ok', menu=changedMenu)
137
        return flask.jsonify(changedMenu)
138
139
    #elif flask.request.method == 'DELETE':
140
    #    delMenu = flask.request.url
141
    #    print delMenu
142
    #    print _id
143
    #    res = siteMenu.remove({'_id': bson.ObjId(_id)})
144
    #    return flask.jsonify(status='deleted')
145
146
147
# Basic login for one single admin user whose credentials are in conf.py
148
@app.route('/login', methods=['GET', 'POST'])
149
def login():
150
    error = None
151
    if flask.request.method == 'POST':
152
        print flask.request.form
153
        if flask.request.form['username'] != conf.ADMIN_USERNAME:
154
            error = 'Invalid username'
155
        elif flask.request.form['password'] != conf.ADMIN_PASSWORD:
156
            error = 'Invaid password'
157
        else:
158
            flask.session['logged_in'] = True
159
            flask.session['key'] = conf.SECRET_KEY
160
            flask.flash('You were logged in')
161
            return flask.redirect(flask.url_for('edit'))
162
    return flask.render_template('login.html', error=error)
163
164
@app.route('/logout')
165
def logout():
166
    flask.session.pop('logged_in', None)
167
    flask.flash('You were logged out')
168
    return flask.redirect(flask.url_for('login'))
169
170
171
#TODO: refactor these code to classes
172
#TODO: find out if this is a good method for saving plugins..
173
@app.route('/static/user_plugins/<filename>', methods=['POST'])
174
def savePlugin(filename):
175
    if flask.request.method == 'POST':
176
        if filename and allowed_file(filename):
177
            data = flask.request.form['code']
178
            filename = secure_filename(filename)
179
            fh = open(os.path.join(PLUGIN_UPLOAD_FOLDER + '/' + filename), 'w')
180
            fh.write(data)
181
            fh.close()
182
            return flask.jsonify(saved = True)
183
184
#TODO: find out if this is a good method for uploading plugins..
185
@app.route('/upload/plugin', methods=['POST'])
186
def uploadPlugin():
187
    if flask.request.method == 'POST':
188
        print flask.request.files
189
        file = flask.request.files['plugin-file']
190
        if file and allowed_file(file.filename):
191
            filename = secure_filename(file.filename)
192
            file.save(os.path.join(app.config['PLUGIN_UPLOAD_FOLDER'],
193
                                   filename))
194
195
            #return flask.redirect(flask.url_for('uploaded_file',
196
            #            filename=filename))
197
            return flask.jsonify(uploaded = True,
198
                                 path=flask.url_for('static', filename =
199
                                                    'user_plugins/'+ filename))
200
201
@app.route('/robots.txt')
202
@app.route('/crossdomain.xml')
203
def static_from_root():
204
    return flask.send_from_directory(app.static_folder, request.path[1:])
205
206
207
app.config.from_object(conf)
208
app.config['PLUGIN_UPLOAD_FOLDER'] = PLUGIN_UPLOAD_FOLDER
209
210
import logging,os
211
from logging import FileHandler
212
213
fil = FileHandler(os.path.join(os.path.dirname(__file__),'logme'),mode='a')
214
fil.setLevel(logging.ERROR)
215
app.logger.addHandler(fil)
216
217
218
219
if __name__ == "__main__":
220
    app.run(debug=True, host=conf.HOST, port=conf.PORT)