"""This is the main flask distribusi page""" import os import zipfile import shutil from datetime import timedelta from flask import ( render_template, redirect, request, flash, url_for, session, abort, send_from_directory, ) from sqlalchemy.exc import ( IntegrityError, DataError, DatabaseError, InterfaceError, InvalidRequestError, ) from flask_login import ( login_user, logout_user, login_required, current_user, ) from werkzeug.routing import BuildError from flask_bcrypt import generate_password_hash, check_password_hash from flask_wtf.csrf import CSRFError from app import create_app, db, login_manager from usermodel import User # Forms! from forms.loginform import LoginForm from forms.registerform import RegisterForm from forms.uploadform import UploadForm from forms.distribusiform import DistribusiForm from forms.themeform import ThemeForm from forms.editorform import EditorForm # Tada! from distribusi.cli import build_argparser from distribusi.distribusi import distribusify APP = create_app() @APP.before_request def session_handler(): session.permanent = True APP.permanent_session_lifetime = timedelta(minutes=1) @APP.route("/") def index(): users = User.query.filter(User.distribusiname.isnot(None)).all() distribusinames = [] for user in users: distribusinames.append(user.distribusiname) return render_template("index.html", distribusinames=distribusinames) @APP.route("/login", methods=["GET", "POST"]) def login(): loginform = LoginForm() if loginform.validate_on_submit(): try: user = User.query.filter_by(email=loginform.email.data).first() if check_password_hash(user.password, loginform.password.data): login_user(user) flash("Logged in successfully.", "success") next = request.args.get("next") if next is not None and not is_safe_url(next): # noqa: F821 return abort(400) return redirect(next or url_for("index")) else: flash("Invalid Username or password!", "danger") loginform.password.errors.append("Invalid email or password!") return render_template("login.html", loginform=loginform) except Exception as e: flash(e, "danger") return render_template("login.html", loginform=loginform) @APP.route("/register", methods=["GET", "POST"]) def register(): registerform = RegisterForm() if registerform.validate_on_submit(): try: email = registerform.email.data password = registerform.confirmpassword.data newuser = User( email=email, password=generate_password_hash(password), ) db.session.add(newuser) db.session.commit() flash("Account Succesfully created", "success") login_user(newuser) return redirect(url_for("index")) except InvalidRequestError: db.session.rollback() flash("Something went wrong!", "danger") except IntegrityError: db.session.rollback() flash("User already exists!.", "warning") except DataError: db.session.rollback() flash("Invalid Entry", "warning") except InterfaceError: db.session.rollback() flash("Error connecting to the database", "danger") except DatabaseError: db.session.rollback() flash("Error connecting to the database", "danger") except BuildError: db.session.rollback() flash("An error occured !", "danger") return render_template("register.html", registerform=registerform) @APP.route("/distribusi", methods=["GET", "POST"]) @login_required def distribusi(): uploadform = UploadForm() distribusiform = DistribusiForm() themeform = ThemeForm() user = User.query.filter_by(email=current_user.email).first() if user.distribusiname is None: print("nothing to deploy!") if distribusiform.validate_on_submit(): zipfilename = "{}.zip".format(user.distribusiname) userfolder = os.path.join("stash", user.distribusiname) unzipfile = os.path.join(userfolder, zipfilename) if os.path.exists(unzipfile): with zipfile.ZipFile(unzipfile, "r") as zip_ref: # To do, replace extractall with inspection and extract zip_ref.extractall(userfolder) if os.path.exists(unzipfile): os.remove(os.path.join(userfolder, zipfilename)) # To Do: Make sure nothing can be executed from the upload folder # add the css file cssfile = "" for filename in os.listdir(userfolder): if filename.endswith(".css"): cssfile = os.path.join(userfolder, filename) parser = build_argparser() args = parser.parse_args(["-s", cssfile]) distribusify(args, userfolder) return redirect(url_for("index")) template = render_template( "distribusi.html", uploadform=uploadform, distribusiform=distribusiform, themeform=themeform, ) return template @APP.route("/upload", methods=["POST"]) @login_required def upload(): success = False uploadform = UploadForm() distribusiform = DistribusiForm() themeform = ThemeForm() if uploadform.validate_on_submit(): user = User.query.filter_by(email=current_user.email).first() user.distribusiname = uploadform.sitename.data db.session.commit() zipfilename = "{}.zip".format(user.distribusiname) zipfile = uploadform.zipfile.data zipfile.save(os.path.join(APP.config["UPLOAD_FOLDER"], zipfilename)) newuserfolder = os.path.join("stash", user.distribusiname) if not os.path.exists(newuserfolder): os.mkdir(newuserfolder) copyzipfile = os.path.join(APP.config["UPLOAD_FOLDER"], zipfilename) shutil.copy(copyzipfile, newuserfolder) os.remove(os.path.join(APP.config["UPLOAD_FOLDER"], zipfilename)) success = True template = render_template( "distribusi.html", uploadform=uploadform, distribusiform=distribusiform, success=success, themeform=themeform, ) return template @APP.route("/theme", methods=["GET", "POST"]) @login_required def theme(): uploadform = UploadForm() distribusiform = DistribusiForm() themeform = ThemeForm() if themeform.validate_on_submit(): user = User.query.filter_by(email=current_user.email).first() newuserfolder = os.path.join("stash", user.distribusiname) copycssfile = os.path.join( "themes", "{}.css".format(themeform.theme.data), ) shutil.copy(copycssfile, newuserfolder) template = render_template( "distribusi.html", uploadform=uploadform, distribusiform=distribusiform, themeform=themeform, ) return template @APP.route("/editor", methods=["GET", "POST"]) @login_required def editor(): editorform = EditorForm() user = User.query.filter_by(email=current_user.email).first() files_uploaded = True if user.distribusiname is None: files_uploaded = False print("no folder to add css to!") if editorform.validate_on_submit(): userfolder = os.path.join("stash", user.distribusiname) cssfilename = "{}.css".format(editorform.cssname.data) with open(os.path.join(userfolder, cssfilename), 'w') as cssfile: cssfile.write(editorform.css.data) cssfile.close template = render_template( "editor.html", files_uploaded=files_uploaded, editorform=editorform, ) return template @APP.route("/stash/") def distribusistash(path): return send_from_directory("stash", path) @APP.route("/admin") @login_required def admin(): return "admin" @APP.route("/logout") @login_required def logout(): logout_user() return redirect(url_for("index")) @APP.errorhandler(CSRFError) def handle_csrf_error(e): return render_template("csrf_error.html", reason=e.description), 400 @login_manager.user_loader def load_user(user_id): return User.query.get(int(user_id)) if __name__ == "__main__": APP.debug = True APP.run(port=5000)