#### Imports import jinja2 as j2 from flask import ( Flask, render_template, render_template_string, request, redirect, flash, send_file, ) from markupsafe import Markup # No longer imported from Flask # Form libraries from flask_wtf import FlaskForm from wtforms import ( StringField, RadioField, SelectField, SubmitField, TextAreaField, BooleanField, SelectMultipleField, ) from wtforms.validators import ( DataRequired, InputRequired, Optional, Regexp, URL, Length, ) # Markdown to HTML - for debugging purposes from misaka import Markdown, HtmlRenderer # Managing zipfiles import zipfile from flask_cors import CORS from urllib import parse from secrets import token_urlsafe #### Create FLASK and Jinja Environments app = Flask(__name__) app.config["SECRET_KEY"] = token_urlsafe(16) # Necessary for the form CORS cors = CORS(app) environment = j2.Environment(loader=j2.FileSystemLoader("templates/")) #### Custom functions # Define custom filter @app.template_filter("render_markdown") def render_markdown(text): renderer = HtmlRenderer() markdown = Markdown(renderer) return markdown(text) # Add custom filter j2.filters.FILTERS["render_markdown"] = render_markdown # Converting markdown to html def markdown_file_to_html_string(file): with open(file, "r") as file: markdown_content = file.read() # Convert content from Markdown to HTML html_content = render_markdown(markdown_content) # Return Markdown and HTML contents return markdown_content, html_content ### Forms ## PHP forms class Form_PHP_Config(FlaskForm): php_config_file = SelectField( "Type de fichier PHP :", choices=[ ( "php-fpm.conf", Markup( 'Fichier de configuration PHP complet (php-fpm.conf)' ), ), ( "php_extra-fpm.conf", Markup( 'Fichier de configuration PHP particulier (extra_php-fpm.conf)' ), ), ], default="php_extra-fpm.conf", validators=[DataRequired()], ) ## TODO : figure out how to include these comments/title values # 'title': 'Remplace la configuration générée par défaut par un fichier de configuration complet. À éviter si possible. # 'title': "Choisir un fichier permettant un paramétrage d'options complémentaires. C'est généralement recommandé." php_config_file_content = TextAreaField( "Saisissez le contenu du fichier de configuration PHP :", validators=[Optional()], render_kw={ "class": "form-control", "style": "width: 50%;height:11em;min-height: 5.5em; max-height: 55em;flex-grow: 1;box-sizing: border-box;", "title": "TODO", "placeholder": "; Additional php.ini defines, specific to this pool of workers. \n\nphp_admin_value[upload_max_filesize] = 100M \nphp_admin_value[post_max_size] = 100M", }, ) class Form_PHP(Form_PHP_Config): use_php = BooleanField("Nécessite PHP", default=False) ## NodeJS forms class Form_NodeJS(FlaskForm): use_nodejs = BooleanField("Nécessite NodeJS", default=False) use_nodejs_version = StringField( "Version de NodeJS :", render_kw={ "placeholder": "20", "class": "form-control", "title": "Saisissez la version de NodeJS à installer. Cela peut-être une version majeure (ex: 20) ou plus précise (ex: 20.1).", }, ) # TODO : this should be validated using a regex, should be only numbers and any (≥0) number of dots in between use_nodejs_needs_yarn = BooleanField( "Nécessite Yarn", default=False, render_kw={ "title": "Faut-il installer automatiquement Yarn ? Cela configurera les dépôts spécifiques à Yarn." }, ) ## Python forms class Form_Python(FlaskForm): use_python = BooleanField( "Nécessite Python", default=False ) ## TODO -> python3, python3-pip, python3-ven dependencies by default python_dependencies_type = SelectField( "Configuration des dépendances Python :", choices=[ ("requirements.txt", Markup("Fichier requirements.txt")), ("manual_list", "Liste manuelle"), ], default="requirements.txt", validators=[DataRequired(), Optional()], ) python_requirements = TextAreaField( "La liste de dépendances inclue dans le fichier requirements.txt :", render_kw={ "class": "form-control", "style": "width: 50%;height:5.5em;min-height: 5.5em; max-height: 55em;flex-grow: 1;box-sizing: border-box;", "title": "Lister les dépendances à installer, une par ligne, avec un numéro de version derrière.\nEx: 'dépendance==1.0'.", "placeholder": "tensorflow==2.3.1 \nuvicorn==0.12.2 \nfastapi==0.63.0", }, ) python_dependencies_list = StringField( "Liste de dépendances python :", render_kw={ "placeholder": "tensorflow uvicorn fastapi", "class": "form-control", "title": "Lister les dépendances à installer, séparées d'un espace.", }, ) class GeneralInfos(FlaskForm): app_id = StringField( Markup( """Identifiant (id) de l'application (en minuscule et sans espaces) :""" ), validators=[DataRequired(), Regexp("[a-z_1-9]+.*(?