import logging import os import configparser import re from pathlib import Path from flask import Flask, render_template, request from flask_dropzone import Dropzone from flask_migrate import Migrate, MigrateCommand from flask_script import Manager from portal.model import db import portal.base ENABLED_FILETYPES = ['txt', 'csv', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'xml', 'mxliff', 'tmx'] REGEX_EMAIL = re.compile('^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$') # TODO: make logging level configurable logging.basicConfig(level=logging.DEBUG, format='[APP LOGGER] %(asctime)s %(levelname)s: %(message)s') ###################### # Load configuration # ###################### config = configparser.ConfigParser() config.read('config.ini') config = config['DEFAULT'] MAIL_HOST = config['MAIL_HOST'] MAIL_LOGIN = config['MAIL_LOGIN'] MAIL_PASS = config['MAIL_PASS'] SMTP_PORT = int(config['SMTP_PORT']) IMAP_PORT = int(config['IMAP_PORT']) MAX_UPLOAD_SIZE = int(config['MAX_UPLOAD_SIZE']) # Bytes MAX_FILES_PER_UPLOAD = int(config['MAX_FILES_PER_UPLOAD']) CONTRACT_CLIENT_CONTACT = config['CONTRACT_CLIENT_CONTACT'] MAIL_SUBJECT = config['MAIL_SUBJECT'] MAIL_BODY = config['MAIL_BODY'] SQL_CONN_STR = config['SQL_CONN_STR'] DESC_PREVODI = config['DESC_PREVODI'] DESC_GIGAFIDA = config['DESC_GIGAFIDA'] if 'UPLOADS_DIR' in config: UPLOADS_DIR = Path(config['UPLOADS_DIR']) else: UPLOADS_DIR = Path(__file__).resolve().parent / 'uploads' if not UPLOADS_DIR.exists: UPLOADS_DIR.mkdir(parents=True) # Override configs with environment variables, if set if 'PORTALDS4DS1_MAIL_HOST' in os.environ: MAIL_HOST = os.environ['PORTALDS4DS1_MAIL_HOST'] if 'PORTALDS4DS1_MAIL_LOGIN' in os.environ: MAIL_LOGIN = os.environ['PORTALDS4DS1_MAIL_LOGIN'] if 'PORTALDS4DS1_MAIL_PASS' in os.environ: MAIL_PASS = os.environ['PORTALDS4DS1_MAIL_PASS'] if 'PORTALDS4DS1_SMTP_PORT' in os.environ: SMTP_PORT = int(os.environ['PORTALDS4DS1_SMTP_PORT']) if 'PORTALDS4DS1_IMAP_PORT' in os.environ: IMAP_PORT = int(os.environ['PORTALDS4DS1_IMAP_PORT']) if 'PORTALDS4DS1_MAX_UPLOAD_SIZE' in os.environ: MAX_UPLOAD_SIZE = int(os.environ['PORTALDS4DS1_MAX_UPLOAD_SIZE']) if 'PORTALDS4DS1_MAX_FILES_PER_UPLOAD' in os.environ: MAX_FILES_PER_UPLOAD = int(os.environ['PORTALDS4DS1_MAX_FILES_PER_UPLOAD']) if 'PORTALDS4DS1_CONTRACT_CLIENT_CONTACT' in os.environ: CONTRACT_CLIENT_CONTACT = os.environ['PORTALDS4DS1_CONTRACT_CLIENT_CONTACT'] if 'PORTALDS4DS1_UPLOADS_DIR' in os.environ: UPLOADS_DIR = os.environ['PORTALDS4DS1_UPLOADS_DIR'] if 'PORTALDS4DS1_MAIL_SUBJECT' in os.environ: MAIL_SUBJECT = os.environ['PORTALDS4DS1_MAIL_SUBJECT'] if 'PORTALDS4DS1_MAIL_BODY' in os.environ: MAIL_BODY = os.environ['PORTALDS4DS1_MAIL_BODY'] if 'PORTALDS4DS1_SQL_CONN_STR' in os.environ: SQL_CONN_STR = os.environ['PORTALDS4DS1_SQL_CONN_STR'] if 'PORTALDS4DS1_DESC_PREVODI' in os.environ: DESC_PREVODI = os.environ['PORTALDS4DS1_DESC_PREVODI'] if 'PORTALDS4DS1_DESC_GIGAFIDA' in os.environ: DESC_GIGAFIDA = os.environ['PORTALDS4DS1_DESC_GIGAFIDA'] VALID_CORPUS_NAMES = ['prevodi', 'gigafida', 'solar'] ###################### app = Flask(__name__) app.config.update( UPLOADED_PATH = UPLOADS_DIR, MAX_CONTENT_LENGTH = MAX_UPLOAD_SIZE, TEMPLATES_AUTO_RELOAD = True, SQLALCHEMY_DATABASE_URI = SQL_CONN_STR, SQLALCHEMY_ECHO = True ) # Run "python app.py db -?" to see more info about DB migrations. manager = Manager(app) db.init_app(app) migrate = Migrate(app, db) manager.add_command('db', MigrateCommand) # Set up dropzone.js to serve all the stuff for "file dropping" on the web interface. dropzone = Dropzone(app) upload_handler = portal.base.UploadHandler( UPLOADS_DIR=UPLOADS_DIR, MAIL_HOST=MAIL_HOST, MAIL_LOGIN=MAIL_LOGIN, MAIL_PASS=MAIL_PASS, SMTP_PORT=SMTP_PORT, IMAP_PORT=IMAP_PORT, MAIL_SUBJECT=MAIL_SUBJECT, MAIL_BODY=MAIL_BODY, CONTRACT_CLIENT_CONTACT=CONTRACT_CLIENT_CONTACT ) @app.route('/') def index(): return render_template('index.html') @app.route('/') def index_corpus(corpus_name): if corpus_name not in VALID_CORPUS_NAMES: return 'Korpus "{}" ne obstaja.'.format(corpus_name), 404 if corpus_name == 'prevodi': description = DESC_PREVODI elif corpus_name == 'gigafida': description = DESC_GIGAFIDA elif corpus_name == 'solar': return handle_solar(request) return render_template('basic.html', corpus_name=corpus_name, description=description, max_files=MAX_FILES_PER_UPLOAD) def handle_solar(request): return 404 @app.route('//upload', methods=['POST']) def handle_upload(corpus_name): if corpus_name not in VALID_CORPUS_NAMES: return 404 if corpus_name == 'solar': return handle_upload_solar(request) else: return handle_upload_unauthenticated(request, corpus_name) def handle_upload_solar(request): return 404 def handle_upload_unauthenticated(request, corpus_name): files = request.files if len(files) > MAX_FILES_PER_UPLOAD: return 'Naložite lahko do {} datotek hkrati.'.format(MAX_FILES_PER_UPLOAD), 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 # Parse request. upload_metadata = upload_handler.extract_upload_metadata(corpus_name, request) logging.info('Upload with id "{}" supplied form data: {}'.format(upload_metadata['upload_id'], str(upload_metadata['form_data']))) # Generate contract PDF file based on the uploads metadata. upload_handler.generate_upload_contract_pdf(upload_metadata) # Store uploaded files to disk. upload_handler.store_datafiles(files, upload_metadata) # Store metadata to database. upload_handler.store_metadata_unauthenticated(upload_metadata) # Send confirmation mail along with the contract to the submitted email address. upload_handler.send_confirm_mail(upload_metadata) 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): ime = form.get('ime') podjetje = form.get('podjetje') naslov = form.get('naslov') posta = form.get('posta') email = form.get('email') telefon = form.get('telefon') 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.' if len(naslov) > 100: return 'Predolg naslov.' if len(posta) > 100: return 'Predolga pošta' return None if __name__ == '__main__': app.run(debug=True)