From 529e3b8f4e3f6be4e5eae025c48476798769e691 Mon Sep 17 00:00:00 2001 From: jarod5001 <68397534+jarod5001@users.noreply.github.com> Date: Thu, 26 May 2022 23:07:12 +0100 Subject: [PATCH 01/14] Update check_process --- check_process | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/check_process b/check_process index f41c4c9..2ef2df1 100644 --- a/check_process +++ b/check_process @@ -8,10 +8,6 @@ domain="domain.tld" path="/path" is_public=1 - language="fr" - admin="john" - password="1Strong-Password" - port="666" ; Checks pkg_linter=1 setup_sub_dir=1 @@ -20,15 +16,8 @@ setup_private=1 setup_public=1 upgrade=1 - upgrade=1 from_commit=CommitHash backup_restore=1 multi_instance=1 - port_already_use=0 change_url=1 ;;; Options -Email= Notification=none -;;; Upgrade options - ; commit=CommitHash - name=Name and date of the commit. - manifest_arg=domain=DOMAIN&path=PATH&is_public=1&language=fr&admin=USER&password=pass&port=666& From 1bb9a23b0f0065fc4989db26fda4c2a5a33c41ca Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Thu, 26 May 2022 22:07:14 +0000 Subject: [PATCH 02/14] Auto-update README --- README.md | 23 ++++++++++++----------- README_fr.md | 29 +++++++++++++++++------------ 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 84b9026..080bba0 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ It shall NOT be edited by hand. # x-prober for YunoHost -[![Integration level](https://dash.yunohost.org/integration/x-prober.svg)](https://dash.yunohost.org/appci/app/x-prober) ![](https://ci-apps.yunohost.org/ci/badges/x-prober.status.svg) ![](https://ci-apps.yunohost.org/ci/badges/x-prober.maintain.svg) +[![Integration level](https://dash.yunohost.org/integration/x-prober.svg)](https://dash.yunohost.org/appci/app/x-prober) ![Working status](https://ci-apps.yunohost.org/ci/badges/x-prober.status.svg) ![Maintenance status](https://ci-apps.yunohost.org/ci/badges/x-prober.maintain.svg) [![Install x-prober with YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=x-prober) *[Lire ce readme en français.](./README_fr.md)* @@ -28,9 +28,9 @@ This is a probe program for PHP environment. It can show your server information ## Screenshots -![](./doc/screenshots/03.jpg) -![](./doc/screenshots/01.jpg) -![](./doc/screenshots/02.jpg) +![Screenshot of x-prober](./doc/screenshots/03.jpg) +![Screenshot of x-prober](./doc/screenshots/01.jpg) +![Screenshot of x-prober](./doc/screenshots/02.jpg) ## Disclaimers / important information @@ -48,21 +48,22 @@ Add network speed testing. ## Documentation and resources -* Official app website: https://prober.inn-studio.com/ -* Official user documentation: https://github.com/kmvan/x-prober -* Upstream app code repository: https://github.com/kmvan/x-prober -* YunoHost documentation for this app: https://yunohost.org/app_x-prober -* Report a bug: https://github.com/YunoHost-Apps/x-prober_ynh/issues +* Official app website: +* Official user documentation: +* Upstream app code repository: +* YunoHost documentation for this app: +* Report a bug: ## Developer info Please send your pull request to the [testing branch](https://github.com/YunoHost-Apps/x-prober_ynh/tree/testing). To try the testing branch, please proceed like that. -``` + +``` bash sudo yunohost app install https://github.com/YunoHost-Apps/x-prober_ynh/tree/testing --debug or sudo yunohost app upgrade x-prober -u https://github.com/YunoHost-Apps/x-prober_ynh/tree/testing --debug ``` -**More info regarding app packaging:** https://yunohost.org/packaging_apps \ No newline at end of file +**More info regarding app packaging:** diff --git a/README_fr.md b/README_fr.md index cd3d187..1127a47 100644 --- a/README_fr.md +++ b/README_fr.md @@ -1,10 +1,14 @@ + + # x-prober pour YunoHost -[![Niveau d'intégration](https://dash.yunohost.org/integration/x-prober.svg)](https://dash.yunohost.org/appci/app/x-prober) ![](https://ci-apps.yunohost.org/ci/badges/x-prober.status.svg) ![](https://ci-apps.yunohost.org/ci/badges/x-prober.maintain.svg) +[![Niveau d'intégration](https://dash.yunohost.org/integration/x-prober.svg)](https://dash.yunohost.org/appci/app/x-prober) ![Statut du fonctionnement](https://ci-apps.yunohost.org/ci/badges/x-prober.status.svg) ![Statut de maintenance](https://ci-apps.yunohost.org/ci/badges/x-prober.maintain.svg) [![Installer x-prober avec YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=x-prober) *[Read this readme in english.](./README.md)* -*[Lire ce readme en français.](./README_fr.md)* > *Ce package vous permet d'installer x-prober rapidement et simplement sur un serveur YunoHost. Si vous n'avez pas YunoHost, regardez [ici](https://yunohost.org/#/install) pour savoir comment l'installer et en profiter.* @@ -24,9 +28,9 @@ This is a probe program for PHP environment. It can show your server information ## Captures d'écran -![](./doc/screenshots/03.jpg) -![](./doc/screenshots/01.jpg) -![](./doc/screenshots/02.jpg) +![Capture d'écran de x-prober](./doc/screenshots/03.jpg) +![Capture d'écran de x-prober](./doc/screenshots/01.jpg) +![Capture d'écran de x-prober](./doc/screenshots/02.jpg) ## Avertissements / informations importantes @@ -44,21 +48,22 @@ Add network speed testing. ## Documentations et ressources -* Site officiel de l'app : https://prober.inn-studio.com/ -* Documentation officielle utilisateur : https://github.com/kmvan/x-prober -* Dépôt de code officiel de l'app : https://github.com/kmvan/x-prober -* Documentation YunoHost pour cette app : https://yunohost.org/app_x-prober -* Signaler un bug : https://github.com/YunoHost-Apps/x-prober_ynh/issues +* Site officiel de l'app : +* Documentation officielle utilisateur : +* Dépôt de code officiel de l'app : +* Documentation YunoHost pour cette app : +* Signaler un bug : ## Informations pour les développeurs Merci de faire vos pull request sur la [branche testing](https://github.com/YunoHost-Apps/x-prober_ynh/tree/testing). Pour essayer la branche testing, procédez comme suit. -``` + +``` bash sudo yunohost app install https://github.com/YunoHost-Apps/x-prober_ynh/tree/testing --debug ou sudo yunohost app upgrade x-prober -u https://github.com/YunoHost-Apps/x-prober_ynh/tree/testing --debug ``` -**Plus d'infos sur le packaging d'applications :** https://yunohost.org/packaging_apps \ No newline at end of file +**Plus d'infos sur le packaging d'applications :** From b60e9d5a912ec469944521412fa842e39660fbe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= <46165813+ericgaspar@users.noreply.github.com> Date: Tue, 10 Jan 2023 18:28:11 +0100 Subject: [PATCH 03/14] Fix --- conf/app.src | 4 ++-- conf/nginx.conf | 4 +--- manifest.json | 14 ++------------ scripts/_common.sh | 3 +-- 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/conf/app.src b/conf/app.src index 1b77ba9..2f58d68 100644 --- a/conf/app.src +++ b/conf/app.src @@ -1,5 +1,5 @@ -SOURCE_URL=https://github.com/kmvan/x-prober/raw/master/dist/prober.php -SOURCE_SUM=0fea147396c0c8147c509ea3d3382adb53aa88a50e81ff9f60fc7f35191ef1a0 +SOURCE_URL=https://github.com/kmvan/x-prober/releases/download/8.16/prober.php +SOURCE_SUM=06691c50cd72bf2b19ecc2169486a582334f18d7070bbe5ae8c402e87c0a6c6c SOURCE_SUM_PRG=sha256sum SOURCE_FORMAT=php SOURCE_IN_SUBDIR=false diff --git a/conf/nginx.conf b/conf/nginx.conf index c52d7e0..be1f44a 100644 --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -2,9 +2,8 @@ location __PATH__/ { # Path to source - alias __FINALPATH__/ ; + alias __FINALPATH__/; -### Example PHP configuration (remove it if not used) index prober.php; # Common parameter to increase upload size limit in conjunction with dedicated php-fpm file @@ -21,7 +20,6 @@ location __PATH__/ { fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param SCRIPT_FILENAME $request_filename; } -### End of PHP configuration part # Include SSOWAT user panel. include conf.d/yunohost_panel.conf.inc; diff --git a/manifest.json b/manifest.json index 08668f5..9f1eaa3 100644 --- a/manifest.json +++ b/manifest.json @@ -6,7 +6,7 @@ "en": "A probe program for PHP environment", "fr": "A probe program for PHP environment" }, - "version": "8.8~ynh1", + "version": "8.16~ynh1", "url": "https://prober.inn-studio.com/", "upstream": { "license": "GPL-3.0", @@ -21,7 +21,7 @@ "email": "" }, "requirements": { - "yunohost": ">= 4.3.0" + "yunohost": ">= 11.0.9" }, "multi_instance": true, "services": [ @@ -41,16 +41,6 @@ "example": "/xprober", "default": "/xprober" }, - { - "name": "phpversion", - "type": "string", - "ask": { - "en": "Choose a PHP version you want to use for your app. Yes, 8 is better", - "fr": "Choisissez une version PHP que vous souhaitez utiliser pour votre application. Oui, la 8 est meilleure" - }, - "choices" : ["7.4", "8.0"], - "default" : "8.0" - }, { "name": "is_public", "type": "boolean", diff --git a/scripts/_common.sh b/scripts/_common.sh index 836939b..b7c971c 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -3,9 +3,8 @@ #================================================= # COMMON VARIABLES #================================================= -YNH_PHP_VERSION="8.0" -# dependencies used by the app +YNH_PHP_VERSION="8.0" #================================================= # PERSONAL HELPERS From 121603caa8c690bc379def046dcbc0da4ebfb925 Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Tue, 10 Jan 2023 17:28:16 +0000 Subject: [PATCH 04/14] Auto-update README --- README.md | 2 +- README_fr.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 080bba0..64ade5b 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ This is a probe program for PHP environment. It can show your server information -**Shipped version:** 8.8~ynh1 +**Shipped version:** 8.16~ynh1 **Demo:** https://prober.inn-studio.com/ diff --git a/README_fr.md b/README_fr.md index 1127a47..3942575 100644 --- a/README_fr.md +++ b/README_fr.md @@ -22,7 +22,7 @@ This is a probe program for PHP environment. It can show your server information -**Version incluse :** 8.8~ynh1 +**Version incluse :** 8.16~ynh1 **Démo :** https://prober.inn-studio.com/ From e78f35c339814c7dc8d45db2f74e1711d5f25212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= <46165813+ericgaspar@users.noreply.github.com> Date: Tue, 10 Jan 2023 18:32:18 +0100 Subject: [PATCH 05/14] Fix --- conf/{php-fpm.conf => extra_php-fpm.conf} | 0 doc/DISCLAIMER.md | 8 +- scripts/backup | 22 ------ scripts/change_url | 23 ------ scripts/install | 91 +---------------------- scripts/remove | 51 ------------- scripts/restore | 34 +-------- scripts/upgrade | 81 -------------------- 8 files changed, 4 insertions(+), 306 deletions(-) rename conf/{php-fpm.conf => extra_php-fpm.conf} (100%) diff --git a/conf/php-fpm.conf b/conf/extra_php-fpm.conf similarity index 100% rename from conf/php-fpm.conf rename to conf/extra_php-fpm.conf diff --git a/doc/DISCLAIMER.md b/doc/DISCLAIMER.md index 01f0445..823b22d 100644 --- a/doc/DISCLAIMER.md +++ b/doc/DISCLAIMER.md @@ -1,11 +1,5 @@ This is a probe program for PHP environment. It can show your server information and readable easily. -more info here - -https://github.com/kmvan/x-prober/blob/master/README.md +more info here: https://github.com/kmvan/x-prober/blob/master/README.md Note that the app works only in public mode for now. - -To do list : -Add Email send testing. -Add network speed testing. diff --git a/scripts/backup b/scripts/backup index 56a924c..07bba6a 100755 --- a/scripts/backup +++ b/scripts/backup @@ -32,17 +32,11 @@ final_path=$(ynh_app_setting_get --app=$app --key=final_path) domain=$(ynh_app_setting_get --app=$app --key=domain) phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) - #================================================= # DECLARE DATA AND CONF FILES TO BACKUP #================================================= ynh_print_info --message="Declaring files to be backed up..." -### 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. - #================================================= # BACKUP THE APP MAIN DIR #================================================= @@ -61,10 +55,6 @@ ynh_backup --src_path="/etc/nginx/conf.d/$domain.d/$app.conf" ynh_backup --src_path="/etc/php/$phpversion/fpm/pool.d/$app.conf" -#================================================= -# BACKUP FAIL2BAN CONFIGURATION -#================================================= - #================================================= # SPECIFIC BACKUP #================================================= @@ -73,18 +63,6 @@ ynh_backup --src_path="/etc/php/$phpversion/fpm/pool.d/$app.conf" ynh_backup --src_path="/etc/logrotate.d/$app" -#================================================= -# BACKUP SYSTEMD -#================================================= - -#================================================= -# BACKUP VARIOUS FILES -#================================================= - -#================================================= -# BACKUP THE MYSQL DATABASE -#================================================= - #================================================= # END OF SCRIPT #================================================= diff --git a/scripts/change_url b/scripts/change_url index b7a4a0f..ff06606 100644 --- a/scripts/change_url +++ b/scripts/change_url @@ -29,11 +29,6 @@ ynh_script_progression --message="Loading installation settings..." --weight=1 # Needed for helper "ynh_add_nginx_config" final_path=$(ynh_app_setting_get --app=$app --key=final_path) -# Add settings here as needed by your application -#db_name=$(ynh_app_setting_get --app=$app --key=db_name) -#db_user=$db_name -#db_pwd=$(ynh_app_setting_get --app=$app --key=db_pwd) - #================================================= # BACKUP BEFORE CHANGE URL THEN ACTIVE TRAP #================================================= @@ -67,12 +62,6 @@ then change_path=1 fi -#================================================= -# STANDARD MODIFICATIONS -#================================================= -# STOP SYSTEMD SERVICE -#================================================= - #================================================= # MODIFY URL IN NGINX CONF #================================================= @@ -102,18 +91,6 @@ then ynh_store_file_checksum --file="/etc/nginx/conf.d/$new_domain.d/$app.conf" fi -#================================================= -# SPECIFIC MODIFICATIONS -#================================================= -# ... -#================================================= - -#================================================= -# GENERIC FINALISATION -#================================================= -# START SYSTEMD SERVICE -#================================================= - #================================================= # RELOAD NGINX #================================================= diff --git a/scripts/install b/scripts/install index a347a2b..bbd6825 100755 --- a/scripts/install +++ b/scripts/install @@ -27,35 +27,14 @@ ynh_abort_if_errors domain=$YNH_APP_ARG_DOMAIN path_url=$YNH_APP_ARG_PATH is_public=$YNH_APP_ARG_IS_PUBLIC -phpversion=$YNH_APP_ARG_PHPVERSION -### If it's a multi-instance app, meaning it can be installed several times independently -### The id of the app as stated in the manifest is available as $YNH_APP_ID -### The instance number is available as $YNH_APP_INSTANCE_NUMBER (equals "1", "2"...) -### The app instance name is available as $YNH_APP_INSTANCE_NAME -### - the first time the app is installed, YNH_APP_INSTANCE_NAME = ynhexample -### - the second time the app is installed, YNH_APP_INSTANCE_NAME = ynhexample__2 -### - ynhexample__{N} for the subsequent installations, with N=3,4... -### The app instance name is probably what interests you most, since this is -### guaranteed to be unique. This is a good unique identifier to define installation path, -### db names... app=$YNH_APP_INSTANCE_NAME #================================================= # CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS #================================================= -### About --weight and --time -### ynh_script_progression will show to your final users the progression of each scripts. -### In order to do that, --weight will represent the relative time of execution compared to the other steps in the script. -### --time is a packager option, it will show you the execution time since the previous call. -### This option should be removed before releasing your app. -### Use the execution time, given by --time, to estimate the weight of a step. -### A common way to do it is to set a weight equal to the execution time in second +1. -### The execution time is given for the duration since the previous call. So the weight should be applied to this previous call. ynh_script_progression --message="Validating installation parameters..." --weight=1 -### If the app uses NGINX as web server (written in HTML/PHP in most cases), the final path should be "/var/www/$app". -### If the app provides an internal web server (or uses another application server such as uWSGI), the final path should be "/opt/yunohost/$app" final_path=/var/www/$app test ! -e "$final_path" || ynh_die --message="This path already contains a folder" @@ -69,22 +48,19 @@ ynh_script_progression --message="Storing installation settings..." --weight=1 ynh_app_setting_set --app=$app --key=domain --value=$domain ynh_app_setting_set --app=$app --key=path --value=$path_url -ynh_app_setting_set --app=$app --key=phpversion --value=$phpversion #================================================= # STANDARD MODIFICATIONS #================================================= # INSTALL DEPENDENCIES #================================================= +ynh_script_progression --message="Installing dependencies..." --weight=2 - ynh_script_progression --message="Installing dependencies..." --weight=2 - - ynh_install_app_dependencies "php${phpversion}-fpm" +ynh_install_app_dependencies #================================================= # STANDARD MODIFICATIONS #================================================= -#================================================= # CREATE DEDICATED USER #================================================= ynh_script_progression --message="Configuring system user..." --weight=1 @@ -97,20 +73,10 @@ ynh_system_user_create --username=$app --home_dir="$final_path" #================================================= ynh_script_progression --message="Setting up source files..." --weight=1 -### `ynh_setup_source` is used to install an app from a zip or tar.gz file, -### downloaded from an upstream source, like a git repository. -### `ynh_setup_source` use the file conf/app.src - ynh_app_setting_set --app=$app --key=final_path --value=$final_path # Download, check integrity, uncompress and patch the source from app.src ynh_setup_source --dest_dir="$final_path" -# FIXME: this should be managed by the core in the future -# Here, as a packager, you may have to tweak the ownerhsip/permissions -# such that the appropriate users (e.g. maybe www-data) can access -# files in some cases. -# But FOR THE LOVE OF GOD, do not allow r/x for "others" on the entire folder - -# this will be treated as a security issue. chmod 750 "$final_path" chmod -R o-rwx "$final_path" chown -R $app:www-data "$final_path" @@ -120,8 +86,6 @@ chown -R $app:www-data "$final_path" #================================================= ynh_script_progression --message="Configuring NGINX web server..." --weight=1 -### `ynh_add_nginx_config` will use the file conf/nginx.conf - # Create a dedicated NGINX config ynh_add_nginx_config @@ -130,41 +94,9 @@ ynh_add_nginx_config #================================================= ynh_script_progression --message="Configuring PHP-FPM..." --weight=1 -### `ynh_add_fpm_config` is used to set up a PHP config. -### You can remove it if your app doesn't use PHP. -### `ynh_add_fpm_config` will use the files conf/php-fpm.conf -### If you're not using these lines: -### - You can remove these files in conf/. -### - Remove the section "BACKUP THE PHP-FPM CONFIGURATION" in the backup script -### - Remove also the section "REMOVE PHP-FPM CONFIGURATION" in the remove script -### - As well as the section "RESTORE THE PHP-FPM CONFIGURATION" in the restore script -### with the reload at the end of the script. -### - And the section "PHP-FPM CONFIGURATION" in the upgrade script - # Create a dedicated PHP-FPM config ynh_add_fpm_config --usage=low --footprint=low --phpversion=$phpversion -#================================================= -# SETUP APPLICATION WITH CURL >>> to be removed -#================================================= - -### 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. - -# Set the app as temporarily public for curl call -# ynh_script_progression --message="Configuring SSOwat..." --time --weight=1 -# Making the app public for curl -# ynh_permission_update --permission="main" --add="visitors" - -# Installation with curl -# ynh_script_progression --message="Finalizing installation..." --time --weight=1 -# ynh_local_curl "/INSTALL_PATH" "key1=value1" "key2=value2" "key3=value3" - -# Remove the public access -# ynh_permission_update --permission="main" --remove="visitors" - #================================================= # GENERIC FINALIZATION #================================================= @@ -172,14 +104,6 @@ ynh_add_fpm_config --usage=low --footprint=low --phpversion=$phpversion #================================================= ynh_script_progression --message="Configuring log rotation..." --weight=1 -### `ynh_use_logrotate` is used to configure a logrotate configuration for the logs of this app. -### Use this helper only if there is effectively a log file for this app. -### If you're not using this helper: -### - Remove the section "BACKUP LOGROTATE" in the backup script -### - Remove also the section "REMOVE LOGROTATE CONFIGURATION" in the remove script -### - As well as the section "RESTORE THE LOGROTATE CONFIGURATION" in the restore script -### - And the section "SETUP LOGROTATE" in the upgrade script - # Use logrotate to manage application logfile(s) ynh_use_logrotate @@ -196,17 +120,6 @@ then ynh_permission_update --permission="main" --add="visitors" fi -### N.B. : the following extra permissions only make sense if your app -### does have for example an admin interface or an API. - -# Only the admin can access the admin panel of the app (if the app has an admin panel) - - -# Everyone can access the API part -# We don't want to display the tile in the SSO so we put --show_tile="false" -# And we don't want the YunoHost admin to be able to remove visitors group to this permission, so we put --protected="true" -# ynh_permission_create --permission="api" --url="/api" --allowed="visitors" --show_tile="false" --protected="true" - #================================================= # RELOAD NGINX #================================================= diff --git a/scripts/remove b/scripts/remove index 7a32181..61b33eb 100755 --- a/scripts/remove +++ b/scripts/remove @@ -18,24 +18,6 @@ app=$YNH_APP_INSTANCE_NAME domain=$(ynh_app_setting_get --app=$app --key=domain) final_path=$(ynh_app_setting_get --app=$app --key=final_path) -datadir=$(ynh_app_setting_get --app=$app --key=datadir) - -#================================================= -# STANDARD REMOVE -#================================================= -# REMOVE SERVICE INTEGRATION IN YUNOHOST -#================================================= - -# 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..." --weight=1 - yunohost service remove $app -fi - -#================================================= -# STOP AND REMOVE SERVICE -#================================================= #================================================= # REMOVE LOGROTATE CONFIGURATION @@ -45,10 +27,6 @@ ynh_script_progression --message="Removing logrotate configuration..." --weight= # Remove the app-specific logrotate config ynh_remove_logrotate -#================================================= -# REMOVE THE MYSQL DATABASE -#================================================= - #================================================= # REMOVE APP MAIN DIR #================================================= @@ -57,17 +35,6 @@ ynh_script_progression --message="Removing app main directory..." --weight=1 # Remove the app directory securely ynh_secure_remove --file="$final_path" -#================================================= -# REMOVE DATA DIR -#================================================= - -# Remove the data directory if --purge option is used -if [ "${YNH_APP_PURGE:-0}" -eq 1 ] -then - ynh_script_progression --message="Removing app data directory..." --weight=1 - ynh_secure_remove --file="$datadir" -fi - #================================================= # REMOVE NGINX CONFIGURATION #================================================= @@ -84,24 +51,6 @@ ynh_script_progression --message="Removing PHP-FPM configuration..." --weight=1 # Remove the dedicated PHP-FPM config ynh_remove_fpm_config -#================================================= -# REMOVE DEPENDENCIES -#================================================= - -#================================================= -# CLOSE A PORT -#================================================= - -#================================================= -# REMOVE FAIL2BAN CONFIGURATION -#================================================= - -#================================================= -# SPECIFIC REMOVE -#================================================= -# REMOVE VARIOUS FILES -#================================================= - #================================================= # GENERIC FINALIZATION #================================================= diff --git a/scripts/restore b/scripts/restore index 9a0b7d9..724402d 100755 --- a/scripts/restore +++ b/scripts/restore @@ -33,7 +33,6 @@ path_url=$(ynh_app_setting_get --app=$app --key=path) final_path=$(ynh_app_setting_get --app=$app --key=final_path) phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) - #================================================= # CHECK IF THE APP CAN BE RESTORED #================================================= @@ -47,12 +46,9 @@ test ! -d $final_path \ #================================================= # REINSTALL DEPENDENCIES #================================================= - - ynh_script_progression --message="Reinstalling dependencies..." --weight=2 -ynh_install_app_dependencies "php${phpversion}-fpm" - +ynh_install_app_dependencies #================================================= # RESTORE THE NGINX CONFIGURATION @@ -76,12 +72,6 @@ ynh_script_progression --message="Restoring the app main directory..." --weight= ynh_restore_file --origin_path="$final_path" -# FIXME: this should be managed by the core in the future -# Here, as a packager, you may have to tweak the ownerhsip/permissions -# such that the appropriate users (e.g. maybe www-data) can access -# files in some cases. -# But FOR THE LOVE OF GOD, do not allow r/x for "others" on the entire folder - -# this will be treated as a security issue. chmod 750 "$final_path" chmod -R o-rwx "$final_path" chown -R $app:www-data "$final_path" @@ -93,28 +83,6 @@ ynh_script_progression --message="Restoring the PHP-FPM configuration..." --weig ynh_restore_file --origin_path="/etc/php/$phpversion/fpm/pool.d/$app.conf" -#================================================= -# RESTORE FAIL2BAN CONFIGURATION -#================================================= - -#================================================= -# SPECIFIC RESTORATION -#================================================= -# REINSTALL DEPENDENCIES -#================================================= - -#================================================= -# RESTORE THE MYSQL DATABASE -#================================================= - -#================================================= -# RESTORE VARIOUS FILES -#================================================= - -#================================================= -# RESTORE SYSTEMD -#================================================= - #================================================= # RESTORE THE LOGROTATE CONFIGURATION #================================================= diff --git a/scripts/upgrade b/scripts/upgrade index 0a775b6..e83c0ae 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -25,12 +25,6 @@ phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) # CHECK VERSION #================================================= -### 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. upgrade_type=$(ynh_check_app_version_changed) #================================================= @@ -47,45 +41,6 @@ ynh_clean_setup () { # Exit if an error occurs during the execution of the script ynh_abort_if_errors -#================================================= -# STANDARD UPGRADE STEPS -#================================================= -# STOP SYSTEMD SERVICE -#================================================= - -#================================================= -# ENSURE DOWNWARD COMPATIBILITY -#================================================= -ynh_script_progression --message="Ensuring downward compatibility..." --weight=1 - -# -# 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 initiaze 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 final_path doesn't exist, create it -#if [ -z "$final_path" ]; then -# final_path=/var/www/$app -# ynh_app_setting_set --app=$app --key=final_path --value=$final_path -#fi - -### If nobody installed your app before 4.1, -### then you may safely remove these lines - -# Cleaning legacy permissions -if ynh_legacy_permissions_exists; then - ynh_legacy_permissions_delete_all - - ynh_app_setting_delete --app=$app --key=is_public -fi - #================================================= # CREATE DEDICATED USER #================================================= @@ -114,12 +69,6 @@ then ynh_setup_source --dest_dir="$final_path" fi -# FIXME: this should be managed by the core in the future -# Here, as a packager, you may have to tweak the ownerhsip/permissions -# such that the appropriate users (e.g. maybe www-data) can access -# files in some cases. -# But FOR THE LOVE OF GOD, do not allow r/x for "others" on the entire folder - -# this will be treated as a security issue. chmod 750 "$final_path" chmod -R o-rwx "$final_path" chown -R $app:www-data "$final_path" @@ -132,10 +81,6 @@ ynh_script_progression --message="Upgrading NGINX web server configuration..." # Create a dedicated NGINX config ynh_add_nginx_config -#================================================= -# UPGRADE DEPENDENCIES -#================================================= - #================================================= # PHP-FPM CONFIGURATION #================================================= @@ -144,20 +89,6 @@ ynh_script_progression --message="Upgrading PHP-FPM configuration..." --weight= # Create a dedicated PHP-FPM config ynh_add_fpm_config --usage=low --footprint=low --phpversion=$phpversion -#================================================= -# SPECIFIC UPGRADE -#================================================= -# ... -#================================================= - -#================================================= -# UPDATE A CONFIG FILE -#================================================= - -#================================================= -# SETUP SYSTEMD -#================================================= - #================================================= # GENERIC FINALIZATION #================================================= @@ -168,18 +99,6 @@ ynh_script_progression --message="Upgrading logrotate configuration..." --weigh # Use logrotate to manage app-specific logfile(s) ynh_use_logrotate --non-append -#================================================= -# INTEGRATE SERVICE IN YUNOHOST -#================================================= - -#================================================= -# START SYSTEMD SERVICE -#================================================= - -#================================================= -# UPGRADE FAIL2BAN -#================================================= - #================================================= # RELOAD NGINX #================================================= From bf49f8da9d48ee46fed4b602a371d0c2637accb3 Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Tue, 10 Jan 2023 17:32:27 +0000 Subject: [PATCH 06/14] Auto-update README --- README.md | 8 +------- README_fr.md | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 64ade5b..e258f2e 100644 --- a/README.md +++ b/README.md @@ -36,16 +36,10 @@ This is a probe program for PHP environment. It can show your server information This is a probe program for PHP environment. It can show your server information and readable easily. -more info here - -https://github.com/kmvan/x-prober/blob/master/README.md +more info here: https://github.com/kmvan/x-prober/blob/master/README.md Note that the app works only in public mode for now. -To do list : -Add Email send testing. -Add network speed testing. - ## Documentation and resources * Official app website: diff --git a/README_fr.md b/README_fr.md index 3942575..dd91897 100644 --- a/README_fr.md +++ b/README_fr.md @@ -36,16 +36,10 @@ This is a probe program for PHP environment. It can show your server information This is a probe program for PHP environment. It can show your server information and readable easily. -more info here - -https://github.com/kmvan/x-prober/blob/master/README.md +more info here: https://github.com/kmvan/x-prober/blob/master/README.md Note that the app works only in public mode for now. -To do list : -Add Email send testing. -Add network speed testing. - ## Documentations et ressources * Site officiel de l'app : From e3a0058e3161455f41cd6aa68724a372cb8512da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= <46165813+ericgaspar@users.noreply.github.com> Date: Tue, 10 Jan 2023 18:36:13 +0100 Subject: [PATCH 07/14] Fix --- conf/extra_php-fpm.conf | 432 +--------------------------------------- conf/nginx.conf | 2 +- scripts/install | 33 ++- scripts/restore | 6 + scripts/upgrade | 65 ++++-- 5 files changed, 76 insertions(+), 462 deletions(-) diff --git a/conf/extra_php-fpm.conf b/conf/extra_php-fpm.conf index ab1a471..700c37c 100644 --- a/conf/extra_php-fpm.conf +++ b/conf/extra_php-fpm.conf @@ -1,430 +1,4 @@ -; Start a new pool named 'www'. -; the variable $pool can be used in any directive and will be replaced by the -; pool name ('www' here) -[__NAMETOCHANGE__] +; Additional php.ini defines, specific to this pool of workers. -; Per pool prefix -; It only applies on the following directives: -; - 'access.log' -; - 'slowlog' -; - 'listen' (unixsocket) -; - 'chroot' -; - 'chdir' -; - 'php_values' -; - 'php_admin_values' -; When not set, the global prefix (or /usr) applies instead. -; Note: This directive can also be relative to the global prefix. -; Default Value: none -;prefix = /path/to/pools/$pool - -; Unix user/group of processes -; Note: The user is mandatory. If the group is not set, the default user's group -; will be used. -user = __USER__ -group = __USER__ - -; The address on which to accept FastCGI requests. -; Valid syntaxes are: -; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on -; a specific port; -; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on -; a specific port; -; 'port' - to listen on a TCP socket to all addresses -; (IPv6 and IPv4-mapped) on a specific port; -; '/path/to/unix/socket' - to listen on a unix socket. -; Note: This value is mandatory. -listen = /var/run/php/php__PHPVERSION__-fpm-__NAMETOCHANGE__.sock - -; Set listen(2) backlog. -; Default Value: 511 (-1 on FreeBSD and OpenBSD) -;listen.backlog = 511 - -; Set permissions for unix socket, if one is used. In Linux, read/write -; permissions must be set in order to allow connections from a web server. Many -; BSD-derived systems allow connections regardless of permissions. -; Default Values: user and group are set as the running user -; mode is set to 0660 -listen.owner = www-data -listen.group = www-data -;listen.mode = 0660 -; When POSIX Access Control Lists are supported you can set them using -; these options, value is a comma separated list of user/group names. -; When set, listen.owner and listen.group are ignored -;listen.acl_users = -;listen.acl_groups = - -; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect. -; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original -; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address -; must be separated by a comma. If this value is left blank, connections will be -; accepted from any ip address. -; Default Value: any -;listen.allowed_clients = 127.0.0.1 - -; Specify the nice(2) priority to apply to the pool processes (only if set) -; The value can vary from -19 (highest priority) to 20 (lower priority) -; Note: - It will only work if the FPM master process is launched as root -; - The pool processes will inherit the master process priority -; unless it specified otherwise -; Default Value: no set -; process.priority = -19 - -; Set the process dumpable flag (PR_SET_DUMPABLE prctl) even if the process user -; or group is differrent than the master process user. It allows to create process -; core dump and ptrace the process for the pool user. -; Default Value: no -; process.dumpable = yes - -; Choose how the process manager will control the number of child processes. -; Possible Values: -; static - a fixed number (pm.max_children) of child processes; -; dynamic - the number of child processes are set dynamically based on the -; following directives. With this process management, there will be -; always at least 1 children. -; pm.max_children - the maximum number of children that can -; be alive at the same time. -; pm.start_servers - the number of children created on startup. -; pm.min_spare_servers - the minimum number of children in 'idle' -; state (waiting to process). If the number -; of 'idle' processes is less than this -; number then some children will be created. -; pm.max_spare_servers - the maximum number of children in 'idle' -; state (waiting to process). If the number -; of 'idle' processes is greater than this -; number then some children will be killed. -; ondemand - no children are created at startup. Children will be forked when -; new requests will connect. The following parameter are used: -; pm.max_children - the maximum number of children that -; can be alive at the same time. -; pm.process_idle_timeout - The number of seconds after which -; an idle process will be killed. -; Note: This value is mandatory. -pm = dynamic - -; The number of child processes to be created when pm is set to 'static' and the -; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. -; This value sets the limit on the number of simultaneous requests that will be -; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. -; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP -; CGI. The below defaults are based on a server without much resources. Don't -; forget to tweak pm.* to fit your needs. -; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' -; Note: This value is mandatory. -pm.max_children = 5 - -; The number of child processes created on startup. -; Note: Used only when pm is set to 'dynamic' -; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 -pm.start_servers = 2 - -; The desired minimum number of idle server processes. -; Note: Used only when pm is set to 'dynamic' -; Note: Mandatory when pm is set to 'dynamic' -pm.min_spare_servers = 1 - -; The desired maximum number of idle server processes. -; Note: Used only when pm is set to 'dynamic' -; Note: Mandatory when pm is set to 'dynamic' -pm.max_spare_servers = 3 - -; The number of seconds after which an idle process will be killed. -; Note: Used only when pm is set to 'ondemand' -; Default Value: 10s -;pm.process_idle_timeout = 10s; - -; The number of requests each child process should execute before respawning. -; This can be useful to work around memory leaks in 3rd party libraries. For -; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. -; Default Value: 0 -;pm.max_requests = 500 - -; The URI to view the FPM status page. If this value is not set, no URI will be -; recognized as a status page. It shows the following informations: -; pool - the name of the pool; -; process manager - static, dynamic or ondemand; -; start time - the date and time FPM has started; -; start since - number of seconds since FPM has started; -; accepted conn - the number of request accepted by the pool; -; listen queue - the number of request in the queue of pending -; connections (see backlog in listen(2)); -; max listen queue - the maximum number of requests in the queue -; of pending connections since FPM has started; -; listen queue len - the size of the socket queue of pending connections; -; idle processes - the number of idle processes; -; active processes - the number of active processes; -; total processes - the number of idle + active processes; -; max active processes - the maximum number of active processes since FPM -; has started; -; max children reached - number of times, the process limit has been reached, -; when pm tries to start more children (works only for -; pm 'dynamic' and 'ondemand'); -; Value are updated in real time. -; Example output: -; pool: www -; process manager: static -; start time: 01/Jul/2011:17:53:49 +0200 -; start since: 62636 -; accepted conn: 190460 -; listen queue: 0 -; max listen queue: 1 -; listen queue len: 42 -; idle processes: 4 -; active processes: 11 -; total processes: 15 -; max active processes: 12 -; max children reached: 0 -; -; By default the status page output is formatted as text/plain. Passing either -; 'html', 'xml' or 'json' in the query string will return the corresponding -; output syntax. Example: -; http://www.foo.bar/status -; http://www.foo.bar/status?json -; http://www.foo.bar/status?html -; http://www.foo.bar/status?xml -; -; By default the status page only outputs short status. Passing 'full' in the -; query string will also return status for each pool process. -; Example: -; http://www.foo.bar/status?full -; http://www.foo.bar/status?json&full -; http://www.foo.bar/status?html&full -; http://www.foo.bar/status?xml&full -; The Full status returns for each process: -; pid - the PID of the process; -; state - the state of the process (Idle, Running, ...); -; start time - the date and time the process has started; -; start since - the number of seconds since the process has started; -; requests - the number of requests the process has served; -; request duration - the duration in µs of the requests; -; request method - the request method (GET, POST, ...); -; request URI - the request URI with the query string; -; content length - the content length of the request (only with POST); -; user - the user (PHP_AUTH_USER) (or '-' if not set); -; script - the main script called (or '-' if not set); -; last request cpu - the %cpu the last request consumed -; it's always 0 if the process is not in Idle state -; because CPU calculation is done when the request -; processing has terminated; -; last request memory - the max amount of memory the last request consumed -; it's always 0 if the process is not in Idle state -; because memory calculation is done when the request -; processing has terminated; -; If the process is in Idle state, then informations are related to the -; last request the process has served. Otherwise informations are related to -; the current request being served. -; Example output: -; ************************ -; pid: 31330 -; state: Running -; start time: 01/Jul/2011:17:53:49 +0200 -; start since: 63087 -; requests: 12808 -; request duration: 1250261 -; request method: GET -; request URI: /test_mem.php?N=10000 -; content length: 0 -; user: - -; script: /home/fat/web/docs/php/test_mem.php -; last request cpu: 0.00 -; last request memory: 0 -; -; Note: There is a real-time FPM status monitoring sample web page available -; It's available in: /usr/share/php/7.0/fpm/status.html -; -; Note: The value must start with a leading slash (/). The value can be -; anything, but it may not be a good idea to use the .php extension or it -; may conflict with a real PHP file. -; Default Value: not set -;pm.status_path = /status - -; The ping URI to call the monitoring page of FPM. If this value is not set, no -; URI will be recognized as a ping page. This could be used to test from outside -; that FPM is alive and responding, or to -; - create a graph of FPM availability (rrd or such); -; - remove a server from a group if it is not responding (load balancing); -; - trigger alerts for the operating team (24/7). -; Note: The value must start with a leading slash (/). The value can be -; anything, but it may not be a good idea to use the .php extension or it -; may conflict with a real PHP file. -; Default Value: not set -;ping.path = /ping - -; This directive may be used to customize the response of a ping request. The -; response is formatted as text/plain with a 200 response code. -; Default Value: pong -;ping.response = pong - -; The access log file -; Default: not set -;access.log = log/$pool.access.log - -; The access log format. -; The following syntax is allowed -; %%: the '%' character -; %C: %CPU used by the request -; it can accept the following format: -; - %{user}C for user CPU only -; - %{system}C for system CPU only -; - %{total}C for user + system CPU (default) -; %d: time taken to serve the request -; it can accept the following format: -; - %{seconds}d (default) -; - %{miliseconds}d -; - %{mili}d -; - %{microseconds}d -; - %{micro}d -; %e: an environment variable (same as $_ENV or $_SERVER) -; it must be associated with embraces to specify the name of the env -; variable. Some exemples: -; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e -; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e -; %f: script filename -; %l: content-length of the request (for POST request only) -; %m: request method -; %M: peak of memory allocated by PHP -; it can accept the following format: -; - %{bytes}M (default) -; - %{kilobytes}M -; - %{kilo}M -; - %{megabytes}M -; - %{mega}M -; %n: pool name -; %o: output header -; it must be associated with embraces to specify the name of the header: -; - %{Content-Type}o -; - %{X-Powered-By}o -; - %{Transfert-Encoding}o -; - .... -; %p: PID of the child that serviced the request -; %P: PID of the parent of the child that serviced the request -; %q: the query string -; %Q: the '?' character if query string exists -; %r: the request URI (without the query string, see %q and %Q) -; %R: remote IP address -; %s: status (response code) -; %t: server time the request was received -; it can accept a strftime(3) format: -; %d/%b/%Y:%H:%M:%S %z (default) -; The strftime(3) format must be encapsuled in a %{}t tag -; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t -; %T: time the log has been written (the request has finished) -; it can accept a strftime(3) format: -; %d/%b/%Y:%H:%M:%S %z (default) -; The strftime(3) format must be encapsuled in a %{}t tag -; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t -; %u: remote user -; -; Default: "%R - %u %t \"%m %r\" %s" -;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%" - -; The log file for slow requests -; Default Value: not set -; Note: slowlog is mandatory if request_slowlog_timeout is set -;slowlog = log/$pool.log.slow - -; The timeout for serving a single request after which a PHP backtrace will be -; dumped to the 'slowlog' file. A value of '0s' means 'off'. -; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) -; Default Value: 0 -;request_slowlog_timeout = 0 - -; The timeout for serving a single request after which the worker process will -; be killed. This option should be used when the 'max_execution_time' ini option -; does not stop script execution for some reason. A value of '0' means 'off'. -; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) -; Default Value: 0 -request_terminate_timeout = 1d - -; Set open file descriptor rlimit. -; Default Value: system defined value -;rlimit_files = 1024 - -; Set max core size rlimit. -; Possible Values: 'unlimited' or an integer greater or equal to 0 -; Default Value: system defined value -;rlimit_core = 0 - -; Chroot to this directory at the start. This value must be defined as an -; absolute path. When this value is not set, chroot is not used. -; Note: you can prefix with '$prefix' to chroot to the pool prefix or one -; of its subdirectories. If the pool prefix is not set, the global prefix -; will be used instead. -; Note: chrooting is a great security feature and should be used whenever -; possible. However, all PHP paths will be relative to the chroot -; (error_log, sessions.save_path, ...). -; Default Value: not set -;chroot = - -; Chdir to this directory at the start. -; Note: relative path can be used. -; Default Value: current directory or / when chroot -chdir = __FINALPATH__ - -; Redirect worker stdout and stderr into main error log. If not set, stdout and -; stderr will be redirected to /dev/null according to FastCGI specs. -; Note: on highloaded environement, this can cause some delay in the page -; process time (several ms). -; Default Value: no -;catch_workers_output = yes - -; Clear environment in FPM workers -; Prevents arbitrary environment variables from reaching FPM worker processes -; by clearing the environment in workers before env vars specified in this -; pool configuration are added. -; Setting to "no" will make all environment variables available to PHP code -; via getenv(), $_ENV and $_SERVER. -; Default Value: yes -;clear_env = no - -; Limits the extensions of the main script FPM will allow to parse. This can -; prevent configuration mistakes on the web server side. You should only limit -; FPM to .php extensions to prevent malicious users to use other extensions to -; execute php code. -; Note: set an empty value to allow all extensions. -; Default Value: .php -;security.limit_extensions = .php .php3 .php4 .php5 .php7 - -; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from -; the current environment. -; Default Value: clean env -;env[HOSTNAME] = $HOSTNAME -;env[PATH] = /usr/local/bin:/usr/bin:/bin -;env[TMP] = /tmp -;env[TMPDIR] = /tmp -;env[TEMP] = /tmp - -; Additional php.ini defines, specific to this pool of workers. These settings -; overwrite the values previously defined in the php.ini. The directives are the -; same as the PHP SAPI: -; php_value/php_flag - you can set classic ini defines which can -; be overwritten from PHP call 'ini_set'. -; php_admin_value/php_admin_flag - these directives won't be overwritten by -; PHP call 'ini_set' -; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no. - -; Defining 'extension' will load the corresponding shared extension from -; extension_dir. Defining 'disable_functions' or 'disable_classes' will not -; overwrite previously defined php.ini values, but will append the new value -; instead. - -; Note: path INI options can be relative and will be expanded with the prefix -; (pool, global or /usr) - -; Default Value: nothing is defined by default except the values in php.ini and -; specified at startup with the -d argument -;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com -;php_flag[display_errors] = off -;php_admin_value[error_log] = /var/log/fpm-php.www.log -;php_admin_flag[log_errors] = on -;php_admin_value[memory_limit] = 32M - -; Common values to change to increase file upload limit -; php_admin_value[upload_max_filesize] = 50M -; php_admin_value[post_max_size] = 50M -; php_admin_flag[mail.add_x_header] = Off - -; Other common parameters -; php_admin_value[max_execution_time] = 600 -; php_admin_value[max_input_time] = 300 -; php_admin_value[memory_limit] = 256M -; php_admin_flag[short_open_tag] = On +php_admin_value[upload_max_filesize] = 50M +php_admin_value[post_max_size] = 50M diff --git a/conf/nginx.conf b/conf/nginx.conf index be1f44a..fc07ff5 100644 --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -7,7 +7,7 @@ location __PATH__/ { index prober.php; # Common parameter to increase upload size limit in conjunction with dedicated php-fpm file - #client_max_body_size 50M; + client_max_body_size 50M; try_files $uri $uri/ index.php; location ~ [^/]\.php(/|$) { diff --git a/scripts/install b/scripts/install index bbd6825..0dd8691 100755 --- a/scripts/install +++ b/scripts/install @@ -30,6 +30,10 @@ is_public=$YNH_APP_ARG_IS_PUBLIC app=$YNH_APP_INSTANCE_NAME +fpm_footprint="low" +fpm_free_footprint=0 +fpm_usage="low" + #================================================= # CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS #================================================= @@ -48,15 +52,9 @@ ynh_script_progression --message="Storing installation settings..." --weight=1 ynh_app_setting_set --app=$app --key=domain --value=$domain ynh_app_setting_set --app=$app --key=path --value=$path_url - -#================================================= -# STANDARD MODIFICATIONS -#================================================= -# INSTALL DEPENDENCIES -#================================================= -ynh_script_progression --message="Installing dependencies..." --weight=2 - -ynh_install_app_dependencies +ynh_app_setting_set --app=$app --key=fpm_footprint --value=$fpm_footprint +ynh_app_setting_set --app=$app --key=fpm_free_footprint --value=$fpm_free_footprint +ynh_app_setting_set --app=$app --key=fpm_usage --value=$fpm_usage #================================================= # STANDARD MODIFICATIONS @@ -81,6 +79,15 @@ chmod 750 "$final_path" chmod -R o-rwx "$final_path" chown -R $app:www-data "$final_path" +#================================================= +# PHP-FPM CONFIGURATION +#================================================= +ynh_script_progression --message="Configuring PHP-FPM..." --weight=1 + +# Create a dedicated PHP-FPM config +ynh_add_fpm_config --usage=$fpm_usage --footprint=$fpm_footprint +phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) + #================================================= # NGINX CONFIGURATION #================================================= @@ -89,14 +96,6 @@ ynh_script_progression --message="Configuring NGINX web server..." --weight=1 # Create a dedicated NGINX config ynh_add_nginx_config -#================================================= -# PHP-FPM CONFIGURATION -#================================================= -ynh_script_progression --message="Configuring PHP-FPM..." --weight=1 - -# Create a dedicated PHP-FPM config -ynh_add_fpm_config --usage=low --footprint=low --phpversion=$phpversion - #================================================= # GENERIC FINALIZATION #================================================= diff --git a/scripts/restore b/scripts/restore index 724402d..1c40374 100755 --- a/scripts/restore +++ b/scripts/restore @@ -33,6 +33,9 @@ path_url=$(ynh_app_setting_get --app=$app --key=path) final_path=$(ynh_app_setting_get --app=$app --key=final_path) phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) +fpm_footprint=$(ynh_app_setting_get --app=$app --key=fpm_footprint) +fpm_usage=$(ynh_app_setting_get --app=$app --key=fpm_usage) + #================================================= # CHECK IF THE APP CAN BE RESTORED #================================================= @@ -83,6 +86,9 @@ ynh_script_progression --message="Restoring the PHP-FPM configuration..." --weig ynh_restore_file --origin_path="/etc/php/$phpversion/fpm/pool.d/$app.conf" +# Recreate a dedicated php-fpm config +ynh_add_fpm_config --usage=$fpm_usage --footprint=$fpm_footprint --phpversion=$phpversion + #================================================= # RESTORE THE LOGROTATE CONFIGURATION #================================================= diff --git a/scripts/upgrade b/scripts/upgrade index e83c0ae..9ac2ace 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -21,6 +21,10 @@ path_url=$(ynh_app_setting_get --app=$app --key=path) final_path=$(ynh_app_setting_get --app=$app --key=final_path) phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) +fpm_footprint=$(ynh_app_setting_get --app=$app --key=fpm_footprint) +fpm_free_footprint=$(ynh_app_setting_get --app=$app --key=fpm_free_footprint) +fpm_usage=$(ynh_app_setting_get --app=$app --key=fpm_usage) + #================================================= # CHECK VERSION #================================================= @@ -30,7 +34,7 @@ upgrade_type=$(ynh_check_app_version_changed) #================================================= # BACKUP BEFORE UPGRADE THEN ACTIVE TRAP #================================================= -ynh_script_progression --message="Backing up the app before upgrading (may take a while)..." --weight=1 +ynh_script_progression --message="Backing up the app before upgrading (may take a while)..." --weight=1 # Backup the current version of the app ynh_backup_before_upgrade @@ -41,10 +45,40 @@ ynh_clean_setup () { # Exit if an error occurs during the execution of the script ynh_abort_if_errors +#================================================= +# ENSURE DOWNWARD COMPATIBILITY +#================================================= +ynh_script_progression --message="Ensuring downward compatibility..." --weight=1 + +# If fpm_footprint doesn't exist, create it +if [ -z "$fpm_footprint" ]; then + fpm_footprint=low + ynh_app_setting_set --app=$app --key=fpm_footprint --value=$fpm_footprint +fi + +# If fpm_free_footprint doesn't exist, create it +if [ -z "$fpm_free_footprint" ]; then + fpm_free_footprint=0 + ynh_app_setting_set --app=$app --key=fpm_free_footprint --value=$fpm_free_footprint +fi + +# If fpm_usage doesn't exist, create it +if [ -z "$fpm_usage" ]; then + fpm_usage=low + ynh_app_setting_set --app=$app --key=fpm_usage --value=$fpm_usage +fi + +# Cleaning legacy permissions +if ynh_legacy_permissions_exists; then + ynh_legacy_permissions_delete_all + + ynh_app_setting_delete --app=$app --key=is_public +fi + #================================================= # CREATE DEDICATED USER #================================================= -ynh_script_progression --message="Making sure dedicated system user exists..." --weight=1 +ynh_script_progression --message="Making sure dedicated system user exists..." --weight=1 # Create a dedicated user (if not existing) ynh_system_user_create --username=$app --home_dir="$final_path" @@ -63,7 +97,7 @@ ynh_install_app_dependencies "php${phpversion}-fpm" if [ "$upgrade_type" == "UPGRADE_APP" ] then - ynh_script_progression --message="Upgrading source files..." --weight=1 + ynh_script_progression --message="Upgrading source files..." --weight=1 # Download, check integrity, uncompress and patch the source from app.src ynh_setup_source --dest_dir="$final_path" @@ -73,28 +107,29 @@ chmod 750 "$final_path" chmod -R o-rwx "$final_path" chown -R $app:www-data "$final_path" +#================================================= +# PHP-FPM CONFIGURATION +#================================================= +ynh_script_progression --message="Upgrading PHP-FPM configuration..." --weight=1 + +# Create a dedicated PHP-FPM config +ynh_add_fpm_config --phpversion=$phpversion --usage=$fpm_usage --footprint=$fpm_footprint +phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) + #================================================= # NGINX CONFIGURATION #================================================= -ynh_script_progression --message="Upgrading NGINX web server configuration..." --weight=1 +ynh_script_progression --message="Upgrading NGINX web server configuration..." --weight=1 # Create a dedicated NGINX config ynh_add_nginx_config -#================================================= -# PHP-FPM CONFIGURATION -#================================================= -ynh_script_progression --message="Upgrading PHP-FPM configuration..." --weight=1 - -# Create a dedicated PHP-FPM config -ynh_add_fpm_config --usage=low --footprint=low --phpversion=$phpversion - #================================================= # GENERIC FINALIZATION #================================================= # SETUP LOGROTATE #================================================= -ynh_script_progression --message="Upgrading logrotate configuration..." --weight=1 +ynh_script_progression --message="Upgrading logrotate configuration..." --weight=1 # Use logrotate to manage app-specific logfile(s) ynh_use_logrotate --non-append @@ -102,7 +137,7 @@ ynh_use_logrotate --non-append #================================================= # RELOAD NGINX #================================================= -ynh_script_progression --message="Reloading NGINX web server..." --weight=1 +ynh_script_progression --message="Reloading NGINX web server..." --weight=1 ynh_systemd_action --service_name=nginx --action=reload @@ -110,4 +145,4 @@ ynh_systemd_action --service_name=nginx --action=reload # END OF SCRIPT #================================================= -ynh_script_progression --message="Upgrade of $app completed" --last +ynh_script_progression --message="Upgrade of $app completed" --last From 6f09a0a5dc6bd17816208083b184fe4c9fd59d3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= <46165813+ericgaspar@users.noreply.github.com> Date: Tue, 10 Jan 2023 18:38:41 +0100 Subject: [PATCH 08/14] Fix screenshots --- doc/screenshots/02.jpg | Bin 73838 -> 0 bytes doc/screenshots/03.jpg | Bin 86928 -> 0 bytes doc/screenshots/{01.jpg => screenshot.jpg} | Bin 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 doc/screenshots/02.jpg delete mode 100644 doc/screenshots/03.jpg rename doc/screenshots/{01.jpg => screenshot.jpg} (100%) diff --git a/doc/screenshots/02.jpg b/doc/screenshots/02.jpg deleted file mode 100644 index 1aab8e0ae701d0a9f14f07b2fd109f1b010013e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73838 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 G;r{{g^WVb& diff --git a/doc/screenshots/03.jpg b/doc/screenshots/03.jpg deleted file mode 100644 index 7716e3687b64c2571527681fc0ce876bbd1cf9d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 86928 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 diff --git a/doc/screenshots/01.jpg b/doc/screenshots/screenshot.jpg similarity index 100% rename from doc/screenshots/01.jpg rename to doc/screenshots/screenshot.jpg From 5a3a7c823ca40544af239ce070d89c047ae2c259 Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Tue, 10 Jan 2023 17:38:45 +0000 Subject: [PATCH 09/14] Auto-update README --- README.md | 4 +--- README_fr.md | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e258f2e..3a9d307 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,7 @@ This is a probe program for PHP environment. It can show your server information ## Screenshots -![Screenshot of x-prober](./doc/screenshots/03.jpg) -![Screenshot of x-prober](./doc/screenshots/01.jpg) -![Screenshot of x-prober](./doc/screenshots/02.jpg) +![Screenshot of x-prober](./doc/screenshots/screenshot.jpg) ## Disclaimers / important information diff --git a/README_fr.md b/README_fr.md index dd91897..21ded4b 100644 --- a/README_fr.md +++ b/README_fr.md @@ -28,9 +28,7 @@ This is a probe program for PHP environment. It can show your server information ## Captures d'écran -![Capture d'écran de x-prober](./doc/screenshots/03.jpg) -![Capture d'écran de x-prober](./doc/screenshots/01.jpg) -![Capture d'écran de x-prober](./doc/screenshots/02.jpg) +![Capture d'écran de x-prober](./doc/screenshots/screenshot.jpg) ## Avertissements / informations importantes From 42ed215ae0d42b3c85c4486c61d63acd92390610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= <46165813+ericgaspar@users.noreply.github.com> Date: Tue, 10 Jan 2023 18:50:29 +0100 Subject: [PATCH 10/14] Fix --- config_panel.toml | 30 ++++ config_panel.toml.example | 295 -------------------------------------- scripts/config | 113 +++++++-------- 3 files changed, 83 insertions(+), 355 deletions(-) create mode 100644 config_panel.toml delete mode 100644 config_panel.toml.example diff --git a/config_panel.toml b/config_panel.toml new file mode 100644 index 0000000..ec8e8f6 --- /dev/null +++ b/config_panel.toml @@ -0,0 +1,30 @@ +version = "1.0" + +[main] +name = "X-Prober configuration" + + [main.php_fpm_config] + name = "PHP-FPM configuration" + + [main.php_fpm_config.fpm_footprint] + ask = "Memory footprint" + type = "select" + choices.low = "Low, <= 20Mb per pool" + choices.medium = "Medium, between 20Mb and 40Mb per pool" + choices.high = "High, > 40Mb per pool" + choices.specific = "Use specific value" + default = "low" + + [main.php_fpm_config.fpm_free_footprint] + visible = "fpm_footprint == 'specific'" + ask = "Memory footprint of the service?" + type = "number" + default = "0" + help = "Free field to specify exactly the footprint in Mb if you don't want to use one of the three previous values." + + [main.php_fpm_config.fpm_usage] + ask = "Expected usage" + type = "select" + choices = ["low", "medium", "high"] + default = "low" + help = "low: Personal usage, behind the SSO. No RAM footprint when not used, but the impact on the processor can be high if many users are using the service.
medium: Low usage, few people or/and publicly accessible. Low RAM footprint, medium processor footprint when used.
high: High usage, frequently visited website. High RAM footprint, but lower on processor usage and quickly responding." diff --git a/config_panel.toml.example b/config_panel.toml.example deleted file mode 100644 index c6bccd8..0000000 --- a/config_panel.toml.example +++ /dev/null @@ -1,295 +0,0 @@ - -## Config panel are available from webadmin > Apps > YOUR_APP > Config Panel Button -## Those panels let user configure some params on their apps using a friendly interface, -## and remove the need to manually edit files from the command line. - -## From a packager perspective, this .toml is coupled to the scripts/config script, -## which may be used to define custom getters/setters. However, most use cases -## should be covered automagically by the core, thus it may not be necessary -## to define a scripts/config at all! - -## ----------------------------------------------------------------------------- -## IMPORTANT: In accordance with YunoHost's spirit, please keep things simple and -## do not overwhelm the admin with tons of misunderstandable or advanced settings. -## ----------------------------------------------------------------------------- - -## The top level describe the entire config panels screen. - -## The version is a required property. -## Here a small reminder to associate config panel version with YunoHost version -## | Config | YNH | Config panel small change log | -## | ------ | --- | ------------------------------------------------------- | -## | 0.1 | 3.x | 0.1 config script not compatible with YNH >= 4.3 | -## | 1.0 | 4.3.x | The new config panel system with 'bind' property | -version = "1.0" - -## (optional) i18n property let you internationalize questions, however this feature -## is only available in core configuration panel (like yunohost domain config). -## So in app config panel this key is ignored for now, but you can internationalize -## by using a lang dictionary (see property name bellow) -# i18n = "prefix_translation_key" - -################################################################################ -#### ABOUT PANELS -################################################################################ - -## The next level describes web admin panels -## You have to choose an ID for each panel, in this example the ID is "main" -## Keep in mind this ID will be used in CLI to refer to your question, so choose -## something short and meaningfull. -## In the webadmin, each panel corresponds to a distinct tab / form -[main] - -## Define the label for your panel -## Internationalization works similarly to the 'description' and 'ask' questions in the manifest -# name.en = "Main configuration" -# name.fr = "Configuration principale" - -## (optional) If you need to trigger a service reload-or-restart after the user -## change a question in this panel, you can add your service in the list. -services = ["__APP__"] -# or services = ["nginx", "__APP__"] to also reload-or-restart nginx - -## (optional) This help properties is a short help displayed on the same line -## than the panel title but not displayed in the tab. -# help = "" - - ############################################################################ - #### ABOUT SECTIONS - ############################################################################ - - ## A panel is composed of one or several sections. - ## - ## Sections are meant to group questions together when they correspond to - ## a same subtopic. This impacts the rendering in terms of CLI prompts - ## and HTML forms - ## - ## You should choose an ID for your section, and prefix it with the panel ID - ## (Be sure to not make a typo in the panel ID, which would implicitly create - ## an other entire panel) - ## - ## We use the context of pepettes_ynh as an example, - ## which is a simple donation form app written in python, - ## and for which the admin will want to edit the configuration - [main.customization] - - ## (optional) Defining a proper title for sections is not mandatory - ## and depends on the exact rendering you're aiming for the CLI / webadmin - name = "" - - ## (optional) This help properties is a short help displayed on the same line - ## than the section title, meant to provide additional details - # help = "" - - ## (optional) As for panel, you can specify to trigger a service - ## reload-or-restart after the user change a question in this section. - ## This property is added to the panel property, it doesn't deactivate it. - ## So no need to replicate, the service list from panel services property. - # services = [] - - ## (optional) By default all questions are optionals, but you can specify a - ## default behaviour for question in the section - optional = false - - ## (optional) It's also possible with the 'visible' property to only - ## display the section depending on the user's answers to previous questions. - ## - ## Be careful that the 'visible' property should only refer to **previous** questions - ## Hence, it should not make sense to have a "visible" property on the very first section. - ## - ## Also, keep in mind that this feature only works in the webadmin and not in CLI - ## (therefore a user could be prompted in CLI for a question that may not be relevant) - # visible = true - - ######################################################################## - #### ABOUT QUESTIONS - ######################################################################## - - ## A section is compound of one or several questions. - - ## --------------------------------------------------------------------- - ## IMPORTANT: as for panel and section you have to choose an ID, but this - ## one should be unique in all this document, even if the question is in - ## an other panel. - ## --------------------------------------------------------------------- - - ## You can use same questions types and properties than in manifest.yml - ## install part. However, in YNH 4.3, a lot of change has been made to - ## extend availables questions types list. - ## See: TODO DOC LINK - - [main.customization.project_name] - - ## (required) The ask property is equivalent to the ask property in - ## the manifest. However, in config panels, questions are displayed on the - ## left side and therefore have less space to be rendered. Therefore, - ## it is better to use a short question, and use the "help" property to - ## provide additional details if necessary. - ask.en = "Name of the project" - - ## (required) The type property indicates how the question should be - ## displayed, validated and managed. Some types have specific properties. - ## - ## Types available: string, boolean, number, range, text, password, path - ## email, url, date, time, color, select, domain, user, tags, file. - ## - ## For a complete list with specific properties, see: TODO DOC LINK - type = "string" - - ######################################################################## - #### ABOUT THE BIND PROPERTY - ######################################################################## - - ## (recommended) 'bind' property is a powerful feature that let you - ## configure how and where the data will be read, validated and written. - - ## By default, 'bind property is in "settings" mode, it means it will - ## **only** read and write the value in application settings file. - ## bind = "settings" - - ## However, settings usually correspond to key/values in actual app configurations - ## Hence, a more useful mode is to have bind = ":FILENAME". In that case, YunoHost - ## will automagically find a line with "KEY=VALUE" in FILENAME - ## (with the adequate separator between KEY and VALUE) - ## - ## YunoHost will then use this value for the read/get operation. - ## During write/set operations, YunoHost will overwrite the value - ## in **both** FILENAME and in the app's settings.yml - - ## Configuration file format supported: yaml, toml, json, ini, env, php, - ## python. The feature probably works with others formats, but should be tested carefully. - - ## Note that this feature only works with relatively simple cases - ## such as `KEY: VALUE`, but won't properly work with - ## complex data structures like multilin array/lists or dictionnaries. - ## It also doesn't work with XML format, custom config function call, php define(), ... - - ## More info on TODO - # bind = ":/var/www/__APP__/settings.py" - - - ## By default, bind = ":FILENAME" will use the question ID as KEY - ## ... but the question ID may sometime not be the exact KEY name in the configuration file. - ## - ## In particular, in pepettes, the python variable is 'name' and not 'project_name' - ## (c.f. https://github.com/YunoHost-Apps/pepettes_ynh/blob/5cc2d3ffd6529cc7356ff93af92dbb6785c3ab9a/conf/settings.py##L11 ) - ## - ## In that case, the key name can be specified before the column ':' - - bind = "name:/var/www/__APP__/settings.py" - - ## --------------------------------------------------------------------- - ## IMPORTANT: other 'bind' mode exists: - ## - ## bind = "FILENAME" (with no column character before FILENAME) - ## may be used to bind to the **entire file content** (instead of a single KEY/VALUE) - ## This could be used to expose an entire configuration file, or binary files such as images - ## For example: - ## bind = "/var/www/__APP__/img/logo.png" - ## - ## bind = "null" can be used to disable reading / writing in settings. - ## This creates sort of a "virtual" or "ephemeral" question which is not related to any actual setting - ## In this mode, you are expected to define custom getter/setters/validators in scripts/config: - ## - ## getter: get__QUESTIONID() - ## setter: set__QUESTIONID() - ## validator: validate__QUESTIONID() - ## - ## You can also specify a common getter / setter / validator, with the - ## function 'bind' mode, for example here it will try to run - ## get__array_settings() first. - # bind = "array_settings()" - ## --------------------------------------------------------------------- - - ## --------------------------------------------------------------------- - ## IMPORTANT: with the exception of bind=null questions, - ## question IDs should almost **always** correspond to an app setting - ## initialized / reused during install/upgrade. - ## Not doing so may result in inconsistencies between the config panel mechanism - ## and the use of ynh_add_config - ## --------------------------------------------------------------------- - - ######################################################################## - #### OTHER GENERIC PROPERTY FOR QUESTIONS - ######################################################################## - - ## (optional) An help text for the question - help = "Fill the name of the project which will received donation" - - ## (optional) An example display as placeholder in web form - # example = "YunoHost" - - ## (optional) set to true in order to redact the value in operation logs - # redact = false - - ## (optional) A validation pattern - ## --------------------------------------------------------------------- - ## IMPORTANT: your pattern should be between simple quote, not double. - ## --------------------------------------------------------------------- - pattern.regexp = '^\w{3,30}$' - pattern.error = "The name should be at least 3 chars and less than 30 chars. Alphanumeric chars are accepted" - - ## Note: visible and optional properties are also available for questions - - - [main.customization.contact_url] - ask = "Contact url" - type = "url" - example = "mailto: contact@example.org" - help = "mailto: accepted" - pattern.regexp = '^mailto:[^@]+@[^@]+|https://$' - pattern.error = "Should be https or mailto:" - bind = ":/var/www/__APP__/settings.py" - - [main.customization.logo] - ask = "Logo" - type = "file" - accept = ".png" - help = "Fill with an already resized logo" - bind = "__FINALPATH__/img/logo.png" - - [main.customization.favicon] - ask = "Favicon" - type = "file" - accept = ".png" - help = "Fill with an already sized favicon" - bind = "__FINALPATH__/img/favicon.png" - - - [main.stripe] - name = "Stripe general info" - optional = false - - # The next alert is overwrited with a getter from the config script - [main.stripe.amount] - ask = "Donation in the month : XX € - type = "alert" - style = "success" - - [main.stripe.publishable_key] - ask = "Publishable key" - type = "string" - redact = true - help = "Indicate here the stripe publishable key" - bind = ":/var/www/__APP__/settings.py" - - [main.stripe.secret_key] - ask = "Secret key" - type = "string" - redact = true - help = "Indicate here the stripe secret key" - bind = ":/var/www/__APP__/settings.py" - - [main.stripe.prices] - ask = "Prices ID" - type = "tags" - help = """\ - Indicates here the prices ID of donation products you created in stripe interfaces. \ - Go on [Stripe products](https://dashboard.stripe.com/products) to create those donation products. \ - Fill it tag with 'FREQUENCY/CURRENCY/PRICE_ID' \ - FREQUENCY: 'one_time' or 'recuring' \ - CURRENCY: 'EUR' or 'USD' \ - PRICE_ID: ID from stripe interfaces starting with 'price_' \ - """ - pattern.regexp = '^(one_time|recuring)/(EUR|USD)/price_.*$' - pattern.error = "Please respect the format describe in help text for each price ID" diff --git a/scripts/config b/scripts/config index b9e79f8..91c2de7 100644 --- a/scripts/config +++ b/scripts/config @@ -1,12 +1,4 @@ #!/bin/bash -# In simple cases, you don't need a config script. - -# With a simple config_panel.toml, you can write in the app settings, in the -# upstream config file or replace complete files (logo ...) and restart services. - -# The config scripts allows you to go further, to handle specific cases -# (validation of several interdependent fields, specific getter/setter for a value, -# display dynamic informations or choices, pre-loading of config type .cube... ). #================================================= # GENERIC STARTING @@ -14,6 +6,7 @@ # IMPORT GENERIC HELPERS #================================================= +source _common.sh source /usr/share/yunohost/helpers ynh_abort_if_errors @@ -22,81 +15,81 @@ ynh_abort_if_errors # RETRIEVE ARGUMENTS #================================================= -final_path=$(ynh_app_setting_get $app final_path) +phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) +current_fpm_footprint=$(ynh_app_setting_get --app=$app --key=fpm_footprint) #================================================= # SPECIFIC GETTERS FOR TOML SHORT KEY #================================================= -get__amount() { - # Here we can imagine to have an API call to stripe to know the amount of donation during a month - local amount = 200 - - # It's possible to change some properties of the question by overriding it: - if [ $amount -gt 100 ] +get__fpm_footprint() { + # Free footprint value for php-fpm + # Check if current_fpm_footprint is an integer + if [ "$current_fpm_footprint" -eq "$current_fpm_footprint" ] 2> /dev/null then - cat << EOF -style: success -value: $amount -ask: - en: A lot of donation this month: **$amount €** -EOF + echo "specific" else - cat << EOF -style: danger -value: $amount -ask: - en: Not so much donation this month: $amount € -EOF + echo "$current_fpm_footprint" fi } -get__prices() { - local prices = "$(grep "DONATION\['" "$final_path/settings.py" | sed -r "s@^DONATION\['([^']*)'\]\['([^']*)'\] = '([^']*)'@\1/\2/\3@g" | sed -z 's/\n/,/g;s/,$/\n/')" - if [ "$prices" == "," ]; +get__free_footprint() { + # Free footprint value for php-fpm + # Check if current_fpm_footprint is an integer + if [ "$current_fpm_footprint" -eq "$current_fpm_footprint" ] 2> /dev/null then - # Return YNH_NULL if you prefer to not return a value at all. - echo YNH_NULL + # If current_fpm_footprint is an integer, that's a numeric value for the footprint + echo "$current_fpm_footprint" else - echo $prices + echo "0" fi } - -#================================================= -# SPECIFIC VALIDATORS FOR TOML SHORT KEYS -#================================================= -validate__publishable_key() { - - # We can imagine here we test if the key is really a publisheable key - (is_secret_key $publishable_key) && - echo 'This key seems to be a secret key' -} - #================================================= # SPECIFIC SETTERS FOR TOML SHORT KEYS #================================================= -set__prices() { - #--------------------------------------------- - # IMPORTANT: setter are trigger only if a change is detected - #--------------------------------------------- - for price in $(echo $prices | sed "s/,/ /"); do - frequency=$(echo $price | cut -d/ -f1) - currency=$(echo $price | cut -d/ -f2) - price_id=$(echo $price | cut -d/ -f3) - sed "d/DONATION\['$frequency'\]\['$currency'\]" "$final_path/settings.py" +set__fpm_footprint() { + if [ "$fpm_footprint" != "specific" ] + then + ynh_app_setting_set --app=$app --key=fpm_footprint --value="$fpm_footprint" + fi +} - echo "DONATION['$frequency']['$currency'] = '$price_id'" >> "$final_path/settings.py" - done - - #--------------------------------------------- - # IMPORTANT: to be able to upgrade properly, you have to saved the value in settings too - #--------------------------------------------- - ynh_app_setting_set $app prices $prices +set__fpm_free_footprint() { + if [ "$fpm_footprint" = "specific" ] + then + ynh_app_setting_set --app=$app --key=fpm_footprint --value="$fpm_free_footprint" + fi } #================================================= # GENERIC FINALIZATION #================================================= + +ynh_app_config_validate() { + _ynh_app_config_validate + + if [ "${changed[fpm_usage]}" == "true" ] || [ "${changed[fpm_footprint]}" == "true" ] || [ "${changed[fpm_free_footprint]}" == "true" ]; then + # If fpm_footprint is set to 'specific', use $fpm_free_footprint value. + if [ "$fpm_footprint" = "specific" ] + then + fpm_footprint=$fpm_free_footprint + fi + + if [ "$fpm_footprint" == "0" ] + then + ynh_print_err --message="When selecting 'specific', you have to set a footprint value into the field below." + + exit 0 + fi + fi +} + +ynh_app_config_apply() { + _ynh_app_config_apply + + ynh_add_fpm_config --phpversion=$phpversion --usage=$fpm_usage --footprint=$fpm_footprint +} + ynh_app_config_run $1 From e9e6589e6d0679fc098af8d09400ca7d56e1eca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= <46165813+ericgaspar@users.noreply.github.com> Date: Tue, 10 Jan 2023 18:56:13 +0100 Subject: [PATCH 11/14] Fix --- doc/DESCRIPTION.md | 4 ---- doc/DISCLAIMER.md | 4 ---- manifest.json | 9 ++------- scripts/backup | 8 -------- scripts/install | 10 ---------- scripts/remove | 8 -------- scripts/restore | 16 ---------------- scripts/upgrade | 18 ------------------ 8 files changed, 2 insertions(+), 75 deletions(-) diff --git a/doc/DESCRIPTION.md b/doc/DESCRIPTION.md index 966fa82..3f2dfe0 100644 --- a/doc/DESCRIPTION.md +++ b/doc/DESCRIPTION.md @@ -1,5 +1 @@ This is a probe program for PHP environment. It can show your server information and readable easily. - - -[![X Prober preview](https://raw.githubusercontent.com/kmvan/x-prober/master/screenshots/preview.webp)](https://raw.githubusercontent.com/kmvan/x-prober/master/screenshots/preview.webp) - diff --git a/doc/DISCLAIMER.md b/doc/DISCLAIMER.md index 823b22d..3f2dfe0 100644 --- a/doc/DISCLAIMER.md +++ b/doc/DISCLAIMER.md @@ -1,5 +1 @@ This is a probe program for PHP environment. It can show your server information and readable easily. - -more info here: https://github.com/kmvan/x-prober/blob/master/README.md - -Note that the app works only in public mode for now. diff --git a/manifest.json b/manifest.json index 9f1eaa3..728a24a 100644 --- a/manifest.json +++ b/manifest.json @@ -44,13 +44,8 @@ { "name": "is_public", "type": "boolean", - "default": true, - "help": { - "en": "Must be set to public to work for now", - "fr": "Vous devriez le laisser public, ne fonctionne pas en mode privé pour l'instant" - } - } - + "default": true + } ] } } diff --git a/scripts/backup b/scripts/backup index 07bba6a..2efaa42 100755 --- a/scripts/backup +++ b/scripts/backup @@ -55,14 +55,6 @@ ynh_backup --src_path="/etc/nginx/conf.d/$domain.d/$app.conf" ynh_backup --src_path="/etc/php/$phpversion/fpm/pool.d/$app.conf" -#================================================= -# SPECIFIC BACKUP -#================================================= -# BACKUP LOGROTATE -#================================================= - -ynh_backup --src_path="/etc/logrotate.d/$app" - #================================================= # END OF SCRIPT #================================================= diff --git a/scripts/install b/scripts/install index 0dd8691..5052f2e 100755 --- a/scripts/install +++ b/scripts/install @@ -96,16 +96,6 @@ ynh_script_progression --message="Configuring NGINX web server..." --weight=1 # Create a dedicated NGINX config ynh_add_nginx_config -#================================================= -# GENERIC FINALIZATION -#================================================= -# SETUP LOGROTATE -#================================================= -ynh_script_progression --message="Configuring log rotation..." --weight=1 - -# Use logrotate to manage application logfile(s) -ynh_use_logrotate - #================================================= # SETUP SSOWAT #================================================= diff --git a/scripts/remove b/scripts/remove index 61b33eb..4a7848b 100755 --- a/scripts/remove +++ b/scripts/remove @@ -19,14 +19,6 @@ app=$YNH_APP_INSTANCE_NAME domain=$(ynh_app_setting_get --app=$app --key=domain) final_path=$(ynh_app_setting_get --app=$app --key=final_path) -#================================================= -# REMOVE LOGROTATE CONFIGURATION -#================================================= -ynh_script_progression --message="Removing logrotate configuration..." --weight=1 - -# Remove the app-specific logrotate config -ynh_remove_logrotate - #================================================= # REMOVE APP MAIN DIR #================================================= diff --git a/scripts/restore b/scripts/restore index 1c40374..900c312 100755 --- a/scripts/restore +++ b/scripts/restore @@ -44,15 +44,6 @@ ynh_script_progression --message="Validating restoration parameters..." --weight test ! -d $final_path \ || ynh_die --message="There is already a directory: $final_path " -#================================================= -# STANDARD RESTORATION STEPS -#================================================= -# REINSTALL DEPENDENCIES -#================================================= -ynh_script_progression --message="Reinstalling dependencies..." --weight=2 - -ynh_install_app_dependencies - #================================================= # RESTORE THE NGINX CONFIGURATION #================================================= @@ -89,13 +80,6 @@ ynh_restore_file --origin_path="/etc/php/$phpversion/fpm/pool.d/$app.conf" # Recreate a dedicated php-fpm config ynh_add_fpm_config --usage=$fpm_usage --footprint=$fpm_footprint --phpversion=$phpversion -#================================================= -# RESTORE THE LOGROTATE CONFIGURATION -#================================================= -ynh_script_progression --message="Restoring the logrotate configuration..." --weight=1 - -ynh_restore_file --origin_path="/etc/logrotate.d/$app" - #================================================= # GENERIC FINALIZATION #================================================= diff --git a/scripts/upgrade b/scripts/upgrade index 9ac2ace..4b61a09 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -83,14 +83,6 @@ ynh_script_progression --message="Making sure dedicated system user exists..." - # Create a dedicated user (if not existing) ynh_system_user_create --username=$app --home_dir="$final_path" -#================================================= -# REINSTALL DEPENDENCIES -#================================================= - -ynh_script_progression --message="Reinstalling dependencies..." --weight=2 - -ynh_install_app_dependencies "php${phpversion}-fpm" - #================================================= # DOWNLOAD, CHECK AND UNPACK SOURCE #================================================= @@ -124,16 +116,6 @@ ynh_script_progression --message="Upgrading NGINX web server configuration..." - # Create a dedicated NGINX config ynh_add_nginx_config -#================================================= -# GENERIC FINALIZATION -#================================================= -# SETUP LOGROTATE -#================================================= -ynh_script_progression --message="Upgrading logrotate configuration..." --weight=1 - -# Use logrotate to manage app-specific logfile(s) -ynh_use_logrotate --non-append - #================================================= # RELOAD NGINX #================================================= From 2a18cf2820ecee5f9e4a635c2cdbe90717fc8cb5 Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Tue, 10 Jan 2023 17:56:18 +0000 Subject: [PATCH 12/14] Auto-update README --- README.md | 8 -------- README_fr.md | 8 -------- 2 files changed, 16 deletions(-) diff --git a/README.md b/README.md index 3a9d307..6300f1d 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,6 @@ If you don't have YunoHost, please consult [the guide](https://yunohost.org/#/in This is a probe program for PHP environment. It can show your server information and readable easily. -[![X Prober preview](https://raw.githubusercontent.com/kmvan/x-prober/master/screenshots/preview.webp)](https://raw.githubusercontent.com/kmvan/x-prober/master/screenshots/preview.webp) - - - **Shipped version:** 8.16~ynh1 **Demo:** https://prober.inn-studio.com/ @@ -34,10 +30,6 @@ This is a probe program for PHP environment. It can show your server information This is a probe program for PHP environment. It can show your server information and readable easily. -more info here: https://github.com/kmvan/x-prober/blob/master/README.md - -Note that the app works only in public mode for now. - ## Documentation and resources * Official app website: diff --git a/README_fr.md b/README_fr.md index 21ded4b..8744e40 100644 --- a/README_fr.md +++ b/README_fr.md @@ -18,10 +18,6 @@ Si vous n'avez pas YunoHost, regardez [ici](https://yunohost.org/#/install) pour This is a probe program for PHP environment. It can show your server information and readable easily. -[![X Prober preview](https://raw.githubusercontent.com/kmvan/x-prober/master/screenshots/preview.webp)](https://raw.githubusercontent.com/kmvan/x-prober/master/screenshots/preview.webp) - - - **Version incluse :** 8.16~ynh1 **Démo :** https://prober.inn-studio.com/ @@ -34,10 +30,6 @@ This is a probe program for PHP environment. It can show your server information This is a probe program for PHP environment. It can show your server information and readable easily. -more info here: https://github.com/kmvan/x-prober/blob/master/README.md - -Note that the app works only in public mode for now. - ## Documentations et ressources * Site officiel de l'app : From af3c35438b53280f81411fbf95bd578839ab5e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= <46165813+ericgaspar@users.noreply.github.com> Date: Tue, 10 Jan 2023 21:16:54 +0100 Subject: [PATCH 13/14] Update install --- scripts/install | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/install b/scripts/install index 5052f2e..6a3b195 100755 --- a/scripts/install +++ b/scripts/install @@ -27,6 +27,7 @@ ynh_abort_if_errors domain=$YNH_APP_ARG_DOMAIN path_url=$YNH_APP_ARG_PATH is_public=$YNH_APP_ARG_IS_PUBLIC +phpversion=$YNH_PHP_VERSION app=$YNH_APP_INSTANCE_NAME From ec7d9403a4c1e03a76a23b577f191902f77e1ae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= <46165813+ericgaspar@users.noreply.github.com> Date: Fri, 20 Jan 2023 20:16:06 +0100 Subject: [PATCH 14/14] Fix --- doc/DISCLAIMER.md | 1 - scripts/install | 1 - 2 files changed, 2 deletions(-) diff --git a/doc/DISCLAIMER.md b/doc/DISCLAIMER.md index 3f2dfe0..e69de29 100644 --- a/doc/DISCLAIMER.md +++ b/doc/DISCLAIMER.md @@ -1 +0,0 @@ -This is a probe program for PHP environment. It can show your server information and readable easily. diff --git a/scripts/install b/scripts/install index 6a3b195..5052f2e 100755 --- a/scripts/install +++ b/scripts/install @@ -27,7 +27,6 @@ ynh_abort_if_errors domain=$YNH_APP_ARG_DOMAIN path_url=$YNH_APP_ARG_PATH is_public=$YNH_APP_ARG_IS_PUBLIC -phpversion=$YNH_PHP_VERSION app=$YNH_APP_INSTANCE_NAME