commit 8996dbcefe46d6559d6183d4969467f330278a5d Author: msinkec Date: Fri Oct 23 10:07:14 2020 +0200 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ebc422c --- /dev/null +++ b/.gitignore @@ -0,0 +1,142 @@ +uploads/* +!uploads/.gitkeep + + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ diff --git a/app.py b/app.py new file mode 100644 index 0000000..0aa3aa7 --- /dev/null +++ b/app.py @@ -0,0 +1,149 @@ +import os +import re +import hashlib +import time +from pathlib import Path + +from flask import Flask, render_template, request +from flask_dropzone import Dropzone + + +enabled_filetypes = ['txt', 'csv', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'] +regex_email = re.compile('^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$') +basedir = Path(__file__).resolve().parent +upload_dir = basedir / 'uploads' +if not upload_dir.exists: + upload_dir.mkdir() + +app = Flask(__name__) + +app.config.update( + UPLOADED_PATH = upload_dir, + MAX_CONTENT_LENGTH = 1000000000 # 1GB +) + +dropzone = Dropzone(app) + + +@app.route('/') +def index(): + return render_template('index.html') + + +@app.route('/upload', methods=['POST']) +def handle_upload(): + files = request.files + if len(files) > 20: + return 'Naložite lahko do 20 datotek hkrati.', 400 + elif len(files) < 1: + return 'Priložena ni bila nobena datoteka.', 400 + + err = check_suffixes(files) + if err: + return err, 400 + + err = check_form(request.form) + if err: + return err, 400 + + file_hashes = create_file_hashes(files) + + store_metadata(request.form, file_hashes) + store_datafiles(files, file_hashes) + return 'Uspešno ste oddali datotek(e). Št. datotek: {}'.format(len(files)) + + +def check_suffixes(files): + for key, f in files.items(): + if key.startswith('file'): + suffix = f.filename.split('.')[-1] + if suffix not in enabled_filetypes: + return 'Datoteka "{}" ni pravilnega formata.'.format(f.filename) + return None + + +def check_form(form): + tip = form.get('tip') + ime = form.get('ime') + podjetje = form.get('podjetje') + email = form.get('email') + telefon = form.get('telefon') + + if tip not in ['enojez', 'prevodi']: + return 'Napačen tip besedila.' + + if len(ime) > 100: + return 'Predolgo ime.' + + if len(podjetje) > 100: + return 'Predolgo ime institucije' + + if len(email) > 100: + return 'Predolgi email naslov' + elif not re.search(regex_email, email): + return 'Email napačnega formata.' + + if len(telefon) > 100: + return 'Predolga telefonska št.' + + return None + + +def create_file_hashes(files): + res = dict() + for key, f in files.items(): + if key.startswith('file'): + h = hashlib.md5(f.filename.encode()) + h.update(f.stream.read()) + res[key] = h.hexdigest() + f.seek(0) + return res + + +def store_metadata(form, file_hashes): + base = app.config['UPLOADED_PATH'] / 'meta' + if not base.exists(): + base.mkdir() + + tip = form.get('tip') + ime = form.get('ime') + podjetje = form.get('podjetje') + email = form.get('email') + telefon = form.get('telefon') + + # This hash serves as an identifier for the whole upload. + metahash = hashlib.md5((tip+ime+podjetje+email+telefon).encode()) + # Include file hashes to avoid metafile name collisions if they have the same form values, + # but different data files. Sort hashes first so upload order doesn't matter. + sorted_f_hashes = list(file_hashes.values()) + sorted_f_hashes.sort() + metahash.update(''.join(sorted_f_hashes).encode()) + metahash = metahash.hexdigest() + + timestamp = int(time.time()) + filename = str(timestamp) + '-' + email + '-' + metahash + '.meta' + + path = base / filename + with path.open('w') as f: + f.write('tip=' + tip) + f.write('\nime=' + ime) + f.write('\npodjetje=' + podjetje) + f.write('\nemail=' + email) + f.write('\ndatoteke=' + str(sorted_f_hashes)) + + +def store_datafiles(files, file_hashes): + base = app.config['UPLOADED_PATH'] / 'files' + if not base.exists(): + base.mkdir() + + for key, f in files.items(): + if key.startswith('file'): + path = base / file_hashes[key] + if not path.exists(): + path.mkdir() + f.save(path / f.filename) + + +if __name__ == '__main__': + app.run(debug=True) diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..24272e4 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,135 @@ + + + + + Portal za oddajanje besedil za DS4 in DS1 + {{ dropzone.load_css() }} + + + +

Portal za oddajanje besedil za DS4 in DS1

+
+
+ + + + + + + + + + + + + + + + + + + +
+ +
+
+{{ dropzone.load_js() }} + + + diff --git a/uploads/.gitkeep b/uploads/.gitkeep new file mode 100644 index 0000000..e69de29