From d432402b1f0a20dab0c850fb7e828747dc0d1ece Mon Sep 17 00:00:00 2001 From: yalh76 Date: Sun, 27 Feb 2022 23:22:06 +0100 Subject: [PATCH 01/13] Apply last example_ynh --- .github/ISSUE_TEMPLATE.md | 55 ++++++++ .github/PULL_REQUEST_TEMPLATE.md | 16 +++ .gitignore | 2 - DEV-v1-staging.md | 19 --- check_process | 25 ++++ check_process.default | 40 ------ conf/app.src | 6 - conf/nginx.conf | 16 +-- conf/systemd.service | 17 --- test => doc/.gitkeep | 0 doc/DESCRIPTION.md | 12 ++ doc/DISCLAIMER.md | 1 + doc/screenshots/.gitkeep | 0 doc/screenshots/screenshot1.png | Bin 0 -> 85871 bytes manifest.json | 45 +++---- pull_request_template.md | 18 --- scripts/_common.sh | 40 +----- scripts/backup | 59 ++------- scripts/change_url | 64 ++++++--- scripts/install | 201 ++++++++++++++--------------- scripts/remove | 76 +++++------ scripts/restore | 93 ++++++------- scripts/upgrade | 169 ++++++++---------------- scripts/ynh_add_extra_apt_repos | 88 ------------- sources/extra_files/app/.gitignore | 2 - sources/patches/.gitignore | 2 - 26 files changed, 415 insertions(+), 651 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md delete mode 100644 .gitignore delete mode 100644 DEV-v1-staging.md create mode 100644 check_process delete mode 100644 check_process.default delete mode 100644 conf/app.src delete mode 100644 conf/systemd.service rename test => doc/.gitkeep (100%) create mode 100644 doc/DESCRIPTION.md create mode 100644 doc/DISCLAIMER.md create mode 100644 doc/screenshots/.gitkeep create mode 100644 doc/screenshots/screenshot1.png delete mode 100644 pull_request_template.md delete mode 100644 scripts/ynh_add_extra_apt_repos delete mode 100644 sources/extra_files/app/.gitignore delete mode 100644 sources/patches/.gitignore diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..2729a6b --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,55 @@ +--- +name: Bug report +about: When creating a bug report, please use the following template to provide all the relevant information and help debugging efficiently. + +--- + +**How to post a meaningful bug report** +1. *Read this whole template first.* +2. *Determine if you are on the right place:* + - *If you were performing an action on the app from the webadmin or the CLI (install, update, backup, restore, change_url...), you are on the right place!* + - *Otherwise, the issue may be due to the app itself. Refer to its documentation or repository for help.* + - *When in doubt, post here and we will figure it out together.* +3. *Delete the italic comments as you write over them below, and remove this guide.* +--- + +### Describe the bug + +*A clear and concise description of what the bug is.* + +### Context + +- Hardware: *VPS bought online / Old laptop or computer / Raspberry Pi at home / Internet Cube with VPN / Other ARM board / ...* +- YunoHost version: x.x.x +- I have access to my server: *Through SSH | through the webadmin | direct access via keyboard / screen | ...* +- Are you in a special context or did you perform some particular tweaking on your YunoHost instance?: *no / yes* + - If yes, please explain: +- Using, or trying to install package version/branch: +- If upgrading, current package version: *can be found in the admin, or with `yunohost app info $app_id`* + +### Steps to reproduce + +- *If you performed a command from the CLI, the command itself is enough. For example:* + ```sh + sudo yunohost app install the_app + ``` +- *If you used the webadmin, please perform the equivalent command from the CLI first.* +- *If the error occurs in your browser, explain what you did:* + 1. *Go to '...'* + 2. *Click on '...'* + 3. *Scroll down to '...'* + 4. *See error* + +### Expected behavior + +*A clear and concise description of what you expected to happen. You can remove this section if the command above is enough to understand your intent.* + +### Logs + +*When an operation fails, YunoHost provides a simple way to share the logs.* +- *In the webadmin, the error message contains a link to the relevant log page. On that page, you will be able to 'Share with Yunopaste'. If you missed it, the logs of previous operations are also available under Tools > Logs.* +- *In command line, the command to share the logs is displayed at the end of the operation and looks like `yunohost log display [log name] --share`. If you missed it, you can find the log ID of a previous operation using `yunohost log list`.* + +*After sharing the log, please copypaste directly the link provided by YunoHost (to help readability, no need to copypaste the entire content of the log here, just the link is enough...)* + +*If applicable and useful, add screenshots to help explain your problem.* diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..ef70e18 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,16 @@ +## Problem + +- *Description of why you made this PR* + +## Solution + +- *And how do you fix that problem* + +## PR Status + +- [ ] Code finished and ready to be reviewed/tested +- [ ] The fix/enhancement were manually tested (if applicable) + +## Automatic tests + +Automatic tests can be triggered on https://ci-apps-dev.yunohost.org/ *after creating the PR*, by commenting "!testme", "!gogogadgetoci" or "By the power of systemd, I invoke The Great App CI to test this Pull Request!". (N.B. : for this to work you need to be a member of the Yunohost-Apps organization) diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 783a4ae..0000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*~ -*.sw[op] diff --git a/DEV-v1-staging.md b/DEV-v1-staging.md deleted file mode 100644 index e42772d..0000000 --- a/DEV-v1-staging.md +++ /dev/null @@ -1,19 +0,0 @@ -# What it takes to go to v1 - -Package will be in v1 and in "working" conditions in Yunohost-Apps when: - -- [x] All codes will be finished -- [x] First bash review performed -- [x] Reviewed with package-linter -- [ ] Remove all the TODOs -- [ ] CI tested on vagrant : install -- [ ] Remove tested : nothing must be left -- [ ] Quiet-ize installer -- [ ] Measure timing of installer to bring proper weight - -And some breadcrumbs: -- [x] change way to install ruby with crappy `rbenv` -- [x] Remove: if the PostgreSQL is empty, remove it ==> NOT APPLICABLE ANYMORE -- [ ] fully remove `/var/$app` (ynh helper crappy?) - -Goal of full-quality :) diff --git a/check_process b/check_process new file mode 100644 index 0000000..a824d32 --- /dev/null +++ b/check_process @@ -0,0 +1,25 @@ +;; Test complet + ; Manifest + domain="domain.tld" + language="fr" + is_public=1 + ; Checks + pkg_linter=1 + setup_sub_dir=1 + setup_root=1 + setup_nourl=0 + setup_private=1 + setup_public=1 + upgrade=1 + #upgrade=1 from_commit=CommitHash + backup_restore=1 + multi_instance=0 + 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&admin=USER&language=fr&is_public=1&password=pass&port=666& diff --git a/check_process.default b/check_process.default deleted file mode 100644 index 97a2bc5..0000000 --- a/check_process.default +++ /dev/null @@ -1,40 +0,0 @@ -# See here for more information -# https://github.com/YunoHost/package_check#syntax-check_process-file - -# Move this file from check_process.default to check_process when you have filled it. - -;; Test complet - ; Manifest - domain="domain.tld" (DOMAIN) - path="/path" (PATH) - admin="john" (USER) - language="fr" - is_public=1 (PUBLIC|public=1|private=0) - password="pass" - port="666" (PORT) - ; Checks - pkg_linter=1 - setup_sub_dir=1 - setup_root=1 - setup_nourl=0 - setup_private=1 - setup_public=1 - upgrade=1 - upgrade=1 from_commit=CommitHash - backup_restore=1 - multi_instance=1 - # This test is no longer necessary since the version 2.7 (PR: https://github.com/YunoHost/yunohost/pull/304), you can still do it if your app could be installed with this version. - # incorrect_path=1 - port_already_use=0 - change_url=1 -;;; Levels - # If the level 5 (Package linter) is forced to 1. Please add justifications here. - Level 5=auto -;;; Options -Email= -Notification=none -;;; Upgrade options - ; commit=CommitHash - name=Name and date of the commit. - manifest_arg=domain=DOMAIN&path=PATH&admin=USER&language=fr&is_public=1&password=pass&port=666& - diff --git a/conf/app.src b/conf/app.src deleted file mode 100644 index 2e37ed0..0000000 --- a/conf/app.src +++ /dev/null @@ -1,6 +0,0 @@ -SOURCE_URL=https://github.com/opf/openproject/archive/v10.5.1.zip -SOURCE_SUM=38d07c757112ef9445ac6278f1963d0021d5c01e09958719896a51ee95b64c45 -SOURCE_SUM_PRG=sha256sum -SOURCE_FORMAT=zip -SOURCE_IN_SUBDIR=true -SOURCE_FILENAME=openproject-10.5.1.zip diff --git a/conf/nginx.conf b/conf/nginx.conf index 5367aaa..6d1ce25 100644 --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -1,18 +1,14 @@ #sub_path_only rewrite ^__PATH__$ __PATH__/ permanent; location __PATH__/ { - # Force usage of https - - if ($scheme = http) { - rewrite ^ https://$server_name$request_uri? permanent; - } - proxy_pass http://127.0.0.1:__PORT__/; proxy_set_header Host $host; - proxy_buffering off; - tcp_nodelay on; - access_log off; - proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host:$server_port; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Forwarded-Server $host:$server_port; + proxy_read_timeout 1200s; # Include SSOWAT user panel. include conf.d/yunohost_panel.conf.inc; diff --git a/conf/systemd.service b/conf/systemd.service deleted file mode 100644 index cb5e91b..0000000 --- a/conf/systemd.service +++ /dev/null @@ -1,17 +0,0 @@ -[Unit] -Description=Launches Application server for OpenProject Rails project -After=network.target - -[Service] -Type=simple -User=__APP__ -Group=__APP__ -WorkingDirectory=__FINALPATH__/ -Environment=RAILS_ENV=production - -ExecStart=/usr/local/bin/bundle exec puma -t 5:5 -p ${PORT:-__PORT__} -e ${RACK_ENV:-production} >> /var/log/__APP__/__APP__.log 2>&1 - -Restart=always - -[Install] -WantedBy=multi-user.target diff --git a/test b/doc/.gitkeep similarity index 100% rename from test rename to doc/.gitkeep diff --git a/doc/DESCRIPTION.md b/doc/DESCRIPTION.md new file mode 100644 index 0000000..ada70da --- /dev/null +++ b/doc/DESCRIPTION.md @@ -0,0 +1,12 @@ +## Overview +OpenProject is a web-based project management software. Its key features are: + +- Project planning and scheduling +- Product roadmap and release planning +- Task management and team collaboration +- Agile and Scrum +- Time tracking, cost reporting and budgeting +- Bug tracking +- Wikis +- Forums +- Meeting agendas and meeting minutes diff --git a/doc/DISCLAIMER.md b/doc/DISCLAIMER.md new file mode 100644 index 0000000..fe93246 --- /dev/null +++ b/doc/DISCLAIMER.md @@ -0,0 +1 @@ +* default user and password is admin / admin \ No newline at end of file diff --git a/doc/screenshots/.gitkeep b/doc/screenshots/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/doc/screenshots/screenshot1.png b/doc/screenshots/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..7bf9a1a7a13e1e6f751b75cbb3a375c8e8f4c1ce GIT binary patch literal 85871 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

