commit f0898bfab737b5216c872c4bf8ee275e5bcc0f89 Author: Jimmy Monin Date: Mon Apr 2 16:36:02 2018 +0200 Initial commit diff --git a/check_process b/check_process new file mode 100644 index 0000000..eb851a0 --- /dev/null +++ b/check_process @@ -0,0 +1,35 @@ +;; Test complet + ; Manifest + domain="domain.tld" (DOMAIN) + path="/path" (PATH) + admin="john" (USER) + is_public=1 (PUBLIC|public=1|private=0) + ; Checks + pkg_linter=1 + setup_sub_dir=1 + setup_root=1 + # setup_nourl=0 + # setup_private=1 + # setup_public=1 + # upgrade=1 + # backup_restore=1 + # multi_instance=1 + # incorrect_path=1 + # port_already_use=0 + # change_url=1 +;;; Levels + Level 1=auto + Level 2=auto + Level 3=auto + Level 4=1 +# https://github.com/YunoHost-Apps/piwigo_ynh/issues/4 + Level 5=1 +# https://github.com/YunoHost-Apps/piwigo_ynh/issues/5 + Level 6=auto + Level 7=auto + Level 8=0 + Level 9=0 + Level 10=0 +;;; Options +Email= +Notification=none diff --git a/conf/app.src b/conf/app.src new file mode 100644 index 0000000..0400079 --- /dev/null +++ b/conf/app.src @@ -0,0 +1,3 @@ +SOURCE_URL=https://github.com/discourse/discourse/archive/v1.9.4.tar.gz +SOURCE_SUM=68a2167fda5689a2817534183c3b890f8657677bc883c34e5dd40ac1cbf0c3ac +SOURCE_FORMAT=tar.gz diff --git a/conf/discourse-puma.service b/conf/discourse-puma.service new file mode 100644 index 0000000..da71b50 --- /dev/null +++ b/conf/discourse-puma.service @@ -0,0 +1,22 @@ +[Unit] +Description=__APP__ puma service +Wants=postgresql.service +Wants=redis-server.service +After=redis-server.service +After=postgresql.service +After=discourse-sidekiq.service +Requires=discourse-sidekiq.service + +[Service] +User=__APP__ +Group=__APP__ +WorkingDirectory=__FINALPATH__ +Environment=RAILS_ENV=production +ExecStart=__FINALPATH__/bin/bundle exec puma --config config/puma.rb -e production +ExecStop=__FINALPATH__/bin/bundle exec pumactl stop +RemainAfterExit=true +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target diff --git a/conf/discourse-sidekiq.service b/conf/discourse-sidekiq.service new file mode 100644 index 0000000..db6bc23 --- /dev/null +++ b/conf/discourse-sidekiq.service @@ -0,0 +1,15 @@ +[Unit] +Description=__APP__ sidekiq service +After=network.target + +[Service] +User=__APP__ +Group=__APP__ +WorkingDirectory=__FINALPATH__ +Environment=RAILS_ENV=production +ExecStart=__FINALPATH__/bin/bundle exec sidekiq -C config/sidekiq.yml +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target diff --git a/conf/ldap-auth.src b/conf/ldap-auth.src new file mode 100644 index 0000000..b17b8ec --- /dev/null +++ b/conf/ldap-auth.src @@ -0,0 +1,3 @@ +SOURCE_URL=https://github.com/jonmbake/discourse-ldap-auth/archive/v0.3.5.tar.gz +SOURCE_SUM=18aa689a2583ca1dc6bb75257a8bd951e6bbc6b16d64f5585b0452ffe0e91a8c +SOURCE_FORMAT=tar.gz diff --git a/conf/nginx.conf b/conf/nginx.conf new file mode 100644 index 0000000..2c5780a --- /dev/null +++ b/conf/nginx.conf @@ -0,0 +1,210 @@ + # maximum file upload size (keep up to date when changing the corresponding site setting) + client_max_body_size 10m; + + # path to discourse's public directory + set $public __FINALPATH__/public/; + + # without weak etags we get zero benefit from etags on dynamically compressed content + # further more etags are based on the file in nginx not sha of data + # use dates, it solves the problem fine even cross server + etag off; + + # prevent direct download of backups + location ^~ __PATH__/backups/ { + internal; + } + + # bypass rails stack with a cheap 204 for favicon.ico requests + location __PATH__/favicon.ico { + return 204; + access_log off; + log_not_found off; + } + + location __PATH__ { + alias $public; + add_header ETag ""; + + if ($scheme = http) { + rewrite ^ https://$server_name$request_uri? permanent; + } + + # auth_basic on; + # auth_basic_user_file /etc/nginx/htpasswd; + + # Include SSOWAT user panel. + include conf.d/yunohost_panel.conf.inc; + + + location ~* (assets|plugins|uploads)/.*\.(eot|ttf|woff|woff2|ico)$ { + expires 1y; + add_header Cache-Control public,immutable; + add_header Access-Control-Allow-Origin *; + } + + location = __PATH__/srv/status { + access_log off; + log_not_found off; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Request-Start "t=${msec}"; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + proxy_pass http://unix:__FINALPATH__/tmp/sockets/puma.sock; + break; + } + + # some minimal caching here so we don't keep asking + # longer term we should increas probably to 1y + location ~ ^/javascripts/ { + expires 1d; + add_header Cache-Control public,immutable; + } + + location ~ ^/assets/(?.+)$ { + expires 1y; + # asset pipeline enables this + # brotli_static on; + gzip_static on; + add_header Cache-Control public,immutable; + # HOOK in asset location (used for extensibility) + # TODO I don't think this break is needed, it just breaks out of rewrite + break; + } + + location ~ ^/plugins/ { + expires 1y; + add_header Cache-Control public,immutable; + } + + # cache emojis + location ~ /images/emoji/ { + expires 1y; + add_header Cache-Control public,immutable; + } + + location ~ ^/uploads/ { + + # NOTE: it is really annoying that we can't just define headers + # at the top level and inherit. + # + # proxy_set_header DOES NOT inherit, by design, we must repeat it, + # otherwise headers are not set correctly + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Request-Start "t=${msec}"; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Sendfile-Type X-Accel-Redirect; + proxy_set_header X-Accel-Mapping $public/=/downloads/; + expires 1y; + add_header Cache-Control public,immutable; + + ## optional upload anti-hotlinking rules + #valid_referers none blocked mysite.com *.mysite.com; + #if ($invalid_referer) { return 403; } + + # custom CSS + location ~ /stylesheet-cache/ { + try_files $uri =404; + } + # this allows us to bypass rails + location ~* \.(gif|png|jpg|jpeg|bmp|tif|tiff|svg|ico|webp)$ { + try_files $uri =404; + } + # thumbnails & optimized images + location ~ /_?optimized/ { + try_files $uri =404; + } + + proxy_pass http://unix:__FINALPATH__/tmp/sockets/puma.sock; + break; + } + + location ~ ^/admin/backups/ { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Request-Start "t=${msec}"; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Sendfile-Type X-Accel-Redirect; + proxy_set_header X-Accel-Mapping $public/=/downloads/; + proxy_pass http://unix:__FINALPATH__/tmp/sockets/puma.sock; + break; + } + + # This big block is needed so we can selectively enable + # acceleration for backups and avatars + # see note about repetition above + location ~ ^/(letter_avatar/|user_avatar|highlight-js|stylesheets|favicon/proxied|service-worker) { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Request-Start "t=${msec}"; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + + # if Set-Cookie is in the response nothing gets cached + # this is double bad cause we are not passing last modified in + proxy_ignore_headers "Set-Cookie"; + proxy_hide_header "Set-Cookie"; + + # note x-accel-redirect can not be used with proxy_cache +# proxy_cache one; + proxy_cache_valid 200 301 302 7d; + proxy_cache_valid any 1m; + proxy_pass http://unix:__FINALPATH__/tmp/sockets/puma.sock; + break; + } + +# location /letter_avatar_proxy/ { +# # Don't send any client headers to the avatars service +# proxy_method GET; +# proxy_pass_request_headers off; +# proxy_pass_request_body off; +# +# # Don't let cookies interrupt caching, and don't pass them to the +# # client +# proxy_ignore_headers "Set-Cookie"; +# proxy_hide_header "Set-Cookie"; +# +# proxy_cache one; +# proxy_cache_key $uri; +# proxy_cache_valid 200 7d; +# proxy_cache_valid 404 1m; +# proxy_set_header Connection ""; +# +# proxy_pass https://avatars.discourse.org/; +# break; +# } + + # we need buffering off for message bus + location __PATH__/message-bus/ { + proxy_set_header X-Request-Start "t=${msec}"; + proxy_set_header Host $http_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 https; + proxy_http_version 1.1; + proxy_buffering off; + proxy_pass http://unix:__FINALPATH__/tmp/sockets/puma.sock; + break; + } + + # this means every file in public is tried first + try_files $uri @__NAME__; + } + + location __PATH__/downloads/ { + internal; + alias $public/; + } + + location @__NAME__ { + add_header Referrer-Policy 'no-referrer-when-downgrade'; + proxy_set_header Host $http_host; + proxy_set_header X-Request-Start "t=${msec}"; + 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 https; + proxy_pass http://unix:__FINALPATH__/tmp/sockets/puma.sock; +} diff --git a/conf/secrets.yml b/conf/secrets.yml new file mode 100644 index 0000000..dd1d809 --- /dev/null +++ b/conf/secrets.yml @@ -0,0 +1,8 @@ +development: + secret_key_base: + +test: + secret_key_base: + +production: + secret_key_base: __SECRET__ diff --git a/conf/sidekiq.yml b/conf/sidekiq.yml new file mode 100644 index 0000000..4c8ab29 --- /dev/null +++ b/conf/sidekiq.yml @@ -0,0 +1,11 @@ +--- +:concurrency: 5 +:pidfile: tmp/pids/sidekiq.pid +staging: + :concurrency: 10 +production: + :concurrency: 20 +:queues: + - default + - critical + - low diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..eb17573 --- /dev/null +++ b/manifest.json @@ -0,0 +1,65 @@ +{ + "name": "Discourse", + "id": "discourse", + "packaging_format": 1, + "description": { + "en": "photo gallery", + "fr": "Galerie photo" + }, + "version": "1.9.4~ynh1", + "url": "http://Discourse.org", + "license": "GPL-2.0", + "maintainer": { + "name": "JimboJoe", + "email": "jimmy@monin.net", + "url": "" + }, + "requirements": { + "yunohost": ">= 2.7.9" + }, + "multi_instance": true, + "services": [ + "nginx" + ], + "arguments": { + "install" : [ + { + "name": "domain", + "type": "domain", + "ask": { + "en": "Choose a domain for Discourse", + "fr": "Choisissez un nom de domaine pour Discourse" + }, + "example": "domain.org" + }, + { + "name": "path", + "type": "path", + "ask": { + "en": "Choose a path for Discourse", + "fr": "Choisissez un chemin pour Discourse" + }, + "example": "/forum", + "default": "/forum" + }, + { + "name": "admin", + "type": "user", + "ask": { + "en": "Choose an admin user", + "fr": "Choisissez l'administrateur" + }, + "example": "homer" + }, + { + "name": "is_public", + "type": "boolean", + "ask": { + "en": "Is it a public application?", + "fr": "Est-ce une application publique ?" + }, + "default": true + } + ] + } +} diff --git a/scripts/_common.sh b/scripts/_common.sh new file mode 100644 index 0000000..f545a42 --- /dev/null +++ b/scripts/_common.sh @@ -0,0 +1,295 @@ +#!/bin/bash +# +# Common variables +# + +pkg_dependencies="ruby-zip libssl-dev libyaml-dev libcurl4-openssl-dev ruby gem libapr1-dev libxslt1-dev checkinstall libxml2-dev ruby-dev vim libmagickwand-dev imagemagick postgresql postgresql-server-dev-all" + +# Execute a command as another user +# usage: exec_as USER COMMAND [ARG ...] +exec_as() { + local user=$1 + shift 1 + + if [[ $user = $(whoami) ]]; then + eval "$@" + else + sudo -u "$user" "$@" + fi +} + +#================================================= +# POSTGRES HELPERS +#================================================= + +ynh_psql_test_if_first_run() { + if [ -f /etc/yunohost/psql ]; + then + echo "PostgreSQL is already installed, no need to create master password" + else + pgsql=$(ynh_string_random) + pg_hba="" + echo "$pgsql" >> /etc/yunohost/psql + + if [ -e /etc/postgresql/9.4/ ] + then + pg_hba=/etc/postgresql/9.4/main/pg_hba.conf + elif [ -e /etc/postgresql/9.6/ ] + then + pg_hba=/etc/postgresql/9.6/main/pg_hba.conf + else + ynh_die "postgresql shoud be 9.4 or 9.6" + fi + + systemctl start postgresql + su --command="psql -c\"ALTER user postgres WITH PASSWORD '${pgsql}'\"" postgres + # we can't use peer since YunoHost create users with nologin + sed -i '/local\s*all\s*all\s*peer/i \ + local all all password' "$pg_hba" + systemctl enable postgresql + systemctl reload postgresql + fi +} + +# Open a connection as a user +# +# example: ynh_psql_connect_as 'user' 'pass' <<< "UPDATE ...;" +# example: ynh_psql_connect_as 'user' 'pass' < /path/to/file.sql +# +# usage: ynh_psql_connect_as user pwd [db] +# | arg: user - the user name to connect as +# | arg: pwd - the user password +# | arg: db - the database to connect to +ynh_psql_connect_as() { + user="$1" + pwd="$2" + db="$3" + su --command="PGUSER=\"${user}\" PGPASSWORD=\"${pwd}\" psql \"${db}\"" postgres +} + +# # Execute a command as root user +# +# usage: ynh_psql_execute_as_root sql [db] +# | arg: sql - the SQL command to execute +# | arg: db - the database to connect to +ynh_psql_execute_as_root () { + sql="$1" + su --command="psql" postgres <<< "$sql" +} + +# Execute a command from a file as root user +# +# usage: ynh_psql_execute_file_as_root file [db] +# | arg: file - the file containing SQL commands +# | arg: db - the database to connect to +ynh_psql_execute_file_as_root() { + file="$1" + db="$2" + su -c "psql $db" postgres < "$file" +} + +# Create a database, an user and its password. Then store the password in the app's config +# +# After executing this helper, the password of the created database will be available in $db_pwd +# It will also be stored as "psqlpwd" into the app settings. +# +# usage: ynh_psql_setup_db user name [pwd] +# | arg: user - Owner of the database +# | arg: name - Name of the database +# | arg: pwd - Password of the database. If not given, a password will be generated +ynh_psql_setup_db () { + db_user="$1" + app="$1" + db_name="$2" + new_db_pwd=$(ynh_string_random) # Generate a random password + # If $3 is not given, use new_db_pwd instead for db_pwd. + db_pwd="${3:-$new_db_pwd}" + ynh_psql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database + ynh_app_setting_set "$app" psqlpwd "$db_pwd" # Store the password in the app's config +} + +# Create a database and grant optionnaly privilegies to a user +# +# usage: ynh_psql_create_db db [user [pwd]] +# | arg: db - the database name to create +# | arg: user - the user to grant privilegies +# | arg: pwd - the user password +ynh_psql_create_db() { + db="$1" + user="$2" + pwd="$3" + ynh_psql_create_user "$user" "$pwd" + su --command="createdb --owner=\"${user}\" \"${db}\"" postgres +} + +# Drop a database +# +# usage: ynh_psql_drop_db db +# | arg: db - the database name to drop +# | arg: user - the user to drop +ynh_psql_remove_db() { + db="$1" + user="$2" + # Force disconnections from the database (https://dba.stackexchange.com/a/11895) + ynh_psql_execute_as_root "UPDATE pg_database SET datallowconn = 'false' WHERE datname = '${db}';" + ynh_psql_execute_as_root "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '${db}';" + + su --command="dropdb \"${db}\"" postgres + ynh_psql_drop_user "${user}" +} + +# Dump a database +# +# example: ynh_psql_dump_db 'roundcube' > ./dump.sql +# +# usage: ynh_psql_dump_db db +# | arg: db - the database name to dump +# | ret: the psqldump output +ynh_psql_dump_db() { + db="$1" + su --command="pg_dump \"${db}\"" postgres +} + + +# Create a user +# +# usage: ynh_psql_create_user user pwd [host] +# | arg: user - the user name to create +ynh_psql_create_user() { + user="$1" + pwd="$2" + su --command="psql -c\"CREATE USER ${user} WITH PASSWORD '${pwd}'\"" postgres +} + +# Drop a user +# +# usage: ynh_psql_drop_user user +# | arg: user - the user name to drop +ynh_psql_drop_user() { + user="$1" + su --command="dropuser \"${user}\"" postgres +} + + +# ============= FUTURE YUNOHOST HELPERS ============= + +# Create a dedicated fail2ban config (jail and filter conf files) +# +# usage: ynh_add_fail2ban_config log_file filter [max_retry [ports]] +# | arg: log_file - Log file to be checked by fail2ban +# | arg: failregex - Failregex to be looked for by fail2ban +# | arg: max_retry - Maximum number of retries allowed before banning IP address - default: 3 +# | arg: ports - Ports blocked for a banned IP address - default: http,https +ynh_add_fail2ban_config () { + # Process parameters + logpath=$1 + failregex=$2 + max_retry=${3:-3} + ports=${4:-http,https} + + test -n "$logpath" || ynh_die "ynh_add_fail2ban_config expects a logfile path as first argument and received nothing." + test -n "$failregex" || ynh_die "ynh_add_fail2ban_config expects a failure regex as second argument and received nothing." + + finalfail2banjailconf="/etc/fail2ban/jail.d/$app.conf" + finalfail2banfilterconf="/etc/fail2ban/filter.d/$app.conf" + ynh_backup_if_checksum_is_different "$finalfail2banjailconf" 1 + ynh_backup_if_checksum_is_different "$finalfail2banfilterconf" 1 + + cat > $finalfail2banjailconf < $finalfail2banfilterconf <&2 + echo "WARNING${fail2ban_error#*WARNING}" >&2 + fi +} + +# Remove the dedicated fail2ban config (jail and filter conf files) +# +# usage: ynh_remove_fail2ban_config +ynh_remove_fail2ban_config () { + ynh_secure_remove "/etc/fail2ban/jail.d/$app.conf" + ynh_secure_remove "/etc/fail2ban/filter.d/$app.conf" + systemctl restart fail2ban +} + +# Delete a file checksum from the app settings +# +# $app should be defined when calling this helper +# +# usage: ynh_remove_file_checksum file +# | arg: file - The file for which the checksum will be deleted +ynh_delete_file_checksum () { + local checksum_setting_name=checksum_${1//[\/ ]/_} # Replace all '/' and ' ' by '_' + ynh_app_setting_delete $app $checksum_setting_name +} + +#!/bin/bash + +# Start or restart a service and follow its booting +# +# usage: ynh_check_starting_systemd "Line to match" [Service name] [Timeout] +# +# | arg: Line to match - The line to find in the log to attest the service have finished to boot. +# | arg: Service name +# | arg: Timeout - The maximum time to wait before ending the watching. Defaut 300 seconds. +ynh_check_starting_systemd () { + local line_to_match="$1" + local service_name="${2:-$app}" + local timeout=${3:-300} + + ynh_clean_check_starting_systemd () { + # Stop the execution of tail. + kill -s 15 $pid_tail 2>&1 + ynh_secure_remove "$templog" 2>&1 + } + + echo "Starting of $service_name" >&2 + systemctl stop $service_name + local templog="$(mktemp)" + # Follow the starting of the app in its log + journalctl -u $service_name -f > "$templog" & + # Get the PID of the tail command + local pid_tail=$! + systemctl start $service_name + + local i=0 + for i in `seq 1 $timeout` + do + # Read the log until the sentence is found, that means the app finished starting. Or run until the timeout + if grep --quiet "$line_to_match" "$templog" + then + echo "The service $service_name has correctly started." >&2 + break + fi + echo -n "." >&2 + sleep 1 + done + if [ $i -eq $timeout ] + then + echo "The service $service_name didn't fully started before the timeout." >&2 + fi + + echo "" + ynh_clean_check_starting_systemd +} diff --git a/scripts/install b/scripts/install new file mode 100644 index 0000000..e63dc56 --- /dev/null +++ b/scripts/install @@ -0,0 +1,266 @@ +#!/bin/bash +shopt -s extglob # sets extended pattern matching options in the bash shell + +#================================================= +# GENERIC STARTING +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source _common.sh +source /usr/share/yunohost/helpers + +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +ynh_clean_setup () { +# Nettoyage des résidus d'installation non pris en charge par le script remove. + ynh_clean_check_starting_systemd +} +ynh_abort_if_errors # Stop script if an error is detected + +#================================================= +# RETRIEVE ARGUMENTS FROM THE MANIFEST +#================================================= + +# Retrieve app id +app=$YNH_APP_INSTANCE_NAME + +# Retrieve arguments +domain=$YNH_APP_ARG_DOMAIN +path_url=$YNH_APP_ARG_PATH +admin=$YNH_APP_ARG_ADMIN +is_public=$YNH_APP_ARG_IS_PUBLIC + +#================================================= +# CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS +#================================================= + +path_url=$(ynh_normalize_url_path $path_url) # Check and normalize path + +final_path=/var/www/$app +test ! -e "$final_path" || ynh_die "This path already contains a folder" + +# Check web path availability +ynh_webpath_available $domain $path_url +# Register (book) web path +ynh_webpath_register $app $domain $path_url + +#================================================= +# STORE SETTINGS FROM MANIFEST +#================================================= + +ynh_app_setting_set $app domain "$domain" +ynh_app_setting_set $app path_url "$path_url" +ynh_app_setting_set $app admin "$admin" +ynh_app_setting_set $app is_public "$is_public" + +#================================================= +# STANDARD MODIFICATIONS +#================================================= +# INSTALL DEPENDENCIES +#================================================= + +ynh_install_app_dependencies "$pkg_dependencies" + +#================================================= +# CREATE A POSTGRES DATABASE +#================================================= + +db_name=$(ynh_sanitize_dbid $app) +db_pwd=$(ynh_string_random) +ynh_app_setting_set $app db_name $db_name +ynh_app_setting_set $app psqlpwd $db_pwd +ynh_psql_test_if_first_run +ynh_psql_create_db $db_name $db_name $db_pwd +# Set extensions +ynh_psql_execute_as_root "\connect $db_name +CREATE EXTENSION IF NOT EXISTS hstore; CREATE EXTENSION IF NOT EXISTS pg_trgm;" + +#================================================= +# DOWNLOAD, CHECK AND UNPACK SOURCE +#================================================= + +ynh_app_setting_set $app final_path $final_path +# Download, check integrity, uncompress and patch the source from app.src +ynh_setup_source "$final_path" +# Install LDAP plugin +mkdir -p "$final_path/plugins/discourse-ldap-auth" +ynh_setup_source "$final_path/plugins/discourse-ldap-auth" ldap-auth + +#================================================= +# NGINX CONFIGURATION +#================================================= + +# Reference: https://meta.discourse.org/t/subfolder-support-with-docker/30507?u=falco&source_topic_id=54191 +if [ "$path_url" != "/" ] ; then + # ynh_replace_string 'proxy_pass http://unix:__FINALPATH__/tmp/sockets/puma.sock;' 'rewrite ^/(.*)$ __PATH__/$1 break; proxy_pass http://unix:__FINALPATH__/tmp/sockets/puma.sock;' ../conf/nginx.conf + # ynh_replace_string 'etag off;' 'etag off; location __PATH__ { rewrite ^__PATH__/?(.*)$ /$1; }' ../conf/nginx.conf + ynh_replace_string '$proxy_add_x_forwarded_for' '$http_your_original_ip_header' ../conf/nginx.conf +fi + +# Create a dedicated nginx config +ynh_add_nginx_config + +#================================================= +# CREATE DEDICATED USER +#================================================= + +# Create a system user +ynh_system_user_create $app "$final_path" + +#================================================= +# SPECIFIC SETUP +#================================================= + +#================================================= +# CONFIGURE DISCOURSE +#================================================= + +# Configure database +cp $final_path/config/discourse_defaults.conf $final_path/config/discourse.conf +#ynh_replace_string "db_host =" "db_host = localhost" "$final_path/config/discourse.conf" +ynh_replace_string "db_name = discourse" "db_name = $db_name" "$final_path/config/discourse.conf" +ynh_replace_string "db_username = discourse" "db_username = $db_name" "$final_path/config/discourse.conf" +ynh_replace_string "db_password =" "db_password = $db_pwd" "$final_path/config/discourse.conf" + +# Configure hostname +ynh_replace_string "hostname = \"www.example.com\"" "hostname = \"$domain\"" "$final_path/config/discourse.conf" +ynh_replace_string "relative_url_root =" "relative_url_root = ${path_url%/}" "$final_path/config/discourse.conf" +# Serve static assets (i.e. images, js, etc.) +ynh_replace_string "serve_static_assets = false" "serve_static_assets = true" "$final_path/config/discourse.conf" + +# Configure e-mail server +admin_mail=$(ynh_user_get_info "$admin" mail) +ynh_replace_string "developer_emails =" "developer_emails = $admin_mail" "$final_path/config/discourse.conf" +ynh_replace_string "smtp_address =" "smtp_address = localhost" "$final_path/config/discourse.conf" +ynh_replace_string "smtp_domain =" "smtp_domain = $domain" "$final_path/config/discourse.conf" +ynh_replace_string "smtp_enable_start_tls = true" "smtp_enable_start_tls = false" "$final_path/config/discourse.conf" + +# Calculate and store the config file checksum +ynh_store_file_checksum "$final_path/config/discourse.conf" + +# Configure LDAP plugins +ynh_replace_string "adfs.example.com" "localhost" "$final_path/plugins/discourse-ldap-auth/config/settings.yml" +ynh_replace_string "dc=example,dc=com" "ou=users,dc=yunohost,dc=org" "$final_path/plugins/discourse-ldap-auth/config/settings.yml" +ynh_replace_string "sAMAccountName" "uid" "$final_path/plugins/discourse-ldap-auth/config/settings.yml" + +#================================================= +# SETUP PUMA, A RUBY SERVER +#================================================= + +ynh_replace_string "#{APP_ROOT}/log/puma" "/var/log/$app/puma" "$final_path/config/puma.rb" +ynh_replace_string "/home/discourse" "/var/www" "$final_path/config/puma.rb" +ynh_replace_string "daemonize true" "daemonize false" "$final_path/config/puma.rb" +# Calculate and store the config file checksum +ynh_store_file_checksum "$final_path/config/puma.rb" + +# Set a secret value +cp ../conf/secrets.yml "$final_path/config/secrets.yml" +ynh_replace_string "__SECRET__" "$(ynh_string_random)" "$final_path/config/secrets.yml" +# Calculate and store the config file checksum +ynh_store_file_checksum "$final_path/config/secrets.yml" + +# Set permissions to app files +chown -R $app: $final_path + + +# # Install puma with gem +(cd "$final_path" +# # Install bundler, a gems installer +gem install bundler +# # Install without documentation +exec_as $app echo "gem: --no-ri --no-rdoc" >> "$final_path/.gemrc" +# # Install dependencies +exec_as $app bundle install --path vendor/bundle --without development test postgresql) + +#================================================= +# SETUP SIDEKIQ +#================================================= +cp ../conf/sidekiq.yml "$final_path/config/sidekiq.yml" + +#================================================= +# PREPARE THE DATABASE +#================================================= + +(cd "$final_path" +rake_exec="exec_as $app bin/rake RAILS_ENV=production" +$rake_exec db:migrate +$rake_exec assets:precompile) + +#================================================= +# INSTALL PLUGINS +#================================================= + +# # Install LDAP plugin +# ynh_setup_source "$final_path/plugins" ldap-auth +# # Set permissions to app files +# chown -R $app: $final_path/plugins +# # TODO install all in one shot? +# (cd "$final_path" +# exec_as $app bin/rake RAILS_ENV=production assets:precompile) + +# TODO setup + +#================================================= +# SETUP SYSTEMD +#================================================= + +ynh_add_systemd_config $app-puma discourse-puma.service +ynh_add_systemd_config $app-sidekiq discourse-sidekiq.service + + +#================================================= +# GENERIC FINALIZATION +#================================================= +# SECURE FILES AND DIRECTORIES +#================================================= + +# Add a pids and socket directory for the systemd script. +mkdir -p "$final_path/tmp/pids" +mkdir "$final_path/tmp/sockets" + +# Set permissions to app files +chown -R $app: $final_path + +#================================================= +# SETUP LOGROTATE +#================================================= + +mkdir -p /var/log/$app +chown -R $app: /var/log/$app + +# Use logrotate to manage application logfile(s) +ynh_use_logrotate + +#================================================= +# ADVERTISE SERVICE IN ADMIN PANEL +#================================================= + +yunohost service add $app-puma --log "/var/log/$app/puma.stderr.log" +yunohost service add $app-sidekiq --log "/var/www/$app/log/production.log" + +#================================================= +# SETUP SSOWAT +#================================================= + +# If app is public, add url to SSOWat conf as skipped_uris +if [ $is_public -eq 1 ]; then + # unprotected_uris allows SSO credentials to be passed anyway. + ynh_app_setting_set "$app" unprotected_uris "/" +fi + +#================================================= +# RELOAD NGINX +#================================================= + +systemctl reload nginx + +#================================================= +# START PUMA AND SIDEKIQ +#================================================= + +# Wait for discourse-puma to be fully started +# As discourse-sidekiq is a dependency, it is automatically started before +ynh_check_starting_systemd "Use Ctrl-C to stop" "$app-puma" "120"