mirror of
https://github.com/YunoHost/apps.git
synced 2024-09-03 20:06:07 +02:00
yologen: babel fixes (#2251)
Co-authored-by: lapineige <lapineige@users.noreply.github.com>
This commit is contained in:
parent
12ada803df
commit
1ad97d5704
1 changed files with 227 additions and 286 deletions
|
@ -37,7 +37,7 @@ from wtforms.validators import (
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
from flask_babel import Babel
|
from flask_babel import Babel
|
||||||
from flask_babel import gettext
|
from flask_babel import gettext, lazy_gettext
|
||||||
|
|
||||||
from flask import redirect, request, make_response # Language swap by redirecting
|
from flask import redirect, request, make_response # Language swap by redirecting
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ from urllib import parse
|
||||||
from secrets import token_urlsafe
|
from secrets import token_urlsafe
|
||||||
|
|
||||||
#### GLOBAL VARIABLES
|
#### GLOBAL VARIABLES
|
||||||
YOLOGEN_VERSION = "0.9.1"
|
YOLOGEN_VERSION = "0.9.2.1"
|
||||||
GENERATOR_DICT = {"GENERATOR_VERSION": YOLOGEN_VERSION}
|
GENERATOR_DICT = {"GENERATOR_VERSION": YOLOGEN_VERSION}
|
||||||
|
|
||||||
#### Create FLASK and Jinja Environments
|
#### Create FLASK and Jinja Environments
|
||||||
|
@ -63,26 +63,32 @@ cors = CORS(app)
|
||||||
environment = j2.Environment(loader=j2.FileSystemLoader("templates/"))
|
environment = j2.Environment(loader=j2.FileSystemLoader("templates/"))
|
||||||
|
|
||||||
# Handle translations
|
# Handle translations
|
||||||
BABEL_TRANSLATION_DIRECTORIES = "translations"
|
BABEL_TRANSLATION_DIRECTORIES='translations'
|
||||||
|
|
||||||
babel = Babel()
|
babel = Babel()
|
||||||
|
|
||||||
LANGUAGES = {"en": "English", "fr": "French"}
|
LANGUAGES = {
|
||||||
|
'en': gettext('English'),
|
||||||
|
'fr': gettext('French')
|
||||||
|
}
|
||||||
|
|
||||||
|
@app.context_processor
|
||||||
|
def inject_conf_var():
|
||||||
|
return dict(AVAILABLE_LANGUAGES=LANGUAGES)
|
||||||
|
|
||||||
def configure(app):
|
def configure(app):
|
||||||
babel.init_app(app, locale_selector=get_locale)
|
babel.init_app(app, locale_selector=get_locale)
|
||||||
app.config["LANGUAGES"] = LANGUAGES
|
app.config['LANGUAGES'] = LANGUAGES
|
||||||
|
|
||||||
|
|
||||||
def get_locale():
|
def get_locale():
|
||||||
print(request.accept_languages.best_match(app.config["LANGUAGES"].keys()))
|
print(request.accept_languages.best_match(app.config['LANGUAGES'].keys()))
|
||||||
print(request.cookies.get("lang", "en"))
|
print(request.cookies.get('lang', 'en'))
|
||||||
# return 'en' # to test
|
#return 'en' # to test
|
||||||
# return 'fr'
|
#return 'fr'
|
||||||
return request.cookies.get("lang", "en")
|
if request.args.get('language'):
|
||||||
# return request.accept_languages.best_match(app.config['LANGUAGES'].keys()) # The result is based on the Accept-Language header. For testing purposes, you can directly return a language code, for example: return ‘de’
|
print(request.args.get('language'))
|
||||||
|
session['language'] = request.args.get('language')
|
||||||
|
return request.cookies.get('lang', 'en')
|
||||||
|
#return request.accept_languages.best_match(app.config['LANGUAGES'].keys()) # The result is based on the Accept-Language header. For testing purposes, you can directly return a language code, for example: return ‘de’
|
||||||
|
|
||||||
configure(app)
|
configure(app)
|
||||||
|
|
||||||
|
@ -113,12 +119,23 @@ def markdown_file_to_html_string(file):
|
||||||
|
|
||||||
### Forms
|
### Forms
|
||||||
|
|
||||||
|
# Language selector. Not used (in GeneratorForm) until it's fixed or superseeded.
|
||||||
|
# Use it in the HTML with {{ form_field(main_form.generator_language) }}
|
||||||
|
class Translations(FlaskForm):
|
||||||
|
generator_language = SelectField(
|
||||||
|
gettext("Select language"),
|
||||||
|
choices=[('none', "")]+[language for language in LANGUAGES.items()],
|
||||||
|
default=['en'],
|
||||||
|
id = 'selectLanguage'
|
||||||
|
)
|
||||||
|
|
||||||
class GeneralInfos(FlaskForm):
|
class GeneralInfos(FlaskForm):
|
||||||
|
|
||||||
app_id = StringField(
|
app_id = StringField(
|
||||||
Markup(gettext("Application identifier (id)")),
|
Markup(
|
||||||
description=gettext("Small caps and without spaces"),
|
lazy_gettext("Application identifier (id)")
|
||||||
|
),
|
||||||
|
description=lazy_gettext("Small caps and without spaces"),
|
||||||
validators=[DataRequired(), Regexp("[a-z_1-9]+.*(?<!_ynh)$")],
|
validators=[DataRequired(), Regexp("[a-z_1-9]+.*(?<!_ynh)$")],
|
||||||
render_kw={
|
render_kw={
|
||||||
"placeholder": "my_super_app",
|
"placeholder": "my_super_app",
|
||||||
|
@ -126,10 +143,8 @@ class GeneralInfos(FlaskForm):
|
||||||
)
|
)
|
||||||
|
|
||||||
app_name = StringField(
|
app_name = StringField(
|
||||||
gettext("App name"),
|
lazy_gettext("App name"),
|
||||||
description=gettext(
|
description=lazy_gettext("It's the application name, displayed in the user interface"),
|
||||||
"It's the application name, displayed in the user interface"
|
|
||||||
),
|
|
||||||
validators=[DataRequired()],
|
validators=[DataRequired()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"placeholder": "My super App",
|
"placeholder": "My super App",
|
||||||
|
@ -137,15 +152,13 @@ class GeneralInfos(FlaskForm):
|
||||||
)
|
)
|
||||||
|
|
||||||
description_en = StringField(
|
description_en = StringField(
|
||||||
gettext("Short description (en)"),
|
lazy_gettext("Short description (en)"),
|
||||||
description=gettext(
|
description=lazy_gettext("Explain in a few words (10-15) why this app is useful or what it does (the goal is to give a broad idea for the user browsing an hundred apps long catalog"),
|
||||||
"Explain in a few words (10-15) why this app is useful or what it does (the goal is to give a broad idea for the user browsing an hundred apps long catalog"
|
|
||||||
),
|
|
||||||
validators=[DataRequired()],
|
validators=[DataRequired()],
|
||||||
)
|
)
|
||||||
description_fr = StringField(
|
description_fr = StringField(
|
||||||
gettext("Description courte (fr)"),
|
lazy_gettext("Description courte (fr)"),
|
||||||
description="Explain in a few words (10-15) why this app is useful or what it does (the goal is to give a broad idea for the user browsing an hundred apps long catalog",
|
description=lazy_gettext("Explain in a few words (10-15) why this app is useful or what it does (the goal is to give a broad idea for the user browsing an hundred apps long catalog"),
|
||||||
validators=[DataRequired()],
|
validators=[DataRequired()],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -154,30 +167,28 @@ class IntegrationInfos(FlaskForm):
|
||||||
|
|
||||||
# TODO : people shouldnt have to put the ~ynh1 ? This should be added automatically when rendering the app files ?
|
# TODO : people shouldnt have to put the ~ynh1 ? This should be added automatically when rendering the app files ?
|
||||||
version = StringField(
|
version = StringField(
|
||||||
"Version",
|
lazy_gettext("Version"),
|
||||||
validators=[Regexp("\d{1,4}.\d{1,4}(.\d{1,4})?(.\d{1,4})?~ynh\d+")],
|
validators=[Regexp("\d{1,4}.\d{1,4}(.\d{1,4})?(.\d{1,4})?~ynh\d+")],
|
||||||
render_kw={"placeholder": "1.0~ynh1"},
|
render_kw={"placeholder": "1.0~ynh1"},
|
||||||
)
|
)
|
||||||
|
|
||||||
maintainers = StringField(
|
maintainers = StringField(
|
||||||
gettext("Maintener of the generated app"),
|
lazy_gettext("Maintener of the generated app"),
|
||||||
description=gettext(
|
description=lazy_gettext("Commonly you put your name here... If you agree with it ;)")
|
||||||
"Commonly you put your name here... If you agree with it ;)"
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
yunohost_required_version = StringField(
|
yunohost_required_version = StringField(
|
||||||
gettext("Minimal YunoHost version"),
|
lazy_gettext("Minimal YunoHost version"),
|
||||||
description=gettext("Minimal YunoHost version for the application to work"),
|
description=lazy_gettext("Minimal YunoHost version for the application to work"),
|
||||||
render_kw={
|
render_kw={
|
||||||
"placeholder": "11.1.21",
|
"placeholder": "11.1.21",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
architectures = SelectMultipleField(
|
architectures = SelectMultipleField(
|
||||||
gettext("Supported architectures"),
|
lazy_gettext("Supported architectures"),
|
||||||
choices=[
|
choices=[
|
||||||
("all", gettext("All architectures")),
|
("all", lazy_gettext("All architectures")),
|
||||||
("amd64", "amd64"),
|
("amd64", "amd64"),
|
||||||
("i386", "i386"),
|
("i386", "i386"),
|
||||||
("armhf", "armhf"),
|
("armhf", "armhf"),
|
||||||
|
@ -188,34 +199,28 @@ class IntegrationInfos(FlaskForm):
|
||||||
)
|
)
|
||||||
|
|
||||||
multi_instance = BooleanField(
|
multi_instance = BooleanField(
|
||||||
gettext(
|
lazy_gettext("The app can be installed multiple times at the same time on the same server"),
|
||||||
"The app can be installed multiple times at the same time on the same server"
|
|
||||||
),
|
|
||||||
default=True,
|
default=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
ldap = SelectField(
|
ldap = SelectField(
|
||||||
gettext("The app will be integrating LDAP"),
|
lazy_gettext("The app will be integrating LDAP"),
|
||||||
description=gettext(
|
description=lazy_gettext("Which means it's possible to use Yunohost credential to connect. 'LDAP' corresponds to the technology used by Yunohost to handle a centralised user base. Bridging the APP and Yunohost LDAP often requires to fill some parameters in the app configuration"),
|
||||||
"Which means it's possible to use Yunohost credential to connect. 'LDAP' corresponds to the technology used by Yunohost to handle a centralised user base. Bridging the APP and Yunohost LDAP often requires to fill some parameters in the app configuration"
|
|
||||||
),
|
|
||||||
choices=[
|
choices=[
|
||||||
("false", gettext("No")),
|
("false", lazy_gettext("No")),
|
||||||
("true", gettext("Yes")),
|
("true", lazy_gettext("Yes")),
|
||||||
("not_relevant", gettext("Not relevant")),
|
("not_relevant", lazy_gettext("Not relevant")),
|
||||||
],
|
],
|
||||||
default="not_relevant",
|
default="not_relevant",
|
||||||
validators=[DataRequired()],
|
validators=[DataRequired()],
|
||||||
)
|
)
|
||||||
sso = SelectField(
|
sso = SelectField(
|
||||||
gettext("The app will be integrated in Yunohost SSO (Single Sign On)"),
|
lazy_gettext("The app will be integrated in Yunohost SSO (Single Sign On)"),
|
||||||
description=gettext(
|
description=lazy_gettext("Which means that one connexion to Yunohost unlock the connexion to the software, without having to sign on specificaly into it. One only has to connect once (Single Sign On)"),
|
||||||
"Which means that one connexion to Yunohost unlock the connexion to the software, without having to sign on specificaly into it. One only has to connect once (Single Sign On)"
|
|
||||||
),
|
|
||||||
choices=[
|
choices=[
|
||||||
("false", gettext("Yes")),
|
("false", lazy_gettext("Yes")),
|
||||||
("true", gettext("No")),
|
("true", lazy_gettext("No")),
|
||||||
("not_relevant", gettext("Not relevant")),
|
("not_relevant", lazy_gettext("Not relevant")),
|
||||||
],
|
],
|
||||||
default="not_relevant",
|
default="not_relevant",
|
||||||
validators=[DataRequired()],
|
validators=[DataRequired()],
|
||||||
|
@ -225,121 +230,111 @@ class IntegrationInfos(FlaskForm):
|
||||||
class UpstreamInfos(FlaskForm):
|
class UpstreamInfos(FlaskForm):
|
||||||
|
|
||||||
license = StringField(
|
license = StringField(
|
||||||
gettext("Licence"),
|
lazy_gettext("Licence"),
|
||||||
description=gettext(
|
description=lazy_gettext("You should check this on the upstream repository. The expected format is a SPDX id listed in https://spdx.org/licenses/"),
|
||||||
"You should check this on the upstream repository. The expected format is a SPDX id listed in https://spdx.org/licenses/"
|
|
||||||
),
|
|
||||||
validators=[DataRequired()],
|
validators=[DataRequired()],
|
||||||
)
|
)
|
||||||
|
|
||||||
website = StringField(
|
website = StringField(
|
||||||
gettext("Official website"),
|
lazy_gettext("Official website"),
|
||||||
description=gettext("Leave empty if there is no official website"),
|
description=lazy_gettext("Leave empty if there is no official website"),
|
||||||
validators=[URL(), Optional()],
|
validators=[URL(), Optional()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"placeholder": "https://awesome-app-website.com",
|
"placeholder": "https://awesome-app-website.com",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
demo = StringField(
|
demo = StringField(
|
||||||
gettext("Official app demo"),
|
lazy_gettext("Official app demo"),
|
||||||
description=gettext("Leave empty if there is no official demo"),
|
description=lazy_gettext("Leave empty if there is no official demo"),
|
||||||
validators=[URL(), Optional()],
|
validators=[URL(), Optional()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"placeholder": "https://awesome-app-website.com/demo",
|
"placeholder": "https://awesome-app-website.com/demo",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
admindoc = StringField(
|
admindoc = StringField(
|
||||||
gettext("Admin documentation"),
|
lazy_gettext("Admin documentation"),
|
||||||
description=gettext("Leave empty if there is no official admin doc"),
|
description=lazy_gettext("Leave empty if there is no official admin doc"),
|
||||||
validators=[URL(), Optional()],
|
validators=[URL(), Optional()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"placeholder": "https://awesome-app-website.com/doc/admin",
|
"placeholder": "https://awesome-app-website.com/doc/admin",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
userdoc = StringField(
|
userdoc = StringField(
|
||||||
gettext("Usage documentation"),
|
lazy_gettext("Usage documentation"),
|
||||||
description=gettext("Leave empty if there is no official user doc"),
|
description=lazy_gettext("Leave empty if there is no official user doc"),
|
||||||
validators=[URL(), Optional()],
|
validators=[URL(), Optional()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"placeholder": "https://awesome-app-website.com/doc/user",
|
"placeholder": "https://awesome-app-website.com/doc/user",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
code = StringField(
|
code = StringField(
|
||||||
gettext("Code repository"),
|
lazy_gettext("Code repository"),
|
||||||
validators=[URL(), DataRequired()],
|
validators=[URL(), DataRequired()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"placeholder": "https://some.git.forge/org/app",
|
"placeholder": "https://some.git.forge/org/app",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class InstallQuestions(FlaskForm):
|
class InstallQuestions(FlaskForm):
|
||||||
|
|
||||||
domain_and_path = SelectField(
|
domain_and_path = SelectField(
|
||||||
gettext(
|
lazy_gettext("Ask the URL where the app will be installed ('domain' and 'path' variables)"),
|
||||||
"Ask the URL where the app will be installed ('domain' and 'path' variables)"
|
|
||||||
),
|
|
||||||
default="true",
|
default="true",
|
||||||
choices=[
|
choices=[
|
||||||
("true", gettext("Ask domain+path")),
|
("true", lazy_gettext("Ask domain+path")),
|
||||||
(
|
("full_domain", lazy_gettext("Ask only the domain (the app requires to be installed at the root of a dedicated domain)")),
|
||||||
"full_domain",
|
("false", lazy_gettext("Do not ask (it isn't a webapp)"))
|
||||||
gettext(
|
|
||||||
"Ask only the domain (the app requires to be installed at the root of a dedicated domain)"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("false", gettext("Do not ask (it isn't a webapp)")),
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
init_main_permission = BooleanField(
|
init_main_permission = BooleanField(
|
||||||
gettext("Ask who can access to the app"),
|
lazy_gettext("Ask who can access to the app"),
|
||||||
description=gettext(
|
description=lazy_gettext("In the users groups : by default at least 'visitors', 'all_users' et 'admins' exists. (It was previously the private/public app concept)"),
|
||||||
"In the users groups : by default at least 'visitors', 'all_users' et 'admins' exists. (It was previously the private/public app concept)"
|
|
||||||
),
|
|
||||||
default=True,
|
default=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
init_admin_permission = BooleanField(
|
init_admin_permission = BooleanField(
|
||||||
gettext("Ask who can access to the admin interface"),
|
lazy_gettext("Ask who can access to the admin interface"),
|
||||||
description=gettext("In the case where the app has an admin interface"),
|
description=lazy_gettext("In the case where the app has an admin interface"),
|
||||||
default=False,
|
default=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
language = SelectMultipleField(
|
language = SelectMultipleField(
|
||||||
gettext("Supported languages"),
|
lazy_gettext("Supported languages"),
|
||||||
choices=[
|
choices=[
|
||||||
("_", gettext("None / not relevant")),
|
("_", lazy_gettext("None / not relevant")),
|
||||||
("en", gettext("English")),
|
("en", lazy_gettext("English")),
|
||||||
("fr", gettext("Français")),
|
("fr", lazy_gettext("Français")),
|
||||||
("en", gettext("Spanish")),
|
("en", lazy_gettext("Spanish")),
|
||||||
("it", gettext("Italian")),
|
("it", lazy_gettext("Italian")),
|
||||||
("de", gettext("German")),
|
("de", lazy_gettext("German")),
|
||||||
("zh", gettext("Chinese")),
|
("zh", lazy_gettext("Chinese")),
|
||||||
("jp", gettext("Japanese")),
|
("jp", lazy_gettext("Japanese")),
|
||||||
("da", gettext("Danish")),
|
("da", lazy_gettext("Danish")),
|
||||||
("pt", gettext("Portugese")),
|
("pt", lazy_gettext("Portugese")),
|
||||||
("nl", gettext("Dutch")),
|
("nl", lazy_gettext("Dutch")),
|
||||||
("ru", gettext("Russian")),
|
("ru", lazy_gettext("Russian")),
|
||||||
],
|
],
|
||||||
default=["_"],
|
default=["_"],
|
||||||
validators=[DataRequired()],
|
validators=[DataRequired()],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# manifest
|
# manifest
|
||||||
class Resources(FlaskForm):
|
class Ressources(FlaskForm):
|
||||||
|
|
||||||
|
|
||||||
# Sources
|
# Sources
|
||||||
source_url = StringField(
|
source_url = StringField(
|
||||||
gettext("Application source code or executable"),
|
lazy_gettext("Application source code or executable"),
|
||||||
validators=[DataRequired(), URL()],
|
validators=[DataRequired(), URL()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"placeholder": "https://github.com/foo/bar/archive/refs/tags/v1.2.3.tar.gz",
|
"placeholder": "https://github.com/foo/bar/archive/refs/tags/v1.2.3.tar.gz",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
sha256sum = StringField(
|
sha256sum = StringField(
|
||||||
gettext("Sources sha256 checksum"),
|
lazy_gettext("Sources sha256 checksum"),
|
||||||
validators=[DataRequired(), Length(min=64, max=64)],
|
validators=[DataRequired(), Length(min=64, max=64)],
|
||||||
render_kw={
|
render_kw={
|
||||||
"placeholder": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
"placeholder": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||||
|
@ -347,10 +342,8 @@ class Resources(FlaskForm):
|
||||||
)
|
)
|
||||||
|
|
||||||
auto_update = SelectField(
|
auto_update = SelectField(
|
||||||
gettext("Activate the automated source update bot"),
|
lazy_gettext("Activate the automated source update bot"),
|
||||||
description=gettext(
|
description=lazy_gettext("If the software is available in one of the handled sources and publish releases or tags for its new updates, or for each new commit, a bot will provide an update with updated URL and checksum"),
|
||||||
"If the software is available in one of the handled sources and publish releases or tags for its new updates, or for each new commit, a bot will provide an update with updated URL and checksum"
|
|
||||||
),
|
|
||||||
default="none",
|
default="none",
|
||||||
choices=[
|
choices=[
|
||||||
("none", "Non"),
|
("none", "Non"),
|
||||||
|
@ -370,16 +363,14 @@ class Resources(FlaskForm):
|
||||||
)
|
)
|
||||||
|
|
||||||
apt_dependencies = StringField(
|
apt_dependencies = StringField(
|
||||||
gettext(
|
lazy_gettext("Dependances to be installed via apt (separated by a quote and/or spaces)"),
|
||||||
"Dependances to be installed via apt (separated by a quote and/or spaces)"
|
|
||||||
),
|
|
||||||
render_kw={
|
render_kw={
|
||||||
"placeholder": "foo, bar2.1-ext, libwat",
|
"placeholder": "foo, bar2.1-ext, libwat",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
database = SelectField(
|
database = SelectField(
|
||||||
gettext("Initialise a SQL database"),
|
lazy_gettext("Initialise a SQL database"),
|
||||||
choices=[
|
choices=[
|
||||||
("false", "Non"),
|
("false", "Non"),
|
||||||
("mysql", "MySQL/MariaDB"),
|
("mysql", "MySQL/MariaDB"),
|
||||||
|
@ -389,19 +380,19 @@ class Resources(FlaskForm):
|
||||||
)
|
)
|
||||||
|
|
||||||
system_user = BooleanField(
|
system_user = BooleanField(
|
||||||
gettext("Initialise a system user for this app"),
|
lazy_gettext("Initialise a system user for this app"),
|
||||||
default=True,
|
default=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
install_dir = BooleanField(
|
install_dir = BooleanField(
|
||||||
gettext("Initialise an installation folder for this app"),
|
lazy_gettext("Initialise an installation folder for this app"),
|
||||||
description=gettext("By default it's /var/www/$app"),
|
description=lazy_gettext("By default it's /var/www/$app"),
|
||||||
default=True,
|
default=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
data_dir = BooleanField(
|
data_dir = BooleanField(
|
||||||
gettext("Initialise a folder to store the app data"),
|
lazy_gettext("Initialise a folder to store the app data"),
|
||||||
description=gettext("By default it's /var/yunohost.app/$app"),
|
description=lazy_gettext("By default it's /var/yunohost.app/$app"),
|
||||||
default=False,
|
default=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -409,26 +400,26 @@ class Resources(FlaskForm):
|
||||||
class SpecificTechnology(FlaskForm):
|
class SpecificTechnology(FlaskForm):
|
||||||
|
|
||||||
main_technology = SelectField(
|
main_technology = SelectField(
|
||||||
gettext("App main technology"),
|
lazy_gettext("App main technology"),
|
||||||
choices=[
|
choices=[
|
||||||
("none", gettext("None / Static application")),
|
("none", lazy_gettext("None / Static application")),
|
||||||
("php", "PHP"),
|
("php", "PHP"),
|
||||||
("nodejs", "NodeJS"),
|
("nodejs", "NodeJS"),
|
||||||
("python", "Python"),
|
("python", "Python"),
|
||||||
("ruby", "Ruby"),
|
("ruby", "Ruby"),
|
||||||
("other", gettext("Other")),
|
("other", lazy_gettext("Other")),
|
||||||
],
|
],
|
||||||
default="none",
|
default="none",
|
||||||
validators=[DataRequired()],
|
validators=[DataRequired()],
|
||||||
)
|
)
|
||||||
|
|
||||||
install_snippet = TextAreaField(
|
install_snippet = TextAreaField(
|
||||||
gettext("Installation specific commands"),
|
lazy_gettext("Installation specific commands"),
|
||||||
description=gettext(
|
description=lazy_gettext("These commands are executed from the app installation folder (by default, /var/www/$app) after the sources have been deployed. This field uses by default a classic example based on the selected technology. You should probably compare and adapt it according to the app installation documentation"),
|
||||||
"These commands are executed from the app installation folder (by default, /var/www/$app) after the sources have been deployed. This field uses by default a classic example based on the selected technology. You should probably compare and adapt it according to the app installation documentation"
|
|
||||||
),
|
|
||||||
validators=[Optional()],
|
validators=[Optional()],
|
||||||
render_kw={"spellcheck": "false"},
|
render_kw={
|
||||||
|
"spellcheck": "false"
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -436,8 +427,8 @@ class SpecificTechnology(FlaskForm):
|
||||||
#
|
#
|
||||||
|
|
||||||
use_composer = BooleanField(
|
use_composer = BooleanField(
|
||||||
gettext("Use composer"),
|
lazy_gettext("Use composer"),
|
||||||
description=gettext("Composer is a PHP dependencies manager used by some apps"),
|
description=lazy_gettext("Composer is a PHP dependencies manager used by some apps"),
|
||||||
default=False,
|
default=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -446,25 +437,23 @@ class SpecificTechnology(FlaskForm):
|
||||||
#
|
#
|
||||||
|
|
||||||
nodejs_version = StringField(
|
nodejs_version = StringField(
|
||||||
gettext("NodeJS version"),
|
lazy_gettext("NodeJS version"),
|
||||||
description=gettext("For example: 16.4, 18, 18.2, 20, 20.1, ..."),
|
description=lazy_gettext("For example: 16.4, 18, 18.2, 20, 20.1, ..."),
|
||||||
render_kw={
|
render_kw={
|
||||||
"placeholder": "20",
|
"placeholder": "20",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
use_yarn = BooleanField(
|
use_yarn = BooleanField(
|
||||||
gettext("Install and use Yarn"),
|
lazy_gettext("Install and use Yarn"),
|
||||||
default=False,
|
default=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
# NodeJS / Python / Ruby / ...
|
# NodeJS / Python / Ruby / ...
|
||||||
|
|
||||||
systemd_execstart = StringField(
|
systemd_execstart = StringField(
|
||||||
gettext("Command to start the app daemon (from systemd service)"),
|
lazy_gettext("Command to start the app daemon (from systemd service)"),
|
||||||
description=gettext(
|
description=lazy_gettext("Corresponds to 'ExecStart' statement in systemd. You can use '__INSTALL_DIR__' to refer to the install directory, or '__APP__' to refer to the app id"),
|
||||||
"Corresponds to 'ExecStart' statement in systemd. You can use '__INSTALL_DIR__' to refer to the install directory, or '__APP__' to refer to the app id"
|
|
||||||
),
|
|
||||||
render_kw={
|
render_kw={
|
||||||
"placeholder": "__INSTALL_DIR__/bin/app --some-option",
|
"placeholder": "__INSTALL_DIR__/bin/app --some-option",
|
||||||
},
|
},
|
||||||
|
@ -474,13 +463,13 @@ class SpecificTechnology(FlaskForm):
|
||||||
class AppConfig(FlaskForm):
|
class AppConfig(FlaskForm):
|
||||||
|
|
||||||
use_custom_config_file = BooleanField(
|
use_custom_config_file = BooleanField(
|
||||||
gettext("The app uses a specific configuration file"),
|
lazy_gettext("The app uses a specific configuration file"),
|
||||||
description=gettext("Usually : .env, config.json, conf.ini, params.yml, ..."),
|
description=lazy_gettext("Usually : .env, config.json, conf.ini, params.yml, ..."),
|
||||||
default=False,
|
default=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
custom_config_file = StringField(
|
custom_config_file = StringField(
|
||||||
gettext("Name or file path to use"),
|
lazy_gettext("Name or file path to use"),
|
||||||
validators=[Optional()],
|
validators=[Optional()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"placeholder": "config.json",
|
"placeholder": "config.json",
|
||||||
|
@ -488,24 +477,19 @@ class AppConfig(FlaskForm):
|
||||||
)
|
)
|
||||||
|
|
||||||
custom_config_file_content = TextAreaField(
|
custom_config_file_content = TextAreaField(
|
||||||
gettext("App configuration file pattern"),
|
lazy_gettext("App configuration file pattern"),
|
||||||
description=gettext(
|
description=lazy_gettext("In this pattern, you can use the syntax __FOO_BAR__ which will automatically replaced by the value of the variable $foo_bar"),
|
||||||
"In this pattern, you can use the syntax __FOO_BAR__ which will automatically replaced by the value of the variable $foo_bar"
|
|
||||||
),
|
|
||||||
validators=[Optional()],
|
validators=[Optional()],
|
||||||
render_kw={"spellcheck": "false"},
|
render_kw={
|
||||||
|
"spellcheck": "false"
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Documentation(FlaskForm):
|
class Documentation(FlaskForm):
|
||||||
# TODO : # screenshot
|
# TODO : # screenshot
|
||||||
description = TextAreaField(
|
description = TextAreaField(
|
||||||
Markup(
|
Markup(lazy_gettext('''Type the content of DESCRIPTION.md file. <br> \
|
||||||
gettext(
|
Do not give the software name at the beginning, as it will be integrated an 'Overview' subpart''')),
|
||||||
"""Type the content of DESCRIPTION.md file. <br> \
|
|
||||||
Do not give the software name at the beginning, as it will be integrated an 'Overview' subpart"""
|
|
||||||
)
|
|
||||||
),
|
|
||||||
validators=[Optional()],
|
validators=[Optional()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"class": "form-control",
|
"class": "form-control",
|
||||||
|
@ -513,9 +497,7 @@ Do not give the software name at the beginning, as it will be integrated an 'Ove
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
disclaimer = TextAreaField(
|
disclaimer = TextAreaField(
|
||||||
gettext(
|
lazy_gettext("Type the DISCLAIMER.md file content, which list warnings and attention points."),
|
||||||
"Type the DISCLAIMER.md file content, which list warnings and attention points."
|
|
||||||
),
|
|
||||||
validators=[Optional()],
|
validators=[Optional()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"class": "form-control",
|
"class": "form-control",
|
||||||
|
@ -523,7 +505,7 @@ Do not give the software name at the beginning, as it will be integrated an 'Ove
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
pre_install = TextAreaField(
|
pre_install = TextAreaField(
|
||||||
gettext("Type the PRE_INSTALL.md file content"),
|
lazy_gettext("Type the PRE_INSTALL.md file content"),
|
||||||
validators=[Optional()],
|
validators=[Optional()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"class": "form-control",
|
"class": "form-control",
|
||||||
|
@ -531,7 +513,7 @@ Do not give the software name at the beginning, as it will be integrated an 'Ove
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
post_install = TextAreaField(
|
post_install = TextAreaField(
|
||||||
gettext("Type the POST_INSTALL.md file content"),
|
lazy_gettext("Type the POST_INSTALL.md file content"),
|
||||||
validators=[Optional()],
|
validators=[Optional()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"class": "form-control",
|
"class": "form-control",
|
||||||
|
@ -539,7 +521,7 @@ Do not give the software name at the beginning, as it will be integrated an 'Ove
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
pre_upgrade = TextAreaField(
|
pre_upgrade = TextAreaField(
|
||||||
gettext("Type the PRE_UPGRADE.md file content"),
|
lazy_gettext("Type the PRE_UPGRADE.md file content"),
|
||||||
validators=[Optional()],
|
validators=[Optional()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"class": "form-control",
|
"class": "form-control",
|
||||||
|
@ -547,7 +529,7 @@ Do not give the software name at the beginning, as it will be integrated an 'Ove
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
post_upgrade = TextAreaField(
|
post_upgrade = TextAreaField(
|
||||||
gettext("Type the POST_UPGRADE.md file content"),
|
lazy_gettext("Type the POST_UPGRADE.md file content"),
|
||||||
validators=[Optional()],
|
validators=[Optional()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"class": "form-control",
|
"class": "form-control",
|
||||||
|
@ -555,7 +537,7 @@ Do not give the software name at the beginning, as it will be integrated an 'Ove
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
admin = TextAreaField(
|
admin = TextAreaField(
|
||||||
gettext("Type the ADMIN.md file content"),
|
lazy_gettext("Type the ADMIN.md file content"),
|
||||||
validators=[Optional()],
|
validators=[Optional()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"class": "form-control",
|
"class": "form-control",
|
||||||
|
@ -563,46 +545,39 @@ Do not give the software name at the beginning, as it will be integrated an 'Ove
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class MoreAdvanced(FlaskForm):
|
class MoreAdvanced(FlaskForm):
|
||||||
|
|
||||||
enable_change_url = BooleanField(
|
enable_change_url = BooleanField(
|
||||||
gettext("Handle app install URL change (change_url script)"),
|
lazy_gettext("Handle app install URL change (change_url script)"),
|
||||||
default=True,
|
default=True,
|
||||||
render_kw={
|
render_kw={
|
||||||
"title": gettext(
|
"title": lazy_gettext("Should changing the app URL be allowed ? (change_url change)")
|
||||||
"Should changing the app URL be allowed ? (change_url change)"
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
use_logrotate = BooleanField(
|
use_logrotate = BooleanField(
|
||||||
gettext("Use logrotate for the app logs"),
|
lazy_gettext("Use logrotate for the app logs"),
|
||||||
default=True,
|
default=True,
|
||||||
render_kw={
|
render_kw={
|
||||||
"title": gettext(
|
"title": lazy_gettext("If the app generates logs, this option permit to handle their archival. Recommended.")
|
||||||
"If the app generates logs, this option permit to handle their archival. Recommended."
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
# TODO : specify custom log file
|
# TODO : specify custom log file
|
||||||
# custom_log_file = "/var/log/$app/$app.log" "/var/log/nginx/${domain}-error.log"
|
# custom_log_file = "/var/log/$app/$app.log" "/var/log/nginx/${domain}-error.log"
|
||||||
use_fail2ban = BooleanField(
|
use_fail2ban = BooleanField(
|
||||||
gettext("Protect the application against brute force attacks (via fail2ban)"),
|
lazy_gettext("Protect the application against brute force attacks (via fail2ban)"),
|
||||||
default=False,
|
default=False,
|
||||||
render_kw={
|
render_kw={
|
||||||
"title": gettext(
|
"title": lazy_gettext("If the app generates failed connexions logs, this option allows to automatically banish the related IP after a certain number of failed password tries. Recommended.")
|
||||||
"If the app generates failed connexions logs, this option allows to automatically banish the related IP after a certain number of failed password tries. Recommended."
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
use_cron = BooleanField(
|
use_cron = BooleanField(
|
||||||
gettext("Add a CRON task for this application"),
|
lazy_gettext("Add a CRON task for this application"),
|
||||||
description=gettext("Corresponds to some app periodic operations"),
|
description=lazy_gettext("Corresponds to some app periodic operations"),
|
||||||
default=False,
|
default=False,
|
||||||
)
|
)
|
||||||
cron_config_file = TextAreaField(
|
cron_config_file = TextAreaField(
|
||||||
gettext("Type the CRON file content"),
|
lazy_gettext("Type the CRON file content"),
|
||||||
validators=[Optional()],
|
validators=[Optional()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"class": "form-control",
|
"class": "form-control",
|
||||||
|
@ -611,59 +586,38 @@ class MoreAdvanced(FlaskForm):
|
||||||
)
|
)
|
||||||
|
|
||||||
fail2ban_regex = StringField(
|
fail2ban_regex = StringField(
|
||||||
gettext("Regular expression for fail2ban"),
|
lazy_gettext("Regular expression for fail2ban"),
|
||||||
# Regex to match into the log for a failed login
|
# Regex to match into the log for a failed login
|
||||||
validators=[Optional()],
|
validators=[Optional()],
|
||||||
render_kw={
|
render_kw={
|
||||||
"placeholder": gettext("A regular expression"),
|
"placeholder": lazy_gettext("A regular expression"),
|
||||||
"class": "form-control",
|
"class": "form-control",
|
||||||
"title": gettext(
|
"title": lazy_gettext("Regular expression to check in the log file to activate failban (search for a line that indicates a credentials error)."),
|
||||||
"Regular expression to check in the log file to activate failban (search for a line that indicates a credentials error)."
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
## Main form
|
## Main form
|
||||||
class GeneratorForm(
|
class GeneratorForm(
|
||||||
GeneralInfos,
|
GeneralInfos, IntegrationInfos, UpstreamInfos, InstallQuestions, Ressources, SpecificTechnology, AppConfig, Documentation, MoreAdvanced
|
||||||
IntegrationInfos,
|
|
||||||
UpstreamInfos,
|
|
||||||
InstallQuestions,
|
|
||||||
Resources,
|
|
||||||
SpecificTechnology,
|
|
||||||
AppConfig,
|
|
||||||
Documentation,
|
|
||||||
MoreAdvanced,
|
|
||||||
):
|
):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
csrf = False
|
csrf = False
|
||||||
|
|
||||||
generator_mode = SelectField(
|
generator_mode = SelectField(
|
||||||
gettext("Generator mode"),
|
lazy_gettext("Generator mode"),
|
||||||
description=gettext(
|
description=lazy_gettext("In tutorial version, the generated app will contain additionnal comments to ease the understanding. In steamlined version, the generated app will only contain the necessary minimum."),
|
||||||
"In tutorial version, the generated app will contain additionnal comments to ease the understanding. In steamlined version, the generated app will only contain the necessary minimum."
|
choices=[("simple", lazy_gettext("Streamlined version")), ("tutorial", lazy_gettext("Tutorial version"))],
|
||||||
),
|
|
||||||
choices=[
|
|
||||||
("simple", gettext("Streamlined version")),
|
|
||||||
("tutorial", gettext("Tutorial version")),
|
|
||||||
],
|
|
||||||
default="true",
|
default="true",
|
||||||
validators=[DataRequired()],
|
validators=[DataRequired()],
|
||||||
)
|
)
|
||||||
|
|
||||||
submit_preview = SubmitField(gettext("Previsualise"))
|
submit_preview = SubmitField(lazy_gettext("Previsualise"))
|
||||||
submit_download = SubmitField(gettext("Download the .zip"))
|
submit_download = SubmitField(lazy_gettext("Download the .zip"))
|
||||||
submit_demo = SubmitField(
|
submit_demo = SubmitField(lazy_gettext('Fill with demo values'), render_kw={"onclick": "fillFormWithDefaultValues()",
|
||||||
gettext("Fill with demo values"),
|
"title": lazy_gettext("Generate a complete and functionnal minimalistic app that you can iterate from")
|
||||||
render_kw={
|
})
|
||||||
"onclick": "fillFormWithDefaultValues()",
|
|
||||||
"title": gettext(
|
|
||||||
"Generate a complete and functionnal minimalistic app that you can iterate from"
|
|
||||||
),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
#### Web pages
|
#### Web pages
|
||||||
|
@ -673,6 +627,7 @@ def main_form_route():
|
||||||
main_form = GeneratorForm()
|
main_form = GeneratorForm()
|
||||||
app_files = []
|
app_files = []
|
||||||
|
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
|
|
||||||
if not main_form.validate_on_submit():
|
if not main_form.validate_on_submit():
|
||||||
|
@ -680,10 +635,7 @@ def main_form_route():
|
||||||
print(main_form.errors)
|
print(main_form.errors)
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"index.html",
|
"index.html", main_form=main_form, generator_info=GENERATOR_DICT, generated_files={}
|
||||||
main_form=main_form,
|
|
||||||
generator_info=GENERATOR_DICT,
|
|
||||||
generated_files={},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if main_form.submit_preview.data:
|
if main_form.submit_preview.data:
|
||||||
|
@ -745,17 +697,13 @@ def main_form_route():
|
||||||
template_dir = os.path.dirname(__file__) + "/templates/"
|
template_dir = os.path.dirname(__file__) + "/templates/"
|
||||||
for app_file in app_files:
|
for app_file in app_files:
|
||||||
template = open(template_dir + app_file.id + ".j2").read()
|
template = open(template_dir + app_file.id + ".j2").read()
|
||||||
app_file.content = render_template_string(
|
app_file.content = render_template_string(template, data=dict(request.form | GENERATOR_DICT))
|
||||||
template, data=dict(request.form | GENERATOR_DICT)
|
app_file.content = re.sub(r'\n\s+$', '\n', app_file.content, flags=re.M)
|
||||||
)
|
app_file.content = re.sub(r'\n{3,}', '\n\n', app_file.content, flags=re.M)
|
||||||
app_file.content = re.sub(r"\n\s+$", "\n", app_file.content, flags=re.M)
|
|
||||||
app_file.content = re.sub(r"\n{3,}", "\n\n", app_file.content, flags=re.M)
|
|
||||||
|
|
||||||
print(main_form.use_custom_config_file.data)
|
print(main_form.use_custom_config_file.data)
|
||||||
if main_form.use_custom_config_file.data:
|
if main_form.use_custom_config_file.data:
|
||||||
app_files.append(
|
app_files.append(AppFile("appconf", "conf/" + main_form.custom_config_file.data))
|
||||||
AppFile("appconf", "conf/" + main_form.custom_config_file.data)
|
|
||||||
)
|
|
||||||
app_files[-1].content = main_form.custom_config_file_content.data
|
app_files[-1].content = main_form.custom_config_file_content.data
|
||||||
print(main_form.custom_config_file.data)
|
print(main_form.custom_config_file.data)
|
||||||
print(main_form.custom_config_file_content.data)
|
print(main_form.custom_config_file_content.data)
|
||||||
|
@ -771,26 +719,19 @@ def main_form_route():
|
||||||
zf.writestr(app_file.destination_path, app_file.content)
|
zf.writestr(app_file.destination_path, app_file.content)
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
# Send the zip file to the user
|
# Send the zip file to the user
|
||||||
return send_file(
|
return send_file(f, as_attachment=True, download_name=request.form["app_id"] + ".zip")
|
||||||
f, as_attachment=True, download_name=request.form["app_id"] + ".zip"
|
|
||||||
)
|
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"index.html",
|
"index.html", main_form=main_form, generator_info=GENERATOR_DICT, generated_files=app_files,
|
||||||
main_form=main_form,
|
|
||||||
generator_info=GENERATOR_DICT,
|
|
||||||
generated_files=app_files,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Localisation
|
# Localisation
|
||||||
@app.route("/language/<language>")
|
@app.route('/language/<language>')
|
||||||
def set_language(language=None):
|
def set_language(language=None):
|
||||||
response = make_response(redirect(request.referrer or "/"))
|
response = make_response(redirect(request.referrer or '/'))
|
||||||
response.set_cookie("lang", language)
|
response.set_cookie('lang', language)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
#### Running the web server
|
#### Running the web server
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(debug=True)
|
app.run(debug=True)
|
||||||
|
|
Loading…
Add table
Reference in a new issue