zip download, and proper config

This commit is contained in:
2018-01-26 14:49:23 +02:00
parent bfaa3467cb
commit 454ea7875c
6 changed files with 119 additions and 32 deletions

View File

@@ -1,23 +1,26 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os,sys import os,sys,time
import json import json
from datetime import datetime from datetime import datetime
from flask import Flask, render_template, jsonify, \ from flask import Flask, render_template, jsonify, \
redirect, url_for, request, g, session, send_from_directory redirect, url_for, request, g, session, send_file, send_from_directory
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
import hashlib import hashlib
import zipfile
from revprox import ReverseProxied from revprox import ReverseProxied
app = Flask(__name__) app = Flask(__name__)
app.config.from_object(__name__) app.config.from_object(__name__)
# Read config from json ! # Read config from json !
app.config['UPLOAD_FOLDER'] = 'data/' config_values = json.load(open(os.getenv('FLEES_CONFIG'),'rt'))
app.config['SHARES_FILE'] = 'data/shares.json' app.config['UPLOAD_FOLDER'] = config_values['data_folder']
app.config['DATE_FORMAT'] = "%Y-%m-%d %H:%M" app.config['SHARES_FILE'] = config_values['shares_file']
app.config['UID'] = 1000 app.config['ZIP_FOLDER'] = config_values['zip_folder']
app.config['DEBUG'] = False app.config['DATE_FORMAT'] = config_values['date_format']
app.config['UID'] = config_values['uid']
app.config['DEBUG'] = config_values['debug']
app.secret_key = 'Cz2dw5NiRt3PSMFBSLTAJJi7U2CdW7iPQqEeOaU6' app.secret_key = 'Cz2dw5NiRt3PSMFBSLTAJJi7U2CdW7iPQqEeOaU6'
app.wsgi_app = ReverseProxied(app.wsgi_app) app.wsgi_app = ReverseProxied(app.wsgi_app)
@@ -151,6 +154,8 @@ def download_direct(name,password,filename):
@app.route('/download/<name>/<password>/<filename>', methods=['GET']) @app.route('/download/<name>/<password>/<filename>', methods=['GET'])
@app.route('/download/<name>/<filename>', methods=['GET']) @app.route('/download/<name>/<filename>', methods=['GET'])
def download_file(name,filename,password = None): def download_file(name,filename,password = None):
if password != None:
session[name] = password
(ok,share) = get_share(name) (ok,share) = get_share(name)
if not ok: if not ok:
return share return share
@@ -159,14 +164,33 @@ def download_file(name,filename,password = None):
return 'no such file', 404 return 'no such file', 404
return send_from_directory(directory=share['path'], filename=filename) return send_from_directory(directory=share['path'], filename=filename)
@app.route('/zip/<name>/<password>', methods=['GET'])
@app.route('/zip/<name>', methods=['GET'])
def download_zip(name,password = None):
if password != None:
session[name] = password
(ok,share) = get_share(name)
if not ok:
return share
zip_clean()
zip_path = zip_share(share)
return send_file(
zip_path,
as_attachment = True,
attachment_filename = name + ".zip"
)
def file_stat(filename): def file_stat(filename):
s = os.stat(filename) s = os.stat(filename)
return { return {
'size': file_size_human(s.st_size), 'size': file_size_MB(s.st_size),
'mtime': file_date_human(s.st_mtime), 'mtime': file_date_human(s.st_mtime),
'name': os.path.basename(filename) 'name': os.path.basename(filename)
} }
def file_size_human(num): def file_size_human(num):
for x in ['&nbsp;B','KB','MB','GB','TB']: for x in ['&nbsp;B','KB','MB','GB','TB']:
if num < 1024.0: if num < 1024.0:
@@ -175,6 +199,10 @@ def file_size_human(num):
return "%3.1f&nbsp;%s" % (num, x) return "%3.1f&nbsp;%s" % (num, x)
num /= 1024.0 num /= 1024.0
def file_size_MB(num):
return "%0.2f"%(num/(1024*1024),)
def file_date_human(num): def file_date_human(num):
return datetime.fromtimestamp( return datetime.fromtimestamp(
num num
@@ -244,6 +272,44 @@ def print_debug(s):
sys.stderr.write(str(s)+"\n") sys.stderr.write(str(s)+"\n")
sys.stderr.flush() sys.stderr.flush()
def zip_share(share):
if not os.path.exists(app.config['ZIP_FOLDER']):
os.makedirs(app.config['ZIP_FOLDER'])
os.chown(app.config['ZIP_FOLDER'], app.config['UID'], -1)
zip_path = os.path.join(
app.config['ZIP_FOLDER'],
"%s-%d.zip"%(
share['name'],
time.time()
)
)
zf = zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED)
for file in sorted(os.listdir(share['path'])):
print_debug(os.path.join(share['path'],file))
zf.write(
os.path.join(share['path'],file),
arcname = os.path.join(share['name'],file)
)
zf.close()
os.chown(zip_path, app.config['UID'], -1)
return zip_path
def zip_clean():
""" delete zip files older than 1 hour """
if not os.path.exists(app.config['ZIP_FOLDER']):
return
for file in os.listdir(app.config['ZIP_FOLDER']):
if not file.endswith("zip"):
continue
mtime = os.stat(
os.path.join(app.config['ZIP_FOLDER'],file)
).st_mtime
if mtime + 3600 < time.time():
os.remove(os.path.join(app.config['ZIP_FOLDER'],file))
if __name__ == "__main__": if __name__ == "__main__":
app.run(debug=True) app.run(debug=True)

View File

@@ -49,8 +49,11 @@ tr:nth-child(even) {
clear: both; clear: both;
} }
#list_left {
float: left;
}
#list_title { #list_title {
float:left;
margin-left: 5em; margin-left: 5em;
} }
@@ -59,10 +62,21 @@ tr:nth-child(even) {
padding: 8px; padding: 8px;
border: 4px solid lightslategray; border: 4px solid lightslategray;
background-color: #f3f3fb; background-color: #f3f3fb;
line-height: 1.5em;
} }
#list_menu ul {
margin-top: 0px;
}
#list_table { #list_table {
border-collapse: collapse; border-collapse: collapse;
margin-left: 2em; margin-left: 2em;
line-height: 1.5em;
}
.direct {
margin-right: 1em;
} }
/* index */ /* index */
@@ -77,6 +91,7 @@ tr:nth-child(even) {
padding: 8px; padding: 8px;
border: 4px solid lightslategray; border: 4px solid lightslategray;
background-color: #f3f3fb; background-color: #f3f3fb;
line-height: 2em;
} }
#index_table { #index_table {

