mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
Merge branch 'migrate_to_bullseye' into bullseye
This commit is contained in:
commit
ae08698253
101 changed files with 6459 additions and 2320 deletions
|
@ -18,6 +18,13 @@ invalidcode39:
|
|||
script:
|
||||
- tox -e py39-invalidcode
|
||||
|
||||
mypy:
|
||||
stage: lint
|
||||
image: "before-install"
|
||||
needs: []
|
||||
script:
|
||||
- tox -e py37-mypy
|
||||
|
||||
format-check:
|
||||
stage: lint
|
||||
image: "before-install"
|
||||
|
|
|
@ -71,7 +71,7 @@ test-translation-format-consistency:
|
|||
test-actionmap:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- python3 -m pytest tests tests/test_actionmap.py
|
||||
- python3 -m pytest tests/test_actionmap.py
|
||||
only:
|
||||
changes:
|
||||
- data/actionsmap/*.yml
|
||||
|
@ -85,11 +85,27 @@ test-helpers:
|
|||
changes:
|
||||
- data/helpers.d/*
|
||||
|
||||
test-domains:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- python3 -m pytest src/yunohost/tests/test_domains.py
|
||||
only:
|
||||
changes:
|
||||
- src/yunohost/domain.py
|
||||
|
||||
test-dns:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- python3 -m pytest src/yunohost/tests/test_dns.py
|
||||
only:
|
||||
changes:
|
||||
- src/yunohost/dns.py
|
||||
- src/yunohost/utils/dns.py
|
||||
|
||||
test-apps:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- cd src/yunohost
|
||||
- python3 -m pytest tests/test_apps.py
|
||||
- python3 -m pytest src/yunohost/tests/test_apps.py
|
||||
only:
|
||||
changes:
|
||||
- src/yunohost/app.py
|
||||
|
@ -97,8 +113,7 @@ test-apps:
|
|||
test-appscatalog:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- cd src/yunohost
|
||||
- python3 -m pytest tests/test_appscatalog.py
|
||||
- python3 -m pytest src/yunohost/tests/test_appscatalog.py
|
||||
only:
|
||||
changes:
|
||||
- src/yunohost/app.py
|
||||
|
@ -106,26 +121,32 @@ test-appscatalog:
|
|||
test-appurl:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- cd src/yunohost
|
||||
- python3 -m pytest tests/test_appurl.py
|
||||
- python3 -m pytest src/yunohost/tests/test_appurl.py
|
||||
only:
|
||||
changes:
|
||||
- src/yunohost/app.py
|
||||
|
||||
test-apps-arguments-parsing:
|
||||
test-questions:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- cd src/yunohost
|
||||
- python3 -m pytest tests/test_apps_arguments_parsing.py
|
||||
- python3 -m pytest src/yunohost/tests/test_questions.py
|
||||
only:
|
||||
changes:
|
||||
- src/yunohost/utils/config.py
|
||||
|
||||
test-app-config:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- python3 -m pytest src/yunohost/tests/test_app_config.py
|
||||
only:
|
||||
changes:
|
||||
- src/yunohost/app.py
|
||||
- src/yunohost/utils/config.py
|
||||
|
||||
test-changeurl:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- cd src/yunohost
|
||||
- python3 -m pytest tests/test_changeurl.py
|
||||
- python3 -m pytest src/yunohost/tests/test_changeurl.py
|
||||
only:
|
||||
changes:
|
||||
- src/yunohost/app.py
|
||||
|
@ -133,8 +154,7 @@ test-changeurl:
|
|||
test-backuprestore:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- cd src/yunohost
|
||||
- python3 -m pytest tests/test_backuprestore.py
|
||||
- python3 -m pytest src/yunohost/tests/test_backuprestore.py
|
||||
only:
|
||||
changes:
|
||||
- src/yunohost/backup.py
|
||||
|
@ -142,8 +162,7 @@ test-backuprestore:
|
|||
test-permission:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- cd src/yunohost
|
||||
- python3 -m pytest tests/test_permission.py
|
||||
- python3 -m pytest src/yunohost/tests/test_permission.py
|
||||
only:
|
||||
changes:
|
||||
- src/yunohost/permission.py
|
||||
|
@ -151,8 +170,7 @@ test-permission:
|
|||
test-settings:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- cd src/yunohost
|
||||
- python3 -m pytest tests/test_settings.py
|
||||
- python3 -m pytest src/yunohost/tests/test_settings.py
|
||||
only:
|
||||
changes:
|
||||
- src/yunohost/settings.py
|
||||
|
@ -160,8 +178,7 @@ test-settings:
|
|||
test-user-group:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- cd src/yunohost
|
||||
- python3 -m pytest tests/test_user-group.py
|
||||
- python3 -m pytest src/yunohost/tests/test_user-group.py
|
||||
only:
|
||||
changes:
|
||||
- src/yunohost/user.py
|
||||
|
@ -169,8 +186,7 @@ test-user-group:
|
|||
test-regenconf:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- cd src/yunohost
|
||||
- python3 -m pytest tests/test_regenconf.py
|
||||
- python3 -m pytest src/yunohost/tests/test_regenconf.py
|
||||
only:
|
||||
changes:
|
||||
- src/yunohost/regenconf.py
|
||||
|
@ -178,8 +194,7 @@ test-regenconf:
|
|||
test-service:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- cd src/yunohost
|
||||
- python3 -m pytest tests/test_service.py
|
||||
- python3 -m pytest src/yunohost/tests/test_service.py
|
||||
only:
|
||||
changes:
|
||||
- src/yunohost/service.py
|
||||
|
@ -187,8 +202,7 @@ test-service:
|
|||
test-ldapauth:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- cd src/yunohost
|
||||
- python3 -m pytest tests/test_ldapauth.py
|
||||
- python3 -m pytest src/yunohost/tests/test_ldapauth.py
|
||||
only:
|
||||
changes:
|
||||
- src/yunohost/authenticators/*.py
|
||||
|
|
|
@ -20,7 +20,7 @@ autofix-translated-strings:
|
|||
- python3 reformat_locales.py
|
||||
- '[ $(git diff -w | wc -l) != 0 ] || exit 0' # stop if there is nothing to commit
|
||||
- git commit -am "[CI] Reformat / remove stale translated strings" || true
|
||||
- git push -f origin "ci-remove-stale-translated-strings-${CI_COMMIT_REF_NAME}":"ci-remove-stale-translated-strings-${CI_COMMIT_REF_NAME}"
|
||||
- git push -f origin "HEAD":"ci-remove-stale-translated-strings-${CI_COMMIT_REF_NAME}"
|
||||
- hub pull-request -m "[CI] Reformat / remove stale translated strings" -b Yunohost:dev -p || true # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
|
||||
only:
|
||||
variables:
|
||||
|
|
|
@ -476,21 +476,17 @@ domain:
|
|||
help: Do not ask confirmation to remove apps
|
||||
action: store_true
|
||||
|
||||
|
||||
### domain_dns_conf()
|
||||
dns-conf:
|
||||
deprecated: true
|
||||
action_help: Generate sample DNS configuration for a domain
|
||||
api: GET /domains/<domain>/dns
|
||||
arguments:
|
||||
domain:
|
||||
help: Target domain
|
||||
-t:
|
||||
full: --ttl
|
||||
help: Time To Live (TTL) in second before DNS servers update. Default is 3600 seconds (i.e. 1 hour).
|
||||
extra:
|
||||
pattern:
|
||||
- !!str ^[0-9]+$
|
||||
- "pattern_positive_number"
|
||||
|
||||
pattern: *pattern_domain
|
||||
|
||||
### domain_maindomain()
|
||||
main-domain:
|
||||
action_help: Check the current main domain, or change it
|
||||
|
@ -508,8 +504,8 @@ domain:
|
|||
|
||||
### certificate_status()
|
||||
cert-status:
|
||||
deprecated: true
|
||||
action_help: List status of current certificates (all by default).
|
||||
api: GET /domains/<domain_list>/cert
|
||||
arguments:
|
||||
domain_list:
|
||||
help: Domains to check
|
||||
|
@ -520,8 +516,8 @@ domain:
|
|||
|
||||
### certificate_install()
|
||||
cert-install:
|
||||
deprecated: true
|
||||
action_help: Install Let's Encrypt certificates for given domains (all by default).
|
||||
api: PUT /domains/<domain_list>/cert
|
||||
arguments:
|
||||
domain_list:
|
||||
help: Domains for which to install the certificates
|
||||
|
@ -541,8 +537,8 @@ domain:
|
|||
|
||||
### certificate_renew()
|
||||
cert-renew:
|
||||
deprecated: true
|
||||
action_help: Renew the Let's Encrypt certificates for given domains (all by default).
|
||||
api: PUT /domains/<domain_list>/cert/renew
|
||||
arguments:
|
||||
domain_list:
|
||||
help: Domains for which to renew the certificates
|
||||
|
@ -572,6 +568,141 @@ domain:
|
|||
path:
|
||||
help: The path to check (e.g. /coffee)
|
||||
|
||||
subcategories:
|
||||
|
||||
config:
|
||||
subcategory_help: Domain settings
|
||||
actions:
|
||||
|
||||
### domain_config_get()
|
||||
get:
|
||||
action_help: Display a domain configuration
|
||||
api: GET /domains/<domain>/config
|
||||
arguments:
|
||||
domain:
|
||||
help: Domain name
|
||||
key:
|
||||
help: A specific panel, section or a question identifier
|
||||
nargs: '?'
|
||||
-f:
|
||||
full: --full
|
||||
help: Display all details (meant to be used by the API)
|
||||
action: store_true
|
||||
-e:
|
||||
full: --export
|
||||
help: Only export key/values, meant to be reimported using "config set --args-file"
|
||||
action: store_true
|
||||
|
||||
### domain_config_set()
|
||||
set:
|
||||
action_help: Apply a new configuration
|
||||
api: PUT /domains/<domain>/config
|
||||
arguments:
|
||||
domain:
|
||||
help: Domain name
|
||||
key:
|
||||
help: The question or form key
|
||||
nargs: '?'
|
||||
-v:
|
||||
full: --value
|
||||
help: new value
|
||||
-a:
|
||||
full: --args
|
||||
help: Serialized arguments for new configuration (i.e. "mail_in=0&mail_out=0")
|
||||
|
||||
dns:
|
||||
subcategory_help: Manage domains DNS
|
||||
actions:
|
||||
### domain_dns_conf()
|
||||
suggest:
|
||||
action_help: Generate sample DNS configuration for a domain
|
||||
api:
|
||||
- GET /domains/<domain>/dns
|
||||
- GET /domains/<domain>/dns/suggest
|
||||
arguments:
|
||||
domain:
|
||||
help: Target domain
|
||||
extra:
|
||||
pattern: *pattern_domain
|
||||
|
||||
### domain_dns_push()
|
||||
push:
|
||||
action_help: Push DNS records to registrar
|
||||
api: POST /domains/<domain>/dns/push
|
||||
arguments:
|
||||
domain:
|
||||
help: Domain name to push DNS conf for
|
||||
extra:
|
||||
pattern: *pattern_domain
|
||||
-d:
|
||||
full: --dry-run
|
||||
help: Only display what's to be pushed
|
||||
action: store_true
|
||||
--force:
|
||||
help: Also update/remove records which were not originally set by Yunohost, or which have been manually modified
|
||||
action: store_true
|
||||
--purge:
|
||||
help: Delete all records
|
||||
action: store_true
|
||||
|
||||
cert:
|
||||
subcategory_help: Manage domain certificates
|
||||
actions:
|
||||
### certificate_status()
|
||||
status:
|
||||
action_help: List status of current certificates (all by default).
|
||||
api: GET /domains/<domain_list>/cert
|
||||
arguments:
|
||||
domain_list:
|
||||
help: Domains to check
|
||||
nargs: "*"
|
||||
--full:
|
||||
help: Show more details
|
||||
action: store_true
|
||||
|
||||
### certificate_install()
|
||||
install:
|
||||
action_help: Install Let's Encrypt certificates for given domains (all by default).
|
||||
api: PUT /domains/<domain_list>/cert
|
||||
arguments:
|
||||
domain_list:
|
||||
help: Domains for which to install the certificates
|
||||
nargs: "*"
|
||||
--force:
|
||||
help: Install even if current certificate is not self-signed
|
||||
action: store_true
|
||||
--no-checks:
|
||||
help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to install. (Not recommended)
|
||||
action: store_true
|
||||
--self-signed:
|
||||
help: Install self-signed certificate instead of Let's Encrypt
|
||||
action: store_true
|
||||
--staging:
|
||||
help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure.
|
||||
action: store_true
|
||||
|
||||
### certificate_renew()
|
||||
renew:
|
||||
action_help: Renew the Let's Encrypt certificates for given domains (all by default).
|
||||
api: PUT /domains/<domain_list>/cert/renew
|
||||
arguments:
|
||||
domain_list:
|
||||
help: Domains for which to renew the certificates
|
||||
nargs: "*"
|
||||
--force:
|
||||
help: Ignore the validity threshold (30 days)
|
||||
action: store_true
|
||||
--email:
|
||||
help: Send an email to root with logs if some renewing fails
|
||||
action: store_true
|
||||
--no-checks:
|
||||
help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to renew. (Not recommended)
|
||||
action: store_true
|
||||
--staging:
|
||||
help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure.
|
||||
action: store_true
|
||||
|
||||
|
||||
#############################
|
||||
# App #
|
||||
#############################
|
||||
|
@ -811,24 +942,45 @@ app:
|
|||
subcategory_help: Applications configuration panel
|
||||
actions:
|
||||
|
||||
### app_config_show_panel()
|
||||
show-panel:
|
||||
action_help: show config panel for the application
|
||||
### app_config_get()
|
||||
get:
|
||||
action_help: Display an app configuration
|
||||
api: GET /apps/<app>/config-panel
|
||||
arguments:
|
||||
app:
|
||||
help: App name
|
||||
app:
|
||||
help: App name
|
||||
key:
|
||||
help: A specific panel, section or a question identifier
|
||||
nargs: '?'
|
||||
-f:
|
||||
full: --full
|
||||
help: Display all details (meant to be used by the API)
|
||||
action: store_true
|
||||
-e:
|
||||
full: --export
|
||||
help: Only export key/values, meant to be reimported using "config set --args-file"
|
||||
action: store_true
|
||||
|
||||
### app_config_apply()
|
||||
apply:
|
||||
action_help: apply the new configuration
|
||||
### app_config_set()
|
||||
set:
|
||||
action_help: Apply a new configuration
|
||||
api: PUT /apps/<app>/config
|
||||
arguments:
|
||||
app:
|
||||
help: App name
|
||||
-a:
|
||||
full: --args
|
||||
help: Serialized arguments for new configuration (i.e. "domain=domain.tld&path=/path")
|
||||
app:
|
||||
help: App name
|
||||
key:
|
||||
help: The question or panel key
|
||||
nargs: '?'
|
||||
-v:
|
||||
full: --value
|
||||
help: new value
|
||||
-a:
|
||||
full: --args
|
||||
help: Serialized arguments for new configuration (i.e. "domain=domain.tld&path=/path")
|
||||
-f:
|
||||
full: --args-file
|
||||
help: YAML or JSON file with key/value couples
|
||||
type: open
|
||||
|
||||
#############################
|
||||
# Backup #
|
||||
|
|
|
@ -13,6 +13,7 @@ import yaml
|
|||
|
||||
THIS_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
ACTIONSMAP_FILE = THIS_SCRIPT_DIR + "/yunohost.yml"
|
||||
os.system(f"mkdir {THIS_SCRIPT_DIR}/../bash-completion.d")
|
||||
BASH_COMPLETION_FILE = THIS_SCRIPT_DIR + "/../bash-completion.d/yunohost"
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
# This file is automatically generated
|
||||
# during Debian's package build by the script
|
||||
# data/actionsmap/yunohost_completion.py
|
|
@ -313,12 +313,25 @@ ynh_restore_file () {
|
|||
ynh_store_file_checksum () {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=f
|
||||
local -A args_array=( [f]=file= )
|
||||
local -A args_array=( [f]=file= [u]=update_only )
|
||||
local file
|
||||
local update_only
|
||||
update_only="${update_only:-0}"
|
||||
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_'
|
||||
|
||||
# If update only, we don't save the new checksum if no old checksum exist
|
||||
if [ $update_only -eq 1 ] ; then
|
||||
local checksum_value=$(ynh_app_setting_get --app=$app --key=$checksum_setting_name)
|
||||
if [ -z "${checksum_value}" ] ; then
|
||||
unset backup_file_checksum
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
ynh_app_setting_set --app=$app --key=$checksum_setting_name --value=$(md5sum "$file" | cut --delimiter=' ' --fields=1)
|
||||
|
||||
# If backup_file_checksum isn't empty, ynh_backup_if_checksum_is_different has made a backup
|
||||
|
|
328
data/helpers.d/config
Normal file
328
data/helpers.d/config
Normal file
|
@ -0,0 +1,328 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
_ynh_app_config_get() {
|
||||
# From settings
|
||||
local lines
|
||||
lines=$(python3 << EOL
|
||||
import toml
|
||||
from collections import OrderedDict
|
||||
with open("../config_panel.toml", "r") as f:
|
||||
file_content = f.read()
|
||||
loaded_toml = toml.loads(file_content, _dict=OrderedDict)
|
||||
|
||||
for panel_name, panel in loaded_toml.items():
|
||||
if not isinstance(panel, dict): continue
|
||||
for section_name, section in panel.items():
|
||||
if not isinstance(section, dict): continue
|
||||
for name, param in section.items():
|
||||
if not isinstance(param, dict):
|
||||
continue
|
||||
print(';'.join([
|
||||
name,
|
||||
param.get('type', 'string'),
|
||||
param.get('bind', 'settings' if param.get('type', 'string') != 'file' else 'null')
|
||||
]))
|
||||
EOL
|
||||
)
|
||||
for line in $lines
|
||||
do
|
||||
# Split line into short_setting, type and bind
|
||||
IFS=';' read short_setting type bind <<< "$line"
|
||||
local getter="get__${short_setting}"
|
||||
binds[${short_setting}]="$bind"
|
||||
types[${short_setting}]="$type"
|
||||
file_hash[${short_setting}]=""
|
||||
formats[${short_setting}]=""
|
||||
# Get value from getter if exists
|
||||
if type -t $getter 2>/dev/null | grep -q '^function$' 2>/dev/null;
|
||||
then
|
||||
old[$short_setting]="$($getter)"
|
||||
formats[${short_setting}]="yaml"
|
||||
|
||||
elif [[ "$bind" == "null" ]]
|
||||
then
|
||||
old[$short_setting]="YNH_NULL"
|
||||
|
||||
# Get value from app settings or from another file
|
||||
elif [[ "$type" == "file" ]]
|
||||
then
|
||||
if [[ "$bind" == "settings" ]]
|
||||
then
|
||||
ynh_die --message="File '${short_setting}' can't be stored in settings"
|
||||
fi
|
||||
old[$short_setting]="$(ls "$(echo $bind | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)" 2> /dev/null || echo YNH_NULL)"
|
||||
file_hash[$short_setting]="true"
|
||||
|
||||
# Get multiline text from settings or from a full file
|
||||
elif [[ "$type" == "text" ]]
|
||||
then
|
||||
if [[ "$bind" == "settings" ]]
|
||||
then
|
||||
old[$short_setting]="$(ynh_app_setting_get $app $short_setting)"
|
||||
elif [[ "$bind" == *":"* ]]
|
||||
then
|
||||
ynh_die --message="For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter"
|
||||
else
|
||||
old[$short_setting]="$(cat $(echo $bind | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/) 2> /dev/null || echo YNH_NULL)"
|
||||
fi
|
||||
|
||||
# Get value from a kind of key/value file
|
||||
else
|
||||
local bind_after=""
|
||||
if [[ "$bind" == "settings" ]]
|
||||
then
|
||||
bind=":/etc/yunohost/apps/$app/settings.yml"
|
||||
fi
|
||||
local bind_key="$(echo "$bind" | cut -d: -f1)"
|
||||
bind_key=${bind_key:-$short_setting}
|
||||
if [[ "$bind_key" == *">"* ]];
|
||||
then
|
||||
bind_after="$(echo "${bind_key}" | cut -d'>' -f1)"
|
||||
bind_key="$(echo "${bind_key}" | cut -d'>' -f2)"
|
||||
fi
|
||||
local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
||||
old[$short_setting]="$(ynh_read_var_in_file --file="${bind_file}" --key="${bind_key}" --after="${bind_after}")"
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
}
|
||||
|
||||
_ynh_app_config_apply() {
|
||||
for short_setting in "${!old[@]}"
|
||||
do
|
||||
local setter="set__${short_setting}"
|
||||
local bind="${binds[$short_setting]}"
|
||||
local type="${types[$short_setting]}"
|
||||
if [ "${changed[$short_setting]}" == "true" ]
|
||||
then
|
||||
# Apply setter if exists
|
||||
if type -t $setter 2>/dev/null | grep -q '^function$' 2>/dev/null;
|
||||
then
|
||||
$setter
|
||||
|
||||
elif [[ "$bind" == "null" ]]
|
||||
then
|
||||
continue
|
||||
|
||||
# Save in a file
|
||||
elif [[ "$type" == "file" ]]
|
||||
then
|
||||
if [[ "$bind" == "settings" ]]
|
||||
then
|
||||
ynh_die --message="File '${short_setting}' can't be stored in settings"
|
||||
fi
|
||||
local bind_file="$(echo "$bind" | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
||||
if [[ "${!short_setting}" == "" ]]
|
||||
then
|
||||
ynh_backup_if_checksum_is_different --file="$bind_file"
|
||||
ynh_secure_remove --file="$bind_file"
|
||||
ynh_delete_file_checksum --file="$bind_file" --update_only
|
||||
ynh_print_info --message="File '$bind_file' removed"
|
||||
else
|
||||
ynh_backup_if_checksum_is_different --file="$bind_file"
|
||||
if [[ "${!short_setting}" != "$bind_file" ]]
|
||||
then
|
||||
cp "${!short_setting}" "$bind_file"
|
||||
fi
|
||||
ynh_store_file_checksum --file="$bind_file" --update_only
|
||||
ynh_print_info --message="File '$bind_file' overwrited with ${!short_setting}"
|
||||
fi
|
||||
|
||||
# Save value in app settings
|
||||
elif [[ "$bind" == "settings" ]]
|
||||
then
|
||||
ynh_app_setting_set --app=$app --key=$short_setting --value="${!short_setting}"
|
||||
ynh_print_info --message="Configuration key '$short_setting' edited in app settings"
|
||||
|
||||
# Save multiline text in a file
|
||||
elif [[ "$type" == "text" ]]
|
||||
then
|
||||
if [[ "$bind" == *":"* ]]
|
||||
then
|
||||
ynh_die --message="For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter"
|
||||
fi
|
||||
local bind_file="$(echo "$bind" | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
||||
ynh_backup_if_checksum_is_different --file="$bind_file"
|
||||
echo "${!short_setting}" > "$bind_file"
|
||||
ynh_store_file_checksum --file="$bind_file" --update_only
|
||||
ynh_print_info --message="File '$bind_file' overwrited with the content you provieded in '${short_setting}' question"
|
||||
|
||||
# Set value into a kind of key/value file
|
||||
else
|
||||
local bind_after=""
|
||||
local bind_key="$(echo "$bind" | cut -d: -f1)"
|
||||
bind_key=${bind_key:-$short_setting}
|
||||
if [[ "$bind_key" == *">"* ]];
|
||||
then
|
||||
bind_after="$(echo "${bind_key}" | cut -d'>' -f1)"
|
||||
bind_key="$(echo "${bind_key}" | cut -d'>' -f2)"
|
||||
fi
|
||||
local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
||||
|
||||
ynh_backup_if_checksum_is_different --file="$bind_file"
|
||||
ynh_write_var_in_file --file="${bind_file}" --key="${bind_key}" --value="${!short_setting}" --after="${bind_after}"
|
||||
ynh_store_file_checksum --file="$bind_file" --update_only
|
||||
|
||||
# We stored the info in settings in order to be able to upgrade the app
|
||||
ynh_app_setting_set --app=$app --key=$short_setting --value="${!short_setting}"
|
||||
ynh_print_info --message="Configuration key '$bind_key' edited into $bind_file"
|
||||
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
_ynh_app_config_show() {
|
||||
for short_setting in "${!old[@]}"
|
||||
do
|
||||
if [[ "${old[$short_setting]}" != YNH_NULL ]]
|
||||
then
|
||||
if [[ "${formats[$short_setting]}" == "yaml" ]]
|
||||
then
|
||||
ynh_return "${short_setting}:"
|
||||
ynh_return "$(echo "${old[$short_setting]}" | sed 's/^/ /g')"
|
||||
else
|
||||
ynh_return "${short_setting}: "'"'"$(echo "${old[$short_setting]}" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\n\n/g')"'"'
|
||||
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
_ynh_app_config_validate() {
|
||||
# Change detection
|
||||
ynh_script_progression --message="Checking what changed in the new configuration..." --weight=1
|
||||
local nothing_changed=true
|
||||
local changes_validated=true
|
||||
for short_setting in "${!old[@]}"
|
||||
do
|
||||
changed[$short_setting]=false
|
||||
if [ -z ${!short_setting+x} ]
|
||||
then
|
||||
# Assign the var with the old value in order to allows multiple
|
||||
# args validation
|
||||
declare "$short_setting"="${old[$short_setting]}"
|
||||
continue
|
||||
fi
|
||||
if [ ! -z "${file_hash[${short_setting}]}" ]
|
||||
then
|
||||
file_hash[old__$short_setting]=""
|
||||
file_hash[new__$short_setting]=""
|
||||
if [ -f "${old[$short_setting]}" ]
|
||||
then
|
||||
file_hash[old__$short_setting]=$(sha256sum "${old[$short_setting]}" | cut -d' ' -f1)
|
||||
if [ -z "${!short_setting}" ]
|
||||
then
|
||||
changed[$short_setting]=true
|
||||
nothing_changed=false
|
||||
fi
|
||||
fi
|
||||
if [ -f "${!short_setting}" ]
|
||||
then
|
||||
file_hash[new__$short_setting]=$(sha256sum "${!short_setting}" | cut -d' ' -f1)
|
||||
if [[ "${file_hash[old__$short_setting]}" != "${file_hash[new__$short_setting]}" ]]
|
||||
then
|
||||
changed[$short_setting]=true
|
||||
nothing_changed=false
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [[ "${!short_setting}" != "${old[$short_setting]}" ]]
|
||||
then
|
||||
changed[$short_setting]=true
|
||||
nothing_changed=false
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [[ "$nothing_changed" == "true" ]]
|
||||
then
|
||||
ynh_print_info --message="Nothing has changed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Run validation if something is changed
|
||||
ynh_script_progression --message="Validating the new configuration..." --weight=1
|
||||
|
||||
for short_setting in "${!old[@]}"
|
||||
do
|
||||
[[ "${changed[$short_setting]}" == "false" ]] && continue
|
||||
local result=""
|
||||
if type -t validate__$short_setting | grep -q '^function$' 2>/dev/null;
|
||||
then
|
||||
result="$(validate__$short_setting)"
|
||||
fi
|
||||
if [ -n "$result" ]
|
||||
then
|
||||
#
|
||||
# Return a yaml such as:
|
||||
#
|
||||
# validation_errors:
|
||||
# some_key: "An error message"
|
||||
# some_other_key: "Another error message"
|
||||
#
|
||||
# We use changes_validated to know if this is
|
||||
# the first validation error
|
||||
if [[ "$changes_validated" == true ]]
|
||||
then
|
||||
ynh_return "validation_errors:"
|
||||
fi
|
||||
ynh_return " ${short_setting}: \"$result\""
|
||||
changes_validated=false
|
||||
fi
|
||||
done
|
||||
|
||||
# If validation failed, exit the script right now (instead of going into apply)
|
||||
# Yunohost core will pick up the errors returned via ynh_return previously
|
||||
if [[ "$changes_validated" == "false" ]]
|
||||
then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
ynh_app_config_get() {
|
||||
_ynh_app_config_get
|
||||
}
|
||||
|
||||
ynh_app_config_show() {
|
||||
_ynh_app_config_show
|
||||
}
|
||||
|
||||
ynh_app_config_validate() {
|
||||
_ynh_app_config_validate
|
||||
}
|
||||
|
||||
ynh_app_config_apply() {
|
||||
_ynh_app_config_apply
|
||||
}
|
||||
|
||||
ynh_app_config_run() {
|
||||
declare -Ag old=()
|
||||
declare -Ag changed=()
|
||||
declare -Ag file_hash=()
|
||||
declare -Ag binds=()
|
||||
declare -Ag types=()
|
||||
declare -Ag formats=()
|
||||
|
||||
case $1 in
|
||||
show)
|
||||
ynh_app_config_get
|
||||
ynh_app_config_show
|
||||
;;
|
||||
apply)
|
||||
max_progression=4
|
||||
ynh_script_progression --message="Reading config panel description and current configuration..."
|
||||
ynh_app_config_get
|
||||
|
||||
ynh_app_config_validate
|
||||
|
||||
ynh_script_progression --message="Applying the new configuration..."
|
||||
ynh_app_config_apply
|
||||
ynh_script_progression --message="Configuration of $app completed" --last
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
|
@ -43,12 +43,14 @@ ynh_replace_string () {
|
|||
local target_file
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
set +o xtrace # set +x
|
||||
|
||||
local delimit=@
|
||||
# Escape the delimiter if it's in the string.
|
||||
match_string=${match_string//${delimit}/"\\${delimit}"}
|
||||
replace_string=${replace_string//${delimit}/"\\${delimit}"}
|
||||
|
||||
set -o xtrace # set -x
|
||||
sed --in-place "s${delimit}${match_string}${delimit}${replace_string}${delimit}g" "$target_file"
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
YNH_APP_BASEDIR=$(realpath $([[ "$(basename $0)" =~ ^backup|restore$ ]] && echo '../settings' || echo '..'))
|
||||
YNH_APP_BASEDIR=${YNH_APP_BASEDIR:-$(realpath ..)}
|
||||
|
||||
# Handle script crashes / failures
|
||||
#
|
||||
|
@ -473,6 +473,207 @@ ynh_replace_vars () {
|
|||
done
|
||||
}
|
||||
|
||||
# Get a value from heterogeneous file (yaml, json, php, python...)
|
||||
#
|
||||
# usage: ynh_read_var_in_file --file=PATH --key=KEY
|
||||
# | arg: -f, --file= - the path to the file
|
||||
# | arg: -k, --key= - the key to get
|
||||
#
|
||||
# This helpers match several var affectation use case in several languages
|
||||
# We don't use jq or equivalent to keep comments and blank space in files
|
||||
# This helpers work line by line, it is not able to work correctly
|
||||
# if you have several identical keys in your files
|
||||
#
|
||||
# Example of line this helpers can managed correctly
|
||||
# .yml
|
||||
# title: YunoHost documentation
|
||||
# email: 'yunohost@yunohost.org'
|
||||
# .json
|
||||
# "theme": "colib'ris",
|
||||
# "port": 8102
|
||||
# "some_boolean": false,
|
||||
# "user": null
|
||||
# .ini
|
||||
# some_boolean = On
|
||||
# action = "Clear"
|
||||
# port = 20
|
||||
# .php
|
||||
# $user=
|
||||
# user => 20
|
||||
# .py
|
||||
# USER = 8102
|
||||
# user = 'https://donate.local'
|
||||
# CUSTOM['user'] = 'YunoHost'
|
||||
#
|
||||
# Requires YunoHost version 4.3 or higher.
|
||||
ynh_read_var_in_file() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=fka
|
||||
local -A args_array=( [f]=file= [k]=key= [a]=after=)
|
||||
local file
|
||||
local key
|
||||
local after
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
after="${after:-}"
|
||||
|
||||
[[ -f $file ]] || ynh_die --message="File $file does not exists"
|
||||
|
||||
set +o xtrace # set +x
|
||||
|
||||
# Get the line number after which we search for the variable
|
||||
local line_number=1
|
||||
if [[ -n "$after" ]];
|
||||
then
|
||||
line_number=$(grep -n $after $file | cut -d: -f1)
|
||||
if [[ -z "$line_number" ]];
|
||||
then
|
||||
set -o xtrace # set -x
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
local filename="$(basename -- "$file")"
|
||||
local ext="${filename##*.}"
|
||||
local endline=',;'
|
||||
local assign="=>|:|="
|
||||
local comments="#"
|
||||
local string="\"'"
|
||||
if [[ "$ext" =~ ^ini|env|toml|yml|yaml$ ]]; then
|
||||
endline='#'
|
||||
fi
|
||||
if [[ "$ext" =~ ^ini|env$ ]]; then
|
||||
comments="[;#]"
|
||||
fi
|
||||
if [[ "php" == "$ext" ]] || [[ "$ext" == "js" ]]; then
|
||||
comments="//"
|
||||
fi
|
||||
local list='\[\s*['$string']?\w+['$string']?\]'
|
||||
local var_part='^\s*((const|var|let)\s+)?\$?(\w+('$list')*(->|\.|\[))*\s*'
|
||||
var_part+="[$string]?${key}[$string]?"
|
||||
var_part+='\s*\]?\s*'
|
||||
var_part+="($assign)"
|
||||
var_part+='\s*'
|
||||
|
||||
# Extract the part after assignation sign
|
||||
local expression_with_comment="$(tail +$line_number ${file} | grep -i -o -P $var_part'\K.*$' || echo YNH_NULL | head -n1)"
|
||||
if [[ "$expression_with_comment" == "YNH_NULL" ]]; then
|
||||
set -o xtrace # set -x
|
||||
echo YNH_NULL
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Remove comments if needed
|
||||
local expression="$(echo "$expression_with_comment" | sed "s@$comments[^$string]*\$@@g" | sed "s@\s*[$endline]*\s*]*\$@@")"
|
||||
|
||||
local first_char="${expression:0:1}"
|
||||
if [[ "$first_char" == '"' ]] ; then
|
||||
echo "$expression" | grep -m1 -o -P '"\K([^"](\\")?)*[^\\](?=")' | head -n1 | sed 's/\\"/"/g'
|
||||
elif [[ "$first_char" == "'" ]] ; then
|
||||
echo "$expression" | grep -m1 -o -P "'\K([^'](\\\\')?)*[^\\\\](?=')" | head -n1 | sed "s/\\\\'/'/g"
|
||||
else
|
||||
echo "$expression"
|
||||
fi
|
||||
set -o xtrace # set -x
|
||||
}
|
||||
|
||||
# Set a value into heterogeneous file (yaml, json, php, python...)
|
||||
#
|
||||
# usage: ynh_write_var_in_file --file=PATH --key=KEY --value=VALUE
|
||||
# | arg: -f, --file= - the path to the file
|
||||
# | arg: -k, --key= - the key to set
|
||||
# | arg: -v, --value= - the value to set
|
||||
#
|
||||
# Requires YunoHost version 4.3 or higher.
|
||||
ynh_write_var_in_file() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=fkva
|
||||
local -A args_array=( [f]=file= [k]=key= [v]=value= [a]=after=)
|
||||
local file
|
||||
local key
|
||||
local value
|
||||
local after
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
after="${after:-}"
|
||||
|
||||
[[ -f $file ]] || ynh_die --message="File $file does not exists"
|
||||
|
||||
set +o xtrace # set +x
|
||||
|
||||
# Get the line number after which we search for the variable
|
||||
local line_number=1
|
||||
if [[ -n "$after" ]];
|
||||
then
|
||||
line_number=$(grep -n $after $file | cut -d: -f1)
|
||||
if [[ -z "$line_number" ]];
|
||||
then
|
||||
set -o xtrace # set -x
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
local range="${line_number},\$ "
|
||||
|
||||
local filename="$(basename -- "$file")"
|
||||
local ext="${filename##*.}"
|
||||
local endline=',;'
|
||||
local assign="=>|:|="
|
||||
local comments="#"
|
||||
local string="\"'"
|
||||
if [[ "$ext" =~ ^ini|env|toml|yml|yaml$ ]]; then
|
||||
endline='#'
|
||||
fi
|
||||
if [[ "$ext" =~ ^ini|env$ ]]; then
|
||||
comments="[;#]"
|
||||
fi
|
||||
if [[ "php" == "$ext" ]] || [[ "$ext" == "js" ]]; then
|
||||
comments="//"
|
||||
fi
|
||||
local list='\[\s*['$string']?\w+['$string']?\]'
|
||||
local var_part='^\s*((const|var|let)\s+)?\$?(\w+('$list')*(->|\.|\[))*\s*'
|
||||
var_part+="[$string]?${key}[$string]?"
|
||||
var_part+='\s*\]?\s*'
|
||||
var_part+="($assign)"
|
||||
var_part+='\s*'
|
||||
|
||||
# Extract the part after assignation sign
|
||||
local expression_with_comment="$(tail +$line_number ${file} | grep -i -o -P $var_part'\K.*$' || echo YNH_NULL | head -n1)"
|
||||
if [[ "$expression_with_comment" == "YNH_NULL" ]]; then
|
||||
set -o xtrace # set -x
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Remove comments if needed
|
||||
local expression="$(echo "$expression_with_comment" | sed "s@$comments[^$string]*\$@@g" | sed "s@\s*[$endline]*\s*]*\$@@")"
|
||||
endline=${expression_with_comment#"$expression"}
|
||||
endline="$(echo "$endline" | sed 's/\\/\\\\/g')"
|
||||
value="$(echo "$value" | sed 's/\\/\\\\/g')"
|
||||
local first_char="${expression:0:1}"
|
||||
delimiter=$'\001'
|
||||
if [[ "$first_char" == '"' ]] ; then
|
||||
# \ and sed is quite complex you need 2 \\ to get one in a sed
|
||||
# So we need \\\\ to go through 2 sed
|
||||
value="$(echo "$value" | sed 's/"/\\\\"/g')"
|
||||
sed -ri "${range}s$delimiter"'(^'"${var_part}"'")([^"]|\\")*("[\s;,]*)(\s*'$comments'.*)?$'$delimiter'\1'"${value}"'"'"${endline}${delimiter}i" ${file}
|
||||
elif [[ "$first_char" == "'" ]] ; then
|
||||
# \ and sed is quite complex you need 2 \\ to get one in a sed
|
||||
# However double quotes implies to double \\ to
|
||||
# So we need \\\\\\\\ to go through 2 sed and 1 double quotes str
|
||||
value="$(echo "$value" | sed "s/'/\\\\\\\\'/g")"
|
||||
sed -ri "${range}s$delimiter(^${var_part}')([^']|\\')*('"'[\s,;]*)(\s*'$comments'.*)?$'$delimiter'\1'"${value}'${endline}${delimiter}i" ${file}
|
||||
else
|
||||
if [[ "$value" == *"'"* ]] || [[ "$value" == *'"'* ]] || [[ "$ext" =~ ^php|py|json|js$ ]] ; then
|
||||
value='\"'"$(echo "$value" | sed 's/"/\\\\"/g')"'\"'
|
||||
fi
|
||||
if [[ "$ext" =~ ^yaml|yml$ ]] ; then
|
||||
value=" $value"
|
||||
fi
|
||||
sed -ri "${range}s$delimiter(^${var_part}).*\$$delimiter\1${value}${endline}${delimiter}i" ${file}
|
||||
fi
|
||||
set -o xtrace # set -x
|
||||
}
|
||||
|
||||
|
||||
# Render templates with Jinja2
|
||||
#
|
||||
# [internal]
|
||||
|
@ -516,6 +717,7 @@ ynh_secure_remove () {
|
|||
local file
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
set +o xtrace # set +x
|
||||
|
||||
local forbidden_path=" \
|
||||
/var/www \
|
||||
|
@ -543,6 +745,8 @@ ynh_secure_remove () {
|
|||
else
|
||||
ynh_print_info --message="'$file' wasn't deleted because it doesn't exist."
|
||||
fi
|
||||
|
||||
set -o xtrace # set -x
|
||||
}
|
||||
|
||||
# Read the value of a key in a ynh manifest file
|
||||
|
|
17
data/hooks/backup/18-data_multimedia
Normal file
17
data/hooks/backup/18-data_multimedia
Normal file
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Exit hook on subcommand error or unset variable
|
||||
set -eu
|
||||
|
||||
# Source YNH helpers
|
||||
source /usr/share/yunohost/helpers
|
||||
|
||||
# Backup destination
|
||||
backup_dir="${1}/data/multimedia"
|
||||
|
||||
if [ -e "/home/yunohost.multimedia/.nobackup" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Backup multimedia directory
|
||||
ynh_backup --src_path="/home/yunohost.multimedia" --dest_path="${backup_dir}" --is_big --not_mandatory
|
|
@ -12,6 +12,7 @@ backup_dir="${1}/conf/ynh"
|
|||
# Backup the configuration
|
||||
ynh_backup "/etc/yunohost/firewall.yml" "${backup_dir}/firewall.yml"
|
||||
ynh_backup "/etc/yunohost/current_host" "${backup_dir}/current_host"
|
||||
ynh_backup "/etc/yunohost/domains" "${backup_dir}/domains"
|
||||
[ ! -e "/etc/yunohost/settings.json" ] || ynh_backup "/etc/yunohost/settings.json" "${backup_dir}/settings.json"
|
||||
[ ! -d "/etc/yunohost/dyndns" ] || ynh_backup "/etc/yunohost/dyndns" "${backup_dir}/dyndns"
|
||||
[ ! -d "/etc/dkim" ] || ynh_backup "/etc/dkim" "${backup_dir}/dkim"
|
||||
|
|
|
@ -12,7 +12,7 @@ ynh_backup --src_path="./manually_modified_files_list"
|
|||
|
||||
for file in $(cat ./manually_modified_files_list)
|
||||
do
|
||||
ynh_backup --src_path="$file"
|
||||
[[ -e $file ]] && ynh_backup --src_path="$file"
|
||||
done
|
||||
|
||||
ynh_backup --src_path="/etc/ssowat/conf.json.persistent"
|
||||
|
|
|
@ -35,6 +35,10 @@ do_init_regen() {
|
|||
mkdir -p /home/yunohost.app
|
||||
chmod 755 /home/yunohost.app
|
||||
|
||||
# Domain settings
|
||||
mkdir -p /etc/yunohost/domains
|
||||
chmod 700 /etc/yunohost/domains
|
||||
|
||||
# Backup folders
|
||||
mkdir -p /home/yunohost.backup/archives
|
||||
chmod 750 /home/yunohost.backup/archives
|
||||
|
@ -51,6 +55,15 @@ do_init_regen() {
|
|||
mkdir -p /var/cache/yunohost/repo
|
||||
chown root:root /var/cache/yunohost
|
||||
chmod 700 /var/cache/yunohost
|
||||
|
||||
cp yunoprompt.service /etc/systemd/system/yunoprompt.service
|
||||
cp dpkg-origins /etc/dpkg/origins/yunohost
|
||||
|
||||
# Change dpkg vendor
|
||||
# see https://wiki.debian.org/Derivatives/Guidelines#Vendor
|
||||
readlink -f /etc/dpkg/origins/default | grep -q debian \
|
||||
&& rm -f /etc/dpkg/origins/default \
|
||||
&& ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
|
||||
}
|
||||
|
||||
do_pre_regen() {
|
||||
|
@ -62,6 +75,7 @@ do_pre_regen() {
|
|||
touch /etc/yunohost/services.yml
|
||||
yunohost tools shell -c "from yunohost.service import _get_services, _save_services; _save_services(_get_services())"
|
||||
|
||||
mkdir -p $pending_dir/etc/systemd/system
|
||||
mkdir -p $pending_dir/etc/cron.d/
|
||||
mkdir -p $pending_dir/etc/cron.daily/
|
||||
|
||||
|
@ -82,7 +96,7 @@ EOF
|
|||
# Cron job that renew lets encrypt certificates if there's any that needs renewal
|
||||
cat > $pending_dir/etc/cron.daily/yunohost-certificate-renew << EOF
|
||||
#!/bin/bash
|
||||
yunohost domain cert-renew --email
|
||||
yunohost domain cert renew --email
|
||||
EOF
|
||||
|
||||
# If we subscribed to a dyndns domain, add the corresponding cron
|
||||
|
@ -122,8 +136,9 @@ HandleLidSwitch=ignore
|
|||
HandleLidSwitchDocked=ignore
|
||||
HandleLidSwitchExternalPower=ignore
|
||||
EOF
|
||||
|
||||
mkdir -p ${pending_dir}/etc/systemd/
|
||||
|
||||
cp yunoprompt.service ${pending_dir}/etc/systemd/system/yunoprompt.service
|
||||
|
||||
if [[ "$(yunohost settings get 'security.experimental.enabled')" == "True" ]]
|
||||
then
|
||||
cp proc-hidepid.service ${pending_dir}/etc/systemd/system/proc-hidepid.service
|
||||
|
@ -131,6 +146,8 @@ EOF
|
|||
touch ${pending_dir}/etc/systemd/system/proc-hidepid.service
|
||||
fi
|
||||
|
||||
cp dpkg-origins ${pending_dir}/etc/dpkg/origins/yunohost
|
||||
|
||||
}
|
||||
|
||||
do_post_regen() {
|
||||
|
@ -174,6 +191,8 @@ do_post_regen() {
|
|||
[ ! -e "/home/$USER" ] || setfacl -m g:all_users:--- /home/$USER
|
||||
done
|
||||
|
||||
# Domain settings
|
||||
mkdir -p /etc/yunohost/domains
|
||||
|
||||
# Misc configuration / state files
|
||||
chown root:root $(ls /etc/yunohost/{*.yml,*.yaml,*.json,mysql,psql} 2>/dev/null)
|
||||
|
@ -182,6 +201,7 @@ do_post_regen() {
|
|||
# Apps folder, custom hooks folder
|
||||
[[ ! -e /etc/yunohost/hooks.d ]] || (chown root /etc/yunohost/hooks.d && chmod 700 /etc/yunohost/hooks.d)
|
||||
[[ ! -e /etc/yunohost/apps ]] || (chown root /etc/yunohost/apps && chmod 700 /etc/yunohost/apps)
|
||||
[[ ! -e /etc/yunohost/domains ]] || (chown root /etc/yunohost/domains && chmod 700 /etc/yunohost/domains)
|
||||
|
||||
# Create ssh.app and sftp.app groups if they don't exist yet
|
||||
grep -q '^ssh.app:' /etc/group || groupadd ssh.app
|
||||
|
@ -191,31 +211,24 @@ do_post_regen() {
|
|||
[[ ! "$regen_conf_files" =~ "ntp.service.d/ynh-override.conf" ]] || { systemctl daemon-reload; systemctl restart ntp; }
|
||||
[[ ! "$regen_conf_files" =~ "nftables.service.d/ynh-override.conf" ]] || systemctl daemon-reload
|
||||
[[ ! "$regen_conf_files" =~ "login.conf.d/ynh-override.conf" ]] || systemctl daemon-reload
|
||||
if [[ "$regen_conf_files" =~ "yunoprompt.service" ]]
|
||||
then
|
||||
systemctl daemon-reload
|
||||
action=$([[ -e /etc/systemd/system/yunoprompt.service ]] && echo 'enable' || echo 'disable')
|
||||
systemctl $action yunoprompt --quiet --now
|
||||
fi
|
||||
if [[ "$regen_conf_files" =~ "proc-hidepid.service" ]]
|
||||
then
|
||||
systemctl daemon-reload
|
||||
action=$([[ -e /etc/systemd/system/proc-hidepid.service ]] && echo 'enable' || echo 'disable')
|
||||
systemctl $action proc-hidepid --quiet --now
|
||||
fi
|
||||
|
||||
# Change dpkg vendor
|
||||
# see https://wiki.debian.org/Derivatives/Guidelines#Vendor
|
||||
readlink -f /etc/dpkg/origins/default | grep -q debian \
|
||||
&& rm -f /etc/dpkg/origins/default \
|
||||
&& ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
init)
|
||||
do_init_regen
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -48,8 +48,6 @@ regen_local_ca() {
|
|||
popd
|
||||
}
|
||||
|
||||
|
||||
|
||||
do_init_regen() {
|
||||
|
||||
LOGFILE=/tmp/yunohost-ssl-init
|
||||
|
@ -121,23 +119,4 @@ do_post_regen() {
|
|||
fi
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
init)
|
||||
do_init_regen
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -40,20 +40,4 @@ do_post_regen() {
|
|||
systemctl restart ssh
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -194,23 +194,4 @@ objectClass: top"
|
|||
done
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
init)
|
||||
do_init_regen
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -22,23 +22,4 @@ do_post_regen() {
|
|||
|| systemctl restart nslcd
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
init)
|
||||
do_init_regen
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -54,20 +54,4 @@ do_post_regen() {
|
|||
update-alternatives --set php /usr/bin/php7.4
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -70,20 +70,4 @@ do_post_regen() {
|
|||
|| systemctl restart metronome
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -65,7 +65,7 @@ do_pre_regen() {
|
|||
export experimental="$(yunohost settings get 'security.experimental.enabled')"
|
||||
ynh_render_template "security.conf.inc" "${nginx_conf_dir}/security.conf.inc"
|
||||
|
||||
cert_status=$(yunohost domain cert-status --json)
|
||||
cert_status=$(yunohost domain cert status --json)
|
||||
|
||||
# add domain conf files
|
||||
for domain in $YNH_DOMAINS; do
|
||||
|
@ -135,23 +135,4 @@ do_post_regen() {
|
|||
pgrep nginx && systemctl reload nginx || { journalctl --no-pager --lines=10 -u nginx >&2; exit 1; }
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
init)
|
||||
do_init_regen
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -80,20 +80,4 @@ do_post_regen() {
|
|||
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -63,20 +63,4 @@ do_post_regen() {
|
|||
systemctl restart dovecot
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -59,20 +59,4 @@ do_post_regen() {
|
|||
systemctl -q restart rspamd.service
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -46,20 +46,4 @@ do_post_regen() {
|
|||
|| systemctl restart mysql
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -10,20 +10,4 @@ do_post_regen() {
|
|||
chown -R redis:adm /var/log/redis
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -61,23 +61,4 @@ do_post_regen() {
|
|||
|| systemctl restart yunomdns
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
init)
|
||||
do_init_regen
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -80,20 +80,4 @@ do_post_regen() {
|
|||
systemctl restart dnsmasq
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -22,23 +22,4 @@ do_post_regen() {
|
|||
|| systemctl restart unscd
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
init)
|
||||
do_init_regen
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -27,20 +27,4 @@ do_post_regen() {
|
|||
|| systemctl reload fail2ban
|
||||
}
|
||||
|
||||
FORCE=${2:-0}
|
||||
DRY_RUN=${3:-0}
|
||||
|
||||
case "$1" in
|
||||
pre)
|
||||
do_pre_regen $4
|
||||
;;
|
||||
post)
|
||||
do_post_regen $4
|
||||
;;
|
||||
*)
|
||||
echo "hook called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
do_$1_regen ${@:2}
|
||||
|
|
|
@ -8,11 +8,11 @@ from publicsuffix2 import PublicSuffixList
|
|||
|
||||
from moulinette.utils.process import check_output
|
||||
|
||||
from yunohost.utils.network import dig
|
||||
from yunohost.utils.dns import dig, YNH_DYNDNS_DOMAINS
|
||||
from yunohost.diagnosis import Diagnoser
|
||||
from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain
|
||||
from yunohost.domain import domain_list, _get_maindomain
|
||||
from yunohost.dns import _build_dns_conf, _get_dns_zone_for_domain
|
||||
|
||||
YNH_DYNDNS_DOMAINS = ["nohost.me", "noho.st", "ynh.fr"]
|
||||
SPECIAL_USE_TLDS = ["local", "localhost", "onion", "test"]
|
||||
|
||||
|
||||
|
@ -26,17 +26,15 @@ class DNSRecordsDiagnoser(Diagnoser):
|
|||
|
||||
main_domain = _get_maindomain()
|
||||
|
||||
all_domains = domain_list()["domains"]
|
||||
all_domains = domain_list(exclude_subdomains=True)["domains"]
|
||||
for domain in all_domains:
|
||||
self.logger_debug("Diagnosing DNS conf for %s" % domain)
|
||||
is_subdomain = domain.split(".", 1)[1] in all_domains
|
||||
is_specialusedomain = any(
|
||||
domain.endswith("." + tld) for tld in SPECIAL_USE_TLDS
|
||||
)
|
||||
for report in self.check_domain(
|
||||
domain,
|
||||
domain == main_domain,
|
||||
is_subdomain=is_subdomain,
|
||||
is_specialusedomain=is_specialusedomain,
|
||||
):
|
||||
yield report
|
||||
|
@ -55,16 +53,16 @@ class DNSRecordsDiagnoser(Diagnoser):
|
|||
for report in self.check_expiration_date(domains_from_registrar):
|
||||
yield report
|
||||
|
||||
def check_domain(self, domain, is_main_domain, is_subdomain, is_specialusedomain):
|
||||
def check_domain(self, domain, is_main_domain, is_specialusedomain):
|
||||
|
||||
base_dns_zone = _get_dns_zone_for_domain(domain)
|
||||
basename = domain.replace(base_dns_zone, "").rstrip(".") or "@"
|
||||
|
||||
expected_configuration = _build_dns_conf(
|
||||
domain, include_empty_AAAA_if_no_ipv6=True
|
||||
)
|
||||
|
||||
categories = ["basic", "mail", "xmpp", "extra"]
|
||||
# For subdomains, we only diagnosis A and AAAA records
|
||||
if is_subdomain:
|
||||
categories = ["basic"]
|
||||
|
||||
if is_specialusedomain:
|
||||
categories = []
|
||||
|
@ -82,8 +80,20 @@ class DNSRecordsDiagnoser(Diagnoser):
|
|||
results = {}
|
||||
|
||||
for r in records:
|
||||
|
||||
id_ = r["type"] + ":" + r["name"]
|
||||
r["current"] = self.get_current_record(domain, r["name"], r["type"])
|
||||
fqdn = r["name"] + "." + base_dns_zone if r["name"] != "@" else domain
|
||||
|
||||
# Ugly hack to not check mail records for subdomains stuff, otherwise will end up in a shitstorm of errors for people with many subdomains...
|
||||
# Should find a cleaner solution in the suggested conf...
|
||||
if r["type"] in ["MX", "TXT"] and fqdn not in [
|
||||
domain,
|
||||
f"mail._domainkey.{domain}",
|
||||
f"_dmarc.{domain}",
|
||||
]:
|
||||
continue
|
||||
|
||||
r["current"] = self.get_current_record(fqdn, r["type"])
|
||||
if r["value"] == "@":
|
||||
r["value"] = domain + "."
|
||||
|
||||
|
@ -106,7 +116,10 @@ class DNSRecordsDiagnoser(Diagnoser):
|
|||
# A bad or missing A record is critical ...
|
||||
# And so is a wrong AAAA record
|
||||
# (However, a missing AAAA record is acceptable)
|
||||
if results["A:@"] != "OK" or results["AAAA:@"] == "WRONG":
|
||||
if (
|
||||
results[f"A:{basename}"] != "OK"
|
||||
or results[f"AAAA:{basename}"] == "WRONG"
|
||||
):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
@ -139,10 +152,9 @@ class DNSRecordsDiagnoser(Diagnoser):
|
|||
|
||||
yield output
|
||||
|
||||
def get_current_record(self, domain, name, type_):
|
||||
def get_current_record(self, fqdn, type_):
|
||||
|
||||
query = "%s.%s" % (name, domain) if name != "@" else domain
|
||||
success, answers = dig(query, type_, resolvers="force_external")
|
||||
success, answers = dig(fqdn, type_, resolvers="force_external")
|
||||
|
||||
if success != "ok":
|
||||
return None
|
||||
|
@ -170,7 +182,7 @@ class DNSRecordsDiagnoser(Diagnoser):
|
|||
)
|
||||
|
||||
# For SPF, ignore parts starting by ip4: or ip6:
|
||||
if r["name"] == "@":
|
||||
if "v=spf1" in r["value"]:
|
||||
current = {
|
||||
part
|
||||
for part in current
|
||||
|
@ -189,7 +201,6 @@ class DNSRecordsDiagnoser(Diagnoser):
|
|||
"""
|
||||
Alert if expiration date of a domain is soon
|
||||
"""
|
||||
|
||||
details = {"not_found": [], "error": [], "warning": [], "success": []}
|
||||
|
||||
for domain in domains:
|
||||
|
@ -199,6 +210,7 @@ class DNSRecordsDiagnoser(Diagnoser):
|
|||
status_ns, _ = dig(domain, "NS", resolvers="force_external")
|
||||
status_a, _ = dig(domain, "A", resolvers="force_external")
|
||||
if "ok" not in [status_ns, status_a]:
|
||||
# i18n: diagnosis_domain_not_found_details
|
||||
details["not_found"].append(
|
||||
(
|
||||
"diagnosis_domain_%s_details" % (expire_date),
|
||||
|
@ -233,6 +245,12 @@ class DNSRecordsDiagnoser(Diagnoser):
|
|||
# Allow to ignore specifically a single domain
|
||||
if len(details[alert_type]) == 1:
|
||||
meta["domain"] = details[alert_type][0][1]["domain"]
|
||||
|
||||
# i18n: diagnosis_domain_expiration_not_found
|
||||
# i18n: diagnosis_domain_expiration_error
|
||||
# i18n: diagnosis_domain_expiration_warning
|
||||
# i18n: diagnosis_domain_expiration_success
|
||||
# i18n: diagnosis_domain_expiration_not_found_details
|
||||
yield dict(
|
||||
meta=meta,
|
||||
data={},
|
||||
|
|
|
@ -121,6 +121,10 @@ class WebDiagnoser(Diagnoser):
|
|||
|
||||
for domain in domains:
|
||||
|
||||
# i18n: diagnosis_http_bad_status_code
|
||||
# i18n: diagnosis_http_connection_error
|
||||
# i18n: diagnosis_http_timeout
|
||||
|
||||
# If both IPv4 and IPv6 (if applicable) are good
|
||||
if all(
|
||||
results[ipversion][domain]["status"] == "ok" for ipversion in ipversions
|
||||
|
|
|
@ -12,7 +12,7 @@ from moulinette.utils.filesystem import read_yaml
|
|||
from yunohost.diagnosis import Diagnoser
|
||||
from yunohost.domain import _get_maindomain, domain_list
|
||||
from yunohost.settings import settings_get
|
||||
from yunohost.utils.network import dig
|
||||
from yunohost.utils.dns import dig
|
||||
|
||||
DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml"
|
||||
|
||||
|
@ -35,11 +35,11 @@ class MailDiagnoser(Diagnoser):
|
|||
# TODO check that the recent mail logs are not filled with thousand of email sending (unusual number of mail sent)
|
||||
# TODO check for unusual failed sending attempt being refused in the logs ?
|
||||
checks = [
|
||||
"check_outgoing_port_25",
|
||||
"check_ehlo",
|
||||
"check_fcrdns",
|
||||
"check_blacklist",
|
||||
"check_queue",
|
||||
"check_outgoing_port_25", # i18n: diagnosis_mail_outgoing_port_25_ok
|
||||
"check_ehlo", # i18n: diagnosis_mail_ehlo_ok
|
||||
"check_fcrdns", # i18n: diagnosis_mail_fcrdns_ok
|
||||
"check_blacklist", # i18n: diagnosis_mail_blacklist_ok
|
||||
"check_queue", # i18n: diagnosis_mail_queue_ok
|
||||
]
|
||||
for check in checks:
|
||||
self.logger_debug("Running " + check)
|
||||
|
@ -102,6 +102,10 @@ class MailDiagnoser(Diagnoser):
|
|||
continue
|
||||
|
||||
if r["status"] != "ok":
|
||||
# i18n: diagnosis_mail_ehlo_bad_answer
|
||||
# i18n: diagnosis_mail_ehlo_bad_answer_details
|
||||
# i18n: diagnosis_mail_ehlo_unreachable
|
||||
# i18n: diagnosis_mail_ehlo_unreachable_details
|
||||
summary = r["status"].replace("error_smtp_", "diagnosis_mail_ehlo_")
|
||||
yield dict(
|
||||
meta={"test": "mail_ehlo", "ipversion": ipversion},
|
||||
|
|
|
@ -76,7 +76,7 @@ class AppDiagnoser(Diagnoser):
|
|||
for deprecated_helper in deprecated_helpers:
|
||||
if (
|
||||
os.system(
|
||||
f"grep -nr -q '{deprecated_helper}' {app['setting_path']}/scripts/"
|
||||
f"grep -hr '{deprecated_helper}' {app['setting_path']}/scripts/ | grep -v -q '^\s*#'"
|
||||
)
|
||||
== 0
|
||||
):
|
||||
|
|
9
data/hooks/restore/18-data_multimedia
Normal file
9
data/hooks/restore/18-data_multimedia
Normal file
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Exit hook on subcommand error or unset variable
|
||||
set -eu
|
||||
|
||||
# Source YNH helpers
|
||||
source /usr/share/yunohost/helpers
|
||||
|
||||
ynh_restore_file --origin_path="/home/yunohost.multimedia" --not_mandatory
|
|
@ -2,6 +2,7 @@ backup_dir="$1/conf/ynh"
|
|||
|
||||
cp -a "${backup_dir}/current_host" /etc/yunohost/current_host
|
||||
cp -a "${backup_dir}/firewall.yml" /etc/yunohost/firewall.yml
|
||||
cp -a "${backup_dir}/domains" /etc/yunohost/domains
|
||||
[ ! -e "${backup_dir}/settings.json" ] || cp -a "${backup_dir}/settings.json" "/etc/yunohost/settings.json"
|
||||
[ ! -d "${backup_dir}/dyndns" ] || cp -raT "${backup_dir}/dyndns" "/etc/yunohost/dyndns"
|
||||
[ ! -d "${backup_dir}/dkim" ] || cp -raT "${backup_dir}/dkim" "/etc/dkim"
|
||||
|
|
55
data/other/config_domain.toml
Normal file
55
data/other/config_domain.toml
Normal file
|
@ -0,0 +1,55 @@
|
|||
version = "1.0"
|
||||
i18n = "domain_config"
|
||||
|
||||
#
|
||||
# Other things we may want to implement in the future:
|
||||
#
|
||||
# - maindomain handling
|
||||
# - default app
|
||||
# - autoredirect www in nginx conf
|
||||
# - ?
|
||||
#
|
||||
|
||||
[feature]
|
||||
|
||||
[feature.mail]
|
||||
#services = ['postfix', 'dovecot']
|
||||
|
||||
[feature.mail.features_disclaimer]
|
||||
type = "alert"
|
||||
style = "warning"
|
||||
icon = "warning"
|
||||
|
||||
[feature.mail.mail_out]
|
||||
type = "boolean"
|
||||
default = 1
|
||||
|
||||
[feature.mail.mail_in]
|
||||
type = "boolean"
|
||||
default = 1
|
||||
|
||||
#[feature.mail.backup_mx]
|
||||
#type = "tags"
|
||||
#default = []
|
||||
#pattern.regexp = '^([^\W_A-Z]+([-]*[^\W_A-Z]+)*\.)+((xn--)?[^\W_]{2,})$'
|
||||
#pattern.error = "pattern_error"
|
||||
|
||||
[feature.xmpp]
|
||||
|
||||
[feature.xmpp.xmpp]
|
||||
type = "boolean"
|
||||
default = 0
|
||||
|
||||
[dns]
|
||||
|
||||
[dns.registrar]
|
||||
optional = true
|
||||
|
||||
# This part is automatically generated in DomainConfigPanel
|
||||
|
||||
# [dns.advanced]
|
||||
#
|
||||
# [dns.advanced.ttl]
|
||||
# type = "number"
|
||||
# min = 0
|
||||
# default = 3600
|
649
data/other/registrar_list.toml
Normal file
649
data/other/registrar_list.toml
Normal file
|
@ -0,0 +1,649 @@
|
|||
[aliyun]
|
||||
[aliyun.auth_key_id]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[aliyun.auth_secret]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[aurora]
|
||||
[aurora.auth_api_key]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[aurora.auth_secret_key]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[azure]
|
||||
[azure.auth_client_id]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[azure.auth_client_secret]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[azure.auth_tenant_id]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[azure.auth_subscription_id]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[azure.resource_group]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[cloudflare]
|
||||
[cloudflare.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[cloudflare.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[cloudflare.zone_id]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[cloudns]
|
||||
[cloudns.auth_id]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[cloudns.auth_subid]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[cloudns.auth_subuser]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[cloudns.auth_password]
|
||||
type = "password"
|
||||
|
||||
[cloudns.weight]
|
||||
type = "number"
|
||||
|
||||
[cloudns.port]
|
||||
type = "number"
|
||||
[cloudxns]
|
||||
[cloudxns.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[cloudxns.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[conoha]
|
||||
[conoha.auth_region]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[conoha.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[conoha.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[conoha.auth_password]
|
||||
type = "password"
|
||||
|
||||
[conoha.auth_tenant_id]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[constellix]
|
||||
[constellix.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[constellix.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[digitalocean]
|
||||
[digitalocean.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[dinahosting]
|
||||
[dinahosting.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[dinahosting.auth_password]
|
||||
type = "password"
|
||||
|
||||
[directadmin]
|
||||
[directadmin.auth_password]
|
||||
type = "password"
|
||||
|
||||
[directadmin.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[directadmin.endpoint]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[dnsimple]
|
||||
[dnsimple.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[dnsimple.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[dnsimple.auth_password]
|
||||
type = "password"
|
||||
|
||||
[dnsimple.auth_2fa]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[dnsmadeeasy]
|
||||
[dnsmadeeasy.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[dnsmadeeasy.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[dnspark]
|
||||
[dnspark.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[dnspark.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[dnspod]
|
||||
[dnspod.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[dnspod.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[dreamhost]
|
||||
[dreamhost.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[dynu]
|
||||
[dynu.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[easydns]
|
||||
[easydns.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[easydns.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[easyname]
|
||||
[easyname.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[easyname.auth_password]
|
||||
type = "password"
|
||||
|
||||
[euserv]
|
||||
[euserv.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[euserv.auth_password]
|
||||
type = "password"
|
||||
|
||||
[exoscale]
|
||||
[exoscale.auth_key]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[exoscale.auth_secret]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[gandi]
|
||||
[gandi.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[gandi.api_protocol]
|
||||
type = "string"
|
||||
choices.rpc = "RPC"
|
||||
choices.rest = "REST"
|
||||
default = "rest"
|
||||
visible = "false"
|
||||
|
||||
[gehirn]
|
||||
[gehirn.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[gehirn.auth_secret]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[glesys]
|
||||
[glesys.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[glesys.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[godaddy]
|
||||
[godaddy.auth_key]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[godaddy.auth_secret]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[googleclouddns]
|
||||
[goggleclouddns.auth_service_account_info]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[gransy]
|
||||
[gransy.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[gransy.auth_password]
|
||||
type = "password"
|
||||
|
||||
[gratisdns]
|
||||
[gratisdns.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[gratisdns.auth_password]
|
||||
type = "password"
|
||||
|
||||
[henet]
|
||||
[henet.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[henet.auth_password]
|
||||
type = "password"
|
||||
|
||||
[hetzner]
|
||||
[hetzner.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[hostingde]
|
||||
[hostingde.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[hover]
|
||||
[hover.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[hover.auth_password]
|
||||
type = "password"
|
||||
|
||||
[infoblox]
|
||||
[infoblox.auth_user]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[infoblox.auth_psw]
|
||||
type = "password"
|
||||
|
||||
[infoblox.ib_view]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[infoblox.ib_host]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[infomaniak]
|
||||
[infomaniak.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[internetbs]
|
||||
[internetbs.auth_key]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[internetbs.auth_password]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[inwx]
|
||||
[inwx.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[inwx.auth_password]
|
||||
type = "password"
|
||||
|
||||
[joker]
|
||||
[joker.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[linode]
|
||||
[linode.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[linode4]
|
||||
[linode4.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[localzone]
|
||||
[localzone.filename]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[luadns]
|
||||
[luadns.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[luadns.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[memset]
|
||||
[memset.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[mythicbeasts]
|
||||
[mythicbeasts.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[mythicbeasts.auth_password]
|
||||
type = "password"
|
||||
|
||||
[mythicbeasts.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[namecheap]
|
||||
[namecheap.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[namecheap.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[namecheap.auth_client_ip]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[namecheap.auth_sandbox]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[namesilo]
|
||||
[namesilo.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[netcup]
|
||||
[netcup.auth_customer_id]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[netcup.auth_api_key]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[netcup.auth_api_password]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[nfsn]
|
||||
[nfsn.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[nfsn.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[njalla]
|
||||
[njalla.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[nsone]
|
||||
[nsone.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[onapp]
|
||||
[onapp.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[onapp.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[onapp.auth_server]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[online]
|
||||
[online.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[ovh]
|
||||
[ovh.auth_entrypoint]
|
||||
type = "select"
|
||||
choices = ["ovh-eu", "ovh-ca", "soyoustart-eu", "soyoustart-ca", "kimsufi-eu", "kimsufi-ca"]
|
||||
default = "ovh-eu"
|
||||
|
||||
[ovh.auth_application_key]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[ovh.auth_application_secret]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[ovh.auth_consumer_key]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[plesk]
|
||||
[plesk.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[plesk.auth_password]
|
||||
type = "password"
|
||||
|
||||
[plesk.plesk_server]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[pointhq]
|
||||
[pointhq.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[pointhq.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[powerdns]
|
||||
[powerdns.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[powerdns.pdns_server]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[powerdns.pdns_server_id]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[powerdns.pdns_disable_notify]
|
||||
type = "boolean"
|
||||
|
||||
[rackspace]
|
||||
[rackspace.auth_account]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[rackspace.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[rackspace.auth_api_key]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[rackspace.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[rackspace.sleep_time]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[rage4]
|
||||
[rage4.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[rage4.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[rcodezero]
|
||||
[rcodezero.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[route53]
|
||||
[route53.auth_access_key]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[route53.auth_access_secret]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[route53.private_zone]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[route53.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[route53.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[safedns]
|
||||
[safedns.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[sakuracloud]
|
||||
[sakuracloud.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[sakuracloud.auth_secret]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[softlayer]
|
||||
[softlayer.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[softlayer.auth_api_key]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[transip]
|
||||
[transip.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[transip.auth_api_key]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[ultradns]
|
||||
[ultradns.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[ultradns.auth_username]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[ultradns.auth_password]
|
||||
type = "password"
|
||||
|
||||
[vultr]
|
||||
[vultr.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[yandex]
|
||||
[yandex.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[zeit]
|
||||
[zeit.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[zilore]
|
||||
[zilore.auth_key]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[zonomi]
|
||||
[zonomy.auth_token]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
||||
[zonomy.auth_entrypoint]
|
||||
type = "string"
|
||||
redact = true
|
||||
|
|
@ -30,7 +30,7 @@ skip-external-locking
|
|||
key_buffer_size = 16K
|
||||
max_allowed_packet = 16M
|
||||
table_open_cache = 4
|
||||
sort_buffer_size = 256K
|
||||
sort_buffer_size = 4M
|
||||
read_buffer_size = 256K
|
||||
read_rnd_buffer_size = 256K
|
||||
net_buffer_length = 2K
|
||||
|
|
35
debian/changelog
vendored
35
debian/changelog
vendored
|
@ -4,6 +4,41 @@ yunohost (11.0.0~alpha) unstable; urgency=low
|
|||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Fri, 05 Feb 2021 00:02:38 +0100
|
||||
|
||||
yunohost (4.3.0) testing; urgency=low
|
||||
|
||||
- [users] Import/export users from/to CSV ([#1089](https://github.com/YunoHost/yunohost/pull/1089))
|
||||
- [domain] Add mDNS for .local domains / replace avahi-daemon ([#1112](https://github.com/YunoHost/yunohost/pull/1112))
|
||||
- [settings] new setting to enable experimental security features ([#1290](https://github.com/YunoHost/yunohost/pull/1290))
|
||||
- [settings] new setting to handle https redirect ([#1304](https://github.com/YunoHost/yunohost/pull/1304))
|
||||
- [diagnosis] add an "app" section to check that app are in catalog with good quality, check for deprecated practices ([#1217](https://github.com/YunoHost/yunohost/pull/1217))
|
||||
- [diagnosis] report suspiciously high number of auth failures ([#1292](https://github.com/YunoHost/yunohost/pull/1292))
|
||||
- [refactor] Rework the authentication system ([#1183](https://github.com/YunoHost/yunohost/pull/1183))
|
||||
- [enh] New config-panel mechanism ([#987](https://github.com/YunoHost/yunohost/pull/987))
|
||||
- [enh] Add backup for multimedia files (88063dc7)
|
||||
- [enh] Configure automatically the DNS records using lexicon ([#1315](https://github.com/YunoHost/yunohost/pull/1315))
|
||||
- also brings domain settings, domain config panel, subdomain awareness, improvements in dns recommended conf
|
||||
- [i18n] Translations updated for Catalan, Chinese (Simplified), Czech, Esperanto, French, Galician, German, Italian, Occitan, Persian, Portuguese, Spanish, Ukrainian
|
||||
|
||||
Thanks to all contributors <3 ! (Corentin Mercier, Daniel, Éric Gaspar, Flavio Cristoforetti, Gregor Lenz, José M, Kay0u, ljf, MercierCorentin, mifegui, Paco, Parviz Homayun, ppr, tituspijean, Tymofii-Lytvynenko)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Sun, 19 Sep 2021 23:55:21 +0200
|
||||
|
||||
yunohost (4.2.8.3) stable; urgency=low
|
||||
|
||||
- [fix] mysql: Another bump for sort_buffer_size to make Nextcloud 22 work (34e9246b)
|
||||
|
||||
Thanks to all contributors <3 ! (ljf (zamentur))
|
||||
|
||||
-- Kay0u <pierre@kayou.io> Fri, 10 Sep 2021 10:40:38 +0200
|
||||
|
||||
yunohost (4.2.8.2) stable; urgency=low
|
||||
|
||||
- [fix] mysql: Bump sort_buffer_size to 256K to fix Nextcloud 22 installation (d8c49619)
|
||||
|
||||
Thanks to all contributors <3 ! (ericg)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 07 Sep 2021 23:23:18 +0200
|
||||
|
||||
yunohost (4.2.8.1) stable; urgency=low
|
||||
|
||||
- [fix] Safer location for slapd backup during hdb/mdb migration (3c646b3d)
|
||||
|
|
2
debian/control
vendored
2
debian/control
vendored
|
@ -14,7 +14,7 @@ Depends: ${python3:Depends}, ${misc:Depends}
|
|||
, python3-psutil, python3-requests, python3-dnspython, python3-openssl
|
||||
, python3-miniupnpc, python3-dbus, python3-jinja2
|
||||
, python3-toml, python3-packaging, python3-publicsuffix2
|
||||
, python3-ldap, python3-zeroconf
|
||||
, python3-ldap, python3-zeroconf, python3-lexicon,
|
||||
, python-is-python3
|
||||
, nginx, nginx-extras (>=1.18)
|
||||
, apt, apt-transport-https, apt-utils, dirmngr
|
||||
|
|
13
debian/install
vendored
13
debian/install
vendored
|
@ -1,17 +1,8 @@
|
|||
bin/* /usr/bin/
|
||||
sbin/* /usr/sbin/
|
||||
data/* /usr/share/yunohost/
|
||||
data/bash-completion.d/yunohost /etc/bash_completion.d/
|
||||
doc/yunohost.8.gz /usr/share/man/man8/
|
||||
data/actionsmap/* /usr/share/moulinette/actionsmap/
|
||||
data/hooks/* /usr/share/yunohost/hooks/
|
||||
data/other/yunoprompt.service /etc/systemd/system/
|
||||
data/other/password/* /usr/share/yunohost/other/password/
|
||||
data/other/dpkg-origins/yunohost /etc/dpkg/origins
|
||||
data/other/dnsbl_list.yml /usr/share/yunohost/other/
|
||||
data/other/ffdhe2048.pem /usr/share/yunohost/other/
|
||||
data/other/* /usr/share/yunohost/yunohost-config/moulinette/
|
||||
data/templates/* /usr/share/yunohost/templates/
|
||||
data/helpers /usr/share/yunohost/
|
||||
data/helpers.d/* /usr/share/yunohost/helpers.d/
|
||||
lib/metronome/modules/* /usr/lib/metronome/modules/
|
||||
locales/* /usr/lib/moulinette/yunohost/locales/
|
||||
src/yunohost /usr/lib/moulinette
|
||||
|
|
11
debian/postinst
vendored
11
debian/postinst
vendored
|
@ -5,6 +5,9 @@ set -e
|
|||
do_configure() {
|
||||
rm -rf /var/cache/moulinette/*
|
||||
|
||||
mkdir -p /usr/share/moulinette/actionsmap/
|
||||
ln -sf /usr/share/yunohost/actionsmap/yunohost.yml /usr/share/moulinette/actionsmap/yunohost.yml
|
||||
|
||||
if [ ! -f /etc/yunohost/installed ]; then
|
||||
# If apps/ is not empty, we're probably already installed in the past and
|
||||
# something funky happened ...
|
||||
|
@ -31,14 +34,6 @@ do_configure() {
|
|||
yunohost diagnosis run --force
|
||||
fi
|
||||
|
||||
# Change dpkg vendor
|
||||
# see https://wiki.debian.org/Derivatives/Guidelines#Vendor
|
||||
readlink -f /etc/dpkg/origins/default | grep -q debian \
|
||||
&& rm -f /etc/dpkg/origins/default \
|
||||
&& ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
|
||||
|
||||
# Yunoprompt
|
||||
systemctl enable yunoprompt.service
|
||||
}
|
||||
|
||||
# summary of how this script can be called:
|
||||
|
|
|
@ -10,11 +10,10 @@ routes:
|
|||
Doc auto-generated by [this script](https://github.com/YunoHost/yunohost/blob/{{ current_commit }}/doc/generate_helper_doc.py) on {{data.date}} (YunoHost version {{data.version}})
|
||||
|
||||
{% for category, helpers in data.helpers %}
|
||||
### {{ category.upper() }}
|
||||
## {{ category.upper() }}
|
||||
{% for h in helpers %}
|
||||
**{{ h.name }}**<br/>
|
||||
#### {{ h.name }}
|
||||
[details summary="<i>{{ h.brief }}</i>" class="helper-card-subtitle text-muted"]
|
||||
<p></p>
|
||||
|
||||
**Usage**: `{{ h.usage }}`
|
||||
{%- if h.args %}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
"app_already_installed": "{app} تم تنصيبه مِن قبل",
|
||||
"app_already_up_to_date": "{app} تم تحديثه مِن قَبل",
|
||||
"app_argument_required": "المُعامِل '{name}' مطلوب",
|
||||
"app_change_url_failed_nginx_reload": "فشلت عملية إعادة تشغيل NGINX. ها هي نتيجة الأمر 'nginx -t':\n{nginx_errors}",
|
||||
"app_extraction_failed": "تعذر فك الضغط عن ملفات التنصيب",
|
||||
"app_install_files_invalid": "ملفات التنصيب خاطئة",
|
||||
"app_not_correctly_installed": "يبدو أن التطبيق {app} لم يتم تنصيبه بشكل صحيح",
|
||||
|
@ -40,7 +39,6 @@
|
|||
"domain_creation_failed": "تعذرت عملية إنشاء النطاق",
|
||||
"domain_deleted": "تم حذف النطاق",
|
||||
"domain_exists": "اسم النطاق موجود مِن قبل",
|
||||
"domain_unknown": "النطاق مجهول",
|
||||
"domains_available": "النطاقات المتوفرة :",
|
||||
"done": "تم",
|
||||
"downloading": "عملية التنزيل جارية …",
|
||||
|
@ -55,7 +53,6 @@
|
|||
"pattern_domain": "يتوجب أن يكون إسم نطاق صالح (مثل my-domain.org)",
|
||||
"pattern_email": "يتوجب أن يكون عنوان بريد إلكتروني صالح (مثل someone@domain.org)",
|
||||
"pattern_password": "يتوجب أن تكون مكونة من 3 حروف على الأقل",
|
||||
"pattern_positive_number": "يجب أن يكون عددا إيجابيا",
|
||||
"restore_extracting": "جارٍ فك الضغط عن الملفات التي نحتاجها من النسخة الاحتياطية…",
|
||||
"server_shutdown": "سوف ينطفئ الخادوم",
|
||||
"server_shutdown_confirm": "سوف ينطفئ الخادوم حالا. متأكد ؟ [{answers}]",
|
||||
|
|
|
@ -6,10 +6,9 @@
|
|||
"app_already_installed": "{app} ja està instal·lada",
|
||||
"app_already_installed_cant_change_url": "Aquesta aplicació ja està instal·lada. La URL no és pot canviar únicament amb aquesta funció. Mireu a `app changeurl` si està disponible.",
|
||||
"app_already_up_to_date": "{app} ja està actualitzada",
|
||||
"app_argument_choice_invalid": "Utilitzeu una de les opcions «{choices}» per l'argument «{name}»",
|
||||
"app_argument_choice_invalid": "Utilitzeu una de les opcions «{choices}» per l'argument «{name}» en lloc de «{value}»",
|
||||
"app_argument_invalid": "Escolliu un valor vàlid per l'argument «{name}»: {error}",
|
||||
"app_argument_required": "Es necessita l'argument '{name}'",
|
||||
"app_change_url_failed_nginx_reload": "No s'ha pogut tornar a carregar NGINX. Aquí teniu el resultat de \"nginx -t\":\n{nginx_errors}",
|
||||
"app_change_url_identical_domains": "L'antic i el nou domini/camí són idèntics ('{domain}{path}'), no hi ha res per fer.",
|
||||
"app_change_url_no_script": "L'aplicació '{app_name}' encara no permet modificar la URL. Potser s'ha d'actualitzar.",
|
||||
"app_change_url_success": "La URL de {app} ara és {domain}{path}",
|
||||
|
@ -112,11 +111,11 @@
|
|||
"certmanager_self_ca_conf_file_not_found": "No s'ha trobat el fitxer de configuració per l'autoritat del certificat auto-signat (fitxer: {file})",
|
||||
"certmanager_unable_to_parse_self_CA_name": "No s'ha pogut analitzar el nom de l'autoritat del certificat auto-signat (fitxer: {file})",
|
||||
"confirm_app_install_warning": "Atenció: Aquesta aplicació funciona, però no està ben integrada amb YunoHost. Algunes característiques com la autenticació única i la còpia de seguretat/restauració poden no estar disponibles. Voleu instal·lar-la de totes maneres? [{answers}] ",
|
||||
"confirm_app_install_danger": "PERILL! Aquesta aplicació encara és experimental (si no és que no funciona directament)! No hauríeu d'instal·lar-la a no ser que sapigueu el que feu. No obtindreu CAP AJUDA si l'aplicació no funciona o trenca el sistema… Si accepteu el risc, escriviu «{answers}»",
|
||||
"confirm_app_install_danger": "PERILL! Aquesta aplicació encara és experimental (si no és que no funciona directament)! No hauríeu d'instal·lar-la a no ser que sapigueu el que feu. No obtindreu CAP AJUDA si l'aplicació no funciona o trenca el sistema... Si accepteu el risc, escriviu «{answers}»",
|
||||
"confirm_app_install_thirdparty": "PERILL! Aquesta aplicació no es part del catàleg d'aplicacions de YunoHost. La instal·lació d'aplicacions de terceres parts pot comprometre la integritat i seguretat del seu sistema. No hauríeu d'instal·lar-ne a no ser que sapigueu el que feu. No obtindreu CAP AJUDA si l'aplicació no funciona o trenca el sistema… Si accepteu el risc, escriviu «{answers}»",
|
||||
"custom_app_url_required": "Heu de especificar una URL per actualitzar la vostra aplicació personalitzada {app}",
|
||||
"admin_password_too_long": "Trieu una contrasenya de menys de 127 caràcters",
|
||||
"dpkg_is_broken": "No es pot fer això en aquest instant perquè dpkg/APT (els gestors de paquets del sistema) sembla estar mal configurat… Podeu intentar solucionar-ho connectant-vos per SSH i executant «sudo apt install --fix-broken» i/o «sudo dpkg --configure -a».",
|
||||
"dpkg_is_broken": "No es pot fer això en aquest instant perquè dpkg/APT (els gestors de paquets del sistema) sembla estar mal configurat... Podeu intentar solucionar-ho connectant-vos per SSH i executant «sudo apt install --fix-broken» i/o «sudo dpkg --configure -a».",
|
||||
"domain_cannot_remove_main": "No es pot eliminar «{domain}» ja que és el domini principal, primer s'ha d'establir un nou domini principal utilitzant «yunohost domain main-domain -n <un-altre-domini>»; aquí hi ha una llista dels possibles dominis: {other_domains}",
|
||||
"domain_cert_gen_failed": "No s'ha pogut generar el certificat",
|
||||
"domain_created": "S'ha creat el domini",
|
||||
|
@ -130,10 +129,9 @@
|
|||
"domain_dyndns_root_unknown": "Domini DynDNS principal desconegut",
|
||||
"domain_hostname_failed": "No s'ha pogut establir un nou nom d'amfitrió. Això podria causar problemes més tard (podria no passar res).",
|
||||
"domain_uninstall_app_first": "Aquestes aplicacions encara estan instal·lades en el vostre domini:\n{apps}\n\nDesinstal·leu-les utilitzant l'ordre «yunohost app remove id_de_lapplicació» o moveu-les a un altre domini amb «yunohost app change-url id_de_lapplicació» abans d'eliminar el domini",
|
||||
"domain_unknown": "Domini desconegut",
|
||||
"domains_available": "Dominis disponibles:",
|
||||
"done": "Fet",
|
||||
"downloading": "Descarregant…",
|
||||
"downloading": "Descarregant...",
|
||||
"dyndns_could_not_check_provide": "No s'ha pogut verificar si {provider} pot oferir {domain}.",
|
||||
"dyndns_could_not_check_available": "No s'ha pogut verificar la disponibilitat de {domain} a {provider}.",
|
||||
"dyndns_ip_update_failed": "No s'ha pogut actualitzar l'adreça IP al DynDNS",
|
||||
|
@ -177,7 +175,7 @@
|
|||
"iptables_unavailable": "No podeu modificar les iptables aquí. O bé sou en un contenidor o bé el vostre nucli no és compatible amb aquesta opció",
|
||||
"log_corrupted_md_file": "El fitxer de metadades YAML associat amb els registres està malmès: « {md_file} »\nError: {error}",
|
||||
"log_link_to_log": "El registre complet d'aquesta operació: «<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>»",
|
||||
"log_help_to_get_log": "Per veure el registre de l'operació « {desc} », utilitzeu l'ordre « yunohost log show {name}{name} »",
|
||||
"log_help_to_get_log": "Per veure el registre de l'operació « {desc} », utilitzeu l'ordre « yunohost log show {name} »",
|
||||
"log_link_to_failed_log": "No s'ha pogut completar l'operació « {desc} ». Per obtenir ajuda, <a href=\"#/tools/logs/{name}\">proveïu el registre complete de l'operació clicant aquí</a>",
|
||||
"log_help_to_get_failed_log": "No s'ha pogut completar l'operació « {desc} ». Per obtenir ajuda, compartiu el registre complete de l'operació utilitzant l'ordre « yunohost log share {name} »",
|
||||
"log_does_exists": "No hi ha cap registre per l'operació amb el nom« {log} », utilitzeu « yunohost log list » per veure tots els registre d'operació disponibles",
|
||||
|
@ -237,7 +235,6 @@
|
|||
"pattern_mailbox_quota": "Ha de ser una mida amb el sufix b/k/M/G/T o 0 per no tenir quota",
|
||||
"pattern_password": "Ha de tenir un mínim de 3 caràcters",
|
||||
"pattern_port_or_range": "Ha de ser un número de port vàlid (i.e. 0-65535) o un interval de ports (ex. 100:200)",
|
||||
"pattern_positive_number": "Ha de ser un nombre positiu",
|
||||
"pattern_username": "Ha d'estar compost per caràcters alfanumèrics en minúscula i guió baix exclusivament",
|
||||
"pattern_password_app": "Les contrasenyes no poden de tenir els següents caràcters: {forbidden_chars}",
|
||||
"port_already_closed": "El port {port} ja està tancat per les connexions {ip_version}",
|
||||
|
@ -254,7 +251,7 @@
|
|||
"regenconf_up_to_date": "La configuració ja està al dia per la categoria «{category}»",
|
||||
"regenconf_updated": "S'ha actualitzat la configuració per la categoria «{category}»",
|
||||
"regenconf_would_be_updated": "La configuració hagués estat actualitzada per la categoria «{category}»",
|
||||
"regenconf_dry_pending_applying": "Verificació de la configuració pendent que s'hauria d'haver aplicat per la categoria «{category}»…",
|
||||
"regenconf_dry_pending_applying": "Verificació de la configuració pendent que s'hauria d'haver aplicat per la categoria «{category}»...",
|
||||
"regenconf_failed": "No s'ha pogut regenerar la configuració per la/les categoria/es : {categories}",
|
||||
"regenconf_pending_applying": "Aplicació de la configuració pendent per la categoria «{category}»...",
|
||||
"restore_already_installed_app": "Una aplicació amb la ID «{app}» ja està instal·lada",
|
||||
|
@ -262,15 +259,15 @@
|
|||
"restore_cleaning_failed": "No s'ha pogut netejar el directori temporal de restauració",
|
||||
"restore_complete": "Restauració completada",
|
||||
"restore_confirm_yunohost_installed": "Esteu segur de voler restaurar un sistema ja instal·lat? [{answers}]",
|
||||
"restore_extracting": "Extracció dels fitxers necessaris de l'arxiu…",
|
||||
"restore_extracting": "Extracció dels fitxers necessaris de l'arxiu...",
|
||||
"restore_failed": "No s'ha pogut restaurar el sistema",
|
||||
"restore_hook_unavailable": "El script de restauració «{part}» no està disponible en el sistema i tampoc és en l'arxiu",
|
||||
"restore_may_be_not_enough_disk_space": "Sembla que no hi ha prou espai disponible en el sistema (lliure: {free_space} B, espai necessari: {needed_space} B, marge de seguretat: {margin} B)",
|
||||
"restore_not_enough_disk_space": "No hi ha prou espai disponible (espai: {free_space} B, espai necessari: {needed_space} B, marge de seguretat: {margin} B)",
|
||||
"restore_nothings_done": "No s'ha restaurat res",
|
||||
"restore_removing_tmp_dir_failed": "No s'ha pogut eliminar un directori temporal antic",
|
||||
"restore_running_app_script": "Restaurant l'aplicació «{app}»…",
|
||||
"restore_running_hooks": "Execució dels hooks de restauració…",
|
||||
"restore_running_app_script": "Restaurant l'aplicació «{app}»...",
|
||||
"restore_running_hooks": "Execució dels hooks de restauració...",
|
||||
"restore_system_part_failed": "No s'ha pogut restaurar la part «{part}» del sistema",
|
||||
"root_password_desynchronized": "S'ha canviat la contrasenya d'administració, però YunoHost no ha pogut propagar-ho cap a la contrasenya root!",
|
||||
"root_password_replaced_by_admin_password": "La contrasenya root s'ha substituït per la contrasenya d'administració.",
|
||||
|
@ -319,13 +316,13 @@
|
|||
"system_upgraded": "S'ha actualitzat el sistema",
|
||||
"system_username_exists": "El nom d'usuari ja existeix en la llista d'usuaris de sistema",
|
||||
"this_action_broke_dpkg": "Aquesta acció a trencat dpkg/APT (els gestors de paquets del sistema)... Podeu intentar resoldre el problema connectant-vos amb SSH i executant «sudo apt install --fix-broken» i/o «sudo dpkg --configure -a».",
|
||||
"tools_upgrade_at_least_one": "Especifiqueu «--apps», o «--system»",
|
||||
"tools_upgrade_at_least_one": "Especifiqueu «apps», o «system»",
|
||||
"tools_upgrade_cant_both": "No es poden actualitzar tant el sistema com les aplicacions al mateix temps",
|
||||
"tools_upgrade_cant_hold_critical_packages": "No es poden mantenir els paquets crítics…",
|
||||
"tools_upgrade_cant_unhold_critical_packages": "No es poden deixar de mantenir els paquets crítics…",
|
||||
"tools_upgrade_regular_packages": "Actualitzant els paquets «normals» (no relacionats amb YunoHost)…",
|
||||
"tools_upgrade_cant_hold_critical_packages": "No es poden mantenir els paquets crítics...",
|
||||
"tools_upgrade_cant_unhold_critical_packages": "No es poden deixar de mantenir els paquets crítics...",
|
||||
"tools_upgrade_regular_packages": "Actualitzant els paquets «normals» (no relacionats amb YunoHost)...",
|
||||
"tools_upgrade_regular_packages_failed": "No s'han pogut actualitzar els paquets següents: {packages_list}",
|
||||
"tools_upgrade_special_packages": "Actualitzant els paquets «especials» (relacionats amb YunoHost)…",
|
||||
"tools_upgrade_special_packages": "Actualitzant els paquets «especials» (relacionats amb YunoHost)...",
|
||||
"tools_upgrade_special_packages_explanation": "Aquesta actualització especial continuarà en segon pla. No comenceu cap altra acció al servidor en els pròxims ~10 minuts (depèn de la velocitat del maquinari). Després d'això, pot ser que us hagueu de tornar a connectar a la interfície d'administració. Els registres de l'actualització estaran disponibles a Eines → Registres (a la interfície d'administració) o utilitzant «yunohost log list» (des de la línia d'ordres).",
|
||||
"tools_upgrade_special_packages_completed": "Actualització dels paquets YunoHost acabada.\nPremeu [Enter] per tornar a la línia d'ordres",
|
||||
"unbackup_app": "{app} no es guardarà",
|
||||
|
@ -345,7 +342,7 @@
|
|||
"user_creation_failed": "No s'ha pogut crear l'usuari {user}: {error}",
|
||||
"user_deleted": "S'ha suprimit l'usuari",
|
||||
"user_deletion_failed": "No s'ha pogut suprimir l'usuari {user}: {error}",
|
||||
"user_home_creation_failed": "No s'ha pogut crear la carpeta personal «home» per l'usuari",
|
||||
"user_home_creation_failed": "No s'ha pogut crear la carpeta personal «{home}» per l'usuari",
|
||||
"user_unknown": "Usuari desconegut: {user}",
|
||||
"user_update_failed": "No s'ha pogut actualitzar l'usuari {user}: {error}",
|
||||
"user_updated": "S'ha canviat la informació de l'usuari",
|
||||
|
@ -472,7 +469,7 @@
|
|||
"diagnosis_http_unreachable": "Sembla que el domini {domain} no és accessible a través de HTTP des de fora de la xarxa local.",
|
||||
"diagnosis_unknown_categories": "Les següents categories són desconegudes: {categories}",
|
||||
"apps_catalog_init_success": "S'ha iniciat el sistema de catàleg d'aplicacions!",
|
||||
"apps_catalog_updating": "S'està actualitzant el catàleg d'aplicacions…",
|
||||
"apps_catalog_updating": "S'està actualitzant el catàleg d'aplicacions...",
|
||||
"apps_catalog_failed_to_download": "No s'ha pogut descarregar el catàleg d'aplicacions {apps_catalog}: {error}",
|
||||
"apps_catalog_obsolete_cache": "La memòria cau del catàleg d'aplicacions és buida o obsoleta.",
|
||||
"apps_catalog_update_success": "S'ha actualitzat el catàleg d'aplicacions!",
|
||||
|
@ -485,14 +482,12 @@
|
|||
"diagnosis_no_cache": "Encara no hi ha memòria cau pel diagnòstic de la categoria «{category}»",
|
||||
"diagnosis_http_timeout": "S'ha exhaurit el temps d'esperar intentant connectar amb el servidor des de l'exterior.<br>1. La causa més probable per a aquest problema és que el port 80 (i 443) <a href='https://yunohost.org/isp_box_config'>no reenvien correctament cap al vostre servidor</a>.<br>2. També us hauríeu d'assegurar que el servei nginx estigui funcionant<br>3. En configuracions més complexes: assegureu-vos que no hi ha cap tallafoc o reverse-proxy interferint.",
|
||||
"diagnosis_http_connection_error": "Error de connexió: no s'ha pogut connectar amb el domini demanat, segurament és inaccessible.",
|
||||
"yunohost_postinstall_end_tip": "S'ha completat la post-instal·lació. Per acabar la configuració, considereu:\n - afegir un primer usuari a través de la secció «Usuaris» a la pàgina web d'administració (o emprant «yunohost user create <username>» a la línia d'ordres);\n - diagnosticar possibles problemes a través de la secció «Diagnòstics» a la pàgina web d'administració (o emprant «yunohost diagnosis run» a la línia d'ordres);\n - llegir les seccions «Finalizing your setup» i «Getting to know Yunohost» a la documentació per administradors: https://yunohost.org/admindoc.",
|
||||
"yunohost_postinstall_end_tip": "S'ha completat la post-instal·lació. Per acabar la configuració, considereu:\n - afegir un primer usuari a través de la secció «Usuaris» a la pàgina web d'administració (o emprant «yunohost user create <username>» a la línia d'ordres);\n - diagnosticar possibles problemes a través de la secció «Diagnòstics» a la pàgina web d'administració (o emprant «yunohost diagnosis run» a la línia d'ordres);\n - llegir les seccions «Finalizing your setup» i «Getting to know YunoHost» a la documentació per administradors: https://yunohost.org/admindoc.",
|
||||
"diagnosis_services_running": "El servei {service} s'està executant!",
|
||||
"diagnosis_services_conf_broken": "La configuració pel servei {service} està trencada!",
|
||||
"diagnosis_ports_needed_by": "És necessari exposar aquest port per a les funcions {category} (servei {service})",
|
||||
"global_settings_setting_pop3_enabled": "Activa el protocol POP3 per al servidor de correu",
|
||||
"log_app_action_run": "Executa l'acció de l'aplicació «{}»",
|
||||
"log_app_config_show_panel": "Mostra el taulell de configuració de l'aplicació «{}»",
|
||||
"log_app_config_apply": "Afegeix la configuració a l'aplicació «{}»",
|
||||
"diagnosis_never_ran_yet": "Sembla que el servidor s'ha configurat recentment i encara no hi cap informe de diagnòstic per mostrar. S'ha d'executar un diagnòstic complet primer, ja sigui des de la pàgina web d'administració o utilitzant la comanda «yunohost diagnosis run» al terminal.",
|
||||
"diagnosis_description_web": "Web",
|
||||
"diagnosis_basesystem_hardware": "L'arquitectura del maquinari del servidor és {virt} {arch}",
|
||||
|
|
|
@ -1 +1 @@
|
|||
{}
|
||||
{}
|
|
@ -11,7 +11,6 @@
|
|||
"action_invalid": "Nesprávné akce '{action}'",
|
||||
"aborting": "Zrušeno.",
|
||||
"app_change_url_identical_domains": "Stará a nová doména/url_cesta jsou totožné ('{domain}{path}'), nebudou provedeny žádné změny.",
|
||||
"app_change_url_failed_nginx_reload": "Nepodařilo se znovunačís NGINX. Následuje výpis příkazu 'nginx -t':\n{nginx_errors}",
|
||||
"app_argument_invalid": "Vyberte správnou hodnotu pro argument '{name}': {error}",
|
||||
"app_argument_choice_invalid": "Vyberte jednu z možností '{choices}' pro argument'{name}'",
|
||||
"app_already_up_to_date": "{app} aplikace je/jsou aktuální",
|
||||
|
@ -55,7 +54,7 @@
|
|||
"global_settings_setting_smtp_relay_password": "SMTP relay heslo uživatele/hostitele",
|
||||
"global_settings_setting_smtp_relay_user": "SMTP relay uživatelské jméno/účet",
|
||||
"global_settings_setting_smtp_relay_port": "SMTP relay port",
|
||||
"global_settings_setting_smtp_relay_host": "Použít SMTP relay hostitele pro odesílání emailů místo této Yunohost instance. Užitečné v různých situacích: port 25 je blokován vaším ISP nebo VPS poskytovatelem, IP adresa je na blacklistu (např. DUHL), nemůžete nastavit reverzní DNS záznam nebo tento server není přímo připojen do internetu a vy chcete použít jiný server k odesílání emailů.",
|
||||
"global_settings_setting_smtp_relay_host": "Použít SMTP relay hostitele pro odesílání emailů místo této YunoHost instance. Užitečné v různých situacích: port 25 je blokován vaším ISP nebo VPS poskytovatelem, IP adresa je na blacklistu (např. DUHL), nemůžete nastavit reverzní DNS záznam nebo tento server není přímo připojen do internetu a vy chcete použít jiný server k odesílání emailů.",
|
||||
"global_settings_setting_smtp_allow_ipv6": "Povolit použití IPv6 pro příjem a odesílání emailů",
|
||||
"global_settings_setting_ssowat_panel_overlay_enabled": "Povolit SSOwat překryvný panel",
|
||||
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Povolit použití (zastaralého) DSA klíče hostitele pro konfiguraci SSH služby",
|
||||
|
|
|
@ -47,9 +47,8 @@
|
|||
"domain_dyndns_root_unknown": "Unbekannte DynDNS Hauptdomain",
|
||||
"domain_exists": "Die Domäne existiert bereits",
|
||||
"domain_uninstall_app_first": "Diese Applikationen sind noch auf Ihrer Domäne installiert; \n{apps}\n\nBitte deinstallieren Sie sie mit dem Befehl 'yunohost app remove the_app_id' oder verschieben Sie sie mit 'yunohost app change-url the_app_id'",
|
||||
"domain_unknown": "Unbekannte Domain",
|
||||
"done": "Erledigt",
|
||||
"downloading": "Wird heruntergeladen…",
|
||||
"downloading": "Wird heruntergeladen...",
|
||||
"dyndns_ip_update_failed": "Konnte die IP-Adresse für DynDNS nicht aktualisieren",
|
||||
"dyndns_ip_updated": "Aktualisierung Ihrer IP-Adresse bei DynDNS",
|
||||
"dyndns_key_generating": "Generierung des DNS-Schlüssels..., das könnte eine Weile dauern.",
|
||||
|
@ -92,8 +91,8 @@
|
|||
"restore_failed": "Das System konnte nicht wiederhergestellt werden",
|
||||
"restore_hook_unavailable": "Das Wiederherstellungsskript für '{part}' steht weder in Ihrem System noch im Archiv zur Verfügung",
|
||||
"restore_nothings_done": "Nichts wurde wiederhergestellt",
|
||||
"restore_running_app_script": "App '{app}' wird wiederhergestellt…",
|
||||
"restore_running_hooks": "Wiederherstellung wird gestartet…",
|
||||
"restore_running_app_script": "App '{app}' wird wiederhergestellt...",
|
||||
"restore_running_hooks": "Wiederherstellung wird gestartet...",
|
||||
"service_add_failed": "Der Dienst '{service}' konnte nicht hinzugefügt werden",
|
||||
"service_added": "Der Dienst '{service}' wurde erfolgreich hinzugefügt",
|
||||
"service_already_started": "Der Dienst '{service}' läuft bereits",
|
||||
|
@ -140,7 +139,6 @@
|
|||
"app_not_properly_removed": "{app} wurde nicht ordnungsgemäß entfernt",
|
||||
"not_enough_disk_space": "Nicht genügend Speicherplatz auf '{path}' frei",
|
||||
"backup_creation_failed": "Konnte Backup-Archiv nicht erstellen",
|
||||
"pattern_positive_number": "Muss eine positive Zahl sein",
|
||||
"app_not_correctly_installed": "{app} scheint nicht korrekt installiert zu sein",
|
||||
"app_requirements_checking": "Überprüfe notwendige Pakete für {app}...",
|
||||
"app_requirements_unmeet": "Anforderungen für {app} werden nicht erfüllt, das Paket {pkgname} ({version}) muss {spec} sein",
|
||||
|
@ -170,7 +168,6 @@
|
|||
"certmanager_unable_to_parse_self_CA_name": "Der Name der Zertifizierungsstelle für selbstsignierte Zertifikate konnte nicht aufgelöst werden (Datei: {file})",
|
||||
"domain_hostname_failed": "Sie können keinen neuen Hostnamen verwenden. Das kann zukünftige Probleme verursachen (es kann auch sein, dass es funktioniert).",
|
||||
"app_already_installed_cant_change_url": "Diese Applikation ist bereits installiert. Die URL kann durch diese Funktion nicht modifiziert werden. Überprüfe ob `app changeurl` verfügbar ist.",
|
||||
"app_change_url_failed_nginx_reload": "NGINX konnte nicht neu gestartet werden. Hier ist der Output von 'nginx -t':\n{nginx_errors}",
|
||||
"app_change_url_identical_domains": "Die alte und neue domain/url_path sind identisch: ('{domain} {path}'). Es gibt nichts zu tun.",
|
||||
"app_already_up_to_date": "{app} ist bereits aktuell",
|
||||
"backup_abstract_method": "Diese Backup-Methode wird noch nicht unterstützt",
|
||||
|
@ -241,10 +238,10 @@
|
|||
"log_operation_unit_unclosed_properly": "Die Operationseinheit wurde nicht richtig geschlossen",
|
||||
"global_settings_setting_security_postfix_compatibility": "Kompatibilitäts- vs. Sicherheits-Kompromiss für den Postfix-Server. Betrifft die Ciphers (und andere sicherheitsrelevante Aspekte)",
|
||||
"global_settings_unknown_type": "Unerwartete Situation, die Einstellung {setting} scheint den Typ {unknown_type} zu haben, ist aber kein vom System unterstützter Typ.",
|
||||
"dpkg_is_broken": "Du kannst das gerade nicht tun, weil dpkg/APT (der Systempaketmanager) in einem defekten Zustand zu sein scheint.... Du kannst versuchen, dieses Problem zu lösen, indem du dich über SSH verbindest und `sudo apt install --fix-broken` sowie/oder `sudo dpkg --configure -a` ausführst.",
|
||||
"dpkg_is_broken": "Du kannst das gerade nicht tun, weil dpkg/APT (der Systempaketmanager) in einem defekten Zustand zu sein scheint... Du kannst versuchen, dieses Problem zu lösen, indem du dich über SSH verbindest und `sudo apt install --fix-broken` sowie/oder `sudo dpkg --configure -a` ausführst.",
|
||||
"global_settings_unknown_setting_from_settings_file": "Unbekannter Schlüssel in den Einstellungen: '{setting_key}', verwerfen und speichern in /etc/yunohost/settings-unknown.json",
|
||||
"log_link_to_log": "Vollständiges Log dieser Operation: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'",
|
||||
"log_help_to_get_log": "Um das Protokoll der Operation '{desc}' anzuzeigen, verwenden Sie den Befehl 'yunohost log show {name}{name}'",
|
||||
"log_help_to_get_log": "Um das Protokoll der Operation '{desc}' anzuzeigen, verwenden Sie den Befehl 'yunohost log show {name}'",
|
||||
"global_settings_setting_security_nginx_compatibility": "Kompatibilitäts- vs. Sicherheits-Kompromiss für den Webserver NGINX. Betrifft die Ciphers (und andere sicherheitsrelevante Aspekte)",
|
||||
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Erlaubt die Verwendung eines (veralteten) DSA-Hostkeys für die SSH-Daemon-Konfiguration",
|
||||
"log_app_remove": "Entferne die Applikation '{}'",
|
||||
|
@ -279,7 +276,7 @@
|
|||
"diagnosis_basesystem_ynh_main_version": "Server läuft YunoHost {main_version} ({repo})",
|
||||
"diagnosis_basesystem_ynh_inconsistent_versions": "Sie verwenden inkonsistente Versionen der YunoHost-Pakete... wahrscheinlich wegen eines fehlgeschlagenen oder teilweisen Upgrades.",
|
||||
"apps_catalog_init_success": "App-Katalogsystem initialisiert!",
|
||||
"apps_catalog_updating": "Aktualisierung des Applikationskatalogs…",
|
||||
"apps_catalog_updating": "Aktualisierung des Applikationskatalogs...",
|
||||
"apps_catalog_failed_to_download": "Der {apps_catalog} App-Katalog kann nicht heruntergeladen werden: {error}",
|
||||
"apps_catalog_obsolete_cache": "Der Cache des App-Katalogs ist leer oder veraltet.",
|
||||
"apps_catalog_update_success": "Der Apps-Katalog wurde aktualisiert!",
|
||||
|
@ -432,9 +429,9 @@
|
|||
"additional_urls_already_removed": "Zusätzliche URL '{url}' bereits entfernt in der zusätzlichen URL für Berechtigung '{permission}'",
|
||||
"app_label_deprecated": "Dieser Befehl ist veraltet! Bitte nutzen Sie den neuen Befehl 'yunohost user permission update' um das Applabel zu verwalten.",
|
||||
"diagnosis_http_hairpinning_issue_details": "Das ist wahrscheinlich aufgrund Ihrer ISP Box / Router. Als Konsequenz können Personen von ausserhalb Ihres Netzwerkes aber nicht von innerhalb Ihres lokalen Netzwerkes (wie wahrscheinlich Sie selber?) wie gewohnt auf Ihren Server zugreifen, wenn Sie ihre Domäne oder Ihre öffentliche IP verwenden. Sie können die Situation wahrscheinlich verbessern, indem Sie ein einen Blick in <a href='https://yunohost.org/dns_local_network'>https://yunohost.org/dns_local_network</a> werfen",
|
||||
"diagnosis_http_nginx_conf_not_up_to_date": "Jemand hat anscheinend die Konfiguration von Nginx manuell geändert. Diese Änderung verhindert, dass Yunohost eine Diagnose durchführen kann, wenn er via HTTP erreichbar ist.",
|
||||
"diagnosis_http_nginx_conf_not_up_to_date": "Jemand hat anscheinend die Konfiguration von Nginx manuell geändert. Diese Änderung verhindert, dass YunoHost eine Diagnose durchführen kann, wenn er via HTTP erreichbar ist.",
|
||||
"diagnosis_http_bad_status_code": "Anscheinend beantwortet ein anderes Gerät als Ihr Server die Anfrage (Vielleicht ihr Internetrouter).<br>1. Die häufigste Ursache ist, dass Port 80 (und 443) <a href='https://yunohost.org/isp_box_config'>nicht richtig auf Ihren Server weitergeleitet wird</a>.<br> 2. Bei komplexeren Setups: Vergewissern Sie sich, dass keine Firewall und keine Reverse-Proxy interferieren.",
|
||||
"diagnosis_never_ran_yet": "Sie haben kürzlich einen neuen Yunohost-Server installiert aber es gibt davon noch keinen Diagnosereport. Sie sollten eine Diagnose anstossen. Sie können das entweder vom Webadmin aus oder in der Kommandozeile machen. In der Kommandozeile verwenden Sie dafür den Befehl 'yunohost diagnosis run'.",
|
||||
"diagnosis_never_ran_yet": "Sie haben kürzlich einen neuen YunoHost-Server installiert aber es gibt davon noch keinen Diagnosereport. Sie sollten eine Diagnose anstossen. Sie können das entweder vom Webadmin aus oder in der Kommandozeile machen. In der Kommandozeile verwenden Sie dafür den Befehl 'yunohost diagnosis run'.",
|
||||
"diagnosis_http_nginx_conf_not_up_to_date_details": "Um dieses Problem zu beheben, geben Sie in der Kommandozeile <cmd>yunohost tools regen-conf nginx --dry-run --with-diff</cmd> ein. Dieses Tool zeigt ihnen den Unterschied an. Wenn Sie damit einverstanden sind, können Sie mit <cmd>yunohost tools regen-conf nginx --force</cmd> die Änderungen übernehmen.",
|
||||
"diagnosis_backports_in_sources_list": "Sie haben anscheinend apt (den Paketmanager) für das Backports-Repository konfiguriert. Wir raten strikte davon ab, Pakete aus dem Backports-Repository zu installieren. Diese würden wahrscheinlich zu Instabilitäten und Konflikten führen. Es sei denn, Sie wissen was Sie tun.",
|
||||
"diagnosis_basesystem_hardware_model": "Das Servermodell ist {model}",
|
||||
|
@ -442,8 +439,8 @@
|
|||
"group_user_not_in_group": "Der Benutzer {user} ist nicht in der Gruppe {group}",
|
||||
"group_user_already_in_group": "Der Benutzer {user} ist bereits in der Gruppe {group}",
|
||||
"group_cannot_edit_visitors": "Die Gruppe \"Besucher\" kann nicht manuell editiert werden. Sie ist eine Sondergruppe und repräsentiert anonyme Besucher",
|
||||
"group_cannot_edit_all_users": "Die Gruppe \"all_users\" kann nicht manuell editiert werden. Sie ist eine Sondergruppe die dafür gedacht ist alle Benutzer in Yunohost zu halten",
|
||||
"group_already_exist_on_system_but_removing_it": "Die Gruppe {group} existiert bereits in den Systemgruppen, aber Yunohost wird sie entfernen...",
|
||||
"group_cannot_edit_all_users": "Die Gruppe \"all_users\" kann nicht manuell editiert werden. Sie ist eine Sondergruppe die dafür gedacht ist alle Benutzer in YunoHost zu halten",
|
||||
"group_already_exist_on_system_but_removing_it": "Die Gruppe {group} existiert bereits in den Systemgruppen, aber YunoHost wird sie entfernen...",
|
||||
"group_already_exist_on_system": "Die Gruppe {group} existiert bereits in den Systemgruppen",
|
||||
"group_already_exist": "Die Gruppe {group} existiert bereits",
|
||||
"global_settings_setting_smtp_relay_password": "SMTP Relay Host Passwort",
|
||||
|
@ -460,8 +457,6 @@
|
|||
"log_backup_restore_app": "'{}' aus einem Backup-Archiv wiederherstellen",
|
||||
"log_backup_restore_system": "System aus einem Backup-Archiv wiederherstellen",
|
||||
"log_available_on_yunopaste": "Das Protokoll ist nun via {url} verfügbar",
|
||||
"log_app_config_apply": "Wende die Konfiguration auf die Applikation '{}' an",
|
||||
"log_app_config_show_panel": "Zeige das Konfigurations-Panel der Applikation '{}'",
|
||||
"log_app_action_run": "Führe Aktion der Applikation '{}' aus",
|
||||
"invalid_regex": "Ungültige Regex:'{regex}'",
|
||||
"migration_description_0016_php70_to_php73_pools": "Migrieren der php7.0-fpm-Konfigurationsdateien zu php7.3",
|
||||
|
@ -566,13 +561,13 @@
|
|||
"regenconf_updated": "Konfiguration aktualisiert für '{category}'",
|
||||
"regenconf_pending_applying": "Wende die anstehende Konfiguration für die Kategorie {category} an...",
|
||||
"regenconf_failed": "Konnte die Konfiguration für die Kategorie(n) {categories} nicht neu erstellen",
|
||||
"regenconf_dry_pending_applying": "Überprüfe die anstehende Konfiguration, welche für die Kategorie {category}' aktualisiert worden wäre…",
|
||||
"regenconf_dry_pending_applying": "Überprüfe die anstehende Konfiguration, welche für die Kategorie {category}' aktualisiert worden wäre...",
|
||||
"regenconf_would_be_updated": "Die Konfiguration wäre für die Kategorie '{category}' aktualisiert worden",
|
||||
"restore_system_part_failed": "Die Systemteile '{part}' konnten nicht wiederhergestellt werden",
|
||||
"restore_removing_tmp_dir_failed": "Ein altes, temporäres Directory konnte nicht entfernt werden",
|
||||
"restore_not_enough_disk_space": "Nicht genug Speicher (Speicher: {free_space} B, benötigter Speicher: {needed_space} B, Sicherheitspuffer: {margin} B)",
|
||||
"restore_may_be_not_enough_disk_space": "Ihr System scheint nicht genug Speicherplatz zu haben (frei: {free_space} B, benötigter Platz: {needed_space} B, Sicherheitspuffer: {margin} B)",
|
||||
"restore_extracting": "Packe die benötigten Dateien aus dem Archiv aus…",
|
||||
"restore_extracting": "Packe die benötigten Dateien aus dem Archiv aus...",
|
||||
"restore_already_installed_apps": "Folgende Apps können nicht wiederhergestellt werden, weil sie schon installiert sind: {apps}",
|
||||
"regex_with_only_domain": "Du kannst regex nicht als Domain verwenden, sondern nur als Pfad",
|
||||
"root_password_desynchronized": "Das Admin-Passwort wurde verändert, aber das Root-Passwort ist immer noch das alte!",
|
||||
|
@ -617,16 +612,16 @@
|
|||
"show_tile_cant_be_enabled_for_regex": "Momentan können Sie 'show_tile' nicht aktivieren, weil die URL für die Berechtigung '{permission}' ein regulärer Ausdruck ist",
|
||||
"show_tile_cant_be_enabled_for_url_not_defined": "Momentan können Sie 'show_tile' nicht aktivieren, weil Sie zuerst eine URL für die Berechtigung '{permission}' definieren müssen",
|
||||
"tools_upgrade_regular_packages_failed": "Konnte für die folgenden Pakete das Upgrade nicht durchführen: {packages_list}",
|
||||
"tools_upgrade_regular_packages": "Momentan werden Upgrades für das System (YunoHost-unabhängige) Pakete durchgeführt…",
|
||||
"tools_upgrade_cant_unhold_critical_packages": "Konnte für die kritischen Pakete das Flag 'hold' nicht aufheben…",
|
||||
"tools_upgrade_cant_hold_critical_packages": "Konnte für die kritischen Pakete das Flag 'hold' nicht setzen…",
|
||||
"tools_upgrade_regular_packages": "Momentan werden Upgrades für das System (YunoHost-unabhängige) Pakete durchgeführt...",
|
||||
"tools_upgrade_cant_unhold_critical_packages": "Konnte für die kritischen Pakete das Flag 'hold' nicht aufheben...",
|
||||
"tools_upgrade_cant_hold_critical_packages": "Konnte für die kritischen Pakete das Flag 'hold' nicht setzen...",
|
||||
"tools_upgrade_cant_both": "Kann das Upgrade für das System und die Applikation nicht gleichzeitig durchführen",
|
||||
"tools_upgrade_at_least_one": "Bitte geben Sie '--apps' oder '--system' an",
|
||||
"this_action_broke_dpkg": "Diese Aktion hat unkonfigurierte Pakete verursacht, welche durch dpkg/apt (die Paketverwaltungen dieses Systems) zurückgelassen wurden... Sie können versuchen dieses Problem zu lösen, indem Sie 'sudo apt install --fix-broken' und/oder 'sudo dpkg --configure -a' ausführen.",
|
||||
"update_apt_cache_failed": "Kann den Cache von APT (Debians Paketmanager) nicht aktualisieren. Hier ist ein Auszug aus den sources.list-Zeilen, die helfen könnten, das Problem zu identifizieren:\n{sourceslist}",
|
||||
"tools_upgrade_special_packages_completed": "YunoHost-Paketupdate beendet.\nDrücke [Enter], um zurück zur Kommandoziele zu kommen",
|
||||
"tools_upgrade_special_packages_explanation": "Das Upgrade \"special\" wird im Hintergrund ausgeführt. Bitte starten Sie keine anderen Aktionen auf Ihrem Server für die nächsten ~10 Minuten. Die Dauer ist abhängig von der Geschwindigkeit Ihres Servers. Nach dem Upgrade müssen Sie sich eventuell erneut in das Adminportal einloggen. Upgrade-Logs sind im Adminbereich unter Tools → Log verfügbar. Alternativ können Sie in der Befehlszeile 'yunohost log list' eingeben.",
|
||||
"tools_upgrade_special_packages": "\"special\" (YunoHost-bezogene) Pakete werden jetzt aktualisiert…",
|
||||
"tools_upgrade_special_packages": "\"special\" (YunoHost-bezogene) Pakete werden jetzt aktualisiert...",
|
||||
"unknown_main_domain_path": "Unbekannte:r Domain oder Pfad für '{app}'. Du musst eine Domain und einen Pfad setzen, um die URL für Berechtigungen zu setzen.",
|
||||
"yunohost_postinstall_end_tip": "Post-install ist fertig! Um das Setup abzuschliessen, wird empfohlen:\n - einen ersten Benutzer über den Bereich 'Benutzer*in' im Adminbereich hinzuzufügen (oder mit 'yunohost user create <username>' in der Kommandezeile);\n - mögliche Fehler zu diagnostizieren über den Bereich 'Diagnose' im Adminbereich (oder mit 'yunohost diagnosis run' in der Kommandozeile;\n - Die Abschnitte 'Install YunoHost' und 'Geführte Tour' im Administratorenhandbuch zu lesen: https://yunohost.org/admindoc.",
|
||||
"user_already_exists": "Der Benutzer '{user}' ist bereits vorhanden",
|
||||
|
@ -634,5 +629,6 @@
|
|||
"global_settings_setting_security_webadmin_allowlist": "IP-Adressen, die auf die Verwaltungsseite zugreifen dürfen. Kommasepariert.",
|
||||
"global_settings_setting_security_webadmin_allowlist_enabled": "Erlaube nur bestimmten IP-Adressen den Zugriff auf die Verwaltungsseite.",
|
||||
"disk_space_not_sufficient_update": "Es ist nicht genügend Speicherplatz frei, um diese Applikation zu aktuallisieren",
|
||||
"disk_space_not_sufficient_install": "Es ist nicht genügend Speicherplatz frei, um diese Applikation zu installieren"
|
||||
}
|
||||
"disk_space_not_sufficient_install": "Es ist nicht genügend Speicherplatz frei, um diese Applikation zu installieren",
|
||||
"danger": "Warnung:"
|
||||
}
|
|
@ -13,14 +13,17 @@
|
|||
"app_already_installed": "{app} is already installed",
|
||||
"app_already_installed_cant_change_url": "This app is already installed. The URL cannot be changed just by this function. Check in `app changeurl` if it's available.",
|
||||
"app_already_up_to_date": "{app} is already up-to-date",
|
||||
"app_argument_choice_invalid": "Use one of these choices '{choices}' for the argument '{name}'",
|
||||
"app_argument_choice_invalid": "Use one of these choices '{choices}' for the argument '{name}' instead of '{value}'",
|
||||
"app_argument_invalid": "Pick a valid value for the argument '{name}': {error}",
|
||||
"app_argument_password_help_keep": "Press Enter to keep the current value",
|
||||
"app_argument_password_help_optional": "Type one space to empty the password",
|
||||
"app_argument_password_no_default": "Error while parsing password argument '{name}': password argument can't have a default value for security reason",
|
||||
"app_argument_required": "Argument '{name}' is required",
|
||||
"app_change_url_failed_nginx_reload": "Could not reload NGINX. Here is the output of 'nginx -t':\n{nginx_errors}",
|
||||
"app_change_url_identical_domains": "The old and new domain/url_path are identical ('{domain}{path}'), nothing to do.",
|
||||
"app_change_url_no_script": "The app '{app_name}' doesn't support URL modification yet. Maybe you should upgrade it.",
|
||||
"app_change_url_success": "{app} URL is now {domain}{path}",
|
||||
"app_config_unable_to_apply": "Failed to apply config panel values.",
|
||||
"app_config_unable_to_read": "Failed to read config panel values.",
|
||||
"app_extraction_failed": "Could not extract the installation files",
|
||||
"app_full_domain_unavailable": "Sorry, this app must be installed on a domain of its own, but other apps are already installed on the domain '{domain}'. You could use a subdomain dedicated to this app instead.",
|
||||
"app_id_invalid": "Invalid app ID",
|
||||
|
@ -139,10 +142,22 @@
|
|||
"certmanager_self_ca_conf_file_not_found": "Could not find configuration file for self-signing authority (file: {file})",
|
||||
"certmanager_unable_to_parse_self_CA_name": "Could not parse name of self-signing authority (file: {file})",
|
||||
"certmanager_warning_subdomain_dns_record": "Subdomain '{subdomain}' does not resolve to the same IP address as '{domain}'. Some features will not be available until you fix this and regenerate the certificate.",
|
||||
"config_apply_failed": "Applying the new configuration failed: {error}",
|
||||
"config_cant_set_value_on_section": "You can't set a single value on an entire config section.",
|
||||
"config_forbidden_keyword": "The keyword '{keyword}' is reserved, you can't create or use a config panel with a question with this id.",
|
||||
"config_no_panel": "No config panel found.",
|
||||
"config_unknown_filter_key": "The filter key '{filter_key}' is incorrect.",
|
||||
"config_validate_color": "Should be a valid RGB hexadecimal color",
|
||||
"config_validate_date": "Should be a valid date like in the format YYYY-MM-DD",
|
||||
"config_validate_email": "Should be a valid email",
|
||||
"config_validate_time": "Should be a valid time like HH:MM",
|
||||
"config_validate_url": "Should be a valid web URL",
|
||||
"config_version_not_supported": "Config panel versions '{version}' are not supported.",
|
||||
"confirm_app_install_danger": "DANGER! This app is known to be still experimental (if not explicitly not working)! You should probably NOT install it unless you know what you are doing. NO SUPPORT will be provided if this app doesn't work or breaks your system... If you are willing to take that risk anyway, type '{answers}'",
|
||||
"confirm_app_install_thirdparty": "DANGER! This app is not part of YunoHost's app catalog. Installing third-party apps may compromise the integrity and security of your system. You should probably NOT install it unless you know what you are doing. NO SUPPORT will be provided if this app doesn't work or breaks your system... If you are willing to take that risk anyway, type '{answers}'",
|
||||
"confirm_app_install_warning": "Warning: This app may work, but is not well-integrated in YunoHost. Some features such as single sign-on and backup/restore might not be available. Install anyway? [{answers}] ",
|
||||
"custom_app_url_required": "You must provide a URL to upgrade your custom app {app}",
|
||||
"danger": "Danger:",
|
||||
"diagnosis_apps_allgood": "All installed apps respect basic packaging practices",
|
||||
"diagnosis_apps_bad_quality": "This application is currently flagged as broken on YunoHost's application catalog. This may be a temporary issue while the maintainers attempt to fix the issue. In the meantime, upgrading this app is disabled.",
|
||||
"diagnosis_apps_broken": "This application is currently flagged as broken on YunoHost's application catalog. This may be a temporary issue while the maintainers attempt to fix the issue. In the meantime, upgrading this app is disabled.",
|
||||
|
@ -302,7 +317,34 @@
|
|||
"domain_name_unknown": "Domain '{domain}' unknown",
|
||||
"domain_remove_confirm_apps_removal": "Removing this domain will remove those applications:\n{apps}\n\nAre you sure you want to do that? [{answers}]",
|
||||
"domain_uninstall_app_first": "Those applications are still installed on your domain:\n{apps}\n\nPlease uninstall them using 'yunohost app remove the_app_id' or move them to another domain using 'yunohost app change-url the_app_id' before proceeding to domain removal",
|
||||
"domain_unknown": "Unknown domain",
|
||||
"domain_registrar_is_not_configured": "The registrar is not yet configured for domain {domain}.",
|
||||
"domain_dns_push_not_applicable": "The automatic DNS configuration feature is not applicable to domain {domain}. You should manually configure your DNS records following the documentation at https://yunohost.org/dns_config.",
|
||||
"domain_dns_push_managed_in_parent_domain": "The automatic DNS configuration feature is managed in the parent domain {parent_domain}.",
|
||||
"domain_dns_registrar_managed_in_parent_domain": "This domain is a subdomain of {parent_domain_link}. DNS registrar configuration should be managed in {parent_domain}'s configuration panel.",
|
||||
"domain_dns_registrar_yunohost": "This domain is a nohost.me / nohost.st / ynh.fr and its DNS configuration is therefore automatically handled by YunoHost without any further configuration. (see the 'yunohost dyndns update' command)",
|
||||
"domain_dns_registrar_not_supported": "YunoHost could not automatically detect the registrar handling this domain. You should manually configure your DNS records following the documentation at https://yunohost.org/dns.",
|
||||
"domain_dns_registrar_supported": "YunoHost automatically detected that this domain is handled by the registrar **{registrar}**. If you want, YunoHost will automatically configure this DNS zone, if you provide it with the appropriate API credentials. You can find documentation on how to obtain your API credentials on this page: https://yunohost.org/registar_api_{registrar}. (You can also manually configure your DNS records following the documentation at https://yunohost.org/dns )",
|
||||
"domain_dns_registrar_experimental": "So far, the interface with **{registrar}**'s API has not been properly tested and reviewed by the YunoHost community. Support is **very experimental** - be careful!",
|
||||
"domain_dns_push_failed_to_authenticate": "Failed to authenticate on registrar's API for domain '{domain}'. Most probably the credentials are incorrect? (Error: {error})",
|
||||
"domain_dns_push_failed_to_list": "Failed to list current records using the registrar's API: {error}",
|
||||
"domain_dns_push_already_up_to_date": "Records already up to date, nothing to do.",
|
||||
"domain_dns_pushing": "Pushing DNS records...",
|
||||
"domain_dns_push_record_failed": "Failed to {action} record {type}/{name} : {error}",
|
||||
"domain_dns_push_success": "DNS records updated!",
|
||||
"domain_dns_push_failed": "Updating the DNS records failed miserably.",
|
||||
"domain_dns_push_partial_failure": "DNS records partially updated: some warnings/errors were reported.",
|
||||
"domain_config_features_disclaimer": "So far, enabling/disabling mail or XMPP features only impact the recommended and automatic DNS configuration, not system configurations!",
|
||||
"domain_config_mail_in": "Incoming emails",
|
||||
"domain_config_mail_out": "Outgoing emails",
|
||||
"domain_config_xmpp": "Instant messaging (XMPP)",
|
||||
"domain_config_auth_token": "Authentication token",
|
||||
"domain_config_auth_key": "Authentication key",
|
||||
"domain_config_auth_secret": "Authentication secret",
|
||||
"domain_config_api_protocol": "API protocol",
|
||||
"domain_config_auth_entrypoint": "API entry point",
|
||||
"domain_config_auth_application_key": "Application key",
|
||||
"domain_config_auth_application_secret": "Application secret key",
|
||||
"domain_config_auth_consumer_key": "Consumer key",
|
||||
"domains_available": "Available domains:",
|
||||
"done": "Done",
|
||||
"downloading": "Downloading...",
|
||||
|
@ -324,6 +366,7 @@
|
|||
"extracting": "Extracting...",
|
||||
"field_invalid": "Invalid field '{}'",
|
||||
"file_does_not_exist": "The file {path} does not exist.",
|
||||
"file_extension_not_accepted": "Refusing file '{path}' because its extension is not among the accepted extensions: {accept}",
|
||||
"firewall_reload_failed": "Could not reload the firewall",
|
||||
"firewall_reloaded": "Firewall reloaded",
|
||||
"firewall_rules_cmd_failed": "Some firewall rule commands have failed. More info in log.",
|
||||
|
@ -337,8 +380,8 @@
|
|||
"global_settings_setting_backup_compress_tar_archives": "When creating new backups, compress the archives (.tar.gz) instead of uncompressed archives (.tar). N.B. : enabling this option means create lighter backup archives, but the initial backup procedure will be significantly longer and heavy on CPU.",
|
||||
"global_settings_setting_pop3_enabled": "Enable the POP3 protocol for the mail server",
|
||||
"global_settings_setting_security_experimental_enabled": "Enable experimental security features (don't enable this if you don't know what you're doing!)",
|
||||
"global_settings_setting_security_nginx_redirect_to_https": "Redirect HTTP requests to HTTPs by default (DO NOT TURN OFF unless you really know what you're doing!)",
|
||||
"global_settings_setting_security_nginx_compatibility": "Compatibility vs. security tradeoff for the web server NGINX. Affects the ciphers (and other security-related aspects)",
|
||||
"global_settings_setting_security_nginx_redirect_to_https": "Redirect HTTP requests to HTTPs by default (DO NOT TURN OFF unless you really know what you're doing!)",
|
||||
"global_settings_setting_security_password_admin_strength": "Admin password strength",
|
||||
"global_settings_setting_security_password_user_strength": "User password strength",
|
||||
"global_settings_setting_security_postfix_compatibility": "Compatibility vs. security tradeoff for the Postfix server. Affects the ciphers (and other security-related aspects)",
|
||||
|
@ -380,16 +423,18 @@
|
|||
"hook_name_unknown": "Unknown hook name '{name}'",
|
||||
"installation_complete": "Installation completed",
|
||||
"invalid_number": "Must be a number",
|
||||
"invalid_number_min": "Must be greater than {min}",
|
||||
"invalid_number_max": "Must be lesser than {max}",
|
||||
"invalid_password": "Invalid password",
|
||||
"invalid_regex": "Invalid regex:'{regex}'",
|
||||
"ip6tables_unavailable": "You cannot play with ip6tables here. You are either in a container or your kernel does not support it",
|
||||
"iptables_unavailable": "You cannot play with iptables here. You are either in a container or your kernel does not support it",
|
||||
"ldap_server_down": "Unable to reach LDAP server",
|
||||
"ldap_server_is_down_restart_it": "The LDAP service is down, attempt to restart it...",
|
||||
"ldap_attribute_already_exists": "LDAP attribute '{attribute}' already exists with value '{value}'",
|
||||
"log_app_action_run": "Run action of the '{}' app",
|
||||
"log_app_change_url": "Change the URL of the '{}' app",
|
||||
"log_app_config_apply": "Apply config to the '{}' app",
|
||||
"log_app_config_show_panel": "Show the config panel of the '{}' app",
|
||||
"log_app_config_set": "Apply config to the '{}' app",
|
||||
"log_app_install": "Install the '{}' app",
|
||||
"log_app_makedefault": "Make '{}' the default app",
|
||||
"log_app_remove": "Remove the '{}' app",
|
||||
|
@ -401,12 +446,14 @@
|
|||
"log_corrupted_md_file": "The YAML metadata file associated with logs is damaged: '{md_file}\nError: {error}'",
|
||||
"log_does_exists": "There is no operation log with the name '{log}', use 'yunohost log list' to see all available operation logs",
|
||||
"log_domain_add": "Add '{}' domain into system configuration",
|
||||
"log_domain_config_set": "Update configuration for domain '{}'",
|
||||
"log_domain_main_domain": "Make '{}' the main domain",
|
||||
"log_domain_remove": "Remove '{}' domain from system configuration",
|
||||
"log_domain_dns_push": "Push DNS records for domain '{}'",
|
||||
"log_dyndns_subscribe": "Subscribe to a YunoHost subdomain '{}'",
|
||||
"log_dyndns_update": "Update the IP associated with your YunoHost subdomain '{}'",
|
||||
"log_help_to_get_failed_log": "The operation '{desc}' could not be completed. Please share the full log of this operation using the command 'yunohost log share {name}' to get help",
|
||||
"log_help_to_get_log": "To view the log of the operation '{desc}', use the command 'yunohost log show {name}{name}'",
|
||||
"log_help_to_get_log": "To view the log of the operation '{desc}', use the command 'yunohost log show {name}'",
|
||||
"log_letsencrypt_cert_install": "Install a Let's Encrypt certificate on '{}' domain",
|
||||
"log_letsencrypt_cert_renew": "Renew '{}' Let's Encrypt certificate",
|
||||
"log_link_to_failed_log": "Could not complete the operation '{desc}'. Please provide the full log of this operation by <a href=\"#/tools/logs/{name}\">clicking here</a> to get help",
|
||||
|
@ -529,7 +576,6 @@
|
|||
"pattern_password": "Must be at least 3 characters long",
|
||||
"pattern_password_app": "Sorry, passwords can not contain the following characters: {forbidden_chars}",
|
||||
"pattern_port_or_range": "Must be a valid port number (i.e. 0-65535) or range of ports (e.g. 100:200)",
|
||||
"pattern_positive_number": "Must be a positive number",
|
||||
"pattern_username": "Must be lower-case alphanumeric and underscore characters only",
|
||||
"permission_already_allowed": "Group '{group}' already has permission '{permission}' enabled",
|
||||
"permission_already_disallowed": "Group '{group}' already has permission '{permission}' disabled",
|
||||
|
@ -614,6 +660,7 @@
|
|||
"service_disabled": "The service '{service}' will not be started anymore when system boots.",
|
||||
"service_enable_failed": "Could not make the service '{service}' automatically start at boot.\n\nRecent service logs:{logs}",
|
||||
"service_enabled": "The service '{service}' will now be automatically started during system boots.",
|
||||
"service_not_reloading_because_conf_broken": "Not reloading/restarting service '{name}' because its configuration is broken: {errors}",
|
||||
"service_regen_conf_is_deprecated": "'yunohost service regen-conf' is deprecated! Please use 'yunohost tools regen-conf' instead.",
|
||||
"service_reload_failed": "Could not reload the service '{service}'\n\nRecent service logs:{logs}",
|
||||
"service_reload_or_restart_failed": "Could not reload or restart the service '{service}'\n\nRecent service logs:{logs}",
|
||||
|
@ -677,4 +724,4 @@
|
|||
"yunohost_installing": "Installing YunoHost...",
|
||||
"yunohost_not_installed": "YunoHost is not correctly installed. Please run 'yunohost tools postinstall'",
|
||||
"yunohost_postinstall_end_tip": "The post-install completed! To finalize your setup, please consider:\n - adding a first user through the 'Users' section of the webadmin (or 'yunohost user create <username>' in command-line);\n - diagnose potential issues through the 'Diagnosis' section of the webadmin (or 'yunohost diagnosis run' in command-line);\n - reading the 'Finalizing your setup' and 'Getting to know YunoHost' parts in the admin documentation: https://yunohost.org/admindoc."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,9 +28,8 @@
|
|||
"admin_password": "Pasvorto de la estro",
|
||||
"admin_password_too_long": "Bonvolu elekti pasvorton pli mallonga ol 127 signoj",
|
||||
"already_up_to_date": "Nenio por fari. Ĉio estas jam ĝisdatigita.",
|
||||
"app_argument_choice_invalid": "Uzu unu el ĉi tiuj elektoj '{choices}' por la argumento '{name}'",
|
||||
"app_argument_choice_invalid": "Uzu unu el ĉi tiuj elektoj '{choices}' por la argumento '{name}' anstataŭ '{value}'",
|
||||
"app_argument_invalid": "Elektu validan valoron por la argumento '{name}': {error}",
|
||||
"app_change_url_failed_nginx_reload": "Ne eblis reŝarĝi NGINX. Jen la eligo de 'nginx -t':\n{nginx_errors}",
|
||||
"ask_new_admin_password": "Nova administrada pasvorto",
|
||||
"app_action_broke_system": "Ĉi tiu ago ŝajne rompis ĉi tiujn gravajn servojn: {services}",
|
||||
"app_unsupported_remote_type": "Malkontrolita fora speco uzita por la apliko",
|
||||
|
@ -121,7 +120,7 @@
|
|||
"pattern_password": "Devas esti almenaŭ 3 signoj longaj",
|
||||
"root_password_desynchronized": "La pasvorta administranto estis ŝanĝita, sed YunoHost ne povis propagandi ĉi tion al la radika pasvorto!",
|
||||
"service_remove_failed": "Ne povis forigi la servon '{service}'",
|
||||
"backup_permission": "Rezerva permeso por app {app}",
|
||||
"backup_permission": "Rezerva permeso por {app}",
|
||||
"log_user_group_delete": "Forigi grupon '{}'",
|
||||
"log_user_group_update": "Ĝisdatigi grupon '{}'",
|
||||
"dyndns_provider_unreachable": "Ne povas atingi la provizanton DynDNS {provider}: ĉu via YunoHost ne estas ĝuste konektita al la interreto aŭ la dyneta servilo malŝaltiĝas.",
|
||||
|
@ -197,7 +196,6 @@
|
|||
"certmanager_acme_not_configured_for_domain": "Atestilo por la domajno '{domain}' ne ŝajnas esti ĝuste instalita. Bonvolu ekzekuti 'cert-instali' por ĉi tiu regado unue.",
|
||||
"user_update_failed": "Ne povis ĝisdatigi uzanton {user}: {error}",
|
||||
"restore_confirm_yunohost_installed": "Ĉu vi vere volas restarigi jam instalitan sistemon? [{answers}]",
|
||||
"pattern_positive_number": "Devas esti pozitiva nombro",
|
||||
"update_apt_cache_failed": "Ne eblis ĝisdatigi la kaŝmemoron de APT (paka administranto de Debian). Jen rubujo de la sources.list-linioj, kiuj povus helpi identigi problemajn liniojn:\n{sourceslist}",
|
||||
"migrations_no_migrations_to_run": "Neniuj migradoj por funkcii",
|
||||
"certmanager_attempt_to_renew_nonLE_cert": "La atestilo por la domajno '{domain}' ne estas elsendita de Let's Encrypt. Ne eblas renovigi ĝin aŭtomate!",
|
||||
|
@ -252,7 +250,6 @@
|
|||
"dyndns_unavailable": "La domajno '{domain}' ne haveblas.",
|
||||
"experimental_feature": "Averto: Ĉi tiu funkcio estas eksperimenta kaj ne konsiderata stabila, vi ne uzu ĝin krom se vi scias kion vi faras.",
|
||||
"root_password_replaced_by_admin_password": "Via radika pasvorto estis anstataŭigita per via administra pasvorto.",
|
||||
"domain_unknown": "Nekonata domajno",
|
||||
"global_settings_setting_security_password_user_strength": "Uzanto pasvorta forto",
|
||||
"restore_may_be_not_enough_disk_space": "Via sistemo ne ŝajnas havi sufiĉe da spaco (libera: {free_space} B, necesa spaco: {needed_space} B, sekureca marĝeno: {margin} B)",
|
||||
"log_corrupted_md_file": "La YAD-metadata dosiero asociita kun protokoloj estas damaĝita: '{md_file}\nEraro: {error} '",
|
||||
|
@ -326,7 +323,7 @@
|
|||
"log_dyndns_subscribe": "Aboni al YunoHost-subdominio '{}'",
|
||||
"password_too_simple_4": "La pasvorto bezonas almenaŭ 12 signojn kaj enhavas ciferon, majuskle, pli malaltan kaj specialajn signojn",
|
||||
"regenconf_file_updated": "Agordodosiero '{conf}' ĝisdatigita",
|
||||
"log_help_to_get_log": "Por vidi la protokolon de la operacio '{desc}', uzu la komandon 'yunohost log show {name}{name}'",
|
||||
"log_help_to_get_log": "Por vidi la protokolon de la operacio '{desc}', uzu la komandon 'yunohost log show {name}'",
|
||||
"global_settings_setting_security_nginx_compatibility": "Kongruo vs sekureca kompromiso por la TTT-servilo NGINX. Afektas la ĉifradojn (kaj aliajn aspektojn pri sekureco)",
|
||||
"restore_complete": "Restarigita",
|
||||
"hook_exec_failed": "Ne povis funkcii skripto: {path}",
|
||||
|
@ -491,8 +488,6 @@
|
|||
"diagnosis_description_ports": "Ekspoziciaj havenoj",
|
||||
"diagnosis_description_mail": "Retpoŝto",
|
||||
"log_app_action_run": "Funkciigu agon de la apliko '{}'",
|
||||
"log_app_config_show_panel": "Montri la agordan panelon de la apliko '{}'",
|
||||
"log_app_config_apply": "Apliki agordon al la apliko '{}'",
|
||||
"diagnosis_never_ran_yet": "Ŝajnas, ke ĉi tiu servilo estis instalita antaŭ nelonge kaj estas neniu diagnoza raporto por montri. Vi devas komenci kurante plenan diagnozon, ĉu de la retadministro aŭ uzante 'yunohost diagnosis run' el la komandlinio.",
|
||||
"certmanager_warning_subdomain_dns_record": "Subdominio '{subdomain}' ne solvas al la sama IP-adreso kiel '{domain}'. Iuj funkcioj ne estos haveblaj ĝis vi riparos ĉi tion kaj regeneros la atestilon.",
|
||||
"diagnosis_basesystem_hardware": "Arkitekturo de servila aparataro estas {virt} {arch}",
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
"domain_dyndns_root_unknown": "Dominio raíz de DynDNS desconocido",
|
||||
"domain_exists": "El dominio ya existe",
|
||||
"domain_uninstall_app_first": "Estas aplicaciones están todavía instaladas en tu dominio:\n{apps}\n\nPor favor desinstálalas utilizando <code>yunohost app remove the_app_id</code> o cambialas a otro dominio usando <code>yunohost app change-url the_app_id</code> antes de continuar con el borrado del dominio.",
|
||||
"domain_unknown": "Dominio desconocido",
|
||||
"done": "Hecho.",
|
||||
"downloading": "Descargando…",
|
||||
"dyndns_ip_update_failed": "No se pudo actualizar la dirección IP en DynDNS",
|
||||
|
@ -91,7 +90,6 @@
|
|||
"pattern_mailbox_quota": "Debe ser un tamaño con el sufijo «b/k/M/G/T» o «0» para no tener una cuota",
|
||||
"pattern_password": "Debe contener al menos 3 caracteres",
|
||||
"pattern_port_or_range": "Debe ser un número de puerto válido (es decir entre 0-65535) o un intervalo de puertos (por ejemplo 100:200)",
|
||||
"pattern_positive_number": "Deber ser un número positivo",
|
||||
"pattern_username": "Solo puede contener caracteres alfanuméricos o el guión bajo",
|
||||
"port_already_closed": "El puerto {port} ya está cerrado para las conexiones {ip_version}",
|
||||
"port_already_opened": "El puerto {port} ya está abierto para las conexiones {ip_version}",
|
||||
|
@ -171,7 +169,6 @@
|
|||
"certmanager_acme_not_configured_for_domain": "El reto ACME no ha podido ser realizado para {domain} porque su configuración de nginx no tiene el el código correcto... Por favor, asegurate que la configuración de nginx es correcta ejecutando en el terminal `yunohost tools regen-conf nginx --dry-run --with-diff`.",
|
||||
"domain_hostname_failed": "No se pudo establecer un nuevo nombre de anfitrión («hostname»). Esto podría causar problemas más tarde (no es seguro... podría ir bien).",
|
||||
"app_already_installed_cant_change_url": "Esta aplicación ya está instalada. La URL no se puede cambiar solo con esta función. Marque `app changeurl` si está disponible.",
|
||||
"app_change_url_failed_nginx_reload": "No se pudo recargar NGINX. Esta es la salida de «nginx -t»:\n{nginx_errors}",
|
||||
"app_change_url_identical_domains": "El antiguo y nuevo dominio/url_path son idénticos ('{domain} {path}'), no se realizarán cambios.",
|
||||
"app_change_url_no_script": "La aplicación «{app_name}» aún no permite la modificación de URLs. Quizás debería actualizarla.",
|
||||
"app_change_url_success": "El URL de la aplicación {app} es ahora {domain} {path}",
|
||||
|
@ -325,7 +322,7 @@
|
|||
"log_does_exists": "No existe ningún registro de actividades con el nombre '{log}', ejecute 'yunohost log list' para ver todos los registros de actividades disponibles",
|
||||
"log_help_to_get_failed_log": "No se pudo completar la operación «{desc}». Para obtener ayuda, comparta el registro completo de esta operación ejecutando la orden «yunohost log share {name}»",
|
||||
"log_link_to_failed_log": "No se pudo completar la operación «{desc}». Para obtener ayuda, proporcione el registro completo de esta operación <a href=\"#/tools/logs/{name}\">pulsando aquí</a>",
|
||||
"log_help_to_get_log": "Para ver el registro de la operación «{desc}», ejecute la orden «yunohost log show {name}{name}»",
|
||||
"log_help_to_get_log": "Para ver el registro de la operación «{desc}», ejecute la orden «yunohost log show {name}»",
|
||||
"log_link_to_log": "Registro completo de esta operación: «<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>»",
|
||||
"log_corrupted_md_file": "El archivo de metadatos YAML asociado con el registro está dañado: «{md_file}\nError: {error}»",
|
||||
"hook_json_return_error": "No se pudo leer la respuesta del gancho {path}. Error: {msg}. Contenido sin procesar: {raw_content}",
|
||||
|
@ -480,8 +477,6 @@
|
|||
"diagnosis_description_web": "Web",
|
||||
"diagnosis_basesystem_hardware": "La arquitectura material del servidor es {virt} {arch}",
|
||||
"log_domain_main_domain": "Hacer de '{}' el dominio principal",
|
||||
"log_app_config_apply": "Aplica la configuración de la aplicación '{}'",
|
||||
"log_app_config_show_panel": "Muestra el panel de configuración de la aplicación '{}'",
|
||||
"log_app_action_run": "Inicializa la acción de la aplicación '{}'",
|
||||
"group_already_exist_on_system_but_removing_it": "El grupo {group} ya existe en los grupos del sistema, pero YunoHost lo suprimirá …",
|
||||
"global_settings_setting_pop3_enabled": "Habilita el protocolo POP3 para el servidor de correo electrónico",
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
{
|
||||
"action_invalid": "اقدام نامعتبر '{action}'",
|
||||
"aborting": "رها کردن.",
|
||||
"app_change_url_failed_nginx_reload": "NGINX بارگیری نشد. در اینجا خروجی 'nginx -t' است:\n{nginx_errors}",
|
||||
"app_argument_required": "استدلال '{name}' الزامی است",
|
||||
"app_argument_password_no_default": "خطا هنگام تجزیه گذرواژه '{name}': به دلایل امنیتی استدلال رمز عبور نمی تواند مقدار پیش فرض داشته باشد",
|
||||
"app_argument_invalid": "یک مقدار معتبر انتخاب کنید برای استدلال '{name}':{error}",
|
||||
|
@ -152,7 +151,7 @@
|
|||
"apps_catalog_update_success": "کاتالوگ برنامه به روز شد!",
|
||||
"apps_catalog_obsolete_cache": "حافظه پنهان کاتالوگ برنامه خالی یا منسوخ شده است.",
|
||||
"apps_catalog_failed_to_download": "بارگیری کاتالوگ برنامه {apps_catalog} امکان پذیر نیست: {error}",
|
||||
"apps_catalog_updating": "در حال به روز رسانی کاتالوگ برنامه…",
|
||||
"apps_catalog_updating": "در حال به روز رسانی کاتالوگ برنامه...",
|
||||
"apps_catalog_init_success": "سیستم کاتالوگ برنامه راه اندازی اولیه شد!",
|
||||
"apps_already_up_to_date": "همه برنامه ها در حال حاضر به روز هستند",
|
||||
"app_packaging_format_not_supported": "این برنامه قابل نصب نیست زیرا قالب بسته بندی آن توسط نسخه YunoHost شما پشتیبانی نمی شود. احتمالاً باید ارتقاء سیستم خود را در نظر بگیرید.",
|
||||
|
@ -352,10 +351,9 @@
|
|||
"dyndns_could_not_check_provide": "بررسی نشد که آیا {provider} می تواند {domain} را ارائه دهد یا خیر.",
|
||||
"dpkg_lock_not_available": "این دستور در حال حاضر قابل اجرا نیست زیرا به نظر می رسد برنامه دیگری از قفل dpkg (مدیر بسته سیستم) استفاده می کند",
|
||||
"dpkg_is_broken": "شما نمی توانید این کار را در حال حاضر انجام دهید زیرا dpkg/APT (اداره کنندگان سیستم بسته ها) به نظر می رسد در وضعیت خرابی است… می توانید با اتصال از طریق SSH و اجرا این فرمان `sudo apt install --fix-broken` and/or `sudo dpkg --configure -a` مشکل را حل کنید.",
|
||||
"downloading": "در حال بارگیری…",
|
||||
"downloading": "در حال بارگیری...",
|
||||
"done": "انجام شد",
|
||||
"domains_available": "دامنه های موجود:",
|
||||
"domain_unknown": "دامنه ناشناخته",
|
||||
"domain_name_unknown": "دامنه '{domain}' ناشناخته است",
|
||||
"domain_uninstall_app_first": "این برنامه ها هنوز روی دامنه شما نصب هستند:\n{apps}\n\nلطفاً قبل از اقدام به حذف دامنه ، آنها را با استفاده از 'برنامه yunohost remove the_app_id' حذف کرده یا با استفاده از 'yunohost app change-url the_app_id' به دامنه دیگری منتقل کنید",
|
||||
"domain_remove_confirm_apps_removal": "حذف این دامنه برنامه های زیر را حذف می کند:\n{apps}\n\nآیا طمئن هستید که میخواهید انجام دهید؟ [{answers}]",
|
||||
|
@ -378,7 +376,6 @@
|
|||
"permission_already_allowed": "گروه '{group}' قبلاً مجوز '{permission}' را فعال کرده است",
|
||||
"pattern_password_app": "متأسفیم ، گذرواژه ها نمی توانند شامل کاراکترهای زیر باشند: {forbidden_chars}",
|
||||
"pattern_username": "باید فقط حروف الفبایی کوچک و خط زیر باشد",
|
||||
"pattern_positive_number": "باید یک عدد مثبت باشد",
|
||||
"pattern_port_or_range": "باید یک شماره پورت معتبر (یعنی 0-65535) یا محدوده پورت (به عنوان مثال 100: 200) باشد",
|
||||
"pattern_password": "باید حداقل 3 کاراکتر داشته باشد",
|
||||
"pattern_mailbox_quota": "باید اندازه ای با پسوند b / k / M / G / T یا 0 داشته باشد تا سهمیه نداشته باشد",
|
||||
|
@ -488,8 +485,6 @@
|
|||
"log_backup_restore_system": "بازیابی سیستم بوسیله آرشیو پشتیبان",
|
||||
"log_backup_create": "بایگانی پشتیبان ایجاد کنید",
|
||||
"log_available_on_yunopaste": "این گزارش اکنون از طریق {url} در دسترس است",
|
||||
"log_app_config_apply": "پیکربندی را در برنامه '{}' اعمال کنید",
|
||||
"log_app_config_show_panel": "پانل پیکربندی برنامه '{}' را نشان دهید",
|
||||
"log_app_action_run": "عملکرد برنامه '{}' را اجرا کنید",
|
||||
"log_app_makedefault": "\"{}\" را برنامه پیش فرض قرار دهید",
|
||||
"log_app_upgrade": "برنامه '{}' را ارتقاء دهید",
|
||||
|
@ -500,7 +495,7 @@
|
|||
"log_does_exists": "هیچ گزارش عملیاتی با نام '{log}' وجود ندارد ، برای مشاهده همه گزارش عملیّات های موجود در خط فرمان از دستور 'yunohost log list' استفاده کنید",
|
||||
"log_help_to_get_failed_log": "عملیات '{desc}' کامل نشد. لطفاً برای دریافت راهنمایی و کمک ، گزارش کامل این عملیات را با استفاده از دستور 'yunohost log share {name}' به اشتراک بگذارید",
|
||||
"log_link_to_failed_log": "عملیّات '{desc}' کامل نشد. لطفاً گزارش کامل این عملیات را ارائه دهید بواسطه <a href=\"#/tools/logs/{name}\">اینجا را کلیک کنید</a> برای دریافت کمک",
|
||||
"log_help_to_get_log": "برای مشاهده گزارش عملیات '{desc}'، از دستور 'yunohost log show {name}{name}' استفاده کنید",
|
||||
"log_help_to_get_log": "برای مشاهده گزارش عملیات '{desc}'، از دستور 'yunohost log show {name}' استفاده کنید",
|
||||
"log_link_to_log": "گزارش کامل این عملیات: <a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'",
|
||||
"log_corrupted_md_file": "فایل فوق داده YAML مربوط به گزارش ها آسیب دیده است: '{md_file}\nخطا: {error} '",
|
||||
"ldap_server_is_down_restart_it": "سرویس LDAP خاموش است ، سعی کنید آن را دوباره راه اندازی کنید...",
|
||||
|
@ -538,11 +533,11 @@
|
|||
"unbackup_app": "{app} ذخیره نمی شود",
|
||||
"tools_upgrade_special_packages_completed": "ارتقاء بسته YunoHost به پایان رسید\nبرای بازگرداندن خط فرمان [Enter] را فشار دهید",
|
||||
"tools_upgrade_special_packages_explanation": "ارتقاء ویژه در پس زمینه ادامه خواهد یافت. لطفاً تا 10 دقیقه دیگر (بسته به سرعت سخت افزار) هیچ اقدام دیگری را روی سرور خود شروع نکنید. پس از این کار ، ممکن است مجبور شوید دوباره وارد webadmin شوید. گزارش ارتقاء در Tools → Log (در webadmin) یا با استفاده از 'yunohost log list' (در خط فرمان) در دسترس خواهد بود.",
|
||||
"tools_upgrade_special_packages": "در حال ارتقاء بسته های 'special' (مربوط به yunohost)…",
|
||||
"tools_upgrade_special_packages": "در حال ارتقاء بسته های 'special' (مربوط به yunohost)...",
|
||||
"tools_upgrade_regular_packages_failed": "بسته ها را نمی توان ارتقا داد: {packages_list}",
|
||||
"tools_upgrade_regular_packages": "در حال ارتقاء بسته های 'regular' (غیر مرتبط با yunohost)…",
|
||||
"tools_upgrade_cant_unhold_critical_packages": "بسته های مهم و حیاتی را نمی توان نگه نداشت…",
|
||||
"tools_upgrade_cant_hold_critical_packages": "بسته های مهم و حیاتی را نمی توان نگه داشت…",
|
||||
"tools_upgrade_regular_packages": "در حال ارتقاء بسته های 'regular' (غیر مرتبط با yunohost)...",
|
||||
"tools_upgrade_cant_unhold_critical_packages": "بسته های مهم و حیاتی را نمی توان نگه نداشت...",
|
||||
"tools_upgrade_cant_hold_critical_packages": "بسته های مهم و حیاتی را نمی توان نگه داشت...",
|
||||
"tools_upgrade_cant_both": "نمی توان سیستم و برنامه ها را به طور همزمان ارتقا داد",
|
||||
"tools_upgrade_at_least_one": "لطفاً مشخص کنید 'apps' ، یا 'system'",
|
||||
"this_action_broke_dpkg": "این اقدام dpkg/APT (مدیران بسته های سیستم) را خراب کرد... می توانید با اتصال از طریق SSH و اجرای فرمان `sudo apt install --fix -break` و/یا` sudo dpkg --configure -a` این مشکل را حل کنید.",
|
||||
|
@ -597,15 +592,15 @@
|
|||
"root_password_replaced_by_admin_password": "گذرواژه ریشه شما با رمز مدیریت جایگزین شده است.",
|
||||
"root_password_desynchronized": "گذرواژه مدیریت تغییر کرد ، اما YunoHost نتوانست این را به رمز عبور ریشه منتقل کند!",
|
||||
"restore_system_part_failed": "بخش سیستم '{part}' بازیابی و ترمیم نشد",
|
||||
"restore_running_hooks": "در حال اجرای قلاب های ترمیم و بازیابی…",
|
||||
"restore_running_app_script": "ترمیم و بازیابی برنامه '{app}'…",
|
||||
"restore_running_hooks": "در حال اجرای قلاب های ترمیم و بازیابی...",
|
||||
"restore_running_app_script": "ترمیم و بازیابی برنامه '{app}'...",
|
||||
"restore_removing_tmp_dir_failed": "پوشه موقت قدیمی حذف نشد",
|
||||
"restore_nothings_done": "هیچ چیز ترمیم و بازسازی نشد",
|
||||
"restore_not_enough_disk_space": "فضای کافی موجود نیست (فضا: {free_space} B ، فضای مورد نیاز: {needed_space} B ، حاشیه امنیتی: {margin} B)",
|
||||
"restore_may_be_not_enough_disk_space": "به نظر می رسد سیستم شما فضای کافی ندارد (فضای آزاد: {free_space} B ، فضای مورد نیاز: {needed_space} B ، حاشیه امنیتی: {margin} B)",
|
||||
"restore_hook_unavailable": "اسکریپت ترمیم و بازسازی برای '{part}' در سیستم شما در دسترس نیست و همچنین در بایگانی نیز وجود ندارد",
|
||||
"restore_failed": "سیستم بازیابی نشد",
|
||||
"restore_extracting": "استخراج فایل های مورد نیاز از بایگانی…",
|
||||
"restore_extracting": "استخراج فایل های مورد نیاز از بایگانی...",
|
||||
"restore_confirm_yunohost_installed": "آیا واقعاً می خواهید سیستمی که هم اکنون نصب شده را بازیابی کنید؟ [{answers}]",
|
||||
"restore_complete": "مرمت به پایان رسید",
|
||||
"restore_cleaning_failed": "فهرست بازسازی موقت پاک نشد",
|
||||
|
@ -617,7 +612,7 @@
|
|||
"regenconf_need_to_explicitly_specify_ssh": "پیکربندی ssh به صورت دستی تغییر یافته است ، اما شما باید صراحتاً دسته \"ssh\" را با --force برای اعمال تغییرات در واقع مشخص کنید.",
|
||||
"regenconf_pending_applying": "در حال اعمال پیکربندی معلق برای دسته '{category}'...",
|
||||
"regenconf_failed": "پیکربندی برای دسته (ها) بازسازی نشد: {categories}",
|
||||
"regenconf_dry_pending_applying": "در حال بررسی پیکربندی معلق که برای دسته '{category}' اعمال می شد…",
|
||||
"regenconf_dry_pending_applying": "در حال بررسی پیکربندی معلق که برای دسته '{category}' اعمال می شد...",
|
||||
"regenconf_would_be_updated": "پیکربندی برای دسته '{category}' به روز می شد",
|
||||
"regenconf_updated": "پیکربندی برای دسته '{category}' به روز شد",
|
||||
"regenconf_up_to_date": "پیکربندی در حال حاضر برای دسته '{category}' به روز است",
|
||||
|
@ -642,4 +637,4 @@
|
|||
"permission_deleted": "مجوز '{permission}' حذف شد",
|
||||
"permission_cant_add_to_all_users": "مجوز {permission} را نمی توان به همه کاربران اضافه کرد.",
|
||||
"permission_currently_allowed_for_all_users": "این مجوز در حال حاضر به همه کاربران علاوه بر آن گروه های دیگر نیز اعطا شده. احتمالاً بخواهید مجوز 'all_users' را حذف کنید یا سایر گروه هایی را که در حال حاضر مجوز به آنها اعطا شده است را هم حذف کنید."
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
"admin_password_change_failed": "Impossible de changer le mot de passe",
|
||||
"admin_password_changed": "Le mot de passe d'administration a été modifié",
|
||||
"app_already_installed": "{app} est déjà installé",
|
||||
"app_argument_choice_invalid": "Choix invalide pour le paramètre '{name}', il doit être l'un de {choices}",
|
||||
"app_argument_choice_invalid": "Choix invalide pour le paramètre '{name}'. Les valeurs acceptées sont {choices}, au lieu de '{value}'",
|
||||
"app_argument_invalid": "Valeur invalide pour le paramètre '{name}' : {error}",
|
||||
"app_argument_required": "Le paramètre '{name}' est requis",
|
||||
"app_extraction_failed": "Impossible d'extraire les fichiers d'installation",
|
||||
|
@ -42,7 +42,7 @@
|
|||
"backup_output_directory_forbidden": "Choisissez un répertoire de destination différent. Les sauvegardes ne peuvent pas être créées dans les sous-dossiers /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives",
|
||||
"backup_output_directory_not_empty": "Le répertoire de destination n'est pas vide",
|
||||
"backup_output_directory_required": "Vous devez spécifier un dossier de destination pour la sauvegarde",
|
||||
"backup_running_hooks": "Exécution des scripts de sauvegarde...",
|
||||
"backup_running_hooks": "Exécution des scripts de sauvegarde ...",
|
||||
"custom_app_url_required": "Vous devez spécifier une URL pour mettre à jour votre application personnalisée {app}",
|
||||
"disk_space_not_sufficient_install": "Il ne reste pas assez d'espace disque pour installer cette application",
|
||||
"disk_space_not_sufficient_update": "Il ne reste pas assez d'espace disque pour mettre à jour cette application",
|
||||
|
@ -55,7 +55,6 @@
|
|||
"domain_dyndns_root_unknown": "Domaine DynDNS principal inconnu",
|
||||
"domain_exists": "Le domaine existe déjà",
|
||||
"domain_uninstall_app_first": "Ces applications sont toujours installées sur votre domaine :\n{apps}\n\nVeuillez les désinstaller avec la commande 'yunohost app remove nom-de-l-application' ou les déplacer vers un autre domaine avec la commande 'yunohost app change-url nom-de-l-application' avant de procéder à la suppression du domaine",
|
||||
"domain_unknown": "Domaine inconnu",
|
||||
"done": "Terminé",
|
||||
"downloading": "Téléchargement en cours...",
|
||||
"dyndns_ip_update_failed": "Impossible de mettre à jour l'adresse IP sur le domaine DynDNS",
|
||||
|
@ -93,7 +92,6 @@
|
|||
"pattern_mailbox_quota": "Doit avoir une taille suffixée avec b/k/M/G/T ou 0 pour désactiver le quota",
|
||||
"pattern_password": "Doit être composé d'au moins 3 caractères",
|
||||
"pattern_port_or_range": "Doit être un numéro de port valide compris entre 0 et 65535, ou une gamme de ports (exemple : 100:200)",
|
||||
"pattern_positive_number": "Doit être un nombre positif",
|
||||
"pattern_username": "Doit être composé uniquement de caractères alphanumériques minuscules et de tirets bas (aussi appelé tiret du 8 ou underscore)",
|
||||
"port_already_closed": "Le port {port} est déjà fermé pour les connexions {ip_version}",
|
||||
"port_already_opened": "Le port {port} est déjà ouvert pour les connexions {ip_version}",
|
||||
|
@ -137,15 +135,15 @@
|
|||
"upnp_dev_not_found": "Aucun périphérique compatible UPnP n'a été trouvé",
|
||||
"upnp_disabled": "L'UPnP est désactivé",
|
||||
"upnp_enabled": "L'UPnP est activé",
|
||||
"upnp_port_open_failed": "Impossible d’ouvrir les ports UPnP",
|
||||
"user_created": "L’utilisateur a été créé",
|
||||
"user_creation_failed": "Impossible de créer l’utilisateur {user} : {error}",
|
||||
"user_deleted": "L’utilisateur a été supprimé",
|
||||
"user_deletion_failed": "Impossible de supprimer l’utilisateur {user} : {error}",
|
||||
"user_home_creation_failed": "Impossible de créer le dossier personnel '{home}' de l’utilisateur",
|
||||
"user_unknown": "L’utilisateur {user} est inconnu",
|
||||
"user_update_failed": "Impossible de mettre à jour l’utilisateur {user} : {error}",
|
||||
"user_updated": "L’utilisateur a été modifié",
|
||||
"upnp_port_open_failed": "Impossible d'ouvrir les ports UPnP",
|
||||
"user_created": "L'utilisateur a été créé",
|
||||
"user_creation_failed": "Impossible de créer l'utilisateur {user} : {error}",
|
||||
"user_deleted": "L'utilisateur a été supprimé",
|
||||
"user_deletion_failed": "Impossible de supprimer l'utilisateur {user} : {error}",
|
||||
"user_home_creation_failed": "Impossible de créer le dossier personnel '{home}' de l'utilisateur",
|
||||
"user_unknown": "L'utilisateur {user} est inconnu",
|
||||
"user_update_failed": "Impossible de mettre à jour l'utilisateur {user} : {error}",
|
||||
"user_updated": "L'utilisateur a été modifié",
|
||||
"yunohost_already_installed": "YunoHost est déjà installé",
|
||||
"yunohost_configured": "YunoHost est maintenant configuré",
|
||||
"yunohost_installing": "L'installation de YunoHost est en cours...",
|
||||
|
@ -169,11 +167,10 @@
|
|||
"certmanager_unable_to_parse_self_CA_name": "Impossible d'analyser le nom de l'autorité du certificat auto-signé (fichier : {file})",
|
||||
"mailbox_used_space_dovecot_down": "Le service Dovecot doit être démarré si vous souhaitez voir l'espace disque occupé par la messagerie",
|
||||
"domains_available": "Domaines disponibles :",
|
||||
"backup_archive_broken_link": "Impossible d’accéder à l’archive de sauvegarde (lien invalide vers {path})",
|
||||
"backup_archive_broken_link": "Impossible d'accéder à l'archive de sauvegarde (lien invalide vers {path})",
|
||||
"certmanager_acme_not_configured_for_domain": "Le challenge ACME n'a pas pu être validé pour le domaine {domain} pour le moment car le code de la configuration NGINX est manquant... Merci de vérifier que votre configuration NGINX est à jour avec la commande : `yunohost tools regen-conf nginx --dry-run --with-diff`.",
|
||||
"domain_hostname_failed": "Échec de l’utilisation d’un nouveau nom d'hôte. Cela pourrait causer des soucis plus tard (cela n'en causera peut-être pas).",
|
||||
"app_already_installed_cant_change_url": "Cette application est déjà installée. L’URL ne peut pas être changé simplement par cette fonction. Vérifiez si cela est disponible avec `app changeurl`.",
|
||||
"app_change_url_failed_nginx_reload": "Le redémarrage de NGINX a échoué. Voici la sortie de 'nginx -t' :\n{nginx_errors}",
|
||||
"domain_hostname_failed": "Échec de l'utilisation d'un nouveau nom d'hôte. Cela pourrait causer des soucis plus tard (cela n'en causera peut-être pas).",
|
||||
"app_already_installed_cant_change_url": "Cette application est déjà installée. L'URL ne peut pas être changé simplement par cette fonction. Vérifiez si cela est disponible avec `app changeurl`.",
|
||||
"app_change_url_identical_domains": "L'ancien et le nouveau couple domaine/chemin_de_l'URL sont identiques pour ('{domain}{path}'), rien à faire.",
|
||||
"app_change_url_no_script": "L'application '{app_name}' ne prend pas encore en charge le changement d'URL. Vous devriez peut-être la mettre à jour.",
|
||||
"app_change_url_success": "L'URL de l'application {app} a été changée en {domain}{path}",
|
||||
|
@ -188,9 +185,9 @@
|
|||
"global_settings_unknown_type": "Situation inattendue : la configuration {setting} semble avoir le type {unknown_type} mais celui-ci n'est pas pris en charge par le système.",
|
||||
"global_settings_unknown_setting_from_settings_file": "Clé inconnue dans les paramètres : '{setting_key}', rejet de cette clé et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
|
||||
"backup_abstract_method": "Cette méthode de sauvegarde reste à implémenter",
|
||||
"backup_applying_method_tar": "Création de l'archive TAR de la sauvegarde...",
|
||||
"backup_applying_method_copy": "Copie de tous les fichiers à sauvegarder...",
|
||||
"backup_applying_method_custom": "Appel de la méthode de sauvegarde personnalisée '{method}'...",
|
||||
"backup_applying_method_tar": "Création de l'archive TAR de la sauvegarde ...",
|
||||
"backup_applying_method_copy": "Copie de tous les fichiers à sauvegarder ...",
|
||||
"backup_applying_method_custom": "Appel de la méthode de sauvegarde personnalisée '{method}' ...",
|
||||
"backup_archive_system_part_not_available": "La partie '{part}' du système n'est pas disponible dans cette sauvegarde",
|
||||
"backup_archive_writing_error": "Impossible d'ajouter des fichiers '{source}' (nommés dans l'archive : '{dest}') à sauvegarder dans l'archive compressée '{archive}'",
|
||||
"backup_ask_for_copying_if_needed": "Voulez-vous effectuer la sauvegarde en utilisant {size}Mo temporairement ? (Cette méthode est utilisée car certains fichiers n'ont pas pu être préparés avec une méthode plus efficace.)",
|
||||
|
@ -251,7 +248,7 @@
|
|||
"experimental_feature": "Attention : cette fonctionnalité est expérimentale et ne doit pas être considérée comme stable, vous ne devriez pas l'utiliser à moins que vous ne sachiez ce que vous faites.",
|
||||
"log_corrupted_md_file": "Le fichier YAML de métadonnées associé aux logs est corrompu : '{md_file}'\nErreur : {error}",
|
||||
"log_link_to_log": "Journal complet de cette opération : '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\"> {desc} </a>'",
|
||||
"log_help_to_get_log": "Pour voir le journal de cette opération '{desc}', utilisez la commande 'yunohost log show {name}{name}'",
|
||||
"log_help_to_get_log": "Pour voir le journal de cette opération '{desc}', utilisez la commande 'yunohost log show {name}'",
|
||||
"log_link_to_failed_log": "L'opération '{desc}' a échoué ! Pour obtenir de l'aide, merci de partager le journal de l'opération en <a href=\"#/tools/logs/{name}\">cliquant ici</a>",
|
||||
"log_help_to_get_failed_log": "L'opération '{desc}' a échoué ! Pour obtenir de l'aide, merci de partager le journal de l'opération en utilisant la commande 'yunohost log share {name}'",
|
||||
"log_does_exists": "Il n'y a pas de journal des opérations avec le nom '{log}', utilisez 'yunohost log list' pour voir tous les journaux d'opérations disponibles",
|
||||
|
@ -300,7 +297,7 @@
|
|||
"app_upgrade_several_apps": "Les applications suivantes seront mises à jour : {apps}",
|
||||
"ask_new_domain": "Nouveau domaine",
|
||||
"ask_new_path": "Nouveau chemin",
|
||||
"backup_actually_backuping": "Création d'une archive de sauvegarde à partir des fichiers collectés...",
|
||||
"backup_actually_backuping": "Création d'une archive de sauvegarde à partir des fichiers collectés ...",
|
||||
"backup_mount_archive_for_restore": "Préparation de l'archive pour restauration...",
|
||||
"confirm_app_install_warning": "Avertissement : cette application peut fonctionner mais n'est pas bien intégrée dans YunoHost. Certaines fonctionnalités telles que l'authentification unique et la sauvegarde/restauration peuvent ne pas être disponibles. L'installer quand même ? [{answers}] ",
|
||||
"confirm_app_install_danger": "DANGER ! Cette application est connue pour être encore expérimentale (si elle ne fonctionne pas explicitement) ! Vous ne devriez probablement PAS l'installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système... Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers}'",
|
||||
|
@ -494,8 +491,6 @@
|
|||
"diagnosis_http_timeout": "Expiration du délai en essayant de contacter votre serveur de l'extérieur. Il semble être inaccessible. Vérifiez que vous transférez correctement le port 80, que Nginx est en cours d'exécution et qu'un pare-feu n'interfère pas.",
|
||||
"global_settings_setting_pop3_enabled": "Activer le protocole POP3 pour le serveur de messagerie",
|
||||
"log_app_action_run": "Lancer l'action de l'application '{}'",
|
||||
"log_app_config_show_panel": "Montrer le panneau de configuration de l'application '{}'",
|
||||
"log_app_config_apply": "Appliquer la configuration à l'application '{}'",
|
||||
"diagnosis_never_ran_yet": "Il apparaît que le serveur a été installé récemment et qu'il n'y a pas encore eu de diagnostic. Vous devriez en lancer un depuis la webadmin ou en utilisant 'yunohost diagnosis run' depuis la ligne de commande.",
|
||||
"diagnosis_description_web": "Web",
|
||||
"diagnosis_basesystem_hardware": "L'architecture du serveur est {virt} {arch}",
|
||||
|
@ -528,7 +523,7 @@
|
|||
"diagnosis_mail_ehlo_ok": "Le serveur de messagerie SMTP est accessible de l'extérieur et peut donc recevoir des emails !",
|
||||
"diagnosis_mail_ehlo_unreachable": "Le serveur de messagerie SMTP est inaccessible de l'extérieur en IPv{ipversion}. Il ne pourra pas recevoir des emails.",
|
||||
"diagnosis_mail_ehlo_unreachable_details": "Impossible d'ouvrir une connexion sur le port 25 à votre serveur en IPv{ipversion}. Il semble inaccessible. <br> 1. La cause la plus courante de ce problème est que le port 25 <a href='https://yunohost.org/isp_box_config'>n'est pas correctement redirigé vers votre serveur</a>. <br> 2. Vous devez également vous assurer que le service postfix est en cours d'exécution. <br> 3. Sur les configurations plus complexes: assurez-vous qu'aucun pare-feu ou proxy inversé n'interfère.",
|
||||
"diagnosis_mail_ehlo_wrong_details": "Le EHLO reçu par le serveur de diagnostique distant en IPv{ipversion} est différent du domaine de votre serveur. <br> EHLO reçu: <code>{wrong_ehlo}</code> <br> Attendu : <code>{right_ehlo}</code> <br> La cause la plus courante ce problème est que le port 25 <a href='https://yunohost.org/isp_box_config'> n'est pas correctement redirigé vers votre serveur </a>. Vous pouvez également vous assurer qu'aucun pare-feu ou proxy inversé n'interfère.",
|
||||
"diagnosis_mail_ehlo_wrong_details": "Le EHLO reçu par le serveur de diagnostique distant en IPv{ipversion} est différent du domaine de votre serveur.<br>EHLO reçu : <code>{wrong_ehlo}</code><br>Attendu : <code>{right_ehlo}</code><br>La cause la plus courante à ce problème est que le port 25 <a href='https ://yunohost.org/isp_box_config'>n'est pas correctement redirigé vers votre serveur</a>. Vous pouvez également vous assurer qu'aucun pare-feu ou reverse-proxy n'interfère.",
|
||||
"diagnosis_mail_fcrdns_nok_alternatives_4": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée...). Si vous rencontrez des problèmes à cause de cela, envisagez les solutions suivantes : <br> - Certains FAI fournissent l'alternative de <a href='https://yunohost.org/#/email_configure_relay'>à l'aide d'un relais de serveur de messagerie</a> bien que cela implique que le relais pourra espionner votre trafic de messagerie. <br> - Une alternative respectueuse de la vie privée consiste à utiliser un VPN *avec une IP publique dédiée* pour contourner ce type de limites. Voir <a href='https://yunohost.org/#/vpn_advantage'>https://yunohost.org/#/vpn_advantage</a> <br> - Enfin, il est également possible de <a href='https://yunohost.org/#/isp'>changer de fournisseur</a>",
|
||||
"diagnosis_mail_fcrdns_nok_alternatives_6": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée...). Si votre DNS inversé est correctement configuré en IPv4, vous pouvez essayer de désactiver l'utilisation d'IPv6 lors de l'envoi d'emails en exécutant <cmd>yunohost settings set smtp.allow_ipv6 -v off</cmd>. Remarque : cette dernière solution signifie que vous ne pourrez pas envoyer ou recevoir de emails avec les quelques serveurs qui ont uniquement de l'IPv6.",
|
||||
"diagnosis_mail_fcrdns_different_from_ehlo_domain_details": "DNS inverse actuel : <code>{rdns_domain}</code> <br> Valeur attendue : <code>{ehlo_domain}</code>",
|
||||
|
@ -657,5 +652,28 @@
|
|||
"user_import_missing_columns": "Les colonnes suivantes sont manquantes : {columns}",
|
||||
"user_import_bad_file": "Votre fichier CSV n'est pas correctement formaté, il sera ignoré afin d'éviter une potentielle perte de données",
|
||||
"user_import_bad_line": "Ligne incorrecte {line} : {details}",
|
||||
"log_user_import": "Importer des utilisateurs"
|
||||
}
|
||||
"log_user_import": "Importer des utilisateurs",
|
||||
"diagnosis_high_number_auth_failures": "Il y a eu récemment un grand nombre d'échecs d'authentification. Assurez-vous que Fail2Ban est en cours d'exécution et est correctement configuré, ou utilisez un port personnalisé pour SSH comme expliqué dans https://yunohost.org/security.",
|
||||
"global_settings_setting_security_nginx_redirect_to_https": "Rediriger les requêtes HTTP vers HTTPS par défaut (NE PAS DÉSACTIVER à moins de savoir vraiment ce que vous faites !)",
|
||||
"config_validate_color": "Doit être une couleur hexadécimale RVB valide",
|
||||
"app_config_unable_to_apply": "Échec de l'application des valeurs du panneau de configuration.",
|
||||
"app_config_unable_to_read": "Échec de la lecture des valeurs du panneau de configuration.",
|
||||
"config_apply_failed": "Échec de l'application de la nouvelle configuration : {error}",
|
||||
"config_cant_set_value_on_section": "Vous ne pouvez pas définir une seule valeur sur une section de configuration entière.",
|
||||
"config_forbidden_keyword": "Le mot-clé '{keyword}' est réservé, vous ne pouvez pas créer ou utiliser un panneau de configuration avec une question avec cet identifiant.",
|
||||
"config_no_panel": "Aucun panneau de configuration trouvé.",
|
||||
"config_unknown_filter_key": "La clé de filtre '{filter_key}' est incorrecte.",
|
||||
"config_validate_date": "Doit être une date valide comme dans le format AAAA-MM-JJ",
|
||||
"config_validate_email": "Doit être un email valide",
|
||||
"config_validate_time": "Doit être une heure valide comme HH:MM",
|
||||
"config_validate_url": "Doit être une URL Web valide",
|
||||
"config_version_not_supported": "Les versions du panneau de configuration '{version}' ne sont pas prises en charge.",
|
||||
"danger": "Danger :",
|
||||
"file_extension_not_accepted": "Le fichier '{path}' est refusé car son extension ne fait pas partie des extensions acceptées : {accept}",
|
||||
"invalid_number_min": "Doit être supérieur à {min}",
|
||||
"invalid_number_max": "Doit être inférieur à {max}",
|
||||
"log_app_config_set": "Appliquer la configuration à l'application '{}'",
|
||||
"service_not_reloading_because_conf_broken": "Le service '{name}' n'a pas été rechargé/redémarré car sa configuration est cassée : {errors}",
|
||||
"app_argument_password_help_keep": "Tapez sur Entrée pour conserver la valeur actuelle",
|
||||
"app_argument_password_help_optional": "Tapez un espace pour vider le mot de passe"
|
||||
}
|
|
@ -14,11 +14,10 @@
|
|||
"additional_urls_already_removed": "URL adicional '{url}' xa foi eliminada das URL adicionais para o permiso '{permission}'",
|
||||
"additional_urls_already_added": "URL adicional '{url}' xa fora engadida ás URL adicionais para o permiso '{permission}'",
|
||||
"action_invalid": "Acción non válida '{action}'",
|
||||
"app_change_url_failed_nginx_reload": "Non se recargou NGINX. Aquí tes a saída de 'nginx -t':\n{nginx_errors}",
|
||||
"app_argument_required": "Requírese o argumento '{name}'",
|
||||
"app_argument_password_no_default": "Erro ao procesar o argumento do contrasinal '{name}': o argumento do contrasinal non pode ter un valor por defecto por razón de seguridade",
|
||||
"app_argument_invalid": "Elixe un valor válido para o argumento '{name}': {error}",
|
||||
"app_argument_choice_invalid": "Usa unha destas opcións '{choices}' para o argumento '{name}'",
|
||||
"app_argument_choice_invalid": "Usa unha destas opcións '{choices}' para o argumento '{name}' no lugar de '{value}'",
|
||||
"backup_archive_writing_error": "Non se puideron engadir os ficheiros '{source}' (chamados no arquivo '{dest}' para ser copiados dentro do arquivo comprimido '{archive}'",
|
||||
"backup_archive_system_part_not_available": "A parte do sistema '{part}' non está dispoñible nesta copia",
|
||||
"backup_archive_corrupted": "Semella que o arquivo de copia '{archive}' está estragado : {error}",
|
||||
|
@ -45,7 +44,7 @@
|
|||
"apps_catalog_update_success": "O catálogo de aplicacións foi actualizado!",
|
||||
"apps_catalog_obsolete_cache": "A caché do catálogo de apps está baleiro ou obsoleto.",
|
||||
"apps_catalog_failed_to_download": "Non se puido descargar o catálogo de apps {apps_catalog}: {error}",
|
||||
"apps_catalog_updating": "Actualizando o catálogo de aplicacións…",
|
||||
"apps_catalog_updating": "Actualizando o catálogo de aplicacións...",
|
||||
"apps_catalog_init_success": "Sistema do catálogo de apps iniciado!",
|
||||
"apps_already_up_to_date": "Xa tes tódalas apps ao día",
|
||||
"app_packaging_format_not_supported": "Esta app non se pode instalar porque o formato de empaquetado non está soportado pola túa versión de YunoHost. Deberías considerar actualizar o teu sistema.",
|
||||
|
@ -292,10 +291,9 @@
|
|||
"dyndns_could_not_check_provide": "Non se comprobou se {provider} pode proporcionar {domain}.",
|
||||
"dpkg_lock_not_available": "Non se pode executar agora mesmo este comando porque semella que outro programa está a utilizar dpkg (o xestos de paquetes do sistema)",
|
||||
"dpkg_is_broken": "Non podes facer isto agora mesmo porque dpkg/APT (o xestor de paquetes do sistema) semella que non está a funcionar... Podes intentar solucionalo conectándote a través de SSH e executando `sudo apt install --fix-broken`e/ou `sudo dpkg --configure -a`.",
|
||||
"downloading": "Descargando…",
|
||||
"downloading": "Descargando...",
|
||||
"done": "Feito",
|
||||
"domains_available": "Dominios dispoñibles:",
|
||||
"domain_unknown": "Dominio descoñecido",
|
||||
"domain_name_unknown": "Dominio '{domain}' descoñecido",
|
||||
"domain_uninstall_app_first": "Aínda están instaladas estas aplicacións no teu dominio:\n{apps}\n\nPrimeiro desinstalaas utilizando 'yunohost app remove id_da_app' ou móveas a outro dominio con 'yunohost app change-url id_da_app' antes de eliminar o dominio",
|
||||
"domain_remove_confirm_apps_removal": "Ao eliminar o dominio tamén vas eliminar estas aplicacións:\n{apps}\n\nTes a certeza de querer facelo? [{answers}]",
|
||||
|
@ -358,7 +356,7 @@
|
|||
"global_settings_setting_security_webadmin_allowlist_enabled": "Permitir que só algúns IPs accedan á webadmin.",
|
||||
"disk_space_not_sufficient_update": "Non hai espazo suficiente no disco para actualizar esta aplicación",
|
||||
"disk_space_not_sufficient_install": "Non queda espazo suficiente no disco para instalar esta aplicación",
|
||||
"log_help_to_get_log": "Para ver o rexistro completo da operación '{desc}', usa o comando 'yunohost log show {name}{name}'",
|
||||
"log_help_to_get_log": "Para ver o rexistro completo da operación '{desc}', usa o comando 'yunohost log show {name}'",
|
||||
"log_link_to_log": "Rexistro completo desta operación: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'",
|
||||
"log_corrupted_md_file": "O ficheiro YAML con metadatos asociado aos rexistros está danado: '{md_file}\nErro: {error}'",
|
||||
"iptables_unavailable": "Non podes andar remexendo en iptables aquí. Ou ben estás nun contedor ou o teu kernel non ten soporte para isto",
|
||||
|
@ -386,8 +384,6 @@
|
|||
"log_backup_restore_system": "Restablecer o sistema desde unha copia de apoio",
|
||||
"log_backup_create": "Crear copia de apoio",
|
||||
"log_available_on_yunopaste": "Este rexistro está dispoñible en {url}",
|
||||
"log_app_config_apply": "Aplicar a configuración da app '{}'",
|
||||
"log_app_config_show_panel": "Mostrar o panel de configuración da app '{}'",
|
||||
"log_app_action_run": "Executar acción da app '{}'",
|
||||
"log_app_makedefault": "Converter '{}' na app por defecto",
|
||||
"log_app_upgrade": "Actualizar a app '{}'",
|
||||
|
@ -458,7 +454,7 @@
|
|||
"migration_0015_specific_upgrade": "Iniciando a actualización dos paquetes do sistema que precisan ser actualizados de xeito independente...",
|
||||
"migration_0015_modified_files": "Ten en conta que os seguintes ficheiros semella que foron modificados manualmente e poderían ser sobrescritos na actualización: {manually_modified_files}",
|
||||
"migration_0015_problematic_apps_warning": "Ten en conta que se detectaron as seguintes apps que poderían ser problemáticas. Semella que non foron instaladas usando o catálogo de YunoHost, ou non están marcadas como 'funcionais'. En consecuencia, non se pode garantir que seguirán funcionando após a actualización: {problematic_apps}",
|
||||
"diagnosis_http_localdomain": "O dominio {domain}, cun TLD .local, non é de agardar que sexa accesible desde o exterior da rede local.",
|
||||
"diagnosis_http_localdomain": "O dominio {domain}, cun TLD .local, non é de agardar que esté exposto ao exterior da rede local.",
|
||||
"diagnosis_dns_specialusedomain": "O dominio {domain} baséase un dominio de nivel alto e uso especial (TLD) polo que non é de agardar que realmente teña rexistros DNS.",
|
||||
"upnp_enabled": "UPnP activado",
|
||||
"upnp_disabled": "UPnP desactivado",
|
||||
|
@ -471,7 +467,6 @@
|
|||
"permission_already_allowed": "O grupo '{group}' xa ten o permiso '{permission}' activado",
|
||||
"pattern_password_app": "Lamentámolo, os contrasinais non poden conter os seguintes caracteres: {forbidden_chars}",
|
||||
"pattern_username": "Só admite caracteres alfanuméricos en minúscula e trazo baixo",
|
||||
"pattern_positive_number": "Ten que ser un número positivo",
|
||||
"pattern_port_or_range": "Debe ser un número válido de porto (entre 0-65535) ou rango de portos (ex. 100:200)",
|
||||
"pattern_password": "Ten que ter polo menos 3 caracteres",
|
||||
"pattern_mailbox_quota": "Ten que ser un tamaño co sufixo b/k/M/G/T ou 0 para non ter unha cota",
|
||||
|
@ -524,7 +519,7 @@
|
|||
"permission_cant_add_to_all_users": "O permiso {permission} non pode ser concecido a tódalas usuarias.",
|
||||
"permission_currently_allowed_for_all_users": "Este permiso está concedido actualmente a tódalas usuarias ademáis de a outros grupos. Probablemente queiras ben eliminar o permiso 'all_users' ou ben eliminar os outros grupos que teñen permiso.",
|
||||
"restore_failed": "Non se puido restablecer o sistema",
|
||||
"restore_extracting": "Extraendo os ficheiros necesarios desde o arquivo…",
|
||||
"restore_extracting": "Extraendo os ficheiros necesarios desde o arquivo...",
|
||||
"restore_confirm_yunohost_installed": "Tes a certeza de querer restablecer un sistema xa instalado? [{answers}]",
|
||||
"restore_complete": "Restablecemento completado",
|
||||
"restore_cleaning_failed": "Non se puido despexar o directorio temporal de restablecemento",
|
||||
|
@ -536,7 +531,7 @@
|
|||
"regenconf_need_to_explicitly_specify_ssh": "A configuración ssh foi modificada manualmente, pero tes que indicar explícitamente a categoría 'ssh' con --force para realmente aplicar os cambios.",
|
||||
"regenconf_pending_applying": "Aplicando a configuración pendente para categoría '{category}'...",
|
||||
"regenconf_failed": "Non se rexenerou a configuración para a categoría(s): {categories}",
|
||||
"regenconf_dry_pending_applying": "Comprobando as configuracións pendentes que deberían aplicarse á categoría '{category}'…",
|
||||
"regenconf_dry_pending_applying": "Comprobando as configuracións pendentes que deberían aplicarse á categoría '{category}'...",
|
||||
"regenconf_would_be_updated": "A configuración debería ser actualizada para a categoría '{category}'",
|
||||
"regenconf_updated": "Configuración actualizada para '{category}'",
|
||||
"regenconf_up_to_date": "A configuración xa está ao día para a categoría '{category}'",
|
||||
|
@ -574,8 +569,8 @@
|
|||
"root_password_replaced_by_admin_password": "O contrasinal root foi substituído polo teu contrasinal de administración.",
|
||||
"root_password_desynchronized": "Mudou o contrasinal de administración, pero YunoHost non puido transferir este cambio ao contrasinal root!",
|
||||
"restore_system_part_failed": "Non se restableceu a parte do sistema '{part}'",
|
||||
"restore_running_hooks": "Executando os ganchos do restablecemento…",
|
||||
"restore_running_app_script": "Restablecendo a app '{app}'…",
|
||||
"restore_running_hooks": "Executando os ganchos do restablecemento...",
|
||||
"restore_running_app_script": "Restablecendo a app '{app}'...",
|
||||
"restore_removing_tmp_dir_failed": "Non se puido eliminar o directorio temporal antigo",
|
||||
"restore_nothings_done": "Nada foi restablecido",
|
||||
"restore_not_enough_disk_space": "Non hai espazo abondo (espazo: {free_space.d} B, espazo necesario: {needed_space} B, marxe de seguridade: {margin} B)",
|
||||
|
@ -593,7 +588,7 @@
|
|||
"user_updated": "Cambiada a info da usuaria",
|
||||
"user_update_failed": "Non se actualizou usuaria {user}: {error}",
|
||||
"user_unknown": "Usuaria descoñecida: {user}",
|
||||
"user_home_creation_failed": "Non se puido crear cartafol 'home' para a usuaria",
|
||||
"user_home_creation_failed": "Non se puido crear cartafol home '{home}' para a usuaria",
|
||||
"user_deletion_failed": "Non se puido eliminar a usuaria {user}: {error}",
|
||||
"user_deleted": "Usuaria eliminada",
|
||||
"user_creation_failed": "Non se puido crear a usuaria {user}: {error}",
|
||||
|
@ -613,11 +608,11 @@
|
|||
"unbackup_app": "{app} non vai ser gardada",
|
||||
"tools_upgrade_special_packages_completed": "Completada a actualización dos paquetes YunoHost.\nPreme [Enter] para recuperar a liña de comandos",
|
||||
"tools_upgrade_special_packages_explanation": "A actualización especial continuará en segundo plano. Non inicies outras tarefas no servidor nos seguintes ~10 minutos (depende do hardware). Após isto, podes volver a conectar na webadmin. O rexistro da actualización estará dispoñible en Ferramentas → Rexistro (na webadmin) ou con 'yunohost log list' (na liña de comandos).",
|
||||
"tools_upgrade_special_packages": "Actualizando paquetes 'special' (yunohost-related)…",
|
||||
"tools_upgrade_special_packages": "Actualizando paquetes 'special' (yunohost-related)...",
|
||||
"tools_upgrade_regular_packages_failed": "Non se actualizaron os paquetes: {packages_list}",
|
||||
"tools_upgrade_regular_packages": "Actualizando os paquetes 'regular' (non-yunohost-related)…",
|
||||
"tools_upgrade_cant_unhold_critical_packages": "Non se desbloquearon os paquetes críticos…",
|
||||
"tools_upgrade_cant_hold_critical_packages": "Non se puideron bloquear os paquetes críticos…",
|
||||
"tools_upgrade_regular_packages": "Actualizando os paquetes 'regular' (non-yunohost-related)...",
|
||||
"tools_upgrade_cant_unhold_critical_packages": "Non se desbloquearon os paquetes críticos...",
|
||||
"tools_upgrade_cant_hold_critical_packages": "Non se puideron bloquear os paquetes críticos...",
|
||||
"tools_upgrade_cant_both": "Non se pode actualizar o sistema e as apps ao mesmo tempo",
|
||||
"tools_upgrade_at_least_one": "Por favor indica 'apps', ou 'system'",
|
||||
"this_action_broke_dpkg": "Esta acción rachou dpkg/APT (xestores de paquetes do sistema)... Podes intentar resolver o problema conectando a través de SSH e executando `sudo apt install --fix-broken`e/ou `sudo dpkg --configure -a`.",
|
||||
|
@ -641,5 +636,44 @@
|
|||
"service_removed": "Eliminado o servizo '{service}'",
|
||||
"service_remove_failed": "Non se eliminou o servizo '{service}'",
|
||||
"service_regen_conf_is_deprecated": "'yunohost service regen-conf' xa non se utiliza! Executa 'yunohost tools regen-conf' no seu lugar.",
|
||||
"service_enabled": "O servizo '{service}' vai ser iniciado automáticamente no inicio do sistema."
|
||||
}
|
||||
"service_enabled": "O servizo '{service}' vai ser iniciado automáticamente no inicio do sistema.",
|
||||
"diagnosis_apps_allgood": "Tódalas apps instaladas respectan as prácticas básicas de empaquetado",
|
||||
"diagnosis_apps_bad_quality": "Esta aplicación está actualmente marcada como estragada no catálogo de aplicacións de YunoHost. Podería ser un problema temporal mentras as mantedoras intentan arranxar o problema. Ata ese momento a actualización desta app está desactivada.",
|
||||
"global_settings_setting_security_nginx_redirect_to_https": "Redirixir peticións HTTP a HTTPs por defecto (NON DESACTIVAR ISTO a non ser que realmente saibas o que fas!)",
|
||||
"log_user_import": "Importar usuarias",
|
||||
"user_import_failed": "A operación de importación de usuarias fracasou",
|
||||
"user_import_missing_columns": "Faltan as seguintes columnas: {columns}",
|
||||
"user_import_nothing_to_do": "Ningunha usuaria precisa ser importada",
|
||||
"user_import_partial_failed": "A operación de importación de usuarias fallou parcialmente",
|
||||
"diagnosis_apps_deprecated_practices": "A versión instalada desta app aínda utiliza algunha das antigas prácticas de empaquetado xa abandonadas. Deberías considerar actualizala.",
|
||||
"diagnosis_apps_outdated_ynh_requirement": "A versión instalada desta app só require yunohost >= 2.x, que normalmente indica que non está ao día coas prácticas recomendadas de empaquetado e asistentes. Deberías considerar actualizala.",
|
||||
"user_import_success": "Usuarias importadas correctamente",
|
||||
"diagnosis_high_number_auth_failures": "Hai un alto número sospeitoso de intentos fallidos de autenticación. Deberías comprobar que fail2ban está a executarse e que está correctamente configurado, ou utiliza un porto personalizado para SSH tal como se explica en https://yunohost.org/security.",
|
||||
"user_import_bad_file": "O ficheiro CSV non ten o formato correcto e será ignorado para evitar unha potencial perda de datos",
|
||||
"user_import_bad_line": "Liña incorrecta {line}: {details}",
|
||||
"diagnosis_description_apps": "Aplicacións",
|
||||
"diagnosis_apps_broken": "Actualmente esta aplicación está marcada como estragada no catálogo de aplicacións de YunoHost. Podería tratarse dun problema temporal mentras as mantedoras intentan arraxala. Entanto así a actualización da app está desactivada.",
|
||||
"diagnosis_apps_issue": "Atopouse un problema na app {app}",
|
||||
"diagnosis_apps_not_in_app_catalog": "Esta aplicación non está no catálgo de aplicacións de YunoHost. Se estivo no pasado e foi eliminada, deberías considerar desinstalala porque non recibirá actualizacións, e podería comprometer a integridade e seguridade do teu sistema.",
|
||||
"app_argument_password_help_optional": "Escribe un espazo para limpar o contrasinal",
|
||||
"config_validate_date": "Debe ser unha data válida co formato YYYY-MM-DD",
|
||||
"config_validate_email": "Debe ser un email válido",
|
||||
"config_validate_time": "Debe ser unha hora válida tal que HH:MM",
|
||||
"config_validate_url": "Debe ser un URL válido",
|
||||
"danger": "Perigo:",
|
||||
"app_argument_password_help_keep": "Preme Enter para manter o valor actual",
|
||||
"app_config_unable_to_read": "Fallou a lectura dos valores de configuración.",
|
||||
"config_apply_failed": "Fallou a aplicación da nova configuración: {error}",
|
||||
"config_forbidden_keyword": "O palabra chave '{keyword}' está reservada, non podes crear ou usar un panel de configuración cunha pregunta con este id.",
|
||||
"config_no_panel": "Non se atopa panel configurado.",
|
||||
"config_unknown_filter_key": "A chave do filtro '{filter_key}' non é correcta.",
|
||||
"config_validate_color": "Debe ser un valor RGB hexadecimal válido",
|
||||
"invalid_number_min": "Ten que ser maior que {min}",
|
||||
"log_app_config_set": "Aplicar a configuración á app '{}'",
|
||||
"app_config_unable_to_apply": "Fallou a aplicación dos valores de configuración.",
|
||||
"config_cant_set_value_on_section": "Non podes establecer un valor único na sección completa de configuración.",
|
||||
"config_version_not_supported": "A versión do panel de configuración '{version}' non está soportada.",
|
||||
"file_extension_not_accepted": "Rexeitouse o ficheiro '{path}' porque a súa extensión non está entre as aceptadas: {accept}",
|
||||
"invalid_number_max": "Ten que ser menor de {max}",
|
||||
"service_not_reloading_because_conf_broken": "Non se recargou/reiniciou o servizo '{name}' porque a súa configuración está estragada: {errors}"
|
||||
}
|
1
locales/id.json
Normal file
1
locales/id.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -42,7 +42,7 @@
|
|||
"ask_new_admin_password": "Nuova password dell'amministrazione",
|
||||
"backup_app_failed": "Non è possibile fare il backup {app}",
|
||||
"backup_archive_app_not_found": "{app} non è stata trovata nel archivio di backup",
|
||||
"app_argument_choice_invalid": "Usa una delle seguenti scelte '{choices}' per il parametro '{name}'",
|
||||
"app_argument_choice_invalid": "Usa una delle seguenti scelte '{choices}' per il parametro '{name}' invece di '{value}'",
|
||||
"app_argument_invalid": "Scegli un valore valido per il parametro '{name}': {error}",
|
||||
"app_argument_required": "L'argomento '{name}' è requisito",
|
||||
"app_id_invalid": "Identificativo dell'applicazione non valido",
|
||||
|
@ -67,7 +67,6 @@
|
|||
"domain_dyndns_root_unknown": "Dominio radice DynDNS sconosciuto",
|
||||
"domain_hostname_failed": "Impossibile impostare il nuovo hostname. Potrebbe causare problemi in futuro (o anche no).",
|
||||
"domain_uninstall_app_first": "Queste applicazioni sono già installate su questo dominio:\n{apps}\n\nDisinstallale eseguendo 'yunohost app remove app_id' o spostale in un altro dominio eseguendo 'yunohost app change-url app_id' prima di procedere alla cancellazione del dominio",
|
||||
"domain_unknown": "Dominio sconosciuto",
|
||||
"done": "Terminato",
|
||||
"domains_available": "Domini disponibili:",
|
||||
"downloading": "Scaricamento…",
|
||||
|
@ -104,7 +103,6 @@
|
|||
"pattern_lastname": "Deve essere un cognome valido",
|
||||
"pattern_password": "Deve contenere almeno 3 caratteri",
|
||||
"pattern_port_or_range": "Deve essere un numero di porta valido (es. 0-65535) o una fascia di porte valida (es. 100:200)",
|
||||
"pattern_positive_number": "Deve essere un numero positivo",
|
||||
"pattern_username": "Caratteri minuscoli alfanumerici o trattini bassi soli",
|
||||
"port_already_closed": "La porta {port} è già chiusa per le connessioni {ip_version}",
|
||||
"restore_already_installed_app": "Un'applicazione con l'ID '{app}' è già installata",
|
||||
|
@ -116,8 +114,8 @@
|
|||
"user_update_failed": "Impossibile aggiornare l'utente {user}: {error}",
|
||||
"restore_hook_unavailable": "Lo script di ripristino per '{part}' non è disponibile per il tuo sistema e non è nemmeno nell'archivio",
|
||||
"restore_nothings_done": "Nulla è stato ripristinato",
|
||||
"restore_running_app_script": "Ripristino dell'app '{app}'…",
|
||||
"restore_running_hooks": "Esecuzione degli hook di ripristino…",
|
||||
"restore_running_app_script": "Ripristino dell'app '{app}'...",
|
||||
"restore_running_hooks": "Esecuzione degli hook di ripristino...",
|
||||
"service_added": "Il servizio '{service}' è stato aggiunto",
|
||||
"service_already_started": "Il servizio '{service}' è già avviato",
|
||||
"service_already_stopped": "Il servizio '{service}' è già stato fermato",
|
||||
|
@ -143,7 +141,7 @@
|
|||
"user_created": "Utente creato",
|
||||
"user_creation_failed": "Impossibile creare l'utente {user}: {error}",
|
||||
"user_deletion_failed": "Impossibile cancellare l'utente {user}: {error}",
|
||||
"user_home_creation_failed": "Impossibile creare la 'home' directory del utente",
|
||||
"user_home_creation_failed": "Impossibile creare la home directory '{home}' del utente",
|
||||
"user_unknown": "Utente sconosciuto: {user}",
|
||||
"user_updated": "Info dell'utente cambiate",
|
||||
"yunohost_already_installed": "YunoHost è già installato",
|
||||
|
@ -159,7 +157,6 @@
|
|||
"certmanager_domain_http_not_working": "Il dominio {domain} non sembra accessibile attraverso HTTP. Verifica nella sezione 'Web' nella diagnosi per maggiori informazioni. (Se sai cosa stai facendo, usa '--no-checks' per disattivare i controlli.)",
|
||||
"app_already_installed_cant_change_url": "Questa applicazione è già installata. L'URL non può essere cambiato solo da questa funzione. Controlla se `app changeurl` è disponibile.",
|
||||
"app_already_up_to_date": "{app} è già aggiornata",
|
||||
"app_change_url_failed_nginx_reload": "Non riesco a riavviare NGINX. Questo è il risultato di 'nginx -t':\n{nginx_errors}",
|
||||
"app_change_url_identical_domains": "Il vecchio ed il nuovo dominio/percorso_url sono identici ('{domain}{path}'), nessuna operazione necessaria.",
|
||||
"app_change_url_no_script": "L'applicazione '{app_name}' non supporta ancora la modifica dell'URL. Forse dovresti aggiornarla.",
|
||||
"app_change_url_success": "L'URL dell'applicazione {app} è stato cambiato in {domain}{path}",
|
||||
|
@ -249,7 +246,7 @@
|
|||
"good_practices_about_admin_password": "Stai per impostare una nuova password di amministratore. La password deve essere almeno di 8 caratteri - anche se è buona pratica utilizzare password più lunghe (es. una frase, una serie di parole) e/o utilizzare vari tipi di caratteri (maiuscole, minuscole, numeri e simboli).",
|
||||
"log_corrupted_md_file": "Il file dei metadati YAML associato con i registri è danneggiato: '{md_file}'\nErrore: {error}",
|
||||
"log_link_to_log": "Registro completo di questa operazione: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'",
|
||||
"log_help_to_get_log": "Per vedere il registro dell'operazione '{desc}', usa il comando 'yunohost log show {name}{name}'",
|
||||
"log_help_to_get_log": "Per vedere il registro dell'operazione '{desc}', usa il comando 'yunohost log show {name}'",
|
||||
"global_settings_setting_security_postfix_compatibility": "Bilanciamento tra compatibilità e sicurezza per il server Postfix. Riguarda gli algoritmi di cifratura (e altri aspetti legati alla sicurezza)",
|
||||
"log_link_to_failed_log": "Impossibile completare l'operazione '{desc}'! Per ricevere aiuto, per favore fornisci il registro completo dell'operazione <a href=\"#/tools/logs/{name}\">cliccando qui</a>",
|
||||
"log_help_to_get_failed_log": "L'operazione '{desc}' non può essere completata. Per ottenere aiuto, per favore condividi il registro completo dell'operazione utilizzando il comando 'yunohost log share {name}'",
|
||||
|
@ -398,11 +395,11 @@
|
|||
"unknown_main_domain_path": "Percorso o dominio sconosciuto per '{app}'. Devi specificare un dominio e un percorso per poter specificare un URL per il permesso.",
|
||||
"tools_upgrade_special_packages_completed": "Aggiornamento pacchetti YunoHost completato.\nPremi [Invio] per tornare al terminale",
|
||||
"tools_upgrade_special_packages_explanation": "L'aggiornamento speciale continuerà in background. Per favore non iniziare nessun'altra azione sul tuo server per i prossimi ~10 minuti (dipende dalla velocità hardware). Dopo questo, dovrai ri-loggarti nel webadmin. Il registro di aggiornamento sarà disponibile in Strumenti → Log/Registri (nel webadmin) o dalla linea di comando eseguendo 'yunohost log list'.",
|
||||
"tools_upgrade_special_packages": "Adesso aggiorno i pacchetti 'speciali' (correlati a yunohost)…",
|
||||
"tools_upgrade_special_packages": "Adesso aggiorno i pacchetti 'speciali' (correlati a yunohost)...",
|
||||
"tools_upgrade_regular_packages_failed": "Impossibile aggiornare i pacchetti: {packages_list}",
|
||||
"tools_upgrade_regular_packages": "Adesso aggiorno i pacchetti 'normali' (non correlati a yunohost)…",
|
||||
"tools_upgrade_cant_unhold_critical_packages": "Impossibile annullare il blocco dei pacchetti critici/importanti…",
|
||||
"tools_upgrade_cant_hold_critical_packages": "Impossibile bloccare i pacchetti critici/importanti…",
|
||||
"tools_upgrade_regular_packages": "Adesso aggiorno i pacchetti 'normali' (non correlati a yunohost)...",
|
||||
"tools_upgrade_cant_unhold_critical_packages": "Impossibile annullare il blocco dei pacchetti critici/importanti...",
|
||||
"tools_upgrade_cant_hold_critical_packages": "Impossibile bloccare i pacchetti critici/importanti...",
|
||||
"tools_upgrade_cant_both": "Impossibile aggiornare sia il sistema e le app nello stesso momento",
|
||||
"tools_upgrade_at_least_one": "Specifica 'apps', o 'system'",
|
||||
"show_tile_cant_be_enabled_for_regex": "Non puoi abilitare 'show_tile' in questo momento, perché l'URL del permesso '{permission}' è una regex",
|
||||
|
@ -438,14 +435,14 @@
|
|||
"restore_removing_tmp_dir_failed": "Impossibile rimuovere una vecchia directory temporanea",
|
||||
"restore_not_enough_disk_space": "Spazio libero insufficiente (spazio: {free_space}B, necessario: {needed_space}B, margine di sicurezza: {margin}B)",
|
||||
"restore_may_be_not_enough_disk_space": "Il tuo sistema non sembra avere abbastanza spazio (libero: {free_space}B, necessario: {needed_space}B, margine di sicurezza: {margin}B)",
|
||||
"restore_extracting": "Sto estraendo i file necessari dall'archivio…",
|
||||
"restore_extracting": "Sto estraendo i file necessari dall'archivio...",
|
||||
"restore_already_installed_apps": "Le seguenti app non possono essere ripristinate perché sono già installate: {apps}",
|
||||
"regex_with_only_domain": "Non puoi usare una regex per il dominio, solo per i percorsi",
|
||||
"regex_incompatible_with_tile": "/!\\ Packagers! Il permesso '{permission}' ha show_tile impostato su 'true' e perciò non è possibile definire un URL regex per l'URL principale",
|
||||
"regenconf_need_to_explicitly_specify_ssh": "La configurazione ssh è stata modificata manualmente, ma devi specificare la categoria 'ssh' con --force per applicare le modifiche.",
|
||||
"regenconf_pending_applying": "Applico le configurazioni in attesa per la categoria '{category}'...",
|
||||
"regenconf_failed": "Impossibile rigenerare la configurazione per le categorie: {categories}",
|
||||
"regenconf_dry_pending_applying": "Controllo configurazioni in attesa che potrebbero essere applicate alla categoria '{category}'…",
|
||||
"regenconf_dry_pending_applying": "Controllo configurazioni in attesa che potrebbero essere applicate alla categoria '{category}'...",
|
||||
"regenconf_would_be_updated": "La configurazione sarebbe stata aggiornata per la categoria '{category}'",
|
||||
"regenconf_updated": "Configurazione aggiornata per '{category}'",
|
||||
"regenconf_up_to_date": "Il file di configurazione è già aggiornato per la categoria '{category}'",
|
||||
|
@ -531,8 +528,6 @@
|
|||
"log_permission_url": "Aggiorna l'URL collegato al permesso '{}'",
|
||||
"log_permission_delete": "Cancella permesso '{}'",
|
||||
"log_permission_create": "Crea permesso '{}'",
|
||||
"log_app_config_apply": "Applica la configurazione all'app '{}'",
|
||||
"log_app_config_show_panel": "Mostra il pannello di configurazione dell'app '{}'",
|
||||
"log_app_action_run": "Esegui l'azione dell'app '{}'",
|
||||
"log_operation_unit_unclosed_properly": "Operazion unit non è stata chiusa correttamente",
|
||||
"invalid_regex": "Regex invalida:'{regex}'",
|
||||
|
|
1
locales/mk.json
Normal file
1
locales/mk.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -27,7 +27,6 @@
|
|||
"app_action_cannot_be_ran_because_required_services_down": "Dette programmet krever noen tjenester som ikke kjører. Før du fortsetter, du bør prøve å starte følgende tjenester på ny (og antagelig undersøke hvorfor de er nede): {services}",
|
||||
"app_already_installed_cant_change_url": "Dette programmet er allerede installert. Nettadressen kan ikke endres kun med denne funksjonen. Ta en titt på `app changeurl` hvis den er tilgjengelig.",
|
||||
"domain_exists": "Domenet finnes allerede",
|
||||
"app_change_url_failed_nginx_reload": "Kunne ikke gjeninnlaste NGINX. Her har du utdataen for 'nginx -t'\n{nginx_errors}",
|
||||
"domains_available": "Tilgjengelige domener:",
|
||||
"done": "Ferdig",
|
||||
"downloading": "Laster ned…",
|
||||
|
@ -83,7 +82,6 @@
|
|||
"domain_created": "Domene opprettet",
|
||||
"domain_creation_failed": "Kunne ikke opprette domene",
|
||||
"domain_dyndns_root_unknown": "Ukjent DynDNS-rotdomene",
|
||||
"domain_unknown": "Ukjent domene",
|
||||
"dyndns_ip_update_failed": "Kunne ikke oppdatere IP-adresse til DynDNS",
|
||||
"dyndns_ip_updated": "Oppdaterte din IP på DynDNS",
|
||||
"dyndns_key_generating": "Oppretter DNS-nøkkel… Dette kan ta en stund.",
|
||||
|
@ -115,7 +113,7 @@
|
|||
"domain_deletion_failed": "Kunne ikke slette domene",
|
||||
"domain_dyndns_already_subscribed": "Du har allerede abonnement på et DynDNS-domene",
|
||||
"log_link_to_log": "Full logg for denne operasjonen: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'",
|
||||
"log_help_to_get_log": "For å vise loggen for operasjonen '{desc}', bruk kommandoen 'yunohost log show {name}{name}'",
|
||||
"log_help_to_get_log": "For å vise loggen for operasjonen '{desc}', bruk kommandoen 'yunohost log show {name}'",
|
||||
"log_user_create": "Legg til '{}' bruker",
|
||||
"app_change_url_success": "{app} nettadressen er nå {domain}{path}",
|
||||
"app_install_failed": "Kunne ikke installere {app}: {error}"
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
"domain_dyndns_root_unknown": "Onbekend DynDNS root domein",
|
||||
"domain_exists": "Domein bestaat al",
|
||||
"domain_uninstall_app_first": "Een of meerdere apps zijn geïnstalleerd op dit domein, verwijder deze voordat u het domein verwijdert",
|
||||
"domain_unknown": "Onbekend domein",
|
||||
"done": "Voltooid",
|
||||
"downloading": "Downloaden...",
|
||||
"dyndns_ip_update_failed": "Kan het IP adres niet updaten bij DynDNS",
|
||||
|
@ -102,7 +101,6 @@
|
|||
"app_manifest_install_ask_domain": "Kies het domein waar deze app op geïnstalleerd moet worden",
|
||||
"app_manifest_install_ask_path": "Kies het pad waar deze app geïnstalleerd moet worden",
|
||||
"app_manifest_install_ask_admin": "Kies een administrator voor deze app",
|
||||
"app_change_url_failed_nginx_reload": "Kon NGINX niet opnieuw laden. Hier is de output van 'nginx -t':\n{nginx_errors}",
|
||||
"app_change_url_success": "{app} URL is nu {domain}{path}",
|
||||
"app_full_domain_unavailable": "Sorry, deze app moet op haar eigen domein geïnstalleerd worden, maar andere apps zijn al geïnstalleerd op het domein '{domain}'. U kunt wel een subdomein aan deze app toewijden.",
|
||||
"app_install_script_failed": "Er is een fout opgetreden in het installatiescript van de app",
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
"app_argument_choice_invalid": "Utilizatz una de las opcions « {choices} » per l’argument « {name} »",
|
||||
"app_argument_invalid": "Causissètz una valor invalida pel paramètre « {name} » : {error}",
|
||||
"app_argument_required": "Lo paramètre « {name} » es requesit",
|
||||
"app_change_url_failed_nginx_reload": "Reaviada de NGINX impossibla. Vaquí la sortida de « nginx -t » :\n{nginx_errors}",
|
||||
"app_change_url_identical_domains": "L’ancian e lo novèl coble domeni/camin son identics per {domain}{path}, pas res a far.",
|
||||
"app_change_url_success": "L’URL de l’aplicacion {app} es ara {domain}{path}",
|
||||
"app_extraction_failed": "Extraccion dels fichièrs d’installacion impossibla",
|
||||
|
@ -108,7 +107,6 @@
|
|||
"domain_dyndns_root_unknown": "Domeni DynDNS màger desconegut",
|
||||
"domain_exists": "Lo domeni existís ja",
|
||||
"domain_hostname_failed": "Fracàs de la creacion d’un nòu nom d’òst. Aquò poirà provocar de problèmas mai tard (mas es pas segur… benlèu que coparà pas res).",
|
||||
"domain_unknown": "Domeni desconegut",
|
||||
"domains_available": "Domenis disponibles :",
|
||||
"done": "Acabat",
|
||||
"downloading": "Telecargament…",
|
||||
|
@ -141,7 +139,6 @@
|
|||
"pattern_lastname": "Deu èsser un nom valid",
|
||||
"pattern_password": "Deu conténer almens 3 caractèrs",
|
||||
"pattern_port_or_range": "Deu èsser un numèro de pòrt valid (ex : 0-65535) o un interval de pòrt (ex : 100:200)",
|
||||
"pattern_positive_number": "Deu èsser un nombre positiu",
|
||||
"port_already_closed": "Lo pòrt {port} es ja tampat per las connexions {ip_version}",
|
||||
"port_already_opened": "Lo pòrt {port} es ja dubèrt per las connexions {ip_version}",
|
||||
"restore_already_installed_app": "Una aplicacion es ja installada amb l’id « {app} »",
|
||||
|
@ -248,7 +245,7 @@
|
|||
"experimental_feature": "Atencion : aquesta foncionalitat es experimentala e deu pas èsser considerada coma establa, deuriatz pas l’utilizar levat que sapiatz çò que fasètz.",
|
||||
"log_corrupted_md_file": "Lo fichièr YAML de metadonadas ligat als jornals d’audit es damatjat : « {md_file} »\nError : {error}",
|
||||
"log_link_to_log": "Jornal complèt d’aquesta operacion : <a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>",
|
||||
"log_help_to_get_log": "Per veire lo jornal d’aquesta operacion « {desc} », utilizatz la comanda « yunohost log show {name}{name} »",
|
||||
"log_help_to_get_log": "Per veire lo jornal d’aquesta operacion « {desc} », utilizatz la comanda « yunohost log show {name} »",
|
||||
"log_link_to_failed_log": "L’operacion « {desc} » a pas capitat ! Per obténer d’ajuda, mercés <a href=\"#/tools/logs/{name}\"> de fornir lo jornal complèt de l’operacion</a>",
|
||||
"log_help_to_get_failed_log": "L’operacion « {desc} » a pas reüssit ! Per obténer d’ajuda, mercés de partejar lo jornal d’audit complèt d’aquesta operacion en utilizant la comanda « yunohost log share {name} »",
|
||||
"log_does_exists": "I a pas cap de jornal d’audit per l’operacion amb lo nom « {log} », utilizatz « yunohost log list » per veire totes los jornals d’operacion disponibles",
|
||||
|
@ -448,7 +445,7 @@
|
|||
"diagnosis_ports_could_not_diagnose_details": "Error : {error}",
|
||||
"diagnosis_http_could_not_diagnose": "Impossible de diagnosticar se lo domeni es accessible de l’exterior.",
|
||||
"diagnosis_http_could_not_diagnose_details": "Error : {error}",
|
||||
"apps_catalog_updating": "Actualizacion del catalòg d’aplicacion…",
|
||||
"apps_catalog_updating": "Actualizacion del catalòg d’aplicacion...",
|
||||
"apps_catalog_failed_to_download": "Telecargament impossible del catalòg d’aplicacions {apps_catalog} : {error}",
|
||||
"apps_catalog_obsolete_cache": "La memòria cache del catalòg d’aplicacion es voida o obsolèta.",
|
||||
"apps_catalog_update_success": "Lo catalòg d’aplicacions es a jorn !",
|
||||
|
@ -504,8 +501,6 @@
|
|||
"migration_description_0016_php70_to_php73_pools": "Migrar los fichièrs de configuracion php7.0 cap a php7.3",
|
||||
"migration_description_0015_migrate_to_buster": "Mesa a nivèl dels sistèmas Debian Buster e YunoHost 4.x",
|
||||
"migrating_legacy_permission_settings": "Migracion dels paramètres de permission ancians...",
|
||||
"log_app_config_apply": "Aplicar la configuracion a l’aplicacion « {} »",
|
||||
"log_app_config_show_panel": "Mostrar lo panèl de configuracion de l’aplicacion « {} »",
|
||||
"log_app_action_run": "Executar l’accion de l’aplicacion « {} »",
|
||||
"diagnosis_basesystem_hardware_model": "Lo modèl del servidor es {model}",
|
||||
"backup_archive_cant_retrieve_info_json": "Obtencion impossibla de las informacions de l’archiu « {archive} »... Se pòt pas recuperar lo fichièr info.json (o es pas un fichièr json valid).",
|
||||
|
|
|
@ -20,26 +20,25 @@
|
|||
"ask_new_admin_password": "Nova senha de administração",
|
||||
"ask_password": "Senha",
|
||||
"backup_created": "Backup completo",
|
||||
"backup_output_directory_not_empty": "A pasta de destino não se encontra vazia",
|
||||
"backup_output_directory_not_empty": "Você deve escolher um diretório de saída que esteja vazio",
|
||||
"custom_app_url_required": "Deve fornecer um link para atualizar a sua aplicação personalizada {app}",
|
||||
"domain_cert_gen_failed": "Não foi possível gerar o certificado",
|
||||
"domain_created": "Domínio criado com êxito",
|
||||
"domain_creation_failed": "Não foi possível criar o domínio",
|
||||
"domain_creation_failed": "Não foi possível criar o domínio {domain}: {error}",
|
||||
"domain_deleted": "Domínio removido com êxito",
|
||||
"domain_deletion_failed": "Não foi possível eliminar o domínio",
|
||||
"domain_deletion_failed": "Não foi possível eliminar o domínio {domain}: {error}",
|
||||
"domain_dyndns_already_subscribed": "Já subscreveu um domínio DynDNS",
|
||||
"domain_dyndns_root_unknown": "Domínio root (administrador) DynDNS desconhecido",
|
||||
"domain_exists": "O domínio já existe",
|
||||
"domain_uninstall_app_first": "Existem uma ou mais aplicações instaladas neste domínio. Por favor desinstale-as antes de proceder com a remoção do domínio.",
|
||||
"domain_unknown": "Domínio desconhecido",
|
||||
"done": "Concluído.",
|
||||
"downloading": "Transferência em curso...",
|
||||
"dyndns_ip_update_failed": "Não foi possível atualizar o endereço IP a partir de DynDNS",
|
||||
"dyndns_ip_updated": "Endereço IP atualizado com êxito a partir de DynDNS",
|
||||
"dyndns_ip_update_failed": "Não foi possível atualizar o endereço IP para DynDNS",
|
||||
"dyndns_ip_updated": "Endereço IP atualizado com êxito para DynDNS",
|
||||
"dyndns_key_generating": "A chave DNS está a ser gerada, isto pode demorar um pouco...",
|
||||
"dyndns_registered": "Dom+inio DynDNS registado com êxito",
|
||||
"dyndns_registration_failed": "Não foi possível registar o domínio DynDNS: {error}",
|
||||
"dyndns_unavailable": "Subdomínio DynDNS indisponível",
|
||||
"dyndns_unavailable": "O domínio '{domain}' não está disponível.",
|
||||
"extracting": "Extração em curso...",
|
||||
"field_invalid": "Campo inválido '{}'",
|
||||
"firewall_reloaded": "Firewall recarregada com êxito",
|
||||
|
@ -97,34 +96,33 @@
|
|||
"app_not_properly_removed": "{app} não foi corretamente removido",
|
||||
"app_requirements_checking": "Verificando os pacotes necessários para {app}...",
|
||||
"app_unsupported_remote_type": "A aplicação não possui suporte ao tipo remoto utilizado",
|
||||
"backup_archive_app_not_found": "A aplicação '{app}' não foi encontrada no arquivo de backup",
|
||||
"backup_archive_broken_link": "Impossível acessar o arquivo de backup (link quebrado ao {path})",
|
||||
"backup_archive_name_exists": "O nome do arquivo de backup já existe",
|
||||
"backup_archive_open_failed": "Não é possível abrir o arquivo de backup",
|
||||
"backup_cleaning_failed": "Não é possível limpar a pasta temporária de backups",
|
||||
"backup_creation_failed": "A criação do backup falhou",
|
||||
"backup_delete_error": "Impossível apagar '{path}'",
|
||||
"backup_deleted": "O backup foi suprimido",
|
||||
"backup_hook_unknown": "Gancho de backup '{hook}' desconhecido",
|
||||
"backup_nothings_done": "Não há nada para guardar",
|
||||
"backup_output_directory_forbidden": "Diretório de saída proibido. Os backups não podem ser criados em /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives subpastas",
|
||||
"backup_archive_app_not_found": "Não foi possível encontrar {app} no arquivo de backup",
|
||||
"backup_archive_broken_link": "Não foi possível acessar o arquivo de backup (link quebrado ao {path})",
|
||||
"backup_archive_name_exists": "Já existe um arquivo de backup com esse nome.",
|
||||
"backup_archive_open_failed": "Não foi possível abrir o arquivo de backup",
|
||||
"backup_cleaning_failed": "Não foi possível limpar o diretório temporário de backup",
|
||||
"backup_creation_failed": "Não foi possível criar o arquivo de backup",
|
||||
"backup_delete_error": "Não foi possível remover '{path}'",
|
||||
"backup_deleted": "Backup removido",
|
||||
"backup_hook_unknown": "O gancho de backup '{hook}' é desconhecido",
|
||||
"backup_nothings_done": "Nada há se salvar",
|
||||
"backup_output_directory_forbidden": "Escolha um diretório de saída diferente. Backups não podem ser criados nos subdiretórios /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives",
|
||||
"app_already_installed_cant_change_url": "Este aplicativo já está instalado. A URL não pode ser alterada apenas por esta função. Confira em `app changeurl` se está disponível.",
|
||||
"app_already_up_to_date": "{app} já está atualizado",
|
||||
"app_argument_choice_invalid": "Use uma das opções '{choices}' para o argumento '{name}'",
|
||||
"app_argument_choice_invalid": "Use uma das opções '{choices}' para o argumento '{name}' em vez de '{value}'",
|
||||
"app_argument_invalid": "Escolha um valor válido para o argumento '{name}': {error}",
|
||||
"app_argument_required": "O argumento '{name}' é obrigatório",
|
||||
"app_change_url_failed_nginx_reload": "Não foi possível reiniciar o nginx. Aqui está o retorno de 'nginx -t':\n{nginx_errors}",
|
||||
"app_location_unavailable": "Esta url ou não está disponível ou está em conflito com outra(s) aplicação(ões) já instalada(s):\n{apps}",
|
||||
"app_upgrade_app_name": "Atualizando {app}…",
|
||||
"app_upgrade_some_app_failed": "Não foi possível atualizar algumas aplicações",
|
||||
"backup_abstract_method": "Este metodo de backup ainda não foi implementado",
|
||||
"backup_app_failed": "Não foi possível fazer o backup dos aplicativos '{app}'",
|
||||
"backup_applying_method_custom": "Chamando o metodo personalizado de backup '{method}'…",
|
||||
"backup_applying_method_tar": "Criando o arquivo tar de backup…",
|
||||
"backup_abstract_method": "Este método de backup ainda não foi implementado",
|
||||
"backup_app_failed": "Não foi possível fazer o backup de '{app}'",
|
||||
"backup_applying_method_custom": "Chamando o método personalizado de backup '{method}'…",
|
||||
"backup_applying_method_tar": "Criando o arquivo TAR de backup…",
|
||||
"backup_archive_name_unknown": "Desconhece-se o arquivo local de backup de nome '{name}'",
|
||||
"backup_archive_system_part_not_available": "A seção do sistema '{part}' está indisponivel neste backup",
|
||||
"backup_ask_for_copying_if_needed": "Alguns arquivos não consiguiram ser preparados para backup utilizando o metodo que não gasta espaço de disco temporariamente. Para realizar o backup {size}MB precisam ser usados temporariamente. Você concorda?",
|
||||
"backup_cant_mount_uncompress_archive": "Não foi possível montar em modo leitura o diretorio de arquivos não comprimido",
|
||||
"backup_archive_system_part_not_available": "A seção do sistema '{part}' está indisponível neste backup",
|
||||
"backup_ask_for_copying_if_needed": "Você quer efetuar o backup usando {size}MB temporariamente? (E necessário fazer dessa forma porque alguns arquivos não puderam ser preparados usando um método mais eficiente)",
|
||||
"backup_cant_mount_uncompress_archive": "Não foi possível montar o arquivo descomprimido como protegido contra escrita",
|
||||
"backup_copying_to_organize_the_archive": "Copiando {size}MB para organizar o arquivo",
|
||||
"app_change_url_identical_domains": "O antigo e o novo domínio / url_path são idênticos ('{domain}{path}'), nada para fazer.",
|
||||
"password_too_simple_1": "A senha precisa ter pelo menos 8 caracteres",
|
||||
|
@ -143,7 +141,7 @@
|
|||
"app_change_url_success": "A URL agora é {domain}{path}",
|
||||
"apps_catalog_obsolete_cache": "O cache do catálogo de aplicações está vazio ou obsoleto.",
|
||||
"apps_catalog_failed_to_download": "Não foi possível fazer o download do catálogo de aplicações {apps_catalog}: {error}",
|
||||
"apps_catalog_updating": "Atualizado o catálogo de aplicações…",
|
||||
"apps_catalog_updating": "Atualizando o catálogo de aplicações...",
|
||||
"apps_catalog_init_success": "Catálogo de aplicações do sistema inicializado!",
|
||||
"apps_already_up_to_date": "Todas as aplicações já estão atualizadas",
|
||||
"app_packaging_format_not_supported": "Essa aplicação não pode ser instalada porque o formato dela não é suportado pela sua versão do YunoHost. Considere atualizar seu sistema.",
|
||||
|
@ -164,5 +162,34 @@
|
|||
"app_manifest_install_ask_path": "Escolha o caminho da url (depois do domínio) em que essa aplicação deve ser instalada",
|
||||
"app_manifest_install_ask_domain": "Escolha o domínio em que esta aplicação deve ser instalada",
|
||||
"app_label_deprecated": "Este comando está deprecado! Por favor use o novo comando 'yunohost user permission update' para gerenciar a etiqueta da aplicação.",
|
||||
"app_make_default_location_already_used": "Não foi passível fazer a aplicação '{app}' ser a padrão no domínio, '{domain}' já está sendo usado por '{other_app}'"
|
||||
}
|
||||
"app_make_default_location_already_used": "Não foi passível fazer a aplicação '{app}' ser a padrão no domínio, '{domain}' já está sendo usado por '{other_app}'",
|
||||
"backup_archive_writing_error": "Não foi possível adicionar os arquivos '{source}' (nomeados dentro do arquivo '{dest}') ao backup no arquivo comprimido '{archive}'",
|
||||
"backup_archive_corrupted": "Parece que o arquivo de backup '{archive}' está corrompido: {error}",
|
||||
"backup_archive_cant_retrieve_info_json": "Não foi possível carregar informações para o arquivo '{archive}'... Não foi possível carregar info.json (ou não é um JSON válido).",
|
||||
"backup_applying_method_copy": "Copiando todos os arquivos para o backup...",
|
||||
"backup_actually_backuping": "Criando cópia de backup dos arquivos obtidos...",
|
||||
"ask_user_domain": "Domínio para usar para o endereço de email e conta XMPP do usuário",
|
||||
"ask_new_path": "Novo caminho",
|
||||
"ask_new_domain": "Novo domínio",
|
||||
"apps_catalog_update_success": "O catálogo de aplicações foi atualizado!",
|
||||
"backup_no_uncompress_archive_dir": "Não existe tal diretório de arquivo descomprimido",
|
||||
"backup_mount_archive_for_restore": "Preparando o arquivo para restauração...",
|
||||
"backup_method_tar_finished": "Arquivo de backup TAR criado",
|
||||
"backup_method_custom_finished": "Método de backup personalizado '{method}' finalizado",
|
||||
"backup_method_copy_finished": "Cópia de backup finalizada",
|
||||
"backup_custom_mount_error": "O método personalizado de backup não pôde passar do passo de 'mount'",
|
||||
"backup_custom_backup_error": "O método personalizado de backup não pôde passar do passo de 'backup'",
|
||||
"backup_csv_creation_failed": "Não foi possível criar o arquivo CSV necessário para a restauração",
|
||||
"backup_csv_addition_failed": "Não foi possível adicionar os arquivos que estarão no backup ao arquivo CSV",
|
||||
"backup_create_size_estimation": "O arquivo irá conter cerca de {size} de dados.",
|
||||
"backup_couldnt_bind": "Não foi possível vincular {src} ao {dest}",
|
||||
"certmanager_attempt_to_replace_valid_cert": "Você está tentando sobrescrever um certificado bom e válido para o domínio {domain}! (Use --force para prosseguir mesmo assim)",
|
||||
"backup_with_no_restore_script_for_app": "A aplicação {app} não tem um script de restauração, você não será capaz de automaticamente restaurar o backup dessa aplicação.",
|
||||
"backup_with_no_backup_script_for_app": "A aplicação '{app}' não tem um script de backup. Ignorando.",
|
||||
"backup_unable_to_organize_files": "Não foi possível usar o método rápido de organizar os arquivos no arquivo de backup",
|
||||
"backup_system_part_failed": "Não foi possível fazer o backup da parte do sistema '{part}'",
|
||||
"backup_running_hooks": "Executando os hooks de backup...",
|
||||
"backup_permission": "Permissão de backup para {app}",
|
||||
"backup_output_symlink_dir_broken": "O diretório de seu arquivo '{path}' é um link simbólico quebrado. Talvez você tenha esquecido de re/montar ou conectar o dispositivo de armazenamento para onde o link aponta.",
|
||||
"backup_output_directory_required": "Você deve especificar um diretório de saída para o backup"
|
||||
}
|
|
@ -13,11 +13,10 @@
|
|||
"app_change_url_success": "URL-адреса {app} тепер {domain}{path}",
|
||||
"app_change_url_no_script": "Застосунок '{app_name}' поки не підтримує зміну URL-адрес. Можливо, вам слід оновити його.",
|
||||
"app_change_url_identical_domains": "Старий і новий domain/url_path збігаються ('{domain}{path}'), нічого робити не треба.",
|
||||
"app_change_url_failed_nginx_reload": "Не вдалося перезавантажити NGINX. Ось результат 'nginx -t':\n{nginx_errors}",
|
||||
"app_argument_required": "Аргумент '{name}' необхідний",
|
||||
"app_argument_password_no_default": "Помилка під час розбору аргументу пароля '{name}': аргумент пароля не може мати типове значення з причин безпеки",
|
||||
"app_argument_invalid": "Виберіть правильне значення для аргументу '{name}': {error}",
|
||||
"app_argument_choice_invalid": "Використовуйте один з цих варіантів '{choices}' для аргументу '{name}'",
|
||||
"app_argument_choice_invalid": "Використовуйте один з цих варіантів '{choices}' для аргументу '{name}' замість '{value}'",
|
||||
"app_already_up_to_date": "{app} має найостаннішу версію",
|
||||
"app_already_installed_cant_change_url": "Цей застосунок уже встановлено. URL-адреса не може бути змінена тільки цією функцією. Перевірте в `app changeurl`, якщо вона доступна.",
|
||||
"app_already_installed": "{app} уже встановлено",
|
||||
|
@ -25,9 +24,9 @@
|
|||
"app_action_cannot_be_ran_because_required_services_down": "Для виконання цієї дії повинні бути запущені наступні необхідні служби: {services}. Спробуйте перезапустити їх, щоб продовжити (і, можливо, з'ясувати, чому вони не працюють).",
|
||||
"already_up_to_date": "Нічого не потрібно робити. Все вже актуально.",
|
||||
"admin_password_too_long": "Будь ласка, виберіть пароль коротше 127 символів",
|
||||
"admin_password_changed": "Пароль адміністратора було змінено",
|
||||
"admin_password_changed": "Пароль адміністрації було змінено",
|
||||
"admin_password_change_failed": "Неможливо змінити пароль",
|
||||
"admin_password": "Пароль адміністратора",
|
||||
"admin_password": "Пароль адміністрації",
|
||||
"additional_urls_already_removed": "Додаткова URL-адреса '{url}' вже видалена в додатковій URL-адресі для дозволу '{permission}'",
|
||||
"additional_urls_already_added": "Додаткова URL-адреса '{url}' вже додана в додаткову URL-адресу для дозволу '{permission}'",
|
||||
"action_invalid": "Неприпустима дія '{action}'",
|
||||
|
@ -87,7 +86,7 @@
|
|||
"restore_cleaning_failed": "Не вдалося очистити тимчасовий каталог відновлення",
|
||||
"restore_backup_too_old": "Цей архів резервних копій не може бути відновлений, бо він отриманий з дуже старої версії YunoHost.",
|
||||
"restore_already_installed_apps": "Наступні програми не можуть бути відновлені, тому що вони вже встановлені: {apps}",
|
||||
"restore_already_installed_app": "Застосунок з ID \"{app} 'вже встановлено",
|
||||
"restore_already_installed_app": "Застосунок з ID «{app}» вже встановлено",
|
||||
"regex_with_only_domain": "Ви не можете використовувати regex для домену, тільки для шляху",
|
||||
"regex_incompatible_with_tile": "/! \\ Packagers! Дозвіл '{permission}' має значення show_tile 'true', тому ви не можете визначити regex URL в якості основної URL",
|
||||
"regenconf_need_to_explicitly_specify_ssh": "Конфігурація ssh була змінена вручну, але вам потрібно явно вказати категорію 'ssh' з --force, щоб застосувати зміни.",
|
||||
|
@ -127,7 +126,6 @@
|
|||
"permission_already_allowed": "Група '{group}' вже має увімкнений дозвіл '{permission}'",
|
||||
"pattern_password_app": "На жаль, паролі не можуть містити такі символи: {forbidden_chars}",
|
||||
"pattern_username": "Має складатися тільки з букв і цифр в нижньому регістрі і символів підкреслення",
|
||||
"pattern_positive_number": "Має бути додатним числом",
|
||||
"pattern_port_or_range": "Має бути припустимий номер порту (наприклад, 0-65535) або діапазон портів (наприклад, 100:200)",
|
||||
"pattern_password": "Має бути довжиною не менше 3 символів",
|
||||
"pattern_mailbox_quota": "Має бути розмір з суфіксом b/k/M/G/T або 0, щоб не мати квоти",
|
||||
|
@ -146,7 +144,7 @@
|
|||
"operation_interrupted": "Операція була вручну перервана?",
|
||||
"invalid_number": "Має бути числом",
|
||||
"not_enough_disk_space": "Недостатньо вільного місця на '{path}'",
|
||||
"migrations_to_be_ran_manually": "Міграція {id} повинна бути запущена вручну. Будь ласка, перейдіть в розділ Засоби → Міграції на сторінці вебадміністратора або виконайте команду `yunohost tools migrations run`.",
|
||||
"migrations_to_be_ran_manually": "Міграція {id} повинна бути запущена вручну. Будь ласка, перейдіть в розділ Засоби → Міграції на сторінці вебадміністрації або виконайте команду `yunohost tools migrations run`.",
|
||||
"migrations_success_forward": "Міграцію {id} завершено",
|
||||
"migrations_skip_migration": "Пропускання міграції {id}...",
|
||||
"migrations_running_forward": "Виконання міграції {id}...",
|
||||
|
@ -175,7 +173,7 @@
|
|||
"migration_0015_cleaning_up": "Очищення кеш-пам'яті і пакетів, які більше не потрібні...",
|
||||
"migration_0015_specific_upgrade": "Початок оновлення системних пакетів, які повинні бути оновлені незалежно...",
|
||||
"migration_0015_modified_files": "Зверніть увагу, що такі файли були змінені вручну і можуть бути перезаписані після оновлення: {manually_modified_files}",
|
||||
"migration_0015_problematic_apps_warning": "Зверніть увагу, що були виявлені наступні, можливо, проблемні встановлені застосунки. Схоже, що вони не були встановлені з каталогу застосунків YunoHost або не зазначені як \"робочі\". Отже, не можна гарантувати, що вони будуть працювати після оновлення: {problematic_apps}",
|
||||
"migration_0015_problematic_apps_warning": "Зверніть увагу, що були виявлені наступні, можливо, проблемні встановлені застосунки. Схоже, що вони не були встановлені з каталогу застосунків YunoHost або не зазначені як «робочі». Отже, не можна гарантувати, що вони будуть працювати після оновлення: {problematic_apps}",
|
||||
"migration_0015_general_warning": "Будь ласка, зверніть увагу, що ця міграція є делікатною операцією. Команда YunoHost зробила все можливе, щоб перевірити і протестувати її, але міграція все ще може порушити частина системи або її застосунків.\n\nТому рекомендовано:\n - Виконати резервне копіювання всіх важливих даних або застосунків. Подробиці на сайті https://yunohost.org/backup; \n - Наберіться терпіння після запуску міграції: В залежності від вашого з'єднання з Інтернетом і апаратного забезпечення, оновлення може зайняти до декількох годин.",
|
||||
"migration_0015_system_not_fully_up_to_date": "Ваша система не повністю оновлена. Будь ласка, виконайте регулярне оновлення перед запуском міграції на Buster.",
|
||||
"migration_0015_not_enough_free_space": "Вільного місця в /var/ досить мало! У вас повинно бути не менше 1 ГБ вільного місця, щоб запустити цю міграцію.",
|
||||
|
@ -211,11 +209,11 @@
|
|||
"log_tools_postinstall": "Післявстановлення сервера YunoHost",
|
||||
"log_tools_migrations_migrate_forward": "Запущено міграції",
|
||||
"log_domain_main_domain": "Зроблено '{}' основним доменом",
|
||||
"log_user_permission_reset": "Скинуто дозвіл \"{} '",
|
||||
"log_user_permission_reset": "Скинуто дозвіл «{}»",
|
||||
"log_user_permission_update": "Оновлено доступи для дозволу '{}'",
|
||||
"log_user_update": "Оновлено відомості для користувача '{}'",
|
||||
"log_user_group_update": "Оновлено групу '{}'",
|
||||
"log_user_group_delete": "Видалено групу \"{} '",
|
||||
"log_user_group_delete": "Видалено групу «{}»",
|
||||
"log_user_group_create": "Створено групу '{}'",
|
||||
"log_user_delete": "Видалення користувача '{}'",
|
||||
"log_user_create": "Додавання користувача '{}'",
|
||||
|
@ -236,19 +234,17 @@
|
|||
"log_backup_restore_system": "Відновлення системи з резервного архіву",
|
||||
"log_backup_create": "Створення резервного архіву",
|
||||
"log_available_on_yunopaste": "Цей журнал тепер доступний за посиланням {url}",
|
||||
"log_app_config_apply": "Застосування конфігурації до застосунку '{}'",
|
||||
"log_app_config_show_panel": "Показ панелі конфігурації застосунку '{}'",
|
||||
"log_app_action_run": "Запуск дії застосунку \"{} '",
|
||||
"log_app_action_run": "Запуск дії застосунку «{}»",
|
||||
"log_app_makedefault": "Застосунок '{}' зроблено типовим",
|
||||
"log_app_upgrade": "Оновлення застосунку '{}'",
|
||||
"log_app_remove": "Вилучення застосунку '{}'",
|
||||
"log_app_install": "Установлення застосунку '{}'",
|
||||
"log_app_change_url": "Змінення URL-адреси застосунку \"{} '",
|
||||
"log_app_change_url": "Змінення URL-адреси застосунку «{}»",
|
||||
"log_operation_unit_unclosed_properly": "Блок операцій не був закритий належним чином",
|
||||
"log_does_exists": "Немає журналу операцій з назвою '{log}', використовуйте 'yunohost log list', щоб подивитися всі доступні журнали операцій",
|
||||
"log_help_to_get_failed_log": "Операція '{desc}' не може бути завершена. Будь ласка, поділіться повним журналом цієї операції, використовуючи команду 'yunohost log share {name}', щоб отримати допомогу",
|
||||
"log_link_to_failed_log": "Не вдалося завершити операцію '{desc}'. Будь ласка, надайте повний журнал цієї операції, <a href=\"#/tools/logs/{name}\">натиснувши тут</a>, щоб отримати допомогу",
|
||||
"log_help_to_get_log": "Щоб переглянути журнал операції '{desc}', використовуйте команду 'yunohost log show {name}{name}'",
|
||||
"log_help_to_get_log": "Щоб переглянути журнал операції '{desc}', використовуйте команду 'yunohost log show {name}'",
|
||||
"log_link_to_log": "Повний журнал цієї операції: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'",
|
||||
"log_corrupted_md_file": "Файл метаданих YAML, пов'язаний з журналами, пошкоджено: '{md_file}\nПомилка: {error}'",
|
||||
"iptables_unavailable": "Ви не можете грати з iptables тут. Ви перебуваєте або в контейнері, або ваше ядро не підтримує його",
|
||||
|
@ -277,11 +273,11 @@
|
|||
"group_already_exist_on_system": "Група {group} вже існує в групах системи",
|
||||
"group_already_exist": "Група {group} вже існує",
|
||||
"good_practices_about_user_password": "Зараз ви збираєтеся поставити новий пароль користувача. Пароль повинен складатися не менше ніж з 8 символів, але хорошою практикою є використання більш довгого пароля (тобто гасла) і/або використання різних символів (великих, малих, цифр і спеціальних символів).",
|
||||
"good_practices_about_admin_password": "Зараз ви збираєтеся поставити новий пароль адміністратора. Пароль повинен складатися не менше ніж з 8 символів, але хорошою практикою є використання більш довгого пароля (тобто парольного гасла) і/або використання різних символів (великих, малих, цифр і спеціальних символів).",
|
||||
"good_practices_about_admin_password": "Зараз ви збираєтеся поставити новий пароль адміністрації. Пароль повинен складатися не менше ніж з 8 символів, але хорошою практикою є використання більш довгого пароля (тобто парольного гасла) і/або використання різних символів (великих, малих, цифр і спеціальних символів).",
|
||||
"global_settings_unknown_type": "Несподівана ситуація, налаштування {setting} має тип {unknown_type}, але це не тип, підтримуваний системою.",
|
||||
"global_settings_setting_backup_compress_tar_archives": "При створенні нових резервних копій стискати архіви (.tar.gz) замість нестислих архівів (.tar). NB: вмикання цієї опції означає створення легших архівів резервних копій, але початкова процедура резервного копіювання буде значно довшою і важчою для CPU.",
|
||||
"global_settings_setting_security_webadmin_allowlist": "IP-адреси, яким дозволений доступ до вебадміністратора. Через кому.",
|
||||
"global_settings_setting_security_webadmin_allowlist_enabled": "Дозволити доступ до вебадміністратора тільки деяким IP-адресам.",
|
||||
"global_settings_setting_security_webadmin_allowlist": "IP-адреси, яким дозволений доступ до вебадміністрації. Через кому.",
|
||||
"global_settings_setting_security_webadmin_allowlist_enabled": "Дозволити доступ до вебадміністрації тільки деяким IP-адресам.",
|
||||
"global_settings_setting_smtp_relay_password": "Пароль хоста SMTP-ретрансляції",
|
||||
"global_settings_setting_smtp_relay_user": "Обліковий запис користувача SMTP-ретрансляції",
|
||||
"global_settings_setting_smtp_relay_port": "Порт SMTP-ретрансляції",
|
||||
|
@ -328,7 +324,6 @@
|
|||
"downloading": "Завантаження…",
|
||||
"done": "Готово",
|
||||
"domains_available": "Доступні домени:",
|
||||
"domain_unknown": "Невідомий домен",
|
||||
"domain_name_unknown": "Домен '{domain}' невідомий",
|
||||
"domain_uninstall_app_first": "Ці застосунки все ще встановлені на вашому домені:\n{apps}\n\nВидаліть їх за допомогою 'yunohost app remove the_app_id' або перемістіть їх на інший домен за допомогою 'yunohost app change-url the_app_id', перш ніж приступити до вилучення домену",
|
||||
"domain_remove_confirm_apps_removal": "Вилучення цього домену призведе до вилучення таких застосунків:\n{apps}\n\nВи впевнені, що хочете це зробити? [{answers}]",
|
||||
|
@ -351,7 +346,7 @@
|
|||
"diagnosis_sshd_config_inconsistent": "Схоже, що порт SSH був уручну змінений в /etc/ssh/sshd_config. Починаючи з версії YunoHost 4.2, доступний новий глобальний параметр 'security.ssh.port', що дозволяє уникнути ручного редагування конфігурації.",
|
||||
"diagnosis_sshd_config_insecure": "Схоже, що конфігурація SSH була змінена вручну і є небезпечною, оскільки не містить директив 'AllowGroups' або 'AllowUsers' для обмеження доступу авторизованих користувачів.",
|
||||
"diagnosis_processes_killed_by_oom_reaper": "Деякі процеси було недавно вбито системою через брак пам'яті. Зазвичай це є симптомом нестачі пам'яті в системі або процесу, який з'їв дуже багато пам'яті. Зведення убитих процесів:\n{kills_summary}",
|
||||
"diagnosis_never_ran_yet": "Схоже, що цей сервер був налаштований недавно, і поки немає звіту про діагностику. Вам слід почати з повної діагностики, або з вебадміністратора, або використовуючи 'yunohost diagnosis run' з командного рядка.",
|
||||
"diagnosis_never_ran_yet": "Схоже, що цей сервер був налаштований недавно, і поки немає звіту про діагностику. Вам слід почати з повної діагностики, або з вебадміністрації, або використовуючи 'yunohost diagnosis run' з командного рядка.",
|
||||
"diagnosis_unknown_categories": "Наступні категорії невідомі: {categories}",
|
||||
"diagnosis_http_nginx_conf_not_up_to_date_details": "Щоб виправити становище, перевірте різницю за допомогою командного рядка, використовуючи <cmd>yunohost tools regen-conf nginx --dry-run --with-diff</cmd>, і якщо все в порядку, застосуйте зміни за допомогою команди <cmd>yunohost tools regen-conf nginx --force</cmd>.",
|
||||
"diagnosis_http_nginx_conf_not_up_to_date": "Схоже, що конфігурація nginx цього домену була змінена вручну, що не дозволяє YunoHost визначити, чи доступний він по HTTP.",
|
||||
|
@ -416,7 +411,7 @@
|
|||
"diagnosis_mail_outgoing_port_25_blocked_details": "Спочатку спробуйте розблокувати вихідний порт 25 в інтерфейсі вашого інтернет-маршрутизатора або в інтерфейсі вашого хостинг-провайдера. (Деякі хостинг-провайдери можуть вимагати, щоб ви відправили їм заявку в службу підтримки).",
|
||||
"diagnosis_mail_outgoing_port_25_blocked": "Поштовий сервер SMTP не може відправляти електронні листи на інші сервери, оскільки вихідний порт 25 заблоковано в IPv{ipversion}.",
|
||||
"app_manifest_install_ask_path": "Оберіть шлях URL (після домену), за яким має бути встановлено цей застосунок",
|
||||
"yunohost_postinstall_end_tip": "Післявстановлення завершено! Щоб завершити доналаштування, будь ласка, розгляньте наступні варіанти:\n - додавання першого користувача через розділ 'Користувачі' вебадміністратора (або 'yunohost user create <username>' в командному рядку);\n - діагностика можливих проблем через розділ 'Діагностика' вебадміністратора (або 'yunohost diagnosis run' в командному рядку);\n - прочитання розділів 'Завершення встановлення' і 'Знайомство з YunoHost' у документації адміністратора: https://yunohost.org/admindoc.",
|
||||
"yunohost_postinstall_end_tip": "Післявстановлення завершено! Щоб завершити доналаштування, будь ласка, розгляньте наступні варіанти:\n - додавання першого користувача через розділ 'Користувачі' вебадміністрації (або 'yunohost user create <username>' в командному рядку);\n - діагностика можливих проблем через розділ 'Діагностика' вебадміністрації (або 'yunohost diagnosis run' в командному рядку);\n - прочитання розділів 'Завершення встановлення' і 'Знайомство з YunoHost' у документації адміністратора: https://yunohost.org/admindoc.",
|
||||
"yunohost_not_installed": "YunoHost установлений неправильно. Будь ласка, запустіть 'yunohost tools postinstall'",
|
||||
"yunohost_installing": "Установлення YunoHost...",
|
||||
"yunohost_configured": "YunoHost вже налаштовано",
|
||||
|
@ -445,7 +440,7 @@
|
|||
"unexpected_error": "Щось пішло не так: {error}",
|
||||
"unbackup_app": "{app} НЕ буде збережено",
|
||||
"tools_upgrade_special_packages_completed": "Оновлення пакета YunoHost завершено.\nНатисніть [Enter] для повернення до командного рядка",
|
||||
"tools_upgrade_special_packages_explanation": "Спеціальне оновлення триватиме у тлі. Будь ласка, не запускайте ніяких інших дій на вашому сервері протягом наступних ~ 10 хвилин (в залежності від швидкості обладнання). Після цього вам, можливо, доведеться заново увійти в вебадміністратора. Журнал оновлення буде доступний в Засоби → Журнал (в веб-адміністраторі) або за допомогою 'yunohost log list' (з командного рядка).",
|
||||
"tools_upgrade_special_packages_explanation": "Спеціальне оновлення триватиме у тлі. Будь ласка, не запускайте ніяких інших дій на вашому сервері протягом наступних ~ 10 хвилин (в залежності від швидкості обладнання). Після цього вам, можливо, доведеться заново увійти в вебадміністрації. Журнал оновлення буде доступний в Засоби → Журнал (в вебадміністрації) або за допомогою 'yunohost log list' (з командного рядка).",
|
||||
"tools_upgrade_special_packages": "Тепер оновлюємо 'спеціальні' (пов'язані з yunohost) пакети…",
|
||||
"tools_upgrade_regular_packages_failed": "Не вдалося оновити пакети: {packages_list}",
|
||||
"tools_upgrade_regular_packages": "Тепер оновлюємо 'звичайні' (не пов'язані з yunohost) пакети…",
|
||||
|
@ -476,7 +471,7 @@
|
|||
"diagnosis_diskusage_ok": "У сховищі <code>{mountpoint}</code> (на пристрої <code>{device}</code>) залишилося {free} ({free_percent}%) вільного місця (з {total})!",
|
||||
"diagnosis_diskusage_low": "Сховище <code>{mountpoint}</code> (на пристрої <code>{device}</code>) має тільки {free} ({free_percent}%) вільного місця (з {total}). Будьте уважні.",
|
||||
"diagnosis_diskusage_verylow": "Сховище <code>{mountpoint}</code> (на пристрої <code>{device}</code>) має тільки {free} ({free_percent}%) вільного місця (з {total}). Вам дійсно варто подумати про очищення простору!",
|
||||
"diagnosis_services_bad_status_tip": "Ви можете спробувати <a href='#/services/{service}'>перезапустити службу</a>, а якщо це не допоможе, подивіться <a href='#/services/{service}'>журнали служби в вебадміністраторі </a> (з командного рядка це можна зробити за допомогою <cmd>yunohost service restart {service}</cmd> і <cmd>yunohost service log {service}</cmd>).",
|
||||
"diagnosis_services_bad_status_tip": "Ви можете спробувати <a href='#/services/{service}'>перезапустити службу</a>, а якщо це не допоможе, подивіться <a href='#/services/{service}'>журнали служби в вебадміністрації </a> (з командного рядка це можна зробити за допомогою <cmd>yunohost service restart {service}</cmd> і <cmd>yunohost service log {service}</cmd>).",
|
||||
"diagnosis_services_bad_status": "Служба {service} у стані {status} :(",
|
||||
"diagnosis_services_conf_broken": "Для служби {service} порушена конфігурація!",
|
||||
"diagnosis_services_running": "Службу {service} запущено!",
|
||||
|
@ -507,7 +502,7 @@
|
|||
"diagnosis_ip_connected_ipv6": "Сервер під'єднаний до Інтернету через IPv6!",
|
||||
"diagnosis_ip_no_ipv4": "Сервер не має робочого IPv4.",
|
||||
"diagnosis_ip_connected_ipv4": "Сервер під'єднаний до Інтернету через IPv4!",
|
||||
"diagnosis_no_cache": "Для категорії \"{category} 'ще немає кеша діагностики",
|
||||
"diagnosis_no_cache": "Для категорії «{category}» ще немає кеша діагностики",
|
||||
"diagnosis_failed": "Не вдалося отримати результат діагностики для категорії '{category}': {error}",
|
||||
"diagnosis_everything_ok": "Усе виглядає добре для {category}!",
|
||||
"diagnosis_found_warnings": "Знайдено {warnings} пунктів, які можна поліпшити для {category}.",
|
||||
|
@ -517,7 +512,7 @@
|
|||
"diagnosis_cant_run_because_of_dep": "Неможливо запустити діагностику для {category}, поки є важливі проблеми, пов'язані з {dep}.",
|
||||
"diagnosis_cache_still_valid": "(Кеш все ще дійсний для діагностики {category}. Повторна діагностика поки не проводиться!)",
|
||||
"diagnosis_failed_for_category": "Не вдалося провести діагностику для категорії '{category}': {error}",
|
||||
"diagnosis_display_tip": "Щоб побачити знайдені проблеми, ви можете перейти в розділ Діагностика в вебадміністраторі або виконати команду 'yunohost diagnosis show --issues --human-readable' з командного рядка.",
|
||||
"diagnosis_display_tip": "Щоб побачити знайдені проблеми, ви можете перейти в розділ Діагностика в вебадміністрації або виконати команду 'yunohost diagnosis show --issues --human-readable' з командного рядка.",
|
||||
"diagnosis_package_installed_from_sury_details": "Деякі пакети були ненавмисно встановлені зі стороннього репозиторію під назвою Sury. Команда YunoHost поліпшила стратегію роботи з цими пакетами, але очікується, що в деяких системах, які встановили застосунки PHP7.3 ще на Stretch, залишаться деякі невідповідності. Щоб виправити це становище, спробуйте виконати наступну команду: <cmd>{cmd_to_fix}</cmd>",
|
||||
"diagnosis_package_installed_from_sury": "Деякі системні пакети мають бути зістарені у версії",
|
||||
"diagnosis_backports_in_sources_list": "Схоже, що apt (менеджер пакетів) налаштований на використання репозиторія backports. Якщо ви не знаєте, що робите, ми наполегливо не радимо встановлювати пакети з backports, тому що це може привести до нестабільності або конфліктів у вашій системі.",
|
||||
|
@ -600,7 +595,7 @@
|
|||
"ask_password": "Пароль",
|
||||
"ask_new_path": "Новий шлях",
|
||||
"ask_new_domain": "Новий домен",
|
||||
"ask_new_admin_password": "Новий пароль адміністратора",
|
||||
"ask_new_admin_password": "Новий пароль адміністрації",
|
||||
"ask_main_domain": "Основний домен",
|
||||
"ask_lastname": "Прізвище",
|
||||
"ask_firstname": "Ім'я",
|
||||
|
@ -637,7 +632,7 @@
|
|||
"app_not_upgraded": "Застосунок '{failed_app}' не вдалося оновити, і, як наслідок, оновлення таких застосунків було скасовано: {apps}",
|
||||
"app_manifest_install_ask_is_public": "Чи має цей застосунок бути відкритим для анонімних відвідувачів?",
|
||||
"app_manifest_install_ask_admin": "Виберіть користувача-адміністратора для цього застосунку",
|
||||
"app_manifest_install_ask_password": "Виберіть пароль адміністратора для цього застосунку",
|
||||
"app_manifest_install_ask_password": "Виберіть пароль адміністрації для цього застосунку",
|
||||
"diagnosis_description_apps": "Застосунки",
|
||||
"user_import_success": "Користувачів успішно імпортовано",
|
||||
"user_import_nothing_to_do": "Не потрібно імпортувати жодного користувача",
|
||||
|
@ -657,5 +652,28 @@
|
|||
"diagnosis_apps_broken": "Цей застосунок наразі позначено як зламаний у каталозі застосунків YunoHost. Це може бути тимчасовою проблемою, поки організатори намагаються вирішити цю проблему. Тим часом оновлення цього застосунку вимкнено.",
|
||||
"diagnosis_apps_not_in_app_catalog": "Цей застосунок не міститься у каталозі застосунків YunoHost. Якщо він був у минулому і був видалений, вам слід подумати про видалення цього застосунку, оскільки він не отримає оновлення, і це може поставити під загрозу цілісність та безпеку вашої системи.",
|
||||
"diagnosis_apps_issue": "Виявлено проблему із застосунком {app}",
|
||||
"diagnosis_apps_allgood": "Усі встановлені застосунки дотримуються основних способів упакування"
|
||||
}
|
||||
"diagnosis_apps_allgood": "Усі встановлені застосунки дотримуються основних способів упакування",
|
||||
"diagnosis_high_number_auth_failures": "Останнім часом сталася підозріло велика кількість помилок автентифікації. Ви можете переконатися, що fail2ban працює і правильно налаштований, або скористатися власним портом для SSH, як описано в https://yunohost.org/security.",
|
||||
"global_settings_setting_security_nginx_redirect_to_https": "Типово переспрямовувати HTTP-запити до HTTP (НЕ ВИМИКАЙТЕ, якщо ви дійсно не знаєте, що робите!)",
|
||||
"app_config_unable_to_apply": "Не вдалося застосувати значення панелі конфігурації.",
|
||||
"app_config_unable_to_read": "Не вдалося розпізнати значення панелі конфігурації.",
|
||||
"config_apply_failed": "Не вдалося застосувати нову конфігурацію: {error}",
|
||||
"config_cant_set_value_on_section": "Ви не можете встановити одне значення на весь розділ конфігурації.",
|
||||
"config_forbidden_keyword": "Ключове слово '{keyword}' зарезервовано, ви не можете створити або використовувати панель конфігурації з запитом із таким ID.",
|
||||
"config_no_panel": "Панель конфігурації не знайдено.",
|
||||
"config_unknown_filter_key": "Ключ фільтра '{filter_key}' недійсний.",
|
||||
"config_validate_color": "Колір RGB має бути дійсним шістнадцятковим кольоровим кодом",
|
||||
"config_validate_date": "Дата має бути дійсною, наприклад, у форматі РРРР-ММ-ДД",
|
||||
"config_validate_email": "Е-пошта має бути дійсною",
|
||||
"config_validate_time": "Час має бути дійсним, наприклад ГГ:ХХ",
|
||||
"config_validate_url": "Вебадреса має бути дійсною",
|
||||
"config_version_not_supported": "Версії конфігураційної панелі '{version}' не підтримуються.",
|
||||
"danger": "Небезпека:",
|
||||
"file_extension_not_accepted": "Файл '{path}' відхиляється, бо його розширення не входить в число прийнятих розширень: {accept}",
|
||||
"invalid_number_min": "Має бути більшим за {min}",
|
||||
"invalid_number_max": "Має бути меншим за {max}",
|
||||
"log_app_config_set": "Застосувати конфігурацію до застосунку '{}'",
|
||||
"service_not_reloading_because_conf_broken": "Неможливо перезавантажити/перезапустити службу '{name}', тому що її конфігурацію порушено: {errors}",
|
||||
"app_argument_password_help_optional": "Введіть один пробіл, щоб очистити пароль",
|
||||
"app_argument_password_help_keep": "Натисніть Enter, щоб зберегти поточне значення"
|
||||
}
|
|
@ -150,7 +150,6 @@
|
|||
"app_change_url_success": "{app} URL现在为 {domain}{path}",
|
||||
"app_change_url_no_script": "应用程序'{app_name}'尚不支持URL修改. 也许您应该升级它。",
|
||||
"app_change_url_identical_domains": "新旧domain / url_path是相同的('{domain}{path}'),无需执行任何操作。",
|
||||
"app_change_url_failed_nginx_reload": "无法重新加载NGINX. 这是'nginx -t'的输出:\n{nginx_errors}",
|
||||
"app_argument_required": "参数'{name}'为必填项",
|
||||
"app_argument_password_no_default": "解析密码参数'{name}'时出错:出于安全原因,密码参数不能具有默认值",
|
||||
"app_argument_invalid": "为参数'{name}'选择一个有效值: {error}",
|
||||
|
@ -360,7 +359,6 @@
|
|||
"downloading": "下载中…",
|
||||
"done": "完成",
|
||||
"domains_available": "可用域:",
|
||||
"domain_unknown": "未知网域",
|
||||
"domain_name_unknown": "域'{domain}'未知",
|
||||
"domain_uninstall_app_first": "这些应用程序仍安装在您的域中:\n{apps}\n\n请先使用 'yunohost app remove the_app_id' 将其卸载,或使用 'yunohost app change-url the_app_id'将其移至另一个域,然后再继续删除域",
|
||||
"domain_remove_confirm_apps_removal": "删除该域将删除这些应用程序:\n{apps}\n\n您确定要这样做吗? [{answers}]",
|
||||
|
@ -499,8 +497,6 @@
|
|||
"diagnosis_dns_discrepancy": "以下DNS记录似乎未遵循建议的配置:<br>类型: <code>{type}</code><br>名称: <code>{name}</code><br>代码> 当前值: <code>{current}期望值: <code>{value}</code>",
|
||||
"log_backup_create": "创建备份档案",
|
||||
"log_available_on_yunopaste": "现在可以通过{url}使用此日志",
|
||||
"log_app_config_apply": "将配置应用于 '{}' 应用",
|
||||
"log_app_config_show_panel": "显示 '{}' 应用的配置面板",
|
||||
"log_app_action_run": "运行 '{}' 应用的操作",
|
||||
"log_app_makedefault": "将 '{}' 设为默认应用",
|
||||
"log_app_upgrade": "升级 '{}' 应用",
|
||||
|
@ -511,7 +507,7 @@
|
|||
"log_does_exists": "没有名称为'{log}'的操作日志,请使用 'yunohost log list' 查看所有可用的操作日志",
|
||||
"log_help_to_get_failed_log": "操作'{desc}'无法完成。请使用命令'yunohost log share {name}' 共享此操作的完整日志以获取帮助",
|
||||
"log_link_to_failed_log": "无法完成操作 '{desc}'。请通过<a href=\"#/tools/logs/{name}\">单击此处</a>提供此操作的完整日志以获取帮助",
|
||||
"log_help_to_get_log": "要查看操作'{desc}'的日志,请使用命令'yunohost log show {name}{name}'",
|
||||
"log_help_to_get_log": "要查看操作'{desc}'的日志,请使用命令'yunohost log show {name}'",
|
||||
"log_link_to_log": "此操作的完整日志: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'",
|
||||
"log_corrupted_md_file": "与日志关联的YAML元数据文件已损坏: '{md_file}\n错误: {error}'",
|
||||
"iptables_unavailable": "你不能在这里使用iptables。你要么在一个容器中,要么你的内核不支持它",
|
||||
|
@ -541,7 +537,6 @@
|
|||
"permission_already_allowed": "群组 '{group}' 已启用权限'{permission}'",
|
||||
"pattern_password_app": "抱歉,密码不能包含以下字符: {forbidden_chars}",
|
||||
"pattern_username": "只能为小写字母数字和下划线字符",
|
||||
"pattern_positive_number": "必须为正数",
|
||||
"pattern_port_or_range": "必须是有效的端口号(即0-65535)或端口范围(例如100:200)",
|
||||
"pattern_password": "必须至少3个字符长",
|
||||
"pattern_mailbox_quota": "必须为带b/k/M/G/T 后缀的大小或0,才能没有配额",
|
||||
|
|
2
src/yunohost/.coveragerc
Normal file
2
src/yunohost/.coveragerc
Normal file
|
@ -0,0 +1,2 @@
|
|||
[report]
|
||||
omit=tests/*,vendor/*,/usr/lib/moulinette/yunohost/
|
File diff suppressed because it is too large
Load diff
|
@ -44,11 +44,11 @@ from moulinette.utils.log import getActionLogger
|
|||
from moulinette.utils.filesystem import read_file, mkdir, write_to_yaml, read_yaml
|
||||
from moulinette.utils.process import check_output
|
||||
|
||||
import yunohost.domain
|
||||
from yunohost.app import (
|
||||
app_info,
|
||||
_is_installed,
|
||||
_make_environment_for_app_script,
|
||||
dump_app_log_extract_for_debugging,
|
||||
_patch_legacy_helpers,
|
||||
_patch_legacy_php_versions,
|
||||
_patch_legacy_php_versions_in_settings,
|
||||
|
@ -60,6 +60,7 @@ from yunohost.hook import (
|
|||
hook_info,
|
||||
hook_callback,
|
||||
hook_exec,
|
||||
hook_exec_with_script_debug_if_failure,
|
||||
CUSTOM_HOOK_FOLDER,
|
||||
)
|
||||
from yunohost.tools import (
|
||||
|
@ -707,6 +708,9 @@ class BackupManager:
|
|||
|
||||
# Prepare environment
|
||||
env_dict = self._get_env_var(app)
|
||||
env_dict["YNH_APP_BASEDIR"] = os.path.join(
|
||||
self.work_dir, "apps", app, "settings"
|
||||
)
|
||||
tmp_app_bkp_dir = env_dict["YNH_APP_BACKUP_DIR"]
|
||||
settings_dir = os.path.join(self.work_dir, "apps", app, "settings")
|
||||
|
||||
|
@ -1287,6 +1291,8 @@ class RestoreManager:
|
|||
else:
|
||||
operation_logger.success()
|
||||
|
||||
yunohost.domain.domain_list_cache = {}
|
||||
|
||||
regen_conf()
|
||||
|
||||
_tools_migrations_run_after_system_restore(
|
||||
|
@ -1491,6 +1497,9 @@ class RestoreManager:
|
|||
"YNH_APP_BACKUP_DIR": os.path.join(
|
||||
self.work_dir, "apps", app_instance_name, "backup"
|
||||
),
|
||||
"YNH_APP_BASEDIR": os.path.join(
|
||||
self.work_dir, "apps", app_instance_name, "settings"
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -1500,37 +1509,19 @@ class RestoreManager:
|
|||
# Execute the app install script
|
||||
restore_failed = True
|
||||
try:
|
||||
restore_retcode = hook_exec(
|
||||
(
|
||||
restore_failed,
|
||||
failure_message_with_debug_instructions,
|
||||
) = hook_exec_with_script_debug_if_failure(
|
||||
restore_script,
|
||||
chdir=app_backup_in_archive,
|
||||
env=env_dict,
|
||||
)[0]
|
||||
# "Common" app restore failure : the script failed and returned exit code != 0
|
||||
restore_failed = True if restore_retcode != 0 else False
|
||||
if restore_failed:
|
||||
error = m18n.n("app_restore_script_failed")
|
||||
logger.error(
|
||||
m18n.n("app_restore_failed", app=app_instance_name, error=error)
|
||||
)
|
||||
failure_message_with_debug_instructions = operation_logger.error(error)
|
||||
if Moulinette.interface.type != "api":
|
||||
dump_app_log_extract_for_debugging(operation_logger)
|
||||
# Script got manually interrupted ... N.B. : KeyboardInterrupt does not inherit from Exception
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
error = m18n.n("operation_interrupted")
|
||||
logger.error(
|
||||
m18n.n("app_restore_failed", app=app_instance_name, error=error)
|
||||
operation_logger=operation_logger,
|
||||
error_message_if_script_failed=m18n.n("app_restore_script_failed"),
|
||||
error_message_if_failed=lambda e: m18n.n(
|
||||
"app_restore_failed", app=app_instance_name, error=e
|
||||
),
|
||||
)
|
||||
failure_message_with_debug_instructions = operation_logger.error(error)
|
||||
# Something wrong happened in Yunohost's code (most probably hook_exec)
|
||||
except Exception:
|
||||
import traceback
|
||||
|
||||
error = m18n.n("unexpected_error", error="\n" + traceback.format_exc())
|
||||
logger.error(
|
||||
m18n.n("app_restore_failed", app=app_instance_name, error=error)
|
||||
)
|
||||
failure_message_with_debug_instructions = operation_logger.error(error)
|
||||
finally:
|
||||
# Cleaning temporary scripts directory
|
||||
shutil.rmtree(tmp_workdir_for_app, ignore_errors=True)
|
||||
|
@ -1546,6 +1537,9 @@ class RestoreManager:
|
|||
|
||||
# Setup environment for remove script
|
||||
env_dict_remove = _make_environment_for_app_script(app_instance_name)
|
||||
env_dict_remove["YNH_APP_BASEDIR"] = os.path.join(
|
||||
self.work_dir, "apps", app_instance_name, "settings"
|
||||
)
|
||||
|
||||
remove_operation_logger = OperationLogger(
|
||||
"remove_on_failed_restore",
|
||||
|
|
|
@ -86,11 +86,8 @@ def certificate_status(domain_list, full=False):
|
|||
domain_list = yunohost.domain.domain_list()["domains"]
|
||||
# Else, validate that yunohost knows the domains given
|
||||
else:
|
||||
yunohost_domains_list = yunohost.domain.domain_list()["domains"]
|
||||
for domain in domain_list:
|
||||
# Is it in Yunohost domain list?
|
||||
if domain not in yunohost_domains_list:
|
||||
raise YunohostValidationError("domain_name_unknown", domain=domain)
|
||||
yunohost.domain._assert_domain_exists(domain)
|
||||
|
||||
certificates = {}
|
||||
|
||||
|
@ -267,9 +264,7 @@ def _certificate_install_letsencrypt(
|
|||
# Else, validate that yunohost knows the domains given
|
||||
else:
|
||||
for domain in domain_list:
|
||||
yunohost_domains_list = yunohost.domain.domain_list()["domains"]
|
||||
if domain not in yunohost_domains_list:
|
||||
raise YunohostValidationError("domain_name_unknown", domain=domain)
|
||||
yunohost.domain._assert_domain_exists(domain)
|
||||
|
||||
# Is it self-signed?
|
||||
status = _get_status(domain)
|
||||
|
@ -368,9 +363,8 @@ def certificate_renew(
|
|||
else:
|
||||
for domain in domain_list:
|
||||
|
||||
# Is it in Yunohost dmomain list?
|
||||
if domain not in yunohost.domain.domain_list()["domains"]:
|
||||
raise YunohostValidationError("domain_name_unknown", domain=domain)
|
||||
# Is it in Yunohost domain list?
|
||||
yunohost.domain._assert_domain_exists(domain)
|
||||
|
||||
status = _get_status(domain)
|
||||
|
||||
|
|
|
@ -36,6 +36,13 @@ class MyMigration(Migration):
|
|||
|
||||
logger.info(m18n.n("migration_0021_start"))
|
||||
|
||||
#
|
||||
# Add new apt .deb signing key
|
||||
#
|
||||
|
||||
new_apt_key = "https://forge.yunohost.org/yunohost_bullseye.asc"
|
||||
check_output(f"wget -O- {new_apt_key} -q | apt-key add -qq -")
|
||||
|
||||
#
|
||||
# Patch sources.list
|
||||
#
|
||||
|
|
1002
src/yunohost/dns.py
Normal file
1002
src/yunohost/dns.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -24,13 +24,12 @@
|
|||
Manage domains
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
from typing import Dict, Any
|
||||
|
||||
from moulinette import m18n, Moulinette
|
||||
from moulinette.core import MoulinetteError
|
||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||
from moulinette.utils.log import getActionLogger
|
||||
from moulinette.utils.filesystem import write_to_file
|
||||
from moulinette.utils.filesystem import write_to_file, read_yaml, write_to_yaml
|
||||
|
||||
from yunohost.app import (
|
||||
app_ssowatconf,
|
||||
|
@ -39,12 +38,18 @@ from yunohost.app import (
|
|||
_get_conflicting_apps,
|
||||
)
|
||||
from yunohost.regenconf import regen_conf, _force_clear_hashes, _process_regen_conf
|
||||
from yunohost.utils.network import get_public_ip
|
||||
from yunohost.utils.config import ConfigPanel, Question
|
||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||
from yunohost.log import is_unit_operation
|
||||
from yunohost.hook import hook_callback
|
||||
|
||||
logger = getActionLogger("yunohost.domain")
|
||||
|
||||
DOMAIN_CONFIG_PATH = "/usr/share/yunohost/other/config_domain.toml"
|
||||
DOMAIN_SETTINGS_DIR = "/etc/yunohost/domains"
|
||||
|
||||
# Lazy dev caching to avoid re-query ldap every time we need the domain list
|
||||
domain_list_cache: Dict[str, Any] = {}
|
||||
|
||||
|
||||
def domain_list(exclude_subdomains=False):
|
||||
"""
|
||||
|
@ -54,6 +59,10 @@ def domain_list(exclude_subdomains=False):
|
|||
exclude_subdomains -- Filter out domains that are subdomains of other declared domains
|
||||
|
||||
"""
|
||||
global domain_list_cache
|
||||
if not exclude_subdomains and domain_list_cache:
|
||||
return domain_list_cache
|
||||
|
||||
from yunohost.utils.ldap import _get_ldap_interface
|
||||
|
||||
ldap = _get_ldap_interface()
|
||||
|
@ -83,7 +92,17 @@ def domain_list(exclude_subdomains=False):
|
|||
|
||||
result_list = sorted(result_list, key=cmp_domain)
|
||||
|
||||
return {"domains": result_list, "main": _get_maindomain()}
|
||||
# Don't cache answer if using exclude_subdomains
|
||||
if exclude_subdomains:
|
||||
return {"domains": result_list, "main": _get_maindomain()}
|
||||
|
||||
domain_list_cache = {"domains": result_list, "main": _get_maindomain()}
|
||||
return domain_list_cache
|
||||
|
||||
|
||||
def _assert_domain_exists(domain):
|
||||
if domain not in domain_list()["domains"]:
|
||||
raise YunohostValidationError("domain_name_unknown", domain=domain)
|
||||
|
||||
|
||||
@is_unit_operation()
|
||||
|
@ -152,6 +171,9 @@ def domain_add(operation_logger, domain, dyndns=False):
|
|||
ldap.add("virtualdomain=%s,ou=domains" % domain, attr_dict)
|
||||
except Exception as e:
|
||||
raise YunohostError("domain_creation_failed", domain=domain, error=e)
|
||||
finally:
|
||||
global domain_list_cache
|
||||
domain_list_cache = {}
|
||||
|
||||
# Don't regen these conf if we're still in postinstall
|
||||
if os.path.exists("/etc/yunohost/installed"):
|
||||
|
@ -203,8 +225,8 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False):
|
|||
# the 'force' here is related to the exception happening in domain_add ...
|
||||
# we don't want to check the domain exists because the ldap add may have
|
||||
# failed
|
||||
if not force and domain not in domain_list()["domains"]:
|
||||
raise YunohostValidationError("domain_name_unknown", domain=domain)
|
||||
if not force:
|
||||
_assert_domain_exists(domain)
|
||||
|
||||
# Check domain is not the main domain
|
||||
if domain == _get_maindomain():
|
||||
|
@ -268,11 +290,18 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False):
|
|||
ldap.remove("virtualdomain=" + domain + ",ou=domains")
|
||||
except Exception as e:
|
||||
raise YunohostError("domain_deletion_failed", domain=domain, error=e)
|
||||
finally:
|
||||
global domain_list_cache
|
||||
domain_list_cache = {}
|
||||
|
||||
os.system("rm -rf /etc/yunohost/certs/%s" % domain)
|
||||
stuff_to_delete = [
|
||||
f"/etc/yunohost/certs/{domain}",
|
||||
f"/etc/yunohost/dyndns/K{domain}.+*",
|
||||
f"{DOMAIN_SETTINGS_DIR}/{domain}.yml",
|
||||
]
|
||||
|
||||
# Delete dyndns keys for this domain (if any)
|
||||
os.system("rm -rf /etc/yunohost/dyndns/K%s.+*" % domain)
|
||||
for stuff in stuff_to_delete:
|
||||
os.system("rm -rf {stuff}")
|
||||
|
||||
# Sometime we have weird issues with the regenconf where some files
|
||||
# appears as manually modified even though they weren't touched ...
|
||||
|
@ -303,57 +332,6 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False):
|
|||
logger.success(m18n.n("domain_deleted"))
|
||||
|
||||
|
||||
def domain_dns_conf(domain, ttl=None):
|
||||
"""
|
||||
Generate DNS configuration for a domain
|
||||
|
||||
Keyword argument:
|
||||
domain -- Domain name
|
||||
ttl -- Time to live
|
||||
|
||||
"""
|
||||
|
||||
if domain not in domain_list()["domains"]:
|
||||
raise YunohostValidationError("domain_name_unknown", domain=domain)
|
||||
|
||||
ttl = 3600 if ttl is None else ttl
|
||||
|
||||
dns_conf = _build_dns_conf(domain, ttl)
|
||||
|
||||
result = ""
|
||||
|
||||
result += "; Basic ipv4/ipv6 records"
|
||||
for record in dns_conf["basic"]:
|
||||
result += "\n{name} {ttl} IN {type} {value}".format(**record)
|
||||
|
||||
result += "\n\n"
|
||||
result += "; XMPP"
|
||||
for record in dns_conf["xmpp"]:
|
||||
result += "\n{name} {ttl} IN {type} {value}".format(**record)
|
||||
|
||||
result += "\n\n"
|
||||
result += "; Mail"
|
||||
for record in dns_conf["mail"]:
|
||||
result += "\n{name} {ttl} IN {type} {value}".format(**record)
|
||||
result += "\n\n"
|
||||
|
||||
result += "; Extra"
|
||||
for record in dns_conf["extra"]:
|
||||
result += "\n{name} {ttl} IN {type} {value}".format(**record)
|
||||
|
||||
for name, record_list in dns_conf.items():
|
||||
if name not in ("basic", "xmpp", "mail", "extra") and record_list:
|
||||
result += "\n\n"
|
||||
result += "; " + name
|
||||
for record in record_list:
|
||||
result += "\n{name} {ttl} IN {type} {value}".format(**record)
|
||||
|
||||
if Moulinette.interface.type == "cli":
|
||||
logger.info(m18n.n("domain_dns_conf_is_just_a_recommendation"))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@is_unit_operation()
|
||||
def domain_main_domain(operation_logger, new_main_domain=None):
|
||||
"""
|
||||
|
@ -370,8 +348,7 @@ def domain_main_domain(operation_logger, new_main_domain=None):
|
|||
return {"current_main_domain": _get_maindomain()}
|
||||
|
||||
# Check domain exists
|
||||
if new_main_domain not in domain_list()["domains"]:
|
||||
raise YunohostValidationError("domain_name_unknown", domain=new_main_domain)
|
||||
_assert_domain_exists(new_main_domain)
|
||||
|
||||
operation_logger.related_to.append(("domain", new_main_domain))
|
||||
operation_logger.start()
|
||||
|
@ -379,7 +356,8 @@ def domain_main_domain(operation_logger, new_main_domain=None):
|
|||
# Apply changes to ssl certs
|
||||
try:
|
||||
write_to_file("/etc/yunohost/current_host", new_main_domain)
|
||||
|
||||
global domain_list_cache
|
||||
domain_list_cache = {}
|
||||
_set_hostname(new_main_domain)
|
||||
except Exception as e:
|
||||
logger.warning("%s" % e, exc_info=1)
|
||||
|
@ -395,6 +373,116 @@ def domain_main_domain(operation_logger, new_main_domain=None):
|
|||
logger.success(m18n.n("main_domain_changed"))
|
||||
|
||||
|
||||
def domain_url_available(domain, path):
|
||||
"""
|
||||
Check availability of a web path
|
||||
|
||||
Keyword argument:
|
||||
domain -- The domain for the web path (e.g. your.domain.tld)
|
||||
path -- The path to check (e.g. /coffee)
|
||||
"""
|
||||
|
||||
return len(_get_conflicting_apps(domain, path)) == 0
|
||||
|
||||
|
||||
def _get_maindomain():
|
||||
with open("/etc/yunohost/current_host", "r") as f:
|
||||
maindomain = f.readline().rstrip()
|
||||
return maindomain
|
||||
|
||||
|
||||
def domain_config_get(domain, key="", full=False, export=False):
|
||||
"""
|
||||
Display a domain configuration
|
||||
"""
|
||||
|
||||
if full and export:
|
||||
raise YunohostValidationError(
|
||||
"You can't use --full and --export together.", raw_msg=True
|
||||
)
|
||||
|
||||
if full:
|
||||
mode = "full"
|
||||
elif export:
|
||||
mode = "export"
|
||||
else:
|
||||
mode = "classic"
|
||||
|
||||
config = DomainConfigPanel(domain)
|
||||
return config.get(key, mode)
|
||||
|
||||
|
||||
@is_unit_operation()
|
||||
def domain_config_set(
|
||||
operation_logger, domain, key=None, value=None, args=None, args_file=None
|
||||
):
|
||||
"""
|
||||
Apply a new domain configuration
|
||||
"""
|
||||
Question.operation_logger = operation_logger
|
||||
config = DomainConfigPanel(domain)
|
||||
return config.set(key, value, args, args_file, operation_logger=operation_logger)
|
||||
|
||||
|
||||
class DomainConfigPanel(ConfigPanel):
|
||||
def __init__(self, domain):
|
||||
_assert_domain_exists(domain)
|
||||
self.domain = domain
|
||||
self.save_mode = "diff"
|
||||
super().__init__(
|
||||
config_path=DOMAIN_CONFIG_PATH,
|
||||
save_path=f"{DOMAIN_SETTINGS_DIR}/{domain}.yml",
|
||||
)
|
||||
|
||||
def _get_toml(self):
|
||||
from yunohost.dns import _get_registrar_config_section
|
||||
|
||||
toml = super()._get_toml()
|
||||
|
||||
toml["feature"]["xmpp"]["xmpp"]["default"] = (
|
||||
1 if self.domain == _get_maindomain() else 0
|
||||
)
|
||||
toml["dns"]["registrar"] = _get_registrar_config_section(self.domain)
|
||||
|
||||
# FIXME: Ugly hack to save the registar id/value and reinject it in _load_current_values ...
|
||||
self.registar_id = toml["dns"]["registrar"]["registrar"]["value"]
|
||||
del toml["dns"]["registrar"]["registrar"]["value"]
|
||||
|
||||
return toml
|
||||
|
||||
def _load_current_values(self):
|
||||
|
||||
# TODO add mechanism to share some settings with other domains on the same zone
|
||||
super()._load_current_values()
|
||||
|
||||
# FIXME: Ugly hack to save the registar id/value and reinject it in _load_current_values ...
|
||||
self.values["registrar"] = self.registar_id
|
||||
|
||||
|
||||
def _get_domain_settings(domain: str) -> dict:
|
||||
|
||||
_assert_domain_exists(domain)
|
||||
|
||||
if os.path.exists(f"{DOMAIN_SETTINGS_DIR}/{domain}.yml"):
|
||||
return read_yaml(f"{DOMAIN_SETTINGS_DIR}/{domain}.yml") or {}
|
||||
else:
|
||||
return {}
|
||||
|
||||
|
||||
def _set_domain_settings(domain: str, settings: dict) -> None:
|
||||
|
||||
_assert_domain_exists(domain)
|
||||
|
||||
write_to_yaml(f"{DOMAIN_SETTINGS_DIR}/{domain}.yml", settings)
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
# Stuff managed in other files
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
def domain_cert_status(domain_list, full=False):
|
||||
import yunohost.certificate
|
||||
|
||||
|
@ -421,268 +509,17 @@ def domain_cert_renew(
|
|||
)
|
||||
|
||||
|
||||
def domain_url_available(domain, path):
|
||||
"""
|
||||
Check availability of a web path
|
||||
|
||||
Keyword argument:
|
||||
domain -- The domain for the web path (e.g. your.domain.tld)
|
||||
path -- The path to check (e.g. /coffee)
|
||||
"""
|
||||
|
||||
return len(_get_conflicting_apps(domain, path)) == 0
|
||||
def domain_dns_conf(domain):
|
||||
return domain_dns_suggest(domain)
|
||||
|
||||
|
||||
def _get_maindomain():
|
||||
with open("/etc/yunohost/current_host", "r") as f:
|
||||
maindomain = f.readline().rstrip()
|
||||
return maindomain
|
||||
def domain_dns_suggest(domain):
|
||||
import yunohost.dns
|
||||
|
||||
return yunohost.dns.domain_dns_suggest(domain)
|
||||
|
||||
|
||||
def _build_dns_conf(domain, ttl=3600, include_empty_AAAA_if_no_ipv6=False):
|
||||
"""
|
||||
Internal function that will returns a data structure containing the needed
|
||||
information to generate/adapt the dns configuration
|
||||
def domain_dns_push(domain, dry_run, force, purge):
|
||||
import yunohost.dns
|
||||
|
||||
The returned datastructure will have the following form:
|
||||
{
|
||||
"basic": [
|
||||
# if ipv4 available
|
||||
{"type": "A", "name": "@", "value": "123.123.123.123", "ttl": 3600},
|
||||
# if ipv6 available
|
||||
{"type": "AAAA", "name": "@", "value": "valid-ipv6", "ttl": 3600},
|
||||
],
|
||||
"xmpp": [
|
||||
{"type": "SRV", "name": "_xmpp-client._tcp", "value": "0 5 5222 domain.tld.", "ttl": 3600},
|
||||
{"type": "SRV", "name": "_xmpp-server._tcp", "value": "0 5 5269 domain.tld.", "ttl": 3600},
|
||||
{"type": "CNAME", "name": "muc", "value": "@", "ttl": 3600},
|
||||
{"type": "CNAME", "name": "pubsub", "value": "@", "ttl": 3600},
|
||||
{"type": "CNAME", "name": "vjud", "value": "@", "ttl": 3600}
|
||||
{"type": "CNAME", "name": "xmpp-upload", "value": "@", "ttl": 3600}
|
||||
],
|
||||
"mail": [
|
||||
{"type": "MX", "name": "@", "value": "10 domain.tld.", "ttl": 3600},
|
||||
{"type": "TXT", "name": "@", "value": "\"v=spf1 a mx ip4:123.123.123.123 ipv6:valid-ipv6 -all\"", "ttl": 3600 },
|
||||
{"type": "TXT", "name": "mail._domainkey", "value": "\"v=DKIM1; k=rsa; p=some-super-long-key\"", "ttl": 3600},
|
||||
{"type": "TXT", "name": "_dmarc", "value": "\"v=DMARC1; p=none\"", "ttl": 3600}
|
||||
],
|
||||
"extra": [
|
||||
# if ipv4 available
|
||||
{"type": "A", "name": "*", "value": "123.123.123.123", "ttl": 3600},
|
||||
# if ipv6 available
|
||||
{"type": "AAAA", "name": "*", "value": "valid-ipv6", "ttl": 3600},
|
||||
{"type": "CAA", "name": "@", "value": "128 issue \"letsencrypt.org\"", "ttl": 3600},
|
||||
],
|
||||
"example_of_a_custom_rule": [
|
||||
{"type": "SRV", "name": "_matrix", "value": "domain.tld.", "ttl": 3600}
|
||||
],
|
||||
}
|
||||
"""
|
||||
|
||||
ipv4 = get_public_ip()
|
||||
ipv6 = get_public_ip(6)
|
||||
|
||||
###########################
|
||||
# Basic ipv4/ipv6 records #
|
||||
###########################
|
||||
|
||||
basic = []
|
||||
if ipv4:
|
||||
basic.append(["@", ttl, "A", ipv4])
|
||||
|
||||
if ipv6:
|
||||
basic.append(["@", ttl, "AAAA", ipv6])
|
||||
elif include_empty_AAAA_if_no_ipv6:
|
||||
basic.append(["@", ttl, "AAAA", None])
|
||||
|
||||
#########
|
||||
# Email #
|
||||
#########
|
||||
|
||||
mail = [
|
||||
["@", ttl, "MX", "10 %s." % domain],
|
||||
["@", ttl, "TXT", '"v=spf1 a mx -all"'],
|
||||
]
|
||||
|
||||
# DKIM/DMARC record
|
||||
dkim_host, dkim_publickey = _get_DKIM(domain)
|
||||
|
||||
if dkim_host:
|
||||
mail += [
|
||||
[dkim_host, ttl, "TXT", dkim_publickey],
|
||||
["_dmarc", ttl, "TXT", '"v=DMARC1; p=none"'],
|
||||
]
|
||||
|
||||
########
|
||||
# XMPP #
|
||||
########
|
||||
|
||||
xmpp = [
|
||||
["_xmpp-client._tcp", ttl, "SRV", "0 5 5222 %s." % domain],
|
||||
["_xmpp-server._tcp", ttl, "SRV", "0 5 5269 %s." % domain],
|
||||
["muc", ttl, "CNAME", "@"],
|
||||
["pubsub", ttl, "CNAME", "@"],
|
||||
["vjud", ttl, "CNAME", "@"],
|
||||
["xmpp-upload", ttl, "CNAME", "@"],
|
||||
]
|
||||
|
||||
#########
|
||||
# Extra #
|
||||
#########
|
||||
|
||||
extra = []
|
||||
|
||||
if ipv4:
|
||||
extra.append(["*", ttl, "A", ipv4])
|
||||
|
||||
if ipv6:
|
||||
extra.append(["*", ttl, "AAAA", ipv6])
|
||||
elif include_empty_AAAA_if_no_ipv6:
|
||||
extra.append(["*", ttl, "AAAA", None])
|
||||
|
||||
extra.append(["@", ttl, "CAA", '128 issue "letsencrypt.org"'])
|
||||
|
||||
####################
|
||||
# Standard records #
|
||||
####################
|
||||
|
||||
records = {
|
||||
"basic": [
|
||||
{"name": name, "ttl": ttl_, "type": type_, "value": value}
|
||||
for name, ttl_, type_, value in basic
|
||||
],
|
||||
"xmpp": [
|
||||
{"name": name, "ttl": ttl_, "type": type_, "value": value}
|
||||
for name, ttl_, type_, value in xmpp
|
||||
],
|
||||
"mail": [
|
||||
{"name": name, "ttl": ttl_, "type": type_, "value": value}
|
||||
for name, ttl_, type_, value in mail
|
||||
],
|
||||
"extra": [
|
||||
{"name": name, "ttl": ttl_, "type": type_, "value": value}
|
||||
for name, ttl_, type_, value in extra
|
||||
],
|
||||
}
|
||||
|
||||
##################
|
||||
# Custom records #
|
||||
##################
|
||||
|
||||
# Defined by custom hooks ships in apps for example ...
|
||||
|
||||
hook_results = hook_callback("custom_dns_rules", args=[domain])
|
||||
for hook_name, results in hook_results.items():
|
||||
#
|
||||
# There can be multiple results per hook name, so results look like
|
||||
# {'/some/path/to/hook1':
|
||||
# { 'state': 'succeed',
|
||||
# 'stdreturn': [{'type': 'SRV',
|
||||
# 'name': 'stuff.foo.bar.',
|
||||
# 'value': 'yoloswag',
|
||||
# 'ttl': 3600}]
|
||||
# },
|
||||
# '/some/path/to/hook2':
|
||||
# { ... },
|
||||
# [...]
|
||||
#
|
||||
# Loop over the sub-results
|
||||
custom_records = [
|
||||
v["stdreturn"] for v in results.values() if v and v["stdreturn"]
|
||||
]
|
||||
|
||||
records[hook_name] = []
|
||||
for record_list in custom_records:
|
||||
# Check that record_list is indeed a list of dict
|
||||
# with the required keys
|
||||
if (
|
||||
not isinstance(record_list, list)
|
||||
or any(not isinstance(record, dict) for record in record_list)
|
||||
or any(
|
||||
key not in record
|
||||
for record in record_list
|
||||
for key in ["name", "ttl", "type", "value"]
|
||||
)
|
||||
):
|
||||
# Display an error, mainly for app packagers trying to implement a hook
|
||||
logger.warning(
|
||||
"Ignored custom record from hook '%s' because the data is not a *list* of dict with keys name, ttl, type and value. Raw data : %s"
|
||||
% (hook_name, record_list)
|
||||
)
|
||||
continue
|
||||
|
||||
records[hook_name].extend(record_list)
|
||||
|
||||
return records
|
||||
|
||||
|
||||
def _get_DKIM(domain):
|
||||
DKIM_file = "/etc/dkim/{domain}.mail.txt".format(domain=domain)
|
||||
|
||||
if not os.path.isfile(DKIM_file):
|
||||
return (None, None)
|
||||
|
||||
with open(DKIM_file) as f:
|
||||
dkim_content = f.read()
|
||||
|
||||
# Gotta manage two formats :
|
||||
#
|
||||
# Legacy
|
||||
# -----
|
||||
#
|
||||
# mail._domainkey IN TXT ( "v=DKIM1; k=rsa; "
|
||||
# "p=<theDKIMpublicKey>" )
|
||||
#
|
||||
# New
|
||||
# ------
|
||||
#
|
||||
# mail._domainkey IN TXT ( "v=DKIM1; h=sha256; k=rsa; "
|
||||
# "p=<theDKIMpublicKey>" )
|
||||
|
||||
is_legacy_format = " h=sha256; " not in dkim_content
|
||||
|
||||
# Legacy DKIM format
|
||||
if is_legacy_format:
|
||||
dkim = re.match(
|
||||
(
|
||||
r"^(?P<host>[a-z_\-\.]+)[\s]+([0-9]+[\s]+)?IN[\s]+TXT[\s]+"
|
||||
r'[^"]*"v=(?P<v>[^";]+);'
|
||||
r'[\s"]*k=(?P<k>[^";]+);'
|
||||
r'[\s"]*p=(?P<p>[^";]+)'
|
||||
),
|
||||
dkim_content,
|
||||
re.M | re.S,
|
||||
)
|
||||
else:
|
||||
dkim = re.match(
|
||||
(
|
||||
r"^(?P<host>[a-z_\-\.]+)[\s]+([0-9]+[\s]+)?IN[\s]+TXT[\s]+"
|
||||
r'[^"]*"v=(?P<v>[^";]+);'
|
||||
r'[\s"]*h=(?P<h>[^";]+);'
|
||||
r'[\s"]*k=(?P<k>[^";]+);'
|
||||
r'[\s"]*p=(?P<p>[^";]+)'
|
||||
),
|
||||
dkim_content,
|
||||
re.M | re.S,
|
||||
)
|
||||
|
||||
if not dkim:
|
||||
return (None, None)
|
||||
|
||||
if is_legacy_format:
|
||||
return (
|
||||
dkim.group("host"),
|
||||
'"v={v}; k={k}; p={p}"'.format(
|
||||
v=dkim.group("v"), k=dkim.group("k"), p=dkim.group("p")
|
||||
),
|
||||
)
|
||||
else:
|
||||
return (
|
||||
dkim.group("host"),
|
||||
'"v={v}; h={h}; k={k}; p={p}"'.format(
|
||||
v=dkim.group("v"),
|
||||
h=dkim.group("h"),
|
||||
k=dkim.group("k"),
|
||||
p=dkim.group("p"),
|
||||
),
|
||||
)
|
||||
return yunohost.dns.domain_dns_push(domain, dry_run, force, purge)
|
||||
|
|
|
@ -37,8 +37,9 @@ from moulinette.utils.filesystem import write_to_file, read_file
|
|||
from moulinette.utils.network import download_json
|
||||
|
||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||
from yunohost.domain import _get_maindomain, _build_dns_conf
|
||||
from yunohost.utils.network import get_public_ip, dig
|
||||
from yunohost.domain import _get_maindomain
|
||||
from yunohost.utils.network import get_public_ip
|
||||
from yunohost.utils.dns import dig
|
||||
from yunohost.log import is_unit_operation
|
||||
from yunohost.regenconf import regen_conf
|
||||
|
||||
|
@ -224,9 +225,8 @@ def dyndns_update(
|
|||
ipv6 -- IPv6 address to send
|
||||
|
||||
"""
|
||||
# Get old ipv4/v6
|
||||
|
||||
old_ipv4, old_ipv6 = (None, None) # (default values)
|
||||
from yunohost.dns import _build_dns_conf
|
||||
|
||||
# If domain is not given, try to guess it from keys available...
|
||||
if domain is None:
|
||||
|
@ -307,6 +307,12 @@ def dyndns_update(
|
|||
logger.debug("Old IPv4/v6 are (%s, %s)" % (old_ipv4, old_ipv6))
|
||||
logger.debug("Requested IPv4/v6 are (%s, %s)" % (ipv4, ipv6))
|
||||
|
||||
if ipv4 is None and ipv6 is None:
|
||||
logger.debug(
|
||||
"No ipv4 nor ipv6 ?! Sounds like the server is not connected to the internet, or the ip.yunohost.org infrastructure is down somehow"
|
||||
)
|
||||
return
|
||||
|
||||
# no need to update
|
||||
if (not force and not dry_run) and (old_ipv4 == ipv4 and old_ipv6 == ipv6):
|
||||
logger.info("No updated needed.")
|
||||
|
|
|
@ -34,7 +34,7 @@ from importlib import import_module
|
|||
from moulinette import m18n, Moulinette
|
||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||
from moulinette.utils import log
|
||||
from moulinette.utils.filesystem import read_json
|
||||
from moulinette.utils.filesystem import read_yaml
|
||||
|
||||
HOOK_FOLDER = "/usr/share/yunohost/hooks/"
|
||||
CUSTOM_HOOK_FOLDER = "/etc/yunohost/hooks.d/"
|
||||
|
@ -326,7 +326,7 @@ def hook_exec(
|
|||
chdir=None,
|
||||
env=None,
|
||||
user="root",
|
||||
return_format="json",
|
||||
return_format="yaml",
|
||||
):
|
||||
"""
|
||||
Execute hook from a file with arguments
|
||||
|
@ -447,10 +447,10 @@ def _hook_exec_bash(path, args, chdir, env, user, return_format, loggers):
|
|||
raw_content = f.read()
|
||||
returncontent = {}
|
||||
|
||||
if return_format == "json":
|
||||
if return_format == "yaml":
|
||||
if raw_content != "":
|
||||
try:
|
||||
returncontent = read_json(stdreturn)
|
||||
returncontent = read_yaml(stdreturn)
|
||||
except Exception as e:
|
||||
raise YunohostError(
|
||||
"hook_json_return_error",
|
||||
|
@ -498,6 +498,40 @@ def _hook_exec_python(path, args, env, loggers):
|
|||
return ret
|
||||
|
||||
|
||||
def hook_exec_with_script_debug_if_failure(*args, **kwargs):
|
||||
|
||||
operation_logger = kwargs.pop("operation_logger")
|
||||
error_message_if_failed = kwargs.pop("error_message_if_failed")
|
||||
error_message_if_script_failed = kwargs.pop("error_message_if_script_failed")
|
||||
|
||||
failed = True
|
||||
failure_message_with_debug_instructions = None
|
||||
try:
|
||||
retcode, retpayload = hook_exec(*args, **kwargs)
|
||||
failed = True if retcode != 0 else False
|
||||
if failed:
|
||||
error = error_message_if_script_failed
|
||||
logger.error(error_message_if_failed(error))
|
||||
failure_message_with_debug_instructions = operation_logger.error(error)
|
||||
if Moulinette.interface.type != "api":
|
||||
operation_logger.dump_script_log_extract_for_debugging()
|
||||
# Script got manually interrupted ...
|
||||
# N.B. : KeyboardInterrupt does not inherit from Exception
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
error = m18n.n("operation_interrupted")
|
||||
logger.error(error_message_if_failed(error))
|
||||
failure_message_with_debug_instructions = operation_logger.error(error)
|
||||
# Something wrong happened in Yunohost's code (most probably hook_exec)
|
||||
except Exception:
|
||||
import traceback
|
||||
|
||||
error = m18n.n("unexpected_error", error="\n" + traceback.format_exc())
|
||||
logger.error(error_message_if_failed(error))
|
||||
failure_message_with_debug_instructions = operation_logger.error(error)
|
||||
|
||||
return failed, failure_message_with_debug_instructions
|
||||
|
||||
|
||||
def _extract_filename_parts(filename):
|
||||
"""Extract hook parts from filename"""
|
||||
if "-" in filename:
|
||||
|
|
|
@ -29,6 +29,7 @@ import re
|
|||
import yaml
|
||||
import glob
|
||||
import psutil
|
||||
from typing import List
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from logging import FileHandler, getLogger, Formatter
|
||||
|
@ -69,7 +70,13 @@ def log_list(limit=None, with_details=False, with_suboperations=False):
|
|||
logs = list(reversed(sorted(logs)))
|
||||
|
||||
if limit is not None:
|
||||
logs = logs[:limit]
|
||||
if with_suboperations:
|
||||
logs = logs[:limit]
|
||||
else:
|
||||
# If we displaying only parent, we are still gonna load up to limit * 5 logs
|
||||
# because many of them are suboperations which are not gonna be kept
|
||||
# Yet we still want to obtain ~limit number of logs
|
||||
logs = logs[: limit * 5]
|
||||
|
||||
for log in logs:
|
||||
|
||||
|
@ -122,6 +129,9 @@ def log_list(limit=None, with_details=False, with_suboperations=False):
|
|||
else:
|
||||
operations = [o for o in operations.values()]
|
||||
|
||||
if limit:
|
||||
operations = operations[:limit]
|
||||
|
||||
operations = list(reversed(sorted(operations, key=lambda o: o["name"])))
|
||||
# Reverse the order of log when in cli, more comfortable to read (avoid
|
||||
# unecessary scrolling)
|
||||
|
@ -151,26 +161,42 @@ def log_show(
|
|||
filter_irrelevant = True
|
||||
|
||||
if filter_irrelevant:
|
||||
filters = [
|
||||
r"set [+-]x$",
|
||||
r"set [+-]o xtrace$",
|
||||
r"local \w+$",
|
||||
r"local legacy_args=.*$",
|
||||
r".*Helper used in legacy mode.*",
|
||||
r"args_array=.*$",
|
||||
r"local -A args_array$",
|
||||
r"ynh_handle_getopts_args",
|
||||
r"ynh_script_progression",
|
||||
]
|
||||
|
||||
def _filter(lines):
|
||||
filters = [
|
||||
r"set [+-]x$",
|
||||
r"set [+-]o xtrace$",
|
||||
r"set [+-]o errexit$",
|
||||
r"set [+-]o nounset$",
|
||||
r"trap '' EXIT",
|
||||
r"local \w+$",
|
||||
r"local exit_code=(1|0)$",
|
||||
r"local legacy_args=.*$",
|
||||
r"local -A args_array$",
|
||||
r"args_array=.*$",
|
||||
r"ret_code=1",
|
||||
r".*Helper used in legacy mode.*",
|
||||
r"ynh_handle_getopts_args",
|
||||
r"ynh_script_progression",
|
||||
r"sleep 0.5",
|
||||
r"'\[' (1|0) -eq (1|0) '\]'$",
|
||||
r"\[?\['? -n '' '?\]\]?$",
|
||||
r"rm -rf /var/cache/yunohost/download/$",
|
||||
r"type -t ynh_clean_setup$",
|
||||
r"DEBUG - \+ echo '",
|
||||
r"DEBUG - \+ exit (1|0)$",
|
||||
]
|
||||
filters = [re.compile(f) for f in filters]
|
||||
return [
|
||||
line
|
||||
for line in lines
|
||||
if not any(f.search(line.strip()) for f in filters)
|
||||
]
|
||||
|
||||
else:
|
||||
filters = []
|
||||
|
||||
def _filter_lines(lines, filters=[]):
|
||||
|
||||
filters = [re.compile(f) for f in filters]
|
||||
return [
|
||||
line for line in lines if not any(f.search(line.strip()) for f in filters)
|
||||
]
|
||||
def _filter(lines):
|
||||
return lines
|
||||
|
||||
# Normalize log/metadata paths and filenames
|
||||
abs_path = path
|
||||
|
@ -209,7 +235,7 @@ def log_show(
|
|||
content += "\n============\n\n"
|
||||
if os.path.exists(log_path):
|
||||
actual_log = read_file(log_path)
|
||||
content += "\n".join(_filter_lines(actual_log.split("\n"), filters))
|
||||
content += "\n".join(_filter(actual_log.split("\n")))
|
||||
|
||||
url = yunopaste(content)
|
||||
|
||||
|
@ -282,13 +308,13 @@ def log_show(
|
|||
if os.path.exists(log_path):
|
||||
from yunohost.service import _tail
|
||||
|
||||
if number and filters:
|
||||
if number and filter_irrelevant:
|
||||
logs = _tail(log_path, int(number * 4))
|
||||
elif number:
|
||||
logs = _tail(log_path, int(number))
|
||||
else:
|
||||
logs = read_file(log_path)
|
||||
logs = _filter_lines(logs, filters)
|
||||
logs = list(_filter(logs))
|
||||
if number:
|
||||
logs = logs[-number:]
|
||||
infos["log_path"] = log_path
|
||||
|
@ -427,7 +453,7 @@ class RedactingFormatter(Formatter):
|
|||
# (the secret part being at least 3 chars to avoid catching some lines like just "db_pwd=")
|
||||
# Some names like "key" or "manifest_key" are ignored, used in helpers like ynh_app_setting_set or ynh_read_manifest
|
||||
match = re.search(
|
||||
r"(pwd|pass|password|passphrase|secret\w*|\w+key|token|PASSPHRASE)=(\S{3,})$",
|
||||
r"(pwd|pass|passwd|password|passphrase|secret\w*|\w+key|token|PASSPHRASE)=(\S{3,})$",
|
||||
record.strip(),
|
||||
)
|
||||
if (
|
||||
|
@ -453,7 +479,7 @@ class OperationLogger(object):
|
|||
This class record logs and metadata like context or start time/end time.
|
||||
"""
|
||||
|
||||
_instances = []
|
||||
_instances: List[object] = []
|
||||
|
||||
def __init__(self, operation, related_to=None, **kwargs):
|
||||
# TODO add a way to not save password on app installation
|
||||
|
@ -707,6 +733,52 @@ class OperationLogger(object):
|
|||
else:
|
||||
self.error(m18n.n("log_operation_unit_unclosed_properly"))
|
||||
|
||||
def dump_script_log_extract_for_debugging(self):
|
||||
|
||||
with open(self.log_path, "r") as f:
|
||||
lines = f.readlines()
|
||||
|
||||
filters = [
|
||||
r"set [+-]x$",
|
||||
r"set [+-]o xtrace$",
|
||||
r"local \w+$",
|
||||
r"local legacy_args=.*$",
|
||||
r".*Helper used in legacy mode.*",
|
||||
r"args_array=.*$",
|
||||
r"local -A args_array$",
|
||||
r"ynh_handle_getopts_args",
|
||||
r"ynh_script_progression",
|
||||
]
|
||||
|
||||
filters = [re.compile(f_) for f_ in filters]
|
||||
|
||||
lines_to_display = []
|
||||
for line in lines:
|
||||
|
||||
if ": " not in line.strip():
|
||||
continue
|
||||
|
||||
# A line typically looks like
|
||||
# 2019-10-19 16:10:27,611: DEBUG - + mysql -u piwigo --password=********** -B piwigo
|
||||
# And we just want the part starting by "DEBUG - "
|
||||
line = line.strip().split(": ", 1)[1]
|
||||
|
||||
if any(filter_.search(line) for filter_ in filters):
|
||||
continue
|
||||
|
||||
lines_to_display.append(line)
|
||||
|
||||
if line.endswith("+ ynh_exit_properly") or " + ynh_die " in line:
|
||||
break
|
||||
elif len(lines_to_display) > 20:
|
||||
lines_to_display.pop(0)
|
||||
|
||||
logger.warning(
|
||||
"Here's an extract of the logs before the crash. It might help debugging the error:"
|
||||
)
|
||||
for line in lines_to_display:
|
||||
logger.info(line)
|
||||
|
||||
|
||||
def _get_datetime_from_name(name):
|
||||
|
||||
|
|
|
@ -457,22 +457,26 @@ def permission_create(
|
|||
"permission_creation_failed", permission=permission, error=e
|
||||
)
|
||||
|
||||
permission_url(
|
||||
permission,
|
||||
url=url,
|
||||
add_url=additional_urls,
|
||||
auth_header=auth_header,
|
||||
sync_perm=False,
|
||||
)
|
||||
try:
|
||||
permission_url(
|
||||
permission,
|
||||
url=url,
|
||||
add_url=additional_urls,
|
||||
auth_header=auth_header,
|
||||
sync_perm=False,
|
||||
)
|
||||
|
||||
new_permission = _update_ldap_group_permission(
|
||||
permission=permission,
|
||||
allowed=allowed,
|
||||
label=label,
|
||||
show_tile=show_tile,
|
||||
protected=protected,
|
||||
sync_perm=sync_perm,
|
||||
)
|
||||
new_permission = _update_ldap_group_permission(
|
||||
permission=permission,
|
||||
allowed=allowed,
|
||||
label=label,
|
||||
show_tile=show_tile,
|
||||
protected=protected,
|
||||
sync_perm=sync_perm,
|
||||
)
|
||||
except:
|
||||
permission_delete(permission, force=True)
|
||||
raise
|
||||
|
||||
logger.debug(m18n.n("permission_created", permission=permission))
|
||||
return new_permission
|
||||
|
@ -860,11 +864,9 @@ def _validate_and_sanitize_permission_url(url, app_base_path, app):
|
|||
re:^/api/.*|/scripts/api.js$
|
||||
"""
|
||||
|
||||
from yunohost.domain import domain_list
|
||||
from yunohost.domain import _assert_domain_exists
|
||||
from yunohost.app import _assert_no_conflicting_apps
|
||||
|
||||
domains = domain_list()["domains"]
|
||||
|
||||
#
|
||||
# Regexes
|
||||
#
|
||||
|
@ -896,8 +898,8 @@ def _validate_and_sanitize_permission_url(url, app_base_path, app):
|
|||
domain, path = url[3:].split("/", 1)
|
||||
path = "/" + path
|
||||
|
||||
if domain.replace("%", "").replace("\\", "") not in domains:
|
||||
raise YunohostValidationError("domain_name_unknown", domain=domain)
|
||||
domain_with_no_regex = domain.replace("%", "").replace("\\", "")
|
||||
_assert_domain_exists(domain_with_no_regex)
|
||||
|
||||
validate_regex(path)
|
||||
|
||||
|
@ -931,8 +933,7 @@ def _validate_and_sanitize_permission_url(url, app_base_path, app):
|
|||
domain, path = split_domain_path(url)
|
||||
sanitized_url = domain + path
|
||||
|
||||
if domain not in domains:
|
||||
raise YunohostValidationError("domain_name_unknown", domain=domain)
|
||||
_assert_domain_exists(domain)
|
||||
|
||||
_assert_no_conflicting_apps(domain, path, ignore_app=app)
|
||||
|
||||
|
|
|
@ -105,13 +105,9 @@ def regen_conf(
|
|||
else:
|
||||
filesystem.mkdir(PENDING_CONF_DIR, 0o755, True)
|
||||
|
||||
# Format common hooks arguments
|
||||
common_args = [1 if force else 0, 1 if dry_run else 0]
|
||||
|
||||
# Execute hooks for pre-regen
|
||||
pre_args = [
|
||||
"pre",
|
||||
] + common_args
|
||||
# element 2 and 3 with empty string is because of legacy...
|
||||
pre_args = ["pre", "", ""]
|
||||
|
||||
def _pre_call(name, priority, path, args):
|
||||
# create the pending conf directory for the category
|
||||
|
@ -417,9 +413,8 @@ def regen_conf(
|
|||
return result
|
||||
|
||||
# Execute hooks for post-regen
|
||||
post_args = [
|
||||
"post",
|
||||
] + common_args
|
||||
# element 2 and 3 with empty string is because of legacy...
|
||||
post_args = ["post", "", ""]
|
||||
|
||||
def _pre_call(name, priority, path, args):
|
||||
# append coma-separated applied changes for the category
|
||||
|
|
|
@ -243,7 +243,7 @@ def service_restart(names):
|
|||
)
|
||||
|
||||
|
||||
def service_reload_or_restart(names):
|
||||
def service_reload_or_restart(names, test_conf=True):
|
||||
"""
|
||||
Reload one or more services if they support it. If not, restart them instead. If the services are not running yet, they will be started.
|
||||
|
||||
|
@ -253,7 +253,36 @@ def service_reload_or_restart(names):
|
|||
"""
|
||||
if isinstance(names, str):
|
||||
names = [names]
|
||||
|
||||
services = _get_services()
|
||||
|
||||
for name in names:
|
||||
|
||||
logger.debug(f"Reloading service {name}")
|
||||
|
||||
test_conf_cmd = services.get(name, {}).get("test_conf")
|
||||
if test_conf and test_conf_cmd:
|
||||
|
||||
p = subprocess.Popen(
|
||||
test_conf_cmd,
|
||||
shell=True,
|
||||
executable="/bin/bash",
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
||||
out, _ = p.communicate()
|
||||
if p.returncode != 0:
|
||||
errors = out.decode().strip().split("\n")
|
||||
logger.error(
|
||||
m18n.n(
|
||||
"service_not_reloading_because_conf_broken",
|
||||
name=name,
|
||||
errors=errors,
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
if _run_service_command("reload-or-restart", name):
|
||||
logger.success(m18n.n("service_reloaded_or_restarted", service=name))
|
||||
else:
|
||||
|
|
|
@ -18,6 +18,9 @@ SETTINGS_PATH_OTHER_LOCATION = "/etc/yunohost/settings-%s.json"
|
|||
|
||||
|
||||
def is_boolean(value):
|
||||
TRUE = ["true", "on", "yes", "y", "1"]
|
||||
FALSE = ["false", "off", "no", "n", "0"]
|
||||
|
||||
"""
|
||||
Ensure a string value is intended as a boolean
|
||||
|
||||
|
@ -30,9 +33,11 @@ def is_boolean(value):
|
|||
"""
|
||||
if isinstance(value, bool):
|
||||
return True, value
|
||||
if value in [0, 1]:
|
||||
return True, bool(value)
|
||||
elif isinstance(value, str):
|
||||
if str(value).lower() in ["true", "on", "yes", "false", "off", "no"]:
|
||||
return True, str(value).lower() in ["true", "on", "yes"]
|
||||
if str(value).lower() in TRUE + FALSE:
|
||||
return True, str(value).lower() in TRUE
|
||||
else:
|
||||
return False, None
|
||||
else:
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
import os
|
||||
import pytest
|
||||
import sys
|
||||
|
||||
import moulinette
|
||||
from moulinette import m18n, Moulinette
|
||||
from yunohost.utils.error import YunohostError
|
||||
from contextlib import contextmanager
|
||||
|
||||
sys.path.append("..")
|
||||
|
||||
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def clone_test_app(request):
|
||||
|
@ -77,6 +74,8 @@ moulinette.core.Moulinette18n.n = new_m18nn
|
|||
|
||||
def pytest_cmdline_main(config):
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, "/usr/lib/moulinette/")
|
||||
import yunohost
|
||||
|
||||
|
@ -84,9 +83,12 @@ def pytest_cmdline_main(config):
|
|||
|
||||
class DummyInterface:
|
||||
|
||||
type = "test"
|
||||
type = "cli"
|
||||
|
||||
def prompt(*args, **kwargs):
|
||||
def prompt(self, *args, **kwargs):
|
||||
raise NotImplementedError
|
||||
|
||||
def display(self, message, *args, **kwargs):
|
||||
print(message)
|
||||
|
||||
Moulinette._interface = DummyInterface()
|
||||
|
|
202
src/yunohost/tests/test_app_config.py
Normal file
202
src/yunohost/tests/test_app_config.py
Normal file
|
@ -0,0 +1,202 @@
|
|||
import glob
|
||||
import os
|
||||
import shutil
|
||||
import pytest
|
||||
|
||||
from .conftest import get_test_apps_dir
|
||||
|
||||
from moulinette.utils.filesystem import read_file
|
||||
|
||||
from yunohost.domain import _get_maindomain
|
||||
from yunohost.app import (
|
||||
app_setting,
|
||||
app_install,
|
||||
app_remove,
|
||||
_is_installed,
|
||||
app_config_get,
|
||||
app_config_set,
|
||||
app_ssowatconf,
|
||||
)
|
||||
|
||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||
|
||||
|
||||
def setup_function(function):
|
||||
|
||||
clean()
|
||||
|
||||
|
||||
def teardown_function(function):
|
||||
|
||||
clean()
|
||||
|
||||
|
||||
def clean():
|
||||
|
||||
# Make sure we have a ssowat
|
||||
os.system("mkdir -p /etc/ssowat/")
|
||||
app_ssowatconf()
|
||||
|
||||
test_apps = ["config_app", "legacy_app"]
|
||||
|
||||
for test_app in test_apps:
|
||||
|
||||
if _is_installed(test_app):
|
||||
app_remove(test_app)
|
||||
|
||||
for filepath in glob.glob("/etc/nginx/conf.d/*.d/*%s*" % test_app):
|
||||
os.remove(filepath)
|
||||
for folderpath in glob.glob("/etc/yunohost/apps/*%s*" % test_app):
|
||||
shutil.rmtree(folderpath, ignore_errors=True)
|
||||
for folderpath in glob.glob("/var/www/*%s*" % test_app):
|
||||
shutil.rmtree(folderpath, ignore_errors=True)
|
||||
|
||||
os.system("bash -c \"mysql -B 2>/dev/null <<< 'DROP DATABASE %s' \"" % test_app)
|
||||
os.system(
|
||||
"bash -c \"mysql -B 2>/dev/null <<< 'DROP USER %s@localhost'\"" % test_app
|
||||
)
|
||||
|
||||
# Reset failed quota for service to avoid running into start-limit rate ?
|
||||
os.system("systemctl reset-failed nginx")
|
||||
os.system("systemctl start nginx")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def legacy_app(request):
|
||||
|
||||
main_domain = _get_maindomain()
|
||||
|
||||
app_install(
|
||||
os.path.join(get_test_apps_dir(), "legacy_app_ynh"),
|
||||
args="domain=%s&path=%s&is_public=%s" % (main_domain, "/", 1),
|
||||
force=True,
|
||||
)
|
||||
|
||||
def remove_app():
|
||||
app_remove("legacy_app")
|
||||
|
||||
request.addfinalizer(remove_app)
|
||||
|
||||
return "legacy_app"
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def config_app(request):
|
||||
|
||||
app_install(
|
||||
os.path.join(get_test_apps_dir(), "config_app_ynh"),
|
||||
args="",
|
||||
force=True,
|
||||
)
|
||||
|
||||
def remove_app():
|
||||
app_remove("config_app")
|
||||
|
||||
request.addfinalizer(remove_app)
|
||||
|
||||
return "config_app"
|
||||
|
||||
|
||||
def test_app_config_get(config_app):
|
||||
|
||||
assert isinstance(app_config_get(config_app), dict)
|
||||
assert isinstance(app_config_get(config_app, full=True), dict)
|
||||
assert isinstance(app_config_get(config_app, export=True), dict)
|
||||
assert isinstance(app_config_get(config_app, "main"), dict)
|
||||
assert isinstance(app_config_get(config_app, "main.components"), dict)
|
||||
assert app_config_get(config_app, "main.components.boolean") == "0"
|
||||
|
||||
|
||||
def test_app_config_nopanel(legacy_app):
|
||||
|
||||
with pytest.raises(YunohostValidationError):
|
||||
app_config_get(legacy_app)
|
||||
|
||||
|
||||
def test_app_config_get_nonexistentstuff(config_app):
|
||||
|
||||
with pytest.raises(YunohostValidationError):
|
||||
app_config_get("nonexistent")
|
||||
|
||||
with pytest.raises(YunohostValidationError):
|
||||
app_config_get(config_app, "nonexistent")
|
||||
|
||||
with pytest.raises(YunohostValidationError):
|
||||
app_config_get(config_app, "main.nonexistent")
|
||||
|
||||
with pytest.raises(YunohostValidationError):
|
||||
app_config_get(config_app, "main.components.nonexistent")
|
||||
|
||||
app_setting(config_app, "boolean", delete=True)
|
||||
with pytest.raises(YunohostError):
|
||||
app_config_get(config_app, "main.components.boolean")
|
||||
|
||||
|
||||
def test_app_config_regular_setting(config_app):
|
||||
|
||||
assert app_config_get(config_app, "main.components.boolean") == "0"
|
||||
|
||||
app_config_set(config_app, "main.components.boolean", "no")
|
||||
|
||||
assert app_config_get(config_app, "main.components.boolean") == "0"
|
||||
assert app_setting(config_app, "boolean") == "0"
|
||||
|
||||
app_config_set(config_app, "main.components.boolean", "yes")
|
||||
|
||||
assert app_config_get(config_app, "main.components.boolean") == "1"
|
||||
assert app_setting(config_app, "boolean") == "1"
|
||||
|
||||
with pytest.raises(YunohostValidationError):
|
||||
app_config_set(config_app, "main.components.boolean", "pwet")
|
||||
|
||||
|
||||
def test_app_config_bind_on_file(config_app):
|
||||
|
||||
# c.f. conf/test.php in the config app
|
||||
assert '$arg5= "Arg5 value";' in read_file("/var/www/config_app/test.php")
|
||||
assert app_config_get(config_app, "bind.variable.arg5") == "Arg5 value"
|
||||
assert app_setting(config_app, "arg5") is None
|
||||
|
||||
app_config_set(config_app, "bind.variable.arg5", "Foo Bar")
|
||||
|
||||
assert '$arg5= "Foo Bar";' in read_file("/var/www/config_app/test.php")
|
||||
assert app_config_get(config_app, "bind.variable.arg5") == "Foo Bar"
|
||||
assert app_setting(config_app, "arg5") == "Foo Bar"
|
||||
|
||||
|
||||
def test_app_config_custom_get(config_app):
|
||||
|
||||
assert app_setting(config_app, "arg9") is None
|
||||
assert (
|
||||
"Files in /var/www"
|
||||
in app_config_get(config_app, "bind.function.arg9")["ask"]["en"]
|
||||
)
|
||||
assert app_setting(config_app, "arg9") is None
|
||||
|
||||
|
||||
def test_app_config_custom_validator(config_app):
|
||||
|
||||
# c.f. the config script
|
||||
# arg8 is a password that must be at least 8 chars
|
||||
assert not os.path.exists("/var/www/config_app/password")
|
||||
assert app_setting(config_app, "arg8") is None
|
||||
|
||||
with pytest.raises(YunohostValidationError):
|
||||
app_config_set(config_app, "bind.function.arg8", "pZo6i7u91h")
|
||||
|
||||
assert not os.path.exists("/var/www/config_app/password")
|
||||
assert app_setting(config_app, "arg8") is None
|
||||
|
||||
|
||||
def test_app_config_custom_set(config_app):
|
||||
|
||||
assert not os.path.exists("/var/www/config_app/password")
|
||||
assert app_setting(config_app, "arg8") is None
|
||||
|
||||
app_config_set(config_app, "bind.function.arg8", "OneSuperStrongPassword")
|
||||
|
||||
assert os.path.exists("/var/www/config_app/password")
|
||||
content = read_file("/var/www/config_app/password")
|
||||
assert "OneSuperStrongPassword" not in content
|
||||
assert content.startswith("$6$saltsalt$")
|
||||
assert app_setting(config_app, "arg8") is None
|
|
@ -2,6 +2,7 @@ import pytest
|
|||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
from mock import patch
|
||||
|
||||
from .conftest import message, raiseYunohostError, get_test_apps_dir
|
||||
|
||||
|
@ -77,7 +78,8 @@ def setup_function(function):
|
|||
if "with_permission_app_installed" in markers:
|
||||
assert not app_is_installed("permissions_app")
|
||||
user_create("alice", "Alice", "White", maindomain, "test123Ynh")
|
||||
install_app("permissions_app_ynh", "/urlpermissionapp" "&admin=alice")
|
||||
with patch.object(os, "isatty", return_value=False):
|
||||
install_app("permissions_app_ynh", "/urlpermissionapp" "&admin=alice")
|
||||
assert app_is_installed("permissions_app")
|
||||
|
||||
if "with_custom_domain" in markers:
|
||||
|
@ -469,7 +471,7 @@ def test_restore_app_script_failure_handling(monkeypatch, mocker):
|
|||
monkeypatch.undo()
|
||||
return (1, None)
|
||||
|
||||
monkeypatch.setattr("yunohost.backup.hook_exec", custom_hook_exec)
|
||||
monkeypatch.setattr("yunohost.hook.hook_exec", custom_hook_exec)
|
||||
|
||||
assert not _is_installed("wordpress")
|
||||
|
||||
|
|
80
src/yunohost/tests/test_dns.py
Normal file
80
src/yunohost/tests/test_dns.py
Normal file
|
@ -0,0 +1,80 @@
|
|||
import pytest
|
||||
|
||||
from moulinette.utils.filesystem import read_toml
|
||||
|
||||
from yunohost.domain import domain_add, domain_remove
|
||||
from yunohost.dns import (
|
||||
DOMAIN_REGISTRAR_LIST_PATH,
|
||||
_get_dns_zone_for_domain,
|
||||
_get_registrar_config_section,
|
||||
_build_dns_conf,
|
||||
)
|
||||
|
||||
|
||||
def setup_function(function):
|
||||
|
||||
clean()
|
||||
|
||||
|
||||
def teardown_function(function):
|
||||
|
||||
clean()
|
||||
|
||||
|
||||
def clean():
|
||||
pass
|
||||
|
||||
|
||||
# DNS utils testing
|
||||
def test_get_dns_zone_from_domain_existing():
|
||||
assert _get_dns_zone_for_domain("yunohost.org") == "yunohost.org"
|
||||
assert _get_dns_zone_for_domain("donate.yunohost.org") == "yunohost.org"
|
||||
assert _get_dns_zone_for_domain("fr.wikipedia.org") == "wikipedia.org"
|
||||
assert _get_dns_zone_for_domain("www.fr.wikipedia.org") == "wikipedia.org"
|
||||
assert (
|
||||
_get_dns_zone_for_domain("non-existing-domain.yunohost.org") == "yunohost.org"
|
||||
)
|
||||
assert _get_dns_zone_for_domain("yolo.nohost.me") == "nohost.me"
|
||||
assert _get_dns_zone_for_domain("foo.yolo.nohost.me") == "nohost.me"
|
||||
assert _get_dns_zone_for_domain("yolo.tld") == "yolo.tld"
|
||||
assert _get_dns_zone_for_domain("foo.yolo.tld") == "yolo.tld"
|
||||
|
||||
|
||||
# Domain registrar testing
|
||||
def test_registrar_list_integrity():
|
||||
assert read_toml(DOMAIN_REGISTRAR_LIST_PATH)
|
||||
|
||||
|
||||
def test_magic_guess_registrar_weird_domain():
|
||||
assert _get_registrar_config_section("yolo.tld")["registrar"]["value"] is None
|
||||
|
||||
|
||||
def test_magic_guess_registrar_ovh():
|
||||
assert (
|
||||
_get_registrar_config_section("yolo.yunohost.org")["registrar"]["value"]
|
||||
== "ovh"
|
||||
)
|
||||
|
||||
|
||||
def test_magic_guess_registrar_yunodyndns():
|
||||
assert (
|
||||
_get_registrar_config_section("yolo.nohost.me")["registrar"]["value"]
|
||||
== "yunohost"
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def example_domain():
|
||||
domain_add("example.tld")
|
||||
yield "example.tld"
|
||||
domain_remove("example.tld")
|
||||
|
||||
|
||||
def test_domain_dns_suggest(example_domain):
|
||||
|
||||
assert _build_dns_conf(example_domain)
|
||||
|
||||
|
||||
# def domain_dns_push(domain, dry_run):
|
||||
# import yunohost.dns
|
||||
# return yunohost.dns.domain_registrar_push(domain, dry_run)
|
118
src/yunohost/tests/test_domains.py
Normal file
118
src/yunohost/tests/test_domains.py
Normal file
|
@ -0,0 +1,118 @@
|
|||
import pytest
|
||||
import os
|
||||
|
||||
from moulinette.core import MoulinetteError
|
||||
|
||||
from yunohost.utils.error import YunohostValidationError
|
||||
from yunohost.domain import (
|
||||
DOMAIN_SETTINGS_DIR,
|
||||
_get_maindomain,
|
||||
domain_add,
|
||||
domain_remove,
|
||||
domain_list,
|
||||
domain_main_domain,
|
||||
domain_config_get,
|
||||
domain_config_set,
|
||||
)
|
||||
|
||||
TEST_DOMAINS = ["example.tld", "sub.example.tld", "other-example.com"]
|
||||
|
||||
|
||||
def setup_function(function):
|
||||
|
||||
# Save domain list in variable to avoid multiple calls to domain_list()
|
||||
domains = domain_list()["domains"]
|
||||
|
||||
# First domain is main domain
|
||||
if not TEST_DOMAINS[0] in domains:
|
||||
domain_add(TEST_DOMAINS[0])
|
||||
else:
|
||||
# Reset settings if any
|
||||
os.system(f"rm -rf {DOMAIN_SETTINGS_DIR}/{TEST_DOMAINS[0]}.yml")
|
||||
|
||||
if not _get_maindomain() == TEST_DOMAINS[0]:
|
||||
domain_main_domain(TEST_DOMAINS[0])
|
||||
|
||||
# Clear other domains
|
||||
for domain in domains:
|
||||
if domain not in TEST_DOMAINS or domain == TEST_DOMAINS[2]:
|
||||
# Clean domains not used for testing
|
||||
domain_remove(domain)
|
||||
elif domain in TEST_DOMAINS:
|
||||
# Reset settings if any
|
||||
os.system(f"rm -rf {DOMAIN_SETTINGS_DIR}/{domain}.yml")
|
||||
|
||||
# Create classical second domain of not exist
|
||||
if TEST_DOMAINS[1] not in domains:
|
||||
domain_add(TEST_DOMAINS[1])
|
||||
|
||||
# Third domain is not created
|
||||
|
||||
clean()
|
||||
|
||||
|
||||
def teardown_function(function):
|
||||
|
||||
clean()
|
||||
|
||||
|
||||
def clean():
|
||||
pass
|
||||
|
||||
|
||||
# Domains management testing
|
||||
def test_domain_add():
|
||||
assert TEST_DOMAINS[2] not in domain_list()["domains"]
|
||||
domain_add(TEST_DOMAINS[2])
|
||||
assert TEST_DOMAINS[2] in domain_list()["domains"]
|
||||
|
||||
|
||||
def test_domain_add_existing_domain():
|
||||
with pytest.raises(MoulinetteError):
|
||||
assert TEST_DOMAINS[1] in domain_list()["domains"]
|
||||
domain_add(TEST_DOMAINS[1])
|
||||
|
||||
|
||||
def test_domain_remove():
|
||||
assert TEST_DOMAINS[1] in domain_list()["domains"]
|
||||
domain_remove(TEST_DOMAINS[1])
|
||||
assert TEST_DOMAINS[1] not in domain_list()["domains"]
|
||||
|
||||
|
||||
def test_main_domain():
|
||||
current_main_domain = _get_maindomain()
|
||||
assert domain_main_domain()["current_main_domain"] == current_main_domain
|
||||
|
||||
|
||||
def test_main_domain_change_unknown():
|
||||
with pytest.raises(YunohostValidationError):
|
||||
domain_main_domain(TEST_DOMAINS[2])
|
||||
|
||||
|
||||
def test_change_main_domain():
|
||||
assert _get_maindomain() != TEST_DOMAINS[1]
|
||||
domain_main_domain(TEST_DOMAINS[1])
|
||||
assert _get_maindomain() == TEST_DOMAINS[1]
|
||||
|
||||
|
||||
# Domain settings testing
|
||||
def test_domain_config_get_default():
|
||||
assert domain_config_get(TEST_DOMAINS[0], "feature.xmpp.xmpp") == 1
|
||||
assert domain_config_get(TEST_DOMAINS[1], "feature.xmpp.xmpp") == 0
|
||||
|
||||
|
||||
def test_domain_config_get_export():
|
||||
|
||||
assert domain_config_get(TEST_DOMAINS[0], export=True)["xmpp"] == 1
|
||||
assert domain_config_get(TEST_DOMAINS[1], export=True)["xmpp"] == 0
|
||||
|
||||
|
||||
def test_domain_config_set():
|
||||
assert domain_config_get(TEST_DOMAINS[1], "feature.xmpp.xmpp") == 0
|
||||
domain_config_set(TEST_DOMAINS[1], "feature.xmpp.xmpp", "yes")
|
||||
assert domain_config_get(TEST_DOMAINS[1], "feature.xmpp.xmpp") == 1
|
||||
|
||||
|
||||
def test_domain_configs_unknown():
|
||||
with pytest.raises(YunohostValidationError):
|
||||
domain_config_get(TEST_DOMAINS[2], "feature.xmpp.xmpp.xmpp")
|
File diff suppressed because it is too large
Load diff
|
@ -9,6 +9,7 @@ from yunohost.service import (
|
|||
service_add,
|
||||
service_remove,
|
||||
service_log,
|
||||
service_reload_or_restart,
|
||||
)
|
||||
|
||||
|
||||
|
@ -38,6 +39,10 @@ def clean():
|
|||
|
||||
_save_services(services)
|
||||
|
||||
if os.path.exists("/etc/nginx/conf.d/broken.conf"):
|
||||
os.remove("/etc/nginx/conf.d/broken.conf")
|
||||
os.system("systemctl reload-or-restart nginx")
|
||||
|
||||
|
||||
def test_service_status_all():
|
||||
|
||||
|
@ -118,3 +123,20 @@ def test_service_update_to_remove_properties():
|
|||
assert _get_services()["dummyservice"].get("test_status") == "false"
|
||||
service_add("dummyservice", description="dummy", test_status="")
|
||||
assert not _get_services()["dummyservice"].get("test_status")
|
||||
|
||||
|
||||
def test_service_conf_broken():
|
||||
|
||||
os.system("echo pwet > /etc/nginx/conf.d/broken.conf")
|
||||
|
||||
status = service_status("nginx")
|
||||
assert status["status"] == "running"
|
||||
assert status["configuration"] == "broken"
|
||||
assert "broken.conf" in status["configuration-details"][0]
|
||||
|
||||
# Service reload-or-restart should check that the conf ain't valid
|
||||
# before reload-or-restart, hence the service should still be running
|
||||
service_reload_or_restart("nginx")
|
||||
assert status["status"] == "running"
|
||||
|
||||
os.remove("/etc/nginx/conf.d/broken.conf")
|
||||
|
|
|
@ -29,6 +29,7 @@ import subprocess
|
|||
import time
|
||||
from importlib import import_module
|
||||
from packaging import version
|
||||
from typing import List
|
||||
|
||||
from moulinette import Moulinette, m18n
|
||||
from moulinette.utils.log import getActionLogger
|
||||
|
@ -1086,7 +1087,9 @@ class Migration(object):
|
|||
# Those are to be implemented by daughter classes
|
||||
|
||||
mode = "auto"
|
||||
dependencies = [] # List of migration ids required before running this migration
|
||||
dependencies: List[
|
||||
str
|
||||
] = [] # List of migration ids required before running this migration
|
||||
|
||||
@property
|
||||
def disclaimer(self):
|
||||
|
|
|
@ -141,7 +141,7 @@ def user_create(
|
|||
from_import=False,
|
||||
):
|
||||
|
||||
from yunohost.domain import domain_list, _get_maindomain
|
||||
from yunohost.domain import domain_list, _get_maindomain, _assert_domain_exists
|
||||
from yunohost.hook import hook_callback
|
||||
from yunohost.utils.password import assert_password_is_strong_enough
|
||||
from yunohost.utils.ldap import _get_ldap_interface
|
||||
|
@ -169,8 +169,7 @@ def user_create(
|
|||
domain = maindomain
|
||||
|
||||
# Check that the domain exists
|
||||
if domain not in domain_list()["domains"]:
|
||||
raise YunohostValidationError("domain_name_unknown", domain=domain)
|
||||
_assert_domain_exists(domain)
|
||||
|
||||
mail = username + "@" + domain
|
||||
ldap = _get_ldap_interface()
|
||||
|
|
1081
src/yunohost/utils/config.py
Normal file
1081
src/yunohost/utils/config.py
Normal file
File diff suppressed because it is too large
Load diff
95
src/yunohost/utils/dns.py
Normal file
95
src/yunohost/utils/dns.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
""" License
|
||||
|
||||
Copyright (C) 2018 YUNOHOST.ORG
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, see http://www.gnu.org/licenses
|
||||
|
||||
"""
|
||||
import dns.resolver
|
||||
from typing import List
|
||||
|
||||
from moulinette.utils.filesystem import read_file
|
||||
|
||||
YNH_DYNDNS_DOMAINS = ["nohost.me", "noho.st", "ynh.fr"]
|
||||
|
||||
# Lazy dev caching to avoid re-reading the file multiple time when calling
|
||||
# dig() often during same yunohost operation
|
||||
external_resolvers_: List[str] = []
|
||||
|
||||
|
||||
def external_resolvers():
|
||||
|
||||
global external_resolvers_
|
||||
|
||||
if not external_resolvers_:
|
||||
resolv_dnsmasq_conf = read_file("/etc/resolv.dnsmasq.conf").split("\n")
|
||||
external_resolvers_ = [
|
||||
r.split(" ")[1] for r in resolv_dnsmasq_conf if r.startswith("nameserver")
|
||||
]
|
||||
# We keep only ipv4 resolvers, otherwise on IPv4-only instances, IPv6
|
||||
# will be tried anyway resulting in super-slow dig requests that'll wait
|
||||
# until timeout...
|
||||
external_resolvers_ = [r for r in external_resolvers_ if ":" not in r]
|
||||
|
||||
return external_resolvers_
|
||||
|
||||
|
||||
def dig(
|
||||
qname, rdtype="A", timeout=5, resolvers="local", edns_size=1500, full_answers=False
|
||||
):
|
||||
"""
|
||||
Do a quick DNS request and avoid the "search" trap inside /etc/resolv.conf
|
||||
"""
|
||||
|
||||
# It's very important to do the request with a qname ended by .
|
||||
# If we don't and the domain fail, dns resolver try a second request
|
||||
# by concatenate the qname with the end of the "hostname"
|
||||
if not qname.endswith("."):
|
||||
qname += "."
|
||||
|
||||
if resolvers == "local":
|
||||
resolvers = ["127.0.0.1"]
|
||||
elif resolvers == "force_external":
|
||||
resolvers = external_resolvers()
|
||||
else:
|
||||
assert isinstance(resolvers, list)
|
||||
|
||||
resolver = dns.resolver.Resolver(configure=False)
|
||||
resolver.use_edns(0, 0, edns_size)
|
||||
resolver.nameservers = resolvers
|
||||
# resolver.timeout is used to trigger the next DNS query on resolvers list.
|
||||
# In python-dns 1.16, this value is set to 2.0. However, this means that if
|
||||
# the 3 first dns resolvers in list are down, we wait 6 seconds before to
|
||||
# run the DNS query to a DNS resolvers up...
|
||||
# In diagnosis dnsrecords, with 10 domains this means at least 12min, too long.
|
||||
resolver.timeout = 1.0
|
||||
# resolver.lifetime is the timeout for resolver.query()
|
||||
# By default set it to 5 seconds to allow 4 resolvers to be unreachable.
|
||||
resolver.lifetime = timeout
|
||||
try:
|
||||
answers = resolver.query(qname, rdtype)
|
||||
except (
|
||||
dns.resolver.NXDOMAIN,
|
||||
dns.resolver.NoNameservers,
|
||||
dns.resolver.NoAnswer,
|
||||
dns.exception.Timeout,
|
||||
) as e:
|
||||
return ("nok", (e.__class__.__name__, e))
|
||||
|
||||
if not full_answers:
|
||||
answers = [answer.to_text() for answer in answers]
|
||||
|
||||
return ("ok", answers)
|
|
@ -59,4 +59,4 @@ class YunohostValidationError(YunohostError):
|
|||
|
||||
def content(self):
|
||||
|
||||
return {"error": self.strerror, "error_key": self.key}
|
||||
return {"error": self.strerror, "error_key": self.key, **self.kwargs}
|
||||
|
|
45
src/yunohost/utils/i18n.py
Normal file
45
src/yunohost/utils/i18n.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
""" License
|
||||
|
||||
Copyright (C) 2018 YUNOHOST.ORG
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, see http://www.gnu.org/licenses
|
||||
|
||||
"""
|
||||
from moulinette import m18n
|
||||
|
||||
|
||||
def _value_for_locale(values):
|
||||
"""
|
||||
Return proper value for current locale
|
||||
|
||||
Keyword arguments:
|
||||
values -- A dict of values associated to their locale
|
||||
|
||||
Returns:
|
||||
An utf-8 encoded string
|
||||
|
||||
"""
|
||||
if not isinstance(values, dict):
|
||||
return values
|
||||
|
||||
for lang in [m18n.locale, m18n.default_locale]:
|
||||
try:
|
||||
return values[lang]
|
||||
except KeyError:
|
||||
continue
|
||||
|
||||
# Fallback to first value
|
||||
return list(values.values())[0]
|
|
@ -101,7 +101,8 @@ class LDAPInterface:
|
|||
except ldap.SERVER_DOWN:
|
||||
raise YunohostError(
|
||||
"Service slapd is not running but is required to perform this action ... "
|
||||
"You can try to investigate what's happening with 'systemctl status slapd'"
|
||||
"You can try to investigate what's happening with 'systemctl status slapd'",
|
||||
raw_msg=True,
|
||||
)
|
||||
|
||||
# Check that we are indeed logged in with the right identity
|
||||
|
@ -289,7 +290,7 @@ class LDAPInterface:
|
|||
attr_found[0],
|
||||
attr_found[1],
|
||||
)
|
||||
raise MoulinetteError(
|
||||
raise YunohostError(
|
||||
"ldap_attribute_already_exists",
|
||||
attribute=attr_found[0],
|
||||
value=attr_found[1],
|
||||
|
|
|
@ -22,7 +22,6 @@ import os
|
|||
import re
|
||||
import logging
|
||||
import time
|
||||
import dns.resolver
|
||||
|
||||
from moulinette.utils.filesystem import read_file, write_to_file
|
||||
from moulinette.utils.network import download_text
|
||||
|
@ -124,76 +123,6 @@ def get_gateway():
|
|||
return addr.popitem()[1] if len(addr) == 1 else None
|
||||
|
||||
|
||||
# Lazy dev caching to avoid re-reading the file multiple time when calling
|
||||
# dig() often during same yunohost operation
|
||||
external_resolvers_ = []
|
||||
|
||||
|
||||
def external_resolvers():
|
||||
|
||||
global external_resolvers_
|
||||
|
||||
if not external_resolvers_:
|
||||
resolv_dnsmasq_conf = read_file("/etc/resolv.dnsmasq.conf").split("\n")
|
||||
external_resolvers_ = [
|
||||
r.split(" ")[1] for r in resolv_dnsmasq_conf if r.startswith("nameserver")
|
||||
]
|
||||
# We keep only ipv4 resolvers, otherwise on IPv4-only instances, IPv6
|
||||
# will be tried anyway resulting in super-slow dig requests that'll wait
|
||||
# until timeout...
|
||||
external_resolvers_ = [r for r in external_resolvers_ if ":" not in r]
|
||||
|
||||
return external_resolvers_
|
||||
|
||||
|
||||
def dig(
|
||||
qname, rdtype="A", timeout=5, resolvers="local", edns_size=1500, full_answers=False
|
||||
):
|
||||
"""
|
||||
Do a quick DNS request and avoid the "search" trap inside /etc/resolv.conf
|
||||
"""
|
||||
|
||||
# It's very important to do the request with a qname ended by .
|
||||
# If we don't and the domain fail, dns resolver try a second request
|
||||
# by concatenate the qname with the end of the "hostname"
|
||||
if not qname.endswith("."):
|
||||
qname += "."
|
||||
|
||||
if resolvers == "local":
|
||||
resolvers = ["127.0.0.1"]
|
||||
elif resolvers == "force_external":
|
||||
resolvers = external_resolvers()
|
||||
else:
|
||||
assert isinstance(resolvers, list)
|
||||
|
||||
resolver = dns.resolver.Resolver(configure=False)
|
||||
resolver.use_edns(0, 0, edns_size)
|
||||
resolver.nameservers = resolvers
|
||||
# resolver.timeout is used to trigger the next DNS query on resolvers list.
|
||||
# In python-dns 1.16, this value is set to 2.0. However, this means that if
|
||||
# the 3 first dns resolvers in list are down, we wait 6 seconds before to
|
||||
# run the DNS query to a DNS resolvers up...
|
||||
# In diagnosis dnsrecords, with 10 domains this means at least 12min, too long.
|
||||
resolver.timeout = 1.0
|
||||
# resolver.lifetime is the timeout for resolver.query()
|
||||
# By default set it to 5 seconds to allow 4 resolvers to be unreachable.
|
||||
resolver.lifetime = timeout
|
||||
try:
|
||||
answers = resolver.query(qname, rdtype)
|
||||
except (
|
||||
dns.resolver.NXDOMAIN,
|
||||
dns.resolver.NoNameservers,
|
||||
dns.resolver.NoAnswer,
|
||||
dns.exception.Timeout,
|
||||
) as e:
|
||||
return ("nok", (e.__class__.__name__, e))
|
||||
|
||||
if not full_answers:
|
||||
answers = [answer.to_text() for answer in answers]
|
||||
|
||||
return ("ok", answers)
|
||||
|
||||
|
||||
def _extract_inet(string, skip_netmask=False, skip_loopback=True):
|
||||
"""
|
||||
Extract IP addresses (v4 and/or v6) from a string limited to one
|
||||
|
|
|
@ -111,8 +111,13 @@ class PasswordValidator(object):
|
|||
listed = password in SMALL_PWD_LIST or self.is_in_most_used_list(password)
|
||||
strength_level = self.strength_level(password)
|
||||
if listed:
|
||||
# i18n: password_listed
|
||||
return ("error", "password_listed")
|
||||
if strength_level < self.validation_strength:
|
||||
# i18n: password_too_simple_1
|
||||
# i18n: password_too_simple_2
|
||||
# i18n: password_too_simple_3
|
||||
# i18n: password_too_simple_4
|
||||
return ("error", "password_too_simple_%s" % self.validation_strength)
|
||||
|
||||
return ("success", "")
|
||||
|
|
|
@ -3,7 +3,7 @@ import json
|
|||
import glob
|
||||
|
||||
# List all locale files (except en.json being the ref)
|
||||
locale_folder = "locales/"
|
||||
locale_folder = "../locales/"
|
||||
locale_files = glob.glob(locale_folder + "*.json")
|
||||
locale_files = [filename.split("/")[-1] for filename in locale_files]
|
||||
locale_files.remove("en.json")
|
||||
|
|
|
@ -3,11 +3,11 @@ import re
|
|||
|
||||
def reformat(lang, transformations):
|
||||
|
||||
locale = open(f"locales/{lang}.json").read()
|
||||
locale = open(f"../locales/{lang}.json").read()
|
||||
for pattern, replace in transformations.items():
|
||||
locale = re.compile(pattern).sub(replace, locale)
|
||||
|
||||
open(f"locales/{lang}.json", "w").write(locale)
|
||||
open(f"../locales/{lang}.json", "w").write(locale)
|
||||
|
||||
|
||||
######################################################
|
||||
|
|
662
tests/test_helpers.d/ynhtest_config.sh
Normal file
662
tests/test_helpers.d/ynhtest_config.sh
Normal file
|
@ -0,0 +1,662 @@
|
|||
|
||||
#################
|
||||
# _ __ _ _ #
|
||||
# | '_ \| | | | #
|
||||
# | |_) | |_| | #
|
||||
# | .__/ \__, | #
|
||||
# | | __/ | #
|
||||
# |_| |___/ #
|
||||
# #
|
||||
#################
|
||||
|
||||
_read_py() {
|
||||
local file="$1"
|
||||
local key="$2"
|
||||
python3 -c "exec(open('$file').read()); print($key)"
|
||||
}
|
||||
|
||||
ynhtest_config_read_py() {
|
||||
|
||||
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
|
||||
file="$dummy_dir/dummy.py"
|
||||
|
||||
cat << EOF > $dummy_dir/dummy.py
|
||||
# Some comment
|
||||
FOO = None
|
||||
ENABLED = False
|
||||
# TITLE = "Old title"
|
||||
TITLE = "Lorem Ipsum"
|
||||
THEME = "colib'ris"
|
||||
EMAIL = "root@example.com" # This is a comment without quotes
|
||||
PORT = 1234 # This is a comment without quotes
|
||||
URL = 'https://yunohost.org'
|
||||
DICT = {}
|
||||
DICT['ldap_base'] = "ou=users,dc=yunohost,dc=org"
|
||||
DICT['ldap_conf'] = {}
|
||||
DICT['ldap_conf']['user'] = "camille"
|
||||
# YNH_ICI
|
||||
DICT['TITLE'] = "Hello world"
|
||||
EOF
|
||||
|
||||
test "$(_read_py "$file" "FOO")" == "None"
|
||||
test "$(ynh_read_var_in_file "$file" "FOO")" == "None"
|
||||
|
||||
test "$(_read_py "$file" "ENABLED")" == "False"
|
||||
test "$(ynh_read_var_in_file "$file" "ENABLED")" == "False"
|
||||
|
||||
test "$(_read_py "$file" "TITLE")" == "Lorem Ipsum"
|
||||
test "$(ynh_read_var_in_file "$file" "TITLE")" == "Lorem Ipsum"
|
||||
|
||||
test "$(_read_py "$file" "THEME")" == "colib'ris"
|
||||
test "$(ynh_read_var_in_file "$file" "THEME")" == "colib'ris"
|
||||
|
||||
test "$(_read_py "$file" "EMAIL")" == "root@example.com"
|
||||
test "$(ynh_read_var_in_file "$file" "EMAIL")" == "root@example.com"
|
||||
|
||||
test "$(_read_py "$file" "PORT")" == "1234"
|
||||
test "$(ynh_read_var_in_file "$file" "PORT")" == "1234"
|
||||
|
||||
test "$(_read_py "$file" "URL")" == "https://yunohost.org"
|
||||
test "$(ynh_read_var_in_file "$file" "URL")" == "https://yunohost.org"
|
||||
|
||||
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=users,dc=yunohost,dc=org"
|
||||
|
||||
test "$(ynh_read_var_in_file "$file" "user")" == "camille"
|
||||
|
||||
test "$(ynh_read_var_in_file "$file" "TITLE" "YNH_ICI")" == "Hello world"
|
||||
|
||||
! _read_py "$file" "NONEXISTENT"
|
||||
test "$(ynh_read_var_in_file "$file" "NONEXISTENT")" == "YNH_NULL"
|
||||
|
||||
! _read_py "$file" "ENABLE"
|
||||
test "$(ynh_read_var_in_file "$file" "ENABLE")" == "YNH_NULL"
|
||||
}
|
||||
|
||||
ynhtest_config_write_py() {
|
||||
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
|
||||
file="$dummy_dir/dummy.py"
|
||||
|
||||
cat << EOF > $dummy_dir/dummy.py
|
||||
# Some comment
|
||||
FOO = None
|
||||
ENABLED = False
|
||||
# TITLE = "Old title"
|
||||
TITLE = "Lorem Ipsum"
|
||||
THEME = "colib'ris"
|
||||
EMAIL = "root@example.com" # This is a comment without quotes
|
||||
PORT = 1234 # This is a comment without quotes
|
||||
URL = 'https://yunohost.org'
|
||||
DICT = {}
|
||||
DICT['ldap_base'] = "ou=users,dc=yunohost,dc=org"
|
||||
# YNH_ICI
|
||||
DICT['TITLE'] = "Hello world"
|
||||
EOF
|
||||
|
||||
ynh_write_var_in_file "$file" "FOO" "bar"
|
||||
test "$(_read_py "$file" "FOO")" == "bar"
|
||||
test "$(ynh_read_var_in_file "$file" "FOO")" == "bar"
|
||||
|
||||
ynh_write_var_in_file "$file" "ENABLED" "True"
|
||||
test "$(_read_py "$file" "ENABLED")" == "True"
|
||||
test "$(ynh_read_var_in_file "$file" "ENABLED")" == "True"
|
||||
|
||||
ynh_write_var_in_file "$file" "TITLE" "Foo Bar"
|
||||
test "$(_read_py "$file" "TITLE")" == "Foo Bar"
|
||||
test "$(ynh_read_var_in_file "$file" "TITLE")" == "Foo Bar"
|
||||
|
||||
ynh_write_var_in_file "$file" "THEME" "super-awesome-theme"
|
||||
test "$(_read_py "$file" "THEME")" == "super-awesome-theme"
|
||||
test "$(ynh_read_var_in_file "$file" "THEME")" == "super-awesome-theme"
|
||||
|
||||
ynh_write_var_in_file "$file" "EMAIL" "sam@domain.tld"
|
||||
test "$(_read_py "$file" "EMAIL")" == "sam@domain.tld"
|
||||
test "$(ynh_read_var_in_file "$file" "EMAIL")" == "sam@domain.tld"
|
||||
|
||||
ynh_write_var_in_file "$file" "PORT" "5678"
|
||||
test "$(_read_py "$file" "PORT")" == "5678"
|
||||
test "$(ynh_read_var_in_file "$file" "PORT")" == "5678"
|
||||
|
||||
ynh_write_var_in_file "$file" "URL" "https://domain.tld/foobar"
|
||||
test "$(_read_py "$file" "URL")" == "https://domain.tld/foobar"
|
||||
test "$(ynh_read_var_in_file "$file" "URL")" == "https://domain.tld/foobar"
|
||||
|
||||
ynh_write_var_in_file "$file" "ldap_base" "ou=users,dc=yunohost,dc=org"
|
||||
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=users,dc=yunohost,dc=org"
|
||||
|
||||
ynh_write_var_in_file "$file" "TITLE" "YOLO" "YNH_ICI"
|
||||
test "$(ynh_read_var_in_file "$file" "TITLE" "YNH_ICI")" == "YOLO"
|
||||
|
||||
! ynh_write_var_in_file "$file" "NONEXISTENT" "foobar"
|
||||
! _read_py "$file" "NONEXISTENT"
|
||||
test "$(ynh_read_var_in_file "$file" "NONEXISTENT")" == "YNH_NULL"
|
||||
|
||||
! ynh_write_var_in_file "$file" "ENABLE" "foobar"
|
||||
! _read_py "$file" "ENABLE"
|
||||
test "$(ynh_read_var_in_file "$file" "ENABLE")" == "YNH_NULL"
|
||||
|
||||
}
|
||||
|
||||
###############
|
||||
# _ _ #
|
||||
# (_) (_) #
|
||||
# _ _ __ _ #
|
||||
# | | '_ \| | #
|
||||
# | | | | | | #
|
||||
# |_|_| |_|_| #
|
||||
# #
|
||||
###############
|
||||
|
||||
_read_ini() {
|
||||
local file="$1"
|
||||
local key="$2"
|
||||
python3 -c "import configparser; c = configparser.ConfigParser(); c.read('$file'); print(c['main']['$key'])"
|
||||
}
|
||||
|
||||
ynhtest_config_read_ini() {
|
||||
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
|
||||
file="$dummy_dir/dummy.ini"
|
||||
|
||||
cat << EOF > $file
|
||||
# Some comment
|
||||
; Another comment
|
||||
[main]
|
||||
foo = null
|
||||
enabled = False
|
||||
# title = Old title
|
||||
title = Lorem Ipsum
|
||||
theme = colib'ris
|
||||
email = root@example.com ; This is a comment without quotes
|
||||
port = 1234 ; This is a comment without quotes
|
||||
url = https://yunohost.org
|
||||
[dict]
|
||||
ldap_base = ou=users,dc=yunohost,dc=org
|
||||
EOF
|
||||
|
||||
test "$(_read_ini "$file" "foo")" == "null"
|
||||
test "$(ynh_read_var_in_file "$file" "foo")" == "null"
|
||||
|
||||
test "$(_read_ini "$file" "enabled")" == "False"
|
||||
test "$(ynh_read_var_in_file "$file" "enabled")" == "False"
|
||||
|
||||
test "$(_read_ini "$file" "title")" == "Lorem Ipsum"
|
||||
test "$(ynh_read_var_in_file "$file" "title")" == "Lorem Ipsum"
|
||||
|
||||
test "$(_read_ini "$file" "theme")" == "colib'ris"
|
||||
test "$(ynh_read_var_in_file "$file" "theme")" == "colib'ris"
|
||||
|
||||
#test "$(_read_ini "$file" "email")" == "root@example.com"
|
||||
test "$(ynh_read_var_in_file "$file" "email")" == "root@example.com"
|
||||
|
||||
#test "$(_read_ini "$file" "port")" == "1234"
|
||||
test "$(ynh_read_var_in_file "$file" "port")" == "1234"
|
||||
|
||||
test "$(_read_ini "$file" "url")" == "https://yunohost.org"
|
||||
test "$(ynh_read_var_in_file "$file" "url")" == "https://yunohost.org"
|
||||
|
||||
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=users,dc=yunohost,dc=org"
|
||||
|
||||
! _read_ini "$file" "nonexistent"
|
||||
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
|
||||
|
||||
! _read_ini "$file" "enable"
|
||||
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
|
||||
|
||||
}
|
||||
|
||||
ynhtest_config_write_ini() {
|
||||
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
|
||||
file="$dummy_dir/dummy.ini"
|
||||
|
||||
cat << EOF > $file
|
||||
# Some comment
|
||||
; Another comment
|
||||
[main]
|
||||
foo = null
|
||||
enabled = False
|
||||
# title = Old title
|
||||
title = Lorem Ipsum
|
||||
theme = colib'ris
|
||||
email = root@example.com # This is a comment without quotes
|
||||
port = 1234 # This is a comment without quotes
|
||||
url = https://yunohost.org
|
||||
[dict]
|
||||
ldap_base = ou=users,dc=yunohost,dc=org
|
||||
EOF
|
||||
|
||||
ynh_write_var_in_file "$file" "foo" "bar"
|
||||
test "$(_read_ini "$file" "foo")" == "bar"
|
||||
test "$(ynh_read_var_in_file "$file" "foo")" == "bar"
|
||||
|
||||
ynh_write_var_in_file "$file" "enabled" "True"
|
||||
test "$(_read_ini "$file" "enabled")" == "True"
|
||||
test "$(ynh_read_var_in_file "$file" "enabled")" == "True"
|
||||
|
||||
ynh_write_var_in_file "$file" "title" "Foo Bar"
|
||||
test "$(_read_ini "$file" "title")" == "Foo Bar"
|
||||
test "$(ynh_read_var_in_file "$file" "title")" == "Foo Bar"
|
||||
|
||||
ynh_write_var_in_file "$file" "theme" "super-awesome-theme"
|
||||
test "$(_read_ini "$file" "theme")" == "super-awesome-theme"
|
||||
test "$(ynh_read_var_in_file "$file" "theme")" == "super-awesome-theme"
|
||||
|
||||
ynh_write_var_in_file "$file" "email" "sam@domain.tld"
|
||||
test "$(_read_ini "$file" "email")" == "sam@domain.tld # This is a comment without quotes"
|
||||
test "$(ynh_read_var_in_file "$file" "email")" == "sam@domain.tld"
|
||||
|
||||
ynh_write_var_in_file "$file" "port" "5678"
|
||||
test "$(_read_ini "$file" "port")" == "5678 # This is a comment without quotes"
|
||||
test "$(ynh_read_var_in_file "$file" "port")" == "5678"
|
||||
|
||||
ynh_write_var_in_file "$file" "url" "https://domain.tld/foobar"
|
||||
test "$(_read_ini "$file" "url")" == "https://domain.tld/foobar"
|
||||
test "$(ynh_read_var_in_file "$file" "url")" == "https://domain.tld/foobar"
|
||||
|
||||
ynh_write_var_in_file "$file" "ldap_base" "ou=users,dc=yunohost,dc=org"
|
||||
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=users,dc=yunohost,dc=org"
|
||||
|
||||
! ynh_write_var_in_file "$file" "nonexistent" "foobar"
|
||||
! _read_ini "$file" "nonexistent"
|
||||
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
|
||||
|
||||
! ynh_write_var_in_file "$file" "enable" "foobar"
|
||||
! _read_ini "$file" "enable"
|
||||
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
|
||||
|
||||
}
|
||||
|
||||
#############################
|
||||
# _ #
|
||||
# | | #
|
||||
# _ _ __ _ _ __ ___ | | #
|
||||
# | | | |/ _` | '_ ` _ \| | #
|
||||
# | |_| | (_| | | | | | | | #
|
||||
# \__, |\__,_|_| |_| |_|_| #
|
||||
# __/ | #
|
||||
# |___/ #
|
||||
# #
|
||||
#############################
|
||||
|
||||
_read_yaml() {
|
||||
local file="$1"
|
||||
local key="$2"
|
||||
python3 -c "import yaml; print(yaml.safe_load(open('$file'))['$key'])"
|
||||
}
|
||||
|
||||
ynhtest_config_read_yaml() {
|
||||
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
|
||||
file="$dummy_dir/dummy.yml"
|
||||
|
||||
cat << EOF > $file
|
||||
# Some comment
|
||||
foo:
|
||||
enabled: false
|
||||
# title: old title
|
||||
title: Lorem Ipsum
|
||||
theme: colib'ris
|
||||
email: root@example.com # This is a comment without quotes
|
||||
port: 1234 # This is a comment without quotes
|
||||
url: https://yunohost.org
|
||||
dict:
|
||||
ldap_base: ou=users,dc=yunohost,dc=org
|
||||
EOF
|
||||
|
||||
test "$(_read_yaml "$file" "foo")" == "None"
|
||||
test "$(ynh_read_var_in_file "$file" "foo")" == ""
|
||||
|
||||
test "$(_read_yaml "$file" "enabled")" == "False"
|
||||
test "$(ynh_read_var_in_file "$file" "enabled")" == "false"
|
||||
|
||||
test "$(_read_yaml "$file" "title")" == "Lorem Ipsum"
|
||||
test "$(ynh_read_var_in_file "$file" "title")" == "Lorem Ipsum"
|
||||
|
||||
test "$(_read_yaml "$file" "theme")" == "colib'ris"
|
||||
test "$(ynh_read_var_in_file "$file" "theme")" == "colib'ris"
|
||||
|
||||
test "$(_read_yaml "$file" "email")" == "root@example.com"
|
||||
test "$(ynh_read_var_in_file "$file" "email")" == "root@example.com"
|
||||
|
||||
test "$(_read_yaml "$file" "port")" == "1234"
|
||||
test "$(ynh_read_var_in_file "$file" "port")" == "1234"
|
||||
|
||||
test "$(_read_yaml "$file" "url")" == "https://yunohost.org"
|
||||
test "$(ynh_read_var_in_file "$file" "url")" == "https://yunohost.org"
|
||||
|
||||
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=users,dc=yunohost,dc=org"
|
||||
|
||||
! _read_yaml "$file" "nonexistent"
|
||||
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
|
||||
|
||||
! _read_yaml "$file" "enable"
|
||||
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
|
||||
}
|
||||
|
||||
|
||||
ynhtest_config_write_yaml() {
|
||||
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
|
||||
file="$dummy_dir/dummy.yml"
|
||||
|
||||
cat << EOF > $file
|
||||
# Some comment
|
||||
foo:
|
||||
enabled: false
|
||||
# title: old title
|
||||
title: Lorem Ipsum
|
||||
theme: colib'ris
|
||||
email: root@example.com # This is a comment without quotes
|
||||
port: 1234 # This is a comment without quotes
|
||||
url: https://yunohost.org
|
||||
dict:
|
||||
ldap_base: ou=users,dc=yunohost,dc=org
|
||||
EOF
|
||||
|
||||
ynh_write_var_in_file "$file" "foo" "bar"
|
||||
# cat $dummy_dir/dummy.yml # to debug
|
||||
! test "$(_read_yaml "$file" "foo")" == "bar" # writing broke the yaml syntax... "foo:bar" (no space aftr :)
|
||||
test "$(ynh_read_var_in_file "$file" "foo")" == "bar"
|
||||
|
||||
ynh_write_var_in_file "$file" "enabled" "true"
|
||||
test "$(_read_yaml "$file" "enabled")" == "True"
|
||||
test "$(ynh_read_var_in_file "$file" "enabled")" == "true"
|
||||
|
||||
ynh_write_var_in_file "$file" "title" "Foo Bar"
|
||||
test "$(_read_yaml "$file" "title")" == "Foo Bar"
|
||||
test "$(ynh_read_var_in_file "$file" "title")" == "Foo Bar"
|
||||
|
||||
ynh_write_var_in_file "$file" "theme" "super-awesome-theme"
|
||||
test "$(_read_yaml "$file" "theme")" == "super-awesome-theme"
|
||||
test "$(ynh_read_var_in_file "$file" "theme")" == "super-awesome-theme"
|
||||
|
||||
ynh_write_var_in_file "$file" "email" "sam@domain.tld"
|
||||
test "$(_read_yaml "$file" "email")" == "sam@domain.tld"
|
||||
test "$(ynh_read_var_in_file "$file" "email")" == "sam@domain.tld"
|
||||
|
||||
ynh_write_var_in_file "$file" "port" "5678"
|
||||
test "$(_read_yaml "$file" "port")" == "5678"
|
||||
test "$(ynh_read_var_in_file "$file" "port")" == "5678"
|
||||
|
||||
ynh_write_var_in_file "$file" "url" "https://domain.tld/foobar"
|
||||
test "$(_read_yaml "$file" "url")" == "https://domain.tld/foobar"
|
||||
test "$(ynh_read_var_in_file "$file" "url")" == "https://domain.tld/foobar"
|
||||
|
||||
ynh_write_var_in_file "$file" "ldap_base" "ou=foobar,dc=domain,dc=tld"
|
||||
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=foobar,dc=domain,dc=tld"
|
||||
|
||||
! ynh_write_var_in_file "$file" "nonexistent" "foobar"
|
||||
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
|
||||
|
||||
! ynh_write_var_in_file "$file" "enable" "foobar"
|
||||
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
|
||||
test "$(ynh_read_var_in_file "$file" "enabled")" == "true"
|
||||
}
|
||||
|
||||
#########################
|
||||
# _ #
|
||||
# (_) #
|
||||
# _ ___ ___ _ __ #
|
||||
# | / __|/ _ \| '_ \ #
|
||||
# | \__ \ (_) | | | | #
|
||||
# | |___/\___/|_| |_| #
|
||||
# _/ | #
|
||||
# |__/ #
|
||||
# #
|
||||
#########################
|
||||
|
||||
_read_json() {
|
||||
local file="$1"
|
||||
local key="$2"
|
||||
python3 -c "import json; print(json.load(open('$file'))['$key'])"
|
||||
}
|
||||
|
||||
ynhtest_config_read_json() {
|
||||
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
|
||||
file="$dummy_dir/dummy.json"
|
||||
|
||||
cat << EOF > $file
|
||||
{
|
||||
"foo": null,
|
||||
"enabled": false,
|
||||
"title": "Lorem Ipsum",
|
||||
"theme": "colib'ris",
|
||||
"email": "root@example.com",
|
||||
"port": 1234,
|
||||
"url": "https://yunohost.org",
|
||||
"dict": {
|
||||
"ldap_base": "ou=users,dc=yunohost,dc=org"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
|
||||
test "$(_read_json "$file" "foo")" == "None"
|
||||
test "$(ynh_read_var_in_file "$file" "foo")" == "null"
|
||||
|
||||
test "$(_read_json "$file" "enabled")" == "False"
|
||||
test "$(ynh_read_var_in_file "$file" "enabled")" == "false"
|
||||
|
||||
test "$(_read_json "$file" "title")" == "Lorem Ipsum"
|
||||
test "$(ynh_read_var_in_file "$file" "title")" == "Lorem Ipsum"
|
||||
|
||||
test "$(_read_json "$file" "theme")" == "colib'ris"
|
||||
test "$(ynh_read_var_in_file "$file" "theme")" == "colib'ris"
|
||||
|
||||
test "$(_read_json "$file" "email")" == "root@example.com"
|
||||
test "$(ynh_read_var_in_file "$file" "email")" == "root@example.com"
|
||||
|
||||
test "$(_read_json "$file" "port")" == "1234"
|
||||
test "$(ynh_read_var_in_file "$file" "port")" == "1234"
|
||||
|
||||
test "$(_read_json "$file" "url")" == "https://yunohost.org"
|
||||
test "$(ynh_read_var_in_file "$file" "url")" == "https://yunohost.org"
|
||||
|
||||
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=users,dc=yunohost,dc=org"
|
||||
|
||||
! _read_json "$file" "nonexistent"
|
||||
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
|
||||
|
||||
! _read_json "$file" "enable"
|
||||
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
|
||||
}
|
||||
|
||||
|
||||
ynhtest_config_write_json() {
|
||||
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
|
||||
file="$dummy_dir/dummy.json"
|
||||
|
||||
cat << EOF > $file
|
||||
{
|
||||
"foo": null,
|
||||
"enabled": false,
|
||||
"title": "Lorem Ipsum",
|
||||
"theme": "colib'ris",
|
||||
"email": "root@example.com",
|
||||
"port": 1234,
|
||||
"url": "https://yunohost.org",
|
||||
"dict": {
|
||||
"ldap_base": "ou=users,dc=yunohost,dc=org"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
ynh_write_var_in_file "$file" "foo" "bar"
|
||||
cat $file
|
||||
test "$(_read_json "$file" "foo")" == "bar"
|
||||
test "$(ynh_read_var_in_file "$file" "foo")" == "bar"
|
||||
|
||||
ynh_write_var_in_file "$file" "enabled" "true"
|
||||
cat $file
|
||||
test "$(_read_json "$file" "enabled")" == "true"
|
||||
test "$(ynh_read_var_in_file "$file" "enabled")" == "true"
|
||||
|
||||
ynh_write_var_in_file "$file" "title" "Foo Bar"
|
||||
cat $file
|
||||
test "$(_read_json "$file" "title")" == "Foo Bar"
|
||||
test "$(ynh_read_var_in_file "$file" "title")" == "Foo Bar"
|
||||
|
||||
ynh_write_var_in_file "$file" "theme" "super-awesome-theme"
|
||||
cat $file
|
||||
test "$(_read_json "$file" "theme")" == "super-awesome-theme"
|
||||
test "$(ynh_read_var_in_file "$file" "theme")" == "super-awesome-theme"
|
||||
|
||||
ynh_write_var_in_file "$file" "email" "sam@domain.tld"
|
||||
cat $file
|
||||
test "$(_read_json "$file" "email")" == "sam@domain.tld"
|
||||
test "$(ynh_read_var_in_file "$file" "email")" == "sam@domain.tld"
|
||||
|
||||
ynh_write_var_in_file "$file" "port" "5678"
|
||||
test "$(_read_json "$file" "port")" == "5678"
|
||||
test "$(ynh_read_var_in_file "$file" "port")" == "5678"
|
||||
|
||||
ynh_write_var_in_file "$file" "url" "https://domain.tld/foobar"
|
||||
test "$(_read_json "$file" "url")" == "https://domain.tld/foobar"
|
||||
test "$(ynh_read_var_in_file "$file" "url")" == "https://domain.tld/foobar"
|
||||
|
||||
ynh_write_var_in_file "$file" "ldap_base" "ou=foobar,dc=domain,dc=tld"
|
||||
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=foobar,dc=domain,dc=tld"
|
||||
|
||||
! ynh_write_var_in_file "$file" "nonexistent" "foobar"
|
||||
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
|
||||
|
||||
! ynh_write_var_in_file "$file" "enable" "foobar"
|
||||
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
|
||||
test "$(ynh_read_var_in_file "$file" "enabled")" == "true"
|
||||
}
|
||||
|
||||
#######################
|
||||
# _ #
|
||||
# | | #
|
||||
# _ __ | |__ _ __ #
|
||||
# | '_ \| '_ \| '_ \ #
|
||||
# | |_) | | | | |_) | #
|
||||
# | .__/|_| |_| .__/ #
|
||||
# | | | | #
|
||||
# |_| |_| #
|
||||
# #
|
||||
#######################
|
||||
|
||||
_read_php() {
|
||||
local file="$1"
|
||||
local key="$2"
|
||||
php -r "include '$file'; echo var_export(\$$key);" | sed "s/^'//g" | sed "s/'$//g"
|
||||
}
|
||||
|
||||
ynhtest_config_read_php() {
|
||||
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
|
||||
file="$dummy_dir/dummy.php"
|
||||
|
||||
cat << EOF > $file
|
||||
<?php
|
||||
// Some comment
|
||||
\$foo = NULL;
|
||||
\$enabled = false;
|
||||
// \$title = "old title";
|
||||
\$title = "Lorem Ipsum";
|
||||
\$theme = "colib'ris";
|
||||
\$email = "root@example.com"; // This is a comment without quotes
|
||||
\$port = 1234; // This is a second comment without quotes
|
||||
\$url = "https://yunohost.org";
|
||||
\$dict = [
|
||||
'ldap_base' => "ou=users,dc=yunohost,dc=org",
|
||||
'ldap_conf' => []
|
||||
];
|
||||
\$dict['ldap_conf']['user'] = 'camille';
|
||||
const DB_HOST = 'localhost';
|
||||
?>
|
||||
EOF
|
||||
|
||||
test "$(_read_php "$file" "foo")" == "NULL"
|
||||
test "$(ynh_read_var_in_file "$file" "foo")" == "NULL"
|
||||
|
||||
test "$(_read_php "$file" "enabled")" == "false"
|
||||
test "$(ynh_read_var_in_file "$file" "enabled")" == "false"
|
||||
|
||||
test "$(_read_php "$file" "title")" == "Lorem Ipsum"
|
||||
test "$(ynh_read_var_in_file "$file" "title")" == "Lorem Ipsum"
|
||||
|
||||
test "$(_read_php "$file" "theme")" == "colib\\'ris"
|
||||
test "$(ynh_read_var_in_file "$file" "theme")" == "colib'ris"
|
||||
|
||||
test "$(_read_php "$file" "email")" == "root@example.com"
|
||||
test "$(ynh_read_var_in_file "$file" "email")" == "root@example.com"
|
||||
|
||||
test "$(_read_php "$file" "port")" == "1234"
|
||||
test "$(ynh_read_var_in_file "$file" "port")" == "1234"
|
||||
|
||||
test "$(_read_php "$file" "url")" == "https://yunohost.org"
|
||||
test "$(ynh_read_var_in_file "$file" "url")" == "https://yunohost.org"
|
||||
|
||||
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=users,dc=yunohost,dc=org"
|
||||
|
||||
test "$(ynh_read_var_in_file "$file" "user")" == "camille"
|
||||
|
||||
test "$(ynh_read_var_in_file "$file" "DB_HOST")" == "localhost"
|
||||
|
||||
! _read_php "$file" "nonexistent"
|
||||
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
|
||||
|
||||
! _read_php "$file" "enable"
|
||||
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
|
||||
}
|
||||
|
||||
|
||||
ynhtest_config_write_php() {
|
||||
local dummy_dir="$(mktemp -d -p $VAR_WWW)"
|
||||
file="$dummy_dir/dummy.php"
|
||||
|
||||
cat << EOF > $file
|
||||
<?php
|
||||
// Some comment
|
||||
\$foo = NULL;
|
||||
\$enabled = false;
|
||||
// \$title = "old title";
|
||||
\$title = "Lorem Ipsum";
|
||||
\$theme = "colib'ris";
|
||||
\$email = "root@example.com"; // This is a comment without quotes
|
||||
\$port = 1234; // This is a comment without quotes
|
||||
\$url = "https://yunohost.org";
|
||||
\$dict = [
|
||||
'ldap_base' => "ou=users,dc=yunohost,dc=org",
|
||||
];
|
||||
?>
|
||||
EOF
|
||||
|
||||
ynh_write_var_in_file "$file" "foo" "bar"
|
||||
test "$(_read_php "$file" "foo")" == "bar"
|
||||
test "$(ynh_read_var_in_file "$file" "foo")" == "bar"
|
||||
|
||||
ynh_write_var_in_file "$file" "enabled" "true"
|
||||
test "$(_read_php "$file" "enabled")" == "true"
|
||||
test "$(ynh_read_var_in_file "$file" "enabled")" == "true"
|
||||
|
||||
ynh_write_var_in_file "$file" "title" "Foo Bar"
|
||||
cat $file
|
||||
test "$(_read_php "$file" "title")" == "Foo Bar"
|
||||
test "$(ynh_read_var_in_file "$file" "title")" == "Foo Bar"
|
||||
|
||||
ynh_write_var_in_file "$file" "theme" "super-awesome-theme"
|
||||
cat $file
|
||||
test "$(_read_php "$file" "theme")" == "super-awesome-theme"
|
||||
test "$(ynh_read_var_in_file "$file" "theme")" == "super-awesome-theme"
|
||||
|
||||
ynh_write_var_in_file "$file" "email" "sam@domain.tld"
|
||||
cat $file
|
||||
test "$(_read_php "$file" "email")" == "sam@domain.tld"
|
||||
test "$(ynh_read_var_in_file "$file" "email")" == "sam@domain.tld"
|
||||
|
||||
ynh_write_var_in_file "$file" "port" "5678"
|
||||
test "$(_read_php "$file" "port")" == "5678"
|
||||
test "$(ynh_read_var_in_file "$file" "port")" == "5678"
|
||||
|
||||
ynh_write_var_in_file "$file" "url" "https://domain.tld/foobar"
|
||||
test "$(_read_php "$file" "url")" == "https://domain.tld/foobar"
|
||||
test "$(ynh_read_var_in_file "$file" "url")" == "https://domain.tld/foobar"
|
||||
|
||||
ynh_write_var_in_file "$file" "ldap_base" "ou=foobar,dc=domain,dc=tld"
|
||||
test "$(ynh_read_var_in_file "$file" "ldap_base")" == "ou=foobar,dc=domain,dc=tld"
|
||||
|
||||
! ynh_write_var_in_file "$file" "nonexistent" "foobar"
|
||||
test "$(ynh_read_var_in_file "$file" "nonexistent")" == "YNH_NULL"
|
||||
|
||||
! ynh_write_var_in_file "$file" "enable" "foobar"
|
||||
test "$(ynh_read_var_in_file "$file" "enable")" == "YNH_NULL"
|
||||
test "$(ynh_read_var_in_file "$file" "enabled")" == "true"
|
||||
}
|
|
@ -6,14 +6,7 @@ import glob
|
|||
import json
|
||||
import yaml
|
||||
import subprocess
|
||||
|
||||
ignore = [
|
||||
"password_too_simple_",
|
||||
"password_listed",
|
||||
"backup_method_",
|
||||
"backup_applying_method_",
|
||||
"confirm_app_install_",
|
||||
]
|
||||
import toml
|
||||
|
||||
###############################################################################
|
||||
# Find used keys in python code #
|
||||
|
@ -137,33 +130,23 @@ def find_expected_string_keys():
|
|||
yield "backup_applying_method_%s" % method
|
||||
yield "backup_method_%s_finished" % method
|
||||
|
||||
for level in ["danger", "thirdparty", "warning"]:
|
||||
yield "confirm_app_install_%s" % level
|
||||
registrars = toml.load(open("data/other/registrar_list.toml"))
|
||||
supported_registrars = ["ovh", "gandi", "godaddy"]
|
||||
for registrar in supported_registrars:
|
||||
for key in registrars[registrar].keys():
|
||||
yield f"domain_config_{key}"
|
||||
|
||||
for errortype in ["not_found", "error", "warning", "success", "not_found_details"]:
|
||||
yield "diagnosis_domain_expiration_%s" % errortype
|
||||
yield "diagnosis_domain_not_found_details"
|
||||
|
||||
for errortype in ["bad_status_code", "connection_error", "timeout"]:
|
||||
yield "diagnosis_http_%s" % errortype
|
||||
|
||||
yield "password_listed"
|
||||
for i in [1, 2, 3, 4]:
|
||||
yield "password_too_simple_%s" % i
|
||||
|
||||
checks = [
|
||||
"outgoing_port_25_ok",
|
||||
"ehlo_ok",
|
||||
"fcrdns_ok",
|
||||
"blacklist_ok",
|
||||
"queue_ok",
|
||||
"ehlo_bad_answer",
|
||||
"ehlo_unreachable",
|
||||
"ehlo_bad_answer_details",
|
||||
"ehlo_unreachable_details",
|
||||
]
|
||||
for check in checks:
|
||||
yield "diagnosis_mail_%s" % check
|
||||
domain_config = toml.load(open("data/other/config_domain.toml"))
|
||||
for panel in domain_config.values():
|
||||
if not isinstance(panel, dict):
|
||||
continue
|
||||
for section in panel.values():
|
||||
if not isinstance(section, dict):
|
||||
continue
|
||||
for key, values in section.items():
|
||||
if not isinstance(values, dict):
|
||||
continue
|
||||
yield f"domain_config_{key}"
|
||||
|
||||
|
||||
###############################################################################
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue