mirror of
https://github.com/YunoHost/apps.git
synced 2024-09-03 20:06:07 +02:00
Merge branch 'master' into patch-8
This commit is contained in:
commit
aafacb17da
157 changed files with 8182 additions and 2535 deletions
29
.github/diff_pot_files.py
vendored
Normal file
29
.github/diff_pot_files.py
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
#! /usr/bin/env python3
|
||||
|
||||
"""
|
||||
Super small script for github action to detect if 2 .pot files have changed for
|
||||
github/workflows/auto_messages_pot.yml
|
||||
"""
|
||||
|
||||
import sys
|
||||
from babel.messages.pofile import PoFileParser
|
||||
|
||||
|
||||
def load_pot_file(file_path):
|
||||
poparser = PoFileParser({})
|
||||
poparser.parse(open(file_path))
|
||||
return poparser.catalog
|
||||
|
||||
|
||||
def main():
|
||||
file_1 = load_pot_file(sys.argv[1])
|
||||
file_2 = load_pot_file(sys.argv[2])
|
||||
|
||||
if [x for x in file_1.keys() if x] == [x for x in file_2.keys() if x]:
|
||||
print("false")
|
||||
else:
|
||||
print("true")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
4
.github/workflows/added_dates.yml
vendored
4
.github/workflows/added_dates.yml
vendored
|
@ -12,6 +12,7 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.YUNOHOST_BOT_TOKEN }}
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
|
@ -30,3 +31,6 @@ jobs:
|
|||
with:
|
||||
commit_message: "Automatically add dates to the catalog files"
|
||||
file_pattern: 'apps.toml wishlist.toml graveyard.toml'
|
||||
commit_user_name: yunohost-bot
|
||||
commit_user_email: yunohost-bot@users.noreply.github.com
|
||||
commit_author: 'yunohost-bot <yunohost-bot@users.noreply.github.com>'
|
||||
|
|
9
.github/workflows/auto_messages_pot.yml
vendored
9
.github/workflows/auto_messages_pot.yml
vendored
|
@ -18,17 +18,18 @@ jobs:
|
|||
run: |
|
||||
cd tools/readme_generator/
|
||||
pip install -r requirements.txt
|
||||
- name: Save old messges.pot for diffing later
|
||||
run: |
|
||||
cd tools/readme_generator/
|
||||
cp messages.pot messages.pot.old
|
||||
- name: Try to generate messages.pot
|
||||
run: |
|
||||
cd tools/readme_generator/
|
||||
pip install -r requirements.txt
|
||||
pybabel extract --ignore-dirs venv -F babel.cfg -o messages.pot .
|
||||
- shell: pwsh
|
||||
id: check_files_changed
|
||||
run: |
|
||||
# Diff HEAD with the previous commit
|
||||
$diff = git diff
|
||||
$HasDiff = $diff.Length -gt 0
|
||||
$HasDiff = python .github/diff_pot_files.py tools/readme_generator/messages.pot.old tools/readme_generator/messages.pot
|
||||
Write-Host "::set-output name=files_changed::$HasDiff"
|
||||
- name: Create Pull Request
|
||||
if: steps.check_files_changed.outputs.files_changed == 'true'
|
||||
|
|
21
README.md
21
README.md
|
@ -31,16 +31,17 @@ them such as their category or maintenance state. This file is regularly read by
|
|||
|
||||
To add your application to the catalog:
|
||||
|
||||
* Fork [this repository](https://github.com/YunoHost/apps)
|
||||
* Edit the [`apps.toml`](/apps.toml) file
|
||||
* Add your app's ID and git information at the right alphabetical place
|
||||
* Indicate the app's functioning state: `notworking`, `inprogress`, or `working`
|
||||
* Indicate the app category, which you can pick from `categories.toml`
|
||||
* Indicate any anti-feature that your app may be subject to, see `antifeatures.toml` (or remove the `antifeatures` key if there's none)
|
||||
* Indicate if your app can be thought of as an alternative to popular proprietary services (or remove the `potential_alternative_to` key if there's none)
|
||||
* *Do not* add the `level` entry by yourself. Our automatic test suite ("the CI") will handle it.
|
||||
* Commit and push your modifications to your repository
|
||||
* Create a [Pull Request](https://github.com/YunoHost/apps/pulls/)
|
||||
- Fork [this repository](https://github.com/YunoHost/apps)
|
||||
- Edit the [`apps.toml`](/apps.toml) file
|
||||
- Add your app's ID and git information at the right alphabetical place
|
||||
- Indicate the app's functioning state: `notworking`, `inprogress`, or `working`
|
||||
- Indicate the app category, which you can pick from `categories.toml`
|
||||
- Indicate any anti-feature that your app may be subject to, see `antifeatures.toml` (or remove the `antifeatures` key if there's none)
|
||||
- Indicate if your app can be thought of as an alternative to popular proprietary services (or remove the `potential_alternative_to` key if there's none)
|
||||
- *Do not* add the `level` entry by yourself. Our automatic test suite ("the CI") will handle it.
|
||||
- Add the app's logo inside the `logos` folder. Please keep this logo as small as possible. It also must be square (or almost square). The filename must be the name of the app in lower case.
|
||||
- Commit and push your modifications to your repository
|
||||
- Create a [Pull Request](https://github.com/YunoHost/apps/pulls/)
|
||||
|
||||
App example addition:
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ description.it = "Ti traccia e/o riporta la tua attività a chi mantiene il codi
|
|||
icon = "user-secret"
|
||||
title.en = "Tracking"
|
||||
title.eu = "Jarraipena"
|
||||
title.fr = "Pistage"
|
||||
title.fr = "Pistage "
|
||||
title.it = "Tracciamento"
|
||||
|
||||
[non-free-network]
|
||||
|
@ -19,7 +19,7 @@ description.it = "Promuove o dipende interamente da servizi di rete non liberi."
|
|||
icon = "sitemap"
|
||||
title.en = "Non-free Network Services"
|
||||
title.eu = "Libreak ez diren sareko zerbitzuak"
|
||||
title.fr = "Services réseau non libres"
|
||||
title.fr = "Services réseau non libres "
|
||||
title.it = "Servizi di rete non liberi"
|
||||
|
||||
[non-free-addons]
|
||||
|
@ -30,7 +30,7 @@ description.it = "Promoove altre applicazioni o plugin non liberi"
|
|||
icon = "puzzle-piece"
|
||||
title.en = "Non-free Addons"
|
||||
title.eu = "Libreak ez diren gehigarriak"
|
||||
title.fr = "Extensions non libres"
|
||||
title.fr = "Extensions non libres "
|
||||
title.it = "Estensioni non libere"
|
||||
|
||||
[non-free-dependencies]
|
||||
|
@ -41,7 +41,7 @@ description.it = "Per funzionare, si basa su dipendenze software non libere."
|
|||
icon = "book"
|
||||
title.en = "Non-free dependencies"
|
||||
title.eu = "Libreak ez diren dependentziak"
|
||||
title.fr = "Dépendances non libres"
|
||||
title.fr = "Dépendances non libres "
|
||||
title.it = "Dipendenze non libere"
|
||||
|
||||
[non-free-assets]
|
||||
|
@ -52,7 +52,7 @@ description.it = "Contiene ed utilizza risorse mediatiche non libere. Il caso pi
|
|||
icon = "file-image-o"
|
||||
title.en = "Non-free assets"
|
||||
title.eu = "Libreak ez diren baliabideak"
|
||||
title.fr = "Ressources non libres"
|
||||
title.fr = "Ressources non libres "
|
||||
title.it = "Risorse non libere"
|
||||
|
||||
[bad-security-reputation]
|
||||
|
@ -63,7 +63,7 @@ description.it = "Ha una cattiva reputazione in termini di sicurezza (per esempi
|
|||
icon = "bug"
|
||||
title.en = "Bad security reputation"
|
||||
title.eu = "Segurtasun txarreko ospea"
|
||||
title.fr = "Mauvaise réputation en matière de sécurité"
|
||||
title.fr = "Mauvaise réputation en matière de sécurité "
|
||||
title.it = "Cattiva reputazione di sicurezza"
|
||||
|
||||
[deprecated-software]
|
||||
|
@ -74,7 +74,7 @@ description.it = "Questo software non è più mantenuto. Ci si può aspettare ch
|
|||
icon = "trash-o"
|
||||
title.en = "Upstream not maintained"
|
||||
title.eu = "Jatorrizko garapena utzita"
|
||||
title.fr = "Application non maintenue"
|
||||
title.fr = "Application non maintenue "
|
||||
title.it = "Applicazione non mantenuta"
|
||||
|
||||
[package-not-maintained]
|
||||
|
@ -85,7 +85,7 @@ description.it = "Questo pacchetto di YunoHost non è più mantenuto e necessita
|
|||
icon = "user-times"
|
||||
title.en = "Package not maintained"
|
||||
title.eu = "Mantendu gabeko paketea"
|
||||
title.fr = "Paquet non maintenu"
|
||||
title.fr = "Paquet non maintenu "
|
||||
title.it = "Pacchetto non mantenuto"
|
||||
|
||||
[paid-content]
|
||||
|
@ -96,7 +96,7 @@ description.it = "Promuove o dipende, interamente o parzialmente, da un servizio
|
|||
icon = "money"
|
||||
title.en = "Paid content"
|
||||
title.eu = "Ordainpeko edukia"
|
||||
title.fr = "Contenu payant"
|
||||
title.fr = "Contenu payant "
|
||||
title.it = "Contenuti a pagamento"
|
||||
|
||||
[arbitrary-limitations]
|
||||
|
@ -107,7 +107,7 @@ description.it = "Contiene limitazioni arbitrarie. Fare riferimento al file “R
|
|||
icon = "star-half-empty"
|
||||
title.en = "Arbitrary limitations"
|
||||
title.eu = "Muga arbitrarioak"
|
||||
title.fr = "Limitations arbitraires"
|
||||
title.fr = "Limitations arbitraires "
|
||||
title.it = "Limitazioni arbitrarie"
|
||||
|
||||
[replaced-by-another-app]
|
||||
|
@ -118,7 +118,7 @@ description.it = "Quest’app è stata sostituita da un’altra app. Fare riferi
|
|||
icon = "repeat"
|
||||
title.en = "Replaced by another app"
|
||||
title.eu = "Beste aplikazio batek ordeztu du"
|
||||
title.fr = "Remplacé par une autre application"
|
||||
title.fr = "Remplacé par une autre application "
|
||||
title.it = "Sostituita da un’altra app"
|
||||
|
||||
[alpha-software]
|
||||
|
@ -129,25 +129,25 @@ description.it = "Questo software è all’inizio della sua fase di sviluppo. Po
|
|||
icon = "flask"
|
||||
title.en = "Alpha software"
|
||||
title.eu = "Alfa softwarea"
|
||||
title.fr = "Logiciel en version alpha"
|
||||
title.fr = "Logiciel en version alpha "
|
||||
title.it = "Software in versione alpha"
|
||||
|
||||
[not-totally-free-upstream]
|
||||
description.en = "The packaged app is under an overall free licence, but with clauses that restrict its use."
|
||||
description.en = "The packaged app is under an overall free license, but with clauses that may restrict its use."
|
||||
description.eu = "Aplikazioak lizentzia librea du orokorrean, baina bere erabilera mugatzen duten klausulekin."
|
||||
description.fr = "L'application packagée est sous une licence globalement libre, mais avec des clauses qui pourraient restreindre son utilisation."
|
||||
description.it = "Quest’applicazione è protetta da licenza generalmente libera, ma con delle clausole che potrebbero limitare il suo utilizzo."
|
||||
icon = "lock"
|
||||
title.en = "Not totally free upstream"
|
||||
title.eu = "Jatorrizkoa ez da erabat librea"
|
||||
title.fr = "Application sous licence libre restreinte"
|
||||
title.fr = "Application sous licence libre restreinte "
|
||||
title.it = "Applicazione con licenza parzialmente libera"
|
||||
|
||||
[not-totally-free-package]
|
||||
description.en = "The YunoHost package of this app is under an overall free licence, but with clauses that restrict its use."
|
||||
description.en = "The YunoHost package of this app is under an overall free license, but with clauses that may restrict its use."
|
||||
description.eu = "Aplikazio honen YunoHost paketeak lizentzia librea du orokorrean, baina bere erabilera mugatzen duten klausulekin."
|
||||
description.fr = "Le package YunoHost de cette application est sous une licence globalement libre, mais avec des clauses qui pourraient restreindre son utilisation."
|
||||
icon = "archive"
|
||||
title.en = "Not totally free package"
|
||||
title.eu = "Paketea ez da erabat librea"
|
||||
title.fr = "Package sous licence libre restreinte"
|
||||
title.fr = "Package sous licence libre restreinte "
|
||||
|
|
194
apps.toml
194
apps.toml
|
@ -49,7 +49,7 @@ url = "https://github.com/YunoHost-Apps/acropolis_ynh"
|
|||
[actual]
|
||||
added_date = 1685962455 # 2023/06/05
|
||||
category = "productivity_and_management"
|
||||
level = 7
|
||||
level = 8
|
||||
potential_alternative_to = [ "Bankin", "Budgea", "Linxo", "Microsoft Money", "Mint", "You Need A Budget" ]
|
||||
state = "working"
|
||||
subtags = [ "accounting" ]
|
||||
|
@ -173,7 +173,7 @@ url = "https://github.com/YunoHost-Apps/audiobookshelf_ynh"
|
|||
[autobrr]
|
||||
added_date = 1681591997 # 2023/04/15
|
||||
category = "multimedia"
|
||||
level = 7
|
||||
level = 8
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/autobrr_ynh"
|
||||
|
||||
|
@ -358,7 +358,7 @@ url = "https://github.com/YunoHost-Apps/castopod_ynh"
|
|||
[cesium]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "wat"
|
||||
level = 6
|
||||
level = 8
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/cesium_ynh"
|
||||
|
||||
|
@ -366,7 +366,7 @@ url = "https://github.com/YunoHost-Apps/cesium_ynh"
|
|||
added_date = 1684063245 # 2023/05/14
|
||||
antifeatures = [ "non-free-network" ]
|
||||
category = "small_utilities"
|
||||
level = 7
|
||||
level = 8
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/chatgpt-web_ynh"
|
||||
|
||||
|
@ -448,7 +448,7 @@ url = "https://github.com/YunoHost-Apps/cjdns_ynh"
|
|||
[cloudlog]
|
||||
added_date = 1685981922 # 2023/06/05
|
||||
category = "small_utilities"
|
||||
level = 7
|
||||
level = 8
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/cloudlog_ynh"
|
||||
|
||||
|
@ -488,7 +488,7 @@ url = "https://github.com/YunoHost-Apps/coin_ynh"
|
|||
[collabora]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "office"
|
||||
level = 6
|
||||
level = 8
|
||||
potential_alternative_to = [ "Apple Pages", "G Suite", "Google Docs", "Microsoft Excel", "Microsoft Office", "Microsoft Word" ]
|
||||
state = "working"
|
||||
subtags = [ "impress", "spreadsheet", "text" ]
|
||||
|
@ -582,7 +582,7 @@ url = "https://github.com/YunoHost-Apps/cowyo_ynh"
|
|||
[crabfit]
|
||||
added_date = 1710114839 # 2024/03/10
|
||||
category = "productivity_and_management"
|
||||
level = 6
|
||||
level = 7
|
||||
potential_alternative_to = [ "Doodle", "OpenSondage" ]
|
||||
state = "working"
|
||||
subtags = [ "poll" ]
|
||||
|
@ -754,7 +754,7 @@ added_date = 1674232499 # 2023/01/20
|
|||
antifeatures = [ "deprecated-software" ]
|
||||
category = "communication"
|
||||
deprecated_date = 1709075769 # 2024/02/27
|
||||
level = 8
|
||||
level = 7
|
||||
state = "working"
|
||||
subtags = [ "chat" ]
|
||||
url = "https://github.com/YunoHost-Apps/dispatch_ynh"
|
||||
|
@ -785,7 +785,7 @@ url = "https://github.com/YunoHost-Apps/django-for-runners_ynh"
|
|||
[django-fritzconnection]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "system_tools"
|
||||
level = 6
|
||||
level = 8
|
||||
state = "working"
|
||||
subtags = [ "network" ]
|
||||
url = "https://github.com/YunoHost-Apps/django-fritzconnection_ynh"
|
||||
|
@ -793,7 +793,7 @@ url = "https://github.com/YunoHost-Apps/django-fritzconnection_ynh"
|
|||
[django_example]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "dev"
|
||||
level = 8
|
||||
level = 3
|
||||
state = "working"
|
||||
subtags = [ "programming" ]
|
||||
url = "https://github.com/YunoHost-Apps/django_example_ynh"
|
||||
|
@ -926,7 +926,7 @@ url = "https://github.com/YunoHost-Apps/element_ynh"
|
|||
[element-call]
|
||||
added_date = 1697570605 # 2023/10/17
|
||||
category = "communication"
|
||||
level = 6
|
||||
level = 7
|
||||
potential_alternative_to = [ "Skype", "Zoom" ]
|
||||
state = "working"
|
||||
subtags = [ "meeting" ]
|
||||
|
@ -935,7 +935,7 @@ url = "https://github.com/YunoHost-Apps/element-call_ynh"
|
|||
[eleventy]
|
||||
added_date = 1683960849 # 2023/05/13
|
||||
category = "publishing"
|
||||
level = 7
|
||||
level = 8
|
||||
potential_alternative_to = [ "Blogger", "Blogspot", "Wix" ]
|
||||
state = "working"
|
||||
subtags = [ "blog", "website" ]
|
||||
|
@ -952,7 +952,7 @@ url = "https://github.com/YunoHost-Apps/emailpoubelle_ynh"
|
|||
[emoncms]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "iot"
|
||||
level = 6
|
||||
level = 8
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/emoncms_ynh"
|
||||
|
||||
|
@ -1065,7 +1065,7 @@ url = "https://github.com/YunoHost-Apps/fastapi_ynh"
|
|||
|
||||
[ffsync]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
antifeatures = [ "deprecated-software" ]
|
||||
antifeatures = [ "deprecated-software", "replaced-by-another-app" ]
|
||||
category = "synchronization"
|
||||
deprecated_date = 1660842060 # 2022/08/18
|
||||
level = 6
|
||||
|
@ -1099,7 +1099,7 @@ url = "https://github.com/YunoHost-Apps/filepizza_ynh"
|
|||
[firefish]
|
||||
added_date = 1691055044 # 2023/08/03
|
||||
category = "social_media"
|
||||
level = 7
|
||||
level = 0
|
||||
potential_alternative_to = [ "Calckey", "Mastodon", "Misskey", "Pleroma", "Threads", "X" ]
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/firefish_ynh"
|
||||
|
@ -1138,6 +1138,16 @@ state = "working"
|
|||
subtags = [ "forum" ]
|
||||
url = "https://github.com/YunoHost-Apps/flarum_ynh"
|
||||
|
||||
[flohmarkt]
|
||||
added_date = 1714137502 # 2024/04/26
|
||||
antifeatures = [ "alpha-software", "arbitrary-limitations" ]
|
||||
category = "publishing"
|
||||
level = 6
|
||||
potential_alternative_to = [ "ClassifiedAds.com", "kleinanzeigen.de" ]
|
||||
state = "working"
|
||||
subtags = [ "ecommerce" ]
|
||||
url = "https://github.com/YunoHost-Apps/flohmarkt_ynh"
|
||||
|
||||
[flood]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "multimedia"
|
||||
|
@ -1184,7 +1194,7 @@ url = "https://github.com/YunoHost-Apps/forgejo_ynh"
|
|||
[framaforms]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "productivity_and_management"
|
||||
level = 0
|
||||
level = 8
|
||||
potential_alternative_to = [ "Google Forms" ]
|
||||
state = "working"
|
||||
subtags = [ "poll" ]
|
||||
|
@ -1246,7 +1256,7 @@ url = "https://github.com/YunoHost-Apps/galene_ynh"
|
|||
[galette]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "productivity_and_management"
|
||||
level = 8
|
||||
level = 6
|
||||
state = "working"
|
||||
subtags = [ "business_and_ngos" ]
|
||||
url = "https://github.com/YunoHost-Apps/galette_ynh"
|
||||
|
@ -1289,7 +1299,7 @@ url = "https://github.com/YunoHost-Apps/garradin_ynh"
|
|||
[gemserv]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "communication"
|
||||
level = 6
|
||||
level = 8
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/gemserv_ynh"
|
||||
|
||||
|
@ -1339,7 +1349,7 @@ url = "https://github.com/YunoHost-Apps/gitlab-runner_ynh"
|
|||
[gitlist]
|
||||
added_date = 1675002183 # 2023/01/29
|
||||
category = "dev"
|
||||
level = 7
|
||||
level = 8
|
||||
state = "working"
|
||||
subtags = [ "forge" ]
|
||||
url = "https://github.com/YunoHost-Apps/gitlist_ynh"
|
||||
|
@ -1405,7 +1415,7 @@ url = "https://github.com/YunoHost-Apps/gotosocial_ynh"
|
|||
[grafana]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "system_tools"
|
||||
level = 8
|
||||
level = 6
|
||||
state = "working"
|
||||
subtags = [ "monitoring" ]
|
||||
url = "https://github.com/YunoHost-Apps/grafana_ynh"
|
||||
|
@ -1460,7 +1470,7 @@ url = "https://github.com/YunoHost-Apps/guacamole_ynh"
|
|||
[h5ai]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "small_utilities"
|
||||
level = 8
|
||||
level = 0
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/h5ai_ynh"
|
||||
|
||||
|
@ -1500,7 +1510,7 @@ url = "https://github.com/YunoHost-Apps/headphones_ynh"
|
|||
[headscale]
|
||||
added_date = 1686503631 # 2023/06/11
|
||||
category = "system_tools"
|
||||
level = 7
|
||||
level = 8
|
||||
potential_alternative_to = [ "Tailscale" ]
|
||||
state = "working"
|
||||
subtags = [ "network" ]
|
||||
|
@ -1546,7 +1556,7 @@ url = "https://github.com/YunoHost-Apps/homeassistant_ynh"
|
|||
[horde]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "communication"
|
||||
level = 4
|
||||
level = 7
|
||||
state = "working"
|
||||
subtags = [ "email" ]
|
||||
url = "https://github.com/YunoHost-Apps/horde_ynh"
|
||||
|
@ -1569,7 +1579,7 @@ url = "https://github.com/Yunohost-Apps/httpsh_ynh"
|
|||
[hubzilla]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "social_media"
|
||||
level = 6
|
||||
level = 8
|
||||
potential_alternative_to = [ "Facebook" ]
|
||||
state = "working"
|
||||
subtags = [ "microblogging" ]
|
||||
|
@ -1638,6 +1648,13 @@ state = "working"
|
|||
subtags = [ "accounting" ]
|
||||
url = "https://github.com/YunoHost-Apps/ihatemoney_ynh"
|
||||
|
||||
[immich]
|
||||
added_date = 1711921326 # 2024/03/31
|
||||
category = "multimedia"
|
||||
level = 7
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/immich_ynh"
|
||||
|
||||
[incus]
|
||||
added_date = 1710508401 # 2024/03/15
|
||||
category = "system_tools"
|
||||
|
@ -1666,7 +1683,7 @@ url = "https://github.com/YunoHost-Apps/influxdb_v2_ynh"
|
|||
added_date = 1674232499 # 2023/01/20
|
||||
antifeatures = [ "non-free-network" ]
|
||||
category = "social_media"
|
||||
level = 8
|
||||
level = 6
|
||||
potential_alternative_to = [ "YouTube" ]
|
||||
state = "working"
|
||||
subtags = [ "videos" ]
|
||||
|
@ -1713,8 +1730,9 @@ url = "https://github.com/YunoHost-Apps/jackett_ynh"
|
|||
|
||||
[jappix]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
antifeatures = [ "package-not-maintained" ]
|
||||
antifeatures = [ "deprecated-software", "package-not-maintained" ]
|
||||
category = "communication"
|
||||
deprecated_date = 1714590228 # 2024/05/01
|
||||
level = 7
|
||||
state = "working"
|
||||
subtags = [ "chat" ]
|
||||
|
@ -1748,7 +1766,7 @@ url = "https://github.com/YunoHost-Apps/jellyfin-vue_ynh"
|
|||
[jellyseerr]
|
||||
added_date = 1683832079 # 2023/05/11
|
||||
category = "multimedia"
|
||||
level = 7
|
||||
level = 8
|
||||
potential_alternative_to = [ "Overseerr" ]
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/jellyseerr_ynh"
|
||||
|
@ -1763,7 +1781,7 @@ url = "https://github.com/YunoHost-Apps/jenkins_ynh"
|
|||
[jirafeau]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "synchronization"
|
||||
level = 6
|
||||
level = 8
|
||||
potential_alternative_to = [ "ImageShack", "Imgur" ]
|
||||
state = "working"
|
||||
subtags = [ "files" ]
|
||||
|
@ -1772,7 +1790,7 @@ url = "https://github.com/YunoHost-Apps/jirafeau_ynh"
|
|||
[jitsi]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "communication"
|
||||
level = 6
|
||||
level = 8
|
||||
potential_alternative_to = [ "Google Hangouts", "Skype" ]
|
||||
state = "working"
|
||||
subtags = [ "meeting" ]
|
||||
|
@ -1790,11 +1808,19 @@ url = "https://github.com/YunoHost-Apps/joomla_ynh"
|
|||
[joplin]
|
||||
added_date = 1702203874 # 2023/12/10
|
||||
category = "office"
|
||||
level = 0
|
||||
state = "notworking"
|
||||
level = 7
|
||||
state = "working"
|
||||
subtags = [ "text" ]
|
||||
url = "https://github.com/YunoHost-Apps/joplin_ynh"
|
||||
|
||||
[jump]
|
||||
added_date = 1714286036 # 2024/04/28
|
||||
category = "productivity_and_management"
|
||||
level = 0
|
||||
potential_alternative_to = [ "Dashy", "Heimdall" ]
|
||||
state = "notworking"
|
||||
url = "https://github.com/YunoHost-Apps/jump_ynh"
|
||||
|
||||
[jupyterlab]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "dev"
|
||||
|
@ -1917,7 +1943,7 @@ url = "https://github.com/YunoHost-Apps/laverna_ynh"
|
|||
[leantime]
|
||||
added_date = 1683586765 # 2023/05/08
|
||||
category = "productivity_and_management"
|
||||
level = 7
|
||||
level = 8
|
||||
potential_alternative_to = [ "Asana", "ClickUp", "Notion" ]
|
||||
state = "working"
|
||||
subtags = [ "task" ]
|
||||
|
@ -2035,14 +2061,14 @@ url = "https://github.com/YunoHost-Apps/limesurvey_ynh"
|
|||
added_date = 1685604095 # 2023/06/01
|
||||
antifeatures = [ "non-free-network" ]
|
||||
category = "small_utilities"
|
||||
level = 7
|
||||
level = 8
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/lingva_ynh"
|
||||
|
||||
[linkstack]
|
||||
added_date = 1683443449 # 2023/05/07
|
||||
category = "publishing"
|
||||
level = 7
|
||||
level = 8
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/linkstack_ynh"
|
||||
|
||||
|
@ -2106,7 +2132,7 @@ url = "https://github.com/YunoHost-Apps/luckysheet_ynh"
|
|||
[lufi]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "synchronization"
|
||||
level = 8
|
||||
level = 6
|
||||
potential_alternative_to = [ "WeTransfer" ]
|
||||
state = "working"
|
||||
subtags = [ "files" ]
|
||||
|
@ -2138,7 +2164,7 @@ url = "https://github.com/YunoHost-Apps/lxd-dashboard_ynh"
|
|||
[lychee]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "multimedia"
|
||||
level = 8
|
||||
level = 6
|
||||
potential_alternative_to = [ "Flickr", "Google Photos" ]
|
||||
state = "working"
|
||||
subtags = [ "pictures" ]
|
||||
|
@ -2173,7 +2199,7 @@ url = "https://github.com/YunoHost-Apps/mastodon_ynh"
|
|||
[matomo]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "publishing"
|
||||
level = 8
|
||||
level = 6
|
||||
potential_alternative_to = [ "Google Analytics", "Xiti" ]
|
||||
state = "working"
|
||||
subtags = [ "analytics" ]
|
||||
|
@ -2218,7 +2244,7 @@ url = "https://github.com/YunoHost-Apps/mattermost_ynh"
|
|||
[mautic]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "productivity_and_management"
|
||||
level = 6
|
||||
level = 8
|
||||
potential_alternative_to = [ "Marketo", "NetResult", "SalesFusion" ]
|
||||
state = "working"
|
||||
subtags = [ "business_and_ngos" ]
|
||||
|
@ -2238,7 +2264,7 @@ added_date = 1674232499 # 2023/01/20
|
|||
antifeatures = [ "deprecated-software" ]
|
||||
category = "communication"
|
||||
deprecated_date = 1709661665 # 2024/03/05
|
||||
level = 6
|
||||
level = 0
|
||||
potential_alternative_to = [ "Facebook Messenger" ]
|
||||
state = "working"
|
||||
subtags = [ "chat" ]
|
||||
|
@ -2247,7 +2273,7 @@ url = "https://github.com/YunoHost-Apps/mautrix_facebook_ynh"
|
|||
[mautrix_signal]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "communication"
|
||||
level = 6
|
||||
level = 0
|
||||
potential_alternative_to = [ "Signal" ]
|
||||
state = "working"
|
||||
subtags = [ "chat" ]
|
||||
|
@ -2256,7 +2282,7 @@ url = "https://github.com/YunoHost-Apps/mautrix_signal_ynh"
|
|||
[mautrix_telegram]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "communication"
|
||||
level = 8
|
||||
level = 0
|
||||
potential_alternative_to = [ "Telegram" ]
|
||||
state = "working"
|
||||
subtags = [ "chat" ]
|
||||
|
@ -2265,7 +2291,7 @@ url = "https://github.com/YunoHost-Apps/mautrix_telegram_ynh"
|
|||
[mautrix_whatsapp]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "communication"
|
||||
level = 8
|
||||
level = 0
|
||||
potential_alternative_to = [ "Whatsapp" ]
|
||||
state = "working"
|
||||
subtags = [ "chat" ]
|
||||
|
@ -2274,7 +2300,7 @@ url = "https://github.com/YunoHost-Apps/mautrix_whatsapp_ynh"
|
|||
[mediawiki]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "publishing"
|
||||
level = 7
|
||||
level = 8
|
||||
state = "working"
|
||||
subtags = [ "wiki" ]
|
||||
url = "https://github.com/YunoHost-Apps/mediawiki_ynh"
|
||||
|
@ -2295,6 +2321,14 @@ state = "working"
|
|||
subtags = [ "monitoring" ]
|
||||
url = "https://github.com/YunoHost-Apps/metabase_ynh"
|
||||
|
||||
[microbin]
|
||||
added_date = 1712237414 # 2024/04/04
|
||||
category = "small_utilities"
|
||||
level = 7
|
||||
state = "working"
|
||||
subtags = [ "pastebin" ]
|
||||
url = "https://github.com/YunoHost-Apps/microbin_ynh"
|
||||
|
||||
[minchat]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "communication"
|
||||
|
@ -2386,14 +2420,14 @@ url = "https://github.com/YunoHost-Apps/mongo-express_ynh"
|
|||
[monica]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "wat"
|
||||
level = 6
|
||||
level = 0
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/monica_ynh"
|
||||
|
||||
[monitorix]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "system_tools"
|
||||
level = 6
|
||||
level = 8
|
||||
state = "working"
|
||||
subtags = [ "monitoring" ]
|
||||
url = "https://github.com/YunoHost-Apps/monitorix_ynh"
|
||||
|
@ -2440,7 +2474,7 @@ url = "https://github.com/YunoHost-Apps/movim_ynh"
|
|||
[mstream]
|
||||
added_date = 1683054560 # 2023/05/02
|
||||
category = "multimedia"
|
||||
level = 7
|
||||
level = 8
|
||||
potential_alternative_to = [ "Anchor", "Deezer", "SoundCloud", "Spotify" ]
|
||||
state = "working"
|
||||
subtags = [ "music" ]
|
||||
|
@ -2473,7 +2507,7 @@ url = "https://github.com/YunoHost-Apps/my-mind_ynh"
|
|||
[my_capsule]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "publishing"
|
||||
level = 6
|
||||
level = 7
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/my_capsule_ynh"
|
||||
|
||||
|
@ -2504,7 +2538,7 @@ url = "https://github.com/YunoHost-Apps/mygpo_ynh"
|
|||
[mytinytodo]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "productivity_and_management"
|
||||
level = 6
|
||||
level = 8
|
||||
state = "working"
|
||||
subtags = [ "task" ]
|
||||
url = "https://github.com/YunoHost-Apps/mytinytodo_ynh"
|
||||
|
@ -2703,7 +2737,7 @@ url = "https://github.com/YunoHost-Apps/opensondage_ynh"
|
|||
[opentracker]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "wat"
|
||||
level = 8
|
||||
level = 0
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/opentracker_ynh"
|
||||
|
||||
|
@ -2719,8 +2753,10 @@ url = "https://github.com/YunoHost-Apps/osada_ynh"
|
|||
|
||||
[osjs]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
antifeatures = [ "deprecated-software" ]
|
||||
category = "wat"
|
||||
level = 8
|
||||
deprecated_date = 1712777448 # 2024/04/10
|
||||
level = 7
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/osjs_ynh"
|
||||
|
||||
|
@ -3016,7 +3052,7 @@ url = "https://github.com/YunoHost-Apps/piped_ynh"
|
|||
[piwigo]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "multimedia"
|
||||
level = 6
|
||||
level = 8
|
||||
potential_alternative_to = [ "Google Photos", "Keepeek", "Koken", "Orkis Ajaris", "Orphéa" ]
|
||||
state = "working"
|
||||
subtags = [ "pictures" ]
|
||||
|
@ -3143,7 +3179,7 @@ url = "https://github.com/YunoHost-Apps/prosody_ynh"
|
|||
[prowlarr]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "multimedia"
|
||||
level = 6
|
||||
level = 8
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/prowlarr_ynh"
|
||||
|
||||
|
@ -3348,7 +3384,7 @@ url = "https://github.com/YunoHost-Apps/rocketchat_ynh"
|
|||
[roundcube]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "communication"
|
||||
level = 6
|
||||
level = 8
|
||||
potential_alternative_to = [ "GMail", "Hotmail", "Microsoft Outlook", "Yahoo! Mail" ]
|
||||
state = "working"
|
||||
subtags = [ "email" ]
|
||||
|
@ -3410,7 +3446,7 @@ url = "https://github.com/YunoHost-Apps/satdress_ynh"
|
|||
[scovie]
|
||||
added_date = 1685183203 # 2023/05/27
|
||||
category = "publishing"
|
||||
level = 7
|
||||
level = 8
|
||||
state = "working"
|
||||
subtags = [ "website" ]
|
||||
url = "https://github.com/YunoHost-Apps/scovie_ynh"
|
||||
|
@ -3541,7 +3577,7 @@ url = "https://github.com/YunoHost-Apps/signaturepdf_ynh"
|
|||
added_date = 1710170758 # 2024/03/11
|
||||
category = "office"
|
||||
level = 6
|
||||
potential_alternative_to = [ "Joplin", "Logreq", "Microsoft OneNote", "Obisian" ]
|
||||
potential_alternative_to = [ "Joplin", "Logseq", "Microsoft OneNote", "Obsidian" ]
|
||||
state = "working"
|
||||
subtags = [ "text" ]
|
||||
url = "https://github.com/YunoHost-Apps/silverbullet_ynh"
|
||||
|
@ -3549,7 +3585,7 @@ url = "https://github.com/YunoHost-Apps/silverbullet_ynh"
|
|||
[simple-file-manager]
|
||||
added_date = 1699776105 # 2023/11/12
|
||||
category = "small_utilities"
|
||||
level = 6
|
||||
level = 7
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/simple-file-manager_ynh"
|
||||
|
||||
|
@ -3582,7 +3618,7 @@ url = "https://github.com/YunoHost-Apps/simplex_ynh"
|
|||
added_date = 1685875056 # 2023/06/04
|
||||
antifeatures = [ "non-free-network" ]
|
||||
category = "small_utilities"
|
||||
level = 7
|
||||
level = 8
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/simplytranslate_ynh"
|
||||
|
||||
|
@ -3632,7 +3668,7 @@ url = "https://github.com/YunoHost-Apps/snserver_ynh"
|
|||
added_date = 1674232499 # 2023/01/20
|
||||
antifeatures = [ "package-not-maintained" ]
|
||||
category = "office"
|
||||
level = 6
|
||||
level = 7
|
||||
state = "working"
|
||||
subtags = [ "text" ]
|
||||
url = "https://github.com/YunoHost-Apps/snweb_ynh"
|
||||
|
@ -3655,7 +3691,7 @@ url = "https://github.com/YunoHost-Apps/sogo_ynh"
|
|||
[sonarr]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "multimedia"
|
||||
level = 6
|
||||
level = 8
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/sonarr_ynh"
|
||||
|
||||
|
@ -3761,7 +3797,7 @@ url = "https://github.com/YunoHost-Apps/svgedit_ynh"
|
|||
[synapse]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "communication"
|
||||
level = 6
|
||||
level = 8
|
||||
potential_alternative_to = [ "Discord", "Facebook Messenger", "Signal", "Skype", "Telegram", "Whatsapp" ]
|
||||
state = "working"
|
||||
subtags = [ "chat" ]
|
||||
|
@ -3770,7 +3806,7 @@ url = "https://github.com/YunoHost-Apps/synapse_ynh"
|
|||
[synapse-admin]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "communication"
|
||||
level = 8
|
||||
level = 1
|
||||
state = "working"
|
||||
subtags = [ "chat" ]
|
||||
url = "https://github.com/YunoHost-Apps/synapse-admin_ynh"
|
||||
|
@ -3925,7 +3961,7 @@ url = "https://github.com/YunoHost-Apps/traccar_ynh"
|
|||
[tracim]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "office"
|
||||
level = 7
|
||||
level = 8
|
||||
potential_alternative_to = [ "Dropbox", "Google Drive", "Slack", "Trello" ]
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/tracim_ynh"
|
||||
|
@ -4046,7 +4082,7 @@ url = "https://github.com/YunoHost-Apps/unattended_upgrades_ynh"
|
|||
[uptime-kuma]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "system_tools"
|
||||
level = 6
|
||||
level = 8
|
||||
state = "working"
|
||||
subtags = [ "monitoring" ]
|
||||
url = "https://github.com/YunoHost-Apps/uptime-kuma_ynh"
|
||||
|
@ -4054,7 +4090,7 @@ url = "https://github.com/YunoHost-Apps/uptime-kuma_ynh"
|
|||
[vaultwarden]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "synchronization"
|
||||
level = 6
|
||||
level = 8
|
||||
potential_alternative_to = [ "1Password", "Dashlane", "Enpass", "LastPass" ]
|
||||
state = "working"
|
||||
subtags = [ "password" ]
|
||||
|
@ -4112,7 +4148,7 @@ url = "https://github.com/YunoHost-Apps/watchdog_ynh"
|
|||
[weblate]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "dev"
|
||||
level = 7
|
||||
level = 6
|
||||
potential_alternative_to = [ "Locize", "Transifex" ]
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/weblate_ynh"
|
||||
|
@ -4127,7 +4163,7 @@ url = "https://github.com/YunoHost-Apps/webmin_ynh"
|
|||
[webtrees]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "wat"
|
||||
level = 6
|
||||
level = 1
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/webtrees_ynh"
|
||||
|
||||
|
@ -4207,12 +4243,20 @@ url = "https://github.com/YunoHost-Apps/woodpecker_ynh"
|
|||
added_date = 1674232499 # 2023/01/20
|
||||
antifeatures = [ "non-free-addons", "paid-content" ]
|
||||
category = "publishing"
|
||||
level = 6
|
||||
level = 8
|
||||
potential_alternative_to = [ "Blogger", "Blogspot", "Wix" ]
|
||||
state = "working"
|
||||
subtags = [ "blog", "website" ]
|
||||
url = "https://github.com/YunoHost-Apps/wordpress_ynh"
|
||||
|
||||
[workout-tracker]
|
||||
added_date = 1712861274 # 2024/04/11
|
||||
category = "small_utilities"
|
||||
level = 7
|
||||
potential_alternative_to = [ "Strava" ]
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/workout-tracker_ynh"
|
||||
|
||||
[writefreely]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "social_media"
|
||||
|
@ -4258,7 +4302,7 @@ url = "https://github.com/YunoHost-Apps/yacy_ynh"
|
|||
[yellow]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "publishing"
|
||||
level = 6
|
||||
level = 8
|
||||
state = "working"
|
||||
subtags = [ "website" ]
|
||||
url = "https://github.com/YunoHost-Apps/yellow_ynh"
|
||||
|
@ -4282,8 +4326,10 @@ url = "https://github.com/YunoHost-Apps/yourls_ynh"
|
|||
|
||||
[yunomonitor]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
antifeatures = [ "deprecated-software" ]
|
||||
category = "system_tools"
|
||||
level = 8
|
||||
deprecated_date = 1672947186 # 2023/01/05
|
||||
level = 7
|
||||
state = "working"
|
||||
subtags = [ "monitoring" ]
|
||||
url = "https://github.com/YunoHost-Apps/yunomonitor_ynh"
|
||||
|
@ -4306,7 +4352,7 @@ url = "https://github.com/YunoHost-Apps/z-push_ynh"
|
|||
[zabbix]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
category = "system_tools"
|
||||
level = 6
|
||||
level = 8
|
||||
state = "working"
|
||||
subtags = [ "monitoring" ]
|
||||
url = "https://github.com/YunoHost-Apps/zabbix_ynh"
|
||||
|
@ -4325,7 +4371,7 @@ url = "https://github.com/YunoHost-Apps/zap_ynh"
|
|||
added_date = 1674232499 # 2023/01/20
|
||||
antifeatures = [ "replaced-by-another-app" ]
|
||||
category = "small_utilities"
|
||||
level = 6
|
||||
level = 7
|
||||
potential_alternative_to = [ "Pastebin" ]
|
||||
state = "working"
|
||||
subtags = [ "pastebin" ]
|
||||
|
@ -4333,8 +4379,10 @@ url = "https://github.com/YunoHost-Apps/zerobin_ynh"
|
|||
|
||||
[zeronet]
|
||||
added_date = 1674232499 # 2023/01/20
|
||||
antifeatures = [ "deprecated-software" ]
|
||||
category = "wat"
|
||||
level = 6
|
||||
deprecated_date = 1714840875 # 2024/05/04
|
||||
level = 8
|
||||
potential_alternative_to = [ "Mullvad" ]
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/zeronet_ynh"
|
||||
|
@ -4352,7 +4400,7 @@ url = "https://github.com/YunoHost-Apps/zerotier_ynh"
|
|||
added_date = 1693093567 # 2023/08/26
|
||||
antifeatures = [ "non-free-dependencies" ]
|
||||
category = "system_tools"
|
||||
level = 7
|
||||
level = 0
|
||||
state = "working"
|
||||
subtags = [ "network" ]
|
||||
url = "https://github.com/YunoHost-Apps/zeroui_ynh"
|
||||
|
|
BIN
logos/flohmarkt.png
Normal file
BIN
logos/flohmarkt.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
BIN
logos/immich.png
BIN
logos/immich.png
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 29 KiB |
BIN
logos/incus.png
Normal file
BIN
logos/incus.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
logos/microbin.png
Normal file
BIN
logos/microbin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
|
@ -575,6 +575,14 @@
|
|||
},
|
||||
"force_version": {
|
||||
"type": "string"
|
||||
},
|
||||
"allow_prereleases": {
|
||||
"type": "boolean",
|
||||
"description": "Allow prereleases when using strategy = latest_X_release"
|
||||
},
|
||||
"needs_manual_tweaks": {
|
||||
"type": "boolean",
|
||||
"description": "Inform the maintainer of manual steps to make autoupdate PRs work"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
37
store/app.py
37
store/app.py
|
@ -84,6 +84,14 @@ def localize(d):
|
|||
return d["en"]
|
||||
|
||||
|
||||
@app.context_processor
|
||||
def utils():
|
||||
return {
|
||||
"user": session.get("user", {}),
|
||||
"locale": get_locale(),
|
||||
}
|
||||
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
||||
|
@ -96,8 +104,6 @@ def favicon():
|
|||
def index():
|
||||
return render_template(
|
||||
"index.html",
|
||||
locale=get_locale(),
|
||||
user=session.get("user", {}),
|
||||
catalog=get_catalog(),
|
||||
)
|
||||
|
||||
|
@ -106,12 +112,10 @@ def index():
|
|||
def browse_catalog():
|
||||
return render_template(
|
||||
"catalog.html",
|
||||
locale=get_locale(),
|
||||
init_sort=request.args.get("sort"),
|
||||
init_search=request.args.get("search"),
|
||||
init_category=request.args.get("category"),
|
||||
init_starsonly=request.args.get("starsonly"),
|
||||
user=session.get("user", {}),
|
||||
catalog=get_catalog(),
|
||||
timestamp_now=int(time.time()),
|
||||
stars=get_stars(),
|
||||
|
@ -134,8 +138,6 @@ def app_info(app_id):
|
|||
|
||||
return render_template(
|
||||
"app.html",
|
||||
locale=get_locale(),
|
||||
user=session.get("user", {}),
|
||||
app_id=app_id,
|
||||
infos=infos,
|
||||
catalog=get_catalog(),
|
||||
|
@ -184,11 +186,6 @@ def star_app(app_id, action):
|
|||
def browse_wishlist():
|
||||
return render_template(
|
||||
"wishlist.html",
|
||||
init_sort=request.args.get("sort"),
|
||||
init_search=request.args.get("search"),
|
||||
init_starsonly=request.args.get("starsonly"),
|
||||
locale=get_locale(),
|
||||
user=session.get("user", {}),
|
||||
wishlist=get_wishlist(),
|
||||
stars=get_stars(),
|
||||
)
|
||||
|
@ -208,8 +205,6 @@ def add_to_wishlist():
|
|||
)
|
||||
return render_template(
|
||||
"wishlist_add.html",
|
||||
locale=get_locale(),
|
||||
user=session.get("user", {}),
|
||||
csrf_token=None,
|
||||
successmsg=None,
|
||||
errormsg=errormsg,
|
||||
|
@ -220,8 +215,6 @@ def add_to_wishlist():
|
|||
errormsg = _("Invalid CSRF token, please refresh the page and try again")
|
||||
return render_template(
|
||||
"wishlist_add.html",
|
||||
locale=get_locale(),
|
||||
user=session.get("user", {}),
|
||||
csrf_token=csrf_token,
|
||||
successmsg=None,
|
||||
errormsg=errormsg,
|
||||
|
@ -256,7 +249,7 @@ def add_to_wishlist():
|
|||
checks = [
|
||||
(
|
||||
check_wishlist_submit_ratelimit(session["user"]["username"]) is True
|
||||
and session["user"]["bypass_ratelimit"] is False,
|
||||
or session["user"]["bypass_ratelimit"] is True,
|
||||
_(
|
||||
"Proposing wishlist additions is limited to once every 15 days per user. Please try again in a few days."
|
||||
),
|
||||
|
@ -315,8 +308,6 @@ def add_to_wishlist():
|
|||
if not check:
|
||||
return render_template(
|
||||
"wishlist_add.html",
|
||||
locale=get_locale(),
|
||||
user=session.get("user", {}),
|
||||
csrf_token=csrf_token,
|
||||
successmsg=None,
|
||||
errormsg=errormsg,
|
||||
|
@ -337,8 +328,6 @@ def add_to_wishlist():
|
|||
url = f"https://apps.yunohost.org/wishlist?search={slug}"
|
||||
return render_template(
|
||||
"wishlist_add.html",
|
||||
locale=get_locale(),
|
||||
user=session.get("user", {}),
|
||||
csrf_token=csrf_token,
|
||||
successmsg=None,
|
||||
errormsg=_(
|
||||
|
@ -354,8 +343,6 @@ def add_to_wishlist():
|
|||
url = f"https://apps.yunohost.org/app/{slug}"
|
||||
return render_template(
|
||||
"wishlist_add.html",
|
||||
locale=get_locale(),
|
||||
user=session.get("user", {}),
|
||||
csrf_token=csrf_token,
|
||||
successmsg=None,
|
||||
errormsg=_(
|
||||
|
@ -389,8 +376,6 @@ def add_to_wishlist():
|
|||
)
|
||||
return render_template(
|
||||
"wishlist_add.html",
|
||||
locale=get_locale(),
|
||||
user=session.get("user", {}),
|
||||
csrf_token=csrf_token,
|
||||
successmsg=None,
|
||||
errormsg=errormsg,
|
||||
|
@ -444,8 +429,6 @@ Description: {description}
|
|||
|
||||
return render_template(
|
||||
"wishlist_add.html",
|
||||
locale=get_locale(),
|
||||
user=session.get("user", {}),
|
||||
successmsg=successmsg,
|
||||
)
|
||||
else:
|
||||
|
@ -454,8 +437,6 @@ Description: {description}
|
|||
session["csrf_token"] = csrf_token
|
||||
return render_template(
|
||||
"wishlist_add.html",
|
||||
locale=get_locale(),
|
||||
user=session.get("user", {}),
|
||||
csrf_token=csrf_token,
|
||||
successmsg=None,
|
||||
errormsg=None,
|
||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -202,7 +202,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -121,7 +121,7 @@
|
|||
{% endif %}
|
||||
|
||||
{% if infos["antifeatures"] %}
|
||||
<h2 class="inline-block text-xl mb-2 font-semibold">{{ _("Anti-features") }}</h2>
|
||||
<h2 class="inline-block text-xl mb-2 font-semibold">{{ _("Antifeatures") }}</h2>
|
||||
<p class="inline-block text-sm">{{ _("(This app has features you may not like)") }}</p>
|
||||
<div class="my-3 rounded-md bg-red-100 text-red-800 px-5 py-2">
|
||||
<ul>
|
||||
|
|
|
@ -89,7 +89,7 @@
|
|||
type="text"
|
||||
id="search"
|
||||
placeholder="{{ _('Search for…') }}"
|
||||
{% if init_search %}value="{{ init_search }}"{% endif %}
|
||||
{% if request.args.get("search") %}value="{{ request.args.get("search") }}"{% endif %}
|
||||
class="w-full rounded-md border-gray-200 shadow-sm sm:text-sm py-2 pe-10"
|
||||
>
|
||||
|
||||
|
@ -106,7 +106,7 @@
|
|||
>
|
||||
<option value="">{{ _("All apps") }}</option>
|
||||
{% for id, category in catalog['categories'].items() %}
|
||||
<option {% if id == init_category %}selected{% endif %} value="{{ id }}">{{ category['title']|localize }}</option>
|
||||
<option {% if id == request.args.get("category") %}selected{% endif %} value="{{ id }}">{{ category['title']|localize }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -120,15 +120,15 @@
|
|||
id="selectsort"
|
||||
class="inline-block rounded-md border-gray-200 text-sm ml-1 pl-1 pr-7 h-8 py-0"
|
||||
>
|
||||
<option {% if not init_sort or init_sort == "popularity" %}selected{% endif %} value="popularity">{{ _("Popularity") }}</option>
|
||||
<option {% if init_sort == "newest" %}selected{% endif %} value="newest">{{ _("Newest") }}</option>
|
||||
<option {% if init_sort == "alpha" %}selected{% endif %} value="alpha">{{ _("Alphabetical") }}</option>
|
||||
<option {% if request.args.get("sort") in [None, "popularity"] %}selected{% endif %} value="popularity">{{ _("Popularity") }}</option>
|
||||
<option {% if request.args.get("sort") == "newest" %}selected{% endif %} value="newest">{{ _("Newest") }}</option>
|
||||
<option {% if request.args.get("sort") == "alpha" %}selected{% endif %} value="alpha">{{ _("Alphabetical") }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="inline-block flex items-center px-2 pt-2 md:pt-0 {% if not user %}text-gray-500{% endif %}" {% if not user %}title="{{ _('Requires to be logged-in') }}" aria-label="{{ _('Requires to be logged-in') }}"{% endif %}>
|
||||
<label for="starsonly" class="inline-block relative mr-2 h-4 w-7 cursor-pointer">
|
||||
<span class="sr-only">{{ _("Show only apps you starred") }}</span>
|
||||
<input type="checkbox" id="starsonly" class="peer sr-only" {% if user and init_starsonly %}checked{% endif %} {% if not user%}disabled{% endif %} >
|
||||
<input type="checkbox" id="starsonly" class="peer sr-only" {% if user and request.args.get("starsonly") %}checked{% endif %} {% if not user%}disabled{% endif %} >
|
||||
|
||||
<span class="absolute inset-0 rounded-full bg-gray-300 transition peer-checked:bg-green-500">
|
||||
</span>
|
||||
|
|
|
@ -42,14 +42,14 @@
|
|||
id="selectsort"
|
||||
class="inline-block rounded-md border-gray-200 text-sm ml-1 pl-1 pr-7 h-8 py-0"
|
||||
>
|
||||
<option {% if not init_sort or init_sort == "popularity" %}selected{% endif %} value="popularity">{{ _("Popularity") }}</option>
|
||||
<option {% if init_sort == "alpha" %}selected{% endif %} value="alpha">{{ _("Alphabetical") }}</option>
|
||||
<option {% if request.args.get("sort") in [None, "popularity"] %}selected{% endif %} value="popularity">{{ _("Popularity") }}</option>
|
||||
<option {% if request.args.get("sort") == "alpha" %}selected{% endif %} value="alpha">{{ _("Alphabetical") }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="inline-block flex items-center px-2 pt-2 md:pt-0 {% if not user %}text-gray-500{% endif %}" {% if not user %}title="{{ _('Requires to be logged-in') }}" aria-label="{{ _('Requires to be logged-in') }}"{% endif %}>
|
||||
<label for="starsonly" class="inline-block relative mr-2 h-4 w-7 cursor-pointer">
|
||||
<span class="sr-only">{{ _("Show only apps you starred") }}</span>
|
||||
<input type="checkbox" id="starsonly" class="peer sr-only" {% if user and init_starsonly %}checked{% endif %} {% if not user%}disabled{% endif %}>
|
||||
<input type="checkbox" id="starsonly" class="peer sr-only" {% if user and request.args.get("starsonly") %}checked{% endif %} {% if not user%}disabled{% endif %}>
|
||||
|
||||
<span class="absolute inset-0 rounded-full bg-gray-300 transition peer-checked:bg-green-500">
|
||||
</span>
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:04+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: ar <LL@li.org>\n"
|
||||
|
@ -204,7 +204,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:05+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: bn_BD <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:05+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: br <LL@li.org>\n"
|
||||
|
@ -207,7 +207,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-03-23 19:04+0000\n"
|
||||
"Last-Translator: OniriCorpe <oniricorpe@disroot.org>\n"
|
||||
"Language-Team: Catalan <https://translate.yunohost.org/projects/yunohost/"
|
||||
|
@ -130,8 +130,8 @@ msgid ""
|
|||
"An app with the name %(slug)s already exists in the catalog, <a "
|
||||
"href='%(url)s'>you can see its page here</a>."
|
||||
msgstr ""
|
||||
"Una aplicació amb el nom %(slug)s ja existeix al catàleg, <a href='%(url)"
|
||||
"s'>podeu veure la seva pàgina aquí</a>."
|
||||
"Una aplicació amb el nom %(slug)s ja existeix al catàleg, <a "
|
||||
"href='%(url)s'>podeu veure la seva pàgina aquí</a>."
|
||||
|
||||
#: app.py:386
|
||||
#, python-format
|
||||
|
@ -239,7 +239,9 @@ msgid "Important infos before installing"
|
|||
msgstr "Informació important abans d'instal·lar"
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
#, fuzzy
|
||||
#| msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr "Anticaracterístiques"
|
||||
|
||||
#: templates/app.html:125
|
||||
|
@ -319,8 +321,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Fet amb <i class='text-red-500 fa fa-heart-o' aria-label='love'></i> fent "
|
||||
"servir <a class='text-blue-800' href='https://flask.palletsprojects."
|
||||
"com'>Flask</a> i <a class='text-blue-800' href='https://tailwindcss.com/"
|
||||
"'>TailwindCSS</a>"
|
||||
"com'>Flask</a> i <a class='text-blue-800' href='https://tailwindcss."
|
||||
"com/'>TailwindCSS</a>"
|
||||
|
||||
#: templates/base.html:198
|
||||
msgid "Source"
|
||||
|
@ -431,8 +433,8 @@ msgid ""
|
|||
"to integrate it, and is merely a source of inspiration for packaging "
|
||||
"volunteers."
|
||||
msgstr ""
|
||||
"La llista de desitjos és el lloc on les persones poden suggerir i votar col·"
|
||||
"lectivament les aplicacions que els agradaria veure empaquetades i "
|
||||
"La llista de desitjos és el lloc on les persones poden suggerir i votar "
|
||||
"col·lectivament les aplicacions que els agradaria veure empaquetades i "
|
||||
"disponibles al catàleg oficial d'aplicacions de YunoHost. No obstant això, "
|
||||
"el fet que les aplicacions s'enumeren aquí no s'ha d'interpretar de cap "
|
||||
"manera com un fet que el projecte YunoHost té previst integrar-lo, i és "
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: ckb <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:09+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: cs <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:05+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: da <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-03-23 19:04+0000\n"
|
||||
"Last-Translator: OniriCorpe <oniricorpe@disroot.org>\n"
|
||||
"Language-Team: German <https://translate.yunohost.org/projects/yunohost/apps/"
|
||||
|
@ -248,7 +248,9 @@ msgid "Important infos before installing"
|
|||
msgstr "Wichtige Informationen vor der Installation"
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
#, fuzzy
|
||||
#| msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr "Anti-Funktionen"
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:06+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: el <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:06+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: eo <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-03-23 00:54+0000\n"
|
||||
"Last-Translator: OniriCorpe <oniricorpe@disroot.org>\n"
|
||||
"Language-Team: Spanish <https://translate.yunohost.org/projects/yunohost/"
|
||||
|
@ -205,7 +205,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-03-23 13:39+0000\n"
|
||||
"Last-Translator: xabirequejo <xabi.rn@gmail.com>\n"
|
||||
"Language-Team: Basque <https://translate.yunohost.org/projects/yunohost/apps/"
|
||||
|
@ -133,8 +133,8 @@ msgid ""
|
|||
"An app with the name %(slug)s already exists in the catalog, <a "
|
||||
"href='%(url)s'>you can see its page here</a>."
|
||||
msgstr ""
|
||||
"Lehendik ere dago %(slug)s izena duen aplikazioa katalogoan, <a href='%(url)"
|
||||
"s'>hemen ikus dezakezu</a>."
|
||||
"Lehendik ere dago %(slug)s izena duen aplikazioa katalogoan, <a "
|
||||
"href='%(url)s'>hemen ikus dezakezu</a>."
|
||||
|
||||
#: app.py:386
|
||||
#, python-format
|
||||
|
@ -236,7 +236,9 @@ msgid "Important infos before installing"
|
|||
msgstr "Informazio garrantzitsua instalatu baino lehen"
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
#, fuzzy
|
||||
#| msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr "Ezaugarri zalantzagarriak"
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: fa <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:06+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: fi <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-03-23 19:04+0000\n"
|
||||
"Last-Translator: OniriCorpe <oniricorpe@disroot.org>\n"
|
||||
"Language-Team: French <https://translate.yunohost.org/projects/yunohost/apps/"
|
||||
|
@ -130,8 +130,8 @@ msgid ""
|
|||
"An app with the name %(slug)s already exists in the catalog, <a "
|
||||
"href='%(url)s'>you can see its page here</a>."
|
||||
msgstr ""
|
||||
"Une app nommée %(slug)s existe déjà dans le catalogue, <a href='%(url)"
|
||||
"s'>vous pouvez voir sa page ici</a>."
|
||||
"Une app nommée %(slug)s existe déjà dans le catalogue, <a "
|
||||
"href='%(url)s'>vous pouvez voir sa page ici</a>."
|
||||
|
||||
#: app.py:386
|
||||
#, python-format
|
||||
|
@ -238,7 +238,9 @@ msgid "Important infos before installing"
|
|||
msgstr "Informations importantes avant l'installation"
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
#, fuzzy
|
||||
#| msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr "Anti-fonctionnalités"
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-03-23 19:04+0000\n"
|
||||
"Last-Translator: OniriCorpe <oniricorpe@disroot.org>\n"
|
||||
"Language-Team: Galician <https://translate.yunohost.org/projects/yunohost/"
|
||||
|
@ -235,7 +235,9 @@ msgid "Important infos before installing"
|
|||
msgstr "Información importante antes de instalar"
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
#, fuzzy
|
||||
#| msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr "Características non desexables"
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:06+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: he <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:06+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: hi <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:06+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: hu <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:06+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: id <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: it <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: ja <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: kab <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:05+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: ko <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: lt <LL@li.org>\n"
|
||||
|
@ -204,7 +204,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: mk <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: nb_NO <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: ne <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: nl <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: oc <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: pl <LL@li.org>\n"
|
||||
|
@ -204,7 +204,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: pt <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: pt_BR <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: ru <LL@li.org>\n"
|
||||
|
@ -204,7 +204,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: sk <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: sl <LL@li.org>\n"
|
||||
|
@ -204,7 +204,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:09+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: sv <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:09+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: te <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:09+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: tr <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:09+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: uk <LL@li.org>\n"
|
||||
|
@ -204,7 +204,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-22 04:59+0100\n"
|
||||
"POT-Creation-Date: 2024-04-01 00:57+0200\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:05+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: zh_Hans <LL@li.org>\n"
|
||||
|
@ -203,7 +203,7 @@ msgid "Important infos before installing"
|
|||
msgstr ""
|
||||
|
||||
#: templates/app.html:124
|
||||
msgid "Anti-features"
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:125
|
||||
|
|
|
@ -77,7 +77,7 @@ def __app_cache_clone_or_update_mapped(data):
|
|||
try:
|
||||
app_cache_clone_or_update(name, info)
|
||||
except Exception as err:
|
||||
logging.error("Error while updating %s: %s", name, err)
|
||||
logging.error("[App caches] Error while updating %s: %s", name, err)
|
||||
|
||||
|
||||
def apps_cache_update_all(apps: dict[str, dict[str, Any]], parallel: int = 8) -> None:
|
||||
|
|
44
tools/app_generator/README.md
Normal file
44
tools/app_generator/README.md
Normal file
|
@ -0,0 +1,44 @@
|
|||
# YunoHost app generator
|
||||
|
||||
This is a Flask app generating a draft .zip of a YunoHost application after filling a form
|
||||
|
||||
Official instance: https://appgenerator.yunohost.org/
|
||||
|
||||
## Developement
|
||||
|
||||
```bash
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip3 install -r requirements.txt
|
||||
|
||||
# you need to manually download the assets to have access to the css and the javascript files
|
||||
(cd assets && bash fetch_assets)
|
||||
```
|
||||
|
||||
And then start the dev server:
|
||||
|
||||
```bash
|
||||
source venv/bin/activate
|
||||
FLASK_APP=app.py FLASK_ENV=development flask --debug run
|
||||
```
|
||||
|
||||
## Translation
|
||||
|
||||
It's based on Flask-Babel : <https://python-babel.github.io/flask-babel/>
|
||||
|
||||
```bash
|
||||
source venv/bin/activate
|
||||
|
||||
# Extract the english sentences from the code, needed if you modified it
|
||||
pybabel extract --ignore-dirs venv -F babel.cfg -o messages.pot .
|
||||
|
||||
# If working on a new locale: initialize it (in this example: fr)
|
||||
pybabel init -i messages.pot -d translations -l fr
|
||||
# Otherwise, update the existing .po:
|
||||
pybabel update -i messages.pot -d translations
|
||||
|
||||
# ... translate stuff in translations/<lang>/LC_MESSAGES/messages.po
|
||||
# re-run the 'update' command to let Babel properly format the text
|
||||
# then compile:
|
||||
pybabel compile -d translations
|
||||
```
|
812
tools/app_generator/app.py
Normal file
812
tools/app_generator/app.py
Normal file
|
@ -0,0 +1,812 @@
|
|||
#### Imports
|
||||
import logging
|
||||
from io import BytesIO
|
||||
import re
|
||||
import os
|
||||
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,
|
||||
)
|
||||
from wtforms.fields import HiddenField
|
||||
|
||||
# Translations
|
||||
from flask_babel import Babel
|
||||
from flask_babel import lazy_gettext as _
|
||||
|
||||
from flask import redirect, request, make_response # Language swap by redirecting
|
||||
|
||||
# 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
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
#### GLOBAL VARIABLES
|
||||
YOLOGEN_VERSION = "0.10"
|
||||
GENERATOR_DICT = {"GENERATOR_VERSION": YOLOGEN_VERSION}
|
||||
|
||||
#### 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/"))
|
||||
|
||||
|
||||
def is_hidden_field_filter(field):
|
||||
|
||||
return isinstance(field, HiddenField)
|
||||
|
||||
|
||||
app.jinja_env.globals["bootstrap_is_hidden_field"] = is_hidden_field_filter
|
||||
|
||||
# Handle translations
|
||||
BABEL_TRANSLATION_DIRECTORIES = "translations"
|
||||
|
||||
babel = Babel()
|
||||
|
||||
LANGUAGES = {"en": _("English"), "fr": _("French")}
|
||||
|
||||
|
||||
@app.context_processor
|
||||
def inject_conf_var():
|
||||
return dict(AVAILABLE_LANGUAGES=LANGUAGES)
|
||||
|
||||
|
||||
def configure(app):
|
||||
babel.init_app(app, locale_selector=get_locale)
|
||||
app.config["LANGUAGES"] = LANGUAGES
|
||||
|
||||
|
||||
def get_locale():
|
||||
print(request.accept_languages.best_match(app.config["LANGUAGES"].keys()))
|
||||
print(request.cookies.get("lang", "en"))
|
||||
# return 'en' # to test
|
||||
# return 'fr'
|
||||
if request.args.get("language"):
|
||||
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)
|
||||
|
||||
#### 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
|
||||
|
||||
|
||||
# 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(
|
||||
_("Select language"),
|
||||
choices=[("none", "")] + [language for language in LANGUAGES.items()],
|
||||
default=["en"],
|
||||
id="selectLanguage",
|
||||
)
|
||||
|
||||
|
||||
class GeneralInfos(FlaskForm):
|
||||
|
||||
app_id = StringField(
|
||||
Markup(_("Application identifier (id)")),
|
||||
description=_("Small caps and without spaces"),
|
||||
validators=[DataRequired(), Regexp("[a-z_1-9]+.*(?<!_ynh)$")],
|
||||
render_kw={
|
||||
"placeholder": "my_super_app",
|
||||
},
|
||||
)
|
||||
|
||||
app_name = StringField(
|
||||
_("App name"),
|
||||
description=_("It's the application name, displayed in the user interface"),
|
||||
validators=[DataRequired()],
|
||||
render_kw={
|
||||
"placeholder": "My super App",
|
||||
},
|
||||
)
|
||||
|
||||
description_en = StringField(
|
||||
_("Short description (en)"),
|
||||
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"
|
||||
),
|
||||
validators=[DataRequired()],
|
||||
)
|
||||
description_fr = StringField(
|
||||
_("Short description (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"
|
||||
),
|
||||
validators=[DataRequired()],
|
||||
)
|
||||
|
||||
|
||||
class IntegrationInfos(FlaskForm):
|
||||
|
||||
# TODO : people shouldnt have to put the ~ynh1 ? This should be added automatically when rendering the app files ?
|
||||
version = StringField(
|
||||
_("Version"),
|
||||
validators=[Regexp("\d{1,4}.\d{1,4}(.\d{1,4})?(.\d{1,4})?~ynh\d+")],
|
||||
render_kw={"placeholder": "1.0~ynh1"},
|
||||
)
|
||||
|
||||
maintainers = StringField(
|
||||
_("Maintainer of the generated app"),
|
||||
description=_("Usually you put your name here... If you're okay with it ;)"),
|
||||
)
|
||||
|
||||
yunohost_required_version = StringField(
|
||||
_("Minimal YunoHost version"),
|
||||
description=_("Minimal YunoHost version for the application to work"),
|
||||
render_kw={
|
||||
"placeholder": "11.1.21",
|
||||
},
|
||||
)
|
||||
|
||||
architectures = SelectMultipleField(
|
||||
_("Supported architectures"),
|
||||
choices=[
|
||||
("all", _("All architectures")),
|
||||
("amd64", "amd64"),
|
||||
("i386", "i386"),
|
||||
("armhf", "armhf"),
|
||||
("arm64", "arm64"),
|
||||
],
|
||||
default=["all"],
|
||||
validators=[DataRequired()],
|
||||
)
|
||||
|
||||
multi_instance = BooleanField(
|
||||
_(
|
||||
"The app can be installed multiple times at the same time on the same server"
|
||||
),
|
||||
default=True,
|
||||
)
|
||||
|
||||
ldap = SelectField(
|
||||
_("The app will be integrating LDAP"),
|
||||
description=_(
|
||||
"Which means it's possible to use Yunohost credentials to log into this app. 'LDAP' corresponds to the technology used by Yunohost to handle a centralised user base. Bridging the app and Yunohost's LDAP often requires to add the proper technical details in the app's configuration file"
|
||||
),
|
||||
choices=[
|
||||
("false", _("No")),
|
||||
("true", _("Yes")),
|
||||
("not_relevant", _("Not relevant")),
|
||||
],
|
||||
default="not_relevant",
|
||||
validators=[DataRequired()],
|
||||
)
|
||||
sso = SelectField(
|
||||
_("The app will be integrated in Yunohost SSO (Single Sign On)"),
|
||||
description=_(
|
||||
"Which means that people will be logged in the app after logging in YunoHost's portal, without having to sign on specifically into this app."
|
||||
),
|
||||
choices=[
|
||||
("false", _("Yes")),
|
||||
("true", _("No")),
|
||||
("not_relevant", _("Not relevant")),
|
||||
],
|
||||
default="not_relevant",
|
||||
validators=[DataRequired()],
|
||||
)
|
||||
|
||||
|
||||
class UpstreamInfos(FlaskForm):
|
||||
|
||||
license = StringField(
|
||||
_("Licence"),
|
||||
description=_(
|
||||
"You should check this on the upstream repository. The expected format is a SPDX id listed in https://spdx.org/licenses/"
|
||||
),
|
||||
validators=[DataRequired()],
|
||||
)
|
||||
|
||||
website = StringField(
|
||||
_("Official website"),
|
||||
description=_("Leave empty if there is no official website"),
|
||||
validators=[URL(), Optional()],
|
||||
render_kw={
|
||||
"placeholder": "https://awesome-app-website.com",
|
||||
},
|
||||
)
|
||||
demo = StringField(
|
||||
_("Official app demo"),
|
||||
description=_("Leave empty if there is no official demo"),
|
||||
validators=[URL(), Optional()],
|
||||
render_kw={
|
||||
"placeholder": "https://awesome-app-website.com/demo",
|
||||
},
|
||||
)
|
||||
admindoc = StringField(
|
||||
_("Admin documentation"),
|
||||
description=_("Leave empty if there is no official admin doc"),
|
||||
validators=[URL(), Optional()],
|
||||
render_kw={
|
||||
"placeholder": "https://awesome-app-website.com/doc/admin",
|
||||
},
|
||||
)
|
||||
userdoc = StringField(
|
||||
_("Usage documentation"),
|
||||
description=_("Leave empty if there is no official user doc"),
|
||||
validators=[URL(), Optional()],
|
||||
render_kw={
|
||||
"placeholder": "https://awesome-app-website.com/doc/user",
|
||||
},
|
||||
)
|
||||
code = StringField(
|
||||
_("Code repository"),
|
||||
validators=[URL(), DataRequired()],
|
||||
render_kw={
|
||||
"placeholder": "https://some.git.forge/org/app",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class InstallQuestions(FlaskForm):
|
||||
|
||||
domain_and_path = SelectField(
|
||||
_(
|
||||
"Ask the URL where the app will be installed ('domain' and 'path' variables)"
|
||||
),
|
||||
default="true",
|
||||
choices=[
|
||||
("true", _("Ask domain+path")),
|
||||
(
|
||||
"full_domain",
|
||||
_(
|
||||
"Ask only the domain (the app requires to be installed at the root of a dedicated domain)"
|
||||
),
|
||||
),
|
||||
("false", _("Do not ask (it isn't a webapp)")),
|
||||
],
|
||||
)
|
||||
|
||||
init_main_permission = BooleanField(
|
||||
_("Ask who can access to the app"),
|
||||
description=_(
|
||||
"In the users groups : by default at least 'visitors', 'all_users' et 'admins' exists. (It was previously the private/public app concept)"
|
||||
),
|
||||
default=True,
|
||||
)
|
||||
|
||||
init_admin_permission = BooleanField(
|
||||
_("Ask who can access to the admin interface"),
|
||||
description=_("In the case where the app has an admin interface"),
|
||||
default=False,
|
||||
)
|
||||
|
||||
language = SelectMultipleField(
|
||||
_("Supported languages"),
|
||||
choices=[
|
||||
("_", _("None / not relevant")),
|
||||
("en", _("English")),
|
||||
("fr", _("French")),
|
||||
("en", _("Spanish")),
|
||||
("it", _("Italian")),
|
||||
("de", _("German")),
|
||||
("zh", _("Chinese")),
|
||||
("jp", _("Japanese")),
|
||||
("da", _("Danish")),
|
||||
("pt", _("Portugese")),
|
||||
("nl", _("Dutch")),
|
||||
("ru", _("Russian")),
|
||||
],
|
||||
default=["_"],
|
||||
validators=[DataRequired()],
|
||||
)
|
||||
|
||||
|
||||
# manifest
|
||||
class Ressources(FlaskForm):
|
||||
|
||||
# Sources
|
||||
source_url = StringField(
|
||||
_("Application source code or executable"),
|
||||
validators=[DataRequired(), URL()],
|
||||
render_kw={
|
||||
"placeholder": "https://github.com/foo/bar/archive/refs/tags/v1.2.3.tar.gz",
|
||||
},
|
||||
)
|
||||
sha256sum = StringField(
|
||||
_("Sources sha256 checksum"),
|
||||
validators=[DataRequired(), Length(min=64, max=64)],
|
||||
render_kw={
|
||||
"placeholder": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||
},
|
||||
)
|
||||
|
||||
auto_update = SelectField(
|
||||
_("Enable automatic update of sources (using a bot running every night)"),
|
||||
description=_(
|
||||
"If the upstream software is hosted in one of the handled sources and publishes proper releases or tags, the bot will create a pull request to update the sources URL and checksum"
|
||||
),
|
||||
default="none",
|
||||
choices=[
|
||||
("none", "Non"),
|
||||
("latest_github_tag", "Github (tag)"),
|
||||
("latest_github_release", "Github (release)"),
|
||||
("latest_github_commit", "Github (commit)"),
|
||||
("latest_gitlab_tag", "Gitlab (tag)"),
|
||||
("latest_gitlab_release", "Gitlab (release)"),
|
||||
("latest_gitlab_commit", "Gitlab (commit)"),
|
||||
("latest_gitea_tag", "Gitea (tag)"),
|
||||
("latest_gitea_release", "Gitea (release)"),
|
||||
("latest_gitea_commit", "Gitea (commit)"),
|
||||
("latest_forgejo_tag", "Forgejo (tag)"),
|
||||
("latest_forgejo_release", "Forgejo (release)"),
|
||||
("latest_forgejo_commit", "Forgejo (commit)"),
|
||||
],
|
||||
)
|
||||
|
||||
apt_dependencies = StringField(
|
||||
_("Dependencies to be installed via apt (separated by comma and/or spaces)"),
|
||||
render_kw={
|
||||
"placeholder": "foo, bar2.1-ext, libwat",
|
||||
},
|
||||
)
|
||||
|
||||
database = SelectField(
|
||||
_("Initialize an SQL database"),
|
||||
choices=[
|
||||
("false", "Non"),
|
||||
("mysql", "MySQL/MariaDB"),
|
||||
("postgresql", "PostgreSQL"),
|
||||
],
|
||||
default="false",
|
||||
)
|
||||
|
||||
system_user = BooleanField(
|
||||
_("Initialize a system user for this app"),
|
||||
default=True,
|
||||
)
|
||||
|
||||
install_dir = BooleanField(
|
||||
_("Initialize an installation folder for this app"),
|
||||
description=_("By default it's /var/www/$app"),
|
||||
default=True,
|
||||
)
|
||||
|
||||
data_dir = BooleanField(
|
||||
_("Initialize a folder to store the app data"),
|
||||
description=_("By default it's /var/yunohost.app/$app"),
|
||||
default=False,
|
||||
)
|
||||
|
||||
|
||||
class SpecificTechnology(FlaskForm):
|
||||
|
||||
main_technology = SelectField(
|
||||
_("App main technology"),
|
||||
choices=[
|
||||
("none", _("None / Static application")),
|
||||
("php", "PHP"),
|
||||
("nodejs", "NodeJS"),
|
||||
("python", "Python"),
|
||||
("ruby", "Ruby"),
|
||||
("other", _("Other")),
|
||||
],
|
||||
default="none",
|
||||
validators=[DataRequired()],
|
||||
)
|
||||
|
||||
install_snippet = TextAreaField(
|
||||
_("Installation specific commands"),
|
||||
description=_(
|
||||
"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()],
|
||||
render_kw={"spellcheck": "false"},
|
||||
)
|
||||
|
||||
#
|
||||
# PHP
|
||||
#
|
||||
|
||||
use_composer = BooleanField(
|
||||
_("Use composer"),
|
||||
description=_("Composer is a PHP dependencies manager used by some apps"),
|
||||
default=False,
|
||||
)
|
||||
|
||||
#
|
||||
# NodeJS
|
||||
#
|
||||
|
||||
nodejs_version = StringField(
|
||||
_("NodeJS version"),
|
||||
description=_("For example: 16.4, 18, 18.2, 20, 20.1, ..."),
|
||||
render_kw={
|
||||
"placeholder": "20",
|
||||
},
|
||||
)
|
||||
|
||||
use_yarn = BooleanField(
|
||||
_("Install and use Yarn"),
|
||||
default=False,
|
||||
)
|
||||
|
||||
# NodeJS / Python / Ruby / ...
|
||||
|
||||
systemd_execstart = StringField(
|
||||
_("Command to start the app daemon (from systemd service)"),
|
||||
description=_(
|
||||
"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={
|
||||
"placeholder": "__INSTALL_DIR__/bin/app --some-option",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class AppConfig(FlaskForm):
|
||||
|
||||
use_custom_config_file = BooleanField(
|
||||
_("The app uses a specific configuration file"),
|
||||
description=_("Usually : .env, config.json, conf.ini, params.yml, ..."),
|
||||
default=False,
|
||||
)
|
||||
|
||||
custom_config_file = StringField(
|
||||
_("Name or file path to use"),
|
||||
validators=[Optional()],
|
||||
render_kw={
|
||||
"placeholder": "config.json",
|
||||
},
|
||||
)
|
||||
|
||||
custom_config_file_content = TextAreaField(
|
||||
_("App configuration file pattern"),
|
||||
description=_(
|
||||
"In this pattern, you can use the syntax __FOO_BAR__ which will automatically replaced by the value of the variable $foo_bar"
|
||||
),
|
||||
validators=[Optional()],
|
||||
render_kw={"spellcheck": "false"},
|
||||
)
|
||||
|
||||
|
||||
class Documentation(FlaskForm):
|
||||
# TODO : # screenshot
|
||||
description = TextAreaField(
|
||||
Markup(
|
||||
_(
|
||||
"""doc/DESCRIPTION.md: A comprehensive presentation of the app, possibly listing the main features, possible warnings and specific details on its functioning in Yunohost (e.g. warning about integration issues)."""
|
||||
)
|
||||
),
|
||||
validators=[Optional()],
|
||||
render_kw={
|
||||
"spellcheck": "false",
|
||||
},
|
||||
)
|
||||
pre_install = TextAreaField(
|
||||
_(
|
||||
"doc/PRE_INSTALL.md: important info to be shown to the admin before installing the app"
|
||||
),
|
||||
description=_("Leave empty if not relevant"),
|
||||
validators=[Optional()],
|
||||
render_kw={
|
||||
"spellcheck": "false",
|
||||
},
|
||||
)
|
||||
post_install = TextAreaField(
|
||||
_(
|
||||
"doc/POST_INSTALL.md: important info to be shown to the admin after installing the app"
|
||||
),
|
||||
description=_("Leave empty if not relevant"),
|
||||
validators=[Optional()],
|
||||
render_kw={
|
||||
"spellcheck": "false",
|
||||
},
|
||||
)
|
||||
pre_upgrade = TextAreaField(
|
||||
_(
|
||||
"doc/PRE_UPGRADE.md: important info to be shown to the admin before upgrading the app"
|
||||
),
|
||||
description=_("Leave empty if not relevant"),
|
||||
validators=[Optional()],
|
||||
render_kw={
|
||||
"spellcheck": "false",
|
||||
},
|
||||
)
|
||||
post_upgrade = TextAreaField(
|
||||
_(
|
||||
"doc/POST_UPGRADE.md: important info to be shown to the admin after upgrading the app"
|
||||
),
|
||||
description=_("Leave empty if not relevant"),
|
||||
validators=[Optional()],
|
||||
render_kw={
|
||||
"spellcheck": "false",
|
||||
},
|
||||
)
|
||||
admin = TextAreaField(
|
||||
_("doc/ADMIN.md: general tips on how to administrate this app"),
|
||||
description=_("Leave empty if not relevant"),
|
||||
validators=[Optional()],
|
||||
render_kw={
|
||||
"spellcheck": "false",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class MoreAdvanced(FlaskForm):
|
||||
|
||||
enable_change_url = BooleanField(
|
||||
_("Handle app install URL change (change_url script)"),
|
||||
default=True,
|
||||
render_kw={
|
||||
"title": _("Should changing the app URL be allowed ? (change_url change)")
|
||||
},
|
||||
)
|
||||
|
||||
use_logrotate = BooleanField(
|
||||
_("Use logrotate for the app logs"),
|
||||
default=True,
|
||||
render_kw={
|
||||
"title": _(
|
||||
"If the app generates logs, this option permit to handle their archival. Recommended."
|
||||
)
|
||||
},
|
||||
)
|
||||
# TODO : specify custom log file
|
||||
# custom_log_file = "/var/log/$app/$app.log" "/var/log/nginx/${domain}-error.log"
|
||||
use_fail2ban = BooleanField(
|
||||
_("Protect the application against brute force attacks (via fail2ban)"),
|
||||
default=False,
|
||||
render_kw={
|
||||
"title": _(
|
||||
"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(
|
||||
_("Add a CRON task for this application"),
|
||||
description=_("Corresponds to some app periodic operations"),
|
||||
default=False,
|
||||
)
|
||||
cron_config_file = TextAreaField(
|
||||
_("Type the CRON file content"),
|
||||
validators=[Optional()],
|
||||
render_kw={
|
||||
"class": "form-control",
|
||||
"spellcheck": "false",
|
||||
},
|
||||
)
|
||||
|
||||
fail2ban_regex = StringField(
|
||||
_("Regular expression for fail2ban"),
|
||||
# Regex to match into the log for a failed login
|
||||
validators=[Optional()],
|
||||
render_kw={
|
||||
"placeholder": _("A regular expression"),
|
||||
"class": "form-control",
|
||||
"title": _(
|
||||
"Regular expression to check in the log file to activate failban (search for a line that indicates a credentials error)."
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
## Main form
|
||||
class GeneratorForm(
|
||||
GeneralInfos,
|
||||
IntegrationInfos,
|
||||
UpstreamInfos,
|
||||
InstallQuestions,
|
||||
Ressources,
|
||||
SpecificTechnology,
|
||||
AppConfig,
|
||||
Documentation,
|
||||
MoreAdvanced,
|
||||
):
|
||||
|
||||
class Meta:
|
||||
csrf = False
|
||||
|
||||
generator_mode = SelectField(
|
||||
_("Generator mode"),
|
||||
description=_(
|
||||
"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", _("Streamlined version")),
|
||||
("tutorial", _("Tutorial version")),
|
||||
],
|
||||
default="true",
|
||||
validators=[DataRequired()],
|
||||
)
|
||||
|
||||
submit_preview = SubmitField(_("Previsualise"))
|
||||
submit_download = SubmitField(_("Download the .zip"))
|
||||
submit_demo = SubmitField(
|
||||
_("Fill with demo values"),
|
||||
render_kw={
|
||||
"onclick": "fillFormWithDefaultValues()",
|
||||
"title": _(
|
||||
"Generate a complete and functionnal minimalistic app that you can iterate from"
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
#### Web pages
|
||||
@app.route("/", methods=["GET", "POST"])
|
||||
def main_form_route():
|
||||
|
||||
main_form = GeneratorForm()
|
||||
app_files = []
|
||||
|
||||
if request.method == "POST":
|
||||
|
||||
if not main_form.validate_on_submit():
|
||||
logging.error("Form not validated?")
|
||||
logging.error(main_form.errors)
|
||||
|
||||
return render_template(
|
||||
"index.html",
|
||||
main_form=main_form,
|
||||
generator_info=GENERATOR_DICT,
|
||||
generated_files={},
|
||||
)
|
||||
|
||||
if main_form.submit_preview.data:
|
||||
submit_mode = "preview"
|
||||
elif main_form.submit_demo.data:
|
||||
submit_mode = "demo" # TODO : for now this always trigger a preview. Not sure if that's an issue
|
||||
else:
|
||||
submit_mode = "download"
|
||||
|
||||
class AppFile:
|
||||
def __init__(self, id_, destination_path=None):
|
||||
self.id = id_
|
||||
self.destination_path = destination_path
|
||||
self.content = None
|
||||
|
||||
app_files = [
|
||||
AppFile("manifest", "manifest.toml"),
|
||||
AppFile("tests", "tests.toml"), # TODO test this
|
||||
AppFile("_common.sh", "scripts/_common.sh"),
|
||||
AppFile("install", "scripts/install"),
|
||||
AppFile("remove", "scripts/remove"),
|
||||
AppFile("backup", "scripts/backup"),
|
||||
AppFile("restore", "scripts/restore"),
|
||||
AppFile("upgrade", "scripts/upgrade"),
|
||||
AppFile("nginx", "conf/nginx.conf"),
|
||||
]
|
||||
|
||||
if main_form.enable_change_url.data:
|
||||
app_files.append(AppFile("change_url", "scripts/change_url"))
|
||||
|
||||
if main_form.main_technology.data not in ["none", "php"]:
|
||||
app_files.append(AppFile("systemd", "conf/systemd.service"))
|
||||
|
||||
# TODO : buggy, tries to open php.j2
|
||||
# if main_form.main_technology.data == "php":
|
||||
# app_files.append(AppFile("php", "conf/extra_php-fpm.conf"))
|
||||
|
||||
if main_form.description.data:
|
||||
app_files.append(AppFile("DESCRIPTION", "doc/DESCRIPTION.md"))
|
||||
|
||||
if main_form.pre_install.data:
|
||||
app_files.append(AppFile("PRE_INSTALL", "doc/PRE_INSTALL.md"))
|
||||
|
||||
if main_form.post_install.data:
|
||||
app_files.append(AppFile("POST_INSTALL", "doc/POST_INSTALL.md"))
|
||||
|
||||
if main_form.pre_upgrade.data:
|
||||
app_files.append(AppFile("PRE_UPGRADE", "doc/PRE_UPGRADE.md"))
|
||||
|
||||
if main_form.post_upgrade.data:
|
||||
app_files.append(AppFile("POST_UPGRADE", "doc/POST_UPGRADE.md"))
|
||||
|
||||
if main_form.admin.data:
|
||||
app_files.append(AppFile("ADMIN", "doc/ADMIN.md"))
|
||||
|
||||
template_dir = os.path.dirname(__file__) + "/templates/"
|
||||
for app_file in app_files:
|
||||
template = open(template_dir + app_file.id + ".j2").read()
|
||||
app_file.content = render_template_string(
|
||||
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)
|
||||
|
||||
print(main_form.use_custom_config_file.data)
|
||||
if main_form.use_custom_config_file.data:
|
||||
app_files.append(
|
||||
AppFile("appconf", "conf/" + main_form.custom_config_file.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_content.data)
|
||||
|
||||
# TODO : same for cron job
|
||||
if submit_mode == "download":
|
||||
# Generate the zip file
|
||||
f = BytesIO()
|
||||
with zipfile.ZipFile(f, "w") as zf:
|
||||
print("Exporting zip archive for app: " + request.form["app_id"])
|
||||
for app_file in app_files:
|
||||
print(app_file.id)
|
||||
zf.writestr(app_file.destination_path, app_file.content)
|
||||
f.seek(0)
|
||||
# Send the zip file to the user
|
||||
return send_file(
|
||||
f, as_attachment=True, download_name=request.form["app_id"] + ".zip"
|
||||
)
|
||||
|
||||
return render_template(
|
||||
"index.html",
|
||||
main_form=main_form,
|
||||
generator_info=GENERATOR_DICT,
|
||||
generated_files=app_files,
|
||||
)
|
||||
|
||||
|
||||
# Localisation
|
||||
@app.route("/language/<language>")
|
||||
def set_language(language=None):
|
||||
response = make_response(redirect(request.referrer or "/"))
|
||||
response.set_cookie("lang", language)
|
||||
return response
|
||||
|
||||
|
||||
#### Running the web server
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=True)
|
2
tools/app_generator/babel.cfg
Normal file
2
tools/app_generator/babel.cfg
Normal file
|
@ -0,0 +1,2 @@
|
|||
[python: *.py]
|
||||
[jinja2: templates/**.html]
|
14
tools/app_generator/gunicorn.py
Normal file
14
tools/app_generator/gunicorn.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
import os
|
||||
|
||||
install_dir = os.path.dirname(__file__)
|
||||
command = f"{install_dir}/venv/bin/gunicorn"
|
||||
pythonpath = install_dir
|
||||
workers = 4
|
||||
user = "appgenerator"
|
||||
bind = f"unix:{install_dir}/sock"
|
||||
pid = "/run/gunicorn/appgenerator-pid"
|
||||
errorlog = "/var/log/appgenerator/error.log"
|
||||
accesslog = "/var/log/appgenerator/access.log"
|
||||
access_log_format = '%({X-Real-IP}i)s %({X-Forwarded-For}i)s %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
|
||||
loglevel = "warning"
|
||||
capture_output = True
|
18
tools/app_generator/requirements.txt
Normal file
18
tools/app_generator/requirements.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
blinker==1.6.3
|
||||
cffi==1.16.0
|
||||
click==8.1.7
|
||||
dominate==2.8.0
|
||||
Flask==3.0.0
|
||||
flask_babel~=4.0.0
|
||||
Flask-Cors==4.0.0
|
||||
Flask-Misaka==1.0.0
|
||||
Flask-WTF==1.2.1
|
||||
itsdangerous==2.1.2
|
||||
Jinja2==3.1.4
|
||||
MarkupSafe==2.1.3
|
||||
misaka==2.1.1
|
||||
pycparser==2.21
|
||||
visitor==0.1.3
|
||||
Werkzeug==3.0.1
|
||||
WTForms==3.0.1
|
||||
gunicorn==22.0.0
|
6
tools/app_generator/static/fetch_assets
Normal file
6
tools/app_generator/static/fetch_assets
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Download standalone tailwind to compile what we need
|
||||
wget https://github.com/tailwindlabs/tailwindcss/releases/download/v3.3.3/tailwindcss-linux-x64
|
||||
chmod +x tailwindcss-linux-x64
|
||||
./tailwindcss-linux-x64 --input tailwind-local.css --output tailwind.css --minify
|
||||
|
||||
|
109
tools/app_generator/static/tailwind-local.css
Normal file
109
tools/app_generator/static/tailwind-local.css
Normal file
|
@ -0,0 +1,109 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer utilities {
|
||||
|
||||
body {
|
||||
@apply text-gray-800;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply text-2xl font-bold;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply text-xl font-bold;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply text-lg font-bold;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.btn {
|
||||
@apply text-sm font-medium rounded-md px-4 py-2 transition bg-gray-200 m-1;
|
||||
}
|
||||
.btn-sm {
|
||||
@apply text-xs font-medium rounded-md px-2 py-2 transition;
|
||||
}
|
||||
.btn-success {
|
||||
@apply text-white bg-green-500 hover:bg-green-700;
|
||||
}
|
||||
.btn-primary {
|
||||
@apply text-white bg-blue-500 hover:bg-blue-700;
|
||||
}
|
||||
.btn-link {
|
||||
@apply bg-gray-400 hover:bg-gray-200;
|
||||
}
|
||||
.panel {
|
||||
@apply block rounded-lg border border-gray-400 mb-2;
|
||||
}
|
||||
.panel-heading {
|
||||
@apply text-white bg-blue-500 hover:bg-blue-700 p-2 font-bold;
|
||||
}
|
||||
.panel-body {
|
||||
@apply p-2;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
@apply text-blue-900 border-blue-900 bg-blue-200 rounded-lg p-4;
|
||||
}
|
||||
|
||||
.active, .collapse-button:hover {
|
||||
background-color: #318ddc;
|
||||
}
|
||||
|
||||
.collapse-title:after {
|
||||
content: '\002B';
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.expanded .collapse-title::after {
|
||||
content: "\2212";
|
||||
}
|
||||
|
||||
.collapsed {
|
||||
padding: 0px 15px 0px 15px;
|
||||
}
|
||||
|
||||
.collapsible {
|
||||
max-height: 0px;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.2s ease-out;
|
||||
}
|
||||
|
||||
label {
|
||||
@apply font-bold;
|
||||
}
|
||||
|
||||
input {
|
||||
@apply rounded-lg;
|
||||
}
|
||||
|
||||
.form-group, .checkbox {
|
||||
@apply px-2 py-4;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
@apply block w-full rounded-md border-gray-300;
|
||||
}
|
||||
|
||||
.help-block {
|
||||
@apply text-gray-500 text-sm;
|
||||
}
|
||||
|
||||
.tip {
|
||||
@apply italic p-2;
|
||||
}
|
||||
|
||||
.has-error {
|
||||
@apply bg-red-200;
|
||||
}
|
||||
}
|
17
tools/app_generator/static/tailwind.config.js
Normal file
17
tools/app_generator/static/tailwind.config.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ['../templates/*.html'],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [
|
||||
require('@tailwindcss/forms'),
|
||||
],
|
||||
safelist: [
|
||||
'safelisted',
|
||||
{
|
||||
pattern: /^(text-[a-z]+-600|border-[a-z]+-400)$/,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
BIN
tools/app_generator/static/yunohost-package.png
Normal file
BIN
tools/app_generator/static/yunohost-package.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
3
tools/app_generator/templates/ADMIN.j2
Normal file
3
tools/app_generator/templates/ADMIN.j2
Normal file
|
@ -0,0 +1,3 @@
|
|||
This is a dummy admin doc for this app
|
||||
|
||||
The app install dir is `__INSTALL_DIR__`
|
1
tools/app_generator/templates/DESCRIPTION.j2
Normal file
1
tools/app_generator/templates/DESCRIPTION.j2
Normal file
|
@ -0,0 +1 @@
|
|||
This is a dummy description of this app features
|
7
tools/app_generator/templates/POST_INSTALL.j2
Normal file
7
tools/app_generator/templates/POST_INSTALL.j2
Normal file
|
@ -0,0 +1,7 @@
|
|||
This is a dummy disclaimer to display after the install
|
||||
|
||||
The app url is <https://__DOMAIN____PATH__>
|
||||
|
||||
The app install dir is `__INSTALL_DIR__`
|
||||
|
||||
The app id is `__ID__`
|
1
tools/app_generator/templates/POST_UPGRADE.j2
Normal file
1
tools/app_generator/templates/POST_UPGRADE.j2
Normal file
|
@ -0,0 +1 @@
|
|||
This is a dummy disclaimer to display after upgrades
|
1
tools/app_generator/templates/PRE_INSTALL.j2
Normal file
1
tools/app_generator/templates/PRE_INSTALL.j2
Normal file
|
@ -0,0 +1 @@
|
|||
This is a dummy disclaimer to display prior to the install
|
1
tools/app_generator/templates/PRE_UPGRADE.j2
Normal file
1
tools/app_generator/templates/PRE_UPGRADE.j2
Normal file
|
@ -0,0 +1 @@
|
|||
This is a dummy disclaimer to display prior to any upgrade
|
14
tools/app_generator/templates/_common.sh.j2
Normal file
14
tools/app_generator/templates/_common.sh.j2
Normal file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
#=================================================
|
||||
# COMMON VARIABLES
|
||||
#=================================================
|
||||
|
||||
{% if data.use_nodejs -%}
|
||||
nodejs_version={{ data.nodejs_version }}
|
||||
{% endif -%}
|
||||
|
||||
#=================================================
|
||||
# PERSONAL HELPERS
|
||||
#=================================================
|
||||
|
105
tools/app_generator/templates/backup.j2
Normal file
105
tools/app_generator/templates/backup.j2
Normal file
|
@ -0,0 +1,105 @@
|
|||
#!/bin/bash
|
||||
#### App file generated with YoloGen, the YunoHost app generator, version {{ data['GENERATOR_VERSION'] }}.
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%} # This is the tutorial version of the app.
|
||||
# It contains extra commands to explain what should be done in case you want to adjust some part of the script.
|
||||
# Once you are done, you may remove them.
|
||||
{% endif %}
|
||||
#=================================================
|
||||
# GENERIC START
|
||||
#=================================================
|
||||
# IMPORT GENERIC HELPERS
|
||||
#=================================================
|
||||
|
||||
# Keep this path for calling _common.sh inside the execution's context of backup and restore scripts
|
||||
source ../settings/scripts/_common.sh
|
||||
source /usr/share/yunohost/helpers
|
||||
|
||||
#=================================================
|
||||
# DECLARE DATA AND CONF FILES TO BACKUP
|
||||
#=================================================
|
||||
ynh_print_info --message="Declaring files to be backed up..."
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
### N.B. : the following 'ynh_backup' calls are only a *declaration* of what needs
|
||||
### to be backuped and not an actual copy of any file. The actual backup that
|
||||
### creates and fill the archive with the files happens in the core after this
|
||||
### script is called. Hence ynh_backups calls takes basically 0 seconds to run.
|
||||
{% endif %}
|
||||
|
||||
{% if data.data_dir -%}
|
||||
#=================================================
|
||||
# BACKUP THE DATA DIR
|
||||
#=================================================
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
### Only relevant if there is a "data_dir" resource for this app
|
||||
# The --is_big parameters ensure this folder is not included in the backup by default (taking less space), except if BACKUP_CORE_ONLY=0 is passed before the backup command. You might want to document that for your users.
|
||||
# TODO : there should be an option for this
|
||||
{% endif %}
|
||||
ynh_backup --src_path="$data_dir" # --is_big
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# SYSTEM CONFIGURATION
|
||||
#=================================================
|
||||
|
||||
# Backup the nginx configuration
|
||||
ynh_backup --src_path="/etc/nginx/conf.d/$domain.d/$app.conf"
|
||||
|
||||
{% if data.main_technology == "php" -%}
|
||||
# Backup the PHP-FPM configuration
|
||||
ynh_backup --src_path="/etc/php/$phpversion/fpm/pool.d/$app.conf"
|
||||
{% endif %}
|
||||
|
||||
{% if data.use_fail2ban -%}
|
||||
# Backup the Fail2Ban config
|
||||
ynh_backup --src_path="/etc/fail2ban/jail.d/$app.conf"
|
||||
ynh_backup --src_path="/etc/fail2ban/filter.d/$app.conf"
|
||||
{% endif %}
|
||||
|
||||
{% if data.use_logrotate -%}
|
||||
# Backup the logrotate configuration
|
||||
ynh_backup --src_path="/etc/logrotate.d/$app"
|
||||
{% endif %}
|
||||
|
||||
{% if data.main_technology not in ["php", "none"] -%}
|
||||
# Backup the systemd service unit
|
||||
ynh_backup --src_path="/etc/systemd/system/$app.service"
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# BACKUP VARIOUS FILES
|
||||
#=================================================
|
||||
|
||||
{% if data.use_cron -%}
|
||||
# Backup the cron configuration
|
||||
ynh_backup --src_path="/etc/cron.d/$app"
|
||||
{% endif %}
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
### For apps with huge logs, you might want to pass --is_big,
|
||||
### and in restore script, mkdir and pass --not_mandatory to ynh_restore_file.
|
||||
{% endif %}
|
||||
ynh_backup --src_path="/var/log/$app/" # TODO : add an option to specify log file
|
||||
|
||||
{% if data.database != 'false' -%}
|
||||
#=================================================
|
||||
# BACKUP THE DATABASE
|
||||
#=================================================
|
||||
ynh_print_info --message="Backing up the {{ data.database }} database..."
|
||||
|
||||
### (However, things like MySQL dumps *do* take some time to run, though the
|
||||
### copy of the generated dump to the archive still happens later)
|
||||
|
||||
{% if data.use_db == 'mysql' -%}
|
||||
ynh_mysql_dump_db --database="$db_name" > db.sql
|
||||
{% elif data.use_db == 'postgresql' -%}
|
||||
ynh_psql_dump_db --database="$db_name" > db.sql
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# END OF SCRIPT
|
||||
#=================================================
|
||||
|
||||
ynh_print_info --message="Backup script completed for $app. (YunoHost will then actually copy those files to the archive)."
|
17
tools/app_generator/templates/base.html
Normal file
17
tools/app_generator/templates/base.html
Normal file
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ gettext("YunoHost app generator") }}</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='fork-awesome.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='tailwind.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<main class="my-2 mx-auto max-w-screen-md">
|
||||
{% block main -%}
|
||||
{%- endblock main %}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
54
tools/app_generator/templates/change_url.j2
Normal file
54
tools/app_generator/templates/change_url.j2
Normal file
|
@ -0,0 +1,54 @@
|
|||
#!/bin/bash
|
||||
### App file generated with YoloGen, the Yunohost app generator, version {{ data['GENERATOR_VERSION'] }}.
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
# This is the tutorial version of the app.
|
||||
# It contains extra commands to explain what should be done in case you want to adjust some part of the script.
|
||||
# Once you are done, you may remove them.
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# GENERIC STARTING
|
||||
#=================================================
|
||||
# IMPORT GENERIC HELPERS
|
||||
#=================================================
|
||||
|
||||
source _common.sh
|
||||
source /usr/share/yunohost/helpers
|
||||
|
||||
{% if data.main_technology not in ["php", "none"] -%}
|
||||
#=================================================
|
||||
# STOP SYSTEMD SERVICE
|
||||
#=================================================
|
||||
ynh_script_progression --message="Stopping a systemd service..."
|
||||
|
||||
ynh_systemd_action --service_name=$app --action="stop" --log_path="/var/log/$app/$app.log"
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# MODIFY URL IN NGINX CONF
|
||||
#=================================================
|
||||
ynh_script_progression --message="Updating NGINX web server configuration..."
|
||||
|
||||
ynh_change_url_nginx_config
|
||||
|
||||
#=================================================
|
||||
# SPECIFIC MODIFICATIONS
|
||||
#=================================================
|
||||
# ...
|
||||
#=================================================
|
||||
|
||||
{% if data.main_technology not in ["php", "none"] -%}
|
||||
#=================================================
|
||||
# START SYSTEMD SERVICE
|
||||
#=================================================
|
||||
ynh_script_progression --message="Starting a systemd service..."
|
||||
|
||||
ynh_systemd_action --service_name=$app --action="start" --log_path="/var/log/$app/$app.log"
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# END OF SCRIPT
|
||||
#=================================================
|
||||
|
||||
ynh_script_progression --message="Change of URL completed for $app" --last
|
361
tools/app_generator/templates/index.html
Normal file
361
tools/app_generator/templates/index.html
Normal file
|
@ -0,0 +1,361 @@
|
|||
{% import "wtf.html" as wtf %}
|
||||
|
||||
{% macro form_field(field,
|
||||
form_type="basic",
|
||||
horizontal_columns=('lg', 2, 10),
|
||||
button_map={}) %}
|
||||
{% if field.widget.input_type == 'checkbox' %}
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
{{field()|safe}} {{field.label.text|safe}}
|
||||
</label>
|
||||
{%- if field.description -%}
|
||||
<p class="help-block">{{field.description|safe}}</p>
|
||||
{%- endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
{{ wtf.form_field(field, form_type, horizontal_columns, button_map) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block main %}
|
||||
<div class="mx-auto w-full text-center p-8">
|
||||
<img alt="YunoHost application logo" src="{{ url_for('static', filename='yunohost-package.png') }}" class="w-32 mx-auto">
|
||||
<h1 class="text-2xl font-bold">
|
||||
{{ _("Yunohost application generation form") }}
|
||||
</h1>
|
||||
<p>Version: {{ generator_info['GENERATOR_VERSION'] }}</p>
|
||||
<script>
|
||||
function changeLanguage(lang) {
|
||||
var url = "{{ url_for('set_language', language=lang) }}" + lang;
|
||||
window.location.href = url;
|
||||
}
|
||||
</script>
|
||||
<div>
|
||||
{% for lang in AVAILABLE_LANGUAGES.items() %}
|
||||
<button class="btn btn-sm bg-gray-200" type="button" onclick="changeLanguage('{{ lang[0] }}')">{{ lang[1] }}</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="POST" role="form">
|
||||
|
||||
{{ main_form.hidden_tag() }}
|
||||
<div class="text-red-800">
|
||||
{{ wtf.form_errors(main_form, hiddens="only") }}
|
||||
</div>
|
||||
|
||||
{{ form_field(main_form.generator_mode) }}
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-heading collapse-button">
|
||||
<h2 class="panel-title collapse-title">{{ gettext("1/9 - General information") }}</h2>
|
||||
</div>
|
||||
<div class="panel-body collapsible collapsed">
|
||||
<div>
|
||||
{{ form_field(main_form.app_name) }}
|
||||
{{ form_field(main_form.app_id) }}
|
||||
{{ form_field(main_form.description_en) }}
|
||||
{{ form_field(main_form.description_fr) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-heading collapse-button">
|
||||
<h2 class="panel-title collapse-title">{{ gettext("2/9 - Upstream information") }}</h2>
|
||||
</div>
|
||||
<div class="panel-body collapsible collapsed">
|
||||
<p class="tip">{{ gettext("The word 'upstream' refers to the original project that develops and maintains the app") }}</p>
|
||||
<div>
|
||||
{{ form_field(main_form.license) }}
|
||||
{{ form_field(main_form.website) }}
|
||||
{{ form_field(main_form.demo) }}
|
||||
{{ form_field(main_form.admindoc) }}
|
||||
{{ form_field(main_form.userdoc) }}
|
||||
{{ form_field(main_form.code) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-heading collapse-button">
|
||||
<h2 class="panel-title collapse-title">{{ gettext("3/9 - Integration in YunoHost") }}</h2>
|
||||
</div>
|
||||
<div class="panel-body collapsible collapsed">
|
||||
<div>
|
||||
{{ form_field(main_form.version) }}
|
||||
{{ form_field(main_form.maintainers) }}
|
||||
{{ form_field(main_form.multi_instance) }}
|
||||
{{ form_field(main_form.architectures) }}
|
||||
{{ form_field(main_form.ldap) }}
|
||||
{{ form_field(main_form.sso) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-heading collapse-button">
|
||||
<h2 class="panel-title collapse-title">{{ gettext("4/9 - Questions to ask during installation") }}</h2>
|
||||
</div>
|
||||
<div class="panel-body collapsible collapsed">
|
||||
<p class="tip">
|
||||
{{ gettext("This part is meant to indicate the questions that will be asked.") }}
|
||||
<br/>
|
||||
{{ gettext("NB: only standard questions are asked here, it might be required to complete it by hand using other questions as a guide.") }}
|
||||
</p>
|
||||
|
||||
<div>
|
||||
{{ form_field(main_form.domain_and_path) }}
|
||||
{{ form_field(main_form.init_main_permission) }}
|
||||
{{ form_field(main_form.init_admin_permission) }}
|
||||
{{ form_field(main_form.language) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-heading collapse-button">
|
||||
<h2 class="panel-title collapse-title">{{ gettext("5/9 - Resources to initialize") }}</h2>
|
||||
</div>
|
||||
<div class="panel-body collapsible collapsed">
|
||||
<p class="tip">
|
||||
{{ gettext("Technical elements configured before launching the 'real' app install script. Usually : creating a system user, downloading app sources, initialiser le dossier d'install et de données, install apt dependencies, create a database, ...") }}
|
||||
</p>
|
||||
|
||||
<h3>Sources du logiciel</h3>
|
||||
<div class="pl-2">
|
||||
{{ form_field(main_form.source_url) }}
|
||||
{{ form_field(main_form.sha256sum) }}
|
||||
{{ form_field(main_form.auto_update) }}
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
{{ form_field(main_form.system_user) }}
|
||||
{{ form_field(main_form.install_dir) }}
|
||||
{{ form_field(main_form.data_dir) }}
|
||||
{{ form_field(main_form.apt_dependencies) }}
|
||||
{{ form_field(main_form.database) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-heading collapse-button">
|
||||
<h2 class="panel-title collapse-title">{{ gettext("6/9 - Specific technology") }}</h2>
|
||||
</div>
|
||||
<div class="panel-body collapsible collapsed">
|
||||
{{ form_field(main_form.main_technology) }}
|
||||
<div id="php_options">
|
||||
<div class="alert alert-info" role="alert"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> {{ gettext("You probably want to make sure to have 'phpX.Y-fpm' and others 'phpX.Y-foobar' libraries listed the apt dependencies earlier (with X.Y being the php version you want to use)") }}</div>
|
||||
<div class="alert alert-info" role="alert"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> {{ gettext("The generated application draft will include an nginx configuration snippet that interfaces with PHP-FPM") }}</div>
|
||||
{{ form_field(main_form.use_composer) }}
|
||||
</div>
|
||||
<div id="nodejs_options">
|
||||
{{ form_field(main_form.nodejs_version) }}
|
||||
{{ form_field(main_form.use_yarn) }}
|
||||
</div>
|
||||
<div id="python_options">
|
||||
<div class="alert alert-info" role="alert"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> {{ gettext("You probably want to make sure to have 'python3' and 'python3-venv' listed in the apt dependencies earlier. Other dependencies should be installed inside a venv (cf the proposed install snippet)") }}</div>
|
||||
</div>
|
||||
{{ form_field(main_form.install_snippet) }}
|
||||
<div id="systemd_options">
|
||||
<div class="alert alert-info" role="alert"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> {{ gettext("The generated application draft will include an nginx configuration snippet that reverse-proxies to a systemd service using an internal port") }}</div>
|
||||
{{ form_field(main_form.systemd_execstart) }}
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
|
||||
let main_technology = document.getElementById("main_technology");
|
||||
let install_snippet = document.getElementById("install_snippet");
|
||||
let systemd_execstart = document.getElementById("systemd_execstart");
|
||||
|
||||
install_snippet.classList.add("font-mono");
|
||||
systemd_execstart.classList.add("font-mono");
|
||||
|
||||
function update_main_technology()
|
||||
{
|
||||
document.getElementById("php_options").classList.add("hide");
|
||||
document.getElementById("nodejs_options").classList.add("hide");
|
||||
document.getElementById("python_options").classList.add("hide");
|
||||
document.getElementById("systemd_options").classList.add("hide");
|
||||
if (main_technology.value == "php") document.getElementById("php_options").classList.remove("hide");
|
||||
if (main_technology.value == "nodejs") document.getElementById("nodejs_options").classList.remove("hide");
|
||||
if (main_technology.value == "python") document.getElementById("python_options").classList.remove("hide");
|
||||
if ((main_technology.value != "php") && (main_technology.value != "none")) document.getElementById("systemd_options").classList.remove("hide");
|
||||
|
||||
if (main_technology.value == "none")
|
||||
{
|
||||
install_snippet.value = "some_command --build";
|
||||
}
|
||||
else if (main_technology.value == "php")
|
||||
{
|
||||
if (document.getElementById("use_composer").checked)
|
||||
{
|
||||
install_snippet.value = "ynh_install_composer";
|
||||
}
|
||||
else
|
||||
{
|
||||
install_snippet.value = "some_command --build";
|
||||
}
|
||||
}
|
||||
else if (main_technology.value == "nodejs")
|
||||
{
|
||||
if (document.getElementById("use_yarn").checked)
|
||||
{
|
||||
install_snippet.value = "ynh_exec_as $app $ynh_node_load_PATH yarn install --production --pure-lockfile\nynh_exec_as $app $ynh_node_load_PATH yarn build";
|
||||
}
|
||||
else
|
||||
{
|
||||
install_snippet.value = "ynh_exec_as $app $ynh_node_load_PATH $ynh_npm install --production --ignore-scripts\nynh_exec_as $app $ynh_node_load_PATH $ynh_npm run build"
|
||||
}
|
||||
}
|
||||
else if (main_technology.value == "python")
|
||||
{
|
||||
install_snippet.value = "python3 -m venv venv\nvenv/bin/pip3 install -r requirements.txt";
|
||||
}
|
||||
else if (main_technology.value == "ruby")
|
||||
{
|
||||
install_snippet.value = "ynh_gem update --system --no-document\nynh_gem install bundler foreman --no-document\nbundle config set --local deployment 'true'\nbundle config set --local without 'development test'\nbundle install";
|
||||
}
|
||||
}
|
||||
main_technology.addEventListener("change", update_main_technology);
|
||||
document.getElementById("use_composer").addEventListener("change", update_main_technology);
|
||||
document.getElementById("use_yarn").addEventListener("change", update_main_technology);
|
||||
update_main_technology();
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-heading collapse-button">
|
||||
<h2 class="panel-title collapse-title">{{ gettext("7/9 - App configuration") }}</h2>
|
||||
</div>
|
||||
<div class="panel-body collapsible collapsed">
|
||||
{{ form_field(main_form.use_custom_config_file) }}
|
||||
<!-- TODO : this show/hide the other fields -->
|
||||
<div id="custom_config_file_options">
|
||||
{{ form_field(main_form.custom_config_file) }}
|
||||
{{ form_field(main_form.custom_config_file_content) }}
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
let use_custom_config_file = document.getElementById("use_custom_config_file");
|
||||
function update_custom_config_file()
|
||||
{
|
||||
document.getElementById("custom_config_file_options").classList.add("hide");
|
||||
if (use_custom_config_file.checked) document.getElementById("custom_config_file_options").classList.remove("hide");
|
||||
}
|
||||
use_custom_config_file.addEventListener("change", update_custom_config_file);
|
||||
update_custom_config_file();
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-heading collapse-button">
|
||||
<h2 class="panel-title collapse-title">{{ gettext("8/9 - General and advanced documentation") }}</h2>
|
||||
</div>
|
||||
<div class="panel-body collapsible collapsed">
|
||||
{{ form_field(main_form.description) }}
|
||||
{{ form_field(main_form.pre_install) }}
|
||||
{{ form_field(main_form.post_install) }}
|
||||
{{ form_field(main_form.pre_upgrade) }}
|
||||
{{ form_field(main_form.post_upgrade) }}
|
||||
{{ form_field(main_form.admin) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-heading collapse-button">
|
||||
<h2 class="panel-title collapse-title">{{ gettext("9/9 - Advanced options") }}</h2>
|
||||
</div>
|
||||
<div class="panel-body collapsible collapsed">
|
||||
{{ form_field(main_form.enable_change_url) }}
|
||||
{{ form_field(main_form.use_logrotate) }}
|
||||
{{ form_field(main_form.use_fail2ban) }}
|
||||
{{ form_field(main_form.fail2ban_regex) }}
|
||||
{{ form_field(main_form.use_cron) }}
|
||||
{{ form_field(main_form.cron_config_file) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Submit button -->
|
||||
<p class="text-center">
|
||||
{{ main_form.submit_preview(class="btn btn-primary") }}
|
||||
{{ main_form.submit_download(class="btn btn-primary") }}
|
||||
<br/>
|
||||
{{ main_form.submit_demo(class="btn") }}
|
||||
</p>
|
||||
|
||||
<!-- Submit button for demo values-->
|
||||
<script>
|
||||
function fillFormWithDefaultValues() {
|
||||
console.log("Filling the form with minimal dummy values")
|
||||
document.getElementById('app_id').value = "awesome_app_demo"
|
||||
document.getElementById('app_name').value = "Awesome demo app"
|
||||
document.getElementById('description_en').value = "Dummy app to demonstrate Yunohost app generator"
|
||||
document.getElementById('description_fr').value = "Application factice de démonstration du générateur d'application Yunohost"
|
||||
document.getElementById('version').value = "1.0~ynh1"
|
||||
document.getElementById('architectures').value = "all"
|
||||
// document.getElementById('ldap').value = "not_relevant"
|
||||
// document.getElementById('sso').value = "not_relevant"
|
||||
document.getElementById('license').value = "AGPL-3.0"
|
||||
document.getElementById('code').value = "https://github.com/YunoHost/example_ynh/"
|
||||
document.getElementById('source_url').value = "https://github.com/YunoHost/example_ynh/archive/1235ae57a3a285a4024d028d860f56980fa5ed19.tar.gz"
|
||||
document.getElementById('sha256sum').value = "471ff03ae251812d3d042fb7e9206c812de5bf07bd4ac4c95763278702eff30a" }
|
||||
</script>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
<hr class="my-2" />
|
||||
|
||||
{% if generated_files %}
|
||||
<div>
|
||||
<h2 class="text-center">Code généré</h2>
|
||||
{% for file in generated_files %}
|
||||
<div class="panel">
|
||||
<div class="panel-heading collapse-button">
|
||||
<h3 class="panel-title collapse-title">{{ file.destination_path }}</h3>
|
||||
</div>
|
||||
<div class="panel-body collapsible collapsed p-0">
|
||||
<pre class="m-0">{{ file.content }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<script>
|
||||
var coll = document.getElementsByClassName("collapse-button");
|
||||
var i;
|
||||
|
||||
for (i = 0; i < coll.length; i++) {
|
||||
coll[i].addEventListener("click", function() {
|
||||
|
||||
if (this.classList.contains('expanded')) {
|
||||
this.classList.remove('expanded');
|
||||
this.nextElementSibling.classList.add('collapsed');
|
||||
} else {
|
||||
this.classList.add('expanded');
|
||||
this.nextElementSibling.classList.remove('collapsed');
|
||||
}
|
||||
|
||||
this.classList.toggle("active");
|
||||
var content = this.nextElementSibling;
|
||||
if (content.style.maxHeight){
|
||||
content.style.maxHeight = null;
|
||||
} else {
|
||||
content.style.maxHeight = content.scrollHeight + "px";
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
215
tools/app_generator/templates/install.j2
Normal file
215
tools/app_generator/templates/install.j2
Normal file
|
@ -0,0 +1,215 @@
|
|||
#!/bin/bash
|
||||
### App file generated with YoloGen, the Yunohost app generator, version {{ data['GENERATOR_VERSION'] }}.
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
# This is the tutorial version of the app.
|
||||
# It contains extra commands to explain what should be done in case you want to adjust some part of the script.
|
||||
# Once you are done, you may remove them.
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# GENERIC START
|
||||
#=================================================
|
||||
# IMPORT GENERIC HELPERS
|
||||
#=================================================
|
||||
source _common.sh
|
||||
source /usr/share/yunohost/helpers
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
# Install parameters are automatically saved as settings
|
||||
#
|
||||
# Settings are automatically loaded as bash variables
|
||||
# in every app script context, therefore typically these will exist:
|
||||
# - $domain
|
||||
# - $path
|
||||
# - $language
|
||||
# ... etc
|
||||
#
|
||||
# Resources defined in the manifest are provisioned prior to this script
|
||||
# and corresponding settings are also available, such as:
|
||||
# - $install_dir
|
||||
# - $port
|
||||
# - $db_name
|
||||
# ...
|
||||
|
||||
#
|
||||
# $app is the app id (i.e. 'example' for first install,
|
||||
# or 'example__2', '__3', ... for multi-instance installs)
|
||||
#
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# INSTALL DEPENDENCIES
|
||||
#=================================================
|
||||
|
||||
{% if data.main_technology == "nodejs" -%}
|
||||
ynh_script_progression --message="Installing NodeJS..." --weight=10
|
||||
|
||||
# Install Nodejs
|
||||
ynh_exec_warn_less ynh_install_nodejs --nodejs_version=$nodejs_version
|
||||
ynh_use_nodejs
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# APP "BUILD" (DEPLOYING SOURCES, VENV, COMPILING ETC)
|
||||
#=================================================
|
||||
# DOWNLOAD, CHECK AND UNPACK SOURCE
|
||||
#=================================================
|
||||
ynh_script_progression --message="Setting up source files..."
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
### `ynh_setup_source` is used to install an app from a zip or tar.gz file,
|
||||
### downloaded from an upstream source, as defined in the manifest.toml
|
||||
{% endif %}
|
||||
|
||||
ynh_setup_source --dest_dir="$install_dir"
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
# $install_dir will automatically be initialized with some decent
|
||||
# permission by default ... however, you may need to recursively reapply
|
||||
# ownership to all files such as after the ynh_setup_source step
|
||||
{% endif %}
|
||||
chown -R $app:www-data "$install_dir"
|
||||
|
||||
#=================================================
|
||||
# SYSTEM CONFIGURATION
|
||||
#=================================================
|
||||
ynh_script_progression --message="Adding system configurations related to $app..."
|
||||
|
||||
{% if data.main_technology == "php" -%}
|
||||
# Create a dedicated PHP-FPM config
|
||||
# conf/extra_php-fpm.conf will be appended to the auto-generated config, which will go in /etc/php/X.Y/fpm/pool.d/
|
||||
ynh_add_fpm_config
|
||||
{% endif %}
|
||||
|
||||
# Create a dedicated NGINX config using the conf/nginx.conf template
|
||||
ynh_add_nginx_config
|
||||
|
||||
{% if data.main_technology not in ["php", "none"] -%}
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
### `ynh_systemd_config` is used to configure a systemd script for an app, using the conf/systemd.service template
|
||||
{% endif %}
|
||||
# Create a dedicated systemd config
|
||||
ynh_add_systemd_config
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
### `yunohost service add` integrates a service in YunoHost. It then gets
|
||||
### displayed in the admin interface and through the others `yunohost service` commands.
|
||||
{% endif %}
|
||||
|
||||
yunohost service add $app --log="/var/log/$app/$app.log"
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
### Additional options starting with 3.8:
|
||||
###
|
||||
### --needs_exposed_ports "$port" a list of ports that needs to be publicly exposed
|
||||
### which will then be checked by YunoHost's diagnosis system
|
||||
### (N.B. DO NOT USE THIS is the port is only internal!!!)
|
||||
###
|
||||
### --test_status "some command" a custom command to check the status of the service
|
||||
### (only relevant if 'systemctl status' doesn't do a good job)
|
||||
###
|
||||
### --test_conf "some command" some command similar to "nginx -t" that validates the conf of the service
|
||||
###
|
||||
### Re-calling 'yunohost service add' during the upgrade script is the right way
|
||||
### to proceed if you later realize that you need to enable some flags that
|
||||
### weren't enabled on old installs (be careful it'll override the existing
|
||||
### service though so you should re-provide all relevant flags when doing so)
|
||||
{% endif -%}
|
||||
{% endif %}
|
||||
|
||||
{% if data.use_logrotate %}
|
||||
# Use logrotate to manage application logfile(s)
|
||||
ynh_use_logrotate
|
||||
{% endif %}
|
||||
|
||||
{% if data.use_fail2ban -%}
|
||||
# Create a dedicated Fail2Ban config
|
||||
ynh_add_fail2ban_config --logpath="/var/log/nginx/${domain}-error.log" --failregex="{{ data.fail2ban_regex }}"
|
||||
{% endif %}
|
||||
|
||||
{% if data.use_cron -%}
|
||||
# Add cron job
|
||||
cron_path="/etc/cron.d/$app"
|
||||
ynh_add_config --template="../conf/task.cron" --destination="$cron_path"
|
||||
chown root: "$cron_path"
|
||||
chmod 644 "$cron_path"
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# APP INITIAL CONFIGURATION
|
||||
#=================================================
|
||||
# ADD A CONFIGURATION
|
||||
#=================================================
|
||||
ynh_script_progression --message="Adding app's configuration file..."
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
### You can add specific configuration files.
|
||||
###
|
||||
### Typically, put your template conf file in ../conf/your_config_file
|
||||
### The template may contain strings such as __FOO__ or __FOO_BAR__,
|
||||
### which will automatically be replaced by the values of $foo and $foo_bar
|
||||
###
|
||||
### ynh_add_config will also keep track of the config file's checksum,
|
||||
### which later during upgrade may allow to automatically backup the config file
|
||||
### if it's found that the file was manually modified
|
||||
###
|
||||
### Check the documentation of `ynh_add_config` for more info.
|
||||
{% endif %}
|
||||
|
||||
ynh_add_config --template="{{ data.custom_config_file }}" --destination="$install_dir/{{ data.custom_config_file }}"
|
||||
|
||||
# FIXME: this should be handled by the core in the future
|
||||
# You may need to use chmod 600 instead of 400,
|
||||
# for example if the app is expected to be able to modify its own config
|
||||
chmod 400 "$install_dir/{{ data.custom_config_file }}"
|
||||
chown $app:$app "$install_dir/{{ data.custom_config_file }}"
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
### For more complex cases where you want to replace stuff using regexes,
|
||||
### you shoud rely on ynh_replace_string (which is basically a wrapper for sed)
|
||||
### When doing so, you also need to manually call ynh_store_file_checksum
|
||||
###
|
||||
### ynh_replace_string --match_string="match_string" --replace_string="replace_string" --target_file="$install_dir/some_config_file"
|
||||
### ynh_store_file_checksum --file="$install_dir/some_config_file"
|
||||
{% endif %}
|
||||
|
||||
{% if data.install_snippet -%}
|
||||
#=================================================
|
||||
# INSTALL APP
|
||||
#=================================================
|
||||
ynh_script_progression --message="Installing app..." --weight=5
|
||||
|
||||
pushd $install_dir
|
||||
{{ data.install_snippet }}
|
||||
popd
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# FINALIZE APP INSTALL WITH CURL
|
||||
#=================================================
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
### Use these lines only if the app installation needs to be finalized through
|
||||
### web forms. We generally don't want to ask the final user,
|
||||
### so we're going to use curl to automatically fill the fields and submit the
|
||||
### forms.
|
||||
{% endif %}
|
||||
|
||||
# REMOVEME? ynh_script_progression --message="Finalizing installation..."
|
||||
# REMOVEME? ynh_local_curl "/INSTALL_PATH" "key1=value1" "key2=value2" "key3=value3"
|
||||
|
||||
{% if data.main_technology not in ["php", "none"] -%}
|
||||
#=================================================
|
||||
# START SYSTEMD SERVICE
|
||||
#=================================================
|
||||
ynh_script_progression --message="Starting app's systemd service..."
|
||||
|
||||
# Start a systemd service
|
||||
ynh_systemd_action --service_name=$app --action="start" --log_path="/var/log/$app/$app.log"
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# END OF SCRIPT
|
||||
#=================================================
|
||||
ynh_script_progression --message="Installation of $app completed" --last
|
178
tools/app_generator/templates/manifest.j2
Normal file
178
tools/app_generator/templates/manifest.j2
Normal file
|
@ -0,0 +1,178 @@
|
|||
#:schema https://raw.githubusercontent.com/YunoHost/apps/master/schemas/manifest.v2.schema.json
|
||||
|
||||
packaging_format = 2
|
||||
|
||||
id = "{{ data.app_id }}"
|
||||
name = "{{ data.app_name }}"
|
||||
|
||||
description.en = "{{ data.description_en }}"
|
||||
description.fr = "{{ data.description_fr }}"
|
||||
|
||||
version = "{{ data.version }}"
|
||||
|
||||
{% if data.maintainers -%}
|
||||
maintainers = ["{{ data.maintainers }}"]
|
||||
{%- endif %}
|
||||
|
||||
[upstream]
|
||||
license = "{{ data.license }}"
|
||||
{% if data.website -%}website = "{{ data.website }}"{%- endif %}
|
||||
{% if data.demo -%}demo = "{{ data.demo }}"{%- endif %}
|
||||
{% if data.admindoc -%}admindoc = "{{ data.admindoc }}"{%- endif %}
|
||||
{% if data.userdoc -%}userdoc = "{{ data.userdoc }}"{%- endif %}
|
||||
{% if data.code -%}code = "{{ data.code }}"{%- endif %}
|
||||
|
||||
[integration]
|
||||
yunohost = '>= {{ data.yunohost_required_version or '11.2'}}'
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# List of supported archs using the dpkg --print-architecture nomenclature (amd64/i386/armhf/arm64), for example: ["amd64", "i386']
|
||||
{% endif -%}
|
||||
architectures = "{{ data.architectures }}" # TODO : handle the "all" option (no ["all"])
|
||||
multi_instance = {{ "true" if data.multi_instance else "false" }}
|
||||
ldap = "{{ data.ldap }}" # TODO : fixme, use actual booleans + handle the "not_relevant" value
|
||||
sso = "{{ data.sso }}"
|
||||
# FIXME: replace with an **estimate** minimum disk and RAM requirements. e.g. 20M, 400M, 1G... You may have have a look at CI results
|
||||
disk = "50M"
|
||||
ram.build = "50M"
|
||||
ram.runtime = "50M"
|
||||
|
||||
[install]
|
||||
|
||||
{% if data.domain_and_path != "false" -%}
|
||||
[install.domain]
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# this is a generic question - ask strings are automatically handled by YunoHost's core
|
||||
{% endif -%}
|
||||
type = "domain"
|
||||
|
||||
{% if data.domain_and_path != "full_domain" -%}
|
||||
[install.path]
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# this is a generic question - ask strings are automatically handled by YunoHost's core
|
||||
{% endif -%}
|
||||
type = "path"
|
||||
default = "/{{ data.app_id }}"
|
||||
{% endif -%}
|
||||
{% endif %}
|
||||
|
||||
{% if data.init_main_permission -%}
|
||||
[install.init_main_permission]
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# this is a generic question - ask strings are automatically handled by YunoHost's core
|
||||
# This won't be saved as setting and will instead be used to initialize the SSOwat permission
|
||||
{% endif -%}
|
||||
type = "group"
|
||||
default = "visitors"
|
||||
{% endif %}
|
||||
|
||||
{% if data.language != "_" -%}
|
||||
[install.language]
|
||||
ask.en = "Choose the application language"
|
||||
ask.fr = "Choisissez la langue de l'application"
|
||||
type = "select"
|
||||
choices = {{ data.language |safe }}
|
||||
{% endif %}
|
||||
|
||||
{% if data.init_admin_permission -%}
|
||||
[install.init_admin_permission]
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# this is a generic question - ask strings are automatically handled by YunoHost's core
|
||||
# This won't be saved as setting and will instead be used to initialize the SSOwat permission
|
||||
{% endif -%}
|
||||
type = "group"
|
||||
default = "admins"
|
||||
{% endif %}
|
||||
|
||||
|
||||
[resources]
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# See the packaging documentation for the full set
|
||||
# of explanation regarding the behavior and properties for each of those
|
||||
# https://yunohost.org/packaging_apps_resources
|
||||
{% endif %}
|
||||
|
||||
[resources.sources]
|
||||
|
||||
[resources.sources.main]
|
||||
# This will pre-fetch the asset which can then be deployed during the install/upgrade scripts with :
|
||||
# ynh_setup_source --dest_dir="$install_dir"
|
||||
# You can also define other assets than "main" and add --source_id="foobar" in the previous command
|
||||
url = "{{data.source_url}}"
|
||||
sha256 = "{{data.sha256sum}}"
|
||||
|
||||
# These infos are used by https://github.com/YunoHost/apps/blob/master/tools/autoupdate_app_sources/autoupdate_app_sources.py
|
||||
# to auto-update the previous asset urls and sha256sum + manifest version
|
||||
# assuming the upstream's code repo is on github and relies on tags or releases
|
||||
# See the 'sources' resource documentation for more details
|
||||
|
||||
{% if data.auto_update != "none" -%}
|
||||
autoupdate.strategy = "{{ data.auto_update }}"
|
||||
{% else -%}
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# You might want to add an "autoupdate strategy" setting to that your app receive automated pull request with each new update, which also trigger automated testing.
|
||||
# autoupdate.strategy = ""
|
||||
{%- endif -%}
|
||||
{% endif %}
|
||||
|
||||
{% if data.system_user -%}
|
||||
[resources.system_user]
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# This will provision/deprovision a unix system user
|
||||
{%- endif -%}
|
||||
{%- endif %}
|
||||
|
||||
{% if data.install_dir -%}
|
||||
[resources.install_dir]
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# This will create/remove the install dir as /var/www/$app
|
||||
# and store the corresponding setting $install_dir
|
||||
{%- endif -%}
|
||||
{%- endif %}
|
||||
|
||||
{% if data.data_dir -%}
|
||||
[resources.data_dir]
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# This will create/remove the data dir as /home/yunohost.app/$app
|
||||
# and store the corresponding setting $data_dir
|
||||
{%- endif -%}
|
||||
{%- endif %}
|
||||
|
||||
[resources.permissions]
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# This will configure SSOwat permission for $domain/$path/
|
||||
# The initial allowed group of user is configured via the init_main_permission question (public=visitors, private=all_users)
|
||||
{% endif -%}
|
||||
main.url = "/"
|
||||
|
||||
{% if data.main_technology not in ['none', 'php'] -%}
|
||||
[resources.ports]
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# This will pick a random port for reverse-proxying and store it as the $port setting
|
||||
{% endif -%}
|
||||
{%- endif %}
|
||||
|
||||
{%- if data.apt_dependencies or data.use_yarn -%}
|
||||
[resources.apt]
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# This will automatically install/uninstall the following apt packages
|
||||
# and implicitly define the $phpversion setting as 8.0 (if phpX.Y-foobar dependencies are listed)
|
||||
{% endif -%}
|
||||
packages = "{{ data.apt_dependencies }} {% if data.database == 'mysql' -%} mariadb-server {% elif data.database == 'postgresql' %} postgresql {% endif -%} {% if data.main_technology == 'python' -%} python3 python3-venv {% endif -%}"
|
||||
{%- endif %}
|
||||
|
||||
{%- if data.use_nodejs_needs_yarn -%}
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# This will configure an extra repository to install yarn dependency
|
||||
{% endif -%}
|
||||
extras.yarn.repo = "deb https://dl.yarnpkg.com/debian/ stable main"
|
||||
extras.yarn.key = "https://dl.yarnpkg.com/debian/pubkey.gpg"
|
||||
extras.yarn.packages = "yarn"
|
||||
{%- endif %}
|
||||
|
||||
{%- if data.database != 'false' -%}
|
||||
[resources.database]
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# This will automatically provision/deprovison a database and store the corresponding credentials in settings $db_user, $db_name, $db_pwd
|
||||
{% endif -%}
|
||||
type = "{{ data.database }}"
|
||||
{%- endif -%}
|
35
tools/app_generator/templates/nginx.j2
Normal file
35
tools/app_generator/templates/nginx.j2
Normal file
|
@ -0,0 +1,35 @@
|
|||
#sub_path_only rewrite ^__PATH__$ __PATH__/ permanent;
|
||||
location __PATH__/ {
|
||||
|
||||
{% if data.main_technology in ["none", "php"] %}
|
||||
# Path to source
|
||||
alias __INSTALL_DIR__/;
|
||||
{% endif %}
|
||||
|
||||
client_max_body_size 10M;
|
||||
|
||||
{% if data.main_technology == "php" %}
|
||||
try_files $uri $uri/ index.php;
|
||||
location ~ [^/]\.php(/|$) {
|
||||
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
|
||||
fastcgi_pass unix:/var/run/php/php__PHPVERSION__-fpm-__NAME__.sock;
|
||||
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
fastcgi_param REMOTE_USER $remote_user;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
fastcgi_param SCRIPT_FILENAME $request_filename;
|
||||
}
|
||||
{% elif data.main_technology not in ["php", "none"] %}
|
||||
proxy_pass http://127.0.0.1:__PORT__;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
|
||||
# preserve client IP
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
{% endif %}
|
||||
|
||||
# Include SSOWAT user panel's shortcut tile.
|
||||
include conf.d/yunohost_panel.conf.inc;
|
||||
}
|
79
tools/app_generator/templates/remove.j2
Normal file
79
tools/app_generator/templates/remove.j2
Normal file
|
@ -0,0 +1,79 @@
|
|||
#!/bin/bash
|
||||
### App file generated with YoloGen, the Yunohost app generator, version {{ data['GENERATOR_VERSION'] }}.
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%} # This is the tutorial version of the app.
|
||||
# It contains extra commands to explain what should be done in case you want to adjust some part of the script.
|
||||
# Once you are done, you may remove them.
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# GENERIC START
|
||||
#=================================================
|
||||
# IMPORT GENERIC HELPERS
|
||||
#=================================================
|
||||
source _common.sh
|
||||
source /usr/share/yunohost/helpers
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
# Settings are automatically loaded as bash variables
|
||||
# in every app script context, therefore typically these will exist:
|
||||
# - $domain
|
||||
# - $path
|
||||
# - $language
|
||||
# - $install_dir
|
||||
# - $port
|
||||
# ...
|
||||
|
||||
# For remove operations :
|
||||
# - the core will deprovision every resource defined in the manifest **after** this script is ran
|
||||
# this includes removing the install directory, and data directory (if --purge was used)
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# REMOVE SYSTEM CONFIGURATIONS
|
||||
#=================================================
|
||||
# REMOVE SYSTEMD SERVICE
|
||||
#=================================================
|
||||
ynh_script_progression --message="Removing system configurations related to $app..."
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
# This should be a symetric version of what happens in the install script
|
||||
{% endif %}
|
||||
|
||||
{% if data.main_technology not in ["php", "none"] -%}
|
||||
# Remove the service from the list of services known by YunoHost (added from `yunohost service add`)
|
||||
if ynh_exec_warn_less yunohost service status $app >/dev/null
|
||||
then
|
||||
ynh_script_progression --message="Removing $app service integration..."
|
||||
yunohost service remove $app
|
||||
fi
|
||||
|
||||
ynh_remove_systemd_config
|
||||
{% endif %}
|
||||
|
||||
ynh_remove_nginx_config
|
||||
|
||||
{% if data.main_technology == "php" -%}
|
||||
ynh_remove_fpm_config
|
||||
{% endif %}
|
||||
|
||||
{% if data.use_logrotate -%}
|
||||
ynh_remove_logrotate
|
||||
{% endif %}
|
||||
|
||||
{% if data.use_fail2ban -%}
|
||||
ynh_remove_fail2ban_config
|
||||
{% endif %}
|
||||
|
||||
# Remove other various files specific to the app... such as :
|
||||
{% if data.use_cron -%}
|
||||
ynh_secure_remove --file="/etc/cron.d/$app"
|
||||
{% endif %}
|
||||
|
||||
ynh_secure_remove --file="/var/log/$app"
|
||||
|
||||
#=================================================
|
||||
# END OF SCRIPT
|
||||
#=================================================
|
||||
|
||||
ynh_script_progression --message="Removal of $app completed" --last
|
132
tools/app_generator/templates/restore.j2
Normal file
132
tools/app_generator/templates/restore.j2
Normal file
|
@ -0,0 +1,132 @@
|
|||
#!/bin/bash
|
||||
### App file generated with YoloGen, the Yunohost app generator, version {{ data['GENERATOR_VERSION'] }}.
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%} # This is the tutorial version of the app.
|
||||
# It contains extra commands to explain what should be done in case you want to adjust some part of the script.
|
||||
# Once you are done, you may remove them.
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# GENERIC START
|
||||
#=================================================
|
||||
# IMPORT GENERIC HELPERS
|
||||
#=================================================
|
||||
|
||||
# Keep this path for calling _common.sh inside the execution's context of backup and restore scripts
|
||||
source ../settings/scripts/_common.sh
|
||||
source /usr/share/yunohost/helpers
|
||||
|
||||
{% if data.install_dir %}
|
||||
#=================================================
|
||||
# RESTORE THE APP MAIN DIR
|
||||
#=================================================
|
||||
ynh_script_progression --message="Restoring the app main directory..." --weight=1
|
||||
|
||||
ynh_restore_file --origin_path="$install_dir"
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
# $install_dir will automatically be initialized with some decent
|
||||
# permission by default ... however, you may need to recursively reapply
|
||||
# ownership to all files such as after the ynh_setup_source step
|
||||
{% endif %}
|
||||
chown -R $app:www-data "$install_dir"
|
||||
{% endif %}
|
||||
|
||||
{% if data.data_dir -%}
|
||||
#=================================================
|
||||
# RESTORE THE DATA DIRECTORY
|
||||
#=================================================
|
||||
ynh_script_progression --message="Restoring the data directory..." --weight=1
|
||||
|
||||
ynh_restore_file --origin_path="$data_dir" --not_mandatory
|
||||
|
||||
# (Same as for install dir)
|
||||
chown -R $app:www-data "$data_dir"
|
||||
{% endif %}
|
||||
|
||||
{% if data.database -%}
|
||||
#=================================================
|
||||
# RESTORE THE MYSQL DATABASE
|
||||
#=================================================
|
||||
{% if data.datase == 'mysql' -%}
|
||||
ynh_script_progression --message="Restoring the MySQL database..." --weight=1
|
||||
|
||||
ynh_mysql_connect_as --user=$db_user --password=$db_pwd --database=$db_name < ./db.sql
|
||||
{% endif %}
|
||||
|
||||
{% if data.database == 'postgresql' -%}
|
||||
ynh_script_progression --message="Restoring the PostgreSQL database..." --weight=1
|
||||
|
||||
ynh_psql_connect_as --user=$db_user --password=$db_pwd --database=$db_name < ./db.sql
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# RESTORE SYSTEM CONFIGURATIONS
|
||||
#=================================================
|
||||
ynh_script_progression --message="Restoring system configurations related to $app..." --weight=1
|
||||
|
||||
# This should be a symetric version of what happens in the install script
|
||||
|
||||
{% if data.main_technology == "php" -%}
|
||||
ynh_restore_file --origin_path="/etc/php/$phpversion/fpm/pool.d/$app.conf"
|
||||
{% endif %}
|
||||
|
||||
ynh_restore_file --origin_path="/etc/nginx/conf.d/$domain.d/$app.conf"
|
||||
|
||||
{% if data.main_technology not in ["php", "none"] -%}
|
||||
ynh_restore_file --origin_path="/etc/systemd/system/$app.service"
|
||||
systemctl enable $app.service --quiet
|
||||
|
||||
yunohost service add $app --log="/var/log/$app/$app.log"
|
||||
{% endif %}
|
||||
|
||||
{% if data.use_logrotate -%}
|
||||
ynh_restore_file --origin_path="/etc/logrotate.d/$app"
|
||||
{% endif %}
|
||||
|
||||
{% if data.use_fail2ban -%}
|
||||
ynh_restore_file --origin_path="/etc/fail2ban/jail.d/$app.conf"
|
||||
ynh_restore_file --origin_path="/etc/fail2ban/filter.d/$app.conf"
|
||||
ynh_systemd_action --action=restart --service_name=fail2ban
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# RESTORE VARIOUS FILES
|
||||
#=================================================
|
||||
|
||||
{% if data.use_cron -%}
|
||||
ynh_restore_file --origin_path="/etc/cron.d/$app"
|
||||
{% endif %}
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
### For apps with huge logs, you might want to not backup logs every time:
|
||||
### The mkdir call is just here in case the log directory was not backed up.
|
||||
### mkdir -p "/var/log/$app"
|
||||
### chown $app:www-data "/var/log/$app"
|
||||
### ynh_restore_file --src_path="/var/log/$app/" --not_mandatory
|
||||
###
|
||||
### For other apps, the simple way is better:
|
||||
{% endif %}
|
||||
ynh_restore_file --origin_path="/var/log/$app/" # TODO : add custom log file option
|
||||
|
||||
#=================================================
|
||||
# RELOAD NGINX AND PHP-FPM OR THE APP SERVICE
|
||||
#=================================================
|
||||
ynh_script_progression --message="Reloading NGINX web server and $app's service..." --weight=1
|
||||
|
||||
# Typically you only have either $app or php-fpm but not both at the same time...
|
||||
{% if data.main_technology not in ["php", "none"] -%}
|
||||
ynh_systemd_action --service_name=$app --action="start" --log_path="/var/log/$app/$app.log"
|
||||
{% endif %}
|
||||
{% if data.main_technology == "php" -%}
|
||||
ynh_systemd_action --service_name=php$phpversion-fpm --action=reload
|
||||
{% endif %}
|
||||
|
||||
ynh_systemd_action --service_name=nginx --action=reload
|
||||
|
||||
#=================================================
|
||||
# END OF SCRIPT
|
||||
#=================================================
|
||||
|
||||
ynh_script_progression --message="Restoration completed for $app" --last
|
54
tools/app_generator/templates/systemd.j2
Normal file
54
tools/app_generator/templates/systemd.j2
Normal file
|
@ -0,0 +1,54 @@
|
|||
[Unit]
|
||||
Description=Service for {{ data.app_name }} (__APP__)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=__APP__
|
||||
Group=__APP__
|
||||
{% if data.custom_config_file == ".env" %}
|
||||
EnvironmentFile=__INSTALL_DIR__/.env
|
||||
{% endif %}
|
||||
WorkingDirectory=__INSTALL_DIR__/
|
||||
ExecStart={{ data.systemd_execstart }}
|
||||
StandardOutput=append:/var/log/__APP__/__APP__.log
|
||||
StandardError=inherit
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
|
||||
# Sandboxing options to harden security
|
||||
# Depending on specificities of your service/app, you may need to tweak these
|
||||
# .. but this should be a good baseline
|
||||
# Details for these options: https://www.freedesktop.org/software/systemd/man/systemd.exec.html
|
||||
NoNewPrivileges=yes
|
||||
PrivateTmp=yes
|
||||
PrivateDevices=yes
|
||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
|
||||
RestrictNamespaces=yes
|
||||
RestrictRealtime=yes
|
||||
DevicePolicy=closed
|
||||
ProtectClock=yes
|
||||
ProtectHostname=yes
|
||||
ProtectProc=invisible
|
||||
ProtectSystem=full
|
||||
ProtectControlGroups=yes
|
||||
ProtectKernelModules=yes
|
||||
ProtectKernelTunables=yes
|
||||
LockPersonality=yes
|
||||
SystemCallArchitectures=native
|
||||
SystemCallFilter=~@clock @debug @module @mount @obsolete @reboot @setuid @swap @cpu-emulation @privileged
|
||||
|
||||
# Denying access to capabilities that should not be relevant for webapps
|
||||
# Doc: https://man7.org/linux/man-pages/man7/capabilities.7.html
|
||||
CapabilityBoundingSet=~CAP_RAWIO CAP_MKNOD
|
||||
CapabilityBoundingSet=~CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE
|
||||
CapabilityBoundingSet=~CAP_SYS_BOOT CAP_SYS_TIME CAP_SYS_MODULE CAP_SYS_PACCT
|
||||
CapabilityBoundingSet=~CAP_LEASE CAP_LINUX_IMMUTABLE CAP_IPC_LOCK
|
||||
CapabilityBoundingSet=~CAP_BLOCK_SUSPEND CAP_WAKE_ALARM
|
||||
CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG
|
||||
CapabilityBoundingSet=~CAP_MAC_ADMIN CAP_MAC_OVERRIDE
|
||||
CapabilityBoundingSet=~CAP_NET_ADMIN CAP_NET_BROADCAST CAP_NET_RAW
|
||||
CapabilityBoundingSet=~CAP_SYS_ADMIN CAP_SYS_PTRACE CAP_SYSLOG
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
82
tools/app_generator/templates/tests.j2
Normal file
82
tools/app_generator/templates/tests.j2
Normal file
|
@ -0,0 +1,82 @@
|
|||
#:schema https://raw.githubusercontent.com/YunoHost/apps/master/schemas/tests.v1.schema.json
|
||||
|
||||
test_format = 1.0
|
||||
|
||||
[default]
|
||||
|
||||
# ------------
|
||||
# Tests to run
|
||||
# ------------
|
||||
|
||||
{% if data.generator_mode == "tutorial" -%}
|
||||
# -------------------------------------------------------------------------------
|
||||
# EVERYTHING PAST THIS POINT IS OPTIONAL AND MOST LIKELY UNNECESSARY FOR NEW APPS
|
||||
#--------------------------------------------------------------------------------
|
||||
## Conventions in this sample:
|
||||
## <- An actual comment
|
||||
# <- uncommenting this should be a valid entry in 'tests.toml'
|
||||
|
||||
## NB: the tests to run are automatically deduced by the CI script according to the
|
||||
## content of the app's manifest. The declarations below allow to customize which
|
||||
## tests are ran, possibly add special test suite to test special args, or
|
||||
## declare which commits to test upgrade from.
|
||||
##
|
||||
## You can also decide (though this is discouraged!) to ban/ignore some tests,
|
||||
## The test IDs to be used in only/exclude statements are:
|
||||
## * install.root
|
||||
## * install.subdir
|
||||
## * install.nourl
|
||||
## * install.multi
|
||||
## * backup_restore
|
||||
## * upgrade
|
||||
## * upgrade.someCommitId
|
||||
## * change_url
|
||||
## NB: you should NOT need this except if you really have a good reason...
|
||||
|
||||
# exclude = ["install.private", "install.multi"]
|
||||
|
||||
## For special usecases, sometimes you need to setup other things on the machine
|
||||
## prior to installing the app (such as installing another app)
|
||||
## (Remove this key entirely if not needed)
|
||||
|
||||
# preinstall = """
|
||||
# sudo yunohost app install foobar
|
||||
# sudo yunohost user list
|
||||
# """
|
||||
|
||||
# -------------------------------
|
||||
# Default args to use for install
|
||||
# -------------------------------
|
||||
|
||||
## By default, the CI will automagically fill the 'standard' args
|
||||
## such as domain, path, admin, is_public and password with relevant values
|
||||
## and also install args with a "default" provided in the manifest..
|
||||
## It should only make sense to declare custom args here for args with no default values
|
||||
## NB: you should NOT need those lines unless for custom questions with no obvious/default value
|
||||
|
||||
# args.language = "fr_FR"
|
||||
# args.multisite = 0
|
||||
|
||||
# -------------------------------
|
||||
# Commits to test upgrade from
|
||||
# -------------------------------
|
||||
|
||||
## 00a1a6e7 is part of commit SHA, preferrably from 'master' branch
|
||||
## that points to valid install of previous version
|
||||
|
||||
# test_upgrade_from.00a1a6e7.name = "Upgrade from 5.4"
|
||||
# test_upgrade_from.00a1a6e7.args.foo = "bar"
|
||||
|
||||
|
||||
## This is an additional test suite
|
||||
# [some_additional_testsuite]
|
||||
|
||||
## On additional tests suites, you can decide to run only specific tests
|
||||
|
||||
# only = ["install.subdir"]
|
||||
|
||||
# args.language = "en_GB"
|
||||
# args.multisite = 1
|
||||
|
||||
|
||||
{% endif -%}
|
185
tools/app_generator/templates/upgrade.j2
Normal file
185
tools/app_generator/templates/upgrade.j2
Normal file
|
@ -0,0 +1,185 @@
|
|||
#!/bin/bash
|
||||
### App file generated with YoloGen, the Yunohost app generator, version {{ data['GENERATOR_VERSION'] }}.
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%} # This is the tutorial version of the app.
|
||||
# It contains extra commands to explain what should be done in case you want to adjust some part of the script.
|
||||
# Once you are done, you may remove them.
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# GENERIC START
|
||||
#=================================================
|
||||
# IMPORT GENERIC HELPERS
|
||||
#=================================================
|
||||
|
||||
source _common.sh
|
||||
source /usr/share/yunohost/helpers
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
# Settings are automatically loaded as bash variables
|
||||
# in every app script context, therefore typically these will exist:
|
||||
# - $domain
|
||||
# - $path
|
||||
# - $language
|
||||
# - $install_dir
|
||||
# - $port
|
||||
# ...
|
||||
|
||||
# In the context of upgrade,
|
||||
# - resources are automatically provisioned / updated / deleted (depending on existing resources)
|
||||
# - a safety backup is automatically created by the core and will be restored if the upgrade fails
|
||||
|
||||
### This helper will compare the version of the currently installed app and the version of the upstream package.
|
||||
### $upgrade_type can have 2 different values
|
||||
### - UPGRADE_APP if the upstream app version has changed
|
||||
### - UPGRADE_PACKAGE if only the YunoHost package has changed
|
||||
### ynh_check_app_version_changed will stop the upgrade if the app is up to date.
|
||||
### UPGRADE_APP should be used to upgrade the core app only if there's an upgrade to do.
|
||||
{% endif %}
|
||||
upgrade_type=$(ynh_check_app_version_changed)
|
||||
|
||||
#=================================================
|
||||
# STANDARD UPGRADE STEPS
|
||||
#=================================================
|
||||
# ENSURE DOWNWARD COMPATIBILITY
|
||||
#=================================================
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
#ynh_script_progression --message="Ensuring downward compatibility..."
|
||||
|
||||
#
|
||||
# N.B. : the followings setting migrations snippets are provided as *EXAMPLES*
|
||||
# of what you may want to do in some cases (e.g. a setting was not defined on
|
||||
# some legacy installs and you therefore want to initialize stuff during upgrade)
|
||||
#
|
||||
|
||||
# If db_name doesn't exist, create it
|
||||
#if [ -z "${db_name:-}" ]; then
|
||||
# db_name=$(ynh_sanitize_dbid --db_name=$app)
|
||||
# ynh_app_setting_set --app=$app --key=db_name --value=$db_name
|
||||
#fi
|
||||
|
||||
# If install_dir doesn't exist, create it
|
||||
#if [ -z "${install_dir:-}" ]; then
|
||||
# install_dir=/var/www/$app
|
||||
# ynh_app_setting_set --app=$app --key=install_dir --value=$install_dir
|
||||
#fi
|
||||
{% endif %}
|
||||
|
||||
{% if data.main_technology not in ["php", "none"] -%}
|
||||
#=================================================
|
||||
# STOP SYSTEMD SERVICE
|
||||
#=================================================
|
||||
ynh_script_progression --message="Stopping a systemd service..."
|
||||
|
||||
ynh_systemd_action --service_name=$app --action="stop" --log_path="/var/log/$app/$app.log"
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# "REBUILD" THE APP (DEPLOY NEW SOURCES, RERUN NPM BUILD...)
|
||||
#=================================================
|
||||
# DOWNLOAD, CHECK AND UNPACK SOURCE
|
||||
#=================================================
|
||||
|
||||
if [ "$upgrade_type" == "UPGRADE_APP" ]
|
||||
then
|
||||
ynh_script_progression --message="Upgrading source files..."
|
||||
|
||||
# Download, check integrity, uncompress and patch the source from app.src
|
||||
ynh_setup_source --dest_dir="$install_dir" --full_replace=1 --keep=".env"
|
||||
{{ data.custom_config_file }}
|
||||
fi
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
# $install_dir will automatically be initialized with some decent
|
||||
# permission by default ... however, you may need to recursively reapply
|
||||
# ownership to all files such as after the ynh_setup_source step
|
||||
{% endif %}
|
||||
chown -R $app:www-data "$install_dir"
|
||||
|
||||
#=================================================
|
||||
# REAPPLY SYSTEM CONFIGURATIONS
|
||||
#=================================================
|
||||
ynh_script_progression --message="Upgrading system configurations related to $app..."
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
# This should be a literal copypasta of what happened in the install's "System configuration" section
|
||||
{% endif %}
|
||||
|
||||
{% if data.main_technology == "php" -%}
|
||||
ynh_add_fpm_config
|
||||
{% endif %}
|
||||
|
||||
ynh_add_nginx_config
|
||||
|
||||
{% if data.main_technology not in ["php", "none"] -%}
|
||||
ynh_add_systemd_config
|
||||
|
||||
yunohost service add $app --log="/var/log/$app/$app.log"
|
||||
{% endif %}
|
||||
|
||||
{% if data.use_logrotate -%}
|
||||
ynh_use_logrotate --non-append
|
||||
{% endif %}
|
||||
|
||||
{% if data.use_fail2ban -%}
|
||||
# Create a dedicated Fail2Ban config
|
||||
ynh_add_fail2ban_config --logpath="/var/log/nginx/${domain}-error.log" --failregex="{{ data.fail2ban_regex }}"
|
||||
{% endif %}
|
||||
|
||||
{% if data.use_cron -%}
|
||||
cron_path="/etc/cron.d/$app"
|
||||
ynh_add_config --template="../conf/task.cron" --destination="$cron_path"
|
||||
chown root: "$cron_path"
|
||||
chmod 644 "$cron_path"
|
||||
{% endif %}
|
||||
|
||||
{% if data.use_custom_config_file -%}
|
||||
#=================================================
|
||||
# RECONFIGURE THE APP (UPDATE CONF, APPLY MIGRATIONS...)
|
||||
#=================================================
|
||||
# UPDATE A CONFIG FILE
|
||||
#=================================================
|
||||
ynh_script_progression --message="Updating a configuration file..."
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
### Same as during install
|
||||
###
|
||||
### The file will automatically be backed-up if it's found to be manually modified (because
|
||||
### ynh_add_config keeps track of the file's checksum)
|
||||
{% endif %}
|
||||
|
||||
ynh_add_config --template="{{ data.custom_config_file }}" --destination="$install_dir/{{ data.custom_config_file }}"
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
# FIXME: this should be handled by the core in the future
|
||||
# You may need to use chmod 600 instead of 400,
|
||||
# for example if the app is expected to be able to modify its own config
|
||||
{% endif %}
|
||||
chmod 400 "$install_dir/{{ data.custom_config_file }}"
|
||||
chown $app:$app "$install_dir/{{ data.custom_config_file }}"
|
||||
|
||||
{% if data.generator_mode == 'tutorial' -%}
|
||||
### For more complex cases where you want to replace stuff using regexes,
|
||||
### you shoud rely on ynh_replace_string (which is basically a wrapper for sed)
|
||||
### When doing so, you also need to manually call ynh_store_file_checksum
|
||||
###
|
||||
### ynh_replace_string --match_string="match_string" --replace_string="replace_string" --target_file="$install_dir/{{ data.custom_config_file }}"
|
||||
### ynh_store_file_checksum --file="$install_dir/{{ data.custom_config_file }}"
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if data.main_technology not in ["php", "none"] -%}
|
||||
#=================================================
|
||||
# START SYSTEMD SERVICE
|
||||
#=================================================
|
||||
ynh_script_progression --message="Starting a systemd service..."
|
||||
|
||||
ynh_systemd_action --service_name=$app --action="start" --log_path="/var/log/$app/$app.log"
|
||||
{% endif %}
|
||||
|
||||
#=================================================
|
||||
# END OF SCRIPT
|
||||
#=================================================
|
||||
|
||||
ynh_script_progression --message="Upgrade of $app completed" --last
|
213
tools/app_generator/templates/wtf.html
Normal file
213
tools/app_generator/templates/wtf.html
Normal file
|
@ -0,0 +1,213 @@
|
|||
{% macro form_errors(form, hiddens=True) %}
|
||||
{%- if form.errors %}
|
||||
{%- for fieldname, errors in form.errors.items() %}
|
||||
{%- if bootstrap_is_hidden_field(form[fieldname]) and hiddens or
|
||||
not bootstrap_is_hidden_field(form[fieldname]) and hiddens != 'only' %}
|
||||
{%- for error in errors %}
|
||||
<p class="error">{{error}}</p>
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro _hz_form_wrap(horizontal_columns, form_type, add_group=False, required=False) %}
|
||||
{% if form_type == "horizontal" %}
|
||||
{% if add_group %}<div class="form-group{% if required %} required{% endif %}">{% endif %}
|
||||
<div class="col-{{horizontal_columns[0]}}-offset-{{horizontal_columns[1]}}
|
||||
col-{{horizontal_columns[0]}}-{{horizontal_columns[2]}}
|
||||
">
|
||||
{% endif %}
|
||||
{{caller()}}
|
||||
|
||||
{% if form_type == "horizontal" %}
|
||||
{% if add_group %}</div>{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro form_field(field,
|
||||
form_type="basic",
|
||||
horizontal_columns=('lg', 2, 10),
|
||||
button_map={}) %}
|
||||
|
||||
{# this is a workaround hack for the more straightforward-code of just passing required=required parameter. older versions of wtforms do not have
|
||||
the necessary fix for required=False attributes, but will also not set the required flag in the first place. we skirt the issue using the code below #}
|
||||
{% if field.flags.required and not required in kwargs %}
|
||||
{% set kwargs = dict(required=True, **kwargs) %}
|
||||
{% endif %}
|
||||
|
||||
{% if field.widget.input_type == 'checkbox' %}
|
||||
{% call _hz_form_wrap(horizontal_columns, form_type, True, required=required) %}
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
{{field()|safe}} {{field.label.text|safe}}
|
||||
</label>
|
||||
</div>
|
||||
{% endcall %}
|
||||
{%- elif field.type == 'RadioField' -%}
|
||||
{# note: A cleaner solution would be rendering depending on the widget,
|
||||
this is just a hack for now, until I can think of something better #}
|
||||
{% call _hz_form_wrap(horizontal_columns, form_type, True, required=required) %}
|
||||
{% for item in field -%}
|
||||
<div class="radio">
|
||||
<label>
|
||||
{{item|safe}} {{item.label.text|safe}}
|
||||
</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endcall %}
|
||||
{%- elif field.type == 'SubmitField' -%}
|
||||
{# deal with jinja scoping issues? #}
|
||||
{% set field_kwargs = kwargs %}
|
||||
|
||||
{# note: same issue as above - should check widget, not field type #}
|
||||
{% call _hz_form_wrap(horizontal_columns, form_type, True, required=required) %}
|
||||
{{field(class='btn btn-%s' % button_map.get(field.name, 'default'),
|
||||
**field_kwargs)}}
|
||||
{% endcall %}
|
||||
{%- elif field.type == 'FormField' -%}
|
||||
{# note: FormFields are tricky to get right and complex setups requiring
|
||||
these are probably beyond the scope of what this macro tries to do.
|
||||
the code below ensures that things don't break horribly if we run into
|
||||
one, but does not try too hard to get things pretty. #}
|
||||
<fieldset>
|
||||
<legend>{{field.label}}</legend>
|
||||
{%- for subfield in field %}
|
||||
{% if not bootstrap_is_hidden_field(subfield) -%}
|
||||
{{ form_field(subfield,
|
||||
form_type=form_type,
|
||||
horizontal_columns=horizontal_columns,
|
||||
button_map=button_map) }}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
</fieldset>
|
||||
{% else -%}
|
||||
<div class="form-group {% if field.errors %} has-error{% endif -%}
|
||||
{%- if field.flags.required %} required{% endif -%}
|
||||
">
|
||||
{%- if form_type == "inline" %}
|
||||
{{field.label(class="sr-only")|safe}}
|
||||
{% if field.type == 'FileField' %}
|
||||
{{field(**kwargs)|safe}}
|
||||
{% else %}
|
||||
{{field(class="form-control", **kwargs)|safe}}
|
||||
{% endif %}
|
||||
{% elif form_type == "horizontal" %}
|
||||
{{field.label(class="control-label " + (
|
||||
" col-%s-%s" % horizontal_columns[0:2]
|
||||
))|safe}}
|
||||
<div class=" col-{{horizontal_columns[0]}}-{{horizontal_columns[2]}}">
|
||||
{% if field.type == 'FileField' %}
|
||||
{{field(**kwargs)|safe}}
|
||||
{% else %}
|
||||
{{field(class="form-control", **kwargs)|safe}}
|
||||
{% endif %}
|
||||
</div>
|
||||
{%- if field.errors %}
|
||||
{%- for error in field.errors %}
|
||||
{% call _hz_form_wrap(horizontal_columns, form_type, required=required) %}
|
||||
<p class="help-block">{{error}}</p>
|
||||
{% endcall %}
|
||||
{%- endfor %}
|
||||
{%- elif field.description -%}
|
||||
{% call _hz_form_wrap(horizontal_columns, form_type, required=required) %}
|
||||
<p class="help-block">{{field.description|safe}}</p>
|
||||
{% endcall %}
|
||||
{%- endif %}
|
||||
{%- else -%}
|
||||
{{field.label(class="control-label")|safe}}
|
||||
{% if field.type == 'FileField' %}
|
||||
{{field(**kwargs)|safe}}
|
||||
{% else %}
|
||||
{{field(class="form-control", **kwargs)|safe}}
|
||||
{% endif %}
|
||||
|
||||
{%- if field.errors %}
|
||||
{%- for error in field.errors %}
|
||||
<p class="help-block">{{error}}</p>
|
||||
{%- endfor %}
|
||||
{%- elif field.description -%}
|
||||
<p class="help-block">{{field.description|safe}}</p>
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{# valid form types are "basic", "inline" and "horizontal" #}
|
||||
{% macro quick_form(form,
|
||||
action="",
|
||||
method="post",
|
||||
extra_classes=None,
|
||||
role="form",
|
||||
form_type="basic",
|
||||
horizontal_columns=('lg', 2, 10),
|
||||
enctype=None,
|
||||
button_map={},
|
||||
id="",
|
||||
novalidate=False) %}
|
||||
{#-
|
||||
action="" is what we want, from http://www.ietf.org/rfc/rfc2396.txt:
|
||||
|
||||
4.2. Same-document References
|
||||
|
||||
A URI reference that does not contain a URI is a reference to the
|
||||
current document. In other words, an empty URI reference within a
|
||||
document is interpreted as a reference to the start of that document,
|
||||
and a reference containing only a fragment identifier is a reference
|
||||
to the identified fragment of that document. Traversal of such a
|
||||
reference should not result in an additional retrieval action.
|
||||
However, if the URI reference occurs in a context that is always
|
||||
intended to result in a new request, as in the case of HTML's FORM
|
||||
element, then an empty URI reference represents the base URI of the
|
||||
current document and should be replaced by that URI when transformed
|
||||
into a request.
|
||||
|
||||
-#}
|
||||
{#- if any file fields are inside the form and enctype is automatic, adjust
|
||||
if file fields are found. could really use the equalto test of jinja2
|
||||
here, but latter is not available until 2.8
|
||||
|
||||
warning: the code below is guaranteed to make you cry =(
|
||||
#}
|
||||
{%- set _enctype = [] %}
|
||||
{%- if enctype is none -%}
|
||||
{%- for field in form %}
|
||||
{%- if field.type == 'FileField' %}
|
||||
{#- for loops come with a fairly watertight scope, so this list-hack is
|
||||
used to be able to set values outside of it #}
|
||||
{%- set _ = _enctype.append('multipart/form-data') -%}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
{%- else %}
|
||||
{% set _ = _enctype.append(enctype) %}
|
||||
{%- endif %}
|
||||
<form
|
||||
{%- if action != None %} action="{{action}}"{% endif -%}
|
||||
{%- if id %} id="{{id}}"{% endif -%}
|
||||
{%- if method %} method="{{method}}"{% endif %}
|
||||
class="form
|
||||
{%- if extra_classes %} {{extra_classes}}{% endif -%}
|
||||
{%- if form_type == "horizontal" %} form-horizontal
|
||||
{%- elif form_type == "inline" %} form-inline
|
||||
{%- endif -%}
|
||||
"
|
||||
{%- if _enctype[0] %} enctype="{{_enctype[0]}}"{% endif -%}
|
||||
{%- if role %} role="{{role}}"{% endif -%}
|
||||
{%- if novalidate %} novalidate{% endif -%}
|
||||
>
|
||||
{{ form.hidden_tag() }}
|
||||
{{ form_errors(form, hiddens='only') }}
|
||||
|
||||
{%- for field in form %}
|
||||
{% if not bootstrap_is_hidden_field(field) -%}
|
||||
{{ form_field(field,
|
||||
form_type=form_type,
|
||||
horizontal_columns=horizontal_columns,
|
||||
button_map=button_map) }}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
|
||||
</form>
|
||||
{%- endmacro %}
|
BIN
tools/app_generator/translations/en/LC_MESSAGES/messages.mo
Normal file
BIN
tools/app_generator/translations/en/LC_MESSAGES/messages.mo
Normal file
Binary file not shown.
760
tools/app_generator/translations/en/LC_MESSAGES/messages.po
Normal file
760
tools/app_generator/translations/en/LC_MESSAGES/messages.po
Normal file
|
@ -0,0 +1,760 @@
|
|||
# English translations for PROJECT.
|
||||
# Copyright (C) 2024 ORGANIZATION
|
||||
# This file is distributed under the same license as the PROJECT project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-04-26 15:39+0200\n"
|
||||
"PO-Revision-Date: 2024-03-31 20:23+0200\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: en\n"
|
||||
"Language-Team: en <LL@li.org>\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.14.0\n"
|
||||
|
||||
#: app.py:68 app.py:334
|
||||
msgid "English"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:68 app.py:335
|
||||
msgid "French"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:127
|
||||
msgid "Select language"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:137
|
||||
msgid "Application identifier (id)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:138
|
||||
msgid "Small caps and without spaces"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:146
|
||||
msgid "App name"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:147
|
||||
msgid "It's the application name, displayed in the user interface"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:157
|
||||
msgid "Short description (en)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:158 app.py:165
|
||||
msgid ""
|
||||
"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"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:164
|
||||
msgid "Short description (fr)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:176
|
||||
msgid "Version"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:182
|
||||
msgid "Maintainer of the generated app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:183
|
||||
msgid "Usually you put your name here... If you're okay with it ;)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:189
|
||||
msgid "Minimal YunoHost version"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:190
|
||||
msgid "Minimal YunoHost version for the application to work"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:199
|
||||
msgid "Supported architectures"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:201
|
||||
msgid "All architectures"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:212
|
||||
msgid ""
|
||||
"The app can be installed multiple times at the same time on the same "
|
||||
"server"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:219
|
||||
msgid "The app will be integrating LDAP"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:220
|
||||
msgid ""
|
||||
"Which means it's possible to use Yunohost credentials to log into this "
|
||||
"app. 'LDAP' corresponds to the technology used by Yunohost to handle a "
|
||||
"centralised user base. Bridging the app and Yunohost's LDAP often "
|
||||
"requires to add the proper technical details in the app's configuration "
|
||||
"file"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:224 app.py:238
|
||||
msgid "No"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:225 app.py:237
|
||||
msgid "Yes"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:226 app.py:239
|
||||
msgid "Not relevant"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:232
|
||||
msgid "The app will be integrated in Yunohost SSO (Single Sign On)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:233
|
||||
msgid ""
|
||||
"Which means that people will be logged in the app after logging in "
|
||||
"YunoHost's portal, without having to sign on specifically into this app."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:249
|
||||
msgid "Licence"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:250
|
||||
msgid ""
|
||||
"You should check this on the upstream repository. The expected format is "
|
||||
"a SPDX id listed in https://spdx.org/licenses/"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:257
|
||||
msgid "Official website"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:258
|
||||
msgid "Leave empty if there is no official website"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:265
|
||||
msgid "Official app demo"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:266
|
||||
msgid "Leave empty if there is no official demo"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:273
|
||||
msgid "Admin documentation"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:274
|
||||
msgid "Leave empty if there is no official admin doc"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:281
|
||||
msgid "Usage documentation"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:282
|
||||
msgid "Leave empty if there is no official user doc"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:289
|
||||
msgid "Code repository"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:300
|
||||
msgid ""
|
||||
"Ask the URL where the app will be installed ('domain' and 'path' "
|
||||
"variables)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:305
|
||||
msgid "Ask domain+path"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:308
|
||||
msgid ""
|
||||
"Ask only the domain (the app requires to be installed at the root of a "
|
||||
"dedicated domain)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:312
|
||||
msgid "Do not ask (it isn't a webapp)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:317
|
||||
msgid "Ask who can access to the app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:318
|
||||
msgid ""
|
||||
"In the users groups : by default at least 'visitors', 'all_users' et "
|
||||
"'admins' exists. (It was previously the private/public app concept)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:325
|
||||
msgid "Ask who can access to the admin interface"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:326
|
||||
msgid "In the case where the app has an admin interface"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:331
|
||||
msgid "Supported languages"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:333
|
||||
msgid "None / not relevant"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:336
|
||||
msgid "Spanish"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:337
|
||||
msgid "Italian"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:338
|
||||
msgid "German"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:339
|
||||
msgid "Chinese"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:340
|
||||
msgid "Japanese"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:341
|
||||
msgid "Danish"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:342
|
||||
msgid "Portugese"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:343
|
||||
msgid "Dutch"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:344
|
||||
msgid "Russian"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:356
|
||||
msgid "Application source code or executable"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:363
|
||||
msgid "Sources sha256 checksum"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:371
|
||||
msgid "Enable automatic update of sources (using a bot running every night)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:372
|
||||
msgid ""
|
||||
"If the upstream software is hosted in one of the handled sources and "
|
||||
"publishes proper releases or tags, the bot will create a pull request to "
|
||||
"update the sources URL and checksum"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:394
|
||||
msgid "Dependencies to be installed via apt (separated by comma and/or spaces)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:403
|
||||
msgid "Initialize an SQL database"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:413
|
||||
msgid "Initialize a system user for this app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:418
|
||||
msgid "Initialize an installation folder for this app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:419
|
||||
msgid "By default it's /var/www/$app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:424
|
||||
msgid "Initialize a folder to store the app data"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:425
|
||||
msgid "By default it's /var/yunohost.app/$app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:433
|
||||
msgid "App main technology"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:435
|
||||
msgid "None / Static application"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:440
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:447
|
||||
msgid "Installation specific commands"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:448
|
||||
msgid ""
|
||||
"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"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:460
|
||||
msgid "Use composer"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:461
|
||||
msgid "Composer is a PHP dependencies manager used by some apps"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:472
|
||||
msgid "NodeJS version"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:473
|
||||
msgid "For example: 16.4, 18, 18.2, 20, 20.1, ..."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:480
|
||||
msgid "Install and use Yarn"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:487
|
||||
msgid "Command to start the app daemon (from systemd service)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:488
|
||||
msgid ""
|
||||
"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"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:500
|
||||
msgid "The app uses a specific configuration file"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:501
|
||||
msgid "Usually : .env, config.json, conf.ini, params.yml, ..."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:508
|
||||
msgid "Name or file path to use"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:516
|
||||
msgid "App configuration file pattern"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:517
|
||||
msgid ""
|
||||
"In this pattern, you can use the syntax __FOO_BAR__ which will "
|
||||
"automatically replaced by the value of the variable $foo_bar"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:529
|
||||
msgid ""
|
||||
"doc/DESCRIPTION.md: A comprehensive presentation of the app, possibly "
|
||||
"listing the main features, possible warnings and specific details on its "
|
||||
"functioning in Yunohost (e.g. warning about integration issues)."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:539
|
||||
msgid ""
|
||||
"doc/PRE_INSTALL.md: important info to be shown to the admin before "
|
||||
"installing the app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:540 app.py:548 app.py:556 app.py:564 app.py:572
|
||||
msgid "Leave empty if not relevant"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:547
|
||||
msgid ""
|
||||
"doc/POST_INSTALL.md: important info to be shown to the admin after "
|
||||
"installing the app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:555
|
||||
msgid ""
|
||||
"doc/PRE_UPGRADE.md: important info to be shown to the admin before "
|
||||
"upgrading the app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:563
|
||||
msgid ""
|
||||
"doc/POST_UPGRADE.md: important info to be shown to the admin after "
|
||||
"upgrading the app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:571
|
||||
msgid "doc/ADMIN.md: general tips on how to administrate this app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:583
|
||||
msgid "Handle app install URL change (change_url script)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:586
|
||||
msgid "Should changing the app URL be allowed ? (change_url change)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:593
|
||||
msgid "Use logrotate for the app logs"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:596
|
||||
msgid ""
|
||||
"If the app generates logs, this option permit to handle their archival. "
|
||||
"Recommended."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:604
|
||||
msgid "Protect the application against brute force attacks (via fail2ban)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:609
|
||||
msgid ""
|
||||
"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."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:615
|
||||
msgid "Add a CRON task for this application"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:616
|
||||
msgid "Corresponds to some app periodic operations"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:620
|
||||
msgid "Type the CRON file content"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:629
|
||||
msgid "Regular expression for fail2ban"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:633
|
||||
msgid "A regular expression"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:635
|
||||
msgid ""
|
||||
"Regular expression to check in the log file to activate failban (search "
|
||||
"for a line that indicates a credentials error)."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:659
|
||||
msgid "Generator mode"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:660
|
||||
msgid ""
|
||||
"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."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:664
|
||||
msgid "Streamlined version"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:665
|
||||
msgid "Tutorial version"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:671
|
||||
msgid "Previsualise"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:672
|
||||
msgid "Download the .zip"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:674
|
||||
msgid "Fill with demo values"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:677
|
||||
msgid ""
|
||||
"Generate a complete and functionnal minimalistic app that you can iterate"
|
||||
" from"
|
||||
msgstr ""
|
||||
|
||||
#: templates/base.html:5
|
||||
msgid "YunoHost app generator"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:28
|
||||
msgid "Yunohost application generation form"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:55
|
||||
msgid "1/9 - General information"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:70
|
||||
msgid "2/9 - Upstream information"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:73
|
||||
msgid ""
|
||||
"The word 'upstream' refers to the original project that develops and "
|
||||
"maintains the app"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:88
|
||||
msgid "3/9 - Integration in YunoHost"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:104
|
||||
msgid "4/9 - Questions to ask during installation"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:108
|
||||
msgid "This part is meant to indicate the questions that will be asked."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:110
|
||||
msgid ""
|
||||
"NB: only standard questions are asked here, it might be required to "
|
||||
"complete it by hand using other questions as a guide."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:124
|
||||
msgid "5/9 - Resources to initialize"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:128
|
||||
msgid ""
|
||||
"Technical elements configured before launching the 'real' app install "
|
||||
"script. Usually : creating a system user, downloading app sources, "
|
||||
"initialiser le dossier d'install et de données, install apt dependencies,"
|
||||
" create a database, ..."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:151
|
||||
msgid "6/9 - Specific technology"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:156
|
||||
msgid ""
|
||||
"You probably want to make sure to have 'phpX.Y-fpm' and others "
|
||||
"'phpX.Y-foobar' libraries listed the apt dependencies earlier (with X.Y "
|
||||
"being the php version you want to use)"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:157
|
||||
msgid ""
|
||||
"The generated application draft will include an nginx configuration "
|
||||
"snippet that interfaces with PHP-FPM"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:165
|
||||
msgid ""
|
||||
"You probably want to make sure to have 'python3' and 'python3-venv' "
|
||||
"listed in the apt dependencies earlier. Other dependencies should be "
|
||||
"installed inside a venv (cf the proposed install snippet)"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:169
|
||||
msgid ""
|
||||
"The generated application draft will include an nginx configuration "
|
||||
"snippet that reverse-proxies to a systemd service using an internal port"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:237
|
||||
msgid "7/9 - App configuration"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:261
|
||||
msgid "8/9 - General and advanced documentation"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:275
|
||||
msgid "9/9 - Advanced options"
|
||||
msgstr ""
|
||||
|
||||
#~ msgid "Maintener of the generated app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Commonly you put your name here... If you agree with it ;)"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "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"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "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)"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Activate the automated source update bot"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "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"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Dependances to be installed via apt "
|
||||
#~ "(separated by a quote and/or spaces)"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Initialise a SQL database"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Initialise a system user for this app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Initialise an installation folder for this app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Initialise a folder to store the app data"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "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"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Type the DISCLAIMER.md file content, "
|
||||
#~ "which list warnings and attention "
|
||||
#~ "points."
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Type the PRE_INSTALL.md file content"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Type the POST_INSTALL.md file content"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Type the PRE_UPGRADE.md file content"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Type the POST_UPGRADE.md file content"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Type the ADMIN.md file content"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "2/9 - Informations about the application"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "The word upstream refers to the original project that maintains the app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "5/9 - Ressources to initialise"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "A more complete presentation that the"
|
||||
#~ " summary completed above, explaining to "
|
||||
#~ "what correspond the software, the "
|
||||
#~ "eventual warnings and specific details "
|
||||
#~ "on its functioning in Yunohost (it's "
|
||||
#~ "the place where one can warn about"
|
||||
#~ " integration issues)."
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Indications to show at key steps "
|
||||
#~ "to manage the package : installation,"
|
||||
#~ " update, message to the admin "
|
||||
#~ "account. You usually don't have to "
|
||||
#~ "fill them."
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Description courte (fr)"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Français"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "doc/DESCRIPTION.md : A comprehensive "
|
||||
#~ "presentation of the app, possibly "
|
||||
#~ "listing the main features, possible "
|
||||
#~ "warnings and specific details on its "
|
||||
#~ "functioning in Yunohost (e.g. warning "
|
||||
#~ "about integration issues)."
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "doc/PRE_INSTALL.md : important info to "
|
||||
#~ "be shown to the admin before "
|
||||
#~ "installing the app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "doc/POST_INSTALL.md : important info to "
|
||||
#~ "be shown to the admin after "
|
||||
#~ "installing the app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "doc/PRE_UPGRADE.md : important info to "
|
||||
#~ "be shown to the admin before "
|
||||
#~ "upgrading the app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "doc/POST_UPGRADE.md : important info to "
|
||||
#~ "be shown to the admin after "
|
||||
#~ "upgrading the app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "doc/ADMIN.md : general tips on how to administrate this app"
|
||||
#~ msgstr ""
|
||||
|
BIN
tools/app_generator/translations/es/LC_MESSAGES/messages.mo
Normal file
BIN
tools/app_generator/translations/es/LC_MESSAGES/messages.mo
Normal file
Binary file not shown.
760
tools/app_generator/translations/es/LC_MESSAGES/messages.po
Normal file
760
tools/app_generator/translations/es/LC_MESSAGES/messages.po
Normal file
|
@ -0,0 +1,760 @@
|
|||
# Spanish translations for PROJECT.
|
||||
# Copyright (C) 2024 ORGANIZATION
|
||||
# This file is distributed under the same license as the PROJECT project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-04-26 15:39+0200\n"
|
||||
"PO-Revision-Date: 2024-03-31 20:02+0200\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: es\n"
|
||||
"Language-Team: es <LL@li.org>\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.14.0\n"
|
||||
|
||||
#: app.py:68 app.py:334
|
||||
msgid "English"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:68 app.py:335
|
||||
msgid "French"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:127
|
||||
msgid "Select language"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:137
|
||||
msgid "Application identifier (id)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:138
|
||||
msgid "Small caps and without spaces"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:146
|
||||
msgid "App name"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:147
|
||||
msgid "It's the application name, displayed in the user interface"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:157
|
||||
msgid "Short description (en)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:158 app.py:165
|
||||
msgid ""
|
||||
"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"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:164
|
||||
msgid "Short description (fr)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:176
|
||||
msgid "Version"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:182
|
||||
msgid "Maintainer of the generated app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:183
|
||||
msgid "Usually you put your name here... If you're okay with it ;)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:189
|
||||
msgid "Minimal YunoHost version"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:190
|
||||
msgid "Minimal YunoHost version for the application to work"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:199
|
||||
msgid "Supported architectures"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:201
|
||||
msgid "All architectures"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:212
|
||||
msgid ""
|
||||
"The app can be installed multiple times at the same time on the same "
|
||||
"server"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:219
|
||||
msgid "The app will be integrating LDAP"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:220
|
||||
msgid ""
|
||||
"Which means it's possible to use Yunohost credentials to log into this "
|
||||
"app. 'LDAP' corresponds to the technology used by Yunohost to handle a "
|
||||
"centralised user base. Bridging the app and Yunohost's LDAP often "
|
||||
"requires to add the proper technical details in the app's configuration "
|
||||
"file"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:224 app.py:238
|
||||
msgid "No"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:225 app.py:237
|
||||
msgid "Yes"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:226 app.py:239
|
||||
msgid "Not relevant"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:232
|
||||
msgid "The app will be integrated in Yunohost SSO (Single Sign On)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:233
|
||||
msgid ""
|
||||
"Which means that people will be logged in the app after logging in "
|
||||
"YunoHost's portal, without having to sign on specifically into this app."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:249
|
||||
msgid "Licence"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:250
|
||||
msgid ""
|
||||
"You should check this on the upstream repository. The expected format is "
|
||||
"a SPDX id listed in https://spdx.org/licenses/"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:257
|
||||
msgid "Official website"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:258
|
||||
msgid "Leave empty if there is no official website"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:265
|
||||
msgid "Official app demo"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:266
|
||||
msgid "Leave empty if there is no official demo"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:273
|
||||
msgid "Admin documentation"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:274
|
||||
msgid "Leave empty if there is no official admin doc"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:281
|
||||
msgid "Usage documentation"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:282
|
||||
msgid "Leave empty if there is no official user doc"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:289
|
||||
msgid "Code repository"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:300
|
||||
msgid ""
|
||||
"Ask the URL where the app will be installed ('domain' and 'path' "
|
||||
"variables)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:305
|
||||
msgid "Ask domain+path"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:308
|
||||
msgid ""
|
||||
"Ask only the domain (the app requires to be installed at the root of a "
|
||||
"dedicated domain)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:312
|
||||
msgid "Do not ask (it isn't a webapp)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:317
|
||||
msgid "Ask who can access to the app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:318
|
||||
msgid ""
|
||||
"In the users groups : by default at least 'visitors', 'all_users' et "
|
||||
"'admins' exists. (It was previously the private/public app concept)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:325
|
||||
msgid "Ask who can access to the admin interface"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:326
|
||||
msgid "In the case where the app has an admin interface"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:331
|
||||
msgid "Supported languages"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:333
|
||||
msgid "None / not relevant"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:336
|
||||
msgid "Spanish"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:337
|
||||
msgid "Italian"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:338
|
||||
msgid "German"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:339
|
||||
msgid "Chinese"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:340
|
||||
msgid "Japanese"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:341
|
||||
msgid "Danish"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:342
|
||||
msgid "Portugese"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:343
|
||||
msgid "Dutch"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:344
|
||||
msgid "Russian"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:356
|
||||
msgid "Application source code or executable"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:363
|
||||
msgid "Sources sha256 checksum"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:371
|
||||
msgid "Enable automatic update of sources (using a bot running every night)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:372
|
||||
msgid ""
|
||||
"If the upstream software is hosted in one of the handled sources and "
|
||||
"publishes proper releases or tags, the bot will create a pull request to "
|
||||
"update the sources URL and checksum"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:394
|
||||
msgid "Dependencies to be installed via apt (separated by comma and/or spaces)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:403
|
||||
msgid "Initialize an SQL database"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:413
|
||||
msgid "Initialize a system user for this app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:418
|
||||
msgid "Initialize an installation folder for this app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:419
|
||||
msgid "By default it's /var/www/$app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:424
|
||||
msgid "Initialize a folder to store the app data"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:425
|
||||
msgid "By default it's /var/yunohost.app/$app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:433
|
||||
msgid "App main technology"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:435
|
||||
msgid "None / Static application"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:440
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:447
|
||||
msgid "Installation specific commands"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:448
|
||||
msgid ""
|
||||
"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"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:460
|
||||
msgid "Use composer"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:461
|
||||
msgid "Composer is a PHP dependencies manager used by some apps"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:472
|
||||
msgid "NodeJS version"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:473
|
||||
msgid "For example: 16.4, 18, 18.2, 20, 20.1, ..."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:480
|
||||
msgid "Install and use Yarn"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:487
|
||||
msgid "Command to start the app daemon (from systemd service)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:488
|
||||
msgid ""
|
||||
"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"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:500
|
||||
msgid "The app uses a specific configuration file"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:501
|
||||
msgid "Usually : .env, config.json, conf.ini, params.yml, ..."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:508
|
||||
msgid "Name or file path to use"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:516
|
||||
msgid "App configuration file pattern"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:517
|
||||
msgid ""
|
||||
"In this pattern, you can use the syntax __FOO_BAR__ which will "
|
||||
"automatically replaced by the value of the variable $foo_bar"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:529
|
||||
msgid ""
|
||||
"doc/DESCRIPTION.md: A comprehensive presentation of the app, possibly "
|
||||
"listing the main features, possible warnings and specific details on its "
|
||||
"functioning in Yunohost (e.g. warning about integration issues)."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:539
|
||||
msgid ""
|
||||
"doc/PRE_INSTALL.md: important info to be shown to the admin before "
|
||||
"installing the app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:540 app.py:548 app.py:556 app.py:564 app.py:572
|
||||
msgid "Leave empty if not relevant"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:547
|
||||
msgid ""
|
||||
"doc/POST_INSTALL.md: important info to be shown to the admin after "
|
||||
"installing the app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:555
|
||||
msgid ""
|
||||
"doc/PRE_UPGRADE.md: important info to be shown to the admin before "
|
||||
"upgrading the app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:563
|
||||
msgid ""
|
||||
"doc/POST_UPGRADE.md: important info to be shown to the admin after "
|
||||
"upgrading the app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:571
|
||||
msgid "doc/ADMIN.md: general tips on how to administrate this app"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:583
|
||||
msgid "Handle app install URL change (change_url script)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:586
|
||||
msgid "Should changing the app URL be allowed ? (change_url change)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:593
|
||||
msgid "Use logrotate for the app logs"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:596
|
||||
msgid ""
|
||||
"If the app generates logs, this option permit to handle their archival. "
|
||||
"Recommended."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:604
|
||||
msgid "Protect the application against brute force attacks (via fail2ban)"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:609
|
||||
msgid ""
|
||||
"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."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:615
|
||||
msgid "Add a CRON task for this application"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:616
|
||||
msgid "Corresponds to some app periodic operations"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:620
|
||||
msgid "Type the CRON file content"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:629
|
||||
msgid "Regular expression for fail2ban"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:633
|
||||
msgid "A regular expression"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:635
|
||||
msgid ""
|
||||
"Regular expression to check in the log file to activate failban (search "
|
||||
"for a line that indicates a credentials error)."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:659
|
||||
msgid "Generator mode"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:660
|
||||
msgid ""
|
||||
"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."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:664
|
||||
msgid "Streamlined version"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:665
|
||||
msgid "Tutorial version"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:671
|
||||
msgid "Previsualise"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:672
|
||||
msgid "Download the .zip"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:674
|
||||
msgid "Fill with demo values"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:677
|
||||
msgid ""
|
||||
"Generate a complete and functionnal minimalistic app that you can iterate"
|
||||
" from"
|
||||
msgstr ""
|
||||
|
||||
#: templates/base.html:5
|
||||
msgid "YunoHost app generator"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:28
|
||||
msgid "Yunohost application generation form"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:55
|
||||
msgid "1/9 - General information"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:70
|
||||
msgid "2/9 - Upstream information"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:73
|
||||
msgid ""
|
||||
"The word 'upstream' refers to the original project that develops and "
|
||||
"maintains the app"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:88
|
||||
msgid "3/9 - Integration in YunoHost"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:104
|
||||
msgid "4/9 - Questions to ask during installation"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:108
|
||||
msgid "This part is meant to indicate the questions that will be asked."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:110
|
||||
msgid ""
|
||||
"NB: only standard questions are asked here, it might be required to "
|
||||
"complete it by hand using other questions as a guide."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:124
|
||||
msgid "5/9 - Resources to initialize"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:128
|
||||
msgid ""
|
||||
"Technical elements configured before launching the 'real' app install "
|
||||
"script. Usually : creating a system user, downloading app sources, "
|
||||
"initialiser le dossier d'install et de données, install apt dependencies,"
|
||||
" create a database, ..."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:151
|
||||
msgid "6/9 - Specific technology"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:156
|
||||
msgid ""
|
||||
"You probably want to make sure to have 'phpX.Y-fpm' and others "
|
||||
"'phpX.Y-foobar' libraries listed the apt dependencies earlier (with X.Y "
|
||||
"being the php version you want to use)"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:157
|
||||
msgid ""
|
||||
"The generated application draft will include an nginx configuration "
|
||||
"snippet that interfaces with PHP-FPM"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:165
|
||||
msgid ""
|
||||
"You probably want to make sure to have 'python3' and 'python3-venv' "
|
||||
"listed in the apt dependencies earlier. Other dependencies should be "
|
||||
"installed inside a venv (cf the proposed install snippet)"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:169
|
||||
msgid ""
|
||||
"The generated application draft will include an nginx configuration "
|
||||
"snippet that reverse-proxies to a systemd service using an internal port"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:237
|
||||
msgid "7/9 - App configuration"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:261
|
||||
msgid "8/9 - General and advanced documentation"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:275
|
||||
msgid "9/9 - Advanced options"
|
||||
msgstr ""
|
||||
|
||||
#~ msgid "Maintener of the generated app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Commonly you put your name here... If you agree with it ;)"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "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"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "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)"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Activate the automated source update bot"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "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"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Dependances to be installed via apt "
|
||||
#~ "(separated by a quote and/or spaces)"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Initialise a SQL database"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Initialise a system user for this app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Initialise an installation folder for this app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Initialise a folder to store the app data"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "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"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Type the DISCLAIMER.md file content, "
|
||||
#~ "which list warnings and attention "
|
||||
#~ "points."
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Type the PRE_INSTALL.md file content"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Type the POST_INSTALL.md file content"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Type the PRE_UPGRADE.md file content"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Type the POST_UPGRADE.md file content"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Type the ADMIN.md file content"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "2/9 - Informations about the application"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "The word upstream refers to the original project that maintains the app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "5/9 - Ressources to initialise"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "A more complete presentation that the"
|
||||
#~ " summary completed above, explaining to "
|
||||
#~ "what correspond the software, the "
|
||||
#~ "eventual warnings and specific details "
|
||||
#~ "on its functioning in Yunohost (it's "
|
||||
#~ "the place where one can warn about"
|
||||
#~ " integration issues)."
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Indications to show at key steps "
|
||||
#~ "to manage the package : installation,"
|
||||
#~ " update, message to the admin "
|
||||
#~ "account. You usually don't have to "
|
||||
#~ "fill them."
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Description courte (fr)"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Français"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "doc/DESCRIPTION.md : A comprehensive "
|
||||
#~ "presentation of the app, possibly "
|
||||
#~ "listing the main features, possible "
|
||||
#~ "warnings and specific details on its "
|
||||
#~ "functioning in Yunohost (e.g. warning "
|
||||
#~ "about integration issues)."
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "doc/PRE_INSTALL.md : important info to "
|
||||
#~ "be shown to the admin before "
|
||||
#~ "installing the app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "doc/POST_INSTALL.md : important info to "
|
||||
#~ "be shown to the admin after "
|
||||
#~ "installing the app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "doc/PRE_UPGRADE.md : important info to "
|
||||
#~ "be shown to the admin before "
|
||||
#~ "upgrading the app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid ""
|
||||
#~ "doc/POST_UPGRADE.md : important info to "
|
||||
#~ "be shown to the admin after "
|
||||
#~ "upgrading the app"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "doc/ADMIN.md : general tips on how to administrate this app"
|
||||
#~ msgstr ""
|
||||
|
BIN
tools/app_generator/translations/fr/LC_MESSAGES/messages.mo
Normal file
BIN
tools/app_generator/translations/fr/LC_MESSAGES/messages.mo
Normal file
Binary file not shown.
699
tools/app_generator/translations/fr/LC_MESSAGES/messages.po
Normal file
699
tools/app_generator/translations/fr/LC_MESSAGES/messages.po
Normal file
|
@ -0,0 +1,699 @@
|
|||
# French translations for PROJECT.
|
||||
# Copyright (C) 2024 ORGANIZATION
|
||||
# This file is distributed under the same license as the PROJECT project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-04-26 15:39+0200\n"
|
||||
"PO-Revision-Date: 2024-03-31 20:23+0200\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: fr\n"
|
||||
"Language-Team: fr <LL@li.org>\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.14.0\n"
|
||||
|
||||
#: app.py:68 app.py:334
|
||||
msgid "English"
|
||||
msgstr "Anglais"
|
||||
|
||||
#: app.py:68 app.py:335
|
||||
msgid "French"
|
||||
msgstr "Français"
|
||||
|
||||
#: app.py:127
|
||||
msgid "Select language"
|
||||
msgstr "Langues supportées"
|
||||
|
||||
#: app.py:137
|
||||
msgid "Application identifier (id)"
|
||||
msgstr "Identifiant (id) de l'application"
|
||||
|
||||
#: app.py:138
|
||||
msgid "Small caps and without spaces"
|
||||
msgstr "En minuscule et sans espace"
|
||||
|
||||
#: app.py:146
|
||||
msgid "App name"
|
||||
msgstr "Nom de l'application"
|
||||
|
||||
#: app.py:147
|
||||
msgid "It's the application name, displayed in the user interface"
|
||||
msgstr ""
|
||||
"Il s'agit du nom l'application, affiché dans les interfaces "
|
||||
"utilisateur·ice·s"
|
||||
|
||||
#: app.py:157
|
||||
msgid "Short description (en)"
|
||||
msgstr "Description courte (en)"
|
||||
|
||||
#: app.py:158 app.py:165
|
||||
msgid ""
|
||||
"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"
|
||||
msgstr ""
|
||||
"Expliquez en *quelques* (10~15) mots l'utilité de l'app ou ce qu'elle "
|
||||
"fait (l'objectif est de donner une idée grossière pour des utilisateurs "
|
||||
"qui naviguent dans un catalogue de 100+ apps)"
|
||||
|
||||
#: app.py:164
|
||||
msgid "Short description (fr)"
|
||||
msgstr "Description courte (fr)"
|
||||
|
||||
#: app.py:176
|
||||
msgid "Version"
|
||||
msgstr "Version"
|
||||
|
||||
#: app.py:182
|
||||
msgid "Maintainer of the generated app"
|
||||
msgstr "Mainteneur·euse de l'app YunoHost créée"
|
||||
|
||||
#: app.py:183
|
||||
msgid "Usually you put your name here... If you're okay with it ;)"
|
||||
msgstr "Généralement vous mettez votre nom ici… Si vous êtes d'accord ;)"
|
||||
|
||||
#: app.py:189
|
||||
msgid "Minimal YunoHost version"
|
||||
msgstr "Version YunoHost minimale"
|
||||
|
||||
#: app.py:190
|
||||
msgid "Minimal YunoHost version for the application to work"
|
||||
msgstr "Version minimale de Yunohost pour que l'application fonctionne."
|
||||
|
||||
#: app.py:199
|
||||
msgid "Supported architectures"
|
||||
msgstr "Architectures supportées"
|
||||
|
||||
#: app.py:201
|
||||
msgid "All architectures"
|
||||
msgstr "Toutes les architectures"
|
||||
|
||||
#: app.py:212
|
||||
msgid ""
|
||||
"The app can be installed multiple times at the same time on the same "
|
||||
"server"
|
||||
msgstr ""
|
||||
"L'app pourra être installée simultanément plusieurs fois sur la même "
|
||||
"machine"
|
||||
|
||||
#: app.py:219
|
||||
msgid "The app will be integrating LDAP"
|
||||
msgstr "L'app s'intègrera avec le LDAP"
|
||||
|
||||
#: app.py:220
|
||||
msgid ""
|
||||
"Which means it's possible to use Yunohost credentials to log into this "
|
||||
"app. 'LDAP' corresponds to the technology used by Yunohost to handle a "
|
||||
"centralised user base. Bridging the app and Yunohost's LDAP often "
|
||||
"requires to add the proper technical details in the app's configuration "
|
||||
"file"
|
||||
msgstr ""
|
||||
"C'est-à-dire pouvoir se connecter en utilisant ses identifiants YunoHost."
|
||||
" 'LDAP' corresponds à la technologie utilisée par YunoHost comme base de "
|
||||
"compte utilisateurs centralisée. L'interface entre l'app et le LDAP de "
|
||||
"YunoHost nécessite le plus souvent de remplir des paramètres dans la "
|
||||
"configuration de l'app"
|
||||
|
||||
#: app.py:224 app.py:238
|
||||
msgid "No"
|
||||
msgstr "Non"
|
||||
|
||||
#: app.py:225 app.py:237
|
||||
msgid "Yes"
|
||||
msgstr "Oui"
|
||||
|
||||
#: app.py:226 app.py:239
|
||||
msgid "Not relevant"
|
||||
msgstr "Non pertinent"
|
||||
|
||||
#: app.py:232
|
||||
msgid "The app will be integrated in Yunohost SSO (Single Sign On)"
|
||||
msgstr "L'app s'intègrera avec le SSO (Single Sign On) de YunoHost"
|
||||
|
||||
#: app.py:233
|
||||
msgid ""
|
||||
"Which means that people will be logged in the app after logging in "
|
||||
"YunoHost's portal, without having to sign on specifically into this app."
|
||||
msgstr ""
|
||||
"Ce qui signifie que les personnes seront logguées dans l'app après s'être"
|
||||
" connectées au portail YunoHost, sans avoir à se connecter spécifiquement"
|
||||
" dans"
|
||||
|
||||
#: app.py:249
|
||||
msgid "Licence"
|
||||
msgstr "License"
|
||||
|
||||
#: app.py:250
|
||||
msgid ""
|
||||
"You should check this on the upstream repository. The expected format is "
|
||||
"a SPDX id listed in https://spdx.org/licenses/"
|
||||
msgstr ""
|
||||
"Vous devriez chercher cela dans le dépôt du logiciel. Le format attendu "
|
||||
"est un identifiant SPDX listé dans https://spdx.org/licenses/"
|
||||
|
||||
#: app.py:257
|
||||
msgid "Official website"
|
||||
msgstr "Site web officiel"
|
||||
|
||||
#: app.py:258
|
||||
msgid "Leave empty if there is no official website"
|
||||
msgstr "Laisser vide s'il n'y a pas de site officiel"
|
||||
|
||||
#: app.py:265
|
||||
msgid "Official app demo"
|
||||
msgstr "Démo officielle de l'app"
|
||||
|
||||
#: app.py:266
|
||||
msgid "Leave empty if there is no official demo"
|
||||
msgstr "Laisser vide s'il n'y a pas de démo officielle"
|
||||
|
||||
#: app.py:273
|
||||
msgid "Admin documentation"
|
||||
msgstr "Documentation d'administration"
|
||||
|
||||
#: app.py:274
|
||||
msgid "Leave empty if there is no official admin doc"
|
||||
msgstr "Laisser vide s'il n'y a pas de documentation d'administration officielle"
|
||||
|
||||
#: app.py:281
|
||||
msgid "Usage documentation"
|
||||
msgstr "Documentation d'utilisation"
|
||||
|
||||
#: app.py:282
|
||||
msgid "Leave empty if there is no official user doc"
|
||||
msgstr "Laisser vide s'il n'y a pas de documentation d'utilisation officielle"
|
||||
|
||||
#: app.py:289
|
||||
msgid "Code repository"
|
||||
msgstr "Dépôt de code"
|
||||
|
||||
#: app.py:300
|
||||
msgid ""
|
||||
"Ask the URL where the app will be installed ('domain' and 'path' "
|
||||
"variables)"
|
||||
msgstr ""
|
||||
"Demander l'URL sur laquelle sera installée l'app (variables 'domain' et "
|
||||
"'path')"
|
||||
|
||||
#: app.py:305
|
||||
msgid "Ask domain+path"
|
||||
msgstr "Demander le domaine+chemin"
|
||||
|
||||
#: app.py:308
|
||||
msgid ""
|
||||
"Ask only the domain (the app requires to be installed at the root of a "
|
||||
"dedicated domain)"
|
||||
msgstr ""
|
||||
"Demander le domaine uniquement (l'app nécessite d'être installée à la "
|
||||
"racine d'un domaine dédié à cette app)"
|
||||
|
||||
#: app.py:312
|
||||
msgid "Do not ask (it isn't a webapp)"
|
||||
msgstr "Ne pas demander (l'app n'est pas une webapp)"
|
||||
|
||||
#: app.py:317
|
||||
msgid "Ask who can access to the app"
|
||||
msgstr "Demander qui pourra accéder à l'app"
|
||||
|
||||
#: app.py:318
|
||||
msgid ""
|
||||
"In the users groups : by default at least 'visitors', 'all_users' et "
|
||||
"'admins' exists. (It was previously the private/public app concept)"
|
||||
msgstr ""
|
||||
"Parmis les groupes d'utilisateurs : par défaut au moins 'visitors', "
|
||||
"'all_users' et 'admins' existent. (Corresponds anciennement à la notion "
|
||||
"d'app privée/publique)"
|
||||
|
||||
#: app.py:325
|
||||
msgid "Ask who can access to the admin interface"
|
||||
msgstr "Demander qui pourra accéder à l'interface d'admin"
|
||||
|
||||
#: app.py:326
|
||||
msgid "In the case where the app has an admin interface"
|
||||
msgstr "Ceci suppose a priori que l'app dispose d'une interface d'admin"
|
||||
|
||||
#: app.py:331
|
||||
msgid "Supported languages"
|
||||
msgstr "Langues supportées"
|
||||
|
||||
#: app.py:333
|
||||
msgid "None / not relevant"
|
||||
msgstr "Aucune / non pertinent"
|
||||
|
||||
#: app.py:336
|
||||
msgid "Spanish"
|
||||
msgstr "Espagnol"
|
||||
|
||||
#: app.py:337
|
||||
msgid "Italian"
|
||||
msgstr "Italien"
|
||||
|
||||
#: app.py:338
|
||||
msgid "German"
|
||||
msgstr "Allemand"
|
||||
|
||||
#: app.py:339
|
||||
msgid "Chinese"
|
||||
msgstr "Chinois"
|
||||
|
||||
#: app.py:340
|
||||
msgid "Japanese"
|
||||
msgstr "Japonais"
|
||||
|
||||
#: app.py:341
|
||||
msgid "Danish"
|
||||
msgstr "Danois"
|
||||
|
||||
#: app.py:342
|
||||
msgid "Portugese"
|
||||
msgstr "Portugais"
|
||||
|
||||
#: app.py:343
|
||||
msgid "Dutch"
|
||||
msgstr "Néerlandais"
|
||||
|
||||
#: app.py:344
|
||||
msgid "Russian"
|
||||
msgstr "Russe"
|
||||
|
||||
#: app.py:356
|
||||
msgid "Application source code or executable"
|
||||
msgstr "Code source ou exécutable de l'application"
|
||||
|
||||
#: app.py:363
|
||||
msgid "Sources sha256 checksum"
|
||||
msgstr "Empreinte sha256 des sources"
|
||||
|
||||
#: app.py:371
|
||||
msgid "Enable automatic update of sources (using a bot running every night)"
|
||||
msgstr ""
|
||||
"Activer le robot de mise à jour automatique des sources (via un robot "
|
||||
"chaque nuit)"
|
||||
|
||||
#: app.py:372
|
||||
msgid ""
|
||||
"If the upstream software is hosted in one of the handled sources and "
|
||||
"publishes proper releases or tags, the bot will create a pull request to "
|
||||
"update the sources URL and checksum"
|
||||
msgstr ""
|
||||
"Si le logiciel est disponible sur une des sources prises en charge et "
|
||||
"publie des releases ou des tags pour ses nouvelles versions, un robot "
|
||||
"proposera automatiquement des mises à jour de l'URL et de la checksum."
|
||||
|
||||
#: app.py:394
|
||||
msgid "Dependencies to be installed via apt (separated by comma and/or spaces)"
|
||||
msgstr "Dépendances à installer via apt (séparées par des virgules et/ou espaces)"
|
||||
|
||||
#: app.py:403
|
||||
msgid "Initialize an SQL database"
|
||||
msgstr "Initialiser une base de données SQL"
|
||||
|
||||
#: app.py:413
|
||||
msgid "Initialize a system user for this app"
|
||||
msgstr "Initialiser un utilisateur système pour cet app"
|
||||
|
||||
#: app.py:418
|
||||
msgid "Initialize an installation folder for this app"
|
||||
msgstr "Initialiser un dossier d'installation de l'app"
|
||||
|
||||
#: app.py:419
|
||||
msgid "By default it's /var/www/$app"
|
||||
msgstr "Par défaut il s'agit de /var/www/$app"
|
||||
|
||||
#: app.py:424
|
||||
msgid "Initialize a folder to store the app data"
|
||||
msgstr "Initialiser un dossier destiné à stocker les données de l'app"
|
||||
|
||||
#: app.py:425
|
||||
msgid "By default it's /var/yunohost.app/$app"
|
||||
msgstr "Par défaut il s'agit de /home/yunohost.app/$app"
|
||||
|
||||
#: app.py:433
|
||||
msgid "App main technology"
|
||||
msgstr "Technologie principale de l'app"
|
||||
|
||||
#: app.py:435
|
||||
msgid "None / Static application"
|
||||
msgstr "Aucune / application statique"
|
||||
|
||||
#: app.py:440
|
||||
msgid "Other"
|
||||
msgstr "Autre"
|
||||
|
||||
#: app.py:447
|
||||
msgid "Installation specific commands"
|
||||
msgstr "Commandes spécifiques d'installation"
|
||||
|
||||
#: app.py:448
|
||||
msgid ""
|
||||
"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"
|
||||
msgstr ""
|
||||
"Ces commandes seront éxécutées depuis le répertoire d'installation de "
|
||||
"l'app (par défaut, /var/www/$app) après que les sources aient été "
|
||||
"déployées. Le champ est pré-rempli avec un exemple classique basé sur la "
|
||||
"technologie sélectionnée. Vous devriez sans-doute le comparer et "
|
||||
"l'adapter en fonction de la documentation d'installation de l'app."
|
||||
|
||||
#: app.py:460
|
||||
msgid "Use composer"
|
||||
msgstr "Utiliser composer"
|
||||
|
||||
#: app.py:461
|
||||
msgid "Composer is a PHP dependencies manager used by some apps"
|
||||
msgstr "Composer est un gestionnaire de dépendance PHP utilisé par certaines apps"
|
||||
|
||||
#: app.py:472
|
||||
msgid "NodeJS version"
|
||||
msgstr "Version de NodeJS"
|
||||
|
||||
#: app.py:473
|
||||
msgid "For example: 16.4, 18, 18.2, 20, 20.1, ..."
|
||||
msgstr "Par exemple: 16.4, 18, 18.2, 20, 20.1, ..."
|
||||
|
||||
#: app.py:480
|
||||
msgid "Install and use Yarn"
|
||||
msgstr "Installer et utiliser Yarn"
|
||||
|
||||
#: app.py:487
|
||||
msgid "Command to start the app daemon (from systemd service)"
|
||||
msgstr "Commande pour lancer le daemon de l'app (depuis le service systemd)"
|
||||
|
||||
#: app.py:488
|
||||
msgid ""
|
||||
"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"
|
||||
msgstr ""
|
||||
"Correspond à l'intruction 'ExecStart' dans systemd. Vous pouvez utiliser "
|
||||
"'__INSTALL_DIR__' pour faire référence directory, our '__APP__' pour "
|
||||
"l'identifiant de l'application"
|
||||
|
||||
#: app.py:500
|
||||
msgid "The app uses a specific configuration file"
|
||||
msgstr "L'app utilise un fichier de configuration spécifique"
|
||||
|
||||
#: app.py:501
|
||||
msgid "Usually : .env, config.json, conf.ini, params.yml, ..."
|
||||
msgstr "Typiquement : .env, config.json, conf.ini, params.yml, ..."
|
||||
|
||||
#: app.py:508
|
||||
msgid "Name or file path to use"
|
||||
msgstr "Nom ou chemin du fichier à utiliser"
|
||||
|
||||
#: app.py:516
|
||||
msgid "App configuration file pattern"
|
||||
msgstr "Modèle de fichier de configuration de l'app"
|
||||
|
||||
#: app.py:517
|
||||
msgid ""
|
||||
"In this pattern, you can use the syntax __FOO_BAR__ which will "
|
||||
"automatically replaced by the value of the variable $foo_bar"
|
||||
msgstr ""
|
||||
"Dans ce modèle, vous pouvez utilisez la syntaxe __FOO_BAR__ qui sera "
|
||||
"automatiquement remplacé par la valeur de la variable $foo_bar"
|
||||
|
||||
#: app.py:529
|
||||
msgid ""
|
||||
"doc/DESCRIPTION.md: A comprehensive presentation of the app, possibly "
|
||||
"listing the main features, possible warnings and specific details on its "
|
||||
"functioning in Yunohost (e.g. warning about integration issues)."
|
||||
msgstr ""
|
||||
"doc/DESCRIPTION.md : Une présentation plus complète que le résumé rempli "
|
||||
"plus haut de ce à quoi correspond le logiciel, et les avertissements et "
|
||||
"précisions éventuelles sur son fonctionnement dans Yunohost (c'est "
|
||||
"l'endroit où l'on signale des problèmes d'intégrations)."
|
||||
|
||||
#: app.py:539
|
||||
msgid ""
|
||||
"doc/PRE_INSTALL.md: important info to be shown to the admin before "
|
||||
"installing the app"
|
||||
msgstr ""
|
||||
"doc/PRE_INSTALL.md : info importantes à montrer aux admins avant "
|
||||
"l'installation de l'app"
|
||||
|
||||
#: app.py:540 app.py:548 app.py:556 app.py:564 app.py:572
|
||||
msgid "Leave empty if not relevant"
|
||||
msgstr "Laisser vide si pas pertinent"
|
||||
|
||||
#: app.py:547
|
||||
msgid ""
|
||||
"doc/POST_INSTALL.md: important info to be shown to the admin after "
|
||||
"installing the app"
|
||||
msgstr ""
|
||||
"doc/POST_INSTALL.md : infos importantes à montrer aux admins après "
|
||||
"l'installation de l'app"
|
||||
|
||||
#: app.py:555
|
||||
msgid ""
|
||||
"doc/PRE_UPGRADE.md: important info to be shown to the admin before "
|
||||
"upgrading the app"
|
||||
msgstr ""
|
||||
"doc/PRE_UPGRADE.md : infos importantes à montrer aux admins avant la mise"
|
||||
" à jour de l'app"
|
||||
|
||||
#: app.py:563
|
||||
msgid ""
|
||||
"doc/POST_UPGRADE.md: important info to be shown to the admin after "
|
||||
"upgrading the app"
|
||||
msgstr ""
|
||||
"doc/POST_UPGRADE.md : infos importantes à montrer aux admins après la "
|
||||
"mise à jour de l'app"
|
||||
|
||||
#: app.py:571
|
||||
msgid "doc/ADMIN.md: general tips on how to administrate this app"
|
||||
msgstr "doc/ADMIN.md : indications générales pour administrer l'app"
|
||||
|
||||
#: app.py:583
|
||||
msgid "Handle app install URL change (change_url script)"
|
||||
msgstr "Gérer le changement d'URL d'installation (script change_url)"
|
||||
|
||||
#: app.py:586
|
||||
msgid "Should changing the app URL be allowed ? (change_url change)"
|
||||
msgstr ""
|
||||
"Faut-il permettre le changement d'URL pour l'application ? (fichier "
|
||||
"change_url)"
|
||||
|
||||
#: app.py:593
|
||||
msgid "Use logrotate for the app logs"
|
||||
msgstr "Utiliser logrotate pour les journaux de l'app"
|
||||
|
||||
#: app.py:596
|
||||
msgid ""
|
||||
"If the app generates logs, this option permit to handle their archival. "
|
||||
"Recommended."
|
||||
msgstr ""
|
||||
"Si l'application genère des journaux (log), cette option permet d'en "
|
||||
"gérer l'archivage. Recommandé."
|
||||
|
||||
#: app.py:604
|
||||
msgid "Protect the application against brute force attacks (via fail2ban)"
|
||||
msgstr "Protéger l'application des attaques par force brute (via fail2ban)"
|
||||
|
||||
#: app.py:609
|
||||
msgid ""
|
||||
"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."
|
||||
msgstr ""
|
||||
"Si l'application genère des journaux (log) d'erreurs de connexion, cette "
|
||||
"option permet de bannir automatiquement les IP au bout d'un certain "
|
||||
"nombre d'essais de mot de passe. Recommandé."
|
||||
|
||||
#: app.py:615
|
||||
msgid "Add a CRON task for this application"
|
||||
msgstr "Ajouter une tâche CRON pour cette application"
|
||||
|
||||
#: app.py:616
|
||||
msgid "Corresponds to some app periodic operations"
|
||||
msgstr "Corresponds à des opérations périodiques de l'application"
|
||||
|
||||
#: app.py:620
|
||||
msgid "Type the CRON file content"
|
||||
msgstr "Saisissez le contenu du fichier CRON"
|
||||
|
||||
#: app.py:629
|
||||
msgid "Regular expression for fail2ban"
|
||||
msgstr "Expression régulière pour fail2ban"
|
||||
|
||||
#: app.py:633
|
||||
msgid "A regular expression"
|
||||
msgstr "Une expression régulière"
|
||||
|
||||
#: app.py:635
|
||||
msgid ""
|
||||
"Regular expression to check in the log file to activate failban (search "
|
||||
"for a line that indicates a credentials error)."
|
||||
msgstr ""
|
||||
"Expression régulière à vérifier dans le journal pour que fail2ban "
|
||||
"s'active (cherchez une ligne qui indique une erreur d'identifiants de "
|
||||
"connexion)."
|
||||
|
||||
#: app.py:659
|
||||
msgid "Generator mode"
|
||||
msgstr "Mode du générateur"
|
||||
|
||||
#: app.py:660
|
||||
msgid ""
|
||||
"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."
|
||||
msgstr ""
|
||||
"En mode tutoriel, l'application générée contiendra des commentaires "
|
||||
"additionnels pour faciliter la compréhension. En version épurée, "
|
||||
"l'application générée ne contiendra que le minimum nécessaire."
|
||||
|
||||
#: app.py:664
|
||||
msgid "Streamlined version"
|
||||
msgstr "Version épurée"
|
||||
|
||||
#: app.py:665
|
||||
msgid "Tutorial version"
|
||||
msgstr "Version tutoriel"
|
||||
|
||||
#: app.py:671
|
||||
msgid "Previsualise"
|
||||
msgstr "Prévisualiser"
|
||||
|
||||
#: app.py:672
|
||||
msgid "Download the .zip"
|
||||
msgstr "Télécharger le .zip"
|
||||
|
||||
#: app.py:674
|
||||
msgid "Fill with demo values"
|
||||
msgstr "Remplir avec des valeurs de démonstration"
|
||||
|
||||
#: app.py:677
|
||||
msgid ""
|
||||
"Generate a complete and functionnal minimalistic app that you can iterate"
|
||||
" from"
|
||||
msgstr ""
|
||||
"Générer une application minimaliste complète et fonctionnelle à partir de"
|
||||
" laquelle itérer"
|
||||
|
||||
#: templates/base.html:5
|
||||
msgid "YunoHost app generator"
|
||||
msgstr "Générateur d'app YunoHost"
|
||||
|
||||
#: templates/index.html:28
|
||||
msgid "Yunohost application generation form"
|
||||
msgstr "Formulaire de génération d'une application Yunohost"
|
||||
|
||||
#: templates/index.html:55
|
||||
msgid "1/9 - General information"
|
||||
msgstr "1/9 - Informations générales"
|
||||
|
||||
#: templates/index.html:70
|
||||
msgid "2/9 - Upstream information"
|
||||
msgstr "2/9 - Informations sur l'upstream"
|
||||
|
||||
#: templates/index.html:73
|
||||
msgid ""
|
||||
"The word 'upstream' refers to the original project that develops and "
|
||||
"maintains the app"
|
||||
msgstr ""
|
||||
"Le terme 'upstream' désigne le projet original qui développe et maintient"
|
||||
" l'app"
|
||||
|
||||
#: templates/index.html:88
|
||||
msgid "3/9 - Integration in YunoHost"
|
||||
msgstr "3/9 - Intégration dans YunoHost"
|
||||
|
||||
#: templates/index.html:104
|
||||
msgid "4/9 - Questions to ask during installation"
|
||||
msgstr "4/9 - Questions à poser pendant l'installation"
|
||||
|
||||
#: templates/index.html:108
|
||||
msgid "This part is meant to indicate the questions that will be asked."
|
||||
msgstr "Cette partie sert à indiquer les questions qui devront être posées."
|
||||
|
||||
#: templates/index.html:110
|
||||
msgid ""
|
||||
"NB: only standard questions are asked here, it might be required to "
|
||||
"complete it by hand using other questions as a guide."
|
||||
msgstr ""
|
||||
"NB: seules des questions standard sont proposées ici, il faudra "
|
||||
"éventuellement compléter à la main en suivant le modèle des autres "
|
||||
"questions."
|
||||
|
||||
#: templates/index.html:124
|
||||
msgid "5/9 - Resources to initialize"
|
||||
msgstr "5/9 - Ressources à initialiser"
|
||||
|
||||
#: templates/index.html:128
|
||||
msgid ""
|
||||
"Technical elements configured before launching the 'real' app install "
|
||||
"script. Usually : creating a system user, downloading app sources, "
|
||||
"initialiser le dossier d'install et de données, install apt dependencies,"
|
||||
" create a database, ..."
|
||||
msgstr ""
|
||||
"Il s'agit d'éléments techniques configurés avant que le 'vrai' script "
|
||||
"d'install de l'app ne soit lancé. Typiquement : créer un user système, "
|
||||
"télécharger les sources de l'app, initialiser le dossier d'install et de "
|
||||
"données, installer des dépendances avec apt, créer une base de données, "
|
||||
"..."
|
||||
|
||||
#: templates/index.html:151
|
||||
msgid "6/9 - Specific technology"
|
||||
msgstr "6/9 - Technologie spécifique"
|
||||
|
||||
#: templates/index.html:156
|
||||
msgid ""
|
||||
"You probably want to make sure to have 'phpX.Y-fpm' and others "
|
||||
"'phpX.Y-foobar' libraries listed the apt dependencies earlier (with X.Y "
|
||||
"being the php version you want to use)"
|
||||
msgstr ""
|
||||
"Vous voulez probablement vous assurer d'avoir 'phpX.Y-fpm' and autres "
|
||||
"librairies 'phpX.Y-foobar' listées dans les dépendances apt (X.Y étant la"
|
||||
" version de PHP que vous voulez utiliser)"
|
||||
|
||||
#: templates/index.html:157
|
||||
msgid ""
|
||||
"The generated application draft will include an nginx configuration "
|
||||
"snippet that interfaces with PHP-FPM"
|
||||
msgstr ""
|
||||
"Le brouillon de l'application inclura une configuration nginx qui "
|
||||
"s'interface avec PHP-FPM"
|
||||
|
||||
#: templates/index.html:165
|
||||
msgid ""
|
||||
"You probably want to make sure to have 'python3' and 'python3-venv' "
|
||||
"listed in the apt dependencies earlier. Other dependencies should be "
|
||||
"installed inside a venv (cf the proposed install snippet)"
|
||||
msgstr ""
|
||||
"Vous voulez probablement vous assurer d'avoir 'python3' et 'python3-venv'"
|
||||
" listés dans les dépendances apt. Les autres dépendences devront être "
|
||||
"installées dans un venv"
|
||||
|
||||
#: templates/index.html:169
|
||||
msgid ""
|
||||
"The generated application draft will include an nginx configuration "
|
||||
"snippet that reverse-proxies to a systemd service using an internal port"
|
||||
msgstr ""
|
||||
"Le brouillon de l'application inclura une configuration nginx qui "
|
||||
"redirige vers le service systemd en utilisant un port interne"
|
||||
|
||||
#: templates/index.html:237
|
||||
msgid "7/9 - App configuration"
|
||||
msgstr "7/9 - Configuration de l'app"
|
||||
|
||||
#: templates/index.html:261
|
||||
msgid "8/9 - General and advanced documentation"
|
||||
msgstr "8/9 - Documentation générale et avancée"
|
||||
|
||||
#: templates/index.html:275
|
||||
msgid "9/9 - Advanced options"
|
||||
msgstr "9/9 - Options avancées"
|
||||
|
||||
#~ msgid "Français"
|
||||
#~ msgstr "French"
|
||||
|
|
@ -34,6 +34,10 @@ def notify(message: str, channel: str, markdown: bool = False) -> None:
|
|||
|
||||
try:
|
||||
subprocess.call(command, stdout=subprocess.DEVNULL)
|
||||
except FileNotFoundError:
|
||||
logging.warning(
|
||||
"The logging sender tool /var/www/webhooks/matrix-commander does not exist."
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
logging.warning(
|
||||
f"""Could not send a notification on {channel}.
|
||||
|
@ -48,7 +52,7 @@ class LogSenderHandler(logging.Handler):
|
|||
self.is_logging = False
|
||||
|
||||
def emit(self, record: logging.LogRecord) -> None:
|
||||
msg = f"[Apps tools error] {record.msg}"
|
||||
msg = f"[Apps tools error] {record.message}"
|
||||
notify(msg, "dev")
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -8,7 +8,6 @@ from enum import Enum
|
|||
from typing import Any, Optional, Union
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
from functools import cache
|
||||
from datetime import datetime
|
||||
|
@ -227,7 +226,8 @@ class AppAutoUpdater:
|
|||
|
||||
# Default message
|
||||
pr_title = commit_msg = "Upgrade sources"
|
||||
branch_name = "ci-auto-update-sources"
|
||||
date = datetime.now().strftime("%y%m%d")
|
||||
branch_name = f"ci-auto-update-sources-{date}"
|
||||
|
||||
for source, infos in self.sources.items():
|
||||
update = self.get_source_update(source, infos)
|
||||
|
@ -447,6 +447,7 @@ class AppAutoUpdater:
|
|||
) -> Optional[tuple[str, Union[str, dict[str, str]], str]]:
|
||||
upstream = autoupdate.get("upstream", self.main_upstream).strip("/")
|
||||
version_re = autoupdate.get("version_regex", None)
|
||||
allow_prereleases = autoupdate.get("allow_prereleases", False)
|
||||
_, remote_type, revision_type = strategy.split("_")
|
||||
|
||||
api: Union[GithubAPI, GitlabAPI, GiteaForgejoAPI]
|
||||
|
@ -462,10 +463,16 @@ class AppAutoUpdater:
|
|||
|
||||
if revision_type == "release":
|
||||
releases: dict[str, dict[str, Any]] = {
|
||||
release["tag_name"]: release
|
||||
for release in api.releases()
|
||||
if not release["draft"] and not release["prerelease"]
|
||||
release["tag_name"]: release for release in api.releases()
|
||||
}
|
||||
|
||||
if not allow_prereleases:
|
||||
releases = {
|
||||
name: info
|
||||
for name, info in releases.items()
|
||||
if not info["draft"] and not info["prerelease"]
|
||||
}
|
||||
|
||||
latest_version_orig, latest_version = self.relevant_versions(
|
||||
list(releases.keys()), self.app_id, version_re
|
||||
)
|
||||
|
@ -718,7 +725,7 @@ def main() -> None:
|
|||
|
||||
if apps_failed:
|
||||
paste_message += f"\n{'=' * 80}\nApps failed:"
|
||||
matrix_message += f"\n- {len(apps_failed)} failed apps updates: {', '.join(str(app) for app in apps_failed.keys())}"
|
||||
matrix_message += f"\n- {len(apps_failed)} failed apps updates: {', '.join(str(app) for app in apps_failed.keys())}\n"
|
||||
for app, logs in apps_failed.items():
|
||||
paste_message += f"\n{'='*40}\n{app}\n{'-'*40}\n{logs[0]}\n{logs[1]}\n\n"
|
||||
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
# Auto-README generation
|
||||
|
||||
Browses all repositories in YunoHost-Apps organization, and updates `updater.yml` with latest actions versions.
|
||||
|
||||
### Initial install
|
||||
|
||||
```
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
This script requires the following files:
|
||||
- `.github_token` containing a token with `public.repo` and `workflow` permission
|
||||
- `.github_login` containing the author's username
|
||||
- `.github_email` containing the author's email address
|
|
@ -1,139 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import urllib.request
|
||||
|
||||
import github
|
||||
from github import Github
|
||||
|
||||
# Debug
|
||||
from rich.traceback import install
|
||||
|
||||
install(width=150, show_locals=True, locals_max_length=None, locals_max_string=None)
|
||||
|
||||
#####
|
||||
#
|
||||
# CONFIG
|
||||
#
|
||||
#####
|
||||
|
||||
# API token for yunohost-bot, need public.repo permission
|
||||
g = Github(open(".github_token").read().strip())
|
||||
|
||||
# Path to the file to be updated
|
||||
path = ".github/workflows/updater.yml"
|
||||
|
||||
# Title of the PR
|
||||
title = "[autopatch] Upgrade auto-updater"
|
||||
|
||||
# Body of the PR message
|
||||
body = """
|
||||
Auto-updater actions need upgrading to continue working:
|
||||
- actions/checkout@v3
|
||||
- peter-evans/create-pull-request@v4
|
||||
"""
|
||||
|
||||
# Author of the commit
|
||||
author = github.InputGitAuthor(
|
||||
open(".github_login").read().strip(), open(".github_email").read().strip()
|
||||
)
|
||||
|
||||
# Name of the branch created for the PR
|
||||
new_branch = "upgrade-auto-updater"
|
||||
|
||||
#####
|
||||
#
|
||||
# CACHE
|
||||
#
|
||||
#####
|
||||
|
||||
with open("processed.txt") as f:
|
||||
processed = f.read().splitlines()
|
||||
|
||||
#####
|
||||
#
|
||||
# CRAWL REPOSITORIES
|
||||
#
|
||||
#####
|
||||
|
||||
u = g.get_user("yunohost-bot")
|
||||
org = g.get_organization("yunohost-apps")
|
||||
|
||||
# For each repositories belonging to the bot (user `u`)
|
||||
i = 0
|
||||
for repo in org.get_repos():
|
||||
if repo.full_name not in processed:
|
||||
|
||||
# Determine base branch, either `testing` or default branch
|
||||
try:
|
||||
base_branch = repo.get_branch("testing").name
|
||||
except:
|
||||
base_branch = repo.default_branch
|
||||
|
||||
# Make sure the repository has an auto-updater
|
||||
try:
|
||||
repo.get_contents(path, ref="refs/heads/" + base_branch)
|
||||
except:
|
||||
with open("processed.txt", "a") as pfile:
|
||||
pfile.write(repo.full_name + "\n")
|
||||
time.sleep(1.5)
|
||||
continue
|
||||
|
||||
# Process the repo
|
||||
print("Processing " + repo.full_name)
|
||||
|
||||
try:
|
||||
# Get the commit base for the new branch, and create it
|
||||
commit_sha = repo.get_branch(base_branch).commit.sha
|
||||
new_branch_ref = repo.create_git_ref(
|
||||
ref="refs/heads/" + new_branch, sha=commit_sha
|
||||
)
|
||||
except:
|
||||
new_branch_ref = repo.get_git_ref(ref="heads/" + new_branch)
|
||||
|
||||
# Get current file contents
|
||||
contents = repo.get_contents(path, ref=new_branch_ref.ref)
|
||||
|
||||
# Update the file
|
||||
updater_yml = contents.decoded_content.decode("unicode_escape")
|
||||
updater_yml = re.sub(
|
||||
r"(?m)uses: actions/checkout@v[\d]+",
|
||||
"uses: actions/checkout@v3",
|
||||
updater_yml,
|
||||
)
|
||||
updater_yml = re.sub(
|
||||
r"(?m)uses: peter-evans/create-pull-request@v[\d]+",
|
||||
"uses: peter-evans/create-pull-request@v4",
|
||||
updater_yml,
|
||||
)
|
||||
updated = repo.update_file(
|
||||
contents.path,
|
||||
message=title,
|
||||
content=updater_yml,
|
||||
sha=contents.sha,
|
||||
branch=new_branch,
|
||||
author=author,
|
||||
)
|
||||
|
||||
# Wait a bit to preserve the API rate limit
|
||||
time.sleep(1.5)
|
||||
|
||||
# Open the PR
|
||||
pr = repo.create_pull(
|
||||
title="Upgrade auto-updater", body=body, head=new_branch, base=base_branch
|
||||
)
|
||||
|
||||
print(repo.full_name + " updated with PR #" + str(pr.id))
|
||||
i = i + 1
|
||||
|
||||
# Wait a bit to preserve the API rate limit
|
||||
time.sleep(1.5)
|
||||
|
||||
with open("processed.txt", "a") as pfile:
|
||||
pfile.write(repo.full_name + "\n")
|
||||
|
||||
print("Done. " + str(i) + " repos processed")
|
|
@ -1,3 +0,0 @@
|
|||
rich
|
||||
PyGithub
|
||||
|
|
@ -65,7 +65,7 @@ def __build_app_dict(data) -> Optional[tuple[str, dict[str, Any]]]:
|
|||
try:
|
||||
return name, build_app_dict(name, info)
|
||||
except Exception as err:
|
||||
logging.error("Error while updating %s: %s", name, err)
|
||||
logging.error("[List builder] Error while updating %s: %s", name, err)
|
||||
|
||||
|
||||
def build_base_catalog(nproc: int):
|
||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-25 01:09+0100\n"
|
||||
"POT-Creation-Date: 2024-03-31 19:33+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -30,7 +30,7 @@ msgstr ""
|
|||
msgid ""
|
||||
"Copy this app before working on it, using the ['Use this "
|
||||
"template'](https://github.com/new?template_name=example_ynh&template_owner=YunoHost)"
|
||||
" button on the Github repo."
|
||||
" button on the Github repo"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:5
|
||||
|
@ -40,13 +40,13 @@ msgstr ""
|
|||
#: templates/README.md.j2:6
|
||||
msgid ""
|
||||
"Edit the `install`, `upgrade`, `remove`, `backup` and `restore` scripts, "
|
||||
"and any relevant conf files in `conf/`."
|
||||
"and any relevant conf files in `conf/`"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:7
|
||||
msgid ""
|
||||
"Using the [script helpers "
|
||||
"documentation.](https://yunohost.org/packaging_apps_helpers)"
|
||||
"documentation](https://yunohost.org/packaging_apps_helpers)"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:8
|
||||
|
@ -56,142 +56,153 @@ msgid ""
|
|||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:9
|
||||
msgid ""
|
||||
"Add a `LICENSE` file for the package. NB: this LICENSE file is not meant "
|
||||
"to necessarily be the LICENSE of the upstream app - it is only the "
|
||||
"LICENSE you want this package's code to published with ;). We recommend "
|
||||
"to use [the AGPL-3](https://www.gnu.org/licenses/agpl-3.0.txt)."
|
||||
msgid "Add a `LICENSE` file for the package."
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:10
|
||||
msgid "Edit files under the `doc/` directory"
|
||||
msgid ""
|
||||
"NB: this `LICENSE` file is not meant to necessarily be the same LICENSE "
|
||||
"as the upstream app - it is only the LICENSE you want this package's code"
|
||||
" to published with and you can choose it freely! (If you don't know which"
|
||||
" to choose, we recommend [the "
|
||||
"AGPL-3](https://www.gnu.org/licenses/agpl-3.0.txt))"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:11
|
||||
msgid ""
|
||||
"Edit files under the `doc/` directory ([see the page about documenting "
|
||||
"packages](https://yunohost.org/packaging_app_doc))"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:12
|
||||
msgid ""
|
||||
"The `README.md` files are to be automatically generated by "
|
||||
"<https://github.com/YunoHost/apps/tree/master/tools/readme_generator>"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:17
|
||||
#: templates/README.md.j2:18
|
||||
msgid ""
|
||||
"N.B.: This README was automatically generated by "
|
||||
"<https://github.com/YunoHost/apps/tree/master/tools/readme_generator>\n"
|
||||
"It shall NOT be edited by hand."
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:21
|
||||
#: templates/README.md.j2:22
|
||||
#, python-format
|
||||
msgid "%(application_name)s for YunoHost"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:23
|
||||
#: templates/README.md.j2:24
|
||||
msgid "Integration level"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:23
|
||||
#: templates/README.md.j2:24
|
||||
msgid "Working status"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:23
|
||||
#: templates/README.md.j2:24
|
||||
msgid "Maintenance status"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:25
|
||||
#: templates/README.md.j2:26
|
||||
#, python-format
|
||||
msgid "Install %(application_name)s with YunoHost"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:27
|
||||
msgid "Read this README is other languages."
|
||||
#: templates/README.md.j2:28
|
||||
msgid "Read this README in other languages."
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:29
|
||||
#: templates/README.md.j2:30
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This package allows you to install %(application_name)s quickly and "
|
||||
"simply on a YunoHost server.\n"
|
||||
"If you don't have YunoHost, please consult [the "
|
||||
"guide](https://yunohost.org/#/install) to learn how to install it."
|
||||
"simply on a YunoHost server."
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:32
|
||||
#: templates/README.md.j2:31
|
||||
msgid ""
|
||||
"If you don't have YunoHost, please consult [the "
|
||||
"guide](https://yunohost.org/install) to learn how to install it."
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:33
|
||||
msgid "Overview"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:35
|
||||
#: templates/README.md.j2:37
|
||||
msgid "Shipped version:"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:39
|
||||
#: templates/README.md.j2:41
|
||||
msgid "Demo:"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:43
|
||||
#: templates/README.md.j2:45
|
||||
msgid "Screenshots"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:46
|
||||
#: templates/README.md.j2:48
|
||||
#, python-format
|
||||
msgid "Screenshot of %(application_name)s"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:51
|
||||
#: templates/README.md.j2:53
|
||||
msgid "Disclaimers / important information"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:57
|
||||
#: templates/README.md.j2:59
|
||||
msgid "Antifeatures"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:64
|
||||
#: templates/README.md.j2:66
|
||||
msgid "Documentation and resources"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:66
|
||||
#: templates/README.md.j2:68
|
||||
msgid "Official app website:"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:68
|
||||
#: templates/README.md.j2:70
|
||||
msgid "Official user documentation:"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:70
|
||||
#: templates/README.md.j2:72
|
||||
msgid "Official admin documentation:"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:72
|
||||
#: templates/README.md.j2:74
|
||||
msgid "Upstream app code repository:"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:74
|
||||
#: templates/README.md.j2:76
|
||||
msgid "YunoHost Store:"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:75
|
||||
#: templates/README.md.j2:77
|
||||
msgid "Report a bug:"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:77
|
||||
#: templates/README.md.j2:79
|
||||
msgid "Developer info"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:79
|
||||
#: templates/README.md.j2:81
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Please send your pull request to the [testing "
|
||||
"branch](%(testing_branch_url)s)"
|
||||
"Please send your pull request to the [`testing` "
|
||||
"branch](%(testing_branch_url)s)."
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:82
|
||||
msgid "To try the testing branch, please proceed like that:"
|
||||
#: templates/README.md.j2:83
|
||||
msgid "To try the `testing` branch, please proceed like that:"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:86
|
||||
#: templates/README.md.j2:87
|
||||
msgid "or"
|
||||
msgstr ""
|
||||
|
||||
#: templates/README.md.j2:90
|
||||
#: templates/README.md.j2:91
|
||||
msgid "More info regarding app packaging:"
|
||||
msgstr ""
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue