from app import app from flask import render_template, url_for, request, flash, redirect, session, make_response, send_from_directory import json from markupsafe import escape from werkzeug.utils import secure_filename import os import re from app.forms import ImageForm, ImageUpload from app.models.sites import DataSite from app.models.blocs import MyBlocs from PIL import Image from flask_bcrypt import Bcrypt from copy import deepcopy from app.forms import Login, CreateWebsite from functools import wraps from app.utils import login_required, list_type_blocs, list_type_pages from flask_wtf.csrf import CSRFProtect from datetime import datetime csrf = CSRFProtect(app) app.secret_key = 'your_secret_key' app.config.from_pyfile('config.py') THEMES_FOLDER = '/themes/' USERS_FOLDER = app.config['USERS_FOLDER'] bcrypt = Bcrypt(app) EXT_IMG = {'.jpg', '.JPG', '.png', '.PNG', '.gif', '.GIF', '.bmp', '.BMP', '.jpeg', '.JPEG' } @app.route('/login', methods=['GET', 'POST']) def login(): form = Login() if 'username' in session : resp = redirect(url_for('edit', _external=True)) else : resp = redirect(url_for('login', _external=True)) if request.method == 'POST' : login = str(request.form['login']) password = str(request.form['passwd']) if login in os.listdir(USERS_FOLDER): db = DataSite(login, USERS_FOLDER) db.load_file() passwd_bcrypt = db.datas['config']['passwd'] if bcrypt.check_password_hash(passwd_bcrypt, password) is True: session['username'] = login resp = redirect(url_for('edit', _external=True)) else: flash(u'Mauvais mot de passe', 'error') else: resp = render_template('/admin/login.html', form=form) return resp @app.route( '/logout', methods=['GET'] ) @login_required def logout(): session.pop('username', None) # Supprimer username de la session s'il s'y trouve session.clear() return redirect(url_for('login')) @app.route ('/new-website', methods=[ 'GET' ]) def new_website(): form = CreateWebsite() return render_template('/admin/create_website.html', form=form) @app.route('/create-website', methods=[ 'POST']) def create_website(): form = CreateWebsite(request.form) login = str(form.login.data) passwd = str(form.passwd.data) theme = str(form.theme.data) if form.validate(): db = DataSite(login, USERS_FOLDER) if db.create(theme): db.set_passwd(bcrypt.generate_password_hash(passwd)) session['username'] = login resp = redirect(url_for('edit')) else: flash(u'Erreur lors de la création du site', error) resp = redirect(url_for('login', _external=True)) else: resp = render_template('/admin/create_website.html', form=form) return resp @app.route('/', methods=['GET'], defaults={'page': ''}) @app.route('//', methods=['GET']) @login_required def edit(page): user = '%s'% escape(session['username']) page = '%s' % escape(page) db = DataSite(user, USERS_FOLDER) db.load_file() type_pages = list_type_pages(db.datas['config']['theme']) type_blocs = list_type_blocs(db.datas['config']['theme']) myblocs = db.get_blocs(page) footer = db.get_footer() return render_template('/edit.html.tpl', blocEdit="", config=db.datas['config'], menu=db.datas['menu'], footer=footer, type_blocs=type_blocs, type_pages=type_pages, theme=db.datas['config']['theme'], pagesList=db.get_pages(), page=page, myblocs=myblocs, serverInfos=db.datas['publish'] ) @app.route('/edit/images//', methods=['GET', 'POST'], defaults={'page': ''}) @app.route('//edit/images//', methods=['GET', 'POST']) @login_required def edit_img(page, image, bloc): user = '%s'% escape(session['username']) page = '%s' % escape(page) image = '%s' % escape(image) bloc = '%s' % escape(bloc) db = DataSite(user, USERS_FOLDER) db.load_file() theme = db.datas['config']['theme'] form = ImageForm() myblocs = db.get_blocs(page) if form.validate_on_submit(): if request.method == 'POST': myblocs[bloc][image] = db.update_img(image, form) db.save_blocs(page, myblocs) form = MyBlocs.make_form() if "hx-request" in request.headers: return make_response(('Image modified', 200)) else: return redirect ('/'+page+'#'+bloc) else: return render_template(THEMES_FOLDER+theme+'/blocs/edit/_image-edit.html', form=form, page=page, image=myblocs[bloc][image], bloc=myblocs[bloc]) @app.route('/upload-gallery/', methods=['POST'], defaults={'page': ''}) @app.route('//upload-gallery/', methods=['POST']) @login_required def drop_upload(page, bloc): user = '%s'% escape(session['username']) page = '%s' % escape(page) db = DataSite(user, USERS_FOLDER) db.load_file() datas = dict() file = request.files['file'] filename = secure_filename(file.filename) myblocs = db.get_blocs(page)['blocs'] ext = os.path.splitext(filename)[-1] save_path = os.path.join(USERS_FOLDER, user, 'public', 'img' ) if ext not in EXT_IMG : return make_response(('Le fichier n\'est pas une image', 400)) current_chunk = int(request.form['dzchunkindex']) if (os.path.isfile(os.path.join(save_path, filename ))) and current_chunk == 0: return make_response(('Un fichier avec le même nom existe déjà', 400)) try: with open(os.path.join(save_path, filename ), 'ab') as f: f.seek(int(request.form['dzchunkbyteoffset'])) f.write(file.stream.read()) except OSError: return make_response(("Une erreur est survenue," " Impossible d'écrire le fichier sur le disque", 500)) total_chunks = int(request.form['dztotalchunkcount']) if current_chunk + 1 == total_chunks: # This was the last chunk, the file should be complete and the size we expect if os.path.getsize(os.path.join(save_path, filename )) != int(request.form['dztotalfilesize']): return make_response(('La taille du fichier source est différentes', 500)) else: with Image.open(os.path.join(save_path, filename )) as img : img.thumbnail((640,480)) img.save(os.path.join(save_path, 'thumbnails', filename ) ) myblocs[bloc][filename] = db.add_img(filename) db.save_blocs(page, myblocs) return make_response(('Chunk upload succesfull', 200)) @app.route('/edit/images//del/', methods=['GET'], defaults={'page': ''}) @app.route('//edit/images//del/', methods=['GET']) @login_required def del_image(page, bloc, image): user = '%s'% escape(session['username']) page = '%s' % escape(page) db = DataSite(user, USERS_FOLDER) db.load_file() myblocs = db.get_blocs(page)['blocs'] myblocs[bloc] = db.del_img(myblocs[bloc], image) db.save_blocs(page, myblocs) return make_response(('Image removed', 200)) @app.route('/imgs_list/', methods=['GET'], defaults={'page': ''}) @app.route('//imgs_list/', methods=['GET']) @login_required def images_list(page, blocname): user = '%s'% escape(session['username']) page = '%s' % escape(page) blocname = '%s' % escape(blocname) db = DataSite(user, USERS_FOLDER) db.load_file() theme = db.datas['config']['theme'] myblocs = db.get_blocs(page) bloc = myblocs[blocname] return render_template(THEMES_FOLDER+theme+'/blocs/edit/images_list.html',page=page, bloc=bloc) @app.route('/edit/', methods=['GET', 'POST'], defaults={'page': ''}) @app.route('//edit/', methods=['GET', 'POST']) @login_required def edit_bloc(page, blocname): user = '%s'% escape(session['username']) page = '%s' % escape(page) db = DataSite(user, USERS_FOLDER) db.load_file() theme = db.datas['config']['theme'] myblocs = db.get_blocs(page) bloc = myblocs[blocname] form = MyBlocs.make_form() if request.method == 'POST': datas=dict() if form.validate_on_submit(): for field, value in request.form.items(): if field != 'csrf_token' and field != 'image': myblocs[blocname][field] = value if 'image' in request.files.keys(): file = request.files['image'] filename = secure_filename(file.filename) bg_custom = 'bg_custom_'+bloc['name']+filename file.save(os.path.join(USERS_FOLDER, user, 'public', 'img', bg_custom )) if 'bg_img' in bloc.keys(): db.del_img(bloc, bloc['bg_img']) myblocs[blocname]['bg_img'] = bg_custom db.save_blocs(page, myblocs) flash(u'Vos changements on été pris en compte et enregistré', 'success') else: print(form.errors) if "hx-request" in request.headers: resp = render_template(THEMES_FOLDER+theme+'/blocs/'+bloc['type']+'.html', theme=theme, page=page, bloc=myblocs[blocname]) else: resp = redirect(url_for('edit', page=page)) else: if "hx-request" in request.headers: resp = render_template(THEMES_FOLDER+theme+'/blocs/edit/'+bloc['type']+'.html', theme=theme, bloc=bloc, page=page, form=form) else: resp = render_template('/edit.html.tpl', config=db.datas['config'], menu=db.datas['menu'], myblocs=myblocs, page=page, theme=theme, blocEdit=bloc['name'], form=form) return resp @app.route('/view/', methods=['GET'], defaults={'page': ''}) @app.route('//view/', methods=['GET']) @login_required def view_bloc(page, bloc): user = '%s'% escape(session['username']) page = '%s' % escape(page) db = DataSite(user, USERS_FOLDER) db.load_file() theme = db.datas['config']['theme'] myblocs = db.get_blocs(page) bloc = myblocs[bloc] return render_template(THEMES_FOLDER+theme+'/blocs/'+bloc['type']+'.html', bloc=bloc) @app.route('/addBloc', methods=['POST'], defaults={'page': ''}) @app.route('//addBloc', methods=['POST']) @login_required def add_bloc(page): user = '%s'% escape(session['username']) page = '%s' % escape(page) db = DataSite(user, USERS_FOLDER) db.load_file() datas = dict() print("page add bloc :" + page) myblocs = db.get_blocs(page)['blocs'] blocName = '%s' % escape(request.form['blocName']) blocType = request.form['blocType'] bloc = MyBlocs.new(blocName, blocType, db.datas['config']['theme']) test_name = "^[A-Za-z0-9_-]*$" if bloc != None: if bool(re.match(test_name, blocName)) : myblocs[blocName] = { 'name': blocName, 'type': blocType} flash (u'Bloc ajouté avec succès', 'succes'); else: return make_response(('Invalid bloc Name', 500)) db.save_blocs(page, myblocs) if page == '': return redirect("/#"+blocName) else: return redirect("/"+page+"#"+blocName) @app.route('/addPage', methods=['POST']) @login_required def add_page(): user = '%s'% escape(session['username']) db = DataSite(user, USERS_FOLDER) db.load_file() datas = dict() pageName = '%s' % escape(request.form['pageName']) pageType = request.form['pageType'] test_name = "^[A-Za-z0-9_-]*$" if bool(re.match(test_name, pageName)) : try : page = db.new_page(pageName, pageType) except FileExistsError: return make_response(('Page already exist', 500)) else: flash (u'Page créé avec succès', 'success'); else: return make_response(('Invalid type ', 500)) mypages = db.get_pages() return redirect(url_for('edit', page=pageName)) @app.route('/rmPage/') @login_required def rm_page(pageName): pageName = '%s' % escape(pageName) user = '%s'% escape(session['username']) db = DataSite(user, USERS_FOLDER) db.load_file() try: db.rm_page(pageName) flash (u'Page supprimé avec succès', 'success'); except OSError as e: flash (u"La page n'a pa pu être supprimer", 'error'); return redirect(url_for('edit')) @app.route('/sortblocs', methods=['POST'], defaults={'page': ''}) @app.route('//sortblocs', methods=['POST']) @login_required def sortblocs(page): user = '%s'% escape(session['username']) page = '%s' % escape(page) db = DataSite(user, USERS_FOLDER) db.load_file() config = db.datas['config'] menu = db.datas['menu'] datas = dict() myblocs = dict() myblocs_orig = db.get_blocs(page)['blocs'] for bloc in request.form: if bloc != 'csrf_token': bloc_name = bloc.replace("bloc-", "", 2) myblocs[bloc_name] = myblocs_orig[bloc_name] flash (u'Les blocs ont été réagencés', 'succes'); db.save_blocs(page, myblocs) return redirect(url_for('edit', page=page)) @app.route('/editmenu', methods=['POST']) @login_required def edit_menu(): user = '%s'% escape(session['username']) db = DataSite(user, USERS_FOLDER) db.load_file() db.datas['menu']=dict() for menu in request.form: if '§§' in menu: submenu = menu.split("§§") if submenu[0] in db.datas['menu'].keys(): db.datas['menu'][submenu[0]] = db.datas['menu'][submenu[0]] | {submenu[1]: str(request.form[menu])} else: db.datas['menu'][submenu[0]] = {submenu[1]: str(request.form[menu])} elif menu == 'csrf_token': pass else: db.datas['menu'][menu] = str(request.form[menu]) db.save_menu(db.datas['menu']) flash (u'Le menu a bien été modifier', 'success'); return redirect(url_for('edit')) @app.route('/img/') @login_required def myimgs(filename): user = '%s' % escape(session['username']) return send_from_directory( os.path.join(USERS_FOLDER, user, 'public', 'img'), filename ) @app.route('/img/thumbnails/') @login_required def mythumbnails(filename): user = '%s' % escape(session['username']) return send_from_directory( os.path.join(USERS_FOLDER, user, 'public', 'img', 'thumbnails'), filename ) @app.route('/favicon.ico', methods=['GET']) @app.route('/favicon.ico/', methods=['GET']) @login_required def favicon(): return make_response(('Ok! ', 200)) @app.route('/publish_progress/', methods=['GET']) @login_required def publish_progress(): user = '%s' % escape(session['username']) db = DataSite(user, USERS_FOLDER) db.load_file() progress = 0 error = False completed = False status = db.get_status_publish() match status: case "Generated" : progress = 30 case "Login Incorrect" | "Upload error" : progress = 100 error = True case "Identification verified": progress = 50 status = "Upload ..." case "Uploaded": progress = 80 status = "Set permissions ..." case str(x) if "Uploaded at:" in x: progress = 100 completed = True status = status.replace("Uploaded at:", "") return render_template('admin/_publish-progress.html', progress=progress, status=status, error = error, completed = completed) @app.route('/publish', methods=['POST']) @login_required def publish(): user = '%s' % escape(session['username']) db = DataSite(user, USERS_FOLDER) db.load_file() listPages = db.get_pages() theme = db.datas['config']['theme'] menu = db.datas['menu'] test_alphanum = "^[A-Za-z0-9/_-]*$" password = str(request.form['password']) serverInfos = dict() serverInfos['Address'] = str(request.form['serverAddress']) serverInfos['Port'] = str(request.form['serverPort']) serverInfos['username'] = str(request.form['username']) serverInfos['folder'] = str(request.form['folder']) footer = db.get_footer() for page in listPages: myblocs = db.get_blocs(page) htmlExport = render_template('/index.html.tpl', config=db.datas['config'], menu=menu, footer=footer, theme=theme, page=page, myblocs=myblocs) db.writeHTML(theme, page, htmlExport) # Export index.html landing page myblocs = db.get_blocs('') htmlExport = render_template('/index.html.tpl', config=db.datas['config'], menu=menu, footer=footer, theme=theme, page='/', myblocs=myblocs) db.writeHTML(theme, '/', htmlExport) db.copy_static_files() db.update_status_publish("Generated") if serverInfos['Port'] == '' or serverInfos['Port'].isdigit() == False : serverPort = '22' if serverInfos['folder'] == '' : folder = '/' elif(bool(re.match(test_alphanum, serverInfos['folder'])) == False): serverInfos['folder'] = '/' if db.test_server_login(serverInfos, password ) == False: db.update_status_publish ("Identification Incorrect") return make_response(('Login Incorrect', 500)) else: db.update_status_publish("Identification verified") if db.publish(serverInfos, password) == False: db.update_status_publish ("Upload error") return make_response('Upload Error !') #Generate date of success upload now = datetime.now() date_upload = now.strftime("%d/%m/%Y, %H:%M:%S") db.update_status_publish ("Uploaded at: "+date_upload) db.save_server_info(serverInfos) return redirect(url_for('edit'))