From 1d593744cace6fa44757c77b06803b5738707889 Mon Sep 17 00:00:00 2001 From: Anon Ray Date: Tue, 21 Jan 2014 18:38:11 +0530 Subject: [PATCH] Add uploads support Add basic uploads support. This should improve both in terms of UI and in terms of robustness, and functionality. --- mouchak/server.py | 44 ++++++++++++++++-- mouchak/static/js/editor.js | 100 ++++++++++++++++++++++++++++++++++++++++- mouchak/templates/editor.html | 43 ++++++++++++++++-- 3 files changed, 180 insertions(+), 7 deletions(-) diff --git a/mouchak/server.py b/mouchak/server.py index 22b65f3..1cccfda 100644 --- a/mouchak/server.py +++ b/mouchak/server.py @@ -34,7 +34,10 @@ from werkzeug import secure_filename PLUGIN_UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)) + '/static/user_plugins') -PLUGIN_ALLOWED_EXTENSIONS = set(['js', 'css']) + +ALLOWED_EXTENSIONS = set(['js', 'css', 'jpg', 'JPG', 'png', 'gif', 'PNG', + 'svg', 'pdf']) +#ALLOWED_EXTENSIONS = set(['js', 'css']) FILE_UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)) + '/static/uploads') @@ -92,7 +95,7 @@ def getContent(): def allowed_file(filename): return '.' in filename and \ - filename.rsplit('.', 1)[1] in PLUGIN_ALLOWED_EXTENSIONS + filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS @app.errorhandler(404) @@ -299,9 +302,43 @@ def uploadPlugin(): #return flask.redirect(flask.url_for('uploaded_file', # filename=filename)) return flask.jsonify(uploaded = True, - path=flask.url_for('static', filename = + path=flask.url_for('static', filename =\ 'user_plugins/'+ filename)) +@app.route('/upload', methods=['GET', 'POST']) +def upload(): + if flask.request.method == 'POST': + print flask.request.files + file = flask.request.files['upload-file'] + if file and allowed_file(file.filename): + print 'file ok' + filename = secure_filename(file.filename) + file.save(os.path.join(app.config['FILE_UPLOAD_FOLDER'], filename)) + + return flask.jsonify(uploaded = True, path =\ + flask.url_for('static', filename =\ + 'uploads/' + filename)) + + else: + resp = flask.make_response() + print 'file not ok' + resp.status_code = 400 + return resp + + if flask.request.method == 'GET': + uploaded_files = os.listdir(app.config['FILE_UPLOAD_FOLDER']) + print uploaded_files + return flask.jsonify({'uploaded_files': uploaded_files}) + +@app.route('/upload/', methods=['DELETE']) +def removeFile(filename): + filepath = os.path.join(app.config['FILE_UPLOAD_FOLDER'], filename) + print filepath + res = os.remove(filepath) + print res + return '200 OK' + + @app.route('/robots.txt') @app.route('/crossdomain.xml') def static_from_root(): @@ -310,6 +347,7 @@ def static_from_root(): app.config.from_object(conf) app.config['PLUGIN_UPLOAD_FOLDER'] = PLUGIN_UPLOAD_FOLDER +app.config['FILE_UPLOAD_FOLDER'] = FILE_UPLOAD_FOLDER import logging,os from logging import FileHandler diff --git a/mouchak/static/js/editor.js b/mouchak/static/js/editor.js index ca6ab8c..824f709 100644 --- a/mouchak/static/js/editor.js +++ b/mouchak/static/js/editor.js @@ -11,7 +11,8 @@ 'click .pagename .remove': 'removePage', 'click #menu-config': 'showMenu', 'click #footer-config': 'showFooterConfig', - 'click #header-config': 'showHeaderConfig' + 'click #header-config': 'showHeaderConfig', + 'click #uploads': 'uploads' }, initialize: function() { _.bindAll.apply(_, [this].concat(_.functions(this))); @@ -30,6 +31,7 @@ this.footerconfigview = new FooterConfigView({model: this.footerconfig}); this.headerconfig = new M.types.model.header(M.site_content.header); this.headerconfigview = new HeaderConfigView({model: this.headerconfig}); + this.uploadview = new UploadView(); }, render: function() { // append the page list @@ -102,6 +104,11 @@ this.headerconfigview.render(); return false; }, + uploads: function(event) { + event.preventDefault(); + this.uploadview.render(); + return false; + }, // validate the page list with menu order list validate: function() { //TODO: validate if the menu order list matches with the list of pages @@ -672,6 +679,97 @@ } }); + /* Upload View */ + var UploadView = Backbone.View.extend({ + tagName: 'div', + className: 'prettybox-lg', + id: 'page', + events: { + 'click #upload-new-file': 'uploadFile', + 'click .uploaded-item .remove': 'removeFile' + }, + initialize: function() { + _.bindAll.apply(_, [this].concat(_.functions(this))); + this.template = _.template($('#uploads-template').html()); + }, + render: function() { + $('#page').remove(); + $('#content-container').append(this.$el); + //console.log('rendering..', this.$el); + var uploaded_files, self = this; + M.editor.showOverlay(); + $.ajax({ + url: '/upload', + type: 'GET', + success: function(data) { + M.editor.hideOverlay(); + self.$el.html(self.template({ + })); + self.appendFileListTemplate(data.uploaded_files); + self.delegateEvents(); + } + }); + }, + appendFileListTemplate: function(files) { + var template = _.template($('#uploaded-item-template').html()); + if(files.length) { + _.each(files, function(file) { + $('#uploads-list').append(template({ + filename: file + })); + }); + } + else { + $('#uploads-list').html(' No files uploaded yet '); + } + }, + uploadFile: function() { + //console.log('upload file'); + var self = this; + M.editor.showOverlay(); + var $form = $('#file-upload-form')[0]; + var formdata = new FormData($form); + $.ajax({ + type: 'POST', + url: '/upload', + data: formdata, + processData: false, + contentType: false, + success: function(response) { + M.editor.hideOverlay(); + M.editor.notifs.show('success', 'Success', 'File uploaded'); + self.render(); + }, + error: function(jqxhr, status, error) { + M.editor.hideOverlay(); + if(error === 'BAD REQUEST') { + var msg = 'File format not allowed. Please contact your administrator to allow this kind of file.' + } else { + var msg = 'Something went wrong. Please try again!'; + } + M.editor.notifs.show('fail', 'Error!', msg); + } + }); + }, + removeFile: function(event) { + M.editor.showOverlay(); + //console.log('remove file'); + var self = this; + var filename = $(event.currentTarget).attr('for'); + $.ajax({ + type: 'DELETE', + url: '/upload/' + filename, + success: function(data) { + M.editor.hideOverlay(); + self.render(); + }, + error: function(jqxhr, status, error) { + console.log(arguments); + } + }); + } + }); + /* The global editor object. * All high-level editor operations are defined here. */ diff --git a/mouchak/templates/editor.html b/mouchak/templates/editor.html index f22095d..b2b2bfc 100644 --- a/mouchak/templates/editor.html +++ b/mouchak/templates/editor.html @@ -26,6 +26,7 @@ M.HeaderURL = function() { return "{{ url_for('insertHeader') }}"; }; M.PageURL = function() { return "{{ url_for('insertPage') }}"; }; M.PluginUploadURL = function() { return "{{ url_for('uploadPlugin') }}"; }; + M.UploadsURL = function() { return "{{ url_for('static', filename='uploads/') }}"; }; M.site_content = {{ content|tojson|safe }}; window.onload = function() { M.editor.init(); @@ -143,6 +144,7 @@

Header

Footer

Navigation Menu

+

Uploads

Go to site

@@ -194,7 +196,7 @@ title of the page -
+
@@ -334,7 +336,7 @@
- +
@@ -405,4 +407,39 @@
+ + + + {% endblock %} -- 1.7.10.4