From bfa0ef2eb81b6fbc2f645d955fb1f98c05f719e3 Mon Sep 17 00:00:00 2001 From: yalh76 Date: Sun, 13 Mar 2022 23:43:18 +0100 Subject: [PATCH 1/4] Apply last example_ynh --- check_process | 28 ++---- conf/gunicorn_config.py | 14 +-- conf/nginx.conf | 24 +++-- doc/.gitkeep | 0 doc/DESCRIPTION.md | 1 + doc/DISCLAIMER.md | 0 doc/screenshots/.gitkeep | 0 doc/screenshots/user-subscriptions.png | Bin 0 -> 44201 bytes manifest.json | 25 ++--- scripts/backup | 12 +-- scripts/change_url | 35 +++++-- scripts/common.sh | 18 ---- scripts/install | 83 ++++++++--------- scripts/remove | 38 ++++---- scripts/restore | 63 ++++++------- scripts/upgrade | 124 +++++++++++-------------- 16 files changed, 214 insertions(+), 251 deletions(-) create mode 100644 doc/.gitkeep create mode 100644 doc/DESCRIPTION.md create mode 100644 doc/DISCLAIMER.md create mode 100644 doc/screenshots/.gitkeep create mode 100644 doc/screenshots/user-subscriptions.png delete mode 100644 scripts/common.sh diff --git a/check_process b/check_process index 79141b3..f963d16 100644 --- a/check_process +++ b/check_process @@ -1,8 +1,8 @@ ;; Test complet sans multisite auto_remove=1 ; Manifest - domain="domain.tld" (DOMAIN) - admin="john" (USER) + domain="domain.tld" + admin="john" email="john@example.com" isp_name="ARN" isp_site="https://arn-fai.net" @@ -12,25 +12,13 @@ setup_root=1 setup_nourl=0 setup_private=0 - setup_public=1 + setup_public=0 upgrade=1 + # upgrade=1 from_commit=CommitHash backup_restore=1 multi_instance=0 - wrong_user=1 - wrong_path=1 - incorrect_path=1 - corrupt_source=0 - fail_download_source=0 port_already_use=0 - final_path_already_use=0 -;;; Levels - Level 1=auto - Level 2=auto - Level 3=auto - Level 4=1 - Level 5=auto - Level 6=auto - Level 7=auto - Level 8=0 - Level 9=0 - Level 10=0 + change_url=0 +;;; Options +Email= +Notification=none diff --git a/conf/gunicorn_config.py b/conf/gunicorn_config.py index 7e6c034..6945d8c 100644 --- a/conf/gunicorn_config.py +++ b/conf/gunicorn_config.py @@ -1,11 +1,11 @@ -command = '/opt/__YNH_APP_INSTANCE_NAME__/venv/bin/gunicorn' -pythonpath = '/opt/__YNH_APP_INSTANCE_NAME__' +command = '/opt/__APP__/venv/bin/gunicorn' +pythonpath = '/opt/__APP__' workers = 4 -user = '__YNH_APP_INSTANCE_NAME__' -bind = 'unix:/opt/__YNH_APP_INSTANCE_NAME__/sock' -pid = '/run/gunicorn/__YNH_APP_INSTANCE_NAME__-pid' -errorlog = '/var/log/__YNH_APP_INSTANCE_NAME__/error.log' -accesslog = '/var/log/__YNH_APP_INSTANCE_NAME__/access.log' +user = '__APP__' +bind = 'unix:/opt/__APP__/sock' +pid = '/run/gunicorn/__APP__-pid' +errorlog = '/var/log/__APP__/error.log' +accesslog = '/var/log/__APP__/access.log' access_log_format = '%({X-Real-IP}i)s %({X-Forwarded-For}i)s %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"' loglevel = 'warning' capture_output = True diff --git a/conf/nginx.conf b/conf/nginx.conf index 36fa9f3..78e1da5 100644 --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -1,31 +1,29 @@ #sub_path_only rewrite ^__PATH__$ __PATH__/ permanent; location __PATH__/ { - if ($scheme = http) { - rewrite ^ https://$server_name$request_uri? permanent; - } try_files $uri @__NAME__; } + location __PATH__/protected/ { - internal; - alias /opt/__NAME__/__NAME__/smedia/; + internal; + alias /opt/__NAME__/__NAME__/smedia/; } location __PATH__/media { - alias /opt/__NAME__/media; + alias /opt/__NAME__/media; } location __PATH__/static { - alias /opt/__NAME__/static; + alias /opt/__NAME__/static; } location __PATH__/assets { - alias /opt/__NAME__/static; + alias /opt/__NAME__/static; } location @__NAME__ { - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_pass http://unix:/opt/__NAME__/sock; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://unix:/opt/__NAME__/sock; } diff --git a/doc/.gitkeep b/doc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/doc/DESCRIPTION.md b/doc/DESCRIPTION.md new file mode 100644 index 0000000..cf72c40 --- /dev/null +++ b/doc/DESCRIPTION.md @@ -0,0 +1 @@ +COIN is an Information System designed for associative ISPs in the FFDN. diff --git a/doc/DISCLAIMER.md b/doc/DISCLAIMER.md new file mode 100644 index 0000000..e69de29 diff --git a/doc/screenshots/.gitkeep b/doc/screenshots/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/doc/screenshots/user-subscriptions.png b/doc/screenshots/user-subscriptions.png new file mode 100644 index 0000000000000000000000000000000000000000..f03a2a680f74ce066ea4ce9117ac384584923a20 GIT binary patch literal 44201 zcmdSBbyS;evp$LyYmp*FinOJ;7MB2RvEs!Yio0uyx5ceEK|+Dz?(SAJxH~1mEx4Z0 z_kF+b+xz_X`Rkmu_F0RSgd|TgGxy9j*L}?mAs-c_aInd-k&uvZq(6u&BO#$ekdTl! zFwqgu4A2ZWAR)a#k`{lb>XEveW*|qnb$4ICLklZ$mmM<^vyW^RC?d(#B2=gdJP2@N z>q-sliN&XVIg3wl{=Io545ytt`U3Xpwbj^=K&BJZ3rqY%>fMURqAvc#$h8djx(iH9 zlU9bcFAkQw<+iHQ+{|QhxdP6af%G!-=3pR{D-E^?1BxgjW4`=`|Nh}7CIKaj`RzZy zCQ&Av|9Kj5BaZyP;xVj<6CNebJKMxt%7V3hdPKbAkT09OuWiDd%WkcK_NOK|>n z={w6?c&aNEDt%@aq`QqPYe(#F?@S6u06Xn7?K7M3`a;R+!0+1L(MbZ zwxq6jzMV7IuJIe*ZTYgr3>LwO#)o=iLf2k<(g(~A%RN9I`l=eg+x@O}m$i|moLG9H zNSoe9;O5T0Tpe}O%z>gvR3xr_$Mu}!Wkw3qIqnD1J4<)(+#9=c52>Mr}CS`2T*?~=r=Vt*G%Y9se7!SPgv9aGVs zDOCy+SF+p^TDK~-es4mxJ3LG5{4n4 zdih-0B*D}*+2mIp8+zs<@mgID+mpx|dKq=GL=#5*Hvvg_W(3Ati z)&pcKJK?sB$b+&*fyu9(k9(U{DR15RT?K|vbC2lGJc5*5t%=lH-tFE`1$D#)b_9tj z-hUU6bQ^SjCnj_T(3M`)pFdhn#1$dsdO>njLPK79IZ~X$;NodGt15&$1|U=sgE#HH zX#*Vmx;;MwAz<%AS7@N)%6s;)LsQu}PJd{v^U4|S&;-9oG%A^h!wQC)z8wttKoZ>2YT z#*Rm(_qpq3PV*5+$RBEFS8M7KBQmfxV+i4S*9-?8*PAVM`oV5ZYw+Pp8oTXUGc;<#vLBlwq zFlc=SakunFm`!hxf#Aib3CZC#Jt+%tUri7cIBy&WT(Z2y=y8;>0H4y0;ZQ_GR_#Ap zBG*lq!kCO;f=oz<+rK>gAaTCG_q{Ce%38Lz(#I7X;vT z!`<7noU(YOuNpJ`n`6Qh4d+CQrPXrFdc6xbEZYqj<@d+7MCsN+-Fp(N^(hXzcevNy zS^OIYk}tXiT`zYMSgg+no(!MxQOMbdoxf0K*9Jx;JBJ+H<7&iiw|v?6M4dT^w<4lk z%d?H7QGx6Q)Zi<{j#QeW+_rB zHCb0Zx&55@g*|_h_)hX`){FTtM#_S&R7RHb>TV17)*{f2ro0N#&0w>Bds}9d= zL6%rKiU)7#H?l`2~DqW+b#Da(Tj?%>W?os7&um>K$XO+EWEl1Ys`M zJ5Z~JgzZi{TQ3*SepWXj=lg6>Tb!Q$5~@{uCstEZs|6;}xozopGLSa606V{{qv6GA zFl+VEDk6^F7cDm8z8uX+dU^*H?+9~#JO6GaZ;%0A-rSakt1!TeJ&XHU2v>M$7?T1C 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 literal 0 HcmV?d00001 diff --git a/manifest.json b/manifest.json index a83f620..a2f2038 100644 --- a/manifest.json +++ b/manifest.json @@ -6,17 +6,22 @@ "en": "Member dashboard for non profit isp.", "fr": "Coin est un Outil pour un Internet Neutre." }, + "version": "20200630~ynh1", + "url": "https://code.ffdn.org/FFDN/coin/", + "upstream": { + "license": "AGPL-3.0-or-later", + "website": "https://code.ffdn.org/FFDN/coin", + "code": "https://code.ffdn.org/ffdn/coin" + }, "license": "AGPL-3.0-or-later", "maintainer": { "name": "ljf", "email": "ljf+coin_ynh@grimaud.me", "url": "https://www.arn-fai.net" }, - "url": "https://code.ffdn.org/FFDN/coin/", "requirements": { - "yunohost": ">= 4.0" + "yunohost": ">= 4.3.0" }, - "version": "20200630~ynh1", "multi_instance": true, "services": [ "nginx" @@ -25,21 +30,11 @@ "install" : [ { "name": "domain", - "type": "domain", - "ask": { - "en": "Choose a domain for Coin", - "fr": "Choisissez un nom de domaine pour Coin" - }, - "example": "domain.org" + "type": "domain" }, { "name": "admin", - "type": "user", - "ask": { - "en": "Choose the Coin administrator (must be an existing YunoHost user)", - "fr": "Choisissez l'administrateur de Coin (doit être un utilisateur YunoHost)" - }, - "example": "johndoe" + "type": "user" }, { "name": "email", diff --git a/scripts/backup b/scripts/backup index c87097b..e04cdd4 100644 --- a/scripts/backup +++ b/scripts/backup @@ -15,7 +15,6 @@ source /usr/share/yunohost/helpers #================================================= ynh_clean_setup () { - ### Remove this function if there's nothing to clean before calling the remove script. true } # Exit if an error occurs during the execution of the script @@ -24,7 +23,7 @@ ynh_abort_if_errors #================================================= # LOAD SETTINGS #================================================= -ynh_script_progression --message="Loading installation settings..." +ynh_print_info --message="Loading installation settings..." app=$YNH_APP_INSTANCE_NAME @@ -33,8 +32,9 @@ 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 #================================================= +ynh_print_info --message="Declaring files to be backed up..." #================================================= # BACKUP THE APP MAIN DIR @@ -55,9 +55,9 @@ ynh_backup --src_path="/etc/nginx/conf.d/$domain.d/$app.conf" ynh_backup --src_path="/etc/systemd/system/$app.service" #================================================= -# BACKUP THE PSQL DATABASE +# BACKUP THE POSTGRESQL DATABASE #================================================= -ynh_script_progression --message="Backing up the PSQL database..." +ynh_print_info --message="Backing up the PSQL database..." ynh_psql_dump_db --database="$db_name" > db.sql @@ -65,4 +65,4 @@ ynh_psql_dump_db --database="$db_name" > db.sql # END OF SCRIPT #================================================= -ynh_script_progression --message="Backup script completed for $app. (YunoHost will then actually copy those files to the archive)." --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 71c9489..bb9d67a 100644 --- a/scripts/change_url +++ b/scripts/change_url @@ -34,6 +34,24 @@ final_path=$(ynh_app_setting_get --app=$app --key=final_path) #db_user=$db_name #db_pwd=$(ynh_app_setting_get --app=$app --key=db_pwd) +#================================================= +# 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 #================================================= @@ -62,23 +80,23 @@ ynh_systemd_action --service_name=$app --action="stop" --log_path="/var/log/$app #================================================= # MODIFY URL IN NGINX CONF #================================================= -ynh_script_progression --message="Updating nginx web server configuration..." +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 + # Set global variables for NGINX helper domain="$old_domain" path_url="$new_path" - # Create a dedicated nginx config + # 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 @@ -101,12 +119,13 @@ fi #================================================= ynh_script_progression --message="Starting a systemd service..." +# Start a systemd service ynh_systemd_action --service_name=$app --action="start" --log_path="/var/log/$app/$app.log" #================================================= # RELOAD NGINX #================================================= -ynh_script_progression --message="Reloading nginx web server..." +ynh_script_progression --message="Reloading NGINX web server..." ynh_systemd_action --service_name=nginx --action=reload @@ -114,4 +133,4 @@ ynh_systemd_action --service_name=nginx --action=reload # END OF SCRIPT #================================================= -ynh_script_progression --message="Change of URL completed for $app" --last +ynh_script_progression --message="Change of URL completed for $app" diff --git a/scripts/common.sh b/scripts/common.sh deleted file mode 100644 index 87e10a8..0000000 --- a/scripts/common.sh +++ /dev/null @@ -1,18 +0,0 @@ - -function install_dependencies() -{ - # Dependencies - ynh_install_app_dependencies gunicorn python-dev python-pip libldap2-dev libpq-dev libsasl2-dev libjpeg-dev libxml2-dev libxslt1-dev libffi-dev python-cairo libpango1.0-0 postgresql postgresql-contrib #libmysqlclient-dev -} - -function init_db() -{ - ynh_psql_test_if_first_run - # Generate random password - db_name=$app - db_user=$app - db_pwd=$(ynh_string_random) - # Initialize database and store pssql password for upgrade - ynh_psql_create_db $db_name $db_user $db_pwd - ynh_app_setting_set "$app" psqlpassword "$db_pwd" -} diff --git a/scripts/install b/scripts/install index 480d4dc..326867f 100644 --- a/scripts/install +++ b/scripts/install @@ -14,8 +14,7 @@ source /usr/share/yunohost/helpers #================================================= ynh_clean_setup () { - ### Remove this function if there's nothing to clean before calling the remove script. - read + ynh_clean_check_starting } # Exit if an error occurs during the execution of the script ynh_abort_if_errors @@ -53,7 +52,6 @@ ynh_script_progression --message="Storing installation settings..." 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=is_public --value=$is_public ynh_app_setting_set --app=$app --key=admin --value=$admin ynh_app_setting_set --app=$app --key=email --value=$email ynh_app_setting_set --app=$app --key=isp_name --value=$isp_name @@ -69,9 +67,17 @@ ynh_script_progression --message="Installing dependencies..." ynh_install_app_dependencies $pkg_dependencies #================================================= -# CREATE DATABASE +# CREATE DEDICATED USER #================================================= -ynh_script_progression --message="Creating a MySQL database..." +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 @@ -79,7 +85,7 @@ export db_name=$(ynh_sanitize_dbid --db_name=$app) export 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 -export db_pwd +export db_pwd=$(ynh_app_setting_get --app=$app --key=psqlpwd) #================================================= # DOWNLOAD, CHECK AND UNPACK SOURCE @@ -90,22 +96,18 @@ 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" +chmod 750 "$final_path" +chmod -R o-rwx "$final_path" +chown -R $app:www-data "$final_path" + #================================================= # NGINX CONFIGURATION #================================================= -ynh_script_progression --message="Configuring nginx web server..." +ynh_script_progression --message="Configuring NGINX web server..." -# Create a dedicated nginx config +# Create a dedicated NGINX config ynh_add_nginx_config -#================================================= -# CREATE DEDICATED USER -#================================================= -ynh_script_progression --message="Configuring system user..." - -# Create a system user -ynh_system_user_create --username=$app - #================================================= # SPECIFIC SETUP #================================================= @@ -138,6 +140,7 @@ ynh_store_file_checksum --file="$final_path/coin/settings_local.py" #================================================= # SERVE STATIC FILES IN PRODUCTION MODE #================================================= + ln -s $final_path/$app/static $final_path/static #================================================= @@ -152,23 +155,26 @@ $final_path/venv/bin/python manage.py collectstatic --noinput popd # Set permissions to directory -chown $app:www-data -R $final_path +chmod 750 "$final_path" +chmod -R o-rwx "$final_path" +chown -R $app:www-data "$final_path" #================================================ # CONFIGURE LOG DIR #================================================ + mkdir -p /var/log/$app chown -R $app /var/log/$app -chgrp -R www-data /var/log/$app +chown -R $app:www-data "/var/log/$app" #================================================ -# SETUP GUNICORN -#================================================ -ynh_replace_string --match_string="__YNH_APP_INSTANCE_NAME__" --replace_string="$app" --target_file="../conf/gunicorn_config.py" -cp ../conf/gunicorn_config.py $final_path/ -ynh_store_file_checksum --file="$final_path/gunicorn_config.py" +# ADD A CONFIGURATION +#================================================= +ynh_script_progression --message="Adding a configuration file..." -chown $app:www-data $final_path/gunicorn_config.py +ynh_add_config --template="../conf/gunicorn_config.py" --destination="$final_path/gunicorn_config.py" + +chown $app:www-data "$final_path/gunicorn_config.py" #================================================= # SETUP SYSTEMD @@ -178,26 +184,14 @@ ynh_script_progression --message="Configuring a systemd service..." # Create a dedicated systemd config ynh_add_systemd_config - #================================================= # GENERIC FINALIZATION #================================================= -# SECURE FILES AND DIRECTORIES +# INTEGRATE SERVICE IN YUNOHOST #================================================= +ynh_script_progression --message="Integrating service in YunoHost..." -### For security reason, any app should set the permissions to root: before anything else. -### Then, if write authorization is needed, any access should be given only to directories -### that really need such authorization. - -# Set permissions to app files -chown -R $app:www-data $final_path - - -#================================================= -# ADVERTISE SERVICE IN ADMIN PANEL -#================================================= - -yunohost service add $app --description "$app daemon" --log "/var/log/$app/$app.log" +yunohost service add $app --description "$app daemon" --log="/var/log/$app/$app.log" #================================================= # START SYSTEMD SERVICE @@ -210,19 +204,20 @@ ynh_systemd_action --service_name=$app --action="start" --log_path="/var/log/$ap #================================================= # SETUP SSOWAT #================================================= -ynh_script_progression --message="Configuring SSOwat..." +ynh_script_progression --message="Configuring permissions..." # 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="/" + # Everyone can access the app. + # The "main" permission is automatically created before the install script. + ynh_permission_update --permission="main" --add="visitors" fi #================================================= # RELOAD NGINX #================================================= -ynh_script_progression --message="Reloading nginx web server..." +ynh_script_progression --message="Reloading NGINX web server..." ynh_systemd_action --service_name=nginx --action=reload @@ -230,4 +225,4 @@ 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 370bbdc..857674c 100644 --- a/scripts/remove +++ b/scripts/remove @@ -6,6 +6,7 @@ # IMPORT GENERIC HELPERS #================================================= +source _common.sh source /usr/share/yunohost/helpers #================================================= @@ -24,13 +25,13 @@ final_path=$(ynh_app_setting_get --app=$app --key=final_path) #================================================= # STANDARD REMOVE #================================================= -# REMOVE SERVICE FROM ADMIN PANEL +# REMOVE SERVICE INTEGRATION IN YUNOHOST #================================================= -# Remove a service from the admin panel, added by `yunohost service add` +# 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..." + ynh_script_progression --message="Removing $app service integration..." yunohost service remove $app fi @@ -43,21 +44,13 @@ ynh_script_progression --message="Stopping and removing the systemd service..." ynh_remove_systemd_config #================================================= -# REMOVE THE DATABASE +# REMOVE THE POSTGRESQL DATABASE #================================================= -ynh_script_progression --message="Removing the database..." +ynh_script_progression --message="Removing the PostgreSQL database..." # Remove a database if it exists, along with the associated user ynh_psql_remove_db --db_user=$db_user --db_name=$db_name -#================================================= -# REMOVE DEPENDENCIES -#================================================= -ynh_script_progression --message="Removing dependencies..." - -# Remove metapackage and its dependencies -ynh_remove_app_dependencies - #================================================= # REMOVE APP MAIN DIR #================================================= @@ -69,17 +62,28 @@ ynh_secure_remove --file="$final_path" #================================================= # REMOVE NGINX CONFIGURATION #================================================= -ynh_script_progression --message="Removing nginx web server configuration..." +ynh_script_progression --message="Removing NGINX web server configuration..." -# Remove the dedicated nginx config +# Remove the dedicated NGINX config ynh_remove_nginx_config +#================================================= +# REMOVE DEPENDENCIES +#================================================= +ynh_script_progression --message="Removing dependencies..." + +# Remove metapackage and its dependencies +ynh_remove_app_dependencies + #================================================= # SPECIFIC REMOVE #================================================= +# REMOVE VARIOUS FILES +#================================================= +ynh_script_progression --message="Removing various files..." # Remove the log files -ynh_secure_remove --file="/var/log/$app/" +ynh_secure_remove --file="/var/log/$app" #================================================= # GENERIC FINALIZATION @@ -95,4 +99,4 @@ 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 ff09a8b..7c603a8 100644 --- a/scripts/restore +++ b/scripts/restore @@ -15,8 +15,7 @@ source /usr/share/yunohost/helpers #================================================= ynh_clean_setup () { - #### Remove this function if there's nothing to clean before calling the remove script. - true + ynh_clean_check_starting } # Exit if an error occurs during the execution of the script ynh_abort_if_errors @@ -30,23 +29,20 @@ export app=$YNH_APP_INSTANCE_NAME export domain=$(ynh_app_setting_get --app=$app --key=domain) export path_url=$(ynh_app_setting_get --app=$app --key=path) +export final_path=$(ynh_app_setting_get --app=$app --key=final_path) +export db_name=$(ynh_app_setting_get --app=$app --key=db_name) +export db_user=$db_name export admin=$(ynh_app_setting_get --app=$app --key=admin) export email=$(ynh_app_setting_get --app=$app --key=email) export isp_name=$(ynh_app_setting_get --app=$app --key=isp_name) export isp_site=$(ynh_app_setting_get --app=$app --key=isp_site) export secret=$(ynh_app_setting_get --app=$app --key=secret) -export is_public=$(ynh_app_setting_get --app=$app --key=is_public) -export final_path=$(ynh_app_setting_get --app=$app --key=final_path) -export db_name=$(ynh_app_setting_get --app=$app --key=db_name) -export db_user=$db_name #================================================= # CHECK IF THE APP CAN BE RESTORED #================================================= 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 \ || ynh_die --message="There is already a directory: $final_path " @@ -55,16 +51,10 @@ 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..." - -ynh_restore_file --origin_path="$final_path" - #================================================= # RECREATE THE DEDICATED USER #================================================= @@ -74,11 +64,15 @@ ynh_script_progression --message="Recreating the dedicated system user..." ynh_system_user_create --username=$app #================================================= -# RESTORE USER RIGHTS +# RESTORE THE APP MAIN DIR #================================================= +ynh_script_progression --message="Restoring the app main directory..." -# Restore permissions on app files -chown -R $app:www-data $final_path +ynh_restore_file --origin_path="$final_path" + +chmod 750 "$final_path" +chmod -R o-rwx "$final_path" +chown -R $app:www-data "$final_path" #================================================= # SPECIFIC RESTORATION @@ -91,13 +85,13 @@ ynh_script_progression --message="Reinstalling dependencies..." ynh_install_app_dependencies $pkg_dependencies #================================================= -# RESTORE THE PSQL DATABASE +# RESTORE THE POSTGRESQL DATABASE #================================================= -ynh_script_progression --message="Restoring the MySQL database..." +ynh_script_progression --message="Restoring the PostgreSQL database..." ynh_psql_test_if_first_run -db_pwd=$(ynh_app_setting_get --app=$app --key=psqlpwd) +export db_pwd=$(ynh_app_setting_get --app=$app --key=psqlpwd) ynh_psql_setup_db --db_user=$db_user --db_name=$db_name --db_pwd=$db_pwd ynh_psql_connect_as --user=$db_user --password=$db_pwd --database=$db_name < ./db.sql @@ -107,13 +101,22 @@ ynh_psql_connect_as --user=$db_user --password=$db_pwd --database=$db_name < ./d 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 + +#================================================ +# CONFIGURE LOG DIR +#================================================ + +mkdir -p /var/log/$app +chown -R $app /var/log/$app +chgrp -R www-data /var/log/$app #================================================= -# 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 --description "$app daemon" --log="/var/log/$app/$app.log" #================================================= # START SYSTEMD SERVICE @@ -122,20 +125,12 @@ ynh_script_progression --message="Starting a systemd service..." ynh_systemd_action --service_name=$app --action="start" --log_path="/var/log/$app/$app.log" - -#================================================ -# CONFIGURE LOG DIR -#================================================ -mkdir -p /var/log/$app -chown -R $app /var/log/$app -chgrp -R www-data /var/log/$app - #================================================= # GENERIC FINALIZATION #================================================= # RELOAD NGINX #================================================= -ynh_script_progression --message="Reloading nginx web server..." +ynh_script_progression --message="Reloading NGINX web server..." ynh_systemd_action --service_name=nginx --action=reload @@ -143,4 +138,4 @@ ynh_systemd_action --service_name=nginx --action=reload # END OF SCRIPT #================================================= -ynh_script_progression --message="Restoration completed for $app" --last +ynh_script_progression --message="Restoration completed for $app" diff --git a/scripts/upgrade b/scripts/upgrade index 2e09bd0..3d4610f 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -23,7 +23,6 @@ export email=$(ynh_app_setting_get --app=$app --key=email) export isp_name=$(ynh_app_setting_get --app=$app --key=isp_name) export isp_site=$(ynh_app_setting_get --app=$app --key=isp_site) export secret=$(ynh_app_setting_get --app=$app --key=secret) -export is_public=$(ynh_app_setting_get --app=$app --key=is_public) export final_path=$(ynh_app_setting_get --app=$app --key=final_path) export db_name=$(ynh_app_setting_get --app=$app --key=db_name) export db_user=$db_name @@ -32,41 +31,10 @@ export db_pwd=$(ynh_app_setting_get --app=$app --key=psqlpwd) #================================================= # 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..." - -# 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=/opt/$app - ynh_app_setting_set --app=$app --key=final_path --value=$final_path -fi - #================================================= # BACKUP BEFORE UPGRADE THEN ACTIVE TRAP #================================================= @@ -75,7 +43,8 @@ ynh_script_progression --message="Backing up the app before upgrading (may take # 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 @@ -90,6 +59,38 @@ ynh_script_progression --message="Stopping a systemd service..." ynh_systemd_action --service_name=$app --action="stop" --log_path="/var/log/$app/$app.log" +#================================================= +# 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 + +# 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=/opt/$app + ynh_app_setting_set --app=$app --key=final_path --value=$final_path +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,12 +103,16 @@ then 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..." +ynh_script_progression --message="Upgrading NGINX web server configuration..." -# Create a dedicated nginx config +# Create a dedicated NGINX config ynh_add_nginx_config #================================================= @@ -117,14 +122,6 @@ ynh_script_progression --message="Upgrading dependencies..." ynh_install_app_dependencies $pkg_dependencies -#================================================= -# 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 - #================================================= # SPECIFIC UPGRADE #================================================= @@ -160,17 +157,18 @@ virtualenv "$final_path/venv" $final_path/venv/bin/python manage.py collectstatic --noinput ) +chmod 750 "$final_path" +chmod -R o-rwx "$final_path" +chown -R $app:www-data "$final_path" + +#================================================ +# UPDATE A CONFIG FILE #================================================= +ynh_script_progression --message="Updating a configuration file..." -#================================================ -# UPDATE GUNICORN -#================================================ -ynh_backup_if_checksum_is_different --file="$final_path/gunicorn_config.py" -ynh_replace_string --match_string="__YNH_APP_INSTANCE_NAME__" --replace_string="$app" --target_file="../conf/gunicorn_config.py" -cp -f ../conf/gunicorn_config.py $final_path/ -ynh_store_file_checksum --file="$final_path/gunicorn_config.py" +ynh_add_config --template="../conf/gunicorn_config.py" --destination="$final_path/gunicorn_config.py" -chown $app:www-data $final_path/gunicorn_config.py +chown $app:www-data "$final_path/gunicorn_config.py" #================================================= # SETUP SYSTEMD @@ -183,23 +181,11 @@ ynh_add_systemd_config #================================================= # GENERIC FINALIZATION #================================================= -# SECURE FILES AND DIRECTORIES +# INTEGRATE SERVICE IN YUNOHOST #================================================= +ynh_script_progression --message="Integrating service in YunoHost..." -# Set permissions on app files -chown -R $app:www-data $final_path - -#================================================= -# SETUP SSOWAT -#================================================= -ynh_script_progression --message="Upgrading SSOwat configuration..." - -# 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 --description "$app daemon" --log="/var/log/$app/$app.log" #================================================= # START SYSTEMD SERVICE @@ -211,7 +197,7 @@ ynh_systemd_action --service_name=$app --action="start" --log_path="/var/log/$ap #================================================= # RELOAD NGINX #================================================= -ynh_script_progression --message="Reloading nginx web server..." +ynh_script_progression --message="Reloading NGINX web server..." ynh_systemd_action --service_name=nginx --action=reload @@ -219,4 +205,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" From 15a125ccba333f8750601f7f024ff3f8161b749b Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Sun, 13 Mar 2022 22:43:23 +0000 Subject: [PATCH 2/4] Auto-update README --- README.md | 46 ++++++++++++++++++++++++++++++++++++++++------ README_fr.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 README_fr.md diff --git a/README.md b/README.md index 5e0cdce..1a032f6 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,47 @@ -coin_ynh -=============== + -Coin for YunoHost +# Coin for YunoHost + +[![Integration level](https://dash.yunohost.org/integration/coin.svg)](https://dash.yunohost.org/appci/app/coin) ![](https://ci-apps.yunohost.org/ci/badges/coin.status.svg) ![](https://ci-apps.yunohost.org/ci/badges/coin.maintain.svg) +[![Install Coin with YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=coin) + +*[Lire ce readme en français.](./README_fr.md)* + +> *This package allows you to install Coin 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.* + +## Overview + +COIN is an Information System designed for associative ISPs in the FFDN. -More information on https://code.ffdn.org/FFDN/coin +**Shipped version:** 20200630~ynh1 -## Install + +## Screenshots + +![](./doc/screenshots/user-subscriptions.png) + +## Documentation and resources + +* Official app website: https://code.ffdn.org/FFDN/coin +* Upstream app code repository: https://code.ffdn.org/ffdn/coin +* YunoHost documentation for this app: https://yunohost.org/app_coin +* Report a bug: https://github.com/YunoHost-Apps/coin_ynh/issues + +## Developer info + +Please send your pull request to the [testing branch](https://github.com/YunoHost-Apps/coin_ynh/tree/testing). + +To try the testing branch, please proceed like that. ``` -yunohost app install https://github.com/YunoHost-Apps/coin_ynh -a "domain=adherents.arn-fai.net&path=/&email=contact@arn-fai.net&isp_name=ARN&isp_site=//arn-fai.net&admin=ljf" +sudo yunohost app install https://github.com/YunoHost-Apps/coin_ynh/tree/testing --debug +or +sudo yunohost app upgrade coin -u https://github.com/YunoHost-Apps/coin_ynh/tree/testing --debug ``` + +**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 new file mode 100644 index 0000000..3d46e4d --- /dev/null +++ b/README_fr.md @@ -0,0 +1,43 @@ +# Coin pour YunoHost + +[![Niveau d'intégration](https://dash.yunohost.org/integration/coin.svg)](https://dash.yunohost.org/appci/app/coin) ![](https://ci-apps.yunohost.org/ci/badges/coin.status.svg) ![](https://ci-apps.yunohost.org/ci/badges/coin.maintain.svg) +[![Installer Coin avec YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=coin) + +*[Read this readme in english.](./README.md)* +*[Lire ce readme en français.](./README_fr.md)* + +> *Ce package vous permet d'installer Coin 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 + +COIN is an Information System designed for associative ISPs in the FFDN. + + +**Version incluse :** 20200630~ynh1 + + + +## Captures d'écran + +![](./doc/screenshots/user-subscriptions.png) + +## Documentations et ressources + +* Site officiel de l'app : https://code.ffdn.org/FFDN/coin +* Dépôt de code officiel de l'app : https://code.ffdn.org/ffdn/coin +* Documentation YunoHost pour cette app : https://yunohost.org/app_coin +* Signaler un bug : https://github.com/YunoHost-Apps/coin_ynh/issues + +## Informations pour les développeurs + +Merci de faire vos pull request sur la [branche testing](https://github.com/YunoHost-Apps/coin_ynh/tree/testing). + +Pour essayer la branche testing, procédez comme suit. +``` +sudo yunohost app install https://github.com/YunoHost-Apps/coin_ynh/tree/testing --debug +ou +sudo yunohost app upgrade coin -u https://github.com/YunoHost-Apps/coin_ynh/tree/testing --debug +``` + +**Plus d'infos sur le packaging d'applications :** https://yunohost.org/packaging_apps \ No newline at end of file From 654da9fa267c04f5dea809e0858cad9ce8bb47cb Mon Sep 17 00:00:00 2001 From: yalh76 Date: Mon, 14 Mar 2022 20:39:33 +0100 Subject: [PATCH 3/4] Fix upgrade --- scripts/install | 10 +++++----- scripts/upgrade | 21 +++++++++++++++------ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/scripts/install b/scripts/install index 326867f..ed6751b 100644 --- a/scripts/install +++ b/scripts/install @@ -113,13 +113,14 @@ ynh_add_nginx_config #================================================= # PYTHON DEPENDENCIES #================================================= - ynh_script_progression --message="Installing more dependencies..." + virtualenv "$final_path/venv" ( set +o nounset source "${final_path}/venv/bin/activate" set -o nounset + $final_path/venv/bin/pip install --upgrade pip $final_path/venv/bin/pip install gunicorn echo "django-auth-ldap<1.4" >> $final_path/requirements.txt @@ -129,7 +130,6 @@ virtualenv "$final_path/venv" #================================================= # CONFIGURATION DJANGO #================================================= - ynh_script_progression --message="Configuring application..." export prefix="${path_url#"/"}/" @@ -150,9 +150,9 @@ ln -s $final_path/$app/static $final_path/static chown -R $app:www-data $final_path pushd $final_path -$final_path/venv/bin/python manage.py migrate --noinput -$final_path/venv/bin/python manage.py collectstatic --noinput -popd + $final_path/venv/bin/python manage.py migrate --noinput + $final_path/venv/bin/python manage.py collectstatic --noinput +popd # Set permissions to directory chmod 750 "$final_path" diff --git a/scripts/upgrade b/scripts/upgrade index 3d4610f..5ed85a1 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -125,14 +125,15 @@ ynh_install_app_dependencies $pkg_dependencies #================================================= # SPECIFIC UPGRADE #================================================= -# CONFIGURATION DJANGO +# CONFIGURE DJANGO #================================================= +ynh_script_progression --message="Configuring Django..." export prefix="${path_url#"/"}/" prefix=${prefix%"/"} -ynh_backup_if_checksum_is_different --file="$final_path/app/settings_local.py" -ynh_render_template ../conf/local.py.j2 "$final_path/app/setings_local.py" -ynh_store_file_checksum --file="$final_path/app/settings_local.py" +ynh_backup_if_checksum_is_different --file="$final_path/coin/settings_local.py" +ynh_render_template ../conf/local.py.j2 "$final_path/coin/setings_local.py" +ynh_store_file_checksum --file="$final_path/coin/settings_local.py" virtualenv "$final_path/venv" ( @@ -143,18 +144,26 @@ virtualenv "$final_path/venv" #================================================= # PYTHON DEPENDENCIES #================================================= + ynh_script_progression --message="Installing more dependencies..." + echo "django-auth-ldap<1.4" >> $final_path/requirements.txt $final_path/venv/bin/pip install -r $final_path/requirements.txt #================================================= # MIGRATE DB #================================================= - $final_path/venv/bin/python manage.py migrate --noinput + ynh_script_progression --message="Migrating database..." + + pushd $final_path + $final_path/venv/bin/python manage.py migrate --noinput #================================================= # COLLECT FILES #================================================= - $final_path/venv/bin/python manage.py collectstatic --noinput + ynh_script_progression --message="Collecting files..." + + $final_path/venv/bin/python manage.py collectstatic --noinput + popd ) chmod 750 "$final_path" From 0aee6f23435131d11897532e425c10f7ea49e039 Mon Sep 17 00:00:00 2001 From: yalh76 Date: Tue, 15 Mar 2022 03:28:49 +0100 Subject: [PATCH 4/4] More example --- LICENSE | 661 ++++++++++++++++++++++++++++++++++++++++++++++++ conf/nginx.conf | 12 +- 2 files changed, 667 insertions(+), 6 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..be3f7b2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/conf/nginx.conf b/conf/nginx.conf index 78e1da5..3947dc2 100644 --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -8,16 +8,16 @@ location __PATH__/protected/ { alias /opt/__NAME__/__NAME__/smedia/; } -location __PATH__/media { - alias /opt/__NAME__/media; +location __PATH__/media/ { + alias /opt/__NAME__/media/; } -location __PATH__/static { - alias /opt/__NAME__/static; +location __PATH__/static/ { + alias /opt/__NAME__/static/; } -location __PATH__/assets { - alias /opt/__NAME__/static; +location __PATH__/assets/ { + alias /opt/__NAME__/static/; } location @__NAME__ {