u_Z|u{q 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 3.6" + "yunohost": ">= 4.3.0" }, "multi_instance": false, "services": [ - "nginx", - "php7.0-fpm", - "mysql" + "nginx" ], "arguments": { - "install" : [ + "install": [ { "name": "domain", - "type": "domain", - "ask": { - "en": "Choose a domain name for openproject", - "fr": "Choisissez un nom de domaine pour openproject" - }, - "example": "example.com" - }, - { - "name": "path", - "type": "path", - "ask": { - "en": "Choose a path for openproject", - "fr": "Choisissez un chemin pour openproject" - }, - "example": "/openproject", - "default": "/openproject" + "type": "domain" }, { "name": "is_public", "type": "boolean", - "ask": { - "en": "Is it a public application?", - "fr": "Est-ce une application publique ?" - }, "default": true, - "help": { + "help": { "en": "A public Openproject app could be less secure depending your configuration. Butit can allow external people from your Yunohost instance to participate to project management.", "fr": "Une instance publique de YunoHost peut-être moins sécurisée mais peut permettre à des personnes externes à l'instance YunoHost de participer à votre projet (invité)" - } + } }, { "name": "language", diff --git a/pull_request_template.md b/pull_request_template.md deleted file mode 100644 index 58353aa..0000000 --- a/pull_request_template.md +++ /dev/null @@ -1,18 +0,0 @@ -## Problem -- *Description of why you made this PR* - -## Solution -- *And how do you fix that problem* - -## PR Status -- [x] Code finished. -- [x] Tested with Package_check. -- [ ] Fix or enhancement tested. -- [ ] Upgrade from last version tested. -- [ ] Can be reviewed and tested. - -## Package_check results ---- -*If you have access to [App Continuous Integration for packagers](https://yunohost.org/#/packaging_apps_ci) you can provide a link to the package_check results like below, replacing '-NUM-' in this link by the PR number and USERNAME by your username on the ci-apps-dev. Or you provide a screenshot or a pastebin of the results* - -[![Build Status](https://ci-apps-dev.yunohost.org/jenkins/job/APP_ynh%20PR-NUM-%20(USERNAME)/badge/icon)](https://ci-apps-dev.yunohost.org/jenkins/job/APP_ynh%20PR-NUM-%20(USERNAME)/) diff --git a/scripts/_common.sh b/scripts/_common.sh index 66b9a90..81eb56a 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -4,52 +4,20 @@ # COMMON VARIABLES #================================================= +PROJECT_VERSION=12 + # dependencies used by the app -export pkg_dependencies="apt-transport-https memcached openproject postgresql postgresql-common" +pkg_dependencies="apt-transport-https memcached postgresql postgresql-common" +extra_pkg_dependencies="openproject" #================================================= # PERSONAL HELPERS #================================================= -# Checks if string existin a file, or add it. -ynh_string_in_file () { -# Declare an array to define the options of this helper. - local legacy_args=msf - declare -Ar args_array=( [m]=match_string= [s]=string= [f]=target_file= ) - local match_string - local string - local target_file - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - - local delimit=@ - # Escape the delimiter if it's in the string. - if grep "$match_string" $target_file; then - else - echo $string > - fi -} - #================================================= # EXPERIMENTAL HELPERS #================================================= -source ynh_add_extra_apt_repos - -# Execute a command as another user -# usage: ynh_exec_as USER COMMAND [ARG ...] -ynh_exec_as() { - local USER=$1 - shift 1 - - if [[ $USER = $(whoami) ]]; then - eval "$@" - else - # use sudo twice to be root and be allowed to use another user - sudo sudo -u "$USER" "$@" - fi -} - #================================================= # FUTURE OFFICIAL HELPERS #================================================= diff --git a/scripts/backup b/scripts/backup index 8f2e7a7..55b01cb 100755 --- a/scripts/backup +++ b/scripts/backup @@ -6,7 +6,7 @@ # IMPORT GENERIC HELPERS #================================================= -#Keep this path for calling _common.sh inside the execution's context of backup and restore scripts +# Keep this path for calling _common.sh inside the execution's context of backup and restore scripts source ../settings/scripts/_common.sh source /usr/share/yunohost/helpers @@ -14,83 +14,50 @@ source /usr/share/yunohost/helpers # MANAGE SCRIPT FAILURE #================================================= +ynh_clean_setup () { + true +} # Exit if an error occurs during the execution of the script ynh_abort_if_errors #================================================= # LOAD SETTINGS #================================================= -ynh_script_progression --message="Loading installation settings..." --time --weight=1 +ynh_print_info --message="Loading installation settings..." app=$YNH_APP_INSTANCE_NAME -final_path=$(ynh_app_setting_get --app="$app" --key=final_path) -domain=$(ynh_app_setting_get --app="$app" --key=domain) -db_name=$(ynh_app_setting_get --app="$app" --key=db_name) +domain=$(ynh_app_setting_get --app=$app --key=domain) +db_name=$(ynh_app_setting_get --app=$app --key=db_name) #================================================= -# STANDARD BACKUP STEPS +# DECLARE DATA AND CONF FILES TO BACKUP #================================================= -# STOP SYSTEMD SERVICE -#================================================= -ynh_script_progression --message="Stopping a systemd service..." --time --weight=1 - -ynh_systemd_action --service_name="$app" --action="stop" --log_path="/var/log/$app/$app.log" - -#================================================= -# BACKUP THE APP MAIN DIR -#================================================= -ynh_script_progression --message="Backing up the main app directory..." --time --weight=1 - -ynh_backup --src_path="$final_path" +ynh_print_info --message="Declaring files to be backed up..." #================================================= # BACKUP THE NGINX CONFIGURATION #================================================= -ynh_script_progression --message="Backing up nginx web server configuration..." --time --weight=1 ynh_backup --src_path="/etc/nginx/conf.d/$domain.d/$app.conf" -#================================================= -# BACKUP THE POSTGRESQL DATABASE -#================================================= -ynh_script_progression --message="Backing up the PostgreSQL database..." --time --weight=1 - -ynh_psql_dump_db -d "$db_name" > db.postgres - -#================================================= -# BACKUP FAIL2BAN CONFIGURATION -#================================================= -ynh_script_progression --message="Backing up fail2ban configuration..." --time --weight=1 - -ynh_backup --src_path="/etc/fail2ban/jail.d/$app.conf" -ynh_backup --src_path="/etc/fail2ban/filter.d/$app.conf" - #================================================= # SPECIFIC BACKUP -#================================================= -# BACKUP LOGROTATE -#================================================= -ynh_script_progression --message="Backing up logrotate configuration..." --time --weight=1 - -ynh_backup --src_path="/etc/logrotate.d/$app" - #================================================= # BACKUP SYSTEMD #================================================= -ynh_script_progression --message="Backing up systemd configuration..." --time --weight=1 ynh_backup --src_path="/etc/systemd/system/$app.service" #================================================= -# START SYSTEMD SERVICE +# BACKUP THE POSTGRESQL DATABASE #================================================= -ynh_script_progression --message="Starting a systemd service..." --time --weight=1 +ynh_print_info --message="Backing up the PostgreSQL database..." -ynh_systemd_action --service_name="$app" --action="start" --log_path="/var/log/$app/$app.log" +ynh_psql_dump_db --database="$db_name" > db.postgres #================================================= # END OF SCRIPT #================================================= -ynh_script_progression --message="Backup script completed for $app. (YunoHost will then actually copy those files to the archive)." --time --last +ynh_print_info --message="Backup script completed for $app. (YunoHost will then actually copy those files to the archive)." diff --git a/scripts/change_url b/scripts/change_url index 9f1b072..cf6bc18 100755 --- a/scripts/change_url +++ b/scripts/change_url @@ -17,20 +17,35 @@ old_domain=$YNH_APP_OLD_DOMAIN old_path=$YNH_APP_OLD_PATH new_domain=$YNH_APP_NEW_DOMAIN -new_path=$YNH_APP_NEW_PATH +new_path="/" app=$YNH_APP_INSTANCE_NAME #================================================= # LOAD SETTINGS #================================================= -ynh_script_progression --message="Loading installation settings..." --time --weight=1 +ynh_script_progression --message="Loading installation settings..." # Needed for helper "ynh_add_nginx_config" -final_path=$(ynh_app_setting_get --app="$app" --key=final_path) -export final_path -port=$(ynh_app_setting_get --app="$app" --key=port) -export port +port=$(ynh_app_setting_get --app=$app --key=port) + +#================================================= +# BACKUP BEFORE CHANGE URL THEN ACTIVE TRAP +#================================================= +ynh_script_progression --message="Backing up the app before changing its URL (may take a while)..." + +# Backup the current version of the app +ynh_backup_before_upgrade +ynh_clean_setup () { + ynh_clean_check_starting + # Remove the new domain config file, the remove script won't do it as it doesn't know yet its location. + ynh_secure_remove --file="/etc/nginx/conf.d/$new_domain.d/$app.conf" + + # Restore it if the upgrade fails + ynh_restore_upgradebackup +} +# Exit if an error occurs during the execution of the script +ynh_abort_if_errors #================================================= # CHECK WHICH PARTS SHOULD BE CHANGED @@ -50,41 +65,56 @@ fi #================================================= # STANDARD MODIFICATIONS +#================================================= +# STOP SYSTEMD SERVICE +#================================================= +ynh_script_progression --message="Stopping a systemd service..." + +ynh_systemd_action --service_name=$app --action="stop" --log_path="systemd" + #================================================= # MODIFY URL IN NGINX CONF #================================================= -ynh_script_progression --message="Updating nginx web server configuration..." --time --weight=1 +ynh_script_progression --message="Updating NGINX web server configuration..." nginx_conf_path=/etc/nginx/conf.d/$old_domain.d/$app.conf -# Change the path in the nginx config file +# Change the path in the NGINX config file if [ $change_path -eq 1 ] then - # Make a backup of the original nginx config file if modified + # Make a backup of the original NGINX config file if modified ynh_backup_if_checksum_is_different --file="$nginx_conf_path" - # Set global variables for nginx helper - export domain="$old_domain" - export path_url="$new_path" - # Create a dedicated nginx config + # Set global variables for NGINX helper + domain="$old_domain" + path_url="$new_path" + # Create a dedicated NGINX config ynh_add_nginx_config fi -# Change the domain for nginx +# Change the domain for NGINX if [ $change_domain -eq 1 ] then # Delete file checksum for the old conf file location ynh_delete_file_checksum --file="$nginx_conf_path" - mv "$nginx_conf_path" "/etc/nginx/conf.d/$new_domain.d/$app.conf" + mv $nginx_conf_path /etc/nginx/conf.d/$new_domain.d/$app.conf # Store file checksum for the new config file location ynh_store_file_checksum --file="/etc/nginx/conf.d/$new_domain.d/$app.conf" fi #================================================= # GENERIC FINALISATION +#================================================= +# START SYSTEMD SERVICE +#================================================= +ynh_script_progression --message="Starting a systemd service..." + +# Start a systemd service +ynh_systemd_action --service_name=$app --action="start" --log_path="systemd" + #================================================= # RELOAD NGINX #================================================= -ynh_script_progression --message="Reloading nginx web server..." --time --weight=1 +ynh_script_progression --message="Reloading NGINX web server..." ynh_systemd_action --service_name=nginx --action=reload @@ -92,4 +122,4 @@ ynh_systemd_action --service_name=nginx --action=reload # END OF SCRIPT #================================================= -ynh_script_progression --message="Change of URL completed for $app" --time --last +ynh_script_progression --message="Change of URL completed for $app" diff --git a/scripts/install b/scripts/install index e7e9e25..1da43bd 100755 --- a/scripts/install +++ b/scripts/install @@ -3,105 +3,115 @@ #================================================= # GENERIC START #================================================= +# IMPORT GENERIC HELPERS +#================================================= source _common.sh source /usr/share/yunohost/helpers +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +ynh_clean_setup () { + ynh_clean_check_starting +} # Exit if an error occurs during the execution of the script ynh_abort_if_errors #================================================= -# Dealing with script's variables +# RETRIEVE ARGUMENTS FROM THE MANIFEST #================================================= -# Note: variables are stored in a single location to avoid confusion -# and declaration sequencing issues. -# Arguments from Manifest + domain=$YNH_APP_ARG_DOMAIN -path_url=$YNH_APP_ARG_PATH +path_url="/" is_public=$YNH_APP_ARG_IS_PUBLIC language=$YNH_APP_ARG_LANGUAGE + app=$YNH_APP_INSTANCE_NAME # Installer variables -db_name=$(ynh_sanitize_dbid --db_name="$app") -db_pwd=$(ynh_string_random) # Generate a random password -db_user=$db_name -final_path="/var/www/$app" _homedir="/var/$app/" -_openproject_install_dat="/etc/openproject/installer.dat" - #================================================= # CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS #================================================= -ynh_script_progression --message="Validating installation parameters..." --weight=1 - -test ! -e "$final_path" || ynh_die --message="This path already contains a folder" - -# Find a free port. -# This will only be used: -# - By OpenProject to fire app server listening to this port, and -# - Nginx to proxify on this. -port=$(ynh_find_port --port=6000) +ynh_script_progression --message="Validating installation parameters..." # Register (book) web path -ynh_webpath_register --app="$app" --domain="$domain" --path_url="$path_url" +ynh_webpath_register --app=$app --domain=$domain --path_url=$path_url #================================================= # STORE SETTINGS FROM MANIFEST #================================================= -ynh_script_progression --message="Storing installation settings..." --weight=1 +ynh_script_progression --message="Storing installation settings..." -ynh_app_setting_set --app="$app" --key=db_name --value="$db_name" -ynh_app_setting_set --app="$app" --key=db_pwd --value="$db_pwd" -ynh_app_setting_set --app="$app" --key=domain --value="$domain" -ynh_app_setting_set --app="$app" --key=final_path --value="$final_path" -ynh_app_setting_set --app="$app" --key=homedir --value="$_homedir" -ynh_app_setting_set --app="$app" --key=is_public --value="$is_public" -ynh_app_setting_set --app="$app" --key=language --value="$language" -ynh_app_setting_set --app="$app" --key=path --value="$path_url" -ynh_app_setting_set --app="$app" --key=port --value="$port" - -# Make app public if necessary -[ "$is_public" -eq 1 ] && ynh_app_setting_set --app="$app" --key=unprotected_uris --value="/" +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=language --value=$language +ynh_app_setting_set --app=$app --key=_homedir --value=$_homedir #================================================= -# ENVIRONMENT SETUP +# STANDARD MODIFICATIONS #================================================= -# Note: it follows: https://www.openproject.org/download-and-installation/ +# FIND AND OPEN A PORT +#================================================= +ynh_script_progression --message="Finding an available port..." -#================================================= -# CREATE DEDICATED USER -#================================================= -ynh_script_progression --message="Configuring system user..." --weight=1 -ynh_system_user_create --username="$app" --home_dir="$_homedir" -s +# Find an available port +port=$(ynh_find_port --port=8095) +ynh_app_setting_set --app=$app --key=port --value=$port #================================================= # INSTALL DEPENDENCIES #================================================= -ynh_script_progression --message="Installing OpenProject & its dependencies..." --weight=1 +ynh_script_progression --message="Installing OpenProject & its dependencies..." -# Add Openproject Key & repo -# Var APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE to disable the STDOUT redirection warning -wget -qO- https://dl.packager.io/srv/opf/openproject/key | APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add - >/dev/null -wget -qO /etc/apt/sources.list.d/openproject.list https://dl.packager.io/srv/opf/openproject/stable/10/installer/debian/9.repo +debian_release=$(lsb_release -r -s) +ynh_install_app_dependencies $pkg_dependencies +ynh_install_extra_app_dependencies --repo="deb https://dl.packager.io/srv/deb/opf/openproject/stable/$PROJECT_VERSION/debian $debian_release main" --package="$extra_pkg_dependencies" --key="https://dl.packager.io/srv/opf/openproject/key" -ynh_install_app_dependencies "$pkg_dependencies" >> "$YNH_STDINFO" +#================================================= +# CREATE DEDICATED USER +#================================================= +ynh_script_progression --message="Configuring system user..." + +# Create a system user +ynh_system_user_create --username=$app + +#================================================= +# CREATE A POSTGRESQL DATABASE +#================================================= +ynh_script_progression --message="Creating a PostgreSQL database..." + +ynh_psql_test_if_first_run + +db_name=$(ynh_sanitize_dbid --db_name=$app) +db_user=$db_name +ynh_app_setting_set --app=$app --key=db_name --value=$db_name +ynh_psql_setup_db --db_user=$db_user --db_name=$db_name +db_pwd=$(ynh_app_setting_get --app=$app --key=psqlpwd) #================================================= # NGINX CONFIGURATION #================================================= -ynh_script_progression --message="Configuring nginx web server..." --weight=1 +ynh_script_progression --message="Configuring NGINX web server..." +# Create a dedicated NGINX config ynh_add_nginx_config +#================================================= +# SPECIFIC SETUP #================================================= # OPENPROJECT CONFIGURATION #================================================= -ynh_script_progression --message="Configuring OpenProject..." --weight=1 +ynh_script_progression --message="Configuring OpenProject..." + +mkdir -p "/etc/openproject/" +_openproject_install_dat="/etc/openproject/installer.dat" #TODO Not sure about this email sending. To be tested. -cat >> "$_openproject_install_dat" << EOF +cat >> "$_openproject_install_dat"<< EOF postgres/autoinstall reuse postgres/db_host 127.0.0.1 postgres/db_port 5432 @@ -109,6 +119,8 @@ postgres/db_username $db_user postgres/db_password $db_pwd postgres/db_name $db_name server/autoinstall skip +server/hostname $domain +server/protocol HTTPS smtp/autoinstall smtp smtp/authentication none smtp/host 127.0.0.1 @@ -123,86 +135,65 @@ EOF ynh_store_file_checksum --file="$_openproject_install_dat" +chmod 750 "/etc/openproject/" +chmod -R o-rwx "/etc/openproject/" +chown -R $app:$app "/etc/openproject/" -ynh_replace_string --match_string=".*PORT=.*" --replace_string="export PORT=$port" --target_file="/etc/default/openproject" +#ynh_replace_string --match_string=".*PORT=.*" --replace_string="export PORT=$port" --target_file="/etc/default/openproject" +#echo $app $app/port select $port | debconf-set-selections +#openproject config:set PORT $port -#================================================= -# CREATE A POSTGRESQL DATABASE -#================================================= -ynh_script_progression --message="Creating a PostgreSQL database..." --weight=1 - -ynh_psql_create_user "$db_user" "$db_pwd" -ynh_psql_create_db "$db_name" "$db_user" "$db_pwd" - -#================================================= -# OPENPROJECT POST-INSTALL -#================================================= -# Note: This section is undocumented on the installer. - -ynh_script_progression --message="Post-install of OpenProject" --weight=1 +openproject config:set PORT=$port +openproject config:set SERVER_PROTOCOL_FORCE_HTTPS="true" +openproject config:set SERVER_HOSTNAME=$domain +openproject config:set SERVER_PATH_PREFIX=$path_url openproject configure >> "$YNH_STDINFO" -####================================================= -#### SETUP APPLICATION WITH CURL -####================================================= -### -#### Set the app as temporarily public for curl call -###ynh_script_progression --message="Configuring SSOwat..." --weight=1 -###ynh_app_setting_set --app="$app" --key=skipped_uris --value="/" -#### Reload SSOwat config -###yunohost app ssowatconf -### -#### Reload Nginx -###ynh_systemd_action --service_name=nginx --action=reload -### -##### TODO REMOVE ? # Installation with curl -##### TODO REMOVE ? ynh_script_progression --message="Finalizing installation..." --weight=1 -##### TODO REMOVE ? ynh_local_curl "/INSTALL_PATH" "key1=value1" "key2=value2" "key3=value3" -### -#### Remove the public access -###if [ $is_public -eq 0 ] -###then -### ynh_app_setting_delete --app="$app" --key=skipped_uris -###fi +#ynh_replace_string --match_string="default: localhost:3000" --replace_string="default: $domain" --target_file="/opt/openproject/config/settings.yml" +#ynh_replace_string --match_string="default: http" --replace_string="default: https" --target_file="/opt/openproject/config/settings.yml" #================================================= # GENERIC FINALIZATION #================================================= -# SETUP LOGROTATE -ynh_script_progression --message="Configuring log rotation..." --weight=1 -ynh_use_logrotate +# INTEGRATE SERVICE IN YUNOHOST +#================================================= +ynh_script_progression --message="Integrating service in YunoHost..." -# ADVERTISE SERVICE IN ADMIN PANEL -yunohost service add "$app" --log "/var/log/$app/$app.log" +yunohost service add $app +#================================================= # START SYSTEMD SERVICE -ynh_script_progression --message="Starting a systemd service..." --weight=1 -# Compat YNH<3.5 -#ynh_systemd_action --service_name="$app" --action="start" --log_path="/var/log/$app/$app.log" -systemctl restart openproject.service +#================================================= +ynh_script_progression --message="Starting a systemd service..." -## SETUP FAIL2BAN -#ynh_script_progression --message="Configuring fail2ban..." --weight=1 -# -## Create a dedicated fail2ban config -#ynh_add_fail2ban_config --logpath="/var/log/nginx/${domain}-error.log" --failregex="Regex to match into the log for a failed login" +# Start a systemd service +ynh_systemd_action --service_name=$app --action="start" --log_path="systemd" #================================================= # SETUP SSOWAT #================================================= -ynh_script_progression --message="Configuring SSOwat..." --weight=1 +ynh_script_progression --message="Configuring permissions..." +# Make app public if necessary +if [ $is_public -eq 1 ] +then + # Everyone can access the app. + # The "main" permission is automatically created before the install script. + ynh_permission_update --permission="main" --add="visitors" +fi + +ynh_permission_create --permission="api" --url="/api" --allowed="visitors" --auth_header="false" --show_tile="false" --protected="true" #================================================= # RELOAD NGINX #================================================= -ynh_script_progression --message="Reloading nginx web server..." --weight=1 +ynh_script_progression --message="Reloading NGINX web server..." -systemctl reload nginx.service +ynh_systemd_action --service_name=nginx --action=reload #================================================= # END OF SCRIPT #================================================= -ynh_script_progression --message="Installation of $app completed" --last +ynh_script_progression --message="Installation of $app completed" diff --git a/scripts/remove b/scripts/remove index a5007e6..b139942 100755 --- a/scripts/remove +++ b/scripts/remove @@ -12,33 +12,32 @@ source /usr/share/yunohost/helpers #================================================= # LOAD SETTINGS #================================================= -ynh_script_progression --message="Loading installation settings..." --weight=1 +ynh_script_progression --message="Loading installation settings..." app=$YNH_APP_INSTANCE_NAME -db_name=$(ynh_app_setting_get --app="$app" --key=db_name) +domain=$(ynh_app_setting_get --app=$app --key=domain) +db_name=$(ynh_app_setting_get --app=$app --key=db_name) db_user=$db_name -final_path=$(ynh_app_setting_get --app="$app" --key=final_path) - -_homedir=/var/$app +_homedir=$(ynh_app_setting_get --app=$app --key=_homedir) #================================================= # STANDARD REMOVE #================================================= -# REMOVE SERVICE FROM ADMIN PANEL +# REMOVE SERVICE INTEGRATION IN YUNOHOST #================================================= -# Remove a service from the admin panel, added by `yunohost service add` -if ynh_exec_warn_less yunohost service status "$app" >/dev/null +# 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..." --weight=1 - yunohost service remove "$app" + ynh_script_progression --message="Removing $app service integration..." + yunohost service remove $app fi #================================================= # STOP AND REMOVE SERVICE #================================================= -ynh_script_progression --message="Stopping and removing the systemd service..." --weight=1 +ynh_script_progression --message="Stopping and removing the systemd service..." # Remove the dedicated systemd config ynh_remove_systemd_config @@ -46,66 +45,51 @@ ynh_remove_systemd_config #================================================= # REMOVE THE POSTGRESQL DATABASE #================================================= -ynh_script_progression --message="Removing the PostgreSQL database..." --weight=1 +ynh_script_progression --message="Removing the PostgreSQL database..." # Remove a database if it exists, along with the associated user -ynh_psql_remove_db "$db_name" "$db_user" +ynh_psql_remove_db --db_user=$db_user --db_name=$db_name + +#================================================= +# REMOVE NGINX CONFIGURATION +#================================================= +ynh_script_progression --message="Removing NGINX web server configuration..." + +# Remove the dedicated NGINX config +ynh_remove_nginx_config #================================================= # REMOVE DEPENDENCIES #================================================= -ynh_script_progression --message="Removing dependencies..." --weight=1 +ynh_script_progression --message="Removing dependencies..." # Remove metapackage and its dependencies ynh_remove_app_dependencies #================================================= -# REMOVE APP MAIN DIR +# SPECIFIC REMOVE #================================================= -ynh_script_progression --message="Removing app main directory..." --weight=1 +# REMOVE VARIOUS FILES +#================================================= +ynh_script_progression --message="Removing various files..." -# Remove the app directory securely -ynh_secure_remove --file="$final_path" ynh_secure_remove --file="$_homedir" -ynh_secure_remove --file="/etc/$app/" -ynh_secure_remove --file="/etc/apt/sources.list.d/openproject.list" -#================================================= -# REMOVE NGINX CONFIGURATION -#================================================= -ynh_script_progression --message="Removing nginx web server configuration..." --weight=1 - -# Remove the dedicated nginx config -ynh_remove_nginx_config - -#================================================= -# REMOVE LOGROTATE CONFIGURATION -#================================================= -ynh_script_progression --message="Removing logrotate configuration..." --weight=1 - -# Remove the app-specific logrotate config -ynh_remove_logrotate - -#================================================= -# REMOVE FAIL2BAN CONFIGURATION -#================================================= -ynh_script_progression --message="Removing fail2ban configuration..." --weight=1 - -# Remove the dedicated fail2ban config -ynh_remove_fail2ban_config +# Remove a directory securely +ynh_secure_remove --file="/etc/$app" #================================================= # GENERIC FINALIZATION #================================================= # REMOVE DEDICATED USER #================================================= -ynh_script_progression --message="Removing the dedicated system user..." --weight=1 +ynh_script_progression --message="Removing the dedicated system user..." # Delete a system user -ynh_system_user_delete --username="$app" +ynh_system_user_delete --username=$app #================================================= # END OF SCRIPT #================================================= -ynh_script_progression --message="Removal of $app completed" --last +ynh_script_progression --message="Removal of $app completed" diff --git a/scripts/restore b/scripts/restore index 6a52cee..4f90ae4 100755 --- a/scripts/restore +++ b/scripts/restore @@ -6,30 +6,38 @@ # IMPORT GENERIC HELPERS #================================================= -#Keep this path for calling _common.sh inside the execution's context of backup and restore scripts +# Keep this path for calling _common.sh inside the execution's context of backup and restore scripts source ../settings/scripts/_common.sh source /usr/share/yunohost/helpers + +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +ynh_clean_setup () { + ynh_clean_check_starting +} +# Exit if an error occurs during the execution of the script ynh_abort_if_errors #================================================= # LOAD SETTINGS #================================================= -ynh_script_progression --message="Loading settings..." --time --weight=1 +ynh_script_progression --message="Loading installation settings..." app=$YNH_APP_INSTANCE_NAME -domain=$(ynh_app_setting_get --app="$app" --key=domain) -path_url=$(ynh_app_setting_get --app="$app" --key=path) -final_path=$(ynh_app_setting_get --app="$app" --key=final_path) +domain=$(ynh_app_setting_get --app=$app --key=domain) +path_url=$(ynh_app_setting_get --app=$app --key=path) +db_name=$(ynh_app_setting_get --app=$app --key=db_name) +db_user=$db_name #================================================= # CHECK IF THE APP CAN BE RESTORED #================================================= -ynh_script_progression --message="Validating restoration parameters..." --time --weight=1 +ynh_script_progression --message="Validating restoration parameters..." -ynh_webpath_available --domain="$domain" --path_url="$path_url" \ - || ynh_die --message="Path not available: ${domain}${path_url}" -test ! -d "$final_path" \ +test ! -d $final_path \ || ynh_die --message="There is already a directory: $final_path " #================================================= @@ -37,90 +45,67 @@ test ! -d "$final_path" \ #================================================= # RESTORE THE NGINX CONFIGURATION #================================================= +ynh_script_progression --message="Restoring the NGINX web server configuration..." ynh_restore_file --origin_path="/etc/nginx/conf.d/$domain.d/$app.conf" -#================================================= -# RESTORE THE APP MAIN DIR -#================================================= -ynh_script_progression --message="Restoring the app main directory..." --time --weight=1 - -ynh_restore_file --origin_path="$final_path" - #================================================= # RECREATE THE DEDICATED USER #================================================= -ynh_script_progression --message="Recreating the dedicated system user..." --time --weight=1 +ynh_script_progression --message="Recreating the dedicated system user..." # Create the dedicated user (if not existing) -ynh_system_user_create --username="$app" - -#================================================= -# RESTORE USER RIGHTS -#================================================= - -# Restore permissions on app files -chown -R "$app": "$final_path" - -#================================================= -# RESTORE FAIL2BAN CONFIGURATION -#================================================= -ynh_script_progression --message="Restoring the fail2ban configuration..." --time --weight=1 - -ynh_restore_file "/etc/fail2ban/jail.d/$app.conf" -ynh_restore_file "/etc/fail2ban/filter.d/$app.conf" -ynh_systemd_action --action=restart --service_name=fail2ban +ynh_system_user_create --username=$app #================================================= # SPECIFIC RESTORATION #================================================= # REINSTALL DEPENDENCIES #================================================= -ynh_script_progression --message="Reinstalling dependencies..." --time --weight=1 +ynh_script_progression --message="Reinstalling dependencies..." -# Define and install dependencies -ynh_install_app_dependencies "$pkg_dependencies" +debian_release=$(lsb_release -r -s) +ynh_install_app_dependencies $pkg_dependencies +ynh_install_extra_app_dependencies --repo="deb https://dl.packager.io/srv/deb/opf/openproject/stable/$PROJECT_VERSION/debian $debian_release main" --package="$extra_pkg_dependencies" --key="https://dl.packager.io/srv/opf/openproject/key" #================================================= # RESTORE THE POSTGRESQL DATABASE #================================================= -ynh_script_progression --message="Restoring the PostgreSQL database..." --time --weight=1 +ynh_script_progression --message="Restoring the PostgreSQL database..." -exec_as postgres psql < db.postgres +db_pwd=$(ynh_app_setting_get --app=$app --key=db_pwd) +ynh_psql_test_if_first_run +ynh_psql_setup_db --db_user=$db_user --db_name=$db_name --db_pwd=$db_pwd +ynh_psql_execute_file_as_root --file="./db.sql" --database=$db_name #================================================= # RESTORE SYSTEMD #================================================= -ynh_script_progression --message="Restoring the systemd configuration..." --time --weight=1 +ynh_script_progression --message="Restoring the systemd configuration..." ynh_restore_file --origin_path="/etc/systemd/system/$app.service" -systemctl enable "$app.service" +systemctl enable $app.service --quiet #================================================= -# ADVERTISE SERVICE IN ADMIN PANEL +# INTEGRATE SERVICE IN YUNOHOST #================================================= +ynh_script_progression --message="Integrating service in YunoHost..." -yunohost service add "$app" --log "/var/log/$app/$app.log" +yunohost service add $app #================================================= # START SYSTEMD SERVICE #================================================= -ynh_script_progression --message="Starting a systemd service..." --time --weight=1 +ynh_script_progression --message="Starting a systemd service..." -ynh_systemd_action --service_name="$app" --action="start" --log_path="/var/log/$app/$app.log" - -#================================================= -# RESTORE THE LOGROTATE CONFIGURATION -#================================================= - -ynh_restore_file --origin_path="/etc/logrotate.d/$app" +ynh_systemd_action --service_name=$app --action="start" --log_path="systemd" #================================================= # GENERIC FINALIZATION #================================================= -# RELOAD NGINX AND PHP-FPM +# RELOAD NGINX #================================================= -ynh_script_progression --message="Reloading nginx web server and php-fpm..." --time --weight=1 +ynh_script_progression --message="Reloading NGINX web server..." ynh_systemd_action --service_name=nginx --action=reload @@ -128,4 +113,4 @@ ynh_systemd_action --service_name=nginx --action=reload # END OF SCRIPT #================================================= -ynh_script_progression --message="Restoration completed for $app" --time --last +ynh_script_progression --message="Restoration completed for $app" diff --git a/scripts/upgrade b/scripts/upgrade index c62521b..05c4acc 100755 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -12,89 +12,70 @@ source /usr/share/yunohost/helpers #================================================= # LOAD SETTINGS #================================================= -ynh_script_progression --message="Loading installation settings..." --time --weight=1 +ynh_script_progression --message="Loading installation settings..." app=$YNH_APP_INSTANCE_NAME -domain=$(ynh_app_setting_get --app="$app" --key=domain) -path_url=$(ynh_app_setting_get --app="$app" --key=path) -is_public=$(ynh_app_setting_get --app="$app" --key=is_public) -final_path=$(ynh_app_setting_get --app="$app" --key=final_path) -#language=$(ynh_app_setting_get --app="$app" --key=language) -db_name=$(ynh_app_setting_get --app="$app" --key=db_name) +domain=$(ynh_app_setting_get --app=$app --key=domain) +path_url=$(ynh_app_setting_get --app=$app --key=path) +language=$(ynh_app_setting_get --app=$app --key=language) +db_name=$(ynh_app_setting_get --app=$app --key=db_name) #================================================= # CHECK VERSION #================================================= +ynh_script_progression --message="Checking 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) -#================================================= -# ENSURE DOWNWARD COMPATIBILITY -#================================================= -ynh_script_progression --message="Ensuring downward compatibility..." --time --weight=1 - -# Fix is_public as a boolean value -if [ "$is_public" = "Yes" ]; then - ynh_app_setting_set --app="$app" --key=is_public --value=1 - is_public=1 -elif [ "$is_public" = "No" ]; then - ynh_app_setting_set --app="$app" --key=is_public --value=0 - is_public=0 -fi - -# 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 - #================================================= # BACKUP BEFORE UPGRADE THEN ACTIVE TRAP #================================================= -ynh_script_progression --message="Backing up the app before upgrading (may take a while)..." --time --weight=1 +ynh_script_progression --message="Backing up the app before upgrading (may take a while)..." # Backup the current version of the app ynh_backup_before_upgrade ynh_clean_setup () { - # restore it if the upgrade fails + ynh_clean_check_starting + # Restore it if the upgrade fails ynh_restore_upgradebackup } # Exit if an error occurs during the execution of the script ynh_abort_if_errors -#================================================= -# CHECK THE PATH -#================================================= - -# Normalize the URL path syntax -# N.B. : this is for app installations before YunoHost 2.7 -# where this value might be something like /foo/ or foo/ -# instead of /foo .... -# If nobody installed your app before 2.7, then you may -# safely remove this line -path_url=$(ynh_normalize_url_path --path_url="$path_url") - #================================================= # STANDARD UPGRADE STEPS #================================================= # STOP SYSTEMD SERVICE #================================================= -ynh_script_progression --message="Stopping a systemd service..." --time --weight=1 +ynh_script_progression --message="Stopping a systemd service..." -ynh_systemd_action --service_name="$app" --action="stop" --log_path="/var/log/$app/$app.log" +ynh_systemd_action --service_name=$app --action="stop" --log_path="systemd" + +#================================================= +# ENSURE DOWNWARD COMPATIBILITY +#================================================= +ynh_script_progression --message="Ensuring downward compatibility..." + +# 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 a permission if needed +if ! ynh_permission_exists --permission="api"; then + ynh_permission_create --permission="api" --url="/api" --allowed="visitors" --auth_header="false" --show_tile="false" --protected="true" +fi + +#================================================= +# CREATE DEDICATED USER +#================================================= +ynh_script_progression --message="Making sure dedicated system user exists..." + +# Create a dedicated user (if not existing) +ynh_system_user_create --username=$app #================================================= # DOWNLOAD, CHECK AND UNPACK SOURCE @@ -102,57 +83,39 @@ ynh_systemd_action --service_name="$app" --action="stop" --log_path="/var/log/$a if [ "$upgrade_type" == "UPGRADE_APP" ] then - ynh_script_progression --message="Upgrading source files..." --time --weight=1 + ynh_script_progression --message="Upgrading source files..." # Download, check integrity, uncompress and patch the source from app.src ynh_setup_source --dest_dir="$final_path" fi +chmod 750 "$final_path" +chmod -R o-rwx "$final_path" +chown -R $app:www-data "$final_path" + #================================================= # NGINX CONFIGURATION #================================================= -ynh_script_progression --message="Upgrading nginx web server configuration..." --time --weight=1 +ynh_script_progression --message="Upgrading NGINX web server configuration..." -# Create a dedicated nginx config +# Create a dedicated NGINX config ynh_add_nginx_config #================================================= # UPGRADE DEPENDENCIES #================================================= -ynh_script_progression --message="Upgrading dependencies..." --time --weight=1 +ynh_script_progression --message="Upgrading dependencies..." -ynh_install_app_dependencies "$pkg_dependencies" +debian_release=$(lsb_release -r -s) +ynh_install_app_dependencies $pkg_dependencies +ynh_install_extra_app_dependencies --repo="deb https://dl.packager.io/srv/deb/opf/openproject/stable/$PROJECT_VERSION/debian $debian_release main" --package="$extra_pkg_dependencies" --key="https://dl.packager.io/srv/opf/openproject/key" #================================================= -# CREATE DEDICATED USER -#================================================= -ynh_script_progression --message="Making sure dedicated system user exists..." --time --weight=1 - -# Create a dedicated user (if not existing) -ynh_system_user_create --username="$app" - -#================================================= -# STORE THE CONFIG FILE CHECKSUM -#================================================= - -### Verify the checksum of a file, stored by `ynh_store_file_checksum` in the install script. -### And create a backup of this file if the checksum is different. So the file will be backed up if the admin had modified it. -ynh_backup_if_checksum_is_different --file="$final_path/CONFIG_FILE" -# Recalculate and store the checksum of the file for the next upgrade. -ynh_store_file_checksum --file="$final_path/CONFIG_FILE" - -#================================================= -# SETUP LOGROTATE -#================================================= -ynh_script_progression --message="Upgrading logrotate configuration..." --time --weight=1 - -# Use logrotate to manage app-specific logfile(s) -ynh_use_logrotate --non-append - +# SPECIFIC UPGRADE #================================================= # SETUP SYSTEMD #================================================= -ynh_script_progression --message="Upgrading systemd configuration..." --time --weight=1 +ynh_script_progression --message="Upgrading systemd configuration..." # Create a dedicated systemd config ynh_add_systemd_config @@ -160,43 +123,23 @@ ynh_add_systemd_config #================================================= # GENERIC FINALIZATION #================================================= -# UPGRADE FAIL2BAN +# INTEGRATE SERVICE IN YUNOHOST #================================================= -ynh_script_progression --message="Reconfiguring fail2ban..." --time --weight=1 +ynh_script_progression --message="Integrating service in YunoHost..." -# Create a dedicated fail2ban config -ynh_add_fail2ban_config --logpath="/var/log/nginx/${domain}-error.log" --failregex="Regex to match into the log for a failed login" - -#================================================= -# SECURE FILES AND DIRECTORIES -#================================================= - -# Set permissions on app files -chown -R root: "$final_path" - -#================================================= -# SETUP SSOWAT -#================================================= -ynh_script_progression --message="Upgrading SSOwat configuration..." --time --weight=1 - -# Make app public if necessary -if [ $is_public -eq 1 ] -then - # unprotected_uris allows SSO credentials to be passed anyway - ynh_app_setting_set --app="$app" --key=unprotected_uris --value="/" -fi +yunohost service add $app #================================================= # START SYSTEMD SERVICE #================================================= -ynh_script_progression --message="Starting a systemd service..." --time --weight=1 +ynh_script_progression --message="Starting a systemd service..." -ynh_systemd_action --service_name="$app" --action="start" --log_path="/var/log/$app/$app.log" +ynh_systemd_action --service_name=$app --action="start" --log_path="systemd" #================================================= # RELOAD NGINX #================================================= -ynh_script_progression --message="Reloading nginx web server..." --time --weight=1 +ynh_script_progression --message="Reloading NGINX web server..." ynh_systemd_action --service_name=nginx --action=reload @@ -204,4 +147,4 @@ ynh_systemd_action --service_name=nginx --action=reload # END OF SCRIPT #================================================= -ynh_script_progression --message="Upgrade of $app completed" --time --last +ynh_script_progression --message="Upgrade of $app completed" diff --git a/scripts/ynh_add_extra_apt_repos b/scripts/ynh_add_extra_apt_repos deleted file mode 100644 index e3bc5f9..0000000 --- a/scripts/ynh_add_extra_apt_repos +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/bash - -# Helper to add a repos quickly and without problem. It create a repos.list in $etc/apt/sources.list.d/. It doesn't update the repos, so it must be used with the ynh_add_dependencies. -# usage : ynh_add_repos nameoftherepos url -# URL IS SOMETHING LIKE : "deb $mirrorurl $prefix(stable or jessie...) $otherprefix(main, non-free, or somting like that)" -ynh_add_repo(){ - local name_repos="$1" - local url_repos="$2" - echo "# $name_repos - ${url_repos}" - > "/etc/apt/sources.list.d/$name_repos.list" -} - -# Helper to pin a repos easily. -# usage : ynh_add_pin_repo nameoftherepos nbrofthepin origin -# Origin is the name of the orga which set up this repos ex: Debian -ynh_add_pin_repo() { - local name_repos="$1" - local pin="$2" - local origin="$3" - echo "Package: * - Pin: release o=$origin,a=$name_repos - Pin-Priority: $pin" \ - > "/etc/apt/preferences.d/$name_repos" -} - -# Add in a secure way backports repo. -# usage : ynh_add_secure_backport -ynh_add_secure_backport() { - local name_repos="debian-backports" - local origin="Debian" - local lsb_version="$(ynh_get_debian_release)" - local url="deb https://ftp.debian.org/debian $lsb_version-backports main" - local pin="450" - ynh_add_repos $name_repos $url - ynh_add_pin_repo $name_repos $origin $pin -} - -# Remove a repos easily in a secure way using the ynh_secure_remove helper -ynh_rm_secure_repos() { - local name_repos=$1 - ynh_secure_remove "/etc/apt/preferences.d/$name_repos" - ynh_secure_remove "/etc/apt/sources.list.d/$name_repos.list" -} - -# Backup the repo -ynh_backup_repo() { - local name_repo=$1 - ynh_backup "/etc/apt/preference.d/$name_repo" - ynh_backup "/etc/apt/sources.list.d/$name_repo.list" -} - -ynh_restore_repo() { - local name_repo=$1 - local custom_arch=$2 - ynh_restore "/etc/apt/preference.d/$name_repo" - if [[ custom_arch -ne true ]] - local arch_system=$(lsb_release -c) - arch_system=$(echo ${arch#Codename:}) - same_arch=$(cat $name_repo | grep $arch) - archs = [jessie, stretch, buster] - ynh_restore "/etc/apt/sources.list.d/$name_repo.list" - for arch in archs - do - same_arch=$(cat $name_repo | grep $arch) - if [[ same_arch -e arch ]] - then - echo "Everything is ok" - else - sed -i "s@$arch@$arch_system@g" "/etc/apt/sources.list.d/$name_repo.list" - fi - done - else - echo "Attention: vous avez choisi de personnaliser votre header" - ynh_restore "/etc/apt/sources.list.d/$name_repo.list" - fi -} - -ynh_backup_all_repos() { - if [[ $(ls /etc/apt/preference.d/) -ne "" ]] - then - ynh_backup "/etc/apt/preference.d/*" - fi - if [[ $(ls /eyc/apt/sources.list.d/) -ne "" ]] - then - ynh_backup "/etc/apt/sources.list.d/*" - fi -} diff --git a/sources/extra_files/app/.gitignore b/sources/extra_files/app/.gitignore deleted file mode 100644 index 783a4ae..0000000 --- a/sources/extra_files/app/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*~ -*.sw[op] diff --git a/sources/patches/.gitignore b/sources/patches/.gitignore deleted file mode 100644 index 783a4ae..0000000 --- a/sources/patches/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*~ -*.sw[op] From 4a3d6903a40916ca3cacd2ece39ee28bc9ca48af Mon Sep 17 00:00:00 2001 From: Yunohost-Bot <> Date: Sun, 27 Feb 2022 22:22:11 +0000 Subject: [PATCH 02/13] Auto-update README --- README.md | 72 +++++++++++++++++++---------------------- README_fr.md | 90 +++++++++++++++++++++++----------------------------- 2 files changed, 73 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index de98686..78ad5a0 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,19 @@ -# OpenProject App for YunoHost + -[![Invtegration level](https://dash.yunohost.org/integration/Openproject.svg)](https://dash.yunohost.org/appci/app/Openproject) -[![Install Openproject with YunoHost](https://install-app.yunohost.org/install-with-yunohost.png)](https://install-app.yunohost.org/?app=Openproject) +# OpenProject for YunoHost + +[![Integration level](https://dash.yunohost.org/integration/openproject.svg)](https://dash.yunohost.org/appci/app/openproject) ![](https://ci-apps.yunohost.org/ci/badges/openproject.status.svg) ![](https://ci-apps.yunohost.org/ci/badges/openproject.maintain.svg) +[![Install OpenProject with YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=openproject) *[Lire ce readme en français.](./README_fr.md)* -