View File

@@ -1,9 +1,10 @@
<!doctype html> <!doctype html>
<head> <head>
<title>Flees</title> <title>Flees</title>
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/styles.css') }}"> <link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/styles.css') }}">
<script src="{{ url_for('static', filename='js/tablesort.js') }}" type="text/javascript"></script> <script src="{{ url_for('static', filename='js/tablesort.js') }}" type="text/javascript"></script>
<script src="{{ url_for('static', filename='js/scripts.js') }}" type="text/javascript"></script> <script src="{{ url_for('static', filename='js/scripts.js') }}" type="text/javascript"></script>
<meta name="viewport" content="width=800" />
</head> </head>
<body> <body>
<div class=page> <div class=page>

View File

@@ -1,6 +1,5 @@
{% extends "layout.html" %} {% extends "layout.html" %}
{% block body %} {% block body %}
<div id=list_title><h1>{{ name }}</h1></div>
<div id=list_menu> <div id=list_menu>
{% if upload %} {% if upload %}
<div id=list_upload> <div id=list_upload>
@@ -9,9 +8,6 @@
<input type=file name=file onchange="document.getElementById('list_upload_button').disabled = false;"> <input type=file name=file onchange="document.getElementById('list_upload_button').disabled = false;">
<input id="list_upload_button" type=submit value=Upload disabled> <input id="list_upload_button" type=submit value=Upload disabled>
</form> </form>
{% if overwrite == false %}
Overwriting disabled
{% endif %}
</div> </div>
{% else %} {% else %}
<div id=list_upload> <div id=list_upload>
@@ -19,44 +15,49 @@
<input type=submit value=Upload disabled> <input type=submit value=Upload disabled>
</div> </div>
{% endif %} {% endif %}
<div id=list_public> <div id=list_info>
Share:
<ul>
{% if public %} {% if public %}
Share is <a href="{{ url_for('index') }}">public</a> <li>is <a href="{{ url_for('index') }}">public</a>
{% else %} {% else %}
Share is <a href="{{ url_for('index') }}">unlisted</a> <li>is <a href="{{ url_for('index') }}">unlisted</a>
{% endif %} {% endif %}
</div>
<div id=list_expire>
{% if expire %} {% if expire %}
Share expires {{ expire }} <li>expires {{ expire }}
{% else %} {% else %}
Share never expires <li>never expires
{% endif %} {% endif %}
{% if overwrite == false %}
<li>overwriting is disabled
{% endif %}
<li><a href="{{ url_for('download_zip',name=name) }}">Download as zip</a>
<li><a href="{{ url_for('logout',name=name) }}">Logout</a>
</div>
</div> </div>
<div id=list_logout> <div id=list_left>
<a href="{{ url_for('logout',name=name) }}">Logout</a> from this share <div id=list_title><h1>{{ name }}</h1></div>
</div>
</div>
<div class=clear></div>
<table class="sortable" id="list_table"> <table class="sortable" id="list_table">
<thead> <thead>
<tr> <tr>
<th>Name <th>Name
<th class=td_right>Size <th class=td_right>Size(MB)
<th>Mod.Time <th>Mod.Time
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for entry in entries %} {% for entry in entries %}
<tr> <tr>
<td><a href="{{ url_for('download_file', name = name, filename = entry.name) }}">{{ entry.name }}</a> <td>
{% if direct %} {% if direct %}
&nbsp;<a href="{{ url_for('download_direct', name = name, password = entry.token, filename = entry.name ) }}" title="Direct share link">&#x2756;</a> <a href="{{ url_for('download_direct', name = name, password = entry.token, filename = entry.name ) }}" title="Direct share link" class=direct>&#x2756;</a>
{% endif %} {% endif %}
<a href="{{ url_for('download_file', name = name, filename = entry.name) }}">{{ entry.name }}</a>
<td class=td_right>{{ entry.size|safe }} <td class=td_right>{{ entry.size|safe }}
<td>{{ entry.mtime|safe }} <td>{{ entry.mtime|safe }}
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div>
{% endblock %} {% endblock %}

View File

@@ -9,6 +9,9 @@ services:
- "${FLEES_EXPOSE}:80" - "${FLEES_EXPOSE}:80"
volumes: volumes:
- ./data/:/code/data/ - ./data/:/code/data/
environment:
- FLEES_CONFIG
restart: unless-stopped restart: unless-stopped

View File

@@ -1 +1,2 @@
FLEES_EXPOSE=127.0.0.1:8136 FLEES_EXPOSE=127.0.0.1:8136
FLEES_CONFIG=data/config.json