Commit 0824b00
Changed files (7)
static/ffu.css
@@ -1,6 +1,20 @@
body {
padding-top: 60px;
}
-#upload_text {
+#form-upload {
+ padding: 15px;
+}
+#upload-zone {
+ margin-bottom: 0px;
+}
+#upload-text {
margin-bottom: 0px;
+ height: 55px;
+ line-height: 55px;
+}
+.top-padding {
+ margin-top:20px;
+}
+.bot-padding {
+ margin-bottom:20px;
}
static/ffu.js
@@ -0,0 +1,76 @@
+if (window.File && window.FileList) {
+ var form = $("#form-upload");
+ form.upload_zone = $("#upload-zone");
+ form.input_file = $("#fileselect");
+ form.file_list = $("#filelist");
+ form.upload_zone.files = new Array();
+ form.submit (function (e) {
+ e.preventDefault();
+
+ // generate formdata to upload
+ var file_data = new FormData(form);
+ for (var i=0, file; file=form.upload_zone.files[i]; i++){
+ file_data.append("fileselect" + i.toString(), file);
+ }
+
+ // send formdata to server
+ var request = new XMLHttpRequest();
+ request.open ($(this).attr("method"), $(this).attr("action"), true);
+ request.onload = function(oEvent) {
+ if (request.status == 200) {
+ form.upload_zone.innerHTML = "Uploaded!";
+ } else {
+ form.upload_zone.innerHTML = "Error " + request.status + " occurred uploading your file.<br \/>";
+ }
+ };
+ form.file_list.empty();
+ console.log("emptied");
+ request.send(file_data);
+ });
+
+ // manage meta-file array
+ var handleFiles = function (files) {
+ for (var i=0, file; file=files[i]; i++){
+ form.upload_zone.files.push (file);
+ form.file_list.append ("<li class='list-group-item'>"+file.name+"\t"+file.size+"B "+"</li>");
+ }
+ } // end handleFiles
+
+ // watch for changes in form-input-file element
+ form.input_file.change (function (event) {
+ handleFiles (form.input_file[0].files); // jquery get to FileList at [0]
+ });
+
+ // open input-file-multiple dialogue
+ form.upload_zone.click (function (event) {
+ form.input_file.focus();
+ form.input_file.click();
+ });
+
+} // end upload jquery functions
+
+$(document).on ('dragstart dragenter dragover', function (e) {
+ if ($.inArray('Files', e.originalEvent.dataTransfer.types) > -1) {
+ e.stopPropagation();
+ e.preventDefault();
+ $('#upload-zone').css('border', '2px dashed #0B85A1');
+ }
+});
+
+$(document).on ('dragleave dragged', function (e) {
+ e.stopPropagation();
+ e.preventDefault();
+ $('#upload-zone').css('border', '');
+});
+
+ $(document).on ('drop', function (e) {
+ e.stopPropagation();
+ e.preventDefault();
+ $('#upload-zone').css('border', '');
+ if (e.target.id =='upload-zone' || $(e.target).parent().is('#upload-zone')){
+ handleFiles(e.originalEvent.dataTransfer.files);
+ }
+});
+
+
+
static/signin.css
@@ -0,0 +1,39 @@
+body {
+ padding-top: 60px;
+ padding-bottom: 40px;
+}
+
+.form-signin {
+ max-width: 330px;
+ padding: 15px;
+ margin: 0 auto;
+}
+.form-signin .form-signin-heading,
+.form-signin .checkbox {
+ margin-bottom: 10px;
+}
+.form-signin .checkbox {
+ font-weight: normal;
+}
+.form-signin .form-control {
+ position: relative;
+ font-size: 16px;
+ height: auto;
+ padding: 10px;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.form-signin .form-control:focus {
+ z-index: 2;
+}
+.form-signin input[type="text"] {
+ margin-bottom: -1px;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.form-signin input[type="password"] {
+ margin-bottom: 10px;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
ffu.py
@@ -3,14 +3,50 @@ import tornado.web
import logging
import tarfile
import uuid
+import base64
from StringIO import StringIO
import os
+class BaseHandler(tornado.web.RequestHandler):
+ def get_login_url(self):
+ return u"/login"
+ def get_current_user(self):
+ user_json = self.get_secure_cookie("user")
+ if user_json:
+ return tornado.escape.json_decode(user_json)
+ else:
+ return None
+
+class LoginHandler(BaseHandler):
+ def get(self):
+ self.render('login.html', next=self.get_argument("next","/"))
+ def post(self):
+ print self
+ print vars(self)
+ username = self.get_argument("username", "")
+ password = self.get_argument("password", "")
+ print "login: ",username," ",password
+ auth = False
+ if username == "user" and password == "pass":
+ auth = True
+ if auth:
+ self.set_current_user(username)
+ self.redirect(self.get_argument("next","/"))
+ else:
+ error_msg = u"?error=" + tornado.escape.url_escape("Login Failed")
+ self.redirect(u"/login" + error_msg)
+ def set_current_user(self, user):
+ if user:
+ self.set_secure_cookie("user", tornado.escape.json_encode(user))
+ else:
+ self.clear_cookie("user")
+
+class LogoutHandler(BaseHandler):
+ def get(self):
+ self.clear_cookie("user")
+ self.redirect(u"/login")
+
class UploadHandler(tornado.web.RequestHandler):
-
-# def _handle_request_exception(self, e):
-# logging.error('error',e)
-
def get(self):
self.render("index.html")
@@ -27,15 +63,19 @@ class UploadHandler(tornado.web.RequestHandler):
f_info.size = len(f[0]['body'])
tar.addfile(f_info, StringIO(f[0]['body']))
tar.close()
- #self.render("index.html")
- settings = {
- "static_path": os.path.join(os.path.dirname(__file__),"static"),
+handlers = [
+ (r"/", UploadHandler),
+ (r"/login", LoginHandler),
+ (r"/logout", LogoutHandler),
+]
+
+settings = {
+ "static_path": os.path.join(os.path.dirname(__file__),"static"),
+ "cookie_secret": base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes),
}
-application = tornado.web.Application([
- (r"/", UploadHandler),
- ], debug=True, static_path=os.path.join(os.path.dirname(__file__),'static'))
+application = tornado.web.Application(handlers, **settings )
if __name__ == "__main__":
application.listen(8888)
index.html
@@ -32,97 +32,28 @@
</div>
<div class="container">
- <form id="upload" enctype="multipart/form-data" action="" method="post">
+ <form id="form-upload" enctype="multipart/form-data" action="" method="post">
<input type="file" id="fileselect" name="fileselect" multiple="multiple" style="display:none"/>
- <div id="upload_zone" class="well upload_zone">
- <p id="upload_text" class="lead text-center text-muted">Drop files or Click here</p>
+ <div class="row">
+ <div class="col-md-8 col-sm-8 bot-padding">
+ <div id="upload-zone" class="well upload-zone">
+ <p id="upload-text" class="lead text-center text-muted">Drop files or Click here</p>
+ </div>
+ </div>
+ <div class="col-md-4 col-sm-4 bot-padding">
+ <button class="btn btn-lg btn-default btn-block" type="submit">Upload</button>
+ <button class="btn btn-lg btn-default btn-block" type="reset">Clear</button>
+ </div>
</div>
+ <div class="row">
+ <div class="col-xs-12">
<ul id="filelist" class="list-group"></ul>
- <button type="submit">Upload</button>
+ </div>
+ </div>
</form>
</div><!-- /.container -->
+
<script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
- <script>
- if (window.File && window.FileList) {
- var form = $("#upload");
- form.upload_zone = $("#upload_zone");
- form.input_file = $("#fileselect");
- form.file_list = $("#filelist");
- form.upload_zone.files = new Array();
- form.submit (function (e) {
- e.preventDefault();
-
- // generate formdata to upload
- var file_data = new FormData(form);
- for (var i=0, file; file=form.upload_zone.files[i]; i++){
- file_data.append("fileselect" + i.toString(), file);
- }
-
- // send formdata to server
- var request = new XMLHttpRequest();
- request.open ($(this).attr("method"), $(this).attr("action"), true);
- request.onload = function(oEvent) {
- if (request.status == 200) {
- form.upload_zone.innerHTML = "Uploaded!";
- } else {
- form.upload_zone.innerHTML = "Error " + request.status + " occurred uploading your file.<br \/>";
- }
- };
- request.send(file_data);
- });
-
- // manage meta-file array
- var handleFiles = function (files) {
- for (var i=0, file; file=files[i]; i++){
- form.upload_zone.files.push (file);
- form.file_list.append ("<li class='list-group-item'>"+file.name+"</li>");
- }
- } // end handleFiles
-
- // watch for changes in form-input-file element
- form.input_file.change (function (event) {
- handleFiles (form.input_file[0].files); // jquery get to FileList at [0]
- });
-
- // open input-file-multiple dialogue
- form.upload_zone.click (function (event) {
- form.input_file.focus();
- form.input_file.click();
- });
-
- // TODO add clear button
- // TODO move upload up with upload_zone
- // TODO add X button area on list elements to remove each
- // TODO (python) send success message
- // TODO file name collisions deduplication
-
- } // end upload jquery functions
-
- $(document).on ('dragstart dragenter dragover', function (e) {
- if ($.inArray('Files', e.originalEvent.dataTransfer.types) > -1) {
- e.stopPropagation();
- e.preventDefault();
- $('#upload_zone').css('border', '2px dashed #0B85A1');
- }
- });
-
- $(document).on ('dragleave dragged', function (e) {
- e.stopPropagation();
- e.preventDefault();
- $('#upload_zone').css('border', '');
- });
-
- $(document).on ('drop', function (e) {
- e.stopPropagation();
- e.preventDefault();
- $('#upload_zone').css('border', '');
- if (e.target.id =='upload_zone' || $(e.target).parent().is('#upload_zone')){
- handleFiles(e.originalEvent.dataTransfer.files);
- }
- });
-
-
-
- </script>
+ <script src="{{ static_url("ffu.js") }}"></script>
</body>
login.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="description" content="">
+ <meta name="author" content="">
+ <link rel="shortcut icon" href="{{ static_url("images/favicon.ico")}}">
+ <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
+ <link rel="stylesheet" href="{{ static_url("signin.css") }}">
+</head>
+
+<body>
+ <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
+ <div class="container">
+ <div class="navbar-header">
+ <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
+ <span class="sr-only">Toggle navigation</span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ <a class="navbar-brand" href="#">FFU</a>
+ </div>
+ <div class="collapse navbar-collapse">
+ <ul class="nav navbar-nav">
+ <li class="active"><a href="#">Home</a></li>
+ <li><a href="#about">Admin</a></li>
+ </ul>
+ </div><!--/.nav-collapse -->
+ </div>
+ </div>
+
+ <div class="container">
+ <form class="form-signin" role="form" action="" method="post">
+ <input type="text" class="form-control" name="username" placeholder="Username" required autofocus>
+ <input type="password" class="form-control" name="password" placeholder="Password" required>
+ <!--<label class="checkbox">
+ <input type="checkbox" value="remember-me"> Remember me
+ </label>-->
+ <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
+ </form>
+ </div> <!-- /container -->
+ <script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
+ <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
+ <script src="{{ static_url("ffu.js") }}"></script>
+</body>
README.md
@@ -0,0 +1,8 @@
+TODO Auth
+TODO add clear button
+TODO move upload up with upload_zone
+TODO add X button area on list elements to remove each
+TODO (python) send success message
+TODO file name collisions deduplication
+TODO Disable Updload / Clear when appropriate
+