- -

+> *This package allows you to install OpenProject quickly and simply on a YunoHost server. +If you don't have YunoHost, please consult [the guide](https://yunohost.org/#/install) to learn how to install it.* -*This package allow you to install Openproject quickly and simply on a YunoHost server. -If you don't have YunoHost, please see [here](https://yunohost.org/#/install) to know how to install and enjoy it.* +## Overview ## Overview OpenProject is a web-based project management software. Its key features are: @@ -25,44 +28,35 @@ OpenProject is a web-based project management software. Its key features are: - Forums - Meeting agendas and meeting minutes -**Shipped version:** 10.0 + +**Shipped version:** 10.5.1~ynh1 + + ## Screenshots -![GANTT-Chart displayed y the App.](https://www.openproject.org/wp-content/uploads/2018/09/Gantt-chart.jpg) +![](./doc/screenshots/screenshot1.png) -## Configuration +## Disclaimers / important information -After installation, every change can be made directly in the web application. +* default user and password is admin / admin +## Documentation and resources -## Documentation +* Official app website: https://www.openproject.org/ +* Official admin documentation: https://www.openproject.org/docs/ +* Upstream app code repository: https://github.com/opf/openproject +* YunoHost documentation for this app: https://yunohost.org/app_openproject +* Report a bug: https://github.com/YunoHost-Apps/openproject_ynh/issues -- [Official documentation here](https://github.com/opf/openproject/tree/stable/10). -- YunoHost documentation: If specific documentation is needed, feel free to contribute! +## Developer info -## YunoHost specific features +Please send your pull request to the [testing branch](https://github.com/YunoHost-Apps/openproject_ynh/tree/testing). -#### Multi-users support +To try the testing branch, please proceed like that. +``` +sudo yunohost app install https://github.com/YunoHost-Apps/openproject_ynh/tree/testing --debug +or +sudo yunohost app upgrade openproject -u https://github.com/YunoHost-Apps/openproject_ynh/tree/testing --debug +``` -LDAP is not embedded yet, neither HTTP authentication support. - -#### Supported architectures - -- x86-64b - [![Build Status](https://ci-apps.yunohost.org/ci/logs/Openproject%20%28Apps%29.svg)](https://ci-apps.yunohost.org/ci/apps/Openproject/) -- ARMv8-A - [![Build Status](https://ci-apps-arm.yunohost.org/ci/logs/Openproject%20%28Apps%29.svg)](https://ci-apps-arm.yunohost.org/ci/apps/Openproject/) -- Jessie x86-64b - [![Build Status](https://ci-stretch.nohost.me/ci/logs/Openproject%20%28Apps%29.svg)](https://ci-stretch.nohost.me/ci/apps/Openproject/) - -## Limitations - -- No known limitations :) - -## License - -This repository is under the GNU AGPL licence v3. Please see [the license file](./LICENSE) for more information. - -## Links - -- Report a bug: https://github.com/YunoHost-Apps/Openproject_ynh/issues -- App website: https://www.openproject.org/ -- Upstream app repository: https://github.com/opf/openproject -- YunoHost website: https://yunohost.org/ +**More info regarding app packaging:** https://yunohost.org/packaging_apps \ No newline at end of file diff --git a/README_fr.md b/README_fr.md index 9025174..8fe0162 100644 --- a/README_fr.md +++ b/README_fr.md @@ -1,68 +1,58 @@ # OpenProject pour YunoHost -[![Niveau d'intégration](https://dash.yunohost.org/integration/Openproject.svg)](https://dash.yunohost.org/appci/app/Openproject) -[![Installer Openproject avec YunoHost](https://install-app.yunohost.org/install-with-yunohost.png)](https://install-app.yunohost.org/?app=Openproject) +[![Niveau d'intégration](https://dash.yunohost.org/integration/openproject.svg)](https://dash.yunohost.org/appci/app/openproject) ![](https://ci-apps.yunohost.org/ci/badges/openproject.status.svg) ![](https://ci-apps.yunohost.org/ci/badges/openproject.maintain.svg) +[![Installer OpenProject avec YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=openproject) -*[Read this readme in English.](./ README.md)* +*[Read this readme in english.](./README.md)* +*[Lire ce readme en français.](./README_fr.md)* -

- -

- -Ce dépôt vous permet d'installer Openproject rapidement et simplement sur un serveur YunoHost. -Si vous n'avez pas YunoHost, veuillez consulter [ici] (https://yunohost.org/#/install) pour savoir comment l'installer et en profiter. +> *Ce package vous permet d'installer OpenProject 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.* ## Vue d'ensemble -OpenProject est un logiciel de gestion de projet entièrement en Web. Ses principales caractéristiques sont : -- Planification et ordonnancement de projets, -- Feuille de route du produit et planification des versions, -- Gestion des tâches et collaboration au sein des équipes, -- Agile et Scrum, -- Suivi du temps, reporting des coûts et budgétisation, -- Suivi des bogues, -- Wikis, -- Forums, -- Ordres du jour et comptes rendus, +## Overview +OpenProject is a web-based project management software. Its key features are: + +- Project planning and scheduling +- Product roadmap and release planning +- Task management and team collaboration +- Agile and Scrum +- Time tracking, cost reporting and budgeting +- Bug tracking +- Wikis +- Forums +- Meeting agendas and meeting minutes + + +**Version incluse :** 10.5.1~ynh1 + -** Version incluse : ** 10.0 ## Captures d'écran -![GANTT-Chart affiché dans l'application.](https://www.openproject.org/wp-content/uploads/2018/09/Gantt-chart.jpg) +![](./doc/screenshots/screenshot1.png) -## Configuration +## Avertissements / informations importantes -Après l'installation, chaque modification peut être effectuée directement dans la page d'admin Web. +* default user and password is admin / admin +## Documentations et ressources -## Documentation +* Site officiel de l'app : https://www.openproject.org/ +* Documentation officielle de l'admin : https://www.openproject.org/docs/ +* Dépôt de code officiel de l'app : https://github.com/opf/openproject +* Documentation YunoHost pour cette app : https://yunohost.org/app_openproject +* Signaler un bug : https://github.com/YunoHost-Apps/openproject_ynh/issues - * [Documentation officielle ici](https://github.com/opf/openproject/tree/stable/10) - * Documentation YunoHost: Si une documentation spécifique est nécessaire, n'hésitez pas à contribuer. +## Informations pour les développeurs -#### Support multi-utilisateurs +Merci de faire vos pull request sur la [branche testing](https://github.com/YunoHost-Apps/openproject_ynh/tree/testing). -LDAP n'est pas encore intégré, ni le support de l'authentification HTTP. - -#### Architectures supportées - -* x86-64b - [![Statut du _build_](https://ci-apps.yunohost.org/ci/logs/Openproject%20%28Apps%29.svg)](https: //ci-apps.yunohost. org / ci / apps / Openproject /) -* ARMv8-A - [![Statut du _build_](https://ci-apps-arm.yunohost.org/ci/logs/Openproject%20%28Apps%29.svg)](https: // ci-apps- arm.yunohost.org/ci/apps/Openproject/) -* Jessie x86-64b - [![Statut du _build_](https://ci-stretch.nohost.me/ci/logs/Openproject%20%28Apps%29.svg)](https: //ci-stretch.nohost .me / ci / apps / Openproject /) - -## Limitations - -* Aucune limitation connue :) - - -## Licence - -Ce dépôt et son code sont sous la licence GNU AGPL v3. Vous pouvez consulter [le fichier de licence](./LICENSE) pour plus d'informations. - -## Liens - - * Signaler un bug: https://github.com/YunoHost-Apps/Openproject_ynh/issues - * Site Web de l'application: https://www.openproject.org/ - * Référentiel d'applications en amont: https://github.com/opf/openproject - * Site Web YunoHost: https://yunohost.org/ +Pour essayer la branche testing, procédez comme suit. +``` +sudo yunohost app install https://github.com/YunoHost-Apps/openproject_ynh/tree/testing --debug +ou +sudo yunohost app upgrade openproject -u https://github.com/YunoHost-Apps/openproject_ynh/tree/testing --debug +``` +**Plus d'infos sur le packaging d'applications :** https://yunohost.org/packaging_apps \ No newline at end of file From d025848f257b8e71023a7260fe8b52fd4f1af65c Mon Sep 17 00:00:00 2001 From: yalh76 Date: Sun, 27 Feb 2022 23:28:09 +0100 Subject: [PATCH 03/13] Cleanup --- scripts/install | 7 ------- 1 file changed, 7 deletions(-) diff --git a/scripts/install b/scripts/install index 1da43bd..da84892 100755 --- a/scripts/install +++ b/scripts/install @@ -139,10 +139,6 @@ chmod 750 "/etc/openproject/" chmod -R o-rwx "/etc/openproject/" chown -R $app:$app "/etc/openproject/" -#ynh_replace_string --match_string=".*PORT=.*" --replace_string="export PORT=$port" --target_file="/etc/default/openproject" -#echo $app $app/port select $port | debconf-set-selections -#openproject config:set PORT $port - openproject config:set PORT=$port openproject config:set SERVER_PROTOCOL_FORCE_HTTPS="true" openproject config:set SERVER_HOSTNAME=$domain @@ -150,9 +146,6 @@ openproject config:set SERVER_PATH_PREFIX=$path_url openproject configure >> "$YNH_STDINFO" -#ynh_replace_string --match_string="default: localhost:3000" --replace_string="default: $domain" --target_file="/opt/openproject/config/settings.yml" -#ynh_replace_string --match_string="default: http" --replace_string="default: https" --target_file="/opt/openproject/config/settings.yml" - #================================================= # GENERIC FINALIZATION #================================================= From 4d596f6422f2d94be1c52a671e2b8825ce0632ea Mon Sep 17 00:00:00 2001 From: yalh76 Date: Mon, 28 Feb 2022 20:24:37 +0100 Subject: [PATCH 04/13] Fix description --- README_fr.md | 58 --------------------------------------------------- check_process | 2 +- manifest.json | 8 +++---- 3 files changed, 4 insertions(+), 64 deletions(-) delete mode 100644 README_fr.md diff --git a/README_fr.md b/README_fr.md deleted file mode 100644 index 8fe0162..0000000 --- a/README_fr.md +++ /dev/null @@ -1,58 +0,0 @@ -# OpenProject pour YunoHost - -[![Niveau d'intégration](https://dash.yunohost.org/integration/openproject.svg)](https://dash.yunohost.org/appci/app/openproject) ![](https://ci-apps.yunohost.org/ci/badges/openproject.status.svg) ![](https://ci-apps.yunohost.org/ci/badges/openproject.maintain.svg) -[![Installer OpenProject avec YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=openproject) - -*[Read this readme in english.](./README.md)* -*[Lire ce readme en français.](./README_fr.md)* - -> *Ce package vous permet d'installer OpenProject 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.* - -## Vue d'ensemble - -## Overview -OpenProject is a web-based project management software. Its key features are: - -- Project planning and scheduling -- Product roadmap and release planning -- Task management and team collaboration -- Agile and Scrum -- Time tracking, cost reporting and budgeting -- Bug tracking -- Wikis -- Forums -- Meeting agendas and meeting minutes - - -**Version incluse :** 10.5.1~ynh1 - - - -## Captures d'écran - -![](./doc/screenshots/screenshot1.png) - -## Avertissements / informations importantes - -* default user and password is admin / admin -## Documentations et ressources - -* Site officiel de l'app : https://www.openproject.org/ -* Documentation officielle de l'admin : https://www.openproject.org/docs/ -* Dépôt de code officiel de l'app : https://github.com/opf/openproject -* Documentation YunoHost pour cette app : https://yunohost.org/app_openproject -* Signaler un bug : https://github.com/YunoHost-Apps/openproject_ynh/issues - -## Informations pour les développeurs - -Merci de faire vos pull request sur la [branche testing](https://github.com/YunoHost-Apps/openproject_ynh/tree/testing). - -Pour essayer la branche testing, procédez comme suit. -``` -sudo yunohost app install https://github.com/YunoHost-Apps/openproject_ynh/tree/testing --debug -ou -sudo yunohost app upgrade openproject -u https://github.com/YunoHost-Apps/openproject_ynh/tree/testing --debug -``` - -**Plus d'infos sur le packaging d'applications :** https://yunohost.org/packaging_apps \ No newline at end of file diff --git a/check_process b/check_process index a824d32..89fb3c4 100644 --- a/check_process +++ b/check_process @@ -1,7 +1,7 @@ ;; Test complet ; Manifest domain="domain.tld" - language="fr" + language="en" is_public=1 ; Checks pkg_linter=1 diff --git a/manifest.json b/manifest.json index efeba5d..64638c2 100644 --- a/manifest.json +++ b/manifest.json @@ -3,8 +3,7 @@ "id": "openproject", "packaging_format": 1, "description": { - "en": "OpenProject integration", - "fr": "Intégration de OpenProject" + "en": "web-based project management software" }, "version": "10.5.1~ynh1", "url": "https://www.openproject.org/", @@ -38,8 +37,7 @@ "type": "boolean", "default": true, "help": { - "en": "A public Openproject app could be less secure depending your configuration. Butit can allow external people from your Yunohost instance to participate to project management.", - "fr": "Une instance publique de YunoHost peut-être moins sécurisée mais peut permettre à des personnes externes à l'instance YunoHost de participer à votre projet (invité)" + "en": "A public Openproject app could be less secure depending your configuration. Butit can allow external people from your Yunohost instance to participate to project management." } }, { @@ -50,7 +48,7 @@ "fr": "Choisissez la langue de l'application" }, "choices": ["fr", "en"], - "default": "fr" + "default": "en" } ] } From 388554b4e598a08de4b466ad46f245df8d037739 Mon Sep 17 00:00:00 2001 From: Yunohost-Bot <> Date: Mon, 28 Feb 2022 19:24:43 +0000 Subject: [PATCH 05/13] Auto-update README --- README_fr.md | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 README_fr.md diff --git a/README_fr.md b/README_fr.md new file mode 100644 index 0000000..8fe0162 --- /dev/null +++ b/README_fr.md @@ -0,0 +1,58 @@ +# OpenProject pour YunoHost + +[![Niveau d'intégration](https://dash.yunohost.org/integration/openproject.svg)](https://dash.yunohost.org/appci/app/openproject) ![](https://ci-apps.yunohost.org/ci/badges/openproject.status.svg) ![](https://ci-apps.yunohost.org/ci/badges/openproject.maintain.svg) +[![Installer OpenProject avec YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=openproject) + +*[Read this readme in english.](./README.md)* +*[Lire ce readme en français.](./README_fr.md)* + +> *Ce package vous permet d'installer OpenProject 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.* + +## Vue d'ensemble + +## Overview +OpenProject is a web-based project management software. Its key features are: + +- Project planning and scheduling +- Product roadmap and release planning +- Task management and team collaboration +- Agile and Scrum +- Time tracking, cost reporting and budgeting +- Bug tracking +- Wikis +- Forums +- Meeting agendas and meeting minutes + + +**Version incluse :** 10.5.1~ynh1 + + + +## Captures d'écran + +![](./doc/screenshots/screenshot1.png) + +## Avertissements / informations importantes + +* default user and password is admin / admin +## Documentations et ressources + +* Site officiel de l'app : https://www.openproject.org/ +* Documentation officielle de l'admin : https://www.openproject.org/docs/ +* Dépôt de code officiel de l'app : https://github.com/opf/openproject +* Documentation YunoHost pour cette app : https://yunohost.org/app_openproject +* Signaler un bug : https://github.com/YunoHost-Apps/openproject_ynh/issues + +## Informations pour les développeurs + +Merci de faire vos pull request sur la [branche testing](https://github.com/YunoHost-Apps/openproject_ynh/tree/testing). + +Pour essayer la branche testing, procédez comme suit. +``` +sudo yunohost app install https://github.com/YunoHost-Apps/openproject_ynh/tree/testing --debug +ou +sudo yunohost app upgrade openproject -u https://github.com/YunoHost-Apps/openproject_ynh/tree/testing --debug +``` + +**Plus d'infos sur le packaging d'applications :** https://yunohost.org/packaging_apps \ No newline at end of file From 057c3674ec00a6777d7e0b467893e6ed8ca4ff67 Mon Sep 17 00:00:00 2001 From: yalh76 Date: Mon, 28 Feb 2022 20:25:28 +0100 Subject: [PATCH 06/13] Remove sub_path check --- check_process | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check_process b/check_process index 89fb3c4..2b53905 100644 --- a/check_process +++ b/check_process @@ -5,7 +5,7 @@ is_public=1 ; Checks pkg_linter=1 - setup_sub_dir=1 + setup_sub_dir=0 setup_root=1 setup_nourl=0 setup_private=1 From d8c8723a022b5c8c257637c9aae7919997dbe49d Mon Sep 17 00:00:00 2001 From: yalh76 Date: Mon, 28 Feb 2022 20:27:32 +0100 Subject: [PATCH 07/13] Fix restore --- scripts/restore | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/restore b/scripts/restore index 4f90ae4..6ebb6b6 100755 --- a/scripts/restore +++ b/scripts/restore @@ -37,9 +37,6 @@ db_user=$db_name #================================================= ynh_script_progression --message="Validating restoration parameters..." -test ! -d $final_path \ - || ynh_die --message="There is already a directory: $final_path " - #================================================= # STANDARD RESTORATION STEPS #================================================= From 4013ada08d1848bd51193ffa81eafa96e61c9f2c Mon Sep 17 00:00:00 2001 From: yalh76 Date: Mon, 28 Feb 2022 20:27:41 +0100 Subject: [PATCH 08/13] fix upgrade --- scripts/upgrade | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/scripts/upgrade b/scripts/upgrade index 05c4acc..06b0ae9 100755 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -77,22 +77,6 @@ ynh_script_progression --message="Making sure dedicated system user exists..." # Create a dedicated user (if not existing) ynh_system_user_create --username=$app -#================================================= -# DOWNLOAD, CHECK AND UNPACK SOURCE -#================================================= - -if [ "$upgrade_type" == "UPGRADE_APP" ] -then - ynh_script_progression --message="Upgrading source files..." - - # Download, check integrity, uncompress and patch the source from app.src - ynh_setup_source --dest_dir="$final_path" -fi - -chmod 750 "$final_path" -chmod -R o-rwx "$final_path" -chown -R $app:www-data "$final_path" - #================================================= # NGINX CONFIGURATION #================================================= From cb4bce22999d71b3e51b038434aecbfb3135bb57 Mon Sep 17 00:00:00 2001 From: yalh76 Date: Tue, 1 Mar 2022 20:07:37 +0100 Subject: [PATCH 09/13] Fix backup/restore --- scripts/backup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/backup b/scripts/backup index 55b01cb..cbbfa3c 100755 --- a/scripts/backup +++ b/scripts/backup @@ -54,7 +54,7 @@ ynh_backup --src_path="/etc/systemd/system/$app.service" #================================================= ynh_print_info --message="Backing up the PostgreSQL database..." -ynh_psql_dump_db --database="$db_name" > db.postgres +ynh_psql_dump_db --database="$db_name" > db.sql #================================================= # END OF SCRIPT From 9762615a3d57dead95476446d5f3b6ebe2033977 Mon Sep 17 00:00:00 2001 From: yalh76 Date: Tue, 1 Mar 2022 20:12:29 +0100 Subject: [PATCH 10/13] Fix upgrade --- scripts/upgrade | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/upgrade b/scripts/upgrade index 06b0ae9..c927d21 100755 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -20,6 +20,7 @@ domain=$(ynh_app_setting_get --app=$app --key=domain) path_url=$(ynh_app_setting_get --app=$app --key=path) language=$(ynh_app_setting_get --app=$app --key=language) db_name=$(ynh_app_setting_get --app=$app --key=db_name) +port=$(ynh_app_setting_get --app=$app --key=port) #================================================= # CHECK VERSION From c6a2b62f9c088d000a588e826577a15fbfede113 Mon Sep 17 00:00:00 2001 From: yalh76 Date: Wed, 2 Mar 2022 17:54:56 +0100 Subject: [PATCH 11/13] fix upgrade --- scripts/upgrade | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/scripts/upgrade b/scripts/upgrade index c927d21..9f806a5 100755 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -95,16 +95,6 @@ debian_release=$(lsb_release -r -s) ynh_install_app_dependencies $pkg_dependencies ynh_install_extra_app_dependencies --repo="deb https://dl.packager.io/srv/deb/opf/openproject/stable/$PROJECT_VERSION/debian $debian_release main" --package="$extra_pkg_dependencies" --key="https://dl.packager.io/srv/opf/openproject/key" -#================================================= -# SPECIFIC UPGRADE -#================================================= -# SETUP SYSTEMD -#================================================= -ynh_script_progression --message="Upgrading systemd configuration..." - -# Create a dedicated systemd config -ynh_add_systemd_config - #================================================= # GENERIC FINALIZATION #================================================= From 3c1412d33dab847a898508e2eaaa5b099f0b544a Mon Sep 17 00:00:00 2001 From: yalh76 Date: Wed, 2 Mar 2022 22:35:33 +0100 Subject: [PATCH 12/13] Fix backup/restore --- scripts/backup | 6 ++++++ scripts/restore | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/scripts/backup b/scripts/backup index cbbfa3c..4aaca4a 100755 --- a/scripts/backup +++ b/scripts/backup @@ -49,6 +49,12 @@ ynh_backup --src_path="/etc/nginx/conf.d/$domain.d/$app.conf" ynh_backup --src_path="/etc/systemd/system/$app.service" +#================================================= +# BACKUP VARIOUS FILES +#================================================= + +ynh_backup --src_path="/etc/$app/" + #================================================= # BACKUP THE POSTGRESQL DATABASE #================================================= diff --git a/scripts/restore b/scripts/restore index 6ebb6b6..30b588a 100755 --- a/scripts/restore +++ b/scripts/restore @@ -75,6 +75,17 @@ ynh_psql_test_if_first_run ynh_psql_setup_db --db_user=$db_user --db_name=$db_name --db_pwd=$db_pwd ynh_psql_execute_file_as_root --file="./db.sql" --database=$db_name +#================================================= +# RESTORE VARIOUS FILES +#================================================= +ynh_script_progression --message="Restoring various files..." + +ynh_restore_file --origin_path="/etc/$app/" + +chmod 750 "/etc/openproject/" +chmod -R o-rwx "/etc/openproject/" +chown -R $app:$app "/etc/openproject/" + #================================================= # RESTORE SYSTEMD #================================================= From 027bd35a976a0d50e3720f139eb977e1b1a9b89b Mon Sep 17 00:00:00 2001 From: yalh76 Date: Thu, 3 Mar 2022 22:54:43 +0100 Subject: [PATCH 13/13] Fix backup/restore --- scripts/backup | 6 ------ scripts/restore | 14 +++++++------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/scripts/backup b/scripts/backup index 4aaca4a..d1a2235 100755 --- a/scripts/backup +++ b/scripts/backup @@ -43,12 +43,6 @@ ynh_backup --src_path="/etc/nginx/conf.d/$domain.d/$app.conf" #================================================= # SPECIFIC BACKUP -#================================================= -# BACKUP SYSTEMD -#================================================= - -ynh_backup --src_path="/etc/systemd/system/$app.service" - #================================================= # BACKUP VARIOUS FILES #================================================= diff --git a/scripts/restore b/scripts/restore index 30b588a..a410887 100755 --- a/scripts/restore +++ b/scripts/restore @@ -31,6 +31,7 @@ domain=$(ynh_app_setting_get --app=$app --key=domain) path_url=$(ynh_app_setting_get --app=$app --key=path) db_name=$(ynh_app_setting_get --app=$app --key=db_name) db_user=$db_name +port=$(ynh_app_setting_get --app=$app --key=port) #================================================= # CHECK IF THE APP CAN BE RESTORED @@ -70,7 +71,7 @@ ynh_install_extra_app_dependencies --repo="deb https://dl.packager.io/srv/deb/op #================================================= ynh_script_progression --message="Restoring the PostgreSQL database..." -db_pwd=$(ynh_app_setting_get --app=$app --key=db_pwd) +db_pwd=$(ynh_app_setting_get --app=$app --key=psqlpwd) ynh_psql_test_if_first_run ynh_psql_setup_db --db_user=$db_user --db_name=$db_name --db_pwd=$db_pwd ynh_psql_execute_file_as_root --file="./db.sql" --database=$db_name @@ -86,13 +87,12 @@ chmod 750 "/etc/openproject/" chmod -R o-rwx "/etc/openproject/" chown -R $app:$app "/etc/openproject/" -#================================================= -# RESTORE SYSTEMD -#================================================= -ynh_script_progression --message="Restoring the systemd configuration..." +openproject config:set PORT=$port +openproject config:set SERVER_PROTOCOL_FORCE_HTTPS="true" +openproject config:set SERVER_HOSTNAME=$domain +openproject config:set SERVER_PATH_PREFIX=$path_url -ynh_restore_file --origin_path="/etc/systemd/system/$app.service" -systemctl enable $app.service --quiet +openproject configure >> "$YNH_STDINFO" #================================================= # INTEGRATE SERVICE IN YUNOHOST