From ee27947a0b7508fe7d016267773fb729ecc2b079 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Sun, 20 May 2018 14:43:15 +0200 Subject: [PATCH 01/16] Improve uwsgi, fix root install, upgrade postgresql --- conf/uwsgi-app@.service | 4 ++++ conf/uwsgi-app@.socket | 11 ---------- scripts/_common.sh | 45 +++++++++++++++++++++++------------------ scripts/backup | 1 - scripts/install | 24 ++++++++++++++++------ scripts/remove | 2 +- scripts/restore | 14 ++++++++----- scripts/upgrade | 22 ++++++++++++++++++++ 8 files changed, 79 insertions(+), 44 deletions(-) delete mode 100644 conf/uwsgi-app@.socket diff --git a/conf/uwsgi-app@.service b/conf/uwsgi-app@.service index c4603d4..888994d 100644 --- a/conf/uwsgi-app@.service +++ b/conf/uwsgi-app@.service @@ -6,6 +6,7 @@ After=syslog.target ExecStart=/usr/bin/uwsgi \ --ini /etc/uwsgi/apps-available/%i.ini \ --socket /var/run/uwsgi/%i.socket \ + --chmod-socket=775 \ --logto /var/log/uwsgi/app/%i User=%i Group=www-data @@ -14,3 +15,6 @@ KillSignal=SIGQUIT Type=notify StandardError=syslog NotifyAccess=all + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/conf/uwsgi-app@.socket b/conf/uwsgi-app@.socket deleted file mode 100644 index 0975e29..0000000 --- a/conf/uwsgi-app@.socket +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=Socket for uWSGI app %i - -[Socket] -ListenStream=/var/run/uwsgi/%i.socket -SocketUser=%i -SocketGroup=www-data -SocketMode=0775 - -[Install] -WantedBy=sockets.target diff --git a/scripts/_common.sh b/scripts/_common.sh index 6d43622..22cc3a4 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -5,13 +5,7 @@ current_version="2.20" ynh_check_global_uwsgi_config () { uwsgi --version || ynh_die "You need to add uwsgi (and appropriate plugin) as a dependency" - if [ -f /etc/systemd/system/uwsgi-app@.service ]; - then - echo "Uwsgi generic file is already installed" - else - cp ../conf/uwsgi-app@.socket /etc/systemd/system/uwsgi-app@.socket - cp ../conf/uwsgi-app@.service /etc/systemd/system/uwsgi-app@.service - fi + cp ../conf/uwsgi-app@.service /etc/systemd/system/uwsgi-app@.service # make sure the folder for sockets exists and set authorizations mkdir -p /var/run/uwsgi/ @@ -63,12 +57,12 @@ ynh_add_uwsgi_service () { ynh_store_file_checksum "$finaluwsgiini" chown root: "$finaluwsgiini" - systemctl enable "uwsgi-app@$app.socket" - systemctl start "uwsgi-app@$app.socket" + systemctl daemon-reload + systemctl enable "uwsgi-app@$app.service" # Add as a service - yunohost service add "uwsgi-app@$app.socket" --log "/var/log/uwsgi/app/$app" + yunohost service add "uwsgi-app@$app.service" --log "/var/log/uwsgi/app/$app" } # Remove the dedicated uwsgi ini file @@ -77,12 +71,11 @@ ynh_add_uwsgi_service () { ynh_remove_uwsgi_service () { finaluwsgiini="/etc/uwsgi/apps-available/$app.ini" if [ -e "$finaluwsgiini" ]; then - systemctl stop "uwsgi-app@$app.socket" - systemctl disable "uwsgi-app@$app.socket" - yunohost service remove "uwsgi-app@$app.socket" + systemctl stop "uwsgi-app@$app.service" + systemctl disable "uwsgi-app@$app.service" + yunohost service remove "uwsgi-app@$app.service" ynh_secure_remove "$finaluwsgiini" - ynh_secure_remove "/var/run/uwsgi/$app.socket" ynh_secure_remove "/var/log/uwsgi/app/$app" fi } @@ -124,6 +117,18 @@ ynh_check_if_checksum_is_different() { echo "$check" } +#================================================= +# +# POSTGRES HELPERS +# +# Point of contact : Jean-Baptiste Holcroft +#================================================= + +# Create a master password and set up global settings +# Please always call this script in install and restore scripts +# +# usage: ynh_psql_test_if_first_run + ynh_psql_test_if_first_run() { if [ -f /etc/yunohost/psql ]; then @@ -144,8 +149,12 @@ ynh_psql_test_if_first_run() { 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 + sudo --login --user=postgres psql -c"ALTER user postgres WITH PASSWORD '$pgsql'" postgres + + # force all user to connect to local database using passwords + # https://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html#EXAMPLE-PG-HBA.CONF + # Note: we can't use peer since YunoHost create users with nologin + # See: https://github.com/YunoHost/yunohost/blob/unstable/data/helpers.d/user sed -i '/local\s*all\s*all\s*peer/i \ local all all password' "$pg_hba" systemctl enable postgresql @@ -167,7 +176,6 @@ ynh_psql_connect_as() { pwd="$2" db="$3" sudo --login --user=postgres PGUSER="$user" PGPASSWORD="$pwd" psql "$db" - echo "ynh_psql_connect_as" && pwd && ls -lah $(pwd) } # # Execute a command as root user @@ -178,7 +186,6 @@ ynh_psql_connect_as() { ynh_psql_execute_as_root () { sql="$1" sudo --login --user=postgres psql <<< "$sql" - echo "ynh_psql_execute_as_root" && pwd && ls -lah $(pwd) } # Execute a command from a file as root user @@ -190,7 +197,6 @@ ynh_psql_execute_file_as_root() { file="$1" db="$2" sudo --login --user=postgres psql "$db" < "$file" - echo "ynh_psql_execute_file_as_root" && pwd && ls -lah $(pwd) } # Create a database, an user and its password. Then store the password in the app's config @@ -204,7 +210,6 @@ ynh_psql_execute_file_as_root() { # | 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. diff --git a/scripts/backup b/scripts/backup index 1acc508..e159b99 100755 --- a/scripts/backup +++ b/scripts/backup @@ -61,7 +61,6 @@ ynh_backup "/etc/cron.d/$app" #================================================= ynh_backup "/etc/uwsgi/apps-available/$app.ini" -ynh_backup "/etc/systemd/system/uwsgi-app@.socket" ynh_backup "/etc/systemd/system/uwsgi-app@.service" #================================================= diff --git a/scripts/install b/scripts/install index 9bda175..2dc9a2d 100755 --- a/scripts/install +++ b/scripts/install @@ -85,14 +85,13 @@ ynh_install_app_dependencies libxml2-dev libxslt-dev libfreetype6-dev \ # CREATE A PostgreSQL DATABASE #================================================= +db_name=$(ynh_sanitize_dbid "$app") +ynh_app_setting_set "$app" db_name "$db_name" + ynh_psql_test_if_first_run -db_name=$(ynh_sanitize_dbid "$app") -db_user_pwd=$(ynh_string_random) # Initialize database and store postgres password for upgrade -ynh_psql_create_db "$db_name" "$app" "$db_user_pwd" -ynh_app_setting_set "$app" db_name "$db_name" -ynh_app_setting_set "$app" psqlpwd "$db_user_pwd" +ynh_psql_setup_db "$db_name" "$app" systemctl reload postgresql @@ -176,6 +175,13 @@ EOF ynh_add_uwsgi_service +# root install doesn't require uwsgi to handle script names +if [ "$path_url" == "/" ] +then + ynh_replace_string "manage-script-name = true" "manage-script-name = false" "$finaluwsgiini" + ynh_store_file_checksum "$finaluwsgiini" +fi + #================================================= # PIP INSTALLATION #================================================= @@ -274,6 +280,12 @@ then ynh_store_file_checksum "$finalnginxconf" fi +#================================================= +# Start weblate +#================================================= + +systemctl start "uwsgi-app@$app.service" + #================================================= # RELOAD NGINX #================================================= @@ -289,4 +301,4 @@ Weblate settings file : $settings If you facing an issue or want to improve this app, please open a new issue in this project: https://github.com/YunoHost-Apps/weblate_ynh " -ynh_send_readme_to_admin "$message" "$admin" +ynh_send_readme_to_admin "$message" "$admin" \ No newline at end of file diff --git a/scripts/remove b/scripts/remove index a8452b3..c377707 100755 --- a/scripts/remove +++ b/scripts/remove @@ -14,7 +14,7 @@ source /usr/share/yunohost/helpers #================================================= app=$YNH_APP_INSTANCE_NAME - +domain=$(ynh_app_setting_get "$app" domain) db_name=$(ynh_app_setting_get "$app" db_name) #================================================= diff --git a/scripts/restore b/scripts/restore index 4159545..a5518bd 100755 --- a/scripts/restore +++ b/scripts/restore @@ -84,14 +84,13 @@ ynh_install_app_dependencies libxml2-dev libxslt-dev libfreetype6-dev \ #================================================= ynh_psql_test_if_first_run -ynh_psql_setup_db "$db_name" "$db_name" "$db_pwd" +ynh_psql_create_db "$db_name" "$db_name" "$db_pwd" ynh_psql_execute_file_as_root ./db.sql "$db_name" #================================================= # RESTORE THE UWSGI MECANICS #================================================= -ynh_restore_file "/etc/systemd/system/uwsgi-app@.socket" ynh_restore_file "/etc/systemd/system/uwsgi-app@.service" # make sure the folder for sockets exists and set authorizations @@ -112,12 +111,11 @@ usermod --append --groups www-data "$app" ynh_restore_file "/etc/uwsgi/apps-available/$app.ini" -systemctl enable "uwsgi-app@$app.socket" -systemctl start "uwsgi-app@$app.socket" systemctl daemon-reload +systemctl enable "uwsgi-app@$app.service" # Add as a service -yunohost service add "uwsgi-app@$app.socket" --log "/var/log/uwsgi/app/$app" +yunohost service add "uwsgi-app@$app.service" --log "/var/log/uwsgi/app/$app" #================================================= # RESTORE THE CRON FILE @@ -133,6 +131,12 @@ ynh_restore_file "/usr/bin/hub" #================================================= # GENERIC FINALIZATION +#================================================= +# Start weblate +#================================================= + +systemctl start "uwsgi-app@$app.service" + #================================================= # RELOAD NGINX & uwsgi #================================================= diff --git a/scripts/upgrade b/scripts/upgrade index 08d1adf..3e265cc 100755 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -83,6 +83,15 @@ then ynh_secure_remove "/etc/systemd/system/$app.service" fi +# (<2.20) remove your old sockets! +if [ -e "/etc/systemd/system/uwsgi-app@.socket" ] +then + systemctl stop "uwsgi-app@$app.socket" + yunohost service remove "uwsgi-app@$app.socket" + ynh_secure_remove "/etc/systemd/system/uwsgi-app@.socket" + systemctl daemon-reload +fi + # (<2.18) move hub to the correct folder if [ -e "$final_path/bin/hub" ] then @@ -145,6 +154,13 @@ ynh_install_app_dependencies libxml2-dev libxslt-dev libfreetype6-dev \ ynh_add_uwsgi_service +# root install doesn't require uwsgi to handle script names +if [ "$path_url" == "/" ] +then + ynh_replace_string "manage-script-name = true" "manage-script-name = false" "$finaluwsgiini" + ynh_store_file_checksum "$finaluwsgiini" +fi + #================================================= # PIP INSTALLATION #================================================= @@ -274,6 +290,12 @@ then ynh_store_file_checksum "$finalnginxconf" fi +#================================================= +# Restart weblate +#================================================= + +systemctl start "uwsgi-app@$app.service" + #================================================= # RELOAD NGINX #================================================= From f4907c50cb9386c09cb649cc4f78e50b2b5826b0 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Mon, 15 Oct 2018 22:26:37 +0200 Subject: [PATCH 02/16] Fix uwsgi folder for reboots --- scripts/_common.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/_common.sh b/scripts/_common.sh index 22cc3a4..c8dfa70 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -8,9 +8,9 @@ ynh_check_global_uwsgi_config () { cp ../conf/uwsgi-app@.service /etc/systemd/system/uwsgi-app@.service # make sure the folder for sockets exists and set authorizations - mkdir -p /var/run/uwsgi/ - chown root:www-data /var/run/uwsgi/ - chmod -R 775 /var/run/uwsgi/ + # make sure it exists on every startup + echo "d /var/run/uwsgi 0775 root www-data" > /usr/lib/tmpfiles.d/uwsgi.conf + systemd-tmpfiles --create # make sure the folder for logs exists and set authorizations mkdir -p /var/log/uwsgi/app/ From 516d9279744ef7f14f885d9b51ce19e6db07b966 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Sun, 3 Jun 2018 15:07:35 +0200 Subject: [PATCH 03/16] Impove mail helper and check_process --- check_process | 7 +++---- scripts/_common.sh | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/check_process b/check_process index f996816..dce862c 100644 --- a/check_process +++ b/check_process @@ -19,8 +19,7 @@ setup_private=1 setup_public=1 upgrade=1 - # latest published in community.json - upgrade=1 from_commit=dc037965b0fbc1bd59d352c4d2b71a97b1e4768f + upgrade=1 from_commit=f2c1f14df484d727f1918821b6ade3887f77ec40 backup_restore=1 multi_instance=1 incorrect_path=1 @@ -43,6 +42,6 @@ Email=jean-baptiste@holcroft.fr Notification=all ;;; Upgrade options - ; commit=dc037965b0fbc1bd59d352c4d2b71a97b1e4768f - name=Upgrade from 2.17.1 + ; commit=f2c1f14df484d727f1918821b6ade3887f77ec40 + name=Upgrade from 2.20 manifest_arg=domain=DOMAIN&path=PATH&admin=USER&is_public=1&github_account=fake&github_token=fake diff --git a/scripts/_common.sh b/scripts/_common.sh index c8dfa70..5a0f3b4 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -285,7 +285,7 @@ ynh_psql_drop_user() { # If you give the name of a YunoHost user, ynh_send_readme_to_admin will find its email adress for you # example: "root admin@domain user1 user2" ynh_send_readme_to_admin() { - local app_message="${1:-...No specific informations...}" + local app_message="${1:-...No specific information...}" local recipients="${2:-root}" # Retrieve the email of users @@ -315,12 +315,24 @@ ynh_send_readme_to_admin() { local mail_subject="☁️🆈🅽🅷☁️: \`$app\` was just installed!" local mail_message="This is an automated message from your beloved YunoHost server. -Specific informations for the application $app. + +Specific information for the application $app. + $app_message + --- Automatic diagnosis data from YunoHost + $(yunohost tools diagnosis | grep -B 100 "services:" | sed '/services:/d')" + # Define binary to use for mail command + if [ -e /usr/bin/bsd-mailx ] + then + local mail_bin=/usr/bin/bsd-mailx + else + local mail_bin=/usr/bin/mail.mailutils + fi + # Send the email to the recipients - echo "$mail_message" | mail -a "Content-Type: text/plain; charset=UTF-8" -s "$mail_subject" "$recipients" + echo "$mail_message" | $mail_bin -a "Content-Type: text/plain; charset=UTF-8" -s "$mail_subject" "$recipients" } From ada13bbce2fb510c9680a918f5478fba40c75087 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Sun, 3 Jun 2018 15:09:02 +0200 Subject: [PATCH 04/16] add 3.0 template for diff purposes --- conf/settings_history/settings.3.0.py | 754 ++++++++++++++++++++++++++ 1 file changed, 754 insertions(+) create mode 100644 conf/settings_history/settings.3.0.py diff --git a/conf/settings_history/settings.3.0.py b/conf/settings_history/settings.3.0.py new file mode 100644 index 0000000..fd84cfc --- /dev/null +++ b/conf/settings_history/settings.3.0.py @@ -0,0 +1,754 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2012 - 2018 Michal Čihař +# +# This file is part of Weblate +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +from __future__ import unicode_literals +import platform +import os +from logging.handlers import SysLogHandler + +# +# Django settings for Weblate project. +# + +DEBUG = False + +ADMINS = ( + ('__ADMIN__', '__ADMINMAIL__'), +) + +MANAGERS = ADMINS + +DATABASES = { + 'default': { + # Database engine + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + # Database name + 'NAME': '__NAME__', + # Database user + 'USER': '__NAME__', + # Database password + 'PASSWORD': '__DB_PWD__', + # Set to empty string for localhost + 'HOST': 'localhost', + # Set to empty string for default + 'PORT': '5432', + } +} + +BASE_DIR = '__FINALPATH__' + +# Data directory +DATA_DIR = os.path.join(BASE_DIR, 'data') + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# In a Windows environment this must be set to your system time zone. +TIME_ZONE = 'UTC' + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = 'en-us' + +LANGUAGES = ( + ('ar', 'العربية'), + ('az', 'Azərbaycan'), + ('be', 'Беларуская'), + ('be@latin', 'Biełaruskaja'), + ('bg', 'Български'), + ('br', 'Brezhoneg'), + ('ca', 'Català'), + ('cs', 'Čeština'), + ('da', 'Dansk'), + ('de', 'Deutsch'), + ('en', 'English'), + ('en-gb', 'English (United Kingdom)'), + ('el', 'Ελληνικά'), + ('es', 'Español'), + ('fi', 'Suomi'), + ('fr', 'Français'), + ('fy', 'Frysk'), + ('gl', 'Galego'), + ('he', 'עברית'), + ('hu', 'Magyar'), + ('id', 'Indonesia'), + ('it', 'Italiano'), + ('ja', '日本語'), + ('ko', '한국어'), + ('ksh', 'Kölsch'), + ('nb', 'Norsk bokmål'), + ('nl', 'Nederlands'), + ('pl', 'Polski'), + ('pt', 'Português'), + ('pt-br', 'Português brasileiro'), + ('ru', 'Русский'), + ('sk', 'Slovenčina'), + ('sl', 'Slovenščina'), + ('sr', 'Српски'), + ('sv', 'Svenska'), + ('tr', 'Türkçe'), + ('uk', 'Українська'), + ('zh-hans', '简体字'), + ('zh-hant', '正體字'), +) + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# If you set this to False, Django will not format dates, numbers and +# calendars according to the current locale. +USE_L10N = True + +# If you set this to False, Django will not use timezone-aware datetimes. +USE_TZ = True + +# URL prefix to use, please see documentation for more details +URL_PREFIX = '__PATHURL__' + +# Absolute filesystem path to the directory that will hold user-uploaded files. +# Example: "/home/media/media.lawrence.com/media/" +MEDIA_ROOT = os.path.join(DATA_DIR, 'media') + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash. +# Examples: "http://media.lawrence.com/media/", "http://example.com/media/" +MEDIA_URL = '{0}/media/'.format(URL_PREFIX) + +# Absolute path to the directory static files should be collected to. +# Don't put anything in this directory yourself; store your static files +# in apps' "static/" subdirectories and in STATICFILES_DIRS. +# Example: "/home/media/media.lawrence.com/static/" +STATIC_ROOT = os.path.join(DATA_DIR, 'static') + +# URL prefix for static files. +# Example: "http://media.lawrence.com/static/" +STATIC_URL = '{0}/static/'.format(URL_PREFIX) + +# Additional locations of static files +STATICFILES_DIRS = ( + # Put strings here, like "/home/html/static" or "C:/www/django/static". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +# List of finder classes that know how to find static files in +# various locations. +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + 'compressor.finders.CompressorFinder', +) + +# Make this unique, and don't share it with anybody. +# You can generate it using examples/generate-secret-key +SECRET_KEY = '__KEY__' # noqa + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + os.path.join(BASE_DIR, 'weblate', 'templates'), + ], + 'OPTIONS': { + 'context_processors': [ + 'django.contrib.auth.context_processors.auth', + 'django.template.context_processors.debug', + 'django.template.context_processors.i18n', + 'django.template.context_processors.request', + 'django.template.context_processors.csrf', + 'django.contrib.messages.context_processors.messages', + 'weblate.trans.context_processors.weblate_context', + ], + 'loaders': [ + ('django.template.loaders.cached.Loader', [ + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + ]), + ], + }, + }, +] + + +# GitHub username for sending pull requests. +# Please see the documentation for more details. +GITHUB_USERNAME = "__GITHUBUSER__" + +# Authentication configuration +AUTHENTICATION_BACKENDS = ( + 'social_core.backends.email.EmailAuth', + # 'social_core.backends.google.GoogleOAuth2', + # 'social_core.backends.github.GithubOAuth2', + # 'social_core.backends.bitbucket.BitbucketOAuth', + 'social_core.backends.suse.OpenSUSEOpenId', + 'social_core.backends.ubuntu.UbuntuOpenId', + 'social_core.backends.fedora.FedoraOpenId', + # 'social_core.backends.facebook.FacebookOAuth2', + 'weblate.accounts.auth.WeblateUserBackend', +) + +# Social auth backends setup +SOCIAL_AUTH_GITHUB_KEY = '' +SOCIAL_AUTH_GITHUB_SECRET = '' +SOCIAL_AUTH_GITHUB_SCOPE = ['user:email'] + +SOCIAL_AUTH_BITBUCKET_KEY = '' +SOCIAL_AUTH_BITBUCKET_SECRET = '' +SOCIAL_AUTH_BITBUCKET_VERIFIED_EMAILS_ONLY = True + +SOCIAL_AUTH_FACEBOOK_KEY = '' +SOCIAL_AUTH_FACEBOOK_SECRET = '' +SOCIAL_AUTH_FACEBOOK_SCOPE = ['email', 'public_profile'] + +SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '' +SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '' + +# Social auth settings +SOCIAL_AUTH_PIPELINE = ( + 'social_core.pipeline.social_auth.social_details', + 'social_core.pipeline.social_auth.social_uid', + 'social_core.pipeline.social_auth.auth_allowed', + 'social_core.pipeline.social_auth.social_user', + 'weblate.accounts.pipeline.store_params', + 'weblate.accounts.pipeline.verify_open', + 'social_core.pipeline.user.get_username', + 'weblate.accounts.pipeline.require_email', + 'social_core.pipeline.mail.mail_validation', + 'weblate.accounts.pipeline.revoke_mail_code', + 'weblate.accounts.pipeline.ensure_valid', + 'weblate.accounts.pipeline.remove_account', + 'social_core.pipeline.social_auth.associate_by_email', + 'weblate.accounts.pipeline.reauthenticate', + 'weblate.accounts.pipeline.verify_username', + 'social_core.pipeline.user.create_user', + 'social_core.pipeline.social_auth.associate_user', + 'social_core.pipeline.social_auth.load_extra_data', + 'weblate.accounts.pipeline.cleanup_next', + 'weblate.accounts.pipeline.user_full_name', + 'weblate.accounts.pipeline.store_email', + 'weblate.accounts.pipeline.notify_connect', + 'weblate.accounts.pipeline.password_reset', +) +SOCIAL_AUTH_DISCONNECT_PIPELINE = ( + 'social_core.pipeline.disconnect.allowed_to_disconnect', + 'social_core.pipeline.disconnect.get_entries', + 'social_core.pipeline.disconnect.revoke_tokens', + 'weblate.accounts.pipeline.cycle_session', + 'weblate.accounts.pipeline.adjust_primary_mail', + 'weblate.accounts.pipeline.notify_disconnect', + 'social_core.pipeline.disconnect.disconnect', + 'weblate.accounts.pipeline.cleanup_next', +) + +# Custom authentication strategy +SOCIAL_AUTH_STRATEGY = 'weblate.accounts.strategy.WeblateStrategy' + +# Raise exceptions so that we can handle them later +SOCIAL_AUTH_RAISE_EXCEPTIONS = True + +SOCIAL_AUTH_EMAIL_VALIDATION_FUNCTION = \ + 'weblate.accounts.pipeline.send_validation' +SOCIAL_AUTH_EMAIL_VALIDATION_URL = \ + '{0}/accounts/email-sent/'.format(URL_PREFIX) +SOCIAL_AUTH_LOGIN_ERROR_URL = \ + '{0}/accounts/login/'.format(URL_PREFIX) +SOCIAL_AUTH_EMAIL_FORM_URL = \ + '{0}/accounts/email/'.format(URL_PREFIX) +SOCIAL_AUTH_NEW_ASSOCIATION_REDIRECT_URL = \ + '{0}/accounts/profile/#auth'.format(URL_PREFIX) +SOCIAL_AUTH_PROTECTED_USER_FIELDS = ('email',) +SOCIAL_AUTH_SLUGIFY_USERNAMES = True +SOCIAL_AUTH_SLUGIFY_FUNCTION = 'weblate.accounts.pipeline.slugify_username' + +# Password validation configuration +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + 'OPTIONS': { + 'min_length': 6, + } + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, + { + 'NAME': 'weblate.accounts.password_validation.CharsPasswordValidator', + }, + { + 'NAME': 'weblate.accounts.password_validation.PastPasswordsValidator', + }, + # Optional password strength validation by django-zxcvbn-password + # { + # 'NAME': 'zxcvbn_password.ZXCVBNValidator', + # 'OPTIONS': { + # 'min_score': 3, + # 'user_attributes': ('username', 'email', 'first_name') + # } + # }, +] + +# Middleware +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'weblate.accounts.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'social_django.middleware.SocialAuthExceptionMiddleware', + 'weblate.accounts.middleware.RequireLoginMiddleware', + 'weblate.middleware.SecurityMiddleware', + 'weblate.wladmin.middleware.ConfigurationErrorsMiddleware', +] + +ROOT_URLCONF = 'weblate.urls' + +# Django and Weblate apps +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django.contrib.admin.apps.SimpleAdminConfig', + 'django.contrib.admindocs', + 'django.contrib.sitemaps', + 'social_django', + 'crispy_forms', + 'compressor', + 'rest_framework', + 'rest_framework.authtoken', + 'weblate.addons', + 'weblate.trans', + 'weblate.lang', + 'weblate.langdata', + 'weblate.memory', + 'weblate.permissions', + 'weblate.screenshots', + 'weblate.accounts', + 'weblate.utils', + 'weblate.wladmin', + 'weblate', + + # Optional: Git exporter + # 'weblate.gitexport', +) + +# Path to locales +LOCALE_PATHS = (os.path.join(BASE_DIR, 'weblate', 'locale'), ) + +# Custom exception reporter to include some details +DEFAULT_EXCEPTION_REPORTER_FILTER = \ + 'weblate.trans.debug.WeblateExceptionReporterFilter' + +# Default logging of Weblate messages +# - to syslog in production (if available) +# - otherwise to console +# - you can also choose 'logfile' to log into separate file +# after configuring it below + +# Detect if we can connect to syslog +HAVE_SYSLOG = False +if platform.system() != 'Windows': + try: + handler = SysLogHandler( + address='/dev/log', facility=SysLogHandler.LOG_LOCAL2 + ) + handler.close() + HAVE_SYSLOG = True + except IOError: + HAVE_SYSLOG = False + +if DEBUG or not HAVE_SYSLOG: + DEFAULT_LOG = 'console' +else: + DEFAULT_LOG = 'syslog' + +# A sample logging configuration. The only tangible logging +# performed by this configuration is to send an email to +# the site admins on every HTTP 500 error when DEBUG=False. +# See http://docs.djangoproject.com/en/stable/topics/logging for +# more details on how to customize your logging configuration. +LOGGING = { + 'version': 1, + 'disable_existing_loggers': True, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse' + } + }, + 'formatters': { + 'syslog': { + 'format': 'weblate[%(process)d]: %(levelname)s %(message)s' + }, + 'simple': { + 'format': '%(levelname)s %(message)s' + }, + 'logfile': { + 'format': '%(asctime)s %(levelname)s %(message)s' + }, + 'django.server': { + '()': 'django.utils.log.ServerFormatter', + 'format': '[%(server_time)s] %(message)s', + } + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler', + 'include_html': True, + }, + 'console': { + 'level': 'DEBUG', + 'class': 'logging.StreamHandler', + 'formatter': 'simple' + }, + 'django.server': { + 'level': 'INFO', + 'class': 'logging.StreamHandler', + 'formatter': 'django.server', + }, + 'syslog': { + 'level': 'DEBUG', + 'class': 'logging.handlers.SysLogHandler', + 'formatter': 'syslog', + 'address': '/dev/log', + 'facility': SysLogHandler.LOG_LOCAL2, + }, + # Logging to a file + # 'logfile': { + # 'level':'DEBUG', + # 'class':'logging.handlers.RotatingFileHandler', + # 'filename': "/var/log/weblate/weblate.log", + # 'maxBytes': 100000, + # 'backupCount': 3, + # 'formatter': 'logfile', + # }, + }, + 'loggers': { + 'django.request': { + 'handlers': ['mail_admins', DEFAULT_LOG], + 'level': 'ERROR', + 'propagate': True, + }, + 'django.server': { + 'handlers': ['django.server'], + 'level': 'INFO', + 'propagate': False, + }, + # Logging database queries + # 'django.db.backends': { + # 'handlers': [DEFAULT_LOG], + # 'level': 'DEBUG', + # }, + 'weblate': { + 'handlers': [DEFAULT_LOG], + 'level': 'DEBUG', + }, + # Logging VCS operations + # 'weblate-vcs': { + # 'handlers': [DEFAULT_LOG], + # 'level': 'DEBUG', + # }, + # Python Social Auth logging + # 'social': { + # 'handlers': [DEFAULT_LOG], + # 'level': 'DEBUG', + # }, + } +} + +# Logging of management commands to console +if (os.environ.get('DJANGO_IS_MANAGEMENT_COMMAND', False) and + 'console' not in LOGGING['loggers']['weblate']['handlers']): + LOGGING['loggers']['weblate']['handlers'].append('console') + +# Remove syslog setup if it's not present +if not HAVE_SYSLOG: + del LOGGING['handlers']['syslog'] + +# List of machine translations +# MACHINE_TRANSLATION_SERVICES = ( +# 'weblate.trans.machine.apertium.ApertiumAPYTranslation', +# 'weblate.trans.machine.deepl.DeepLTranslation', +# 'weblate.trans.machine.glosbe.GlosbeTranslation', +# 'weblate.trans.machine.google.GoogleTranslation', +# 'weblate.trans.machine.microsoft.MicrosoftCognitiveTranslation', +# 'weblate.trans.machine.mymemory.MyMemoryTranslation', +# 'weblate.trans.machine.tmserver.AmagamaTranslation', +# 'weblate.trans.machine.tmserver.TMServerTranslation', +# 'weblate.trans.machine.yandex.YandexTranslation', +# 'weblate.trans.machine.weblatetm.WeblateTranslation', +# 'weblate.trans.machine.saptranslationhub.SAPTranslationHub', +# 'weblate.memory.machine.WeblateMemory', +# ) + +# Machine translation API keys + +# URL of the Apertium APy server +MT_APERTIUM_APY = None + +# DeepL API key +MT_DEEPL_KEY = None + +# Microsoft Cognitive Services Translator API, register at +# https://portal.azure.com/ +MT_MICROSOFT_COGNITIVE_KEY = None + +# MyMemory identification email, see +# https://mymemory.translated.net/doc/spec.php +MT_MYMEMORY_EMAIL = None + +# Optional MyMemory credentials to access private translation memory +MT_MYMEMORY_USER = None +MT_MYMEMORY_KEY = None + +# Google API key for Google Translate API +MT_GOOGLE_KEY = None + +# API key for Yandex Translate API +MT_YANDEX_KEY = None + +# tmserver URL +MT_TMSERVER = None + +# SAP Translation Hub +MT_SAP_BASE_URL = None +MT_SAP_SANDBOX_APIKEY = None +MT_SAP_USERNAME = None +MT_SAP_PASSWORD = None +MT_SAP_USE_MT = True + +# Title of site to use +SITE_TITLE = 'Weblate' + +# Whether site uses https +ENABLE_HTTPS = True + +# Use HTTPS when creating redirect URLs for social authentication, see +# documentation for more details: +# http://python-social-auth-docs.readthedocs.io/en/latest/configuration/settings.html#processing-redirects-and-urlopen +SOCIAL_AUTH_REDIRECT_IS_HTTPS = ENABLE_HTTPS + +# Make CSRF cookie HttpOnly, see documentation for more details: +# https://docs.djangoproject.com/en/1.11/ref/settings/#csrf-cookie-httponly +CSRF_COOKIE_HTTPONLY = True +CSRF_COOKIE_SECURE = ENABLE_HTTPS +# Store CSRF token in session (since Django 1.11) +CSRF_USE_SESSIONS = True +SESSION_COOKIE_SECURE = ENABLE_HTTPS +# Session cookie age (in seconds) +SESSION_COOKIE_AGE = 1209600 + +# URL of login +LOGIN_URL = '{0}/accounts/login/'.format(URL_PREFIX) + +# URL of logout +LOGOUT_URL = '{0}/accounts/logout/'.format(URL_PREFIX) + +# Default location for login +LOGIN_REDIRECT_URL = '{0}/'.format(URL_PREFIX) + +# Anonymous user name +ANONYMOUS_USER_NAME = 'anonymous' + +# Reverse proxy settings +IP_BEHIND_REVERSE_PROXY = False +IP_PROXY_HEADER = 'HTTP_X_FORWARDED_FOR' +IP_PROXY_OFFSET = 0 + +# Sending HTML in mails +EMAIL_SEND_HTML = True + +# Subject of emails includes site title +EMAIL_SUBJECT_PREFIX = '[{0}] '.format(SITE_TITLE) + +EMAIL_BACKEND = 'django_sendmail_backend.backends.EmailBackend' + +# Enable remote hooks +ENABLE_HOOKS = True + +# Whether to run hooks in background +BACKGROUND_HOOKS = True + +# Number of nearby messages to show in each direction +NEARBY_MESSAGES = 5 + +# Offload indexing +OFFLOAD_INDEXING = True + +# Use simple language codes for default language/country combinations +SIMPLIFY_LANGUAGES = True + +# Render forms using bootstrap +CRISPY_TEMPLATE_PACK = 'bootstrap3' + +# List of quality checks +# CHECK_LIST = ( +# 'weblate.trans.checks.same.SameCheck', +# 'weblate.trans.checks.chars.BeginNewlineCheck', +# 'weblate.trans.checks.chars.EndNewlineCheck', +# 'weblate.trans.checks.chars.BeginSpaceCheck', +# 'weblate.trans.checks.chars.EndSpaceCheck', +# 'weblate.trans.checks.chars.EndStopCheck', +# 'weblate.trans.checks.chars.EndColonCheck', +# 'weblate.trans.checks.chars.EndQuestionCheck', +# 'weblate.trans.checks.chars.EndExclamationCheck', +# 'weblate.trans.checks.chars.EndEllipsisCheck', +# 'weblate.trans.checks.chars.EndSemicolonCheck', +# 'weblate.trans.checks.chars.MaxLengthCheck', +# 'weblate.trans.checks.format.PythonFormatCheck', +# 'weblate.trans.checks.format.PythonBraceFormatCheck', +# 'weblate.trans.checks.format.PHPFormatCheck', +# 'weblate.trans.checks.format.CFormatCheck', +# 'weblate.trans.checks.format.PerlFormatCheck', +# 'weblate.trans.checks.format.JavascriptFormatCheck', +# 'weblate.trans.checks.consistency.PluralsCheck', +# 'weblate.trans.checks.consistency.SamePluralsCheck', +# 'weblate.trans.checks.consistency.ConsistencyCheck', +# 'weblate.trans.checks.consistency.TranslatedCheck', +# 'weblate.trans.checks.chars.NewlineCountingCheck', +# 'weblate.trans.checks.markup.BBCodeCheck', +# 'weblate.trans.checks.chars.ZeroWidthSpaceCheck', +# 'weblate.trans.checks.markup.XMLValidityCheck', +# 'weblate.trans.checks.markup.XMLTagsCheck', +# 'weblate.trans.checks.source.OptionalPluralCheck', +# 'weblate.trans.checks.source.EllipsisCheck', +# 'weblate.trans.checks.source.MultipleFailingCheck', +# ) + +# List of automatic fixups +# AUTOFIX_LIST = ( +# 'weblate.trans.autofixes.whitespace.SameBookendingWhitespace', +# 'weblate.trans.autofixes.chars.ReplaceTrailingDotsWithEllipsis', +# 'weblate.trans.autofixes.chars.RemoveZeroSpace', +# 'weblate.trans.autofixes.chars.RemoveControlChars', +# ) + +# List of enabled addons +# WEBLATE_ADDONS = ( +# 'weblate.addons.gettext.GenerateMoAddon', +# 'weblate.addons.gettext.UpdateLinguasAddon', +# 'weblate.addons.gettext.UpdateConfigureAddon', +# 'weblate.addons.gettext.MsgmergeAddon', +# 'weblate.addons.gettext.GettextCustomizeAddon', +# 'weblate.addons.cleanup.CleanupAddon', +# 'weblate.addons.flags.SourceEditAddon', +# 'weblate.addons.flags.TargetEditAddon', +# 'weblate.addons.json.JSONCustomizeAddon', +# 'weblate.addons.generate.GenerateFileAddon', +# 'weblate.addons.properties.PropertiesSortAddon', +# ) + + +# List of scripts to use in custom processing +# POST_UPDATE_SCRIPTS = ( +# ) +# PRE_COMMIT_SCRIPTS = ( +# ) + +# E-mail address that error messages come from. +SERVER_EMAIL = 'noreply@__DOMAIN__' + +# Default email address to use for various automated correspondence from +# the site managers. Used for registration emails. +DEFAULT_FROM_EMAIL = '__ADMINMAIL__' + +# List of URLs your site is supposed to serve +ALLOWED_HOSTS = ['__DOMAIN__'] + +# Example configuration to use memcached for caching +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', + 'LOCATION': '127.0.0.1:__MEMCPORT__', + }, + 'avatar': { + 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': os.path.join(BASE_DIR, 'avatar-cache'), + 'TIMEOUT': 3600, + 'OPTIONS': { + 'MAX_ENTRIES': 1000, + }, + } +} + +# REST framework settings for API +REST_FRAMEWORK = { + # Use Django's standard `django.contrib.auth` permissions, + # or allow read-only access for unauthenticated users. + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAuthenticatedOrReadOnly' + ], + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework.authentication.TokenAuthentication', + 'weblate.api.authentication.BearerAuthentication', + 'rest_framework.authentication.SessionAuthentication', + ), + 'DEFAULT_THROTTLE_CLASSES': ( + 'rest_framework.throttling.AnonRateThrottle', + 'rest_framework.throttling.UserRateThrottle' + ), + 'DEFAULT_THROTTLE_RATES': { + 'anon': '100/day', + 'user': '1000/day' + }, + 'DEFAULT_PAGINATION_CLASS': ( + 'rest_framework.pagination.PageNumberPagination' + ), + 'PAGE_SIZE': 20, + 'VIEW_DESCRIPTION_FUNCTION': 'weblate.api.views.get_view_description', + 'UNAUTHENTICATED_USER': 'weblate.accounts.models.get_anonymous', +} + +# Example for restricting access to logged in users +# LOGIN_REQUIRED_URLS = ( +# r'/(.*)$', +# ) + +# In such case you will want to include some of the exceptions +# LOGIN_REQUIRED_URLS_EXCEPTIONS = ( +# r'/accounts/(.*)$', # Required for login +# r'/static/(.*)$', # Required for development mode +# r'/widgets/(.*)$', # Allowing public access to widgets +# r'/data/(.*)$', # Allowing public access to data exports +# r'/hooks/(.*)$', # Allowing public access to notification hooks +# r'/api/(.*)$', # Allowing access to API +# r'/js/i18n/$', # Javascript localization +# r'/contact/$', # Optional for contact form +# r'/legal/(.*)$', # Optional for legal app +# ) + +# Force sane test runner +TEST_RUNNER = 'django.test.runner.DiscoverRunner' + From 3fd38cdae6ccd52305b5783d00bc3f7d9de06ac8 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Wed, 6 Jun 2018 00:23:36 +0200 Subject: [PATCH 05/16] Upgrade to 3.0 --- README.md | 10 +++ conf/settings_history/settings.3.0.py | 109 +++++++++++++------------- manifest.json | 2 +- scripts/_common.sh | 2 +- scripts/upgrade | 13 +++ 5 files changed, 81 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index f36b71d..73b3ff3 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,16 @@ The YunoHost team uses [Weblate](https://weblate.org) for translations: https:// An admin user is created at installation, the login is what you provided at installation, the password is **weblate**. +## Weblate 3.0 upgrade + +This upgrade is a major one, remember to read this page before upgrading: https://docs.weblate.org/en/latest/admin/upgrade.html#upgrade-3 + +After upgrading: + + * All existing users and groups have been migrated to new model. + * Any per user permissions are removed, please assign users to appropriate groups and roles to grant them permissions. + * Any custom groups will not have any permissions after upgrade, please grant the permissions again. + ## Github You'll need to give weblate a github user and a token. Please read [github's documentation about token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/). diff --git a/conf/settings_history/settings.3.0.py b/conf/settings_history/settings.3.0.py index fd84cfc..a142e66 100644 --- a/conf/settings_history/settings.3.0.py +++ b/conf/settings_history/settings.3.0.py @@ -207,6 +207,9 @@ AUTHENTICATION_BACKENDS = ( 'weblate.accounts.auth.WeblateUserBackend', ) +# Custom user model +AUTH_USER_MODEL = 'weblate_auth.User' + # Social auth backends setup SOCIAL_AUTH_GITHUB_KEY = '' SOCIAL_AUTH_GITHUB_SECRET = '' @@ -308,7 +311,7 @@ AUTH_PASSWORD_VALIDATORS = [ # 'NAME': 'zxcvbn_password.ZXCVBNValidator', # 'OPTIONS': { # 'min_score': 3, - # 'user_attributes': ('username', 'email', 'first_name') + # 'user_attributes': ('username', 'email', 'full_name') # } # }, ] @@ -348,6 +351,10 @@ INSTALLED_APPS = ( 'rest_framework', 'rest_framework.authtoken', 'weblate.addons', + 'weblate.auth', + 'weblate.checks', + 'weblate.formats', + 'weblate.machinery', 'weblate.trans', 'weblate.lang', 'weblate.langdata', @@ -356,6 +363,7 @@ INSTALLED_APPS = ( 'weblate.screenshots', 'weblate.accounts', 'weblate.utils', + 'weblate.vcs', 'weblate.wladmin', 'weblate', @@ -498,18 +506,18 @@ if not HAVE_SYSLOG: del LOGGING['handlers']['syslog'] # List of machine translations -# MACHINE_TRANSLATION_SERVICES = ( -# 'weblate.trans.machine.apertium.ApertiumAPYTranslation', -# 'weblate.trans.machine.deepl.DeepLTranslation', -# 'weblate.trans.machine.glosbe.GlosbeTranslation', -# 'weblate.trans.machine.google.GoogleTranslation', -# 'weblate.trans.machine.microsoft.MicrosoftCognitiveTranslation', -# 'weblate.trans.machine.mymemory.MyMemoryTranslation', -# 'weblate.trans.machine.tmserver.AmagamaTranslation', -# 'weblate.trans.machine.tmserver.TMServerTranslation', -# 'weblate.trans.machine.yandex.YandexTranslation', -# 'weblate.trans.machine.weblatetm.WeblateTranslation', -# 'weblate.trans.machine.saptranslationhub.SAPTranslationHub', +# MT_SERVICES = ( +# 'weblate.machinery.apertium.ApertiumAPYTranslation', +# 'weblate.machinery.deepl.DeepLTranslation', +# 'weblate.machinery.glosbe.GlosbeTranslation', +# 'weblate.machinery.google.GoogleTranslation', +# 'weblate.machinery.microsoft.MicrosoftCognitiveTranslation', +# 'weblate.machinery.mymemory.MyMemoryTranslation', +# 'weblate.machinery.tmserver.AmagamaTranslation', +# 'weblate.machinery.tmserver.TMServerTranslation', +# 'weblate.machinery.yandex.YandexTranslation', +# 'weblate.machinery.weblatetm.WeblateTranslation', +# 'weblate.machinery.saptranslationhub.SAPTranslationHub', # 'weblate.memory.machine.WeblateMemory', # ) @@ -615,36 +623,36 @@ CRISPY_TEMPLATE_PACK = 'bootstrap3' # List of quality checks # CHECK_LIST = ( -# 'weblate.trans.checks.same.SameCheck', -# 'weblate.trans.checks.chars.BeginNewlineCheck', -# 'weblate.trans.checks.chars.EndNewlineCheck', -# 'weblate.trans.checks.chars.BeginSpaceCheck', -# 'weblate.trans.checks.chars.EndSpaceCheck', -# 'weblate.trans.checks.chars.EndStopCheck', -# 'weblate.trans.checks.chars.EndColonCheck', -# 'weblate.trans.checks.chars.EndQuestionCheck', -# 'weblate.trans.checks.chars.EndExclamationCheck', -# 'weblate.trans.checks.chars.EndEllipsisCheck', -# 'weblate.trans.checks.chars.EndSemicolonCheck', -# 'weblate.trans.checks.chars.MaxLengthCheck', -# 'weblate.trans.checks.format.PythonFormatCheck', -# 'weblate.trans.checks.format.PythonBraceFormatCheck', -# 'weblate.trans.checks.format.PHPFormatCheck', -# 'weblate.trans.checks.format.CFormatCheck', -# 'weblate.trans.checks.format.PerlFormatCheck', -# 'weblate.trans.checks.format.JavascriptFormatCheck', -# 'weblate.trans.checks.consistency.PluralsCheck', -# 'weblate.trans.checks.consistency.SamePluralsCheck', -# 'weblate.trans.checks.consistency.ConsistencyCheck', -# 'weblate.trans.checks.consistency.TranslatedCheck', -# 'weblate.trans.checks.chars.NewlineCountingCheck', -# 'weblate.trans.checks.markup.BBCodeCheck', -# 'weblate.trans.checks.chars.ZeroWidthSpaceCheck', -# 'weblate.trans.checks.markup.XMLValidityCheck', -# 'weblate.trans.checks.markup.XMLTagsCheck', -# 'weblate.trans.checks.source.OptionalPluralCheck', -# 'weblate.trans.checks.source.EllipsisCheck', -# 'weblate.trans.checks.source.MultipleFailingCheck', +# 'weblate.checks.same.SameCheck', +# 'weblate.checks.chars.BeginNewlineCheck', +# 'weblate.checks.chars.EndNewlineCheck', +# 'weblate.checks.chars.BeginSpaceCheck', +# 'weblate.checks.chars.EndSpaceCheck', +# 'weblate.checks.chars.EndStopCheck', +# 'weblate.checks.chars.EndColonCheck', +# 'weblate.checks.chars.EndQuestionCheck', +# 'weblate.checks.chars.EndExclamationCheck', +# 'weblate.checks.chars.EndEllipsisCheck', +# 'weblate.checks.chars.EndSemicolonCheck', +# 'weblate.checks.chars.MaxLengthCheck', +# 'weblate.checks.format.PythonFormatCheck', +# 'weblate.checks.format.PythonBraceFormatCheck', +# 'weblate.checks.format.PHPFormatCheck', +# 'weblate.checks.format.CFormatCheck', +# 'weblate.checks.format.PerlFormatCheck', +# 'weblate.checks.format.JavascriptFormatCheck', +# 'weblate.checks.consistency.PluralsCheck', +# 'weblate.checks.consistency.SamePluralsCheck', +# 'weblate.checks.consistency.ConsistencyCheck', +# 'weblate.checks.consistency.TranslatedCheck', +# 'weblate.checks.chars.NewlineCountingCheck', +# 'weblate.checks.markup.BBCodeCheck', +# 'weblate.checks.chars.ZeroWidthSpaceCheck', +# 'weblate.checks.markup.XMLValidityCheck', +# 'weblate.checks.markup.XMLTagsCheck', +# 'weblate.checks.source.OptionalPluralCheck', +# 'weblate.checks.source.EllipsisCheck', +# 'weblate.checks.source.MultipleFailingCheck', # ) # List of automatic fixups @@ -662,21 +670,17 @@ CRISPY_TEMPLATE_PACK = 'bootstrap3' # 'weblate.addons.gettext.UpdateConfigureAddon', # 'weblate.addons.gettext.MsgmergeAddon', # 'weblate.addons.gettext.GettextCustomizeAddon', +# 'weblate.addons.gettext.GettextAuthorComments', # 'weblate.addons.cleanup.CleanupAddon', +# 'weblate.addons.consistency.LangaugeConsistencyAddon', +# 'weblate.addons.discovery.DiscoveryAddon', # 'weblate.addons.flags.SourceEditAddon', # 'weblate.addons.flags.TargetEditAddon', -# 'weblate.addons.json.JSONCustomizeAddon', # 'weblate.addons.generate.GenerateFileAddon', +# 'weblate.addons.json.JSONCustomizeAddon', # 'weblate.addons.properties.PropertiesSortAddon', # ) - -# List of scripts to use in custom processing -# POST_UPDATE_SCRIPTS = ( -# ) -# PRE_COMMIT_SCRIPTS = ( -# ) - # E-mail address that error messages come from. SERVER_EMAIL = 'noreply@__DOMAIN__' @@ -728,7 +732,7 @@ REST_FRAMEWORK = { ), 'PAGE_SIZE': 20, 'VIEW_DESCRIPTION_FUNCTION': 'weblate.api.views.get_view_description', - 'UNAUTHENTICATED_USER': 'weblate.accounts.models.get_anonymous', + 'UNAUTHENTICATED_USER': 'weblate.auth.models.get_anonymous', } # Example for restricting access to logged in users @@ -751,4 +755,3 @@ REST_FRAMEWORK = { # Force sane test runner TEST_RUNNER = 'django.test.runner.DiscoverRunner' - diff --git a/manifest.json b/manifest.json index 47fcfbb..41d3fc4 100644 --- a/manifest.json +++ b/manifest.json @@ -8,7 +8,7 @@ "description": { "en": "A translation platform using Git and Python" }, - "version": "2.20-1", + "version": "3.0~ynh1", "url": "https://weblate.org", "license": "AGPL-3.0", "maintainer": { diff --git a/scripts/_common.sh b/scripts/_common.sh index 5a0f3b4..a2d3238 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -1,6 +1,6 @@ #!/bin/bash -current_version="2.20" +current_version="3.0" ynh_check_global_uwsgi_config () { uwsgi --version || ynh_die "You need to add uwsgi (and appropriate plugin) as a dependency" diff --git a/scripts/upgrade b/scripts/upgrade index 3e265cc..5c87db3 100755 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -203,6 +203,8 @@ then # send diff to the server administrator mail_message=" Weblate was updated from version $previous_version to $current_version + This is a MAJOR upgrade, please read this: + https://docs.weblate.org/en/latest/admin/upgrade.html#upgrade-3 A new settings.py has been created in: $settings @@ -236,6 +238,17 @@ fi set -o nounset export DJANGO_SETTINGS_MODULE="weblate.settings" cd "${final_path}" + + # https://docs.weblate.org/en/latest/admin/upgrade.html#upgrade-3 + # https://github.com/WeblateOrg/docker/blob/386aa8d98bb57dfec3707680827d4e4f4d79e3fd/start#L81-L88 + weblate showmigrations --plan > /tmp/migrations.txt + if grep -Fq '[X] auth.0001_initial' /tmp/migrations.txt && grep -Fq '[ ] weblate_auth.0001_initial' /tmp/migrations.txt ; then + ynh_replace_string "AUTH_USER_MODEL" "#AUTH_USER_MODEL" "$settings" + weblate migrate weblate_auth 0001 + ynh_replace_string "#AUTH_USER_MODEL" "AUTH_USER_MODEL" "$settings" + fi + ynh_secure_remove /tmp/migrations.txt + weblate migrate --noinput weblate collectstatic --noinput weblate setuplang From d942065f6afbf1e737796abce0f4066adbfef51c Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Wed, 13 Jun 2018 22:27:46 +0200 Subject: [PATCH 06/16] Upgrade to 3.0.1 --- conf/settings_history/settings.3.0.1.py | 757 ++++++++++++++++++++++++ manifest.json | 2 +- scripts/_common.sh | 2 +- 3 files changed, 759 insertions(+), 2 deletions(-) create mode 100644 conf/settings_history/settings.3.0.1.py diff --git a/conf/settings_history/settings.3.0.1.py b/conf/settings_history/settings.3.0.1.py new file mode 100644 index 0000000..a142e66 --- /dev/null +++ b/conf/settings_history/settings.3.0.1.py @@ -0,0 +1,757 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2012 - 2018 Michal Čihař +# +# This file is part of Weblate +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +from __future__ import unicode_literals +import platform +import os +from logging.handlers import SysLogHandler + +# +# Django settings for Weblate project. +# + +DEBUG = False + +ADMINS = ( + ('__ADMIN__', '__ADMINMAIL__'), +) + +MANAGERS = ADMINS + +DATABASES = { + 'default': { + # Database engine + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + # Database name + 'NAME': '__NAME__', + # Database user + 'USER': '__NAME__', + # Database password + 'PASSWORD': '__DB_PWD__', + # Set to empty string for localhost + 'HOST': 'localhost', + # Set to empty string for default + 'PORT': '5432', + } +} + +BASE_DIR = '__FINALPATH__' + +# Data directory +DATA_DIR = os.path.join(BASE_DIR, 'data') + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# In a Windows environment this must be set to your system time zone. +TIME_ZONE = 'UTC' + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = 'en-us' + +LANGUAGES = ( + ('ar', 'العربية'), + ('az', 'Azərbaycan'), + ('be', 'Беларуская'), + ('be@latin', 'Biełaruskaja'), + ('bg', 'Български'), + ('br', 'Brezhoneg'), + ('ca', 'Català'), + ('cs', 'Čeština'), + ('da', 'Dansk'), + ('de', 'Deutsch'), + ('en', 'English'), + ('en-gb', 'English (United Kingdom)'), + ('el', 'Ελληνικά'), + ('es', 'Español'), + ('fi', 'Suomi'), + ('fr', 'Français'), + ('fy', 'Frysk'), + ('gl', 'Galego'), + ('he', 'עברית'), + ('hu', 'Magyar'), + ('id', 'Indonesia'), + ('it', 'Italiano'), + ('ja', '日本語'), + ('ko', '한국어'), + ('ksh', 'Kölsch'), + ('nb', 'Norsk bokmål'), + ('nl', 'Nederlands'), + ('pl', 'Polski'), + ('pt', 'Português'), + ('pt-br', 'Português brasileiro'), + ('ru', 'Русский'), + ('sk', 'Slovenčina'), + ('sl', 'Slovenščina'), + ('sr', 'Српски'), + ('sv', 'Svenska'), + ('tr', 'Türkçe'), + ('uk', 'Українська'), + ('zh-hans', '简体字'), + ('zh-hant', '正體字'), +) + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# If you set this to False, Django will not format dates, numbers and +# calendars according to the current locale. +USE_L10N = True + +# If you set this to False, Django will not use timezone-aware datetimes. +USE_TZ = True + +# URL prefix to use, please see documentation for more details +URL_PREFIX = '__PATHURL__' + +# Absolute filesystem path to the directory that will hold user-uploaded files. +# Example: "/home/media/media.lawrence.com/media/" +MEDIA_ROOT = os.path.join(DATA_DIR, 'media') + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash. +# Examples: "http://media.lawrence.com/media/", "http://example.com/media/" +MEDIA_URL = '{0}/media/'.format(URL_PREFIX) + +# Absolute path to the directory static files should be collected to. +# Don't put anything in this directory yourself; store your static files +# in apps' "static/" subdirectories and in STATICFILES_DIRS. +# Example: "/home/media/media.lawrence.com/static/" +STATIC_ROOT = os.path.join(DATA_DIR, 'static') + +# URL prefix for static files. +# Example: "http://media.lawrence.com/static/" +STATIC_URL = '{0}/static/'.format(URL_PREFIX) + +# Additional locations of static files +STATICFILES_DIRS = ( + # Put strings here, like "/home/html/static" or "C:/www/django/static". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +# List of finder classes that know how to find static files in +# various locations. +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + 'compressor.finders.CompressorFinder', +) + +# Make this unique, and don't share it with anybody. +# You can generate it using examples/generate-secret-key +SECRET_KEY = '__KEY__' # noqa + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + os.path.join(BASE_DIR, 'weblate', 'templates'), + ], + 'OPTIONS': { + 'context_processors': [ + 'django.contrib.auth.context_processors.auth', + 'django.template.context_processors.debug', + 'django.template.context_processors.i18n', + 'django.template.context_processors.request', + 'django.template.context_processors.csrf', + 'django.contrib.messages.context_processors.messages', + 'weblate.trans.context_processors.weblate_context', + ], + 'loaders': [ + ('django.template.loaders.cached.Loader', [ + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + ]), + ], + }, + }, +] + + +# GitHub username for sending pull requests. +# Please see the documentation for more details. +GITHUB_USERNAME = "__GITHUBUSER__" + +# Authentication configuration +AUTHENTICATION_BACKENDS = ( + 'social_core.backends.email.EmailAuth', + # 'social_core.backends.google.GoogleOAuth2', + # 'social_core.backends.github.GithubOAuth2', + # 'social_core.backends.bitbucket.BitbucketOAuth', + 'social_core.backends.suse.OpenSUSEOpenId', + 'social_core.backends.ubuntu.UbuntuOpenId', + 'social_core.backends.fedora.FedoraOpenId', + # 'social_core.backends.facebook.FacebookOAuth2', + 'weblate.accounts.auth.WeblateUserBackend', +) + +# Custom user model +AUTH_USER_MODEL = 'weblate_auth.User' + +# Social auth backends setup +SOCIAL_AUTH_GITHUB_KEY = '' +SOCIAL_AUTH_GITHUB_SECRET = '' +SOCIAL_AUTH_GITHUB_SCOPE = ['user:email'] + +SOCIAL_AUTH_BITBUCKET_KEY = '' +SOCIAL_AUTH_BITBUCKET_SECRET = '' +SOCIAL_AUTH_BITBUCKET_VERIFIED_EMAILS_ONLY = True + +SOCIAL_AUTH_FACEBOOK_KEY = '' +SOCIAL_AUTH_FACEBOOK_SECRET = '' +SOCIAL_AUTH_FACEBOOK_SCOPE = ['email', 'public_profile'] + +SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '' +SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '' + +# Social auth settings +SOCIAL_AUTH_PIPELINE = ( + 'social_core.pipeline.social_auth.social_details', + 'social_core.pipeline.social_auth.social_uid', + 'social_core.pipeline.social_auth.auth_allowed', + 'social_core.pipeline.social_auth.social_user', + 'weblate.accounts.pipeline.store_params', + 'weblate.accounts.pipeline.verify_open', + 'social_core.pipeline.user.get_username', + 'weblate.accounts.pipeline.require_email', + 'social_core.pipeline.mail.mail_validation', + 'weblate.accounts.pipeline.revoke_mail_code', + 'weblate.accounts.pipeline.ensure_valid', + 'weblate.accounts.pipeline.remove_account', + 'social_core.pipeline.social_auth.associate_by_email', + 'weblate.accounts.pipeline.reauthenticate', + 'weblate.accounts.pipeline.verify_username', + 'social_core.pipeline.user.create_user', + 'social_core.pipeline.social_auth.associate_user', + 'social_core.pipeline.social_auth.load_extra_data', + 'weblate.accounts.pipeline.cleanup_next', + 'weblate.accounts.pipeline.user_full_name', + 'weblate.accounts.pipeline.store_email', + 'weblate.accounts.pipeline.notify_connect', + 'weblate.accounts.pipeline.password_reset', +) +SOCIAL_AUTH_DISCONNECT_PIPELINE = ( + 'social_core.pipeline.disconnect.allowed_to_disconnect', + 'social_core.pipeline.disconnect.get_entries', + 'social_core.pipeline.disconnect.revoke_tokens', + 'weblate.accounts.pipeline.cycle_session', + 'weblate.accounts.pipeline.adjust_primary_mail', + 'weblate.accounts.pipeline.notify_disconnect', + 'social_core.pipeline.disconnect.disconnect', + 'weblate.accounts.pipeline.cleanup_next', +) + +# Custom authentication strategy +SOCIAL_AUTH_STRATEGY = 'weblate.accounts.strategy.WeblateStrategy' + +# Raise exceptions so that we can handle them later +SOCIAL_AUTH_RAISE_EXCEPTIONS = True + +SOCIAL_AUTH_EMAIL_VALIDATION_FUNCTION = \ + 'weblate.accounts.pipeline.send_validation' +SOCIAL_AUTH_EMAIL_VALIDATION_URL = \ + '{0}/accounts/email-sent/'.format(URL_PREFIX) +SOCIAL_AUTH_LOGIN_ERROR_URL = \ + '{0}/accounts/login/'.format(URL_PREFIX) +SOCIAL_AUTH_EMAIL_FORM_URL = \ + '{0}/accounts/email/'.format(URL_PREFIX) +SOCIAL_AUTH_NEW_ASSOCIATION_REDIRECT_URL = \ + '{0}/accounts/profile/#auth'.format(URL_PREFIX) +SOCIAL_AUTH_PROTECTED_USER_FIELDS = ('email',) +SOCIAL_AUTH_SLUGIFY_USERNAMES = True +SOCIAL_AUTH_SLUGIFY_FUNCTION = 'weblate.accounts.pipeline.slugify_username' + +# Password validation configuration +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + 'OPTIONS': { + 'min_length': 6, + } + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, + { + 'NAME': 'weblate.accounts.password_validation.CharsPasswordValidator', + }, + { + 'NAME': 'weblate.accounts.password_validation.PastPasswordsValidator', + }, + # Optional password strength validation by django-zxcvbn-password + # { + # 'NAME': 'zxcvbn_password.ZXCVBNValidator', + # 'OPTIONS': { + # 'min_score': 3, + # 'user_attributes': ('username', 'email', 'full_name') + # } + # }, +] + +# Middleware +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'weblate.accounts.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'social_django.middleware.SocialAuthExceptionMiddleware', + 'weblate.accounts.middleware.RequireLoginMiddleware', + 'weblate.middleware.SecurityMiddleware', + 'weblate.wladmin.middleware.ConfigurationErrorsMiddleware', +] + +ROOT_URLCONF = 'weblate.urls' + +# Django and Weblate apps +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django.contrib.admin.apps.SimpleAdminConfig', + 'django.contrib.admindocs', + 'django.contrib.sitemaps', + 'social_django', + 'crispy_forms', + 'compressor', + 'rest_framework', + 'rest_framework.authtoken', + 'weblate.addons', + 'weblate.auth', + 'weblate.checks', + 'weblate.formats', + 'weblate.machinery', + 'weblate.trans', + 'weblate.lang', + 'weblate.langdata', + 'weblate.memory', + 'weblate.permissions', + 'weblate.screenshots', + 'weblate.accounts', + 'weblate.utils', + 'weblate.vcs', + 'weblate.wladmin', + 'weblate', + + # Optional: Git exporter + # 'weblate.gitexport', +) + +# Path to locales +LOCALE_PATHS = (os.path.join(BASE_DIR, 'weblate', 'locale'), ) + +# Custom exception reporter to include some details +DEFAULT_EXCEPTION_REPORTER_FILTER = \ + 'weblate.trans.debug.WeblateExceptionReporterFilter' + +# Default logging of Weblate messages +# - to syslog in production (if available) +# - otherwise to console +# - you can also choose 'logfile' to log into separate file +# after configuring it below + +# Detect if we can connect to syslog +HAVE_SYSLOG = False +if platform.system() != 'Windows': + try: + handler = SysLogHandler( + address='/dev/log', facility=SysLogHandler.LOG_LOCAL2 + ) + handler.close() + HAVE_SYSLOG = True + except IOError: + HAVE_SYSLOG = False + +if DEBUG or not HAVE_SYSLOG: + DEFAULT_LOG = 'console' +else: + DEFAULT_LOG = 'syslog' + +# A sample logging configuration. The only tangible logging +# performed by this configuration is to send an email to +# the site admins on every HTTP 500 error when DEBUG=False. +# See http://docs.djangoproject.com/en/stable/topics/logging for +# more details on how to customize your logging configuration. +LOGGING = { + 'version': 1, + 'disable_existing_loggers': True, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse' + } + }, + 'formatters': { + 'syslog': { + 'format': 'weblate[%(process)d]: %(levelname)s %(message)s' + }, + 'simple': { + 'format': '%(levelname)s %(message)s' + }, + 'logfile': { + 'format': '%(asctime)s %(levelname)s %(message)s' + }, + 'django.server': { + '()': 'django.utils.log.ServerFormatter', + 'format': '[%(server_time)s] %(message)s', + } + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler', + 'include_html': True, + }, + 'console': { + 'level': 'DEBUG', + 'class': 'logging.StreamHandler', + 'formatter': 'simple' + }, + 'django.server': { + 'level': 'INFO', + 'class': 'logging.StreamHandler', + 'formatter': 'django.server', + }, + 'syslog': { + 'level': 'DEBUG', + 'class': 'logging.handlers.SysLogHandler', + 'formatter': 'syslog', + 'address': '/dev/log', + 'facility': SysLogHandler.LOG_LOCAL2, + }, + # Logging to a file + # 'logfile': { + # 'level':'DEBUG', + # 'class':'logging.handlers.RotatingFileHandler', + # 'filename': "/var/log/weblate/weblate.log", + # 'maxBytes': 100000, + # 'backupCount': 3, + # 'formatter': 'logfile', + # }, + }, + 'loggers': { + 'django.request': { + 'handlers': ['mail_admins', DEFAULT_LOG], + 'level': 'ERROR', + 'propagate': True, + }, + 'django.server': { + 'handlers': ['django.server'], + 'level': 'INFO', + 'propagate': False, + }, + # Logging database queries + # 'django.db.backends': { + # 'handlers': [DEFAULT_LOG], + # 'level': 'DEBUG', + # }, + 'weblate': { + 'handlers': [DEFAULT_LOG], + 'level': 'DEBUG', + }, + # Logging VCS operations + # 'weblate-vcs': { + # 'handlers': [DEFAULT_LOG], + # 'level': 'DEBUG', + # }, + # Python Social Auth logging + # 'social': { + # 'handlers': [DEFAULT_LOG], + # 'level': 'DEBUG', + # }, + } +} + +# Logging of management commands to console +if (os.environ.get('DJANGO_IS_MANAGEMENT_COMMAND', False) and + 'console' not in LOGGING['loggers']['weblate']['handlers']): + LOGGING['loggers']['weblate']['handlers'].append('console') + +# Remove syslog setup if it's not present +if not HAVE_SYSLOG: + del LOGGING['handlers']['syslog'] + +# List of machine translations +# MT_SERVICES = ( +# 'weblate.machinery.apertium.ApertiumAPYTranslation', +# 'weblate.machinery.deepl.DeepLTranslation', +# 'weblate.machinery.glosbe.GlosbeTranslation', +# 'weblate.machinery.google.GoogleTranslation', +# 'weblate.machinery.microsoft.MicrosoftCognitiveTranslation', +# 'weblate.machinery.mymemory.MyMemoryTranslation', +# 'weblate.machinery.tmserver.AmagamaTranslation', +# 'weblate.machinery.tmserver.TMServerTranslation', +# 'weblate.machinery.yandex.YandexTranslation', +# 'weblate.machinery.weblatetm.WeblateTranslation', +# 'weblate.machinery.saptranslationhub.SAPTranslationHub', +# 'weblate.memory.machine.WeblateMemory', +# ) + +# Machine translation API keys + +# URL of the Apertium APy server +MT_APERTIUM_APY = None + +# DeepL API key +MT_DEEPL_KEY = None + +# Microsoft Cognitive Services Translator API, register at +# https://portal.azure.com/ +MT_MICROSOFT_COGNITIVE_KEY = None + +# MyMemory identification email, see +# https://mymemory.translated.net/doc/spec.php +MT_MYMEMORY_EMAIL = None + +# Optional MyMemory credentials to access private translation memory +MT_MYMEMORY_USER = None +MT_MYMEMORY_KEY = None + +# Google API key for Google Translate API +MT_GOOGLE_KEY = None + +# API key for Yandex Translate API +MT_YANDEX_KEY = None + +# tmserver URL +MT_TMSERVER = None + +# SAP Translation Hub +MT_SAP_BASE_URL = None +MT_SAP_SANDBOX_APIKEY = None +MT_SAP_USERNAME = None +MT_SAP_PASSWORD = None +MT_SAP_USE_MT = True + +# Title of site to use +SITE_TITLE = 'Weblate' + +# Whether site uses https +ENABLE_HTTPS = True + +# Use HTTPS when creating redirect URLs for social authentication, see +# documentation for more details: +# http://python-social-auth-docs.readthedocs.io/en/latest/configuration/settings.html#processing-redirects-and-urlopen +SOCIAL_AUTH_REDIRECT_IS_HTTPS = ENABLE_HTTPS + +# Make CSRF cookie HttpOnly, see documentation for more details: +# https://docs.djangoproject.com/en/1.11/ref/settings/#csrf-cookie-httponly +CSRF_COOKIE_HTTPONLY = True +CSRF_COOKIE_SECURE = ENABLE_HTTPS +# Store CSRF token in session (since Django 1.11) +CSRF_USE_SESSIONS = True +SESSION_COOKIE_SECURE = ENABLE_HTTPS +# Session cookie age (in seconds) +SESSION_COOKIE_AGE = 1209600 + +# URL of login +LOGIN_URL = '{0}/accounts/login/'.format(URL_PREFIX) + +# URL of logout +LOGOUT_URL = '{0}/accounts/logout/'.format(URL_PREFIX) + +# Default location for login +LOGIN_REDIRECT_URL = '{0}/'.format(URL_PREFIX) + +# Anonymous user name +ANONYMOUS_USER_NAME = 'anonymous' + +# Reverse proxy settings +IP_BEHIND_REVERSE_PROXY = False +IP_PROXY_HEADER = 'HTTP_X_FORWARDED_FOR' +IP_PROXY_OFFSET = 0 + +# Sending HTML in mails +EMAIL_SEND_HTML = True + +# Subject of emails includes site title +EMAIL_SUBJECT_PREFIX = '[{0}] '.format(SITE_TITLE) + +EMAIL_BACKEND = 'django_sendmail_backend.backends.EmailBackend' + +# Enable remote hooks +ENABLE_HOOKS = True + +# Whether to run hooks in background +BACKGROUND_HOOKS = True + +# Number of nearby messages to show in each direction +NEARBY_MESSAGES = 5 + +# Offload indexing +OFFLOAD_INDEXING = True + +# Use simple language codes for default language/country combinations +SIMPLIFY_LANGUAGES = True + +# Render forms using bootstrap +CRISPY_TEMPLATE_PACK = 'bootstrap3' + +# List of quality checks +# CHECK_LIST = ( +# 'weblate.checks.same.SameCheck', +# 'weblate.checks.chars.BeginNewlineCheck', +# 'weblate.checks.chars.EndNewlineCheck', +# 'weblate.checks.chars.BeginSpaceCheck', +# 'weblate.checks.chars.EndSpaceCheck', +# 'weblate.checks.chars.EndStopCheck', +# 'weblate.checks.chars.EndColonCheck', +# 'weblate.checks.chars.EndQuestionCheck', +# 'weblate.checks.chars.EndExclamationCheck', +# 'weblate.checks.chars.EndEllipsisCheck', +# 'weblate.checks.chars.EndSemicolonCheck', +# 'weblate.checks.chars.MaxLengthCheck', +# 'weblate.checks.format.PythonFormatCheck', +# 'weblate.checks.format.PythonBraceFormatCheck', +# 'weblate.checks.format.PHPFormatCheck', +# 'weblate.checks.format.CFormatCheck', +# 'weblate.checks.format.PerlFormatCheck', +# 'weblate.checks.format.JavascriptFormatCheck', +# 'weblate.checks.consistency.PluralsCheck', +# 'weblate.checks.consistency.SamePluralsCheck', +# 'weblate.checks.consistency.ConsistencyCheck', +# 'weblate.checks.consistency.TranslatedCheck', +# 'weblate.checks.chars.NewlineCountingCheck', +# 'weblate.checks.markup.BBCodeCheck', +# 'weblate.checks.chars.ZeroWidthSpaceCheck', +# 'weblate.checks.markup.XMLValidityCheck', +# 'weblate.checks.markup.XMLTagsCheck', +# 'weblate.checks.source.OptionalPluralCheck', +# 'weblate.checks.source.EllipsisCheck', +# 'weblate.checks.source.MultipleFailingCheck', +# ) + +# List of automatic fixups +# AUTOFIX_LIST = ( +# 'weblate.trans.autofixes.whitespace.SameBookendingWhitespace', +# 'weblate.trans.autofixes.chars.ReplaceTrailingDotsWithEllipsis', +# 'weblate.trans.autofixes.chars.RemoveZeroSpace', +# 'weblate.trans.autofixes.chars.RemoveControlChars', +# ) + +# List of enabled addons +# WEBLATE_ADDONS = ( +# 'weblate.addons.gettext.GenerateMoAddon', +# 'weblate.addons.gettext.UpdateLinguasAddon', +# 'weblate.addons.gettext.UpdateConfigureAddon', +# 'weblate.addons.gettext.MsgmergeAddon', +# 'weblate.addons.gettext.GettextCustomizeAddon', +# 'weblate.addons.gettext.GettextAuthorComments', +# 'weblate.addons.cleanup.CleanupAddon', +# 'weblate.addons.consistency.LangaugeConsistencyAddon', +# 'weblate.addons.discovery.DiscoveryAddon', +# 'weblate.addons.flags.SourceEditAddon', +# 'weblate.addons.flags.TargetEditAddon', +# 'weblate.addons.generate.GenerateFileAddon', +# 'weblate.addons.json.JSONCustomizeAddon', +# 'weblate.addons.properties.PropertiesSortAddon', +# ) + +# E-mail address that error messages come from. +SERVER_EMAIL = 'noreply@__DOMAIN__' + +# Default email address to use for various automated correspondence from +# the site managers. Used for registration emails. +DEFAULT_FROM_EMAIL = '__ADMINMAIL__' + +# List of URLs your site is supposed to serve +ALLOWED_HOSTS = ['__DOMAIN__'] + +# Example configuration to use memcached for caching +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', + 'LOCATION': '127.0.0.1:__MEMCPORT__', + }, + 'avatar': { + 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': os.path.join(BASE_DIR, 'avatar-cache'), + 'TIMEOUT': 3600, + 'OPTIONS': { + 'MAX_ENTRIES': 1000, + }, + } +} + +# REST framework settings for API +REST_FRAMEWORK = { + # Use Django's standard `django.contrib.auth` permissions, + # or allow read-only access for unauthenticated users. + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAuthenticatedOrReadOnly' + ], + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework.authentication.TokenAuthentication', + 'weblate.api.authentication.BearerAuthentication', + 'rest_framework.authentication.SessionAuthentication', + ), + 'DEFAULT_THROTTLE_CLASSES': ( + 'rest_framework.throttling.AnonRateThrottle', + 'rest_framework.throttling.UserRateThrottle' + ), + 'DEFAULT_THROTTLE_RATES': { + 'anon': '100/day', + 'user': '1000/day' + }, + 'DEFAULT_PAGINATION_CLASS': ( + 'rest_framework.pagination.PageNumberPagination' + ), + 'PAGE_SIZE': 20, + 'VIEW_DESCRIPTION_FUNCTION': 'weblate.api.views.get_view_description', + 'UNAUTHENTICATED_USER': 'weblate.auth.models.get_anonymous', +} + +# Example for restricting access to logged in users +# LOGIN_REQUIRED_URLS = ( +# r'/(.*)$', +# ) + +# In such case you will want to include some of the exceptions +# LOGIN_REQUIRED_URLS_EXCEPTIONS = ( +# r'/accounts/(.*)$', # Required for login +# r'/static/(.*)$', # Required for development mode +# r'/widgets/(.*)$', # Allowing public access to widgets +# r'/data/(.*)$', # Allowing public access to data exports +# r'/hooks/(.*)$', # Allowing public access to notification hooks +# r'/api/(.*)$', # Allowing access to API +# r'/js/i18n/$', # Javascript localization +# r'/contact/$', # Optional for contact form +# r'/legal/(.*)$', # Optional for legal app +# ) + +# Force sane test runner +TEST_RUNNER = 'django.test.runner.DiscoverRunner' diff --git a/manifest.json b/manifest.json index 41d3fc4..551eb23 100644 --- a/manifest.json +++ b/manifest.json @@ -8,7 +8,7 @@ "description": { "en": "A translation platform using Git and Python" }, - "version": "3.0~ynh1", + "version": "3.0.1~ynh1", "url": "https://weblate.org", "license": "AGPL-3.0", "maintainer": { diff --git a/scripts/_common.sh b/scripts/_common.sh index a2d3238..bc8eba1 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -1,6 +1,6 @@ #!/bin/bash -current_version="3.0" +current_version="3.0.1" ynh_check_global_uwsgi_config () { uwsgi --version || ynh_die "You need to add uwsgi (and appropriate plugin) as a dependency" From 5e78b6e62ee2937f9fbe1557aced448921b66884 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Wed, 13 Jun 2018 23:49:24 +0200 Subject: [PATCH 07/16] Improve cron file --- conf/cron | 6 +++--- scripts/install | 1 + scripts/upgrade | 7 +++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/conf/cron b/conf/cron index 86c40be..08f59d1 100644 --- a/conf/cron +++ b/conf/cron @@ -1,9 +1,9 @@ # https://docs.weblate.org/en/latest/admin/install.html#production-cron # Fulltext index updates -*/5 * * * * weblate DJANGO_SETTINGS_MODULE="weblate.settings" __FINALPATH__/venv/bin/weblate update_index +*/5 * * * * __APP__ export DJANGO_SETTINGS_MODULE="weblate.settings" && cd __FINALPATH__ && venv/bin/weblate update_index # Cleanup stale objects -@daily weblate DJANGO_SETTINGS_MODULE="weblate.settings" __FINALPATH__/venv/bin/weblate cleanuptrans +@daily __APP__ export DJANGO_SETTINGS_MODULE="weblate.settings" && cd __FINALPATH__ && venv/bin/weblate cleanuptrans # Commit pending changes after 96 hours -@hourly weblate DJANGO_SETTINGS_MODULE="weblate.settings" __FINALPATH__/venv/bin/weblate commit_pending --all --age=96 --verbosity=0 +@hourly __APP__ export DJANGO_SETTINGS_MODULE="weblate.settings" && cd __FINALPATH__ && venv/bin/weblate commit_pending --all --age=96 --verbosity=0 diff --git a/scripts/install b/scripts/install index 2dc9a2d..1e7d764 100755 --- a/scripts/install +++ b/scripts/install @@ -239,6 +239,7 @@ ynh_app_setting_set "$app" memc_port "$memc_port" # SETUP CRON #================================================= cp ../conf/cron "/etc/cron.d/$app" +ynh_replace_string "__APP__" "$app" "/etc/cron.d/$app" ynh_replace_string "__FINALPATH__" "$final_path/" "/etc/cron.d/$app" #================================================= diff --git a/scripts/upgrade b/scripts/upgrade index 5c87db3..94f8844 100755 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -270,6 +270,13 @@ fi # Recalculate and store the config file checksum into the app settings ynh_store_file_checksum "$final_path/venv/lib/python2.7/site-packages/weblate/settings.py" +#================================================= +# SETUP CRON +#================================================= +cp ../conf/cron "/etc/cron.d/$app" +ynh_replace_string "__APP__" "$app" "/etc/cron.d/$app" +ynh_replace_string "__FINALPATH__" "$final_path/" "/etc/cron.d/$app" + #================================================= # GENERIC FINALIZATION #================================================= From ba3cc65b61082412e0e9e918d4902ec8f6383df1 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Mon, 27 Aug 2018 22:27:38 +0200 Subject: [PATCH 08/16] remove pgsql helpers (included in core) --- manifest.json | 4 +- scripts/_common.sh | 159 --------------------------------------------- 2 files changed, 2 insertions(+), 161 deletions(-) diff --git a/manifest.json b/manifest.json index 551eb23..16226dd 100644 --- a/manifest.json +++ b/manifest.json @@ -3,12 +3,12 @@ "id": "weblate", "packaging_format": 1, "requirements": { - "yunohost": ">= 2.7.10" + "yunohost": ">= 3.1.0" }, "description": { "en": "A translation platform using Git and Python" }, - "version": "3.0.1~ynh1", + "version": "3.0.1~ynh2", "url": "https://weblate.org", "license": "AGPL-3.0", "maintainer": { diff --git a/scripts/_common.sh b/scripts/_common.sh index bc8eba1..cb6afd8 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -117,165 +117,6 @@ ynh_check_if_checksum_is_different() { echo "$check" } -#================================================= -# -# POSTGRES HELPERS -# -# Point of contact : Jean-Baptiste Holcroft -#================================================= - -# Create a master password and set up global settings -# Please always call this script in install and restore scripts -# -# usage: ynh_psql_test_if_first_run - -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 - sudo --login --user=postgres psql -c"ALTER user postgres WITH PASSWORD '$pgsql'" postgres - - # force all user to connect to local database using passwords - # https://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html#EXAMPLE-PG-HBA.CONF - # Note: we can't use peer since YunoHost create users with nologin - # See: https://github.com/YunoHost/yunohost/blob/unstable/data/helpers.d/user - 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" - sudo --login --user=postgres PGUSER="$user" PGPASSWORD="$pwd" psql "$db" -} - -# # 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" - sudo --login --user=postgres psql <<< "$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" - sudo --login --user=postgres psql "$db" < "$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" - 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 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" - sudo --login --user=postgres createdb --owner="$user" "$db" -} - -# 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" - sudo --login --user=postgres dropdb "$db" - 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" - sudo --login --user=postgres pg_dump "$db" -} - - -# 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" - sudo --login --user=postgres 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" - sudo --login --user=postgres dropuser "$user" -} - # Send an email to inform the administrator # # usage: ynh_send_readme_to_admin app_message [recipients] From 93253fb1c8f21befc13b888b83f33b0c336030fa Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Mon, 27 Aug 2018 22:30:12 +0200 Subject: [PATCH 09/16] Add 3.1.1 setting file --- conf/settings_history/settings.3.1.1.py | 757 ++++++++++++++++++++++++ 1 file changed, 757 insertions(+) create mode 100644 conf/settings_history/settings.3.1.1.py diff --git a/conf/settings_history/settings.3.1.1.py b/conf/settings_history/settings.3.1.1.py new file mode 100644 index 0000000..a142e66 --- /dev/null +++ b/conf/settings_history/settings.3.1.1.py @@ -0,0 +1,757 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2012 - 2018 Michal Čihař +# +# This file is part of Weblate +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +from __future__ import unicode_literals +import platform +import os +from logging.handlers import SysLogHandler + +# +# Django settings for Weblate project. +# + +DEBUG = False + +ADMINS = ( + ('__ADMIN__', '__ADMINMAIL__'), +) + +MANAGERS = ADMINS + +DATABASES = { + 'default': { + # Database engine + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + # Database name + 'NAME': '__NAME__', + # Database user + 'USER': '__NAME__', + # Database password + 'PASSWORD': '__DB_PWD__', + # Set to empty string for localhost + 'HOST': 'localhost', + # Set to empty string for default + 'PORT': '5432', + } +} + +BASE_DIR = '__FINALPATH__' + +# Data directory +DATA_DIR = os.path.join(BASE_DIR, 'data') + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# In a Windows environment this must be set to your system time zone. +TIME_ZONE = 'UTC' + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = 'en-us' + +LANGUAGES = ( + ('ar', 'العربية'), + ('az', 'Azərbaycan'), + ('be', 'Беларуская'), + ('be@latin', 'Biełaruskaja'), + ('bg', 'Български'), + ('br', 'Brezhoneg'), + ('ca', 'Català'), + ('cs', 'Čeština'), + ('da', 'Dansk'), + ('de', 'Deutsch'), + ('en', 'English'), + ('en-gb', 'English (United Kingdom)'), + ('el', 'Ελληνικά'), + ('es', 'Español'), + ('fi', 'Suomi'), + ('fr', 'Français'), + ('fy', 'Frysk'), + ('gl', 'Galego'), + ('he', 'עברית'), + ('hu', 'Magyar'), + ('id', 'Indonesia'), + ('it', 'Italiano'), + ('ja', '日本語'), + ('ko', '한국어'), + ('ksh', 'Kölsch'), + ('nb', 'Norsk bokmål'), + ('nl', 'Nederlands'), + ('pl', 'Polski'), + ('pt', 'Português'), + ('pt-br', 'Português brasileiro'), + ('ru', 'Русский'), + ('sk', 'Slovenčina'), + ('sl', 'Slovenščina'), + ('sr', 'Српски'), + ('sv', 'Svenska'), + ('tr', 'Türkçe'), + ('uk', 'Українська'), + ('zh-hans', '简体字'), + ('zh-hant', '正體字'), +) + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# If you set this to False, Django will not format dates, numbers and +# calendars according to the current locale. +USE_L10N = True + +# If you set this to False, Django will not use timezone-aware datetimes. +USE_TZ = True + +# URL prefix to use, please see documentation for more details +URL_PREFIX = '__PATHURL__' + +# Absolute filesystem path to the directory that will hold user-uploaded files. +# Example: "/home/media/media.lawrence.com/media/" +MEDIA_ROOT = os.path.join(DATA_DIR, 'media') + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash. +# Examples: "http://media.lawrence.com/media/", "http://example.com/media/" +MEDIA_URL = '{0}/media/'.format(URL_PREFIX) + +# Absolute path to the directory static files should be collected to. +# Don't put anything in this directory yourself; store your static files +# in apps' "static/" subdirectories and in STATICFILES_DIRS. +# Example: "/home/media/media.lawrence.com/static/" +STATIC_ROOT = os.path.join(DATA_DIR, 'static') + +# URL prefix for static files. +# Example: "http://media.lawrence.com/static/" +STATIC_URL = '{0}/static/'.format(URL_PREFIX) + +# Additional locations of static files +STATICFILES_DIRS = ( + # Put strings here, like "/home/html/static" or "C:/www/django/static". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +# List of finder classes that know how to find static files in +# various locations. +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + 'compressor.finders.CompressorFinder', +) + +# Make this unique, and don't share it with anybody. +# You can generate it using examples/generate-secret-key +SECRET_KEY = '__KEY__' # noqa + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + os.path.join(BASE_DIR, 'weblate', 'templates'), + ], + 'OPTIONS': { + 'context_processors': [ + 'django.contrib.auth.context_processors.auth', + 'django.template.context_processors.debug', + 'django.template.context_processors.i18n', + 'django.template.context_processors.request', + 'django.template.context_processors.csrf', + 'django.contrib.messages.context_processors.messages', + 'weblate.trans.context_processors.weblate_context', + ], + 'loaders': [ + ('django.template.loaders.cached.Loader', [ + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + ]), + ], + }, + }, +] + + +# GitHub username for sending pull requests. +# Please see the documentation for more details. +GITHUB_USERNAME = "__GITHUBUSER__" + +# Authentication configuration +AUTHENTICATION_BACKENDS = ( + 'social_core.backends.email.EmailAuth', + # 'social_core.backends.google.GoogleOAuth2', + # 'social_core.backends.github.GithubOAuth2', + # 'social_core.backends.bitbucket.BitbucketOAuth', + 'social_core.backends.suse.OpenSUSEOpenId', + 'social_core.backends.ubuntu.UbuntuOpenId', + 'social_core.backends.fedora.FedoraOpenId', + # 'social_core.backends.facebook.FacebookOAuth2', + 'weblate.accounts.auth.WeblateUserBackend', +) + +# Custom user model +AUTH_USER_MODEL = 'weblate_auth.User' + +# Social auth backends setup +SOCIAL_AUTH_GITHUB_KEY = '' +SOCIAL_AUTH_GITHUB_SECRET = '' +SOCIAL_AUTH_GITHUB_SCOPE = ['user:email'] + +SOCIAL_AUTH_BITBUCKET_KEY = '' +SOCIAL_AUTH_BITBUCKET_SECRET = '' +SOCIAL_AUTH_BITBUCKET_VERIFIED_EMAILS_ONLY = True + +SOCIAL_AUTH_FACEBOOK_KEY = '' +SOCIAL_AUTH_FACEBOOK_SECRET = '' +SOCIAL_AUTH_FACEBOOK_SCOPE = ['email', 'public_profile'] + +SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '' +SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '' + +# Social auth settings +SOCIAL_AUTH_PIPELINE = ( + 'social_core.pipeline.social_auth.social_details', + 'social_core.pipeline.social_auth.social_uid', + 'social_core.pipeline.social_auth.auth_allowed', + 'social_core.pipeline.social_auth.social_user', + 'weblate.accounts.pipeline.store_params', + 'weblate.accounts.pipeline.verify_open', + 'social_core.pipeline.user.get_username', + 'weblate.accounts.pipeline.require_email', + 'social_core.pipeline.mail.mail_validation', + 'weblate.accounts.pipeline.revoke_mail_code', + 'weblate.accounts.pipeline.ensure_valid', + 'weblate.accounts.pipeline.remove_account', + 'social_core.pipeline.social_auth.associate_by_email', + 'weblate.accounts.pipeline.reauthenticate', + 'weblate.accounts.pipeline.verify_username', + 'social_core.pipeline.user.create_user', + 'social_core.pipeline.social_auth.associate_user', + 'social_core.pipeline.social_auth.load_extra_data', + 'weblate.accounts.pipeline.cleanup_next', + 'weblate.accounts.pipeline.user_full_name', + 'weblate.accounts.pipeline.store_email', + 'weblate.accounts.pipeline.notify_connect', + 'weblate.accounts.pipeline.password_reset', +) +SOCIAL_AUTH_DISCONNECT_PIPELINE = ( + 'social_core.pipeline.disconnect.allowed_to_disconnect', + 'social_core.pipeline.disconnect.get_entries', + 'social_core.pipeline.disconnect.revoke_tokens', + 'weblate.accounts.pipeline.cycle_session', + 'weblate.accounts.pipeline.adjust_primary_mail', + 'weblate.accounts.pipeline.notify_disconnect', + 'social_core.pipeline.disconnect.disconnect', + 'weblate.accounts.pipeline.cleanup_next', +) + +# Custom authentication strategy +SOCIAL_AUTH_STRATEGY = 'weblate.accounts.strategy.WeblateStrategy' + +# Raise exceptions so that we can handle them later +SOCIAL_AUTH_RAISE_EXCEPTIONS = True + +SOCIAL_AUTH_EMAIL_VALIDATION_FUNCTION = \ + 'weblate.accounts.pipeline.send_validation' +SOCIAL_AUTH_EMAIL_VALIDATION_URL = \ + '{0}/accounts/email-sent/'.format(URL_PREFIX) +SOCIAL_AUTH_LOGIN_ERROR_URL = \ + '{0}/accounts/login/'.format(URL_PREFIX) +SOCIAL_AUTH_EMAIL_FORM_URL = \ + '{0}/accounts/email/'.format(URL_PREFIX) +SOCIAL_AUTH_NEW_ASSOCIATION_REDIRECT_URL = \ + '{0}/accounts/profile/#auth'.format(URL_PREFIX) +SOCIAL_AUTH_PROTECTED_USER_FIELDS = ('email',) +SOCIAL_AUTH_SLUGIFY_USERNAMES = True +SOCIAL_AUTH_SLUGIFY_FUNCTION = 'weblate.accounts.pipeline.slugify_username' + +# Password validation configuration +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + 'OPTIONS': { + 'min_length': 6, + } + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, + { + 'NAME': 'weblate.accounts.password_validation.CharsPasswordValidator', + }, + { + 'NAME': 'weblate.accounts.password_validation.PastPasswordsValidator', + }, + # Optional password strength validation by django-zxcvbn-password + # { + # 'NAME': 'zxcvbn_password.ZXCVBNValidator', + # 'OPTIONS': { + # 'min_score': 3, + # 'user_attributes': ('username', 'email', 'full_name') + # } + # }, +] + +# Middleware +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'weblate.accounts.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'social_django.middleware.SocialAuthExceptionMiddleware', + 'weblate.accounts.middleware.RequireLoginMiddleware', + 'weblate.middleware.SecurityMiddleware', + 'weblate.wladmin.middleware.ConfigurationErrorsMiddleware', +] + +ROOT_URLCONF = 'weblate.urls' + +# Django and Weblate apps +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django.contrib.admin.apps.SimpleAdminConfig', + 'django.contrib.admindocs', + 'django.contrib.sitemaps', + 'social_django', + 'crispy_forms', + 'compressor', + 'rest_framework', + 'rest_framework.authtoken', + 'weblate.addons', + 'weblate.auth', + 'weblate.checks', + 'weblate.formats', + 'weblate.machinery', + 'weblate.trans', + 'weblate.lang', + 'weblate.langdata', + 'weblate.memory', + 'weblate.permissions', + 'weblate.screenshots', + 'weblate.accounts', + 'weblate.utils', + 'weblate.vcs', + 'weblate.wladmin', + 'weblate', + + # Optional: Git exporter + # 'weblate.gitexport', +) + +# Path to locales +LOCALE_PATHS = (os.path.join(BASE_DIR, 'weblate', 'locale'), ) + +# Custom exception reporter to include some details +DEFAULT_EXCEPTION_REPORTER_FILTER = \ + 'weblate.trans.debug.WeblateExceptionReporterFilter' + +# Default logging of Weblate messages +# - to syslog in production (if available) +# - otherwise to console +# - you can also choose 'logfile' to log into separate file +# after configuring it below + +# Detect if we can connect to syslog +HAVE_SYSLOG = False +if platform.system() != 'Windows': + try: + handler = SysLogHandler( + address='/dev/log', facility=SysLogHandler.LOG_LOCAL2 + ) + handler.close() + HAVE_SYSLOG = True + except IOError: + HAVE_SYSLOG = False + +if DEBUG or not HAVE_SYSLOG: + DEFAULT_LOG = 'console' +else: + DEFAULT_LOG = 'syslog' + +# A sample logging configuration. The only tangible logging +# performed by this configuration is to send an email to +# the site admins on every HTTP 500 error when DEBUG=False. +# See http://docs.djangoproject.com/en/stable/topics/logging for +# more details on how to customize your logging configuration. +LOGGING = { + 'version': 1, + 'disable_existing_loggers': True, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse' + } + }, + 'formatters': { + 'syslog': { + 'format': 'weblate[%(process)d]: %(levelname)s %(message)s' + }, + 'simple': { + 'format': '%(levelname)s %(message)s' + }, + 'logfile': { + 'format': '%(asctime)s %(levelname)s %(message)s' + }, + 'django.server': { + '()': 'django.utils.log.ServerFormatter', + 'format': '[%(server_time)s] %(message)s', + } + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler', + 'include_html': True, + }, + 'console': { + 'level': 'DEBUG', + 'class': 'logging.StreamHandler', + 'formatter': 'simple' + }, + 'django.server': { + 'level': 'INFO', + 'class': 'logging.StreamHandler', + 'formatter': 'django.server', + }, + 'syslog': { + 'level': 'DEBUG', + 'class': 'logging.handlers.SysLogHandler', + 'formatter': 'syslog', + 'address': '/dev/log', + 'facility': SysLogHandler.LOG_LOCAL2, + }, + # Logging to a file + # 'logfile': { + # 'level':'DEBUG', + # 'class':'logging.handlers.RotatingFileHandler', + # 'filename': "/var/log/weblate/weblate.log", + # 'maxBytes': 100000, + # 'backupCount': 3, + # 'formatter': 'logfile', + # }, + }, + 'loggers': { + 'django.request': { + 'handlers': ['mail_admins', DEFAULT_LOG], + 'level': 'ERROR', + 'propagate': True, + }, + 'django.server': { + 'handlers': ['django.server'], + 'level': 'INFO', + 'propagate': False, + }, + # Logging database queries + # 'django.db.backends': { + # 'handlers': [DEFAULT_LOG], + # 'level': 'DEBUG', + # }, + 'weblate': { + 'handlers': [DEFAULT_LOG], + 'level': 'DEBUG', + }, + # Logging VCS operations + # 'weblate-vcs': { + # 'handlers': [DEFAULT_LOG], + # 'level': 'DEBUG', + # }, + # Python Social Auth logging + # 'social': { + # 'handlers': [DEFAULT_LOG], + # 'level': 'DEBUG', + # }, + } +} + +# Logging of management commands to console +if (os.environ.get('DJANGO_IS_MANAGEMENT_COMMAND', False) and + 'console' not in LOGGING['loggers']['weblate']['handlers']): + LOGGING['loggers']['weblate']['handlers'].append('console') + +# Remove syslog setup if it's not present +if not HAVE_SYSLOG: + del LOGGING['handlers']['syslog'] + +# List of machine translations +# MT_SERVICES = ( +# 'weblate.machinery.apertium.ApertiumAPYTranslation', +# 'weblate.machinery.deepl.DeepLTranslation', +# 'weblate.machinery.glosbe.GlosbeTranslation', +# 'weblate.machinery.google.GoogleTranslation', +# 'weblate.machinery.microsoft.MicrosoftCognitiveTranslation', +# 'weblate.machinery.mymemory.MyMemoryTranslation', +# 'weblate.machinery.tmserver.AmagamaTranslation', +# 'weblate.machinery.tmserver.TMServerTranslation', +# 'weblate.machinery.yandex.YandexTranslation', +# 'weblate.machinery.weblatetm.WeblateTranslation', +# 'weblate.machinery.saptranslationhub.SAPTranslationHub', +# 'weblate.memory.machine.WeblateMemory', +# ) + +# Machine translation API keys + +# URL of the Apertium APy server +MT_APERTIUM_APY = None + +# DeepL API key +MT_DEEPL_KEY = None + +# Microsoft Cognitive Services Translator API, register at +# https://portal.azure.com/ +MT_MICROSOFT_COGNITIVE_KEY = None + +# MyMemory identification email, see +# https://mymemory.translated.net/doc/spec.php +MT_MYMEMORY_EMAIL = None + +# Optional MyMemory credentials to access private translation memory +MT_MYMEMORY_USER = None +MT_MYMEMORY_KEY = None + +# Google API key for Google Translate API +MT_GOOGLE_KEY = None + +# API key for Yandex Translate API +MT_YANDEX_KEY = None + +# tmserver URL +MT_TMSERVER = None + +# SAP Translation Hub +MT_SAP_BASE_URL = None +MT_SAP_SANDBOX_APIKEY = None +MT_SAP_USERNAME = None +MT_SAP_PASSWORD = None +MT_SAP_USE_MT = True + +# Title of site to use +SITE_TITLE = 'Weblate' + +# Whether site uses https +ENABLE_HTTPS = True + +# Use HTTPS when creating redirect URLs for social authentication, see +# documentation for more details: +# http://python-social-auth-docs.readthedocs.io/en/latest/configuration/settings.html#processing-redirects-and-urlopen +SOCIAL_AUTH_REDIRECT_IS_HTTPS = ENABLE_HTTPS + +# Make CSRF cookie HttpOnly, see documentation for more details: +# https://docs.djangoproject.com/en/1.11/ref/settings/#csrf-cookie-httponly +CSRF_COOKIE_HTTPONLY = True +CSRF_COOKIE_SECURE = ENABLE_HTTPS +# Store CSRF token in session (since Django 1.11) +CSRF_USE_SESSIONS = True +SESSION_COOKIE_SECURE = ENABLE_HTTPS +# Session cookie age (in seconds) +SESSION_COOKIE_AGE = 1209600 + +# URL of login +LOGIN_URL = '{0}/accounts/login/'.format(URL_PREFIX) + +# URL of logout +LOGOUT_URL = '{0}/accounts/logout/'.format(URL_PREFIX) + +# Default location for login +LOGIN_REDIRECT_URL = '{0}/'.format(URL_PREFIX) + +# Anonymous user name +ANONYMOUS_USER_NAME = 'anonymous' + +# Reverse proxy settings +IP_BEHIND_REVERSE_PROXY = False +IP_PROXY_HEADER = 'HTTP_X_FORWARDED_FOR' +IP_PROXY_OFFSET = 0 + +# Sending HTML in mails +EMAIL_SEND_HTML = True + +# Subject of emails includes site title +EMAIL_SUBJECT_PREFIX = '[{0}] '.format(SITE_TITLE) + +EMAIL_BACKEND = 'django_sendmail_backend.backends.EmailBackend' + +# Enable remote hooks +ENABLE_HOOKS = True + +# Whether to run hooks in background +BACKGROUND_HOOKS = True + +# Number of nearby messages to show in each direction +NEARBY_MESSAGES = 5 + +# Offload indexing +OFFLOAD_INDEXING = True + +# Use simple language codes for default language/country combinations +SIMPLIFY_LANGUAGES = True + +# Render forms using bootstrap +CRISPY_TEMPLATE_PACK = 'bootstrap3' + +# List of quality checks +# CHECK_LIST = ( +# 'weblate.checks.same.SameCheck', +# 'weblate.checks.chars.BeginNewlineCheck', +# 'weblate.checks.chars.EndNewlineCheck', +# 'weblate.checks.chars.BeginSpaceCheck', +# 'weblate.checks.chars.EndSpaceCheck', +# 'weblate.checks.chars.EndStopCheck', +# 'weblate.checks.chars.EndColonCheck', +# 'weblate.checks.chars.EndQuestionCheck', +# 'weblate.checks.chars.EndExclamationCheck', +# 'weblate.checks.chars.EndEllipsisCheck', +# 'weblate.checks.chars.EndSemicolonCheck', +# 'weblate.checks.chars.MaxLengthCheck', +# 'weblate.checks.format.PythonFormatCheck', +# 'weblate.checks.format.PythonBraceFormatCheck', +# 'weblate.checks.format.PHPFormatCheck', +# 'weblate.checks.format.CFormatCheck', +# 'weblate.checks.format.PerlFormatCheck', +# 'weblate.checks.format.JavascriptFormatCheck', +# 'weblate.checks.consistency.PluralsCheck', +# 'weblate.checks.consistency.SamePluralsCheck', +# 'weblate.checks.consistency.ConsistencyCheck', +# 'weblate.checks.consistency.TranslatedCheck', +# 'weblate.checks.chars.NewlineCountingCheck', +# 'weblate.checks.markup.BBCodeCheck', +# 'weblate.checks.chars.ZeroWidthSpaceCheck', +# 'weblate.checks.markup.XMLValidityCheck', +# 'weblate.checks.markup.XMLTagsCheck', +# 'weblate.checks.source.OptionalPluralCheck', +# 'weblate.checks.source.EllipsisCheck', +# 'weblate.checks.source.MultipleFailingCheck', +# ) + +# List of automatic fixups +# AUTOFIX_LIST = ( +# 'weblate.trans.autofixes.whitespace.SameBookendingWhitespace', +# 'weblate.trans.autofixes.chars.ReplaceTrailingDotsWithEllipsis', +# 'weblate.trans.autofixes.chars.RemoveZeroSpace', +# 'weblate.trans.autofixes.chars.RemoveControlChars', +# ) + +# List of enabled addons +# WEBLATE_ADDONS = ( +# 'weblate.addons.gettext.GenerateMoAddon', +# 'weblate.addons.gettext.UpdateLinguasAddon', +# 'weblate.addons.gettext.UpdateConfigureAddon', +# 'weblate.addons.gettext.MsgmergeAddon', +# 'weblate.addons.gettext.GettextCustomizeAddon', +# 'weblate.addons.gettext.GettextAuthorComments', +# 'weblate.addons.cleanup.CleanupAddon', +# 'weblate.addons.consistency.LangaugeConsistencyAddon', +# 'weblate.addons.discovery.DiscoveryAddon', +# 'weblate.addons.flags.SourceEditAddon', +# 'weblate.addons.flags.TargetEditAddon', +# 'weblate.addons.generate.GenerateFileAddon', +# 'weblate.addons.json.JSONCustomizeAddon', +# 'weblate.addons.properties.PropertiesSortAddon', +# ) + +# E-mail address that error messages come from. +SERVER_EMAIL = 'noreply@__DOMAIN__' + +# Default email address to use for various automated correspondence from +# the site managers. Used for registration emails. +DEFAULT_FROM_EMAIL = '__ADMINMAIL__' + +# List of URLs your site is supposed to serve +ALLOWED_HOSTS = ['__DOMAIN__'] + +# Example configuration to use memcached for caching +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', + 'LOCATION': '127.0.0.1:__MEMCPORT__', + }, + 'avatar': { + 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': os.path.join(BASE_DIR, 'avatar-cache'), + 'TIMEOUT': 3600, + 'OPTIONS': { + 'MAX_ENTRIES': 1000, + }, + } +} + +# REST framework settings for API +REST_FRAMEWORK = { + # Use Django's standard `django.contrib.auth` permissions, + # or allow read-only access for unauthenticated users. + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAuthenticatedOrReadOnly' + ], + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework.authentication.TokenAuthentication', + 'weblate.api.authentication.BearerAuthentication', + 'rest_framework.authentication.SessionAuthentication', + ), + 'DEFAULT_THROTTLE_CLASSES': ( + 'rest_framework.throttling.AnonRateThrottle', + 'rest_framework.throttling.UserRateThrottle' + ), + 'DEFAULT_THROTTLE_RATES': { + 'anon': '100/day', + 'user': '1000/day' + }, + 'DEFAULT_PAGINATION_CLASS': ( + 'rest_framework.pagination.PageNumberPagination' + ), + 'PAGE_SIZE': 20, + 'VIEW_DESCRIPTION_FUNCTION': 'weblate.api.views.get_view_description', + 'UNAUTHENTICATED_USER': 'weblate.auth.models.get_anonymous', +} + +# Example for restricting access to logged in users +# LOGIN_REQUIRED_URLS = ( +# r'/(.*)$', +# ) + +# In such case you will want to include some of the exceptions +# LOGIN_REQUIRED_URLS_EXCEPTIONS = ( +# r'/accounts/(.*)$', # Required for login +# r'/static/(.*)$', # Required for development mode +# r'/widgets/(.*)$', # Allowing public access to widgets +# r'/data/(.*)$', # Allowing public access to data exports +# r'/hooks/(.*)$', # Allowing public access to notification hooks +# r'/api/(.*)$', # Allowing access to API +# r'/js/i18n/$', # Javascript localization +# r'/contact/$', # Optional for contact form +# r'/legal/(.*)$', # Optional for legal app +# ) + +# Force sane test runner +TEST_RUNNER = 'django.test.runner.DiscoverRunner' From 84c2ceb7a87a94c5e41cacf0996d8a5a9587ff65 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Mon, 27 Aug 2018 22:36:09 +0200 Subject: [PATCH 10/16] Upgrade to 3.1.1 --- conf/settings_history/settings.3.1.1.py | 35 +++++++++++++++++-------- manifest.json | 2 +- scripts/_common.sh | 2 +- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/conf/settings_history/settings.3.1.1.py b/conf/settings_history/settings.3.1.1.py index a142e66..d405f72 100644 --- a/conf/settings_history/settings.3.1.1.py +++ b/conf/settings_history/settings.3.1.1.py @@ -27,7 +27,7 @@ from logging.handlers import SysLogHandler # Django settings for Weblate project. # -DEBUG = False +DEBUG = FALSE ADMINS = ( ('__ADMIN__', '__ADMINMAIL__'), @@ -359,7 +359,6 @@ INSTALLED_APPS = ( 'weblate.lang', 'weblate.langdata', 'weblate.memory', - 'weblate.permissions', 'weblate.screenshots', 'weblate.accounts', 'weblate.utils', @@ -575,9 +574,21 @@ CSRF_COOKIE_SECURE = ENABLE_HTTPS # Store CSRF token in session (since Django 1.11) CSRF_USE_SESSIONS = True SESSION_COOKIE_SECURE = ENABLE_HTTPS +# SSL redirect +SECURE_SSL_REDIRECT = ENABLE_HTTPS # Session cookie age (in seconds) SESSION_COOKIE_AGE = 1209600 +# Some security headers +SECURE_BROWSER_XSS_FILTER = True +X_FRAME_OPTIONS = 'DENY' +SECURE_CONTENT_TYPE_NOSNIFF = True + +# Optionally enable HSTS +SECURE_HSTS_SECONDS = 0 +SECURE_HSTS_PRELOAD = False +SECURE_HSTS_INCLUDE_SUBDOMAINS = False + # URL of login LOGIN_URL = '{0}/accounts/login/'.format(URL_PREFIX) @@ -742,15 +753,17 @@ REST_FRAMEWORK = { # In such case you will want to include some of the exceptions # LOGIN_REQUIRED_URLS_EXCEPTIONS = ( -# r'/accounts/(.*)$', # Required for login -# r'/static/(.*)$', # Required for development mode -# r'/widgets/(.*)$', # Allowing public access to widgets -# r'/data/(.*)$', # Allowing public access to data exports -# r'/hooks/(.*)$', # Allowing public access to notification hooks -# r'/api/(.*)$', # Allowing access to API -# r'/js/i18n/$', # Javascript localization -# r'/contact/$', # Optional for contact form -# r'/legal/(.*)$', # Optional for legal app +# r'/accounts/(.*)$', # Required for login +# r'/admin/login/(.*)$', # Required for admin login +# r'/static/(.*)$', # Required for development mode +# r'/widgets/(.*)$', # Allowing public access to widgets +# r'/data/(.*)$', # Allowing public access to data exports +# r'/hooks/(.*)$', # Allowing public access to notification hooks +# r'/healthz/$', # Allowing public access to health check +# r'/api/(.*)$', # Allowing access to API +# r'/js/i18n/$', # Javascript localization +# r'/contact/$', # Optional for contact form +# r'/legal/(.*)$', # Optional for legal app # ) # Force sane test runner diff --git a/manifest.json b/manifest.json index 16226dd..1dfb4d8 100644 --- a/manifest.json +++ b/manifest.json @@ -8,7 +8,7 @@ "description": { "en": "A translation platform using Git and Python" }, - "version": "3.0.1~ynh2", + "version": "3.1.1~ynh2", "url": "https://weblate.org", "license": "AGPL-3.0", "maintainer": { diff --git a/scripts/_common.sh b/scripts/_common.sh index cb6afd8..9a94ba5 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -1,6 +1,6 @@ #!/bin/bash -current_version="3.0.1" +current_version="3.1.1" ynh_check_global_uwsgi_config () { uwsgi --version || ynh_die "You need to add uwsgi (and appropriate plugin) as a dependency" From ff2fda78dba383c419cfcdede7f868fccc9cc887 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Sat, 1 Sep 2018 15:16:50 +0200 Subject: [PATCH 11/16] Add 3.1.1 upgrade with two steps upgrade --- conf/settings_history/settings.3.1.1.py | 2 +- hooks/post_app_upgrade | 18 ++++++++++ scripts/upgrade | 48 +++++++++++++++++++++---- 3 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 hooks/post_app_upgrade diff --git a/conf/settings_history/settings.3.1.1.py b/conf/settings_history/settings.3.1.1.py index d405f72..37193f5 100644 --- a/conf/settings_history/settings.3.1.1.py +++ b/conf/settings_history/settings.3.1.1.py @@ -27,7 +27,7 @@ from logging.handlers import SysLogHandler # Django settings for Weblate project. # -DEBUG = FALSE +DEBUG = False ADMINS = ( ('__ADMIN__', '__ADMINMAIL__'), diff --git a/hooks/post_app_upgrade b/hooks/post_app_upgrade new file mode 100644 index 0000000..e397d3c --- /dev/null +++ b/hooks/post_app_upgrade @@ -0,0 +1,18 @@ +#!/bin/bash + +migration311=$(yunohost app setting "$YNH_APP_INSTANCE_NAME" "migration311" --output-as plain --quiet) +mig_type=$(yunohost app setting "$YNH_APP_INSTANCE_NAME" "migration311_type" --output-as plain --quiet) +mig_parm=$(yunohost app setting "$YNH_APP_INSTANCE_NAME" "migration311_parm" --output-as plain --quiet) + +if [[ "$migration311" = "two_steps_upgrade_3.0to3.1-needed" ]] +then + yunohost app setting "$YNH_APP_INSTANCE_NAME" "migration311" --value="two_steps_upgrade_3.0to3.1-progress" --quiet + if [ "$mig_type" = "file" ] + then + yunohost app upgrade "$YNH_APP_INSTANCE_NAME" --file "$mig_parm" + else + yunohost app upgrade "$YNH_APP_INSTANCE_NAME" --url "$mig_parm" + fi + + yunohost app setting "$YNH_APP_INSTANCE_NAME" "migration311" --value="two_steps_upgrade_3.0to3.1-done" --quiet +fi \ No newline at end of file diff --git a/scripts/upgrade b/scripts/upgrade index 94f8844..c7710e0 100755 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -26,6 +26,7 @@ admin=$(ynh_app_setting_get "$app" admin) admin_mail=$(ynh_user_get_info "$admin" mail) memc_port=$(ynh_app_setting_get "$app" memc_port) github_account=$(ynh_app_setting_get "$app" github_account) +migration311=$(ynh_app_setting_get "$app" migration311) key=$(ynh_string_random) #================================================= @@ -84,7 +85,7 @@ then fi # (<2.20) remove your old sockets! -if [ -e "/etc/systemd/system/uwsgi-app@.socket" ] +if [ -e "/etc/systemd/system/uwsgi-app@$app.socket" ] then systemctl stop "uwsgi-app@$app.socket" yunohost service remove "uwsgi-app@$app.socket" @@ -104,6 +105,34 @@ then ynh_secure_remove "$final_path/bin/" fi +# Weblate requires an update to 3.0 before 3.1 +# the upgrade hook will launch this script again to make sure it works +if [[ -z "$migration311" ]] +then + # $migration311 is not set, version is <3.0 + migration311="two_steps_upgrade_3.0to3.1-needed" + + mig_type=$(cat "/etc/yunohost/apps/$YNH_APP_ID/status.json" | sed -e 's/.*"type":.*"\(.\+\)".*/\1/gi') + + if [ "$mig_type" = "file" ] + then + mig_parm=$(cat "/etc/yunohost/apps/$YNH_APP_ID/status.json" | sed -e 's/.*"path": "\(.\+\)",.*/\1/gi') + else + mig_parm=$(cat "/etc/yunohost/apps/$YNH_APP_ID/status.json" | sed -e 's/.*"url": "\(.\+\)", "type".*/\1/gi') + fi + + ynh_app_setting_set "$app" migration311 "$migration311" + ynh_app_setting_set "$app" migration311_type "$mig_type" + ynh_app_setting_set "$app" migration311_parm "$mig_parm" + current_version="3.0.1" +fi + +# Make sure the uwsgi service is stoped +if [[ -e "/var/run/uwsgi/$app.socket" ]] +then + systemctl stop "uwsgi-app@$app.service" +fi + #================================================= # CHECK THE PATH #================================================= @@ -241,13 +270,18 @@ fi # https://docs.weblate.org/en/latest/admin/upgrade.html#upgrade-3 # https://github.com/WeblateOrg/docker/blob/386aa8d98bb57dfec3707680827d4e4f4d79e3fd/start#L81-L88 - weblate showmigrations --plan > /tmp/migrations.txt - if grep -Fq '[X] auth.0001_initial' /tmp/migrations.txt && grep -Fq '[ ] weblate_auth.0001_initial' /tmp/migrations.txt ; then - ynh_replace_string "AUTH_USER_MODEL" "#AUTH_USER_MODEL" "$settings" - weblate migrate weblate_auth 0001 - ynh_replace_string "#AUTH_USER_MODEL" "AUTH_USER_MODEL" "$settings" + if [[ $current_version = "3.0.1" ]] + then + weblate showmigrations --plan > /tmp/migrations.txt + if grep -Fq '[X] auth.0001_initial' /tmp/migrations.txt && grep -Fq '[ ] weblate_auth.0001_initial' /tmp/migrations.txt ; then + ynh_replace_string "AUTH_USER_MODEL" "#AUTH_USER_MODEL" "$settings" + weblate migrate weblate_auth 0001 + ynh_replace_string "#AUTH_USER_MODEL" "AUTH_USER_MODEL" "$settings" + fi + + ynh_secure_remove /tmp/migrations.txt fi - ynh_secure_remove /tmp/migrations.txt + weblate migrate --noinput weblate collectstatic --noinput From ea006f8e362777d790e21a7893059f083d759a19 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Sat, 1 Sep 2018 15:18:49 +0200 Subject: [PATCH 12/16] fix warning security.W009 (secret key length should be >=50) --- scripts/install | 2 +- scripts/upgrade | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/install b/scripts/install index 1e7d764..91d9338 100755 --- a/scripts/install +++ b/scripts/install @@ -207,7 +207,7 @@ virtualenv "${final_path}/venv" #================================================= db_pwd=$(ynh_app_setting_get "$app" psqlpwd) admin_mail=$(ynh_user_get_info "$admin" mail) -key=$(ynh_string_random) +key=$(ynh_string_random 50) memc_port=$(ynh_find_port 8080) settings="$final_path/venv/lib/python2.7/site-packages/weblate/settings.py" cp "../conf/settings_history/settings.$current_version.py" "$settings" diff --git a/scripts/upgrade b/scripts/upgrade index c7710e0..bf0fdbd 100755 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -27,7 +27,7 @@ admin_mail=$(ynh_user_get_info "$admin" mail) memc_port=$(ynh_app_setting_get "$app" memc_port) github_account=$(ynh_app_setting_get "$app" github_account) migration311=$(ynh_app_setting_get "$app" migration311) -key=$(ynh_string_random) +key=$(ynh_string_random 50) #================================================= # Get previous version number From 27cc87b09cd6d39a6642995043fef27a8b1b19f9 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Sat, 1 Sep 2018 22:42:51 +0200 Subject: [PATCH 13/16] Fix upgrade for locally modified settings files --- scripts/_common.sh | 2 +- scripts/upgrade | 66 +++++++++++++++++++++++++++++----------------- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/scripts/_common.sh b/scripts/_common.sh index 9a94ba5..da63d39 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -82,7 +82,7 @@ ynh_remove_uwsgi_service () { weblate_fill_settings() { - settings="$1" + local settings="$1" ynh_replace_string "__NAME__" "$app" "$settings" ynh_replace_string "__DB_PWD__" "$db_pwd" "$settings" diff --git a/scripts/upgrade b/scripts/upgrade index bf0fdbd..0643508 100755 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -8,8 +8,6 @@ source _common.sh source /usr/share/yunohost/helpers -ynh_abort_if_errors - #================================================= # LOAD SETTINGS #================================================= @@ -42,8 +40,10 @@ key=$(ynh_string_random 50) ) previous_version=$(cat freeze.pip | grep "Weblate==" | sed "s|Weblate==||") -previous_version_file="../conf/settings_history/settings.$previous_version.py" -test -e "$previous_version_file" || ynh_die "Previous version unknown: $previous_version" +ynh_secure_remove freeze.pip + +previous_version_template="../conf/settings_history/settings.$previous_version.py" +test -e "$previous_version_template" || ynh_die "Previous version unknown: $previous_version" #================================================= # ENSURE DOWNWARD COMPATIBILITY @@ -133,6 +133,19 @@ then systemctl stop "uwsgi-app@$app.service" fi +#================================================= +# BACKUP BEFORE UPGRADE THEN ACTIVE TRAP +#================================================= + +# Backup the current version of the app +ynh_backup_before_upgrade +ynh_clean_setup () { + # restore it if the upgrade fails + ynh_restore_upgradebackup +} +# Exit if an error occurs during the execution of the script +ynh_abort_if_errors + #================================================= # CHECK THE PATH #================================================= @@ -194,12 +207,6 @@ fi # PIP INSTALLATION #================================================= -# save old settings file -cp "$settings" "$final_path/settings.$previous_version.old.py" - -old_settings="./settings.$previous_version.old.py" -settings_diff="$final_path/settings.${previous_version}_${current_version}.diff" - ( set +o nounset source "${final_path}/venv/bin/activate" @@ -213,36 +220,44 @@ settings_diff="$final_path/settings.${previous_version}_${current_version}.diff" pip install django_sendmail_backend ) +#================================================= +# CONFIG FILE UPGRADE +#================================================= + +# save old settings file + +old_settings="$final_path/settings.$previous_version.old.py" + +cp "$settings" "$old_settings" + check=$(ynh_check_if_checksum_is_different "$settings") if [[ "$check" -eq 1 ]] then echo "Settings.py was modified localy, running diff before using the new default file for $current_version." # generate previous defaults settings - cp "$previous_version_file" "$old_settings" + cp "$previous_version_template" "$old_settings" weblate_fill_settings "$old_settings" # store diff between defaults and local settings - diff --unified "$old_settings" "$settings" > "$settings_diff" - - # generate new defaults settings - cp "../conf/settings_history/settings.$current_version.py" "$settings" - weblate_fill_settings "$settings" + set +eu + diff --unified "$old_settings" "$settings" > "$final_path/settings.${previous_version}_${current_version}.diff" + set -eu # send diff to the server administrator mail_message=" Weblate was updated from version $previous_version to $current_version - This is a MAJOR upgrade, please read this: - https://docs.weblate.org/en/latest/admin/upgrade.html#upgrade-3 + Please read: + https://docs.weblate.org/en/latest/admin/upgrade.html - A new settings.py has been created in: + A new settings.py has been created: $settings You may have changed your defaults settings. - To help you to apply it again, here is a diff file with every changes you did. + To help you, here is a diff file with every changes you did. Diff has been created in: - $settings_diff + $final_path/settings.${previous_version}_${current_version}.diff Please note secret key is updated, this is normal. @@ -252,11 +267,14 @@ then ynh_send_readme_to_admin "$mail_message" root "$admin_mail" else echo "Settings.py was not modified, using the new default file for $current_version." - # generate new defaults settings - cp "../conf/settings_history/settings.$current_version.py" "$settings" - weblate_fill_settings "$settings" fi +# generate new defaults settings +cp "../conf/settings_history/settings.$current_version.py" "$settings" +weblate_fill_settings "$settings" + +ynh_secure_remove "$old_settings" + #================================================= # Run migration scripts #================================================= From 69b0e9ddd2515a1d56205b0bd7bc771dba4d23c6 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Sun, 2 Sep 2018 14:18:13 +0200 Subject: [PATCH 14/16] ynh_string_random can't go further 24... --- scripts/install | 2 +- scripts/upgrade | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/install b/scripts/install index 91d9338..6d99a0f 100755 --- a/scripts/install +++ b/scripts/install @@ -207,7 +207,7 @@ virtualenv "${final_path}/venv" #================================================= db_pwd=$(ynh_app_setting_get "$app" psqlpwd) admin_mail=$(ynh_user_get_info "$admin" mail) -key=$(ynh_string_random 50) +key=$(ynh_string_random 24)$(ynh_string_random 24)$(ynh_string_random 2) memc_port=$(ynh_find_port 8080) settings="$final_path/venv/lib/python2.7/site-packages/weblate/settings.py" cp "../conf/settings_history/settings.$current_version.py" "$settings" diff --git a/scripts/upgrade b/scripts/upgrade index 0643508..35cda87 100755 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -25,7 +25,7 @@ admin_mail=$(ynh_user_get_info "$admin" mail) memc_port=$(ynh_app_setting_get "$app" memc_port) github_account=$(ynh_app_setting_get "$app" github_account) migration311=$(ynh_app_setting_get "$app" migration311) -key=$(ynh_string_random 50) +key=$(ynh_string_random 24)$(ynh_string_random 24)$(ynh_string_random 2) #================================================= # Get previous version number From a49d61e52eef896d5eddbe6e5ab2129ab707d582 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Mon, 15 Oct 2018 22:30:24 +0200 Subject: [PATCH 15/16] fix ImportError: No module named backports --- manifest.json | 2 +- scripts/install | 2 ++ scripts/upgrade | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 1dfb4d8..c1568b3 100644 --- a/manifest.json +++ b/manifest.json @@ -8,7 +8,7 @@ "description": { "en": "A translation platform using Git and Python" }, - "version": "3.1.1~ynh2", + "version": "3.1.1~ynh3", "url": "https://weblate.org", "license": "AGPL-3.0", "maintainer": { diff --git a/scripts/install b/scripts/install index 6d99a0f..e3a6fce 100755 --- a/scripts/install +++ b/scripts/install @@ -198,6 +198,8 @@ virtualenv "${final_path}/venv" pip install pytz python-bidi PyYaML Babel pyuca pylibravatar pydns psycopg2-binary python-memcached phply # specific to YunoHost package: pip install django_sendmail_backend + # Fix ImportError: No module named backports + pip install backports.csv ) #================================================= diff --git a/scripts/upgrade b/scripts/upgrade index 35cda87..1065456 100755 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -218,6 +218,8 @@ fi pip install pytz python-bidi PyYaML Babel pyuca pylibravatar pydns psycopg2-binary python-memcached phply # specific to YunoHost package: pip install django_sendmail_backend + # Fix ImportError: No module named backports + pip install backports.csv ) #================================================= From 3ed8265e35ae6d48da2bbe4257f20c9c023497fa Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Mon, 15 Oct 2018 22:44:02 +0200 Subject: [PATCH 16/16] Make sure the service is stoped for removing --- scripts/remove | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/remove b/scripts/remove index c377707..841b4ff 100755 --- a/scripts/remove +++ b/scripts/remove @@ -17,6 +17,12 @@ app=$YNH_APP_INSTANCE_NAME domain=$(ynh_app_setting_get "$app" domain) db_name=$(ynh_app_setting_get "$app" db_name) +#================================================= +# STOP WEBLATE'S SERVICE +#================================================= + +systemctl stop "uwsgi-app@$app.service" + #================================================= # REMOVE THE PostgreSQL DATABASE #=================================================