Merge remote-tracking branch 'origin/dev' into dyndns-password

This commit is contained in:
Alexandre Aubin 2023-04-11 16:16:25 +02:00
commit c98da124b2
141 changed files with 7095 additions and 3773 deletions

View file

@ -1,2 +1,2 @@
[report]
omit=src/tests/*,src/vendor/*,/usr/lib/moulinette/yunohost/*
omit=src/tests/*,src/vendor/*,/usr/lib/moulinette/yunohost/*,/usr/lib/python3/dist-packages/yunohost/tests/*,/usr/lib/python3/dist-packages/yunohost/vendor/*

40
.github/workflows/codeql.yml vendored Normal file
View file

@ -0,0 +1,40 @@
name: "CodeQL"
on:
push:
branches: [ "dev" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "dev" ]
schedule:
- cron: '43 12 * * 3'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'python' ]
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
queries: security-extended,security-and-quality
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{matrix.language}}"

View file

@ -1,78 +0,0 @@
#!/bin/bash
#=================================================
# N UPDATING HELPER
#=================================================
# This script is meant to be run by GitHub Actions.
# It is derived from the Updater script from the YunoHost-Apps organization.
# It aims to automate the update of `n`, the Node version management system.
#=================================================
# FETCHING LATEST RELEASE AND ITS ASSETS
#=================================================
# Fetching information
source helpers/nodejs
current_version="$n_version"
repo="tj/n"
# Some jq magic is needed, because the latest upstream release is not always the latest version (e.g. security patches for older versions)
version=$(curl --silent "https://api.github.com/repos/$repo/releases" | jq -r '.[] | select( .prerelease != true ) | .tag_name' | sort -V | tail -1)
# Later down the script, we assume the version has only digits and dots
# Sometimes the release name starts with a "v", so let's filter it out.
if [[ ${version:0:1} == "v" || ${version:0:1} == "V" ]]; then
version=${version:1}
fi
# Setting up the environment variables
echo "Current version: $current_version"
echo "Latest release from upstream: $version"
echo "VERSION=$version" >> $GITHUB_ENV
# For the time being, let's assume the script will fail
echo "PROCEED=false" >> $GITHUB_ENV
# Proceed only if the retrieved version is greater than the current one
if ! dpkg --compare-versions "$current_version" "lt" "$version" ; then
echo "::warning ::No new version available"
exit 0
# Proceed only if a PR for this new version does not already exist
elif git ls-remote -q --exit-code --heads https://github.com/${GITHUB_REPOSITORY:-YunoHost/yunohost}.git ci-auto-update-n-v$version ; then
echo "::warning ::A branch already exists for this update"
exit 0
fi
#=================================================
# UPDATE SOURCE FILES
#=================================================
asset_url="https://github.com/tj/n/archive/v${version}.tar.gz"
echo "Handling asset at $asset_url"
# Create the temporary directory
tempdir="$(mktemp -d)"
# Download sources and calculate checksum
filename=${asset_url##*/}
curl --silent -4 -L $asset_url -o "$tempdir/$filename"
checksum=$(sha256sum "$tempdir/$filename" | head -c 64)
# Delete temporary directory
rm -rf $tempdir
echo "Calculated checksum for n v${version} is $checksum"
#=================================================
# GENERIC FINALIZATION
#=================================================
# Replace new version in helper
sed -i -E "s/^n_version=.*$/n_version=$version/" helpers/nodejs
# Replace checksum in helper
sed -i -E "s/^n_checksum=.*$/n_checksum=$checksum/" helpers/nodejs
# The Action will proceed only if the PROCEED environment variable is set to true
echo "PROCEED=true" >> $GITHUB_ENV
exit 0

View file

@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Fetch the source code
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run the updater script
@ -21,7 +21,8 @@ jobs:
git config --global user.name 'yunohost-bot'
git config --global user.email 'yunohost-bot@users.noreply.github.com'
# Run the updater script
/bin/bash .github/workflows/n_updater.sh
wget https://raw.githubusercontent.com/tj/n/master/bin/n --output-document=helpers/vendor/n/n
[[ -z "$(git diff helpers/vendor/n/n)" ]] || echo "PROCEED=true" >> $GITHUB_ENV
- name: Commit changes
id: commit
if: ${{ env.PROCEED == 'true' }}

View file

@ -16,6 +16,9 @@ default:
code_quality:
tags:
- docker
rules:
- if: $CI_COMMIT_TAG # Only for tags
code_quality_html:
extends: code_quality
@ -23,6 +26,9 @@ code_quality_html:
REPORT_FORMAT: html
artifacts:
paths: [gl-code-quality-report.html]
rules:
- if: $CI_COMMIT_TAG # Only for tags
# see: https://docs.gitlab.com/ee/ci/yaml/#switch-between-branch-pipelines-and-merge-request-pipelines
workflow:
@ -37,7 +43,7 @@ workflow:
- when: always
variables:
YNH_BUILD_DIR: "ynh-build"
YNH_BUILD_DIR: "/ynh-build"
include:
- template: Code-Quality.gitlab-ci.yml

View file

@ -8,7 +8,7 @@
- DEBIAN_FRONTEND=noninteractive apt update
artifacts:
paths:
- $YNH_BUILD_DIR/*.deb
- ./*.deb
.build_script: &build_script
- DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" install devscripts --no-install-recommends
@ -17,6 +17,8 @@
- VERSION_NIGHTLY="${VERSION}+$(date +%Y%m%d%H%M)"
- dch --package "${PACKAGE}" --force-bad-version -v "${VERSION_NIGHTLY}" -D "unstable" --force-distribution "Daily build."
- debuild --no-lintian -us -uc
- cp $YNH_BUILD_DIR/*.deb ${CI_PROJECT_DIR}/
- cd ${CI_PROJECT_DIR}
########################################
# BUILD DEB
@ -31,7 +33,7 @@ build-yunohost:
- mkdir -p $YNH_BUILD_DIR/$PACKAGE
- cat archive.tar.gz | tar -xz -C $YNH_BUILD_DIR/$PACKAGE
- rm archive.tar.gz
- DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $(pwd)/$YNH_BUILD_DIR/$PACKAGE
- DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $YNH_BUILD_DIR/$PACKAGE
- *build_script
@ -42,7 +44,7 @@ build-ssowat:
script:
- DEBIAN_DEPENDS=$(cat debian/control | tr "," "\n" | grep -Po "ssowat \([>,=,<]+ .*\)" | grep -Po "[0-9\.]+")
- git clone $YNH_SOURCE/$PACKAGE -b $CI_COMMIT_REF_NAME $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE -b $DEBIAN_DEPENDS $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE $YNH_BUILD_DIR/$PACKAGE --depth 1
- DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $(pwd)/$YNH_BUILD_DIR/$PACKAGE
- DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $YNH_BUILD_DIR/$PACKAGE
- *build_script
build-moulinette:
@ -52,5 +54,5 @@ build-moulinette:
script:
- DEBIAN_DEPENDS=$(cat debian/control | tr "," "\n" | grep -Po "moulinette \([>,=,<]+ .*\)" | grep -Po "[0-9\.]+")
- git clone $YNH_SOURCE/$PACKAGE -b $CI_COMMIT_REF_NAME $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE -b $DEBIAN_DEPENDS $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE $YNH_BUILD_DIR/$PACKAGE --depth 1
- DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $(pwd)/$YNH_BUILD_DIR/$PACKAGE
- DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $YNH_BUILD_DIR/$PACKAGE
- *build_script

View file

@ -13,15 +13,18 @@ generate-helpers-doc:
script:
- cd doc
- python3 generate_helper_doc.py
- python3 generate_resource_doc.py > resources.md
- hub clone https://$GITHUB_TOKEN:x-oauth-basic@github.com/YunoHost/doc.git doc_repo
- cp helpers.md doc_repo/pages/06.contribute/10.packaging_apps/11.helpers/packaging_apps_helpers.md
- cp helpers.md doc_repo/pages/06.contribute/10.packaging_apps/80.resources/11.helpers/packaging_apps_helpers.md
- cp resources.md doc_repo/pages/06.contribute/10.packaging_apps/80.resources/15.appresources/packaging_apps_resources.md
- cd doc_repo
# replace ${CI_COMMIT_REF_NAME} with ${CI_COMMIT_TAG} ?
- hub checkout -b "${CI_COMMIT_REF_NAME}"
- hub commit -am "[CI] Helper for ${CI_COMMIT_REF_NAME}"
- hub pull-request -m "[CI] Helper for ${CI_COMMIT_REF_NAME}" -p # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
- hub commit -am "[CI] Update app helpers/resources for ${CI_COMMIT_REF_NAME}"
- hub pull-request -m "[CI] Update app helpers/resources for ${CI_COMMIT_REF_NAME}" -p # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
artifacts:
paths:
- doc/helpers.md
- doc/resources.md
only:
- tags

View file

@ -17,7 +17,7 @@ upgrade:
image: "after-install"
script:
- apt-get update -o Acquire::Retries=3
- DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ./$YNH_BUILD_DIR/*.deb
- DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ${CI_PROJECT_DIR}/*.deb
install-postinstall:
@ -25,5 +25,5 @@ install-postinstall:
image: "before-install"
script:
- apt-get update -o Acquire::Retries=3
- DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ./$YNH_BUILD_DIR/*.deb
- DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ${CI_PROJECT_DIR}/*.deb
- yunohost tools postinstall -d domain.tld -u syssa -F 'Syssa Mine' -p the_password --ignore-dyndns --force-diskspace

View file

@ -42,7 +42,6 @@ black:
- '[ $(git diff | wc -l) != 0 ] || exit 0' # stop if there is nothing to commit
- git commit -am "[CI] Format code with Black" || true
- git push -f origin "ci-format-${CI_COMMIT_REF_NAME}":"ci-format-${CI_COMMIT_REF_NAME}"
- hub pull-request -m "[CI] Format code with Black" -b Yunohost:$CI_COMMIT_REF_NAME -p || true # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
- hub pull-request -m "[CI] Format code with Black" -b Yunohost:dev -p || true # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
only:
variables:
- $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
- tags

View file

@ -1,6 +1,6 @@
.install_debs: &install_debs
- apt-get update -o Acquire::Retries=3
- DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ./$YNH_BUILD_DIR/*.deb
- DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ${CI_PROJECT_DIR}/*.deb
- pip3 install -U mock pip pytest pytest-cov pytest-mock pytest-sugar requests-mock tox ansi2html black jinja2 "packaging<22"
.test-stage:
@ -36,7 +36,7 @@ full-tests:
- *install_debs
- yunohost tools postinstall -d domain.tld -u syssa -F 'Syssa Mine' -p the_password --ignore-dyndns --force-diskspace
script:
- python3 -m pytest --cov=yunohost tests/ src/tests/ src/diagnosers/ --junitxml=report.xml
- python3 -m pytest --cov=yunohost tests/ src/tests/ --junitxml=report.xml
- cd tests
- bash test_helpers.sh
needs:
@ -46,6 +46,7 @@ full-tests:
artifacts: true
- job: build-moulinette
artifacts: true
coverage: '/TOTAL.*\s+(\d+%)/'
artifacts:
reports:
junit: report.xml

View file

@ -26,7 +26,7 @@ autofix-translated-strings:
- git checkout -b "ci-autofix-translated-strings-${CI_COMMIT_REF_NAME}" --no-track
- python3 maintenance/missing_i18n_keys.py --fix
- python3 maintenance/autofix_locale_format.py
- '[ $(git diff | wc -l) != 0 ] || exit 0' # stop if there is nothing to commit
- '[ $(git diff --ignore-blank-lines --ignore-all-space --ignore-space-at-eol --ignore-cr-at-eol | 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-autofix-translated-strings-${CI_COMMIT_REF_NAME}":"ci-remove-stale-translated-strings-${CI_COMMIT_REF_NAME}"
- hub pull-request -m "[CI] Reformat / remove stale translated strings" -b Yunohost:$CI_COMMIT_REF_NAME -p || true # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd

View file

@ -1,4 +0,0 @@
extraction:
python:
python_setup:
version: "3"

View file

@ -7,10 +7,10 @@
<div align="center">
![Version](https://img.shields.io/github/v/tag/yunohost/yunohost?label=version&sort=semver)
[![Build status](https://shields.io/gitlab/pipeline/yunohost/yunohost/dev)](https://gitlab.com/yunohost/yunohost/-/pipelines)
![Test coverage](https://img.shields.io/gitlab/coverage/yunohost/yunohost/dev)
[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/YunoHost/yunohost.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/YunoHost/yunohost/context:python)
[![GitHub license](https://img.shields.io/github/license/YunoHost/yunohost)](https://github.com/YunoHost/yunohost/blob/dev/LICENSE)
[![Pipeline status](https://gitlab.com/yunohost/yunohost/badges/dev/pipeline.svg)](https://gitlab.com/yunohost/yunohost/-/pipelines)
![Test coverage](https://gitlab.com/yunohost/yunohost/badges/dev/coverage.svg)
[![Project license](https://img.shields.io/gitlab/license/yunohost/yunohost)](https://github.com/YunoHost/yunohost/blob/dev/LICENSE)
[![CodeQL](https://github.com/yunohost/yunohost/workflows/CodeQL/badge.svg)](https://github.com/YunoHost/yunohost/security/code-scanning)
[![Mastodon Follow](https://img.shields.io/mastodon/follow/28084)](https://mastodon.social/@yunohost)
</div>

View file

@ -10,7 +10,7 @@ mail_uid = 500
protocols = imap sieve {% if pop3_enabled == "True" %}pop3{% endif %}
mail_plugins = $mail_plugins quota
mail_plugins = $mail_plugins quota notify push_notification
###############################################################################

View file

@ -6,7 +6,7 @@ map $http_upgrade $connection_upgrade {
server {
listen 80;
listen [::]:80;
server_name {{ domain }}{% if xmpp_enabled != "True" %} xmpp-upload.{{ domain }} muc.{{ domain }}{% endif %};
server_name {{ domain }}{% if xmpp_enabled == "True" %} xmpp-upload.{{ domain }} muc.{{ domain }}{% endif %};
access_by_lua_file /usr/share/ssowat/access.lua;

View file

@ -7,9 +7,11 @@ location /yunohost/admin/ {
index index.html;
{% if webadmin_allowlist_enabled == "True" %}
{% for ip in webadmin_allowlist.split(',') %}
allow {{ ip }};
{% endfor %}
{% if webadmin_allowlist.strip() -%}
{% for ip in webadmin_allowlist.strip().split(',') -%}
allow {{ ip.strip() }};
{% endfor -%}
{% endif -%}
deny all;
{% endif %}

View file

@ -2,8 +2,6 @@ server_host = localhost
server_port = 389
search_base = dc=yunohost,dc=org
query_filter = (&(objectClass=groupOfNamesYnh)(mail=%s))
exclude_internal = yes
search_timeout = 30
scope = sub
result_attribute = memberUid, mail
terminal_result_attribute = memberUid

335
debian/changelog vendored
View file

@ -1,3 +1,338 @@
yunohost (11.1.17) stable; urgency=low
- domains: fix autodns for gandi root domain ([#1634](https://github.com/yunohost/yunohost/pull/1634))
- helpers: fix previous change about using YNH_APP_ACTION ... which is not defined in config panel context (8c25aa9b)
- appsv2: for the dir/subdirs of data_dir, create parent folders if they don't exist (9a4267ff)
- quality: Split utils/config.py ([#1635](https://github.com/yunohost/yunohost/pull/1635))
- quality: Rework questions/options tests ([#1629](https://github.com/yunohost/yunohost/pull/1629))
Thanks to all contributors <3 ! (axolotle, Kayou)
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 05 Apr 2023 16:00:09 +0200
yunohost (11.1.16) stable; urgency=low
- apps: fix i18n panel+section names ([#1630](https://github.com/yunohost/yunohost/pull/1630))
- appsv2: don't remove yhh-deps virtual package if it doesn't exist. Otherwise when apt fails to install dependency, we end up with another error about failing to remove the ynh-deps package (3656c199)
- appsv2: add validation for expected types for permissions stuff (b2596f32)
- appsv2: add support for subdirs property in data_dir (4b46f322)
- appsv2: various fixes regarding sources toml parsing/caching (14bf2ee4)
- appsv2: add documentation about the new 'autoupdate' mechanism for app sources (63981aac)
- ynh_setup_source: fix buggy checksum mismatch handling, can't compute the sha256sum after we delete the file @_@ (1b2fa91f)
- users: fix quota parsing being wrong by a factor 1000 ... doveadm returns kilos, not bytes (821aedef)
- backup: fix boring issue where archive is a broken symlink... (a95d10e5)
Thanks to all contributors <3 ! (axolotle)
-- Alexandre Aubin <alex.aubin@mailoo.org> Sun, 02 Apr 2023 20:29:33 +0200
yunohost (11.1.15) stable; urgency=low
- doc: Fix version number in autogenerated resource doc (5b58e0e6)
- helpers: Fix documentation for ynh_setup_source (7491dd4c)
- helpers: fix ynh_setup_source, 'source_id' may contain slashes x_x (eaf7a290)
- helpers/nodejs: simplify 'n' script install and maintenance ([#1627](https://github.com/yunohost/yunohost/pull/1627))
-- Alexandre Aubin <alex.aubin@mailoo.org> Sat, 11 Mar 2023 16:50:50 +0100
yunohost (11.1.14) stable; urgency=low
- helpers: simplify --time display option for ynh_script_progression .. we don't care about displaying time when below 10 sc (8731f77a)
- appsv2: add support for a 'sources' app resources to modernize and replace app.src format ([#1615](https://github.com/yunohost/yunohost/pull/1615))
- i18n: Translations updated for Arabic, Polish, Ukrainian
Thanks to all contributors <3 ! (ButterflyOfFire, Grzegorz Cichocki, Tymofii-Lytvynenko)
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 09 Mar 2023 15:34:17 +0100
yunohost (11.1.13) stable; urgency=low
- appsv2: fix port already used detection ([#1622](https://github.com/yunohost/yunohost/pull/1622))
- appsv2: when hydrating template, the data may be not-string, eg ports are int (72986842)
- [i18n] Translations updated for Arabic, French, Galician, German, Occitan
Thanks to all contributors <3 ! (ButterflyOfFire, Christian Wehrli, José M, Kay0u, ppr)
-- Alexandre Aubin <alex.aubin@mailoo.org> Fri, 03 Mar 2023 22:57:14 +0100
yunohost (11.1.12.2) stable; urgency=low
- helpers: omg base64 wraps the output by default :| (d04f2085)
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 01 Mar 2023 22:12:51 +0100
yunohost (11.1.12.1) stable; urgency=low
- helper: fix previous tweak about debugging diff for manually modified files on the CI @_@ (fd304008)
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 01 Mar 2023 08:08:55 +0100
yunohost (11.1.12) stable; urgency=low
- apps: add '--continue-on-failure' to 'yunohost app upgrade ([#1602](https://github.com/yunohost/yunohost/pull/1602))
- appsv2: Create parent dirs when provisioning install_dir ([#1609](https://github.com/yunohost/yunohost/pull/1609))
- appsv2: set `w` as default permission on `install_dir` folder ([#1611](https://github.com/yunohost/yunohost/pull/1611))
- appsv2: Handle undefined main permission url ([#1620](https://github.com/yunohost/yunohost/pull/1620))
- apps/helpers: tweak behavior of checksum helper in CI context to help debug why file appear as 'manually modified' ([#1618](https://github.com/yunohost/yunohost/pull/1618))
- apps/helpers: more robust way to grep that the service correctly started ? ([#1617](https://github.com/yunohost/yunohost/pull/1617))
- regenconf: sometimes ntp doesnt exist (97c0128c)
- nginx/security: fix empty webadmin allowlist breaking nginx conf... (e458d881)
- misc: automatic get rid of /etc/profile.d/check_yunohost_is_installed.sh when yunohost is postinstalled (20e8805e)
- settings: Fix pop3_enabled parsing returning 0/1 instead of True/False ... (b40c0de3)
- [i18n] Translations updated for French, Galician, Italian, Polish
Thanks to all contributors <3 ! (Éric Gaspar, John Schmidt, José M, Krakinou, Kuba Bazan, Laurent Peuch, ppr, tituspijean)
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 28 Feb 2023 23:08:02 +0100
yunohost (11.1.11.2) stable; urgency=low
- Rebump version to flag as stable, not testing >_>
-- Alexandre Aubin <alex.aubin@mailoo.org> Fri, 24 Feb 2023 13:09:48 +0100
yunohost (11.1.11.1) testing; urgency=low
- appsv2: fix previous commit about __DOMAIN__ because url may be None x_x (e05df676)
-- Alexandre Aubin <alex.aubin@mailoo.org> Fri, 24 Feb 2023 01:30:14 +0100
yunohost (11.1.11) stable; urgency=low
- logs: fix decoding errors not handled when trying to read service logs ([#1606](https://github.com/yunohost/yunohost/pull/1606))
- mail: fix dovecot-pop3d not being installed when enabling pop3 ([#1607](https://github.com/yunohost/yunohost/pull/1607))
- apps: when creating the app's bash env for script, make sure to use the manifest from the workdir instead of app setting dir, which is important for consistency during edge case when upgrade from v1 to v2 fails (bab27014)
- appsv2: data_dir's owner should have rwx by default (139e54a2)
- appsv2: fix usage of __DOMAIN__ in permission url (943b9ff8)
Thanks to all contributors <3 ! (Eric Geldmacher, ljf)
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 23 Feb 2023 22:31:02 +0100
yunohost (11.1.10) stable; urgency=low
- apps: add 'YNH_DEBIAN_VERSION' variable in apps contexts (df6a2a2c)
- appsv2: add support for a packages_from_raw_bash option in apt where one can add a multiline bash snippet to echo packages (4dfff201)
- appsv2: fix resource provisioning scripts picking up already-closed operation logger, resulting in confusing debugging output (888593ad)
- appsv2: fix reload_only_if_change option not working as expected, resulting in incorrect 'Firewall reloaded' messages (d725b454)
- appsv2: fix check that postgresql db exists... (1dc8b753)
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 21 Feb 2023 18:57:33 +0100
yunohost (11.1.9) stable; urgency=low
- apps: simplify the redaction of change_url scripts by adding a new ynh_change_url_nginx_config helper + predefining new/old/change domain/path variables (2b70ccbf)
- appsv2: revert commit that adds a bunch of warning about apt/database consistency, it's more relevant to have them in package linter instead (63f0f084)
- appsv2: fix system user group update, broke in commit from earlier (ec4c2684)
- log: Previous trick about getting rid of setting didnt work, forgot to use metadata instead of self.metadata (848adf89)
- ux: Moar boring postgresql messages displayed as warning (290d627f)
Thanks to all contributors <3 ! (Bram)
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 20 Feb 2023 20:32:28 +0100
yunohost (11.1.8.2) stable; urgency=low
- regenconf: fix undefined var in apt regenconf (343065eb)
-- Alexandre Aubin <alex.aubin@mailoo.org> Sun, 19 Feb 2023 21:38:59 +0100
yunohost (11.1.8.1) stable; urgency=low
- postgresql: moar regenconf fixes (e6ae3892)
- postgresql: ugly hack to hide boring warning messages when installing postgresql with apt the first time ... (13d50f4f)
-- Alexandre Aubin <alex.aubin@mailoo.org> Sun, 19 Feb 2023 19:41:05 +0100
yunohost (11.1.8) stable; urgency=low
- apps: don't miserably crash when failing to read .md file such as DESCRIPTION.md (58ac633d)
- apps: fix edge case when upgrading using a local folder not modified since a while (d3ec5d05)
- appsv2: fix system user provisioning ... (d123fd76, 771b801e)
- appsv2: add check about database vs. apt consistency in resource / warn about lack of explicit dependency to mariadb-server (97b69e7c)
- appsv2: add home dir that defaults to /var/www/__APP__ for system user resource (ce7227c0)
- postgresql: fix regenconf hook, the arg format thingy changed a bit at some point ? (8a43b046)
- regenconf: in apt/php stuff, don't try to upgrade-alternatives if the default PHP version ain't available anymore (similar to commit e24ddd29) (18e034df)
- postinstall: raise a proper error when trying to use e.g. 'admin' as the first username which will conflict with the admins group mail aliases (475c93d5)
- i18n: Translations updated for Arabic, Basque
Thanks to all contributors <3 ! (ButterflyOfFire, xabirequejo)
-- Alexandre Aubin <alex.aubin@mailoo.org> Sun, 19 Feb 2023 18:22:02 +0100
yunohost (11.1.7) stable; urgency=low
- mail: fix complain about unused parameters in postfix: exclude_internal=yes / search_timeout=30 (0da6370d)
- mail: Add push notification plugins in dovecot ([#1594](https://github.com/yunohost/yunohost/pull/1594))
- diagnosis: fix typo, diagnosis detail should be a list, not a string (d0ca120e)
- helpers: in apt/php stuff, don't try to upgrade-alternatives if the default PHP version ain't available anymore (e24ddd29)
- apps: fix inconsistent app removal during remove-after-failed-upgrade and remove-after-failed-backup contexts (7be7eb11)
- appsv2: we don't want to store user-provided passwords by default, but they should still be set in the env for the script to use it (9bd4344f)
- appsv2: fix i18n for arch mismatch, can't juste join() inside string formated with .format() (aa9bc47a)
- appsv2: missing raw_msg=True for exceptions (1d1a3756)
- appsv2: fix check that main permission url is '/' (ab8a6b94)
- appsv2: mysqlshow is fucking dumb and returns exit code 0 when DB doesnt exists ... (0ab20b73)
- appsv2: also replace __DOMAIN__ in resource properties (0c4a006a)
- appsv2: in php helpers, use the global $phpversion var/setting by default instead of $YNH_PHP_VERSION (60b21795)
- i18n: Translations updated for Arabic, Galician
Thanks to all contributors <3 ! (ButterflyOfFire, John Hackett, José M)
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 15 Feb 2023 21:08:04 +0100
yunohost (11.1.6.2) stable; urgency=low
- permissions: fix trailing-slash issue in edge case where app has additional urls related to a different domain (a4fa6e07)
- backup: fix postinstall during full restore ... tmp admin user can't be named 'admin' because of conflicting alias with the admins group (65894007)
- doc: improve app resource doc (a154e811)
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 09 Feb 2023 19:00:42 +0100
yunohost (11.1.6.1) stable; urgency=low
- dns: fix CAA recommended DNS conf -> 0 is apparently a more sensible value than 128... (2eb7da06)
- users: Allow digits in user fullname (024db62a)
- backup: fix full backup restore postinstall calls that now need first username+fullname+password (48e488f8)
- i18n: Translations updated for Arabic, Basque, Chinese (Simplified)
Thanks to all contributors <3 ! (ButterflyOfFire, Poesty Li, xabirequejo)
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 08 Feb 2023 22:50:37 +0100
yunohost (11.1.6) stable; urgency=low
- helpers: allow to use ynh_replace_string with @ ([#1588](https://github.com/yunohost/yunohost/pull/1588))
- helpers: fix behavior of ynh_write_var_in_file when key is duplicated ([#1589](https://github.com/yunohost/yunohost/pull/1589), [#1591](https://github.com/yunohost/yunohost/pull/1591))
- helpers: fix composer workdir variable for package v2 ([#1586](https://github.com/yunohost/yunohost/pull/1586))
- configpanels: properly escape & for values used in ynh_write_var_in_file ([#1590](https://github.com/yunohost/yunohost/pull/1590))
- appsv2/group question: don't include primary groups in choices (c179d4b8)
- appsv2: when initalizing permission, make sure to add 'all_users' when visitors is chosen (71042f08)
- backup/multimedia: test that /home/yunohots.multimedia does exists to avoid boring warning later (170eaf5d)
- domains: add missing logic to inject translated 'help' keys in config panel like we do for global settings (4dee434e)
- domain/dns: don't miserably crash when the domain is known by lexicon but not in registrar_list.toml (b5b69e95)
- admin->admins migration: try to losen up even more the search for first admin user x_x (1e520342)
- i18n: Translations updated for French, Polish
Thanks to all contributors <3 ! (Éric Gaspar, Grzegorz Cichocki, Kayou, Krzysztof Nowakowski, ljf, ppr)
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 07 Feb 2023 00:14:17 +0100
yunohost (11.1.5.5) stable; urgency=low
- admin->admins migration: try to handle boring case where the 'first' user cant be identified because it doesnt have the root@ alias (8485ebc7)
- appsv2: ignore the old/ugly/legacy removal of apt deps when removing the php conf, because that's handled by the apt resource (3bbba640)
- appsv2: moar fixes for v1->v2 upgrade not getting the proper env context (fb54da2e)
-- Alexandre Aubin <alex.aubin@mailoo.org> Sat, 04 Feb 2023 18:51:03 +0100
yunohost (11.1.5.4) stable; urgency=low
- appsv2: typo in ports resource doc x_x (0e787acb)
- appsv2: fix permission provisioning for fulldomain apps + fix apps not properly getting removed after failed resources init (476908bd)
-- Alexandre Aubin <alex.aubin@mailoo.org> Fri, 03 Feb 2023 20:43:04 +0100
yunohost (11.1.5.3) stable; urgency=low
- helpers/appsv2: replacement of __PHPVERSION__ should use the phpversion setting, not YNH_PHP_VERSION (13d4e16e)
- appv2 resources: document the fact that the apt resource may create a phpversion setting when the dependencies contain php packages (2107a848)
-- Alexandre Aubin <alex.aubin@mailoo.org> Fri, 03 Feb 2023 03:05:11 +0100
yunohost (11.1.5.2) stable; urgency=low
- maintenance: new year, update copyright header (ba4f1925)
- helpers: fix remaining __FINALPATH__ in php template (note that this is backward compatible because ynh_add_config will replace __INSTALL_DIR__ by $finalpath if $finalpath exists... (9b7668da)
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 02 Feb 2023 23:58:29 +0100
yunohost (11.1.5.1) stable; urgency=low
- debian: Bump moulinette/ssowat requirement to 11.1 (0826a541)
- helpers: Fixes $app unbound when running ynh_secure_remove ([#1582](https://github.com/yunohost/yunohost/pull/1582))
- log/appv2: don't dump all settings in log metadata (a9ac55e4)
- appv2: resource upgrade will tweak settings, we have to re-update the env_dict after upgrading resources (3110460a)
- appv2: safety-backup-before-upgrade should only contain the app (1c95bcff)
- appv2: fix env not including vars for v1->v2 upgrade (2b2d49a5)
- backup: add name of the backup in create/delete message, otherwise that creates some spooky messages with 'Backup created' directly followed by 'Backup deleted' during safety-backup-before-upgrade in v2 apps (8090acb1)
- [i18n] Translations updated for Arabic, French, Galician, Polish
Thanks to all contributors <3 ! (ButterflyOfFire, Éric Gaspar, Eryk Michalak, Florent, José M, ppr)
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 02 Feb 2023 23:37:46 +0100
yunohost (11.1.5) stable; urgency=low
- Release as stable !
- diagnosis: we can't yield an ERROR if there's no IPv6, otherwise that blocks all subsequent network-related diagnoser because of the dependency system ... (ade92e43)
- domains: fix domain_config.toml typos in conditions (480f7a43)
- certs: Don't try restarting metronome if no domain configured for it (452ba8bb)
Thanks to all contributors <3 ! (Axolotle)
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 01 Feb 2023 20:21:56 +0100
yunohost (11.1.4.1) testing; urgency=low
- debian: don't dump upgradable apps during postinst's catalog update (82d30f02)
- ynh_setup_source: Output checksums when source is 'corrupt' ([#1578](https://github.com/yunohost/yunohost/pull/1578))
- metronome: Auto-enable/disable metronome if there's no/at least one domain configured for XMPP (c990cee6)
Thanks to all contributors <3 ! (tituspijean)
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 01 Feb 2023 17:10:32 +0100
yunohost (11.1.4) testing; urgency=low
- settings: Add DNS exposure setting given the IP version ([#1451](https://github.com/yunohost/yunohost/pull/1451))
Thanks to all contributors <3 ! (Tagada)
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 30 Jan 2023 16:28:56 +0100
yunohost (11.1.3.1) testing; urgency=low
- nginx: add xmpp-upload. and muc. server_name only if xmpp_enabled is enabled (c444dee4)
- [i18n] Translations updated for Arabic, Basque, French, Galician, Spanish, Turkish
Thanks to all contributors <3 ! (Alperen İsa Nalbant, ButterflyOfFire, cristian amoyao, Éric Gaspar, José M, Kayou, ppr, quiwy, xabirequejo)
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 30 Jan 2023 15:44:30 +0100
yunohost (11.1.3) testing; urgency=low
- helpers: Include procedures in MySQL database backup ([#1570](https://github.com/yunohost/yunohost/pull/1570))
- users: be able to change the loginShell of a user ([#1538](https://github.com/yunohost/yunohost/pull/1538))
- debian: refresh catalog upon package upgrade (be5b1c1b)
Thanks to all contributors <3 ! (Éric Gaspar, Kay0u, ljf, Metin Bektas)
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 19 Jan 2023 23:08:10 +0100
yunohost (11.1.2.2) testing; urgency=low
- Minor technical fixes (b37d4baf, 68342171)
- configpanel: stop the madness of returning a 500 error when trying to load config panel 0.1 ... otherwise this will crash the new app info view ... (f21fbed2)
- apps: fix trick to find the default branch from git repo @_@ (25c10166)
- debian: regen ssowatconf during package upgrade (4615d7b7)
- [i18n] Translations updated for French
Thanks to all contributors <3 ! (Éric Gaspar, ppr)
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 10 Jan 2023 13:23:28 +0100
yunohost (11.1.2.1) testing; urgency=low
- i18n: fix (un)defined string issues (dd33476f)
- doc: Revive the old auto documentation of API with swagger
- apps: don't clone 'master' branch by default, use git ls-remote to check what's the default branch instead (a6db52b7)
- ssowat: add use_remote_user_var_in_nginx_conf flag on permission (f258eab6)
Thanks to all contributors <3 ! (ljf)
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 09 Jan 2023 23:58:51 +0100
yunohost (11.1.2) testing; urgency=low
- apps: Various fixes/improvements for appsv2, mostly related to webadmin integration ([#1526](https://github.com/yunohost/yunohost/pull/1526))

2
debian/control vendored
View file

@ -10,7 +10,7 @@ Package: yunohost
Essential: yes
Architecture: all
Depends: ${python3:Depends}, ${misc:Depends}
, moulinette (>= 11.0), ssowat (>= 11.0)
, moulinette (>= 11.1), ssowat (>= 11.1)
, python3-psutil, python3-requests, python3-dnspython, python3-openssl
, python3-miniupnpc, python3-dbus, python3-jinja2
, python3-toml, python3-packaging, python3-publicsuffix2

5
debian/postinst vendored
View file

@ -20,6 +20,7 @@ do_configure() {
fi
else
echo "Regenerating configuration, this might take a while..."
yunohost app ssowatconf
yunohost tools regen-conf --output-as none
echo "Launching migrations..."
@ -27,6 +28,9 @@ do_configure() {
echo "Re-diagnosing server health..."
yunohost diagnosis run --force
echo "Refreshing app catalog..."
yunohost tools update apps --output-as none || true
fi
# Trick to let yunohost handle the restart of the API,
@ -52,7 +56,6 @@ API_START_TIMESTAMP="\$(date --date="\$(systemctl show yunohost-api | grep ExecM
if [ "\$(( \$(date +%s) - \$API_START_TIMESTAMP ))" -ge 60 ];
then
echo "restart" >> /var/log/testalex
systemctl restart yunohost-api
fi
EOF

View file

@ -22,291 +22,262 @@ import os
import sys
import yaml
import json
import requests
def main():
"""
"""
with open('../share/actionsmap.yml') as f:
with open("../share/actionsmap.yml") as f:
action_map = yaml.safe_load(f)
try:
with open('/etc/yunohost/current_host', 'r') as f:
domain = f.readline().rstrip()
except IOError:
domain = requests.get('http://ip.yunohost.org').text
with open('../debian/changelog') as f:
# try:
# with open("/etc/yunohost/current_host", "r") as f:
# domain = f.readline().rstrip()
# except IOError:
# domain = requests.get("http://ip.yunohost.org").text
with open("../debian/changelog") as f:
top_changelog = f.readline()
api_version = top_changelog[top_changelog.find("(")+1:top_changelog.find(")")]
api_version = top_changelog[top_changelog.find("(") + 1 : top_changelog.find(")")]
csrf = {
'name': 'X-Requested-With',
'in': 'header',
'required': True,
'schema': {
'type': 'string',
'default': 'Swagger API'
}
"name": "X-Requested-With",
"in": "header",
"required": True,
"schema": {"type": "string", "default": "Swagger API"},
}
resource_list = {
'openapi': '3.0.3',
'info': {
'title': 'YunoHost API',
'description': 'This is the YunoHost API used on all YunoHost instances. This API is essentially used by YunoHost Webadmin.',
'version': api_version,
"openapi": "3.0.3",
"info": {
"title": "YunoHost API",
"description": "This is the YunoHost API used on all YunoHost instances. This API is essentially used by YunoHost Webadmin.",
"version": api_version,
},
'servers': [
"servers": [
{
'url': "https://{domain}/yunohost/api",
'variables': {
'domain': {
'default': 'demo.yunohost.org',
'description': 'Your yunohost domain'
"url": "https://{domain}/yunohost/api",
"variables": {
"domain": {
"default": "demo.yunohost.org",
"description": "Your yunohost domain",
}
}
},
}
],
'tags': [
{
'name': 'public',
'description': 'Public route'
}
],
'paths': {
'/login': {
'post': {
'tags': ['public'],
'summary': 'Logs in and returns the authentication cookie',
'parameters': [csrf],
'requestBody': {
'required': True,
'content': {
'multipart/form-data': {
'schema': {
'type': 'object',
'properties': {
'credentials': {
'type': 'string',
'format': 'password'
"tags": [{"name": "public", "description": "Public route"}],
"paths": {
"/login": {
"post": {
"tags": ["public"],
"summary": "Logs in and returns the authentication cookie",
"parameters": [csrf],
"requestBody": {
"required": True,
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"credentials": {
"type": "string",
"format": "password",
}
},
'required': [
'credentials'
]
"required": ["credentials"],
}
}
},
},
"security": [],
"responses": {
"200": {
"description": "Successfully login",
"headers": {"Set-Cookie": {"schema": {"type": "string"}}},
}
},
'security': [],
'responses': {
'200': {
'description': 'Successfully login',
'headers': {
'Set-Cookie': {
'schema': {
'type': 'string'
}
}
}
}
}
}
},
'/installed': {
'get': {
'tags': ['public'],
'summary': 'Test if the API is working',
'parameters': [],
'security': [],
'responses': {
'200': {
'description': 'Successfully working',
"/installed": {
"get": {
"tags": ["public"],
"summary": "Test if the API is working",
"parameters": [],
"security": [],
"responses": {
"200": {
"description": "Successfully working",
}
}
},
}
}
},
},
}
def convert_categories(categories, parent_category=""):
for category, category_params in categories.items():
if parent_category:
category = f"{parent_category} {category}"
if 'subcategory_help' in category_params:
category_params['category_help'] = category_params['subcategory_help']
if "subcategory_help" in category_params:
category_params["category_help"] = category_params["subcategory_help"]
if 'category_help' not in category_params:
category_params['category_help'] = ''
resource_list['tags'].append({
'name': category,
'description': category_params['category_help']
})
if "category_help" not in category_params:
category_params["category_help"] = ""
resource_list["tags"].append(
{"name": category, "description": category_params["category_help"]}
)
for action, action_params in category_params['actions'].items():
if 'action_help' not in action_params:
action_params['action_help'] = ''
if 'api' not in action_params:
for action, action_params in category_params["actions"].items():
if "action_help" not in action_params:
action_params["action_help"] = ""
if "api" not in action_params:
continue
if not isinstance(action_params['api'], list):
action_params['api'] = [action_params['api']]
if not isinstance(action_params["api"], list):
action_params["api"] = [action_params["api"]]
for i, api in enumerate(action_params['api']):
for i, api in enumerate(action_params["api"]):
print(api)
method, path = api.split(' ')
method, path = api.split(" ")
method = method.lower()
key_param = ''
if '{' in path:
key_param = path[path.find("{")+1:path.find("}")]
resource_list['paths'].setdefault(path, {})
key_param = ""
if "{" in path:
key_param = path[path.find("{") + 1 : path.find("}")]
resource_list["paths"].setdefault(path, {})
notes = ''
notes = ""
operationId = f"{category}_{action}"
if i > 0:
operationId += f"_{i}"
operation = {
'tags': [category],
'operationId': operationId,
'summary': action_params['action_help'],
'description': notes,
'responses': {
'200': {
'description': 'successful operation'
}
}
"tags": [category],
"operationId": operationId,
"summary": action_params["action_help"],
"description": notes,
"responses": {"200": {"description": "successful operation"}},
}
if action_params.get('deprecated'):
operation['deprecated'] = True
if action_params.get("deprecated"):
operation["deprecated"] = True
operation['parameters'] = []
if method == 'post':
operation['parameters'] = [csrf]
operation["parameters"] = []
if method == "post":
operation["parameters"] = [csrf]
if 'arguments' in action_params:
if method in ['put', 'post', 'patch']:
operation['requestBody'] = {
'required': True,
'content': {
'multipart/form-data': {
'schema': {
'type': 'object',
'properties': {
},
'required': []
if "arguments" in action_params:
if method in ["put", "post", "patch"]:
operation["requestBody"] = {
"required": True,
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {},
"required": [],
}
}
}
},
}
for arg_name, arg_params in action_params['arguments'].items():
if 'help' not in arg_params:
arg_params['help'] = ''
param_type = 'query'
for arg_name, arg_params in action_params["arguments"].items():
if "help" not in arg_params:
arg_params["help"] = ""
param_type = "query"
allow_multiple = False
required = True
allowable_values = None
name = str(arg_name).replace('-', '_')
if name[0] == '_':
name = str(arg_name).replace("-", "_")
if name[0] == "_":
required = False
if 'full' in arg_params:
name = arg_params['full'][2:]
if "full" in arg_params:
name = arg_params["full"][2:]
else:
name = name[2:]
name = name.replace('-', '_')
name = name.replace("-", "_")
if 'choices' in arg_params:
allowable_values = arg_params['choices']
_type = 'string'
if 'type' in arg_params:
types = {
'open': 'file',
'int': 'int'
}
_type = types[arg_params['type']]
if 'action' in arg_params and arg_params['action'] == 'store_true':
_type = 'boolean'
if "choices" in arg_params:
allowable_values = arg_params["choices"]
_type = "string"
if "type" in arg_params:
types = {"open": "file", "int": "int"}
_type = types[arg_params["type"]]
if (
"action" in arg_params
and arg_params["action"] == "store_true"
):
_type = "boolean"
if 'nargs' in arg_params:
if arg_params['nargs'] == '*':
if "nargs" in arg_params:
if arg_params["nargs"] == "*":
allow_multiple = True
required = False
_type = 'array'
if arg_params['nargs'] == '+':
_type = "array"
if arg_params["nargs"] == "+":
allow_multiple = True
required = True
_type = 'array'
if arg_params['nargs'] == '?':
_type = "array"
if arg_params["nargs"] == "?":
allow_multiple = False
required = False
else:
allow_multiple = False
if name == key_param:
param_type = 'path'
param_type = "path"
required = True
allow_multiple = False
if method in ['put', 'post', 'patch']:
schema = operation['requestBody']['content']['multipart/form-data']['schema']
schema['properties'][name] = {
'type': _type,
'description': arg_params['help']
if method in ["put", "post", "patch"]:
schema = operation["requestBody"]["content"][
"multipart/form-data"
]["schema"]
schema["properties"][name] = {
"type": _type,
"description": arg_params["help"],
}
if required:
schema['required'].append(name)
prop_schema = schema['properties'][name]
schema["required"].append(name)
prop_schema = schema["properties"][name]
else:
parameters = {
'name': name,
'in': param_type,
'description': arg_params['help'],
'required': required,
'schema': {
'type': _type,
"name": name,
"in": param_type,
"description": arg_params["help"],
"required": required,
"schema": {
"type": _type,
},
'explode': allow_multiple
"explode": allow_multiple,
}
prop_schema = parameters['schema']
operation['parameters'].append(parameters)
prop_schema = parameters["schema"]
operation["parameters"].append(parameters)
if allowable_values is not None:
prop_schema['enum'] = allowable_values
if 'default' in arg_params:
prop_schema['default'] = arg_params['default']
if arg_params.get('metavar') == 'PASSWORD':
prop_schema['format'] = 'password'
if arg_params.get('metavar') == 'MAIL':
prop_schema['format'] = 'mail'
prop_schema["enum"] = allowable_values
if "default" in arg_params:
prop_schema["default"] = arg_params["default"]
if arg_params.get("metavar") == "PASSWORD":
prop_schema["format"] = "password"
if arg_params.get("metavar") == "MAIL":
prop_schema["format"] = "mail"
# Those lines seems to slow swagger ui too much
#if 'pattern' in arg_params.get('extra', {}):
# if 'pattern' in arg_params.get('extra', {}):
# prop_schema['pattern'] = arg_params['extra']['pattern'][0]
resource_list['paths'][path][method.lower()] = operation
resource_list["paths"][path][method.lower()] = operation
# Includes subcategories
if 'subcategories' in category_params:
convert_categories(category_params['subcategories'], category)
if "subcategories" in category_params:
convert_categories(category_params["subcategories"], category)
del action_map['_global']
del action_map["_global"]
convert_categories(action_map)
openapi_json = json.dumps(resource_list)
# Save the OpenAPI json
with open(os.getcwd() + '/openapi.json', 'w') as f:
with open(os.getcwd() + "/openapi.json", "w") as f:
f.write(openapi_json)
openapi_js = f"var openapiJSON = {openapi_json}"
with open(os.getcwd() + '/openapi.js', 'w') as f:
with open(os.getcwd() + "/openapi.js", "w") as f:
f.write(openapi_js)
if __name__ == '__main__':
if __name__ == "__main__":
sys.exit(main())

View file

@ -31,7 +31,6 @@ def get_dict_actions(OPTION_SUBTREE, category):
with open(ACTIONSMAP_FILE, "r") as stream:
# Getting the dictionary containning what actions are possible per category
OPTION_TREE = yaml.safe_load(stream)
@ -65,7 +64,6 @@ with open(ACTIONSMAP_FILE, "r") as stream:
os.makedirs(BASH_COMPLETION_FOLDER, exist_ok=True)
with open(BASH_COMPLETION_FILE, "w") as generated_file:
# header of the file
generated_file.write("#\n")
generated_file.write("# completion for yunohost\n")

View file

@ -20,12 +20,11 @@ def get_current_commit():
def render(helpers):
current_commit = get_current_commit()
data = {
"helpers": helpers,
"date": datetime.datetime.now().strftime("%m/%d/%Y"),
"date": datetime.datetime.now().strftime("%d/%m/%Y"),
"version": open("../debian/changelog").readlines()[0].split()[1].strip("()"),
}
@ -56,20 +55,17 @@ def render(helpers):
class Parser:
def __init__(self, filename):
self.filename = filename
self.file = open(filename, "r").readlines()
self.blocks = None
def parse_blocks(self):
self.blocks = []
current_reading = "void"
current_block = {"name": None, "line": -1, "comments": [], "code": []}
for i, line in enumerate(self.file):
if line.startswith("#!/bin/bash"):
continue
@ -117,7 +113,6 @@ class Parser:
current_reading = "code"
elif current_reading == "code":
if line == "}":
# We're getting out of the function
current_reading = "void"
@ -138,7 +133,6 @@ class Parser:
continue
def parse_block(self, b):
b["brief"] = ""
b["details"] = ""
b["usage"] = ""
@ -164,7 +158,6 @@ class Parser:
elif subblock.startswith("usage"):
for line in subblock.split("\n"):
if line.startswith("| arg"):
linesplit = line.split()
argname = linesplit[2]
@ -216,7 +209,6 @@ def malformed_error(line_number):
def main():
helper_files = sorted(glob.glob("../helpers/*"))
helpers = []

View file

@ -60,7 +60,6 @@ def main():
# man pages of "yunohost *"
with open(ACTIONSMAP_FILE, "r") as actionsmap:
# Getting the dictionary containning what actions are possible per domain
actionsmap = ordered_yaml_load(actionsmap)

View file

@ -1,12 +1,72 @@
from yunohost.utils.resources import AppResourceClassesByType
import ast
import datetime
import subprocess
resources = sorted(AppResourceClassesByType.values(), key=lambda r: r.priority)
version = open("../debian/changelog").readlines()[0].split()[1].strip("()")
today = datetime.datetime.now().strftime("%d/%m/%Y")
for klass in resources:
doc = klass.__doc__.replace("\n ", "\n")
def get_current_commit():
p = subprocess.Popen(
"git rev-parse --verify HEAD",
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
stdout, stderr = p.communicate()
current_commit = stdout.strip().decode("utf-8")
return current_commit
current_commit = get_current_commit()
print(
f"""---
title: App resources
template: docs
taxonomy:
category: docs
routes:
default: '/packaging_apps_resources'
---
Doc auto-generated by [this script](https://github.com/YunoHost/yunohost/blob/{current_commit}/doc/generate_resource_doc.py) on {today} (YunoHost version {version})
"""
)
fname = "../src/utils/resources.py"
content = open(fname).read()
# NB: This magic is because we want to be able to run this script outside of a YunoHost context,
# in which we cant really 'import' the file because it will trigger a bunch of moulinette/yunohost imports...
tree = ast.parse(content)
ResourceClasses = [
c
for c in tree.body
if isinstance(c, ast.ClassDef) and c.bases and c.bases[0].id == "AppResource"
]
ResourceDocString = {}
for c in ResourceClasses:
assert c.body[1].targets[0].id == "type"
resource_id = c.body[1].value.value
docstring = ast.get_docstring(c)
ResourceDocString[resource_id] = docstring
for resource_id, doc in sorted(ResourceDocString.items()):
doc = doc.replace("\n ", "\n")
print("----------------")
print("")
print(f"## {klass.type.replace('_', ' ').title()}")
print(f"## {resource_id.replace('_', ' ').title()}")
print("")
print(doc)
print("")

View file

@ -277,7 +277,10 @@ ynh_install_app_dependencies() {
ynh_app_setting_set --app=$app --key=phpversion --value=$specific_php_version
# Set the default php version back as the default version for php-cli.
update-alternatives --set php /usr/bin/php$YNH_DEFAULT_PHP_VERSION
if test -e /usr/bin/php$YNH_DEFAULT_PHP_VERSION
then
update-alternatives --set php /usr/bin/php$YNH_DEFAULT_PHP_VERSION
fi
elif grep --quiet 'php' <<< "$dependencies"; then
ynh_app_setting_set --app=$app --key=phpversion --value=$YNH_DEFAULT_PHP_VERSION
fi
@ -367,7 +370,13 @@ ynh_remove_app_dependencies() {
apt-mark unhold ${dep_app}-ynh-deps
fi
ynh_package_autopurge ${dep_app}-ynh-deps # Remove the fake package and its dependencies if they not still used.
# Remove the fake package and its dependencies if they not still used.
# (except if dpkg doesn't know anything about the package,
# which should be symptomatic of a failed install, and we don't want bash to report an error)
if dpkg-query --show ${dep_app}-ynh-deps &>/dev/null
then
ynh_package_autopurge ${dep_app}-ynh-deps
fi
}
# Install packages from an extra repository properly.

View file

@ -327,6 +327,13 @@ ynh_store_file_checksum() {
ynh_app_setting_set --app=$app --key=$checksum_setting_name --value=$(md5sum "$file" | cut --delimiter=' ' --fields=1)
if [ ${PACKAGE_CHECK_EXEC:-0} -eq 1 ]; then
# Using a base64 is in fact more reversible than "replace / and space by _" ... So we can in fact obtain the original file path in an easy reliable way ...
local file_path_base64=$(echo "$file" | base64 -w0)
mkdir -p /var/cache/yunohost/appconfbackup/
cat $file > /var/cache/yunohost/appconfbackup/original_${file_path_base64}
fi
# If backup_file_checksum isn't empty, ynh_backup_if_checksum_is_different has made a backup
if [ -n "${backup_file_checksum-}" ]; then
# Print the diff between the previous file and the new one.
@ -361,11 +368,20 @@ ynh_backup_if_checksum_is_different() {
backup_file_checksum=""
if [ -n "$checksum_value" ]; then # Proceed only if a value was stored into the app settings
if [ -e $file ] && ! echo "$checksum_value $file" | md5sum --check --status; then # If the checksum is now different
backup_file_checksum="/var/cache/yunohost/appconfbackup/$file.backup.$(date '+%Y%m%d.%H%M%S')"
mkdir --parents "$(dirname "$backup_file_checksum")"
cp --archive "$file" "$backup_file_checksum" # Backup the current file
ynh_print_warn "File $file has been manually modified since the installation or last upgrade. So it has been duplicated in $backup_file_checksum"
echo "$backup_file_checksum" # Return the name of the backup file
if [ ${PACKAGE_CHECK_EXEC:-0} -eq 1 ]; then
local file_path_base64=$(echo "$file" | base64 -w0)
if test -e /var/cache/yunohost/appconfbackup/original_${file_path_base64}
then
ynh_print_warn "Diff with the original file:"
diff --report-identical-files --unified --color=always /var/cache/yunohost/appconfbackup/original_${file_path_base64} $file >&2 || true
fi
fi
fi
fi
}

View file

@ -308,8 +308,8 @@ ynh_script_progression() {
local progression_bar="${progress_string2:0:$effective_progression}${progress_string1:0:$expected_progression}${progress_string0:0:$left_progression}"
local print_exec_time=""
if [ $time -eq 1 ]; then
print_exec_time=" [$(date +%Hh%Mm,%Ss --date="0 + $exec_time sec")]"
if [ $time -eq 1 ] && [ "$exec_time" -gt 10 ]; then
print_exec_time=" [$(bc <<< "scale=1; $exec_time / 60" ) minutes]"
fi
ynh_print_info "[$progression_bar] > ${message}${print_exec_time}"

View file

@ -133,7 +133,7 @@ ynh_mysql_dump_db() {
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
mysqldump --single-transaction --skip-dump-date "$database"
mysqldump --single-transaction --skip-dump-date --routines "$database"
}
# Create a user

View file

@ -42,3 +42,37 @@ ynh_remove_nginx_config() {
ynh_secure_remove --file="/etc/nginx/conf.d/$domain.d/$app.conf"
ynh_systemd_action --service_name=nginx --action=reload
}
# Move / regen the nginx config in a change url context
#
# usage: ynh_change_url_nginx_config
#
# Requires YunoHost version 11.1.9 or higher.
ynh_change_url_nginx_config() {
local old_nginx_conf_path=/etc/nginx/conf.d/$old_domain.d/$app.conf
local new_nginx_conf_path=/etc/nginx/conf.d/$new_domain.d/$app.conf
# Change the path in the NGINX config file
if [ $change_path -eq 1 ]
then
# Make a backup of the original NGINX config file if modified
ynh_backup_if_checksum_is_different --file="$old_nginx_conf_path"
# Set global variables for NGINX helper
domain="$old_domain"
path="$new_path"
path_url="$new_path"
# Create a dedicated NGINX config
ynh_add_nginx_config
fi
# Change the domain for NGINX
if [ $change_domain -eq 1 ]
then
ynh_delete_file_checksum --file="$old_nginx_conf_path"
mv "$old_nginx_conf_path" "$new_nginx_conf_path"
ynh_store_file_checksum --file="$new_nginx_conf_path"
fi
ynh_systemd_action --service_name=nginx --action=reload
}

View file

@ -1,32 +1,10 @@
#!/bin/bash
n_version=9.0.1
n_checksum=ad305e8ee9111aa5b08e6dbde23f01109401ad2d25deecacd880b3f9ea45702b
n_install_dir="/opt/node_n"
node_version_path="$n_install_dir/n/versions/node"
# N_PREFIX is the directory of n, it needs to be loaded as a environment variable.
export N_PREFIX="$n_install_dir"
# Install Node version management
#
# [internal]
#
# usage: ynh_install_n
#
# Requires YunoHost version 2.7.12 or higher.
ynh_install_n() {
# Build an app.src for n
echo "SOURCE_URL=https://github.com/tj/n/archive/v${n_version}.tar.gz
SOURCE_SUM=${n_checksum}" >"$YNH_APP_BASEDIR/conf/n.src"
# Download and extract n
ynh_setup_source --dest_dir="$n_install_dir/git" --source_id=n
# Install n
(
cd "$n_install_dir/git"
PREFIX=$N_PREFIX make install 2>&1
)
}
# Load the version of node for an app, and set variables.
#
# usage: ynh_use_nodejs
@ -133,14 +111,10 @@ ynh_install_nodejs() {
test -x /usr/bin/node && mv /usr/bin/node /usr/bin/node_n
test -x /usr/bin/npm && mv /usr/bin/npm /usr/bin/npm_n
# If n is not previously setup, install it
if ! $n_install_dir/bin/n --version >/dev/null 2>&1; then
ynh_install_n
elif dpkg --compare-versions "$($n_install_dir/bin/n --version)" lt $n_version; then
ynh_install_n
fi
# Modify the default N_PREFIX in n script
# Install (or update if YunoHost vendor/ folder updated since last install) n
mkdir -p $n_install_dir/bin/
cp /usr/share/yunohost/helpers.d/vendor/n/n $n_install_dir/bin/n
# Tweak for n to understand it's installed in $N_PREFIX
ynh_replace_string --match_string="^N_PREFIX=\${N_PREFIX-.*}$" --replace_string="N_PREFIX=\${N_PREFIX-$N_PREFIX}" --target_file="$n_install_dir/bin/n"
# Restore /usr/local/bin in PATH

View file

@ -57,6 +57,7 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
#
# Requires YunoHost version 4.1.0 or higher.
ynh_add_fpm_config() {
local _globalphpversion=${phpversion-:}
# Declare an array to define the options of this helper.
local legacy_args=vtufpd
local -A args_array=([v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service)
@ -81,11 +82,16 @@ ynh_add_fpm_config() {
dedicated_service=${dedicated_service:-0}
# Set the default PHP-FPM version by default
phpversion="${phpversion:-$YNH_PHP_VERSION}"
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
phpversion="${phpversion:-$YNH_PHP_VERSION}"
else
phpversion="${phpversion:-$_globalphpversion}"
fi
local old_phpversion=$(ynh_app_setting_get --app=$app --key=phpversion)
# If the PHP version changed, remove the old fpm conf
# (NB: This stuff is also handled by the apt helper, which is usually triggered before this helper)
if [ -n "$old_phpversion" ] && [ "$old_phpversion" != "$phpversion" ]; then
local old_php_fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
local old_php_finalphpconf="$old_php_fpm_config_dir/pool.d/$app.conf"
@ -100,6 +106,7 @@ ynh_add_fpm_config() {
# Legacy args (packager should just list their php dependency as regular apt dependencies...
if [ -n "$package" ]; then
# Install the additionnal packages from the default repository
ynh_print_warn --message "Argument --package of ynh_add_fpm_config is deprecated and to be removed in the future"
ynh_install_app_dependencies "$package"
fi
@ -156,7 +163,7 @@ ynh_add_fpm_config() {
user = __APP__
group = __APP__
chdir = __FINALPATH__
chdir = __INSTALL_DIR__
listen = /var/run/php/php__PHPVERSION__-fpm-__APP__.sock
listen.owner = www-data
@ -283,7 +290,7 @@ ynh_remove_fpm_config() {
# If the PHP version used is not the default version for YunoHost
# The second part with YNH_APP_PURGE is an ugly hack to guess that we're inside the remove script
# (we don't actually care about its value, we just check its not empty hence it exists)
if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] && [ -n "${YNH_APP_PURGE:-}" ]; then
if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] && [ -n "${YNH_APP_PURGE:-}" ] && dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
# Remove app dependencies ... but ideally should happen via an explicit call from packager
ynh_remove_app_dependencies
fi
@ -481,6 +488,7 @@ YNH_COMPOSER_VERSION=${YNH_COMPOSER_VERSION:-$YNH_DEFAULT_COMPOSER_VERSION}
#
# Requires YunoHost version 4.2 or higher.
ynh_composer_exec() {
local _globalphpversion=${phpversion-:}
# Declare an array to define the options of this helper.
local legacy_args=vwc
declare -Ar args_array=([v]=phpversion= [w]=workdir= [c]=commands=)
@ -490,7 +498,12 @@ ynh_composer_exec() {
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
workdir="${workdir:-${install_dir:-$final_path}}"
phpversion="${phpversion:-$YNH_PHP_VERSION}"
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
phpversion="${phpversion:-$YNH_PHP_VERSION}"
else
phpversion="${phpversion:-$_globalphpversion}"
fi
COMPOSER_HOME="$workdir/.composer" COMPOSER_MEMORY_LIMIT=-1 \
php${phpversion} "$workdir/composer.phar" $commands \
@ -499,14 +512,15 @@ ynh_composer_exec() {
# Install and initialize Composer in the given directory
#
# usage: ynh_install_composer [--phpversion=phpversion] [--workdir=$final_path] [--install_args="--optimize-autoloader"] [--composerversion=composerversion]
# usage: ynh_install_composer [--phpversion=phpversion] [--workdir=$install_dir] [--install_args="--optimize-autoloader"] [--composerversion=composerversion]
# | arg: -v, --phpversion - PHP version to use with composer
# | arg: -w, --workdir - The directory from where the command will be executed. Default $final_path.
# | arg: -w, --workdir - The directory from where the command will be executed. Default $install_dir.
# | arg: -a, --install_args - Additional arguments provided to the composer install. Argument --no-dev already include
# | arg: -c, --composerversion - Composer version to install
#
# Requires YunoHost version 4.2 or higher.
ynh_install_composer() {
local _globalphpversion=${phpversion-:}
# Declare an array to define the options of this helper.
local legacy_args=vwac
declare -Ar args_array=([v]=phpversion= [w]=workdir= [a]=install_args= [c]=composerversion=)
@ -516,8 +530,18 @@ ynh_install_composer() {
local composerversion
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
workdir="${workdir:-$final_path}"
phpversion="${phpversion:-$YNH_PHP_VERSION}"
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
workdir="${workdir:-$final_path}"
else
workdir="${workdir:-$install_dir}"
fi
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
phpversion="${phpversion:-$YNH_PHP_VERSION}"
else
phpversion="${phpversion:-$_globalphpversion}"
fi
install_args="${install_args:-}"
composerversion="${composerversion:-$YNH_COMPOSER_VERSION}"

View file

@ -48,7 +48,7 @@ ynh_replace_string() {
ynh_handle_getopts_args "$@"
set +o xtrace # set +x
local delimit=@
local delimit=$'\001'
# Escape the delimiter if it's in the string.
match_string=${match_string//${delimit}/"\\${delimit}"}
replace_string=${replace_string//${delimit}/"\\${delimit}"}

View file

@ -61,7 +61,7 @@ ynh_remove_systemd_config() {
# | arg: -l, --line_match= - Line to match - The line to find in the log to attest the service have finished to boot. If not defined it don't wait until the service is completely started.
# | arg: -p, --log_path= - Log file - Path to the log file. Default : `/var/log/$app/$app.log`
# | arg: -t, --timeout= - Timeout - The maximum time to wait before ending the watching. Default : 300 seconds.
# | arg: -e, --length= - Length of the error log : Default : 20
# | arg: -e, --length= - Length of the error log displayed for debugging : Default : 20
#
# Requires YunoHost version 3.5.0 or higher.
ynh_systemd_action() {
@ -110,6 +110,8 @@ ynh_systemd_action() {
action="reload-or-restart"
fi
local time_start="$(date --utc --rfc-3339=seconds | cut -d+ -f1) UTC"
# If the service fails to perform the action
if ! systemctl $action $service_name; then
# Show syslog for this service
@ -128,9 +130,17 @@ ynh_systemd_action() {
local i=0
for i in $(seq 1 $timeout); do
# Read the log until the sentence is found, that means the app finished to start. Or run until the timeout
if grep --extended-regexp --quiet "$line_match" "$templog"; then
ynh_print_info --message="The service $service_name has correctly executed the action ${action}."
break
if [ "$log_path" == "systemd" ]; then
# For systemd services, we in fact dont rely on the templog, which for some reason is not reliable, but instead re-read journalctl every iteration, starting at the timestamp where we triggered the action
if journalctl --unit=$service_name --since="$time_start" --quiet --no-pager --no-hostname | grep --extended-regexp --quiet "$line_match"; then
ynh_print_info --message="The service $service_name has correctly executed the action ${action}."
break
fi
else
if grep --extended-regexp --quiet "$line_match" "$templog"; then
ynh_print_info --message="The service $service_name has correctly executed the action ${action}."
break
fi
fi
if [ $i -eq 30 ]; then
echo "(this may take some time)" >&2

View file

@ -22,7 +22,10 @@ YNH_APP_BASEDIR=${YNH_APP_BASEDIR:-$(realpath ..)}
ynh_exit_properly() {
local exit_code=$?
rm -rf "/var/cache/yunohost/download/"
if [[ "${YNH_APP_ACTION:-}" =~ ^install$|^upgrade$|^restore$ ]]
then
rm -rf "/var/cache/yunohost/download/"
fi
if [ "$exit_code" -eq 0 ]; then
exit 0 # Exit without error if the script ended correctly
@ -71,39 +74,79 @@ fi
#
# usage: ynh_setup_source --dest_dir=dest_dir [--source_id=source_id] [--keep="file1 file2"] [--full_replace]
# | arg: -d, --dest_dir= - Directory where to setup sources
# | arg: -s, --source_id= - Name of the source, defaults to `app`
# | arg: -s, --source_id= - Name of the source, defaults to `main` (when the sources resource exists in manifest.toml) or (legacy) `app` otherwise
# | arg: -k, --keep= - Space-separated list of files/folders that will be backup/restored in $dest_dir, such as a config file you don't want to overwrite. For example 'conf.json secrets.json logs/'
# | arg: -r, --full_replace= - Remove previous sources before installing new sources
#
# #### New 'sources' resources
#
# (See also the resources documentation which may be more complete?)
#
# This helper will read infos from the 'sources' resources in the manifest.toml of the app
# and expect a structure like:
#
# ```toml
# [resources.sources]
# [resources.sources.main]
# url = "https://some.address.to/download/the/app/archive"
# sha256 = "0123456789abcdef" # The sha256 sum of the asset obtained from the URL
# ```
#
# ##### Optional flags
#
# ```text
# format = "tar.gz"/xz/bz2 # automatically guessed from the extension of the URL, but can be set explicitly. Will use `tar` to extract
# "zip" # automatically guessed from the extension of the URL, but can be set explicitly. Will use `unzip` to extract
# "docker" # useful to extract files from an already-built docker image (instead of rebuilding them locally). Will use `docker-image-extract` to extract
# "whatever" # an arbitrary value, not really meaningful except to imply that the file won't be extracted
#
# in_subdir = true # default, there's an intermediate subdir in the archive before accessing the actual files
# false # sources are directly in the archive root
# n # (special cases) an integer representing a number of subdirs levels to get rid of
#
# extract = true # default if file is indeed an archive such as .zip, .tar.gz, .tar.bz2, ...
# = false # default if file 'format' is not set and the file is not to be extracted because it is not an archive but a script or binary or whatever asset.
# # in which case the file will only be `mv`ed to the location possibly renamed using the `rename` value
#
# rename = "whatever_your_want" # to be used for convenience when `extract` is false and the default name of the file is not practical
# platform = "linux/amd64" # (defaults to "linux/$YNH_ARCH") to be used in conjonction with `format = "docker"` to specify which architecture to extract for
# ```
#
# You may also define assets url and checksum per-architectures such as:
# ```toml
# [resources.sources]
# [resources.sources.main]
# amd64.url = "https://some.address.to/download/the/app/archive/when/amd64"
# amd64.sha256 = "0123456789abcdef"
# armhf.url = "https://some.address.to/download/the/app/archive/when/armhf"
# armhf.sha256 = "fedcba9876543210"
# ```
#
# In which case ynh_setup_source --dest_dir="$install_dir" will automatically pick the appropriate source depending on the arch
#
#
#
# #### Legacy format '.src'
#
# This helper will read `conf/${source_id}.src`, download and install the sources.
#
# The src file need to contains:
# ```
# SOURCE_URL=Address to download the app archive
# SOURCE_SUM=Control sum
# # (Optional) Program to check the integrity (sha256sum, md5sum...). Default: sha256
# SOURCE_SUM_PRG=sha256
# # (Optional) Archive format. Default: tar.gz
# SOURCE_SUM=Sha256 sum
# SOURCE_FORMAT=tar.gz
# # (Optional) Put false if sources are directly in the archive root. Default: true
# # Instead of true, SOURCE_IN_SUBDIR could be the number of sub directories to remove.
# SOURCE_IN_SUBDIR=false
# # (Optionnal) Name of the local archive (offline setup support). Default: ${src_id}.${src_format}
# SOURCE_FILENAME=example.tar.gz
# # (Optional) If it set as false don't extract the source. Default: true
# # (Useful to get a debian package or a python wheel.)
# SOURCE_EXTRACT=(true|false)
# # (Optionnal) Name of the plateform. Default: "linux/$YNH_ARCH"
# SOURCE_PLATFORM=linux/arm64/v8
# ```
#
# The helper will:
# - Check if there is a local source archive in `/opt/yunohost-apps-src/$APP_ID/$SOURCE_FILENAME`
# - Download `$SOURCE_URL` if there is no local archive
# - Check the integrity with `$SOURCE_SUM_PRG -c --status`
# - Download the specific URL if there is no local archive
# - Check the integrity with the specific sha256 sum
# - Uncompress the archive to `$dest_dir`.
# - If `$SOURCE_IN_SUBDIR` is true, the first level directory of the archive will be removed.
# - If `$SOURCE_IN_SUBDIR` is a numeric value, the N first level directories will be removed.
# - If `in_subdir` is true, the first level directory of the archive will be removed.
# - If `in_subdir` is a numeric value, the N first level directories will be removed.
# - Patches named `sources/patches/${src_id}-*.patch` will be applied to `$dest_dir`
# - Extra files in `sources/extra_files/$src_id` will be copied to dest_dir
#
@ -118,22 +161,66 @@ ynh_setup_source() {
local full_replace
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
source_id="${source_id:-app}"
keep="${keep:-}"
full_replace="${full_replace:-0}"
local src_file_path="$YNH_APP_BASEDIR/conf/${source_id}.src"
if test -e $YNH_APP_BASEDIR/manifest.toml && cat $YNH_APP_BASEDIR/manifest.toml | toml_to_json | jq -e '.resources.sources' >/dev/null
then
source_id="${source_id:-main}"
local sources_json=$(cat $YNH_APP_BASEDIR/manifest.toml | toml_to_json | jq ".resources.sources[\"$source_id\"]")
if jq -re ".url" <<< "$sources_json"
then
local arch_prefix=""
else
local arch_prefix=".$YNH_ARCH"
fi
# Load value from configuration file (see above for a small doc about this file
# format)
local src_url=$(grep 'SOURCE_URL=' "$src_file_path" | cut --delimiter='=' --fields=2-)
local src_sum=$(grep 'SOURCE_SUM=' "$src_file_path" | cut --delimiter='=' --fields=2-)
local src_sumprg=$(grep 'SOURCE_SUM_PRG=' "$src_file_path" | cut --delimiter='=' --fields=2-)
local src_format=$(grep 'SOURCE_FORMAT=' "$src_file_path" | cut --delimiter='=' --fields=2-)
local src_in_subdir=$(grep 'SOURCE_IN_SUBDIR=' "$src_file_path" | cut --delimiter='=' --fields=2-)
local src_filename=$(grep 'SOURCE_FILENAME=' "$src_file_path" | cut --delimiter='=' --fields=2-)
local src_extract=$(grep 'SOURCE_EXTRACT=' "$src_file_path" | cut --delimiter='=' --fields=2-)
local src_plateform=$(grep 'SOURCE_PLATFORM=' "$src_file_path" | cut --delimiter='=' --fields=2-)
local src_url="$(jq -r "$arch_prefix.url" <<< "$sources_json" | sed 's/^null$//')"
local src_sum="$(jq -r "$arch_prefix.sha256" <<< "$sources_json" | sed 's/^null$//')"
local src_sumprg="sha256sum"
local src_format="$(jq -r ".format" <<< "$sources_json" | sed 's/^null$//')"
local src_in_subdir="$(jq -r ".in_subdir" <<< "$sources_json" | sed 's/^null$//')"
local src_extract="$(jq -r ".extract" <<< "$sources_json" | sed 's/^null$//')"
local src_platform="$(jq -r ".platform" <<< "$sources_json" | sed 's/^null$//')"
local src_rename="$(jq -r ".rename" <<< "$sources_json" | sed 's/^null$//')"
[[ -n "$src_url" ]] || ynh_die "No URL defined for source $source_id$arch_prefix ?"
[[ -n "$src_sum" ]] || ynh_die "No sha256 sum defined for source $source_id$arch_prefix ?"
if [[ -z "$src_format" ]]
then
if [[ "$src_url" =~ ^.*\.zip$ ]] || [[ "$src_url" =~ ^.*/zipball/.*$ ]]
then
src_format="zip"
elif [[ "$src_url" =~ ^.*\.tar\.gz$ ]] || [[ "$src_url" =~ ^.*\.tgz$ ]] || [[ "$src_url" =~ ^.*/tar\.gz/.*$ ]] || [[ "$src_url" =~ ^.*/tarball/.*$ ]]
then
src_format="tar.gz"
elif [[ "$src_url" =~ ^.*\.tar\.xz$ ]]
then
src_format="tar.xz"
elif [[ "$src_url" =~ ^.*\.tar\.bz2$ ]]
then
src_format="tar.bz2"
elif [[ -z "$src_extract" ]]
then
src_extract="false"
fi
fi
else
source_id="${source_id:-app}"
local src_file_path="$YNH_APP_BASEDIR/conf/${source_id}.src"
# Load value from configuration file (see above for a small doc about this file
# format)
local src_url=$(grep 'SOURCE_URL=' "$src_file_path" | cut --delimiter='=' --fields=2-)
local src_sum=$(grep 'SOURCE_SUM=' "$src_file_path" | cut --delimiter='=' --fields=2-)
local src_sumprg=$(grep 'SOURCE_SUM_PRG=' "$src_file_path" | cut --delimiter='=' --fields=2-)
local src_format=$(grep 'SOURCE_FORMAT=' "$src_file_path" | cut --delimiter='=' --fields=2-)
local src_in_subdir=$(grep 'SOURCE_IN_SUBDIR=' "$src_file_path" | cut --delimiter='=' --fields=2-)
local src_rename=$(grep 'SOURCE_FILENAME=' "$src_file_path" | cut --delimiter='=' --fields=2-)
local src_extract=$(grep 'SOURCE_EXTRACT=' "$src_file_path" | cut --delimiter='=' --fields=2-)
local src_platform=$(grep 'SOURCE_PLATFORM=' "$src_file_path" | cut --delimiter='=' --fields=2-)
fi
# Default value
src_sumprg=${src_sumprg:-sha256sum}
@ -141,33 +228,53 @@ ynh_setup_source() {
src_format=${src_format:-tar.gz}
src_format=$(echo "$src_format" | tr '[:upper:]' '[:lower:]')
src_extract=${src_extract:-true}
if [ "$src_filename" = "" ]; then
src_filename="${source_id}.${src_format}"
if [[ "$src_extract" != "true" ]] && [[ "$src_extract" != "false" ]]
then
ynh_die "For source $source_id, expected either 'true' or 'false' for the extract parameter"
fi
# (Unused?) mecanism where one can have the file in a special local cache to not have to download it...
local local_src="/opt/yunohost-apps-src/${YNH_APP_ID}/${src_filename}"
mkdir -p /var/cache/yunohost/download/${YNH_APP_ID}/
src_filename="/var/cache/yunohost/download/${YNH_APP_ID}/${src_filename}"
# (Unused?) mecanism where one can have the file in a special local cache to not have to download it...
local local_src="/opt/yunohost-apps-src/${YNH_APP_ID}/${source_id}"
# Gotta use this trick with 'dirname' because source_id may contain slashes x_x
mkdir -p $(dirname /var/cache/yunohost/download/${YNH_APP_INSTANCE_NAME}/${source_id})
src_filename="/var/cache/yunohost/download/${YNH_APP_INSTANCE_NAME}/${source_id}"
if [ "$src_format" = "docker" ]; then
src_plateform="${src_plateform:-"linux/$YNH_ARCH"}"
src_platform="${src_platform:-"linux/$YNH_ARCH"}"
elif test -e "$local_src"; then
cp $local_src $src_filename
else
[ -n "$src_url" ] || ynh_die "Couldn't parse SOURCE_URL from $src_file_path ?"
# NB. we have to declare the var as local first,
# otherwise 'local foo=$(false) || echo 'pwet'" does'nt work
# because local always return 0 ...
local out
# Timeout option is here to enforce the timeout on dns query and tcp connect (c.f. man wget)
out=$(wget --tries 3 --no-dns-cache --timeout 900 --no-verbose --output-document=$src_filename $src_url 2>&1) \
|| ynh_die --message="$out"
# If the file was prefetched but somehow doesn't match the sum, rm and redownload it
if [ -e "$src_filename" ] && ! echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status
then
rm -f "$src_filename"
fi
# Only redownload the file if it wasnt prefetched
if [ ! -e "$src_filename" ]
then
# NB. we have to declare the var as local first,
# otherwise 'local foo=$(false) || echo 'pwet'" does'nt work
# because local always return 0 ...
local out
# Timeout option is here to enforce the timeout on dns query and tcp connect (c.f. man wget)
out=$(wget --tries 3 --no-dns-cache --timeout 900 --no-verbose --output-document=$src_filename $src_url 2>&1) \
|| ynh_die --message="$out"
fi
# Check the control sum
echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status \
|| ynh_die --message="Corrupt source"
if ! echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status
then
local actual_sum="$(${src_sumprg} ${src_filename} | cut --delimiter=' ' --fields=1)"
local actual_size="$(du -hs ${src_filename} | cut --delimiter=' ' --fields=1)"
rm -f ${src_filename}
ynh_die --message="Corrupt source for ${src_filename}: Expected ${src_sum} but got ${actual_sum} (size: ${actual_size})."
fi
fi
# Keep files to be backup/restored at the end of the helper
@ -199,11 +306,16 @@ ynh_setup_source() {
_ynh_apply_default_permissions $dest_dir
fi
if ! "$src_extract"; then
mv $src_filename $dest_dir
elif [ "$src_format" = "docker" ]; then
/usr/share/yunohost/helpers.d/vendor/docker-image-extract/docker-image-extract -p $src_plateform -o $dest_dir $src_url 2>&1
elif [ "$src_format" = "zip" ]; then
if [[ "$src_extract" == "false" ]]; then
if [[ -z "$src_rename" ]]
then
mv $src_filename $dest_dir
else
mv $src_filename $dest_dir/$src_rename
fi
elif [[ "$src_format" == "docker" ]]; then
/usr/share/yunohost/helpers.d/vendor/docker-image-extract/docker-image-extract -p $src_platform -o $dest_dir $src_url 2>&1
elif [[ "$src_format" == "zip" ]]; then
# Zip format
# Using of a temp directory, because unzip doesn't manage --strip-components
if $src_in_subdir; then
@ -348,7 +460,7 @@ ynh_local_curl() {
# __NAMETOCHANGE__ by $app
# __USER__ by $app
# __FINALPATH__ by $final_path
# __PHPVERSION__ by $YNH_PHP_VERSION
# __PHPVERSION__ by $YNH_PHP_VERSION (packaging v1 only, packaging v2 uses phpversion setting implicitly set by apt resource)
# __YNH_NODE_LOAD_PATH__ by $ynh_node_load_PATH
# ```
# And any dynamic variables that should be defined before calling this helper like:
@ -417,7 +529,7 @@ ynh_add_config() {
# __NAMETOCHANGE__ by $app
# __USER__ by $app
# __FINALPATH__ by $final_path
# __PHPVERSION__ by $YNH_PHP_VERSION
# __PHPVERSION__ by $YNH_PHP_VERSION (packaging v1 only, packaging v2 uses phpversion setting implicitly set by apt resource)
# __YNH_NODE_LOAD_PATH__ by $ynh_node_load_PATH
#
# And any dynamic variables that should be defined before calling this helper like:
@ -452,7 +564,8 @@ ynh_replace_vars() {
ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$file"
ynh_replace_string --match_string="__INSTALL_DIR__" --replace_string="$final_path" --target_file="$file"
fi
if test -n "${YNH_PHP_VERSION:-}"; then
# Legacy / Packaging v1 only
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2 && test -n "${YNH_PHP_VERSION:-}"; then
ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$YNH_PHP_VERSION" --target_file="$file"
fi
if test -n "${ynh_node_load_PATH:-}"; then
@ -567,7 +680,7 @@ ynh_read_var_in_file() {
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)"
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
@ -613,15 +726,14 @@ ynh_write_var_in_file() {
set +o xtrace # set +x
# Get the line number after which we search for the variable
local line_number=1
local after_line_number=1
if [[ -n "$after" ]]; then
line_number=$(grep -m1 -n $after $file | cut -d: -f1)
if [[ -z "$line_number" ]]; then
after_line_number=$(grep -m1 -n $after $file | cut -d: -f1)
if [[ -z "$after_line_number" ]]; then
set -o xtrace # set -x
return 1
fi
fi
local range="${line_number},\$ "
local filename="$(basename -- "$file")"
local ext="${filename##*.}"
@ -646,17 +758,21 @@ ynh_write_var_in_file() {
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)"
local expression_with_comment="$((tail +$after_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
local value_line_number="$(tail +$after_line_number ${file} | grep -m1 -n -i -P $var_part'\K.*$' | cut -d: -f1)"
value_line_number=$((after_line_number + value_line_number))
local range="${after_line_number},${value_line_number} "
# 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')"
value=${value//&/"\&"}
local first_char="${expression:0:1}"
delimiter=$'\001'
if [[ "$first_char" == '"' ]]; then
@ -718,7 +834,7 @@ _acceptable_path_to_delete() {
local forbidden_paths=$(ls -d / /* /{var,home,usr}/* /etc/{default,sudoers.d,yunohost,cron*})
# Legacy : A couple apps still have data in /home/$app ...
if [[ -n "$app" ]]
if [[ -n "${app:-}" ]]
then
forbidden_paths=$(echo "$forbidden_paths" | grep -v "/home/$app")
fi
@ -966,3 +1082,7 @@ _ynh_apply_default_permissions() {
int_to_bool() {
sed -e 's/^1$/True/g' -e 's/^0$/False/g'
}
toml_to_json() {
python3 -c 'import toml, json, sys; print(json.dumps(toml.load(sys.stdin)))'
}

21
helpers/vendor/n/LICENSE vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 TJ Holowaychuk
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

1
helpers/vendor/n/README.md vendored Normal file
View file

@ -0,0 +1 @@
This is taken from https://github.com/tj/n/

1621
helpers/vendor/n/n vendored Executable file

File diff suppressed because it is too large Load diff

View file

@ -9,7 +9,7 @@ source /usr/share/yunohost/helpers
# Backup destination
backup_dir="${1}/data/multimedia"
if [ -e "/home/yunohost.multimedia/.nobackup" ]; then
if [ ! -e "/home/yunohost.multimedia" ] || [ -e "/home/yunohost.multimedia/.nobackup" ]; then
exit 0
fi

View file

@ -125,12 +125,15 @@ EOF
fi
# Skip ntp if inside a container (inspired from the conf of systemd-timesyncd)
mkdir -p ${pending_dir}/etc/systemd/system/ntp.service.d/
cat >${pending_dir}/etc/systemd/system/ntp.service.d/ynh-override.conf <<EOF
if systemctl | grep -q 'ntp.service'
then
mkdir -p ${pending_dir}/etc/systemd/system/ntp.service.d/
cat >${pending_dir}/etc/systemd/system/ntp.service.d/ynh-override.conf <<EOF
[Unit]
ConditionCapability=CAP_SYS_TIME
ConditionVirtualization=!container
EOF
fi
# Make nftable conflict with yunohost-firewall
mkdir -p ${pending_dir}/etc/systemd/system/nftables.service.d/
@ -215,10 +218,13 @@ do_post_regen() {
grep -q '^sftp.app:' /etc/group || groupadd sftp.app
# Propagates changes in systemd service config overrides
[[ ! "$regen_conf_files" =~ "ntp.service.d/ynh-override.conf" ]] || {
systemctl daemon-reload
systemctl restart ntp
}
if systemctl | grep -q 'ntp.service'
then
[[ ! "$regen_conf_files" =~ "ntp.service.d/ynh-override.conf" ]] || {
systemctl daemon-reload
systemctl restart ntp
}
fi
[[ ! "$regen_conf_files" =~ "nftables.service.d/ynh-override.conf" ]] || systemctl daemon-reload
[[ ! "$regen_conf_files" =~ "login.conf.d/ynh-override.conf" ]] || {
systemctl daemon-reload
@ -245,6 +251,11 @@ do_post_regen() {
rm -f /etc/dpkg/origins/default
ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
fi
if test -e /etc/yunohost/installed && test -e /etc/profile.d/check_yunohost_is_installed.sh
then
rm /etc/profile.d/check_yunohost_is_installed.sh
fi
}
do_$1_regen ${@:2}

View file

@ -2,6 +2,8 @@
set -e
readonly YNH_DEFAULT_PHP_VERSION=7.4
do_pre_regen() {
pending_dir=$1
@ -68,7 +70,10 @@ do_post_regen() {
fi
# Make sure php7.4 is the default version when using php in cli
update-alternatives --set php /usr/bin/php7.4
if test -e /usr/bin/php$YNH_DEFAULT_PHP_VERSION
then
update-alternatives --set php /usr/bin/php$YNH_DEFAULT_PHP_VERSION
fi
}
do_$1_regen ${@:2}

View file

@ -74,8 +74,22 @@ do_post_regen() {
chown -R metronome: /var/lib/metronome/
chown -R metronome: /etc/metronome/conf.d/
[[ -z "$regen_conf_files" ]] \
|| systemctl restart metronome
if [[ -z "$(ls /etc/metronome/conf.d/*.cfg.lua 2>/dev/null)" ]]
then
if systemctl is-enabled metronome &>/dev/null
then
systemctl disable metronome --now 2>/dev/null
fi
else
if ! systemctl is-enabled metronome &>/dev/null
then
systemctl enable metronome --now 2>/dev/null
sleep 3
fi
[[ -z "$regen_conf_files" ]] \
|| systemctl restart metronome
fi
}
do_$1_regen ${@:2}

View file

@ -16,7 +16,7 @@ do_pre_regen() {
cp dovecot-ldap.conf "${dovecot_dir}/dovecot-ldap.conf"
cp dovecot.sieve "${dovecot_dir}/global_script/dovecot.sieve"
export pop3_enabled="$(yunohost settings get 'email.pop3.pop3_enabled')"
export pop3_enabled="$(yunohost settings get 'email.pop3.pop3_enabled' | int_to_bool)"
export main_domain=$(cat /etc/yunohost/current_host)
export domain_list="$(yunohost domain list --features mail_in mail_out --output-as json | jq -r ".domains[]" | tr '\n' ' ')"

View file

@ -20,7 +20,7 @@ do_pre_regen() {
}
do_post_regen() {
regen_conf_files=$1
#regen_conf_files=$1
# Make sure postgresql is started and enabled
# (N.B. : to check the active state, we check the cluster state because
@ -34,6 +34,8 @@ do_post_regen() {
if [ ! -f "$PSQL_ROOT_PWD_FILE" ] || [ -z "$(cat $PSQL_ROOT_PWD_FILE)" ]; then
ynh_string_random >$PSQL_ROOT_PWD_FILE
fi
[ ! -e $PSQL_ROOT_PWD_FILE ] || { chown root:postgres $PSQL_ROOT_PWD_FILE; chmod 440 $PSQL_ROOT_PWD_FILE; }
sudo --login --user=postgres psql -c"ALTER user postgres WITH PASSWORD '$(cat $PSQL_ROOT_PWD_FILE)'" postgres
@ -47,20 +49,4 @@ do_post_regen() {
ynh_systemd_action --service_name=postgresql --action=reload
}
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}

View file

@ -5,16 +5,16 @@
"app_already_up_to_date": "{app} حديثٌ",
"app_argument_required": "المُعامِل '{name}' مطلوب",
"app_extraction_failed": "تعذر فك الضغط عن ملفات التنصيب",
"app_install_files_invalid": "ملفات التنصيب خاطئة",
"app_install_files_invalid": "لا يمكن تنصيب هذه الملفات",
"app_not_correctly_installed": "يبدو أن التطبيق {app} لم يتم تنصيبه بشكل صحيح",
"app_not_installed": "إنّ التطبيق {app} غير مُنصَّب",
"app_not_properly_removed": "لم يتم حذف تطبيق {app} بشكلٍ جيّد",
"app_removed": "تمت إزالة تطبيق {app}",
"app_requirements_checking": "جار فحص الحزم اللازمة لـ {app}…",
"app_sources_fetch_failed": "تعذرت عملية جلب مصادر الملفات",
"app_requirements_checking": "جار فحص متطلبات تطبيق {app}…",
"app_sources_fetch_failed": "تعذر جلب ملفات المصدر ، هل عنوان URL صحيح؟",
"app_unknown": "برنامج مجهول",
"app_upgrade_app_name": "جارٍ تحديث {app}…",
"app_upgrade_failed": "تعذرت عملية ترقية {app}",
"app_upgrade_failed": "تعذرت عملية تحديث {app}: {error}",
"app_upgrade_some_app_failed": "تعذرت عملية ترقية بعض التطبيقات",
"app_upgraded": "تم تحديث التطبيق {app}",
"ask_main_domain": "النطاق الرئيسي",
@ -22,7 +22,7 @@
"ask_password": "كلمة السر",
"backup_applying_method_copy": "جارٍ نسخ كافة الملفات المراد نسخها احتياطيا …",
"backup_applying_method_tar": "جارٍ إنشاء ملف TAR للنسخة الاحتياطية…",
"backup_created": "تم إنشاء النسخة الإحتياطية",
"backup_created": "تم إنشاء النسخة الإحتياطية: {name}",
"backup_method_copy_finished": "إنتهت عملية النسخ الإحتياطي",
"backup_nothings_done": "ليس هناك أي شيء للحفظ",
"backup_output_directory_required": "يتوجب عليك تحديد مجلد لتلقي النسخ الإحتياطية",
@ -30,7 +30,7 @@
"certmanager_cert_install_success_selfsigned": "نجحت عملية تثبيت الشهادة الموقعة ذاتيا الخاصة بالنطاق '{domain}'",
"certmanager_cert_renew_success": "نجحت عملية تجديد شهادة Let's Encrypt الخاصة باسم النطاق '{domain}'",
"certmanager_cert_signing_failed": "فشل إجراء توقيع الشهادة الجديدة",
"certmanager_no_cert_file": "تعذرت عملية قراءة شهادة نطاق {domain} (الملف : {file})",
"certmanager_no_cert_file": "تعذرت عملية قراءة ملف شهادة نطاق {domain} (الملف : {file})",
"domain_created": "تم إنشاء النطاق",
"domain_creation_failed": "تعذرت عملية إنشاء النطاق {domain}: {error}",
"domain_deleted": "تم حذف النطاق",
@ -39,7 +39,7 @@
"done": "تم",
"downloading": "عملية التنزيل جارية …",
"dyndns_ip_updated": "لقد تم تحديث عنوان الإيبي الخاص بك على نظام أسماء النطاقات الديناميكي",
"dyndns_key_generating": "عملية توليد مفتاح نظام أسماء النطاقات جارية. يمكن للعملية أن تستغرق بعضا من الوقت…",
"dyndns_key_generating": "جارٍ إنشاء مفتاح DNS ... قد يستغرق الأمر بعض الوقت.",
"dyndns_key_not_found": "لم يتم العثور على مفتاح DNS الخاص باسم النطاق هذا",
"extracting": "عملية فك الضغط جارية…",
"installation_complete": "إكتملت عملية التنصيب",
@ -49,15 +49,15 @@
"pattern_domain": "يتوجب أن يكون إسم نطاق صالح (مثل my-domain.org)",
"pattern_email": "يتوجب أن يكون عنوان بريد إلكتروني صالح (مثل someone@domain.org)",
"pattern_password": "يتوجب أن تكون مكونة من 3 حروف على الأقل",
"restore_extracting": "جارٍ فك الضغط عن الملفات التي نحتاجها من النسخة الاحتياطية…",
"restore_extracting": "جارٍ فك الضغط عن الملفات اللازمة من النسخة الاحتياطية…",
"server_shutdown": "سوف ينطفئ الخادوم",
"server_shutdown_confirm": "سوف ينطفئ الخادوم حالا. متأكد ؟ [{answers}]",
"server_reboot": "سيعاد تشغيل الخادوم",
"server_reboot_confirm": "سيعاد تشغيل الخادوم في الحين. هل أنت متأكد ؟ [{answers}]",
"service_add_failed": "تعذرت إضافة خدمة '{service}'",
"service_already_stopped": "إنّ خدمة '{service}' متوقفة مِن قبلُ",
"service_disabled": "لن يتم إطلاق خدمة '{service}' أثناء بداية تشغيل النظام.",
"service_enabled": "تم تنشيط خدمة '{service}'",
"service_disabled": "لن يتم إطلاق خدمة '{service}' أثناء بداية تشغيل النظام بتاتا.",
"service_enabled": "سيتم الآن بدء تشغيل الخدمة '{service}' تلقائيًا أثناء تمهيد النظام.",
"service_removed": "تمت إزالة خدمة '{service}'",
"service_started": "تم إطلاق تشغيل خدمة '{service}'",
"service_stopped": "تمّ إيقاف خدمة '{service}'",
@ -71,10 +71,10 @@
"user_deleted": "تم حذف المستخدم",
"user_deletion_failed": "لا يمكن حذف المستخدم",
"user_unknown": "المستخدم {user} مجهول",
"user_update_failed": "لا يمكن تحديث المستخدم",
"user_updated": "تم تحديث المستخدم",
"user_update_failed": "لا يمكن تحديث المستخدم {user}: {error}",
"user_updated": "تم تحديث معلومات المستخدم",
"yunohost_installing": "عملية تنصيب واي يونوهوست جارية …",
"yunohost_not_installed": "إنَّ واي يونوهوست ليس مُنَصَّب أو هو مثبت حاليا بشكل خاطئ. قم بتنفيذ الأمر 'yunohost tools postinstall'",
"yunohost_not_installed": "إنَّ واي يونوهوست ليس مُنَصَّب بشكل جيد. فضلًا قم بتنفيذ الأمر 'yunohost tools postinstall'",
"migrations_list_conflict_pending_done": "لا يمكنك استخدام --previous و --done معًا على نفس سطر الأوامر.",
"service_description_metronome": "يُدير حسابات الدردشة الفورية XMPP",
"service_description_nginx": "يقوم بتوفير النفاذ و السماح بالوصول إلى كافة مواقع الويب المستضافة على خادومك",
@ -119,7 +119,7 @@
"already_up_to_date": "كل شيء على ما يرام. ليس هناك ما يتطلّب تحديثًا.",
"service_description_slapd": "يخزّن المستخدمين والنطاقات والمعلومات المتعلقة بها",
"service_reloaded": "تم إعادة تشغيل خدمة '{service}'",
"service_restarted": "تم إعادة تشغيل خدمة '{service}'",
"service_restarted": "تم إعادة تشغيل خدمة '{service}'",
"group_unknown": "الفريق '{group}' مجهول",
"group_deletion_failed": "فشلت عملية حذف الفريق '{group}': {error}",
"group_deleted": "تم حذف الفريق '{group}'",
@ -170,7 +170,7 @@
"domain_config_cert_issuer": "الهيئة الموثِّقة",
"domain_config_cert_renew": "تجديد شهادة Let's Encrypt",
"domain_config_cert_summary": "حالة الشهادة",
"domain_config_cert_summary_ok": "حسنًا، يبدو أنّ الشهادة جيدة!",
"domain_config_cert_summary_ok": "حسنًا، يبدو أنّ الشهادة الحالية جيدة!",
"domain_config_cert_validity": "مدة الصلاحية",
"domain_config_xmpp": "المراسَلة الفورية (XMPP)",
"global_settings_setting_root_password": "كلمة السر الجديدة لـ root",
@ -193,5 +193,68 @@
"diagnosis_ports_ok": "المنفذ {port} مفتوح ومتاح الوصول إليه مِن الخارج.",
"global_settings_setting_smtp_allow_ipv6": "سماح IPv6",
"disk_space_not_sufficient_update": "ليس هناك مساحة كافية لتحديث هذا التطبيق",
"domain_cert_gen_failed": "لا يمكن إعادة توليد الشهادة"
}
"domain_cert_gen_failed": "لا يمكن إعادة توليد الشهادة",
"diagnosis_apps_issue": "تم العثور على مشكلة في تطبيق {app}",
"tools_upgrade": "تحديث حُزم النظام",
"service_description_yunomdns": "يسمح لك بالوصول إلى خادمك الخاص باستخدام 'yunohost.local' في شبكتك المحلية",
"good_practices_about_user_password": "أنت الآن على وشك تحديد كلمة مرور مستخدم جديدة. يجب أن تتكون كلمة المرور من 8 أحرف على الأقل - أخذا بعين الإعتبار أنه من الممارسات الجيدة استخدام كلمة مرور أطول (أي عبارة مرور) و / أو مجموعة متنوعة من الأحرف (الأحرف الكبيرة والصغيرة والأرقام والأحرف الخاصة).",
"root_password_changed": "تم تغيير كلمة مرور الجذر",
"root_password_desynchronized": "تم تغيير كلمة مرور المدير ، لكن لم يتمكن YunoHost من نشرها على كلمة مرور الجذر!",
"user_import_bad_line": "سطر غير صحيح {line}: {details}",
"user_import_success": "تم استيراد المستخدمين بنجاح",
"visitors": "الزوار",
"password_too_simple_3": "يجب أن تتكون كلمة المرور من 8 أحرف على الأقل وأن تحتوي على أرقام و حروف كبيرة وصغيرة وأحرف خاصة",
"password_too_simple_4": "يجب أن تتكون كلمة المرور من 12 حرفًا على الأقل وأن تحتوي على أرقام وحروف كبيرة وصغيرة وأحرف خاصة",
"service_unknown": "الخدمة '{service}' غير معروفة",
"unbackup_app": "لن يتم حفظ التطبيق '{app}'",
"unrestore_app": "لن يتم استعادة التطبيق '{app}'",
"yunohost_already_installed": "إنّ YunoHost مُنصّب مِن قَبل",
"hook_name_unknown": "إسم الإجراء '{name}' غير معروف",
"app_manifest_install_ask_admin": "اختر مستخدمًا إداريًا لهذا التطبيق",
"domain_config_cert_summary_abouttoexpire": "مدة صلاحية الشهادة الحالية على وشك الإنتهاء ومِن المفتَرض أن يتم تجديدها تلقائيا قريبا.",
"app_manifest_install_ask_path": "اختر مسار URL (بعد النطاق) حيث ينبغي تنصيب هذا التطبيق",
"app_manifest_install_ask_domain": "اختر اسم النطاق الذي ينبغي فيه تنصيب هذا التطبيق",
"app_manifest_install_ask_is_public": "هل يجب أن يكون هذا التطبيق ظاهرًا للزوار المجهولين؟",
"domain_config_default_app_help": "سيعاد توجيه الناس تلقائيا إلى هذا التطبيق عند فتح اسم النطاق هذا. وإذا لم يُحدَّد أي تطبيق، يعاد توجيه الناس إلى استمارة تسجيل الدخولفي بوابة المستخدمين.",
"domain_config_xmpp_help": "ملاحطة: بعض ميزات الـ(إكس إم بي بي) ستتطلب أن تُحدّث سجلاتك الخاصة لـ DNS وتُعيد توليد شهادة Lets Encrypt لتفعيلها",
"certmanager_cert_install_failed": "أخفقت عملية تنصيب شهادة Let's Encrypt على {domains}",
"app_manifest_install_ask_password": "اختيار كلمة إدارية لهذا التطبيق",
"app_id_invalid": "مُعرّف التطبيق غير صالح",
"ask_admin_fullname": "الإسم الكامل للمدير",
"admins": "المدراء",
"all_users": "كافة مستخدمي واي يونوهوست",
"ask_user_domain": "اسم النطاق الذي سيُستخدَم لعنوان بريد المستخدِم وكذا لحساب XMPP",
"app_change_url_success": "تم تعديل الرابط التشعبي لتطبيق {app} إلى {domain}{path}",
"backup_app_failed": "لا يُمكن حِفظ {app}",
"pattern_password_app": "آسف، كلمات السر لا يمكن أن تحتوي على الحروف التالية: {forbidden_chars}",
"diagnosis_http_could_not_diagnose_details": "خطأ: {error}",
"mail_unavailable": "عنوان البريد الإلكتروني هذا مخصص لفريق المدراء",
"mailbox_disabled": "صندوق البريد معطل للمستخدم {user}",
"migration_0021_cleaning_up": "تنظيف ذاكرة التخزين المؤقت وكذا الحُزم التي تَعُد مفيدة…",
"migration_0021_yunohost_upgrade": "بداية تحديث نواة YunoHost…",
"migration_ldap_migration_failed_trying_to_rollback": "فشِلَت الهجرة… محاولة استعادة الرجوع إلى النظام.",
"migration_ldap_rollback_success": "تمت العودة إلى حالة النظام الأصلي.",
"migrations_success_forward": "اكتملت الهجرة {id}",
"password_too_simple_2": "يجب أن يكون طول كلمة المرور 8 حروف على الأقل وأن تحتوي على أرقام وحروف علوية ودنيا",
"pattern_lastname": "يجب أن يكون لقبًا صالحًا (على الأقل 3 حروف)",
"migration_0021_start": "بداية الهجرة إلى Bullseye",
"migrations_running_forward": "جارٍ تنفيذ الهجرة {id}…",
"password_confirmation_not_the_same": "كلمة المرور وتأكيدها غير متطابقان",
"password_too_long": "فضلا قم باختيار كلمة مرور طولها أقل مِن 127 حرفًا",
"pattern_fullname": "يجب أن يكون اسماً كاملاً صالحاً (على الأقل 3 حروف)",
"migration_0021_main_upgrade": "بداية التحديث الرئيسي…",
"migration_0021_patching_sources_list": "تحديث ملف sources.lists…",
"pattern_firstname": "يجب أن يكون اسماً أولياً صالحاً (على الأقل 3 حروف)",
"yunohost_configured": "تم إعداد YunoHost الآن",
"global_settings_setting_backup_compress_tar_archives": "ضغط النُسخ الاحتياطية",
"diagnosis_description_apps": "التطبيقات",
"danger": "خطر:",
"diagnosis_basesystem_hardware": "بنية الخادم هي {virt} {arch}",
"diagnosis_basesystem_hardware_model": "طراز الخادم {model}",
"diagnosis_mail_queue_ok": "هناك {nb_pending} رسائل بريد إلكتروني معلقة في قوائم انتظار البريد",
"diagnosis_mail_ehlo_ok": "يمكن الوصول إلى خادم بريد SMTP من الخارج وبالتالي فهو قادر على استقبال رسائل البريد الإلكتروني!",
"diagnosis_dns_good_conf": "تم إعداد سجلات نظام أسماء النطاقات DNS بشكل صحيح للنطاق {domain} (category {category})",
"diagnosis_ip_dnsresolution_working": "تحليل اسم النطاق يعمل!",
"diagnosis_mail_blacklist_listed_by": "إن عنوان الـ IP الخاص بك أو نطاقك <code>{item}</code> مُدرَج ضمن قائمة سوداء على {blacklist_name}",
"diagnosis_mail_outgoing_port_25_ok": "خادم بريد SMTP قادر على إرسال رسائل البريد الإلكتروني (منفذ البريد الصادر 25 غير محظور)."
}

View file

@ -165,7 +165,6 @@
"log_available_on_yunopaste": "Aquest registre està disponible via {url}",
"log_backup_restore_system": "Restaura el sistema a partir d'una còpia de seguretat",
"log_backup_restore_app": "Restaura « {} » a partir d'una còpia de seguretat",
"log_remove_on_failed_restore": "Elimina « {} » després de que la restauració a partir de la còpia de seguretat hagi fallat",
"log_remove_on_failed_install": "Elimina « {} » després de que la instal·lació hagi fallat",
"log_domain_add": "Afegir el domini « {} » a la configuració del sistema",
"log_domain_remove": "Elimina el domini « {} » de la configuració del sistema",

View file

@ -417,7 +417,6 @@
"domain_cannot_remove_main_add_new_one": "Sie können '{domain}' nicht entfernen, da es die Hauptdomäne und Ihre einzige Domäne ist. Sie müssen zuerst eine andere Domäne mit 'yunohost domain add <domäne.com>' hinzufügen, dann als Hauptdomäne mit 'yunohost domain main-domain -n <domäne.com>' festlegen und dann können Sie die Domäne '{domain}' mit 'yunohost domain remove {domain}' entfernen'.'",
"diagnosis_rootfstotalspace_critical": "Das Root-Filesystem hat noch freien Speicher von {space}. Das ist besorngiserregend! Der Speicher wird schnell aufgebraucht sein. 16 GB für das Root-Filesystem werden empfohlen.",
"diagnosis_rootfstotalspace_warning": "Das Root-Filesystem hat noch freien Speicher von {space}. Möglich, dass das in Ordnung ist. Vielleicht ist er aber auch schneller aufgebraucht. 16 GB für das Root-Filesystem werden empfohlen.",
"log_remove_on_failed_restore": "Entfernen von '{}' nach einer fehlgeschlagenen Wiederherstellung aus einem Sicherungsarchiv",
"log_backup_restore_app": "Wiederherstellen von '{}' aus einem Sicherungsarchiv",
"log_backup_restore_system": "System aus einem Sicherungsarchiv wiederherstellen",
"log_available_on_yunopaste": "Das Protokoll ist nun via {url} verfügbar",
@ -565,7 +564,6 @@
"diagnosis_apps_issue": "Ein Problem für die App {app} ist aufgetreten",
"config_validate_time": "Sollte eine zulässige Zeit wie HH:MM sein",
"config_validate_url": "Sollte eine zulässige web URL sein",
"config_version_not_supported": "Konfigurationspanel Versionen '{version}' sind nicht unterstützt.",
"diagnosis_apps_allgood": "Alle installierten Apps berücksichtigen die grundlegenden Paketierungspraktiken",
"diagnosis_apps_broken": "Diese App ist im YunoHost-Applikationskatalog momentan als defekt gekennzeichnet. Es könnte sich dabei um einen vorübergehendes Problem handeln. Während der/die Betreuer:in versucht das Problem zu beheben, ist die Upgrade-Funktion für diese App gesperrt.",
"diagnosis_apps_not_in_app_catalog": "Diese Applikation steht nicht im Applikationskatalog von YunoHost. Sie sollten in Betracht ziehen, sie zu deinstallieren, weil sie keine Aktualisierungen mehr erhält und die Integrität und die Sicherheit Ihres Systems kompromittieren könnte.",
@ -605,7 +603,6 @@
"domain_dns_push_success": "DNS-Einträge aktualisiert!",
"domain_dns_push_failed": "Die Aktualisierung der DNS-Einträge ist leider gescheitert.",
"domain_dns_push_partial_failure": "DNS-Einträge teilweise aktualisiert: einige Warnungen/Fehler wurden gemeldet.",
"domain_config_features_disclaimer": "Bisher hat das Aktivieren/Deaktivieren von Mail- oder XMPP-Funktionen nur Auswirkungen auf die empfohlene und automatische DNS-Konfiguration, nicht auf die Systemkonfigurationen!",
"domain_config_mail_in": "Eingehende E-Mails",
"domain_config_mail_out": "Ausgehende E-Mails",
"domain_config_xmpp": "Instant Messaging (XMPP)",
@ -695,5 +692,17 @@
"domain_config_cert_summary_abouttoexpire": "Das aktuelle Zertifikat läuft bald ab. Es sollte bald automatisch erneuert werden.",
"domain_config_cert_summary_expired": "ACHTUNG: Das aktuelle Zertifikat ist nicht gültig! HTTPS wird gar nicht funktionieren!",
"domain_config_cert_summary_letsencrypt": "Toll! Sie benutzen ein gültiges Let's Encrypt-Zertifikat!",
"domain_config_cert_summary_ok": "Gut, das aktuelle Zertifikat sieht gut aus!"
}
"domain_config_cert_summary_ok": "Gut, das aktuelle Zertifikat sieht gut aus!",
"app_change_url_require_full_domain": "{app} kann nicht auf diese neue URL verschoben werden, weil sie eine vollständige eigene Domäne benötigt (z.B. mit Pfad = /)",
"app_not_upgraded_broken_system_continue": "Die App '{failed_app}' konnte nicht aktualisiert werden und hat Ihr System in einen beschädigten Zustand versetzt (folglich wird --continue-on-failure ignoriert) und als Konsequenz wurde die Aktualisierung der folgenden Apps abgelehnt: {apps}",
"app_yunohost_version_not_supported": "Diese App setzt YunoHost >= {required} voraus aber die gegenwärtig installierte Version ist {current}",
"app_failed_to_upgrade_but_continue": "Die App {failed_app} konnte nicht aktualisiert werden und es wird anforderungsgemäss zur nächsten Aktualisierung fortgefahren. Starten sie 'yunohost log show {operation_logger_name}' um den Fehlerbericht zu sehen",
"app_not_upgraded_broken_system": "Die App '{failed_app}' konnte nicht aktualisiert werden und hat Ihr System in einen beschädigten Zustand versetzt und als Konzequenz wurde die Aktualisierung der folgenden Apps abgelehnt: {apps}",
"apps_failed_to_upgrade": "Diese Apps konnten nicht aktualisiert werden: {apps}",
"app_arch_not_supported": "Diese App kann nur auf bestimmten Architekturen {required} installiert werden, aber Ihre gegenwärtige Serverarchitektur ist {current}",
"app_not_enough_disk": "Diese App benötigt {required} freien Speicherplatz.",
"app_not_enough_ram": "Diese App benötigt {required} RAM um installiert/aktualisiert zu werden, aber es sind aktuell nur {current} verfügbar.",
"app_change_url_failed": "Kann die URL für {app} nicht ändern: {error}",
"app_change_url_script_failed": "Es ist ein Fehler im URL-Änderungs-Script aufgetreten",
"app_resource_failed": "Automatische Ressourcen-Allokation (provisioning), die Unterbindung des Zugriffts auf Ressourcen (deprovisioning) oder die Aktualisierung der Ressourcen für {app} schlug fehl: {error}"
}

View file

@ -13,21 +13,26 @@
"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_arch_not_supported": "This app can only be installed on architectures {', '.join(required)} but your server architecture is {current}",
"app_arch_not_supported": "This app can only be installed on architectures {required} but your server architecture is {current}",
"app_argument_choice_invalid": "Pick a valid value for argument '{name}': '{value}' is not among the available choices ({choices})",
"app_argument_invalid": "Pick a valid value for the argument '{name}': {error}",
"app_argument_password_no_default": "Error while parsing password argument '{name}': password argument can't have a default value for security reasons",
"app_argument_required": "Argument '{name}' is required",
"app_change_url_failed": "Could not change the url for {app}: {error}",
"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_require_full_domain": "{app} cannot be moved to this new URL because it requires a full domain (i.e. with path = /)",
"app_change_url_script_failed": "An error occured inside the change url script",
"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_corrupt_source": "YunoHost was able to download the asset '{source_id}' ({url}) for {app}, but the asset doesn't match the expected checksum. This could mean that some temporary network failure happened on your server, OR the asset was somehow changed by the upstream maintainer (or a malicious actor?) and YunoHost packagers need to investigate and update the app manifest to reflect this change.\n Expected sha256 checksum: {expected_sha256}\n Downloaded sha256 checksum: {computed_sha256}\n Downloaded file size: {size}",
"app_extraction_failed": "Could not extract the installation files",
"app_failed_to_download_asset": "Failed to download asset '{source_id}' ({url}) for {app}: {out}",
"app_failed_to_upgrade_but_continue": "App {failed_app} failed to upgrade, continue to next upgrades as requested. Run 'yunohost log show {operation_logger_name}' to see failure log",
"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",
"app_install_failed": "Unable to install {app}: {error}",
"app_resource_failed": "Provisioning, deprovisioning, or updating resources for {app} failed: {error}",
"app_install_files_invalid": "These files cannot be installed",
"app_install_script_failed": "An error occurred inside the app installation script",
"app_label_deprecated": "This command is deprecated! Please use the new command 'yunohost user permission update' to manage the app label.",
@ -46,10 +51,13 @@
"app_not_installed": "Could not find {app} in the list of installed apps: {all_apps}",
"app_not_properly_removed": "{app} has not been properly removed",
"app_not_upgraded": "The app '{failed_app}' failed to upgrade, and as a consequence the following apps' upgrades have been cancelled: {apps}",
"app_not_upgraded_broken_system": "The app '{failed_app}' failed to upgrade and put the system in a broken state, and as a consequence the following apps' upgrades have been cancelled: {apps}",
"app_not_upgraded_broken_system_continue": "The app '{failed_app}' failed to upgrade and put the system in a broken state (so --continue-on-failure is ignored), and as a consequence the following apps' upgrades have been cancelled: {apps}",
"app_packaging_format_not_supported": "This app cannot be installed because its packaging format is not supported by your YunoHost version. You should probably consider upgrading your system.",
"app_remove_after_failed_install": "Removing the app after installation failure...",
"app_removed": "{app} uninstalled",
"app_requirements_checking": "Checking requirements for {app}...",
"app_resource_failed": "Provisioning, deprovisioning, or updating resources for {app} failed: {error}",
"app_restore_failed": "Could not restore {app}: {error}",
"app_restore_script_failed": "An error occured inside the app restore script",
"app_sources_fetch_failed": "Could not fetch source files, is the URL correct?",
@ -72,6 +80,8 @@
"apps_catalog_obsolete_cache": "The app catalog cache is empty or obsolete.",
"apps_catalog_update_success": "The application catalog has been updated!",
"apps_catalog_updating": "Updating application catalog...",
"apps_failed_to_upgrade": "Those applications failed to upgrade:{apps}",
"apps_failed_to_upgrade_line": "\n * {app_id} (to see corresponding log do a 'yunohost log show {operation_logger_name}')",
"ask_admin_fullname": "Admin full name",
"ask_admin_username": "Admin username",
"ask_fullname": "Full name",
@ -103,14 +113,14 @@
"backup_copying_to_organize_the_archive": "Copying {size}MB to organize the archive",
"backup_couldnt_bind": "Could not bind {src} to {dest}.",
"backup_create_size_estimation": "The archive will contain about {size} of data.",
"backup_created": "Backup created",
"backup_created": "Backup created: {name}",
"backup_creation_failed": "Could not create the backup archive",
"backup_csv_addition_failed": "Could not add files to backup into the CSV file",
"backup_csv_creation_failed": "Could not create the CSV file needed for restoration",
"backup_custom_backup_error": "Custom backup method could not get past the 'backup' step",
"backup_custom_mount_error": "Custom backup method could not get past the 'mount' step",
"backup_delete_error": "Could not delete '{path}'",
"backup_deleted": "Backup deleted",
"backup_deleted": "Backup deleted: {name}",
"backup_hook_unknown": "The backup hook '{hook}' is unknown",
"backup_method_copy_finished": "Backup copy finalized",
"backup_method_custom_finished": "Custom backup method '{method}' finished",
@ -163,7 +173,6 @@
"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 into YunoHost. Some features such as single sign-on and backup/restore might not be available. Install anyway? [{answers}] ",
@ -247,6 +256,7 @@
"diagnosis_ip_no_ipv4": "The server does not have working IPv4.",
"diagnosis_ip_no_ipv6": "The server does not have working IPv6.",
"diagnosis_ip_no_ipv6_tip": "Having a working IPv6 is not mandatory for your server to work, but it is better for the health of the Internet as a whole. IPv6 should usually be automatically configured by the system or your provider if it's available. Otherwise, you might need to configure a few things manually as explained in the documentation here: <a href='https://yunohost.org/#/ipv6'>https://yunohost.org/#/ipv6</a>. If you cannot enable IPv6 or if it seems too technical for you, you can also safely ignore this warning.",
"diagnosis_ip_no_ipv6_tip_important": "IPv6 should usually be automatically configured by the system or your provider if it's available. Otherwise, you might need to configure a few things manually as explained in the documentation here: <a href='https://yunohost.org/#/ipv6'>https://yunohost.org/#/ipv6</a>.",
"diagnosis_ip_not_connected_at_all": "The server does not seem to be connected to the Internet at all!?",
"diagnosis_ip_weird_resolvconf": "DNS resolution seems to be working, but it looks like you're using a custom <code>/etc/resolv.conf</code>.",
"diagnosis_ip_weird_resolvconf_details": "The file <code>/etc/resolv.conf</code> should be a symlink to <code>/etc/resolvconf/run/resolv.conf</code> itself pointing to <code>127.0.0.1</code> (dnsmasq). If you want to manually configure DNS resolvers, please edit <code>/etc/resolv.dnsmasq.conf</code>.",
@ -318,8 +328,8 @@
"diagnosis_using_yunohost_testing_details": "This is probably OK if you know what you are doing, but pay attention to the release notes before installing YunoHost upgrades! If you want to disable 'testing' upgrades, you should remove the <cmd>testing</cmd> keyword from <cmd>/etc/apt/sources.list.d/yunohost.list</cmd>.",
"disk_space_not_sufficient_install": "There is not enough disk space left to install this application",
"disk_space_not_sufficient_update": "There is not enough disk space left to update this application",
"domain_cannot_add_xmpp_upload": "You cannot add domains starting with 'xmpp-upload.'. This kind of name is reserved for the XMPP upload feature integrated into YunoHost.",
"domain_cannot_add_muc_upload": "You cannot add domains starting with 'muc.'. This kind of name is reserved for the XMPP multi-users chat feature integrated into YunoHost.",
"domain_cannot_add_xmpp_upload": "You cannot add domains starting with 'xmpp-upload.'. This kind of name is reserved for the XMPP upload feature integrated into YunoHost.",
"domain_cannot_remove_main": "You cannot remove '{domain}' since it's the main domain, you first need to set another domain as the main domain using 'yunohost domain main-domain -n <another-domain>'; here is the list of candidate domains: {other_domains}",
"domain_cannot_remove_main_add_new_one": "You cannot remove '{domain}' since it's the main domain and your only domain, you need to first add another domain using 'yunohost domain add <another-domain.com>', then set is as the main domain using 'yunohost domain main-domain -n <another-domain.com>' and then you can remove the domain '{domain}' using 'yunohost domain remove {domain}'.'",
"domain_cert_gen_failed": "Could not generate certificate",
@ -346,9 +356,11 @@
"domain_config_cert_summary_selfsigned": "WARNING: Current certificate is self-signed. Browsers will display a spooky warning to new visitors!",
"domain_config_cert_validity": "Validity",
"domain_config_default_app": "Default app",
"domain_config_default_app_help": "People will automatically be redirected to this app when opening this domain. If no app is specified, people are redirected to the user portal login form.",
"domain_config_mail_in": "Incoming emails",
"domain_config_mail_out": "Outgoing emails",
"domain_config_xmpp": "Instant messaging (XMPP)",
"domain_config_xmpp_help": "NB: some XMPP features will require that you update your DNS records and regenerate your Lets Encrypt certificate to be enabled",
"domain_created": "Domain created",
"domain_creation_failed": "Unable to create domain {domain}: {error}",
"domain_deleted": "Domain deleted",
@ -408,17 +420,21 @@
"firewall_reloaded": "Firewall reloaded",
"firewall_rules_cmd_failed": "Some firewall rule commands have failed. More info in log.",
"global_settings_reset_success": "Reset global settings",
"global_settings_setting_passwordless_sudo": "Allow admins to use 'sudo' without re-typing their passwords",
"global_settings_setting_admin_strength": "Admin password strength requirements",
"global_settings_setting_admin_strength_help": "These requirements are only enforced when initializing or changing the password",
"global_settings_setting_backup_compress_tar_archives": "Compress backups",
"global_settings_setting_backup_compress_tar_archives_help": "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_dns_exposure": "IP versions to consider for DNS configuration and diagnosis",
"global_settings_setting_dns_exposure_help": "NB: This only affects the recommended DNS configuration and diagnosis checks. This does not affect system configurations.",
"global_settings_setting_nginx_compatibility": "NGINX Compatibility",
"global_settings_setting_nginx_compatibility_help": "Compatibility vs. security tradeoff for the web server NGINX. Affects the ciphers (and other security-related aspects)",
"global_settings_setting_nginx_redirect_to_https": "Force HTTPS",
"global_settings_setting_nginx_redirect_to_https_help": "Redirect HTTP requests to HTTPs by default (DO NOT TURN OFF unless you really know what you're doing!)",
"global_settings_setting_passwordless_sudo": "Allow admins to use 'sudo' without re-typing their passwords",
"global_settings_setting_pop3_enabled": "Enable POP3",
"global_settings_setting_pop3_enabled_help": "Enable the POP3 protocol for the mail server",
"global_settings_setting_portal_theme": "Portal theme",
"global_settings_setting_portal_theme_help": "More info regarding creating custom portal themes at https://yunohost.org/theming",
"global_settings_setting_postfix_compatibility": "Postfix Compatibility",
"global_settings_setting_postfix_compatibility_help": "Compatibility vs. security tradeoff for the Postfix server. Affects the ciphers (and other security-related aspects)",
"global_settings_setting_root_access_explain": "On Linux systems, 'root' is the absolute admin. In YunoHost context, direct 'root' SSH login is by default disable - except from the local network of the server. Members of the 'admins' group can use the sudo command to act as root from the command line. However, it can be helpful to have a (robust) root password to debug the system if for some reason regular admins can not login anymore.",
@ -440,8 +456,6 @@
"global_settings_setting_ssh_password_authentication_help": "Allow password authentication for SSH",
"global_settings_setting_ssh_port": "SSH port",
"global_settings_setting_ssowat_panel_overlay_enabled": "Enable the small 'YunoHost' portal shortcut square on apps",
"global_settings_setting_portal_theme": "Portal theme",
"global_settings_setting_portal_theme_help": "More info regarding creating custom portal themes at https://yunohost.org/theming",
"global_settings_setting_user_strength": "User password strength requirements",
"global_settings_setting_user_strength_help": "These requirements are only enforced when initializing or changing the password",
"global_settings_setting_webadmin_allowlist": "Webadmin IP allowlist",
@ -461,11 +475,11 @@
"group_creation_failed": "Could not create the group '{group}': {error}",
"group_deleted": "Group '{group}' deleted",
"group_deletion_failed": "Could not delete the group '{group}': {error}",
"group_no_change": "Nothing to change for group '{group}'",
"group_unknown": "The group '{group}' is unknown",
"group_update_aliases": "Updating aliases for group '{group}'",
"group_update_failed": "Could not update the group '{group}': {error}",
"group_updated": "Group '{group}' updated",
"group_update_aliases": "Updating aliases for group '{group}'",
"group_no_change": "Nothing to change for group '{group}'",
"group_user_already_in_group": "User {user} is already in group {group}",
"group_user_not_in_group": "User {user} is not in group {group}",
"hook_exec_failed": "Could not run script: {path}",
@ -479,6 +493,7 @@
"invalid_number_max": "Must be lesser than {max}",
"invalid_number_min": "Must be greater than {min}",
"invalid_regex": "Invalid regex:'{regex}'",
"invalid_shell": "Invalid shell: {shell}",
"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_attribute_already_exists": "LDAP attribute '{attribute}' already exists with value '{value}'",
@ -517,7 +532,6 @@
"log_permission_url": "Update URL related to permission '{}'",
"log_regen_conf": "Regenerate system configurations '{}'",
"log_remove_on_failed_install": "Remove '{}' after a failed installation",
"log_remove_on_failed_restore": "Remove '{}' after a failed restore from a backup archive",
"log_resource_snippet": "Provisioning/deprovisioning/updating a resource",
"log_selfsigned_cert_install": "Install self-signed certificate on '{}' domain",
"log_settings_reset": "Reset setting",
@ -758,4 +772,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 - 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."
}
}

View file

@ -191,7 +191,6 @@
"unexpected_error": "Io neatendita iris malbone: {error}",
"password_listed": "Ĉi tiu pasvorto estas inter la plej uzataj pasvortoj en la mondo. Bonvolu elekti ion pli unikan.",
"ssowat_conf_generated": "SSOwat-agordo generita",
"log_remove_on_failed_restore": "Forigu '{}' post malsukcesa restarigo de rezerva ar archiveivo",
"dpkg_is_broken": "Vi ne povas fari ĉi tion nun ĉar dpkg/APT (la administrantoj pri pakaĵaj sistemoj) ŝajnas esti rompita stato ... Vi povas provi solvi ĉi tiun problemon per konekto per SSH kaj funkcianta `sudo dpkg --configure -a`.",
"certmanager_cert_signing_failed": "Ne povis subskribi la novan atestilon",
"log_tools_upgrade": "Ĝisdatigu sistemajn pakaĵojn",

View file

@ -78,8 +78,8 @@
"pattern_backup_archive_name": "Debe ser un nombre de archivo válido con un máximo de 30 caracteres, solo se admiten caracteres alfanuméricos y los caracteres -_. (guiones y punto)",
"pattern_domain": "El nombre de dominio debe ser válido (por ejemplo mi-dominio.org)",
"pattern_email": "Debe ser una dirección de correo electrónico válida, sin el símbolo '+' (ej. alguien@ejemplo.com)",
"pattern_firstname": "Debe ser un nombre válido",
"pattern_lastname": "Debe ser un apellido válido",
"pattern_firstname": "Debe ser un nombre válido (al menos 3 caracteres)",
"pattern_lastname": "Debe ser un apellido válido (al menos 3 caracteres)",
"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)",
@ -266,7 +266,7 @@
"migrations_failed_to_load_migration": "No se pudo cargar la migración {id}: {error}",
"migrations_dependencies_not_satisfied": "Ejecutar estas migraciones: «{dependencies_id}» antes de migrar {id}.",
"migrations_already_ran": "Esas migraciones ya se han realizado: {ids}",
"mail_unavailable": "Esta dirección de correo está reservada y será asignada automáticamente al primer usuario",
"mail_unavailable": "Esta dirección de correo electrónico está reservada para el grupo de administradores",
"mailbox_disabled": "Correo desactivado para usuario {user}",
"log_tools_reboot": "Reiniciar el servidor",
"log_tools_shutdown": "Apagar el servidor",
@ -287,7 +287,6 @@
"log_domain_remove": "Eliminar el dominio «{}» de la configuración del sistema",
"log_domain_add": "Añadir el dominio «{}» a la configuración del sistema",
"log_remove_on_failed_install": "Eliminar «{}» después de una instalación fallida",
"log_remove_on_failed_restore": "Eliminar «{}» después de una restauración fallida desde un archivo de respaldo",
"log_backup_restore_app": "Restaurar «{}» desde un archivo de respaldo",
"log_backup_restore_system": "Restaurar sistema desde un archivo de respaldo",
"log_available_on_yunopaste": "Este registro está ahora disponible vía {url}",
@ -316,7 +315,7 @@
"dyndns_could_not_check_available": "No se pudo comprobar si {domain} está disponible en {provider}.",
"domain_dns_conf_is_just_a_recommendation": "Este comando muestra la configuración *recomendada*. No configura las entradas DNS por ti. Es tu responsabilidad configurar la zona DNS en su registrador según esta recomendación.",
"dpkg_lock_not_available": "Esta orden no se puede ejecutar en este momento ,parece que programa está usando el bloqueo de dpkg (el gestor de paquetes del sistema)",
"dpkg_is_broken": "No puede hacer esto en este momento porque dpkg/APT (los gestores de paquetes del sistema) parecen estar mal configurados... Puede tratar de solucionar este problema conectando a través de SSH y ejecutando `sudo apt install --fix-broken` y/o `sudo dpkg --configure -a`.",
"dpkg_is_broken": "No puede hacer esto en este momento porque dpkg/APT (los gestores de paquetes del sistema) parecen estar mal configurados... Puede tratar de solucionar este problema conectando a través de SSH y ejecutando `sudo apt install --fix-broken` y/o `sudo dpkg --configure -a` y/o `sudo dpkg --audit`.",
"confirm_app_install_thirdparty": "¡PELIGRO! Esta aplicación no forma parte del catálogo de aplicaciones de YunoHost. La instalación de aplicaciones de terceros puede comprometer la integridad y seguridad de tu sistema. Probablemente NO deberías instalarla a menos que sepas lo que estás haciendo. NO se proporcionará NINGÚN SOPORTE si esta aplicación no funciona o rompe su sistema… Si de todos modos quieres correr ese riesgo, escribe '{answers}'",
"confirm_app_install_danger": "¡PELIGRO! ¡Esta aplicación sigue siendo experimental (si no es expresamente no funcional)! Probablemente NO deberías instalarla a menos que sepas lo que estás haciendo. NO se proporcionará NINGÚN SOPORTE si esta aplicación no funciona o rompe tu sistema… Si de todos modos quieres correr ese riesgo, escribe '{answers}'",
"confirm_app_install_warning": "Aviso: esta aplicación puede funcionar pero no está bien integrada en YunoHost. Algunas herramientas como la autentificación única y respaldo/restauración podrían no estar disponibles. ¿Instalar de todos modos? [{answers}] ",
@ -454,7 +453,7 @@
"diagnosis_ports_forwarding_tip": "Para solucionar este incidente, lo más seguro deberías configurar la redirección de los puertos en el router como se especifica en <a href='https://yunohost.org/isp_box_config'>https://yunohost.org/isp_box_config</a>",
"certmanager_warning_subdomain_dns_record": "El subdominio '{subdomain}' no se resuelve en la misma dirección IP que '{domain}'. Algunas funciones no estarán disponibles hasta que solucione esto y regenere el certificado.",
"domain_cannot_add_xmpp_upload": "No puede agregar dominios que comiencen con 'xmpp-upload'. Este tipo de nombre está reservado para la función de carga XMPP integrada en YunoHost.",
"yunohost_postinstall_end_tip": "¡La post-instalación completada! Para finalizar su configuración, por favor considere:\n - agregar un primer usuario a través de la sección 'Usuarios' del administrador web (o 'yunohost user create <username>' en la línea de comandos);\n - diagnosticar problemas potenciales a través de la sección 'Diagnóstico' del administrador web (o 'yunohost diagnosis run' en la línea de comandos);\n - leyendo las partes 'Finalizando su configuración' y 'Conociendo YunoHost' en la documentación del administrador: https://yunohost.org/admindoc.",
"yunohost_postinstall_end_tip": "¡La post-instalación completada! Para finalizar su configuración, por favor considere:\n - diagnosticar problemas potenciales a través de la sección 'Diagnóstico' del administrador web (o 'yunohost diagnosis run' en la línea de comandos);\n - leyendo las partes 'Finalizando su configuración' y 'Conociendo YunoHost' en la documentación del administrador: https://yunohost.org/admindoc.",
"diagnosis_dns_point_to_doc": "Por favor, consulta la documentación en <a href='https://yunohost.org/dns_config'>https://yunohost.org/dns_config</a> si necesitas ayuda para configurar los registros DNS.",
"diagnosis_ip_global": "IP Global: <code>{global}</code>",
"diagnosis_mail_outgoing_port_25_ok": "El servidor de email SMTP puede mandar emails (puerto saliente 25 no está bloqueado).",
@ -552,7 +551,6 @@
"config_validate_email": "Debe ser una dirección de correo correcta",
"config_validate_time": "Debe ser una hora valida en formato HH:MM",
"config_validate_url": "Debe ser una URL válida",
"config_version_not_supported": "Las versiones del panel de configuración '{version}' no están soportadas.",
"domain_remove_confirm_apps_removal": "La supresión de este dominio también eliminará las siguientes aplicaciones:\n{apps}\n\n¿Seguro? [{answers}]",
"domain_registrar_is_not_configured": "El registrador aún no ha configurado el dominio {domain}.",
"diagnosis_apps_not_in_app_catalog": "Esta aplicación se encuentra ausente o ya no figura en el catálogo de aplicaciones de YunoHost. Deberías considerar desinstalarla ya que no recibirá actualizaciones y podría comprometer la integridad y seguridad de tu sistema.",
@ -574,7 +572,6 @@
"domain_dns_push_failed_to_authenticate": "No se pudo autenticar en la API del registrador para el dominio '{domain}'. ¿Lo más probable es que las credenciales sean incorrectas? (Error: {error})",
"domain_dns_registrar_experimental": "Hasta ahora, la comunidad de YunoHost no ha probado ni revisado correctamente la interfaz con la API de **{registrar}**. El soporte es **muy experimental**. ¡Ten cuidado!",
"domain_dns_push_record_failed": "No se pudo {action} registrar {type}/{name}: {error}",
"domain_config_features_disclaimer": "Hasta ahora, habilitar/deshabilitar las funciones de correo o XMPP solo afecta la configuración de DNS recomendada y automática, ¡no las configuraciones del sistema!",
"domain_config_mail_in": "Correos entrantes",
"domain_config_mail_out": "Correos salientes",
"domain_config_xmpp": "Mensajería instantánea (XMPP)",
@ -600,7 +597,7 @@
"postinstall_low_rootfsspace": "El sistema de archivos raíz tiene un espacio total inferior a 10 GB, ¡lo cual es bastante preocupante! ¡Es probable que se quede sin espacio en disco muy rápidamente! Se recomienda tener al menos 16 GB para el sistema de archivos raíz. Si desea instalar YunoHost a pesar de esta advertencia, vuelva a ejecutar la instalación posterior con --force-diskspace",
"migration_ldap_rollback_success": "Sistema revertido.",
"permission_protected": "Permiso {permission} está protegido. No puede agregar o quitar el grupo de visitantes a/desde este permiso.",
"global_settings_setting_ssowat_panel_overlay_enabled": "Habilitar la superposición del panel SSOwat",
"global_settings_setting_ssowat_panel_overlay_enabled": "Habilitar el pequeño cuadrado de acceso directo al portal \"YunoHost\" en las aplicaciones",
"migration_0021_start": "Iniciando migración a Bullseye",
"migration_0021_patching_sources_list": "Parcheando los sources.lists...",
"migration_0021_main_upgrade": "Iniciando actualización principal...",
@ -679,5 +676,76 @@
"config_action_failed": "Error al ejecutar la acción '{action}': {error}",
"config_forbidden_readonly_type": "El tipo '{type}' no puede establecerse como solo lectura, utilice otro tipo para representar este valor (arg id relevante: '{id}').",
"diagnosis_using_stable_codename": "<cmd>apt</cmd> (el gestor de paquetes del sistema) está configurado actualmente para instalar paquetes de nombre en clave 'estable', en lugar del nombre en clave de la versión actual de Debian (bullseye).",
"diagnosis_using_stable_codename_details": "Esto suele deberse a una configuración incorrecta de su proveedor de alojamiento. Esto es peligroso, porque tan pronto como la siguiente versión de Debian se convierta en la nueva 'estable', <cmd>apt</cmd> querrá actualizar todos los paquetes del sistema sin pasar por un procedimiento de migración adecuado. Se recomienda arreglar esto editando la fuente de apt para el repositorio base de Debian, y reemplazar la palabra clave <cmd>stable</cmd> por <cmd>bullseye</cmd>. El fichero de configuración correspondiente debería ser <cmd>/etc/apt/sources.list</cmd>, o un fichero en <cmd>/etc/apt/sources.list.d/</cmd>."
}
"diagnosis_using_stable_codename_details": "Esto suele deberse a una configuración incorrecta de su proveedor de alojamiento. Esto es peligroso, porque tan pronto como la siguiente versión de Debian se convierta en la nueva 'estable', <cmd>apt</cmd> querrá actualizar todos los paquetes del sistema sin pasar por un procedimiento de migración adecuado. Se recomienda arreglar esto editando la fuente de apt para el repositorio base de Debian, y reemplazar la palabra clave <cmd>stable</cmd> por <cmd>bullseye</cmd>. El fichero de configuración correspondiente debería ser <cmd>/etc/apt/sources.list</cmd>, o un fichero en <cmd>/etc/apt/sources.list.d/</cmd>.",
"domain_config_cert_install": "Instalar el certificado Let's Encrypt",
"domain_cannot_add_muc_upload": "No puedes añadir dominios que empiecen por 'muc.'. Este tipo de nombre está reservado para la función de chat XMPP multi-usuarios integrada en YunoHost.",
"domain_config_cert_renew_help": "El certificado se renovará automáticamente durante los últimos 15 días de validez. Si lo desea, puede renovarlo manualmente. (No recomendado).",
"domain_config_cert_summary_expired": "CRÍTICO: ¡El certificado actual no es válido! ¡HTTPS no funcionará en absoluto!",
"domain_config_cert_summary_letsencrypt": "¡Muy bien! Estás utilizando un certificado Let's Encrypt válido.",
"global_settings_setting_postfix_compatibility": "Compatibilidad con Postfix",
"global_settings_setting_root_password_confirm": "Nueva contraseña de root (confirmar)",
"global_settings_setting_webadmin_allowlist_enabled": "Activar la lista de IPs permitidas para Webadmin",
"migration_0024_rebuild_python_venv_broken_app": "Omitiendo {app} porque virtualenv no puede ser reconstruido fácilmente para esta app. En su lugar, deberías arreglar la situación forzando la actualización de esta app usando `yunohost app upgrade --force {app}`.",
"migration_0024_rebuild_python_venv_in_progress": "Ahora intentando reconstruir el virtualenv de Python para `{app}`",
"confirm_app_insufficient_ram": "¡PELIGRO! Esta aplicación requiere {required} de RAM para ser instalada/actualizada, pero solo hay {current} disponible actualmente. Incluso si esta aplicación pudiera ejecutarse, su proceso de instalación/actualización requiere una gran cantidad de RAM, por lo que tu servidor puede congelarse y fallar miserablemente. Si estás dispuesto a asumir ese riesgo de todos modos, escribe '{answers}'",
"confirm_notifications_read": "ADVERTENCIA: Deberías revisar las notificaciones de la aplicación antes de continuar, puede haber información importante que debes conocer. [{answers}]",
"domain_config_cert_summary_selfsigned": "ADVERTENCIA: El certificado actual es autofirmado. ¡Los navegadores mostrarán una espeluznante advertencia a los nuevos visitantes!.",
"global_settings_setting_backup_compress_tar_archives": "Comprimir las copias de seguridad",
"global_settings_setting_root_access_explain": "En sistemas Linux, 'root' es el administrador absoluto. En el contexto de YunoHost, el acceso directo 'root' SSH está deshabilitado por defecto - excepto desde la red local del servidor. Los miembros del grupo 'admins' pueden usar el comando sudo para actuar como root desde la linea de comandos. Sin embargo, puede ser útil tener una contraseña de root (robusta) para depurar el sistema si por alguna razón los administradores regulares ya no pueden iniciar sesión.",
"migration_0021_not_buster2": "¡La distribución Debian actual no es Buster! Si ya ha ejecutado la migración Buster->Bullseye, entonces este error es sintomático del hecho de que el procedimiento de migración no fue 100% exitoso (de lo contrario YunoHost lo habría marcado como completado). Se recomienda investigar lo sucedido con el equipo de soporte, que necesitará el registro **completo** de la `migración, que se puede encontrar en Herramientas > Registros en el webadmin.",
"global_settings_reset_success": "Restablecer la configuración global",
"global_settings_setting_nginx_compatibility": "Compatibilidad con NGINX",
"global_settings_setting_nginx_redirect_to_https": "Forzar HTTPS",
"global_settings_setting_user_strength_help": "Estos requisitos sólo se aplican al inicializar o cambiar la contraseña",
"log_resource_snippet": "Aprovisionar/desaprovisionar/actualizar un recurso",
"global_settings_setting_pop3_enabled": "Habilitar POP3",
"global_settings_setting_smtp_allow_ipv6": "Permitir IPv6",
"global_settings_setting_security_experimental_enabled": "Funciones de seguridad experimentales",
"migration_0024_rebuild_python_venv_disclaimer_ignored": "Virtualenvs no puede reconstruirse automáticamente para esas aplicaciones. Necesitas forzar una actualización para ellas, lo que puede hacerse desde la línea de comandos con: `yunohost app upgrade --force APP`: {ignored_apps}",
"migration_0024_rebuild_python_venv_failed": "Error al reconstruir el virtualenv de Python para {app}. La aplicación puede no funcionar mientras esto no se resuelva. Deberías arreglar la situación forzando la actualización de esta app usando `yunohost app upgrade --force {app}`.",
"app_arch_not_supported": "Esta aplicación sólo puede instalarse en arquitecturas {required} pero la arquitectura de su servidor es {current}",
"app_resource_failed": "Falló la asignación, desasignación o actualización de recursos para {app}: {error}",
"app_not_enough_disk": "Esta aplicación requiere {required} espacio libre.",
"app_not_enough_ram": "Esta aplicación requiere {required} de RAM para ser instalada/actualizada, pero solo hay {current} disponible actualmente.",
"app_yunohost_version_not_supported": "Esta aplicación requiere YunoHost >= {required} pero la versión actualmente instalada es {current}",
"global_settings_setting_ssh_compatibility": "Compatibilidad con SSH",
"root_password_changed": "la contraseña de root fue cambiada",
"domain_config_acme_eligible_explain": "Este dominio no parece estar preparado para un certificado Let's Encrypt. Compruebe la configuración DNS y la accesibilidad del servidor HTTP. Las secciones \"Registros DNS\" y \"Web\" de <a href='#/diagnosis'>la página de diagnóstico</a> pueden ayudarte a entender qué está mal configurado.",
"domain_config_cert_no_checks": "Ignorar las comprobaciones de diagnóstico",
"domain_config_cert_renew": "Renovar el certificado Let's Encrypt",
"domain_config_cert_summary": "Estado del certificado",
"domain_config_cert_summary_abouttoexpire": "El certificado actual está a punto de caducar. Pronto debería renovarse automáticamente.",
"domain_config_cert_summary_ok": "Muy bien, ¡el certificado actual tiene buena pinta!",
"domain_config_cert_validity": "Validez",
"global_settings_setting_admin_strength_help": "Estos requisitos sólo se aplican al inicializar o cambiar la contraseña",
"global_settings_setting_pop3_enabled_help": "Habilitar el protocolo POP3 para el servidor de correo",
"log_settings_reset_all": "Restablecer todos los ajustes",
"log_settings_set": "Aplicar ajustes",
"pattern_fullname": "Debe ser un nombre completo válido (al menos 3 caracteres)",
"password_confirmation_not_the_same": "La contraseña y su confirmación no coinciden",
"password_too_long": "Elija una contraseña de menos de 127 caracteres",
"diagnosis_using_yunohost_testing": "<cmd>apt</cmd> (el gestor de paquetes del sistema) está actualmente configurado para instalar cualquier actualización de 'testing' para el núcleo de YunoHost.",
"diagnosis_using_yunohost_testing_details": "Esto probablemente esté bien si sabes lo que estás haciendo, ¡pero presta atención a las notas de la versión antes de instalar actualizaciones de YunoHost! Si quieres deshabilitar las actualizaciones de prueba, debes eliminar la palabra clave <cmd>testing</cmd> de <cmd>/etc/apt/sources.list.d/yunohost.list</cmd>.",
"global_settings_setting_passwordless_sudo": "Permitir a los administradores utilizar 'sudo' sin tener que volver a escribir sus contraseñas.",
"group_update_aliases": "Actualizando alias para el grupo '{group}'",
"group_no_change": "Nada que cambiar para el grupo '{group}'",
"global_settings_setting_portal_theme": "Tema del portal",
"global_settings_setting_portal_theme_help": "Más información sobre la creación de temas de portal personalizados en https://yunohost.org/theming",
"invalid_credentials": "Contraseña o nombre de usuario no válidos",
"global_settings_setting_root_password": "Nueva contraseña de root",
"global_settings_setting_webadmin_allowlist": "Lista de IPs permitidas para Webadmin",
"migration_0024_rebuild_python_venv_disclaimer_base": "Tras la actualización a Debian Bullseye, algunas aplicaciones Python necesitan ser parcialmente reconstruidas para ser convertidas a la nueva versión de Python distribuida en Debian (en términos técnicos: lo que se llama el 'virtualenv' necesita ser recreado). Mientras tanto, esas aplicaciones Python pueden no funcionar. YunoHost puede intentar reconstruir el virtualenv para algunas de ellas, como se detalla a continuación. Para otras aplicaciones, o si el intento de reconstrucción falla, necesitarás forzar manualmente una actualización para esas aplicaciones.",
"migration_description_0024_rebuild_python_venv": "Reparar la aplicación Python tras la migración a bullseye",
"global_settings_setting_smtp_relay_enabled": "Activar el relé SMTP",
"domain_config_acme_eligible": "Elegibilidad ACME",
"global_settings_setting_ssh_password_authentication": "Autenticación por contraseña",
"domain_config_cert_issuer": "Autoridad de certificación",
"invalid_shell": "Shell inválido: {shell}",
"log_settings_reset": "Restablecer ajuste",
"migration_description_0026_new_admins_group": "Migrar al nuevo sistema de 'varios administradores'",
"visitors": "Visitantes",
"global_settings_setting_smtp_relay_host": "Host de retransmisión SMTP",
"migration_0024_rebuild_python_venv_disclaimer_rebuild": "Se intentará reconstruir el virtualenv para las siguientes apps (NB: ¡la operación puede llevar algún tiempo!): {rebuild_apps}",
"migration_description_0025_global_settings_to_configpanel": "Migración de la nomenclatura de ajustes globales heredada a la nomenclatura nueva y moderna",
"registrar_infos": "Información sobre el registrador"
}

View file

@ -8,7 +8,7 @@
"diagnosis_ip_global": "IP orokorra: <code>{global}</code>",
"app_argument_password_no_default": "Errorea egon da '{name}' pasahitzaren argumentua ikuskatzean: pasahitzak ezin du balio hori izan segurtasun arrazoiengatik",
"app_extraction_failed": "Ezinezkoa izan da instalazio fitxategiak ateratzea",
"backup_deleted": "Babeskopia ezabatuta",
"backup_deleted": "Babeskopia ezabatu da: {name}",
"app_argument_required": "'{name}' argumentua ezinbestekoa da",
"certmanager_acme_not_configured_for_domain": "Une honetan ezinezkoa da ACME azterketa {domain} domeinurako burutzea nginx ezarpenek ez dutelako beharrezko kodea… Egiaztatu nginx ezarpenak egunean daudela 'yunohost tools regen-conf nginx --dry-run --with-diff' komandoa exekutatuz.",
"certmanager_domain_dns_ip_differs_from_public_ip": "'{domain}' domeinurako DNS balioak ez datoz bat zerbitzariaren IParekin. Egiaztatu 'DNS balioak' (oinarrizkoa) kategoria diagnostikoen atalean. 'A' balioak duela gutxi aldatu badituzu, itxaron hedatu daitezen (badaude DNSen hedapena ikusteko erramintak interneten). (Zertan ari zeren baldin badakizu, erabili '--no-checks' egiaztapen horiek desgaitzeko.)",
@ -49,7 +49,6 @@
"config_validate_email": "Benetazko posta elektronikoa izan behar da",
"config_validate_time": "OO:MM formatua duen ordu bat izan behar da",
"config_validate_url": "Benetazko URL bat izan behar da",
"config_version_not_supported": "Ezinezkoa da konfigurazio-panelaren '{version}' bertsioa erabiltzea.",
"app_restore_script_failed": "Errorea gertatu da aplikazioa lehengoratzeko aginduan",
"app_upgrade_some_app_failed": "Ezinezkoa izan da aplikazio batzuk eguneratzea",
"app_install_failed": "Ezinezkoa izan da {app} instalatzea: {error}",
@ -200,7 +199,7 @@
"backup_archive_writing_error": "Ezinezkoa izan da '{source}' ('{dest}' fitxategiak eskatu dituenak) fitxategia '{archive}' konprimatutako babeskopian sartzea",
"backup_ask_for_copying_if_needed": "Behin-behinean {size}MB erabili nahi dituzu babeskopia gauzatu ahal izateko? (Horrela egiten da fitxategi batzuk ezin direlako modu eraginkorragoan prestatu.)",
"backup_cant_mount_uncompress_archive": "Ezinezkoa izan da deskonprimatutako fitxategia muntatzea idazketa-babesa duelako",
"backup_created": "Babeskopia sortu da",
"backup_created": "Babeskopia sortu da: {name}",
"backup_copying_to_organize_the_archive": "{size}MB kopiatzen fitxategia antolatzeko",
"backup_couldnt_bind": "Ezin izan da {src} {dest}-ra lotu.",
"backup_output_directory_forbidden": "Aukeratu beste katalogo bat emaitza gordetzeko. Babeskopiak ezin dira sortu /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var edo /home/yunohost.backup/archives azpi-katalogoetan",
@ -337,7 +336,6 @@
"domain_dns_registrar_supported": "YunoHostek automatikoki antzeman du domeinu hau **{registrar}** erregistro-enpresak kudeatzen duela. Nahi baduzu YunoHostek automatikoki konfiguratu ditzake DNS ezarpenak, API egiaztagiri zuzenak zehazten badituzu. API egiaztagiriak non lortzeko dokumentazioa orri honetan duzu: https://yunohost.org/registar_api_{registrar}. (Baduzu DNS erregistroak eskuz konfiguratzeko aukera ere, gidalerro hauetan ageri den bezala: https://yunohost.org/dns)",
"domain_dns_push_failed_to_list": "Ezinezkoa izan da APIa erabiliz oraingo erregistroak antzematea: {error}",
"domain_dns_push_already_up_to_date": "Ezarpenak egunean daude, ez dago zereginik.",
"domain_config_features_disclaimer": "Oraingoz, posta elektronikoa edo XMPP funtzioak gaitu/desgaitzeak DNS ezarpenei soilik eragiten die, ez sistemaren konfigurazioari!",
"domain_config_mail_out": "Bidalitako mezuak",
"domain_config_xmpp": "Bat-bateko mezularitza (XMPP)",
"good_practices_about_user_password": "Erabiltzaile-pasahitz berria ezartzear zaude. Pasahitzak 8 karaktere izan beharko lituzke gutxienez, baina gomendagarria da pasahitz luzeagoa erabiltzea (esaldi bat, esaterako) edota karaktere desberdinak erabiltzea (hizki larriak, txikiak, zenbakiak eta karaktere bereziak).",
@ -400,7 +398,6 @@
"hook_exec_not_terminated": "Aginduak ez du behar bezala amaitu: {path}",
"log_corrupted_md_file": "Erregistroei lotutako YAML metadatu fitxategia kaltetuta dago: '{md_file}\nErrorea: {error}'",
"log_letsencrypt_cert_renew": "Berriztu '{}' Let's Encrypt ziurtagiria",
"log_remove_on_failed_restore": "Ezabatu '{}' babeskopia baten lehengoratzeak huts egin eta gero",
"diagnosis_package_installed_from_sury_details": "Sury izena duen kanpoko biltegi batetik instalatu dira pakete batzuk, nahi gabe. YunoHosten taldeak hobekuntzak egin ditu pakete hauek kudeatzeko, baina litekeena da PHP7.3 aplikazioak Stretch sistema eragilean instalatu zituzten kasu batzuetan arazoak sortzea. Egoera hau konpontzeko, honako komando hau exekutatu beharko zenuke: <cmd>{cmd_to_fix}</cmd>",
"log_help_to_get_log": "'{desc}' eragiketaren erregistroa ikusteko, exekutatu 'yunohost log show {name}'",
"dpkg_is_broken": "Une honetan ezinezkoa da sistemaren dpkg/APT pakateen kudeatzaileek hondatutako itxura dutelako… Arazoa konpontzeko SSH bidez konektatzen saia zaitezke eta ondoren exekutatu 'sudo apt install --fix-broken' edota 'sudo dpkg --configure -a' edota 'sudo dpkg --audit'.",
@ -737,5 +734,26 @@
"password_too_long": "Aukeratu 127 karaktere baino laburragoa den pasahitz bat",
"diagnosis_using_stable_codename_details": "Ostatatzaileak zerbait oker ezarri duenean gertatu ohi da hau. Arriskutsua da, Debianen datorren bertsioa 'estable' (egonkorra) bilakatzen denean, <cmd>apt</cmd>-ek sistemaren pakete guztiak bertsio-berritzen saiatuko da, beharrezko migrazio-prozedurarik burutu gabe. Debianen repositorioan apt iturria editatzen konpontzea da gomendioa, <cmd>stable</cmd> gakoa <cmd>bullseye</cmd> gakoarekin ordezkatuz. Ezarpen-fitxategia <cmd>/etc/apt/sources.list</cmd> izan beharko litzateke, edo <cmd>/etc/apt/sources.list.d/</cmd> direktorioko fitxategiren bat.",
"group_update_aliases": "'{group}' taldearen aliasak eguneratzen",
"group_no_change": "Ez da ezer aldatu behar '{group}' talderako"
"group_no_change": "Ez da ezer aldatu behar '{group}' talderako",
"app_not_enough_ram": "Aplikazio honek {required} RAM behar ditu instalatu edo bertsio-berritzeko, baina {current} bakarrik daude erabilgarri une honetan.",
"domain_cannot_add_muc_upload": "Ezin duzu 'muc.'-ekin hasten den domeinurik gehitu. Mota honetako izenak YunoHosten integratuta dagoen XMPP taldeko txatek erabil ditzaten gordeta daude.",
"confirm_app_insufficient_ram": "KONTUZ! Aplikazio honek {required} RAM behar ditu instalatu edo bertsio-berritzeko baina unean soilik {current} daude erabilgarri. Aplikazioa ibiliko balitz ere, instalazioak edo bertsio-berritzeak RAM kopuru handia behar du eta zure zerbitzariak erantzuteari utzi eta huts egin lezake. Hala ere arriskatu nahi baduzu idatzi '{answers}'",
"confirm_notifications_read": "ADI: ikuskatu aplikazioaren jakinarazpenak jarraitu baino lehen, baliteke jakin beharreko zerbait esatea. [{answers}]",
"app_arch_not_supported": "Aplikazio hau {required} arkitekturan instala daiteke bakarrik, baina zure zerbitzariaren arkitektura {current} da",
"app_resource_failed": "Huts egin du {app} aplikaziorako baliabideen eguneraketak / prestaketak / askapenak: {error}",
"app_not_enough_disk": "Aplikazio honek {required} espazio libre behar ditu.",
"app_yunohost_version_not_supported": "Aplikazio honek YunoHost >= {required} behar du baina unean instalatutako bertsioa {current} da",
"global_settings_setting_passwordless_sudo": "Baimendu administrariek 'sudo' erabiltzea pasahitzak berriro idatzi beharrik gabe",
"global_settings_setting_portal_theme": "Atariko gaia",
"global_settings_setting_portal_theme_help": "Atariko gai propioak sortzeari buruzko informazio gehiago: https://yunohost.org/theming",
"invalid_shell": "Shell baliogabea: {shell}",
"domain_config_default_app_help": "Jendea automatikoki birbideratuko da aplikazio honetara domeinu hau bisitatzerakoan. Aplikaziorik ezarri ezean, jendea saioa hasteko erabiltzaileen atarira birbideratuko da.",
"domain_config_xmpp_help": "Ohart ongi: XMPP ezaugarri batzuk gaitzeko DNS erregistroak eguneratu eta Lets Encrypt ziurtagiria birsortu beharko dira",
"global_settings_setting_dns_exposure": "DNS ezarpenetan eta diagnostikoan kontuan hartzeko IP bertsioak",
"global_settings_setting_dns_exposure_help": "Ohart ongi: honek gomendatutako DNS ezarpenei eta diagnostikoari eragiten die soilik. Ez du eraginik sistemaren ezarpenetan.",
"diagnosis_ip_no_ipv6_tip_important": "IPv6 automatikoki ezarri ohi du sistemak edo hornitzaileak erabilgarri baldin badago. Bestela eskuz ezarri beharko dituzu aukera batzuk ondorengo dokumentazioan azaldu bezala: <a href='https://yunohost.org/#/ipv6'>https://yunohost.org/#/ipv6</a>.",
"pattern_fullname": "Baliozko izen oso bat izan behar da (gutxienez hiru karaktere)",
"app_change_url_failed": "Ezin izan da {app} aplikazioaren URLa aldatu: {error}",
"app_change_url_require_full_domain": "Ezin da {app} aplikazioa URL berri honetara aldatu domeinu oso bat behar duelako (i.e. with path = /)",
"app_change_url_script_failed": "Errorea gertatu da URLa aldatzeko aginduaren barnean"
}

View file

@ -414,7 +414,6 @@
"log_domain_remove": "دامنه '{}' را از پیکربندی سیستم حذف کنید",
"log_domain_add": "دامنه '{}' را به پیکربندی سیستم اضافه کنید",
"log_remove_on_failed_install": "پس از نصب ناموفق '{}' را حذف کنید",
"log_remove_on_failed_restore": "پس از بازیابی ناموفق از بایگانی پشتیبان، '{}' را حذف کنید",
"log_backup_restore_app": "بازیابی '{}' از بایگانی پشتیبان",
"log_backup_restore_system": "بازیابی سیستم بوسیله آرشیو پشتیبان",
"log_backup_create": "بایگانی پشتیبان ایجاد کنید",

View file

@ -27,10 +27,10 @@
"backup_archive_name_unknown": "L'archive locale de sauvegarde nommée '{name}' est inconnue",
"backup_archive_open_failed": "Impossible d'ouvrir l'archive de la sauvegarde",
"backup_cleaning_failed": "Impossible de nettoyer le dossier temporaire de sauvegarde",
"backup_created": "Sauvegarde terminée",
"backup_created": "Sauvegarde créée : {name}",
"backup_creation_failed": "Impossible de créer l'archive de la sauvegarde",
"backup_delete_error": "Impossible de supprimer '{path}'",
"backup_deleted": "La sauvegarde a été supprimée",
"backup_deleted": "Sauvegarde supprimée : {name}",
"backup_hook_unknown": "Script de sauvegarde '{hook}' inconnu",
"backup_nothings_done": "Il n'y a rien à sauvegarder",
"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",
@ -241,7 +241,6 @@
"log_available_on_yunopaste": "Le journal est désormais disponible via {url}",
"log_backup_restore_system": "Restaurer le système depuis une archive de sauvegarde",
"log_backup_restore_app": "Restaurer '{}' depuis une sauvegarde",
"log_remove_on_failed_restore": "Retirer '{}' après un échec de restauration depuis une archive de sauvegarde",
"log_remove_on_failed_install": "Enlever '{}' après une installation échouée",
"log_domain_add": "Ajouter le domaine '{}' dans la configuration du système",
"log_domain_remove": "Enlever le domaine '{}' de la configuration du système",
@ -259,7 +258,7 @@
"log_tools_upgrade": "Mettre à jour les paquets du système",
"log_tools_shutdown": "Éteindre votre serveur",
"log_tools_reboot": "Redémarrer votre serveur",
"mail_unavailable": "Cette adresse e-mail est réservée au groupe des administrateurs",
"mail_unavailable": "Cette adresse email est réservée au groupe des administrateurs",
"good_practices_about_admin_password": "Vous êtes sur le point de définir un nouveau mot de passe administrateur. Le mot de passe doit comporter au moins 8 caractères, bien qu'il soit recommandé d'utiliser un mot de passe plus long (c'est-à-dire une phrase secrète) et/ou d'utiliser une combinaison de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"good_practices_about_user_password": "Vous êtes sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères, bien qu'il soit recommandé d'utiliser un mot de passe plus long (c'est-à-dire une phrase secrète) et/ou une combinaison de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"password_listed": "Ce mot de passe fait partie des mots de passe les plus utilisés dans le monde. Veuillez en choisir un autre moins commun et plus robuste.",
@ -389,7 +388,7 @@
"diagnosis_basesystem_ynh_single_version": "{package} version : {version} ({repo})",
"diagnosis_basesystem_ynh_main_version": "Le serveur utilise YunoHost {main_version} ({repo})",
"diagnosis_basesystem_ynh_inconsistent_versions": "Vous exécutez des versions incohérentes des packages YunoHost ... très probablement en raison d'une mise à niveau échouée ou partielle.",
"diagnosis_failed_for_category": "Échec du diagnostic pour la catégorie '{category}': {error}",
"diagnosis_failed_for_category": "Échec du diagnostic pour la catégorie '{category}' : {error}",
"diagnosis_cache_still_valid": "(Le cache est encore valide pour le diagnostic {category}. Il ne sera pas re-diagnostiqué pour le moment !)",
"diagnosis_ignored_issues": "(+ {nb_ignored} problème(s) ignoré(s))",
"diagnosis_found_warnings": "Trouvé {warnings} objet(s) pouvant être amélioré(s) pour {category}.",
@ -483,7 +482,7 @@
"diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "Certains opérateurs ne vous laisseront pas débloquer le port 25 parce qu'ils ne se soucient pas de la neutralité du Net.<br> - Certains d'entre eux offrent la possibilité d'<a href='https://yunohost.org/#/email_configure_relay'>utiliser un serveur de messagerie relai</a> bien que cela implique que celui-ci sera en mesure d'espionner le trafic de votre 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> - Vous pouvez également envisager de passer à <a href='https://yunohost.org/#/isp'>un fournisseur plus respectueux de la neutralité du net</a>",
"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_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 reverse-proxy n'interfère.",
"diagnosis_mail_fcrdns_nok_alternatives_4": "Certains opérateurs ne vous laisseront pas configurer votre reverse-DNS (ou leur fonctionnalité pourrait être cassée ...). Si vous rencontrez des problèmes à cause de cela, envisagez les solutions suivantes :<br> - Certains FAI offre cette possibilité <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 d'opérateur</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 email.smtp.smtp_allow_ipv6 -v off</cmd>. Remarque : cette dernière solution signifie que vous ne pourrez pas envoyer ou recevoir d'emails avec les quelques serveurs qui ont uniquement de l'IPv6.",
@ -590,7 +589,6 @@
"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 :",
"invalid_number_min": "Doit être supérieur à {min}",
"invalid_number_max": "Doit être inférieur à {max}",
@ -600,7 +598,6 @@
"domain_dns_push_not_applicable": "La fonction de configuration DNS automatique n'est pas applicable au domaine {domain}. Vous devez configurer manuellement vos enregistrements DNS en suivant la documentation sur https://yunohost.org/dns_config.",
"domain_dns_registrar_yunohost": "Ce domaine est de type nohost.me / nohost.st / ynh.fr et sa configuration DNS est donc automatiquement gérée par YunoHost sans qu'il n'y ait d'autre configuration à faire. (voir la commande 'yunohost dyndns update')",
"domain_dns_registrar_supported": "YunoHost a détecté automatiquement que ce domaine est géré par le registrar **{registrar}**. Si vous le souhaitez, YunoHost configurera automatiquement cette zone DNS, si vous lui fournissez les identifiants API appropriés. Vous pouvez trouver de la documentation sur la façon d'obtenir vos identifiants API sur cette page : https://yunohost.org/registar_api_{registrar}. (Vous pouvez également configurer manuellement vos enregistrements DNS en suivant la documentation sur https://yunohost.org/dns )",
"domain_config_features_disclaimer": "Jusqu'à présent, l'activation/désactivation des fonctionnalités de messagerie ou XMPP n'a d'impact que sur la configuration DNS recommandée et automatique, et non sur les configurations système !",
"domain_dns_push_managed_in_parent_domain": "La fonctionnalité de configuration DNS automatique est gérée dans le domaine parent {parent_domain}.",
"domain_dns_registrar_managed_in_parent_domain": "Ce domaine est un sous-domaine de {parent_domain_link}. La configuration du registrar DNS doit être gérée dans le panneau de configuration de {parent_domain}.",
"domain_dns_registrar_not_supported": "YunoHost n'a pas pu détecter automatiquement le bureau d'enregistrement gérant ce domaine. Vous devez configurer manuellement vos enregistrements DNS en suivant la documentation sur https://yunohost.org/dns.",
@ -629,7 +626,7 @@
"diagnosis_http_special_use_tld": "Le domaine {domain} est basé sur un domaine de premier niveau (TLD) à usage spécial tel que .local ou .test et n'est donc pas censé être exposé en dehors du réseau local.",
"domain_dns_conf_special_use_tld": "Ce domaine est basé sur un domaine de premier niveau (TLD) à usage spécial tel que .local ou .test et ne devrait donc pas avoir d'enregistrements DNS réels.",
"other_available_options": "... et {n} autres options disponibles non affichées",
"domain_config_auth_consumer_key": "La clé utilisateur",
"domain_config_auth_consumer_key": "Clé utilisateur",
"domain_unknown": "Domaine '{domain}' inconnu",
"migration_0021_start": "Démarrage de la migration vers Bullseye",
"migration_0021_patching_sources_list": "Mise à jour du fichier sources.lists...",
@ -654,10 +651,10 @@
"tools_upgrade_failed": "Impossible de mettre à jour les paquets : {packages_list}",
"migration_0023_not_enough_space": "Prévoyez suffisamment d'espace disponible dans {path} pour exécuter la migration.",
"migration_0023_postgresql_11_not_installed": "PostgreSQL n'a pas été installé sur votre système. Il n'y a rien à faire.",
"global_settings_setting_backup_compress_tar_archives_help": "Lors de la création de nouvelles sauvegardes, compresser automatiquement les archives (.tar.gz) au lieu des archives non compressées (.tar). N.B. : activer cette option permet de créer des archives plus légères, mais la procédure de sauvegarde initiale sera significativement plus longues et plus gourmandes en CPU.",
"global_settings_setting_backup_compress_tar_archives_help": "Lors de la création de nouvelles sauvegardes, compresser automatiquement les archives (.tar.gz) au lieu des archives non compressées (.tar).\nN.B. : activer cette option permet de créer des archives plus légères, mais la procédure de sauvegarde initiale sera significativement plus longues et plus gourmandes en CPU.",
"global_settings_setting_security_experimental_enabled": "Fonctionnalités de sécurité expérimentales",
"global_settings_setting_security_experimental_enabled_help": "Activer les fonctionnalités de sécurité expérimentales (ne l'activez pas si vous ne savez pas ce que vous faites !)",
"global_settings_setting_nginx_compatibility_help": "Compromis 'compatibilité versus sécurité' pour le serveur web Nginx. Affecte les cryptogrammes utilisés (et d'autres aspects liés à la sécurité)",
"global_settings_setting_nginx_compatibility_help": "Compromis 'compatibilité versus sécurité' pour le serveur web NGINX. Affecte les cryptogrammes utilisés (et d'autres aspects liés à la sécurité)",
"global_settings_setting_nginx_redirect_to_https_help": "Rediriger les requêtes HTTP vers HTTPS par défaut (NE PAS DÉSACTIVER à moins de savoir vraiment ce que vous faites !)",
"global_settings_setting_admin_strength": "Critères pour les mots de passe administrateur",
"global_settings_setting_user_strength": "Critères pour les mots de passe utilisateurs",
@ -710,7 +707,7 @@
"visitors": "Visiteurs",
"global_settings_reset_success": "Réinitialisation des paramètres généraux",
"domain_config_acme_eligible": "Éligibilité au protocole ACME (Automatic Certificate Management Environment, littéralement : environnement de gestion automatique de certificat)",
"domain_config_acme_eligible_explain": "Ce domaine ne semble pas près pour installer un certificat Let's Encrypt. Veuillez vérifier votre configuration DNS mais aussi que votre serveur est bien joignable en HTTP. Les sections 'Enregistrements DNS' et 'Web' de <a href='#/diagnosis'>la page Diagnostic</a> peuvent vous aider à comprendre ce qui est mal configuré.",
"domain_config_acme_eligible_explain": "Ce domaine ne semble pas prêt pour installer un certificat Let's Encrypt. Veuillez vérifier votre configuration DNS mais aussi que votre serveur est bien joignable en HTTP. Les sections 'Enregistrements DNS' et 'Web' de <a href='#/diagnosis'>la page Diagnostic</a> peuvent vous aider à comprendre ce qui est mal configuré.",
"domain_config_cert_install": "Installer un certificat Let's Encrypt",
"domain_config_cert_issuer": "Autorité de certification",
"domain_config_cert_no_checks": "Ignorer les tests et autres vérifications du diagnostic",
@ -738,9 +735,32 @@
"global_settings_setting_smtp_allow_ipv6": "Autoriser l'IPv6",
"password_too_long": "Veuillez choisir un mot de passe de moins de 127 caractères",
"domain_cannot_add_muc_upload": "Vous ne pouvez pas ajouter de domaines commençant par 'muc.'. Ce type de nom est réservé à la fonction de chat XMPP multi-utilisateurs intégrée à YunoHost.",
"group_update_aliases": "Mise à jour des alias du groupe '{group}'.",
"group_update_aliases": "Mise à jour des alias du groupe '{group}'",
"group_no_change": "Rien à mettre à jour pour le groupe '{group}'",
"global_settings_setting_portal_theme": "Thème du portail",
"global_settings_setting_portal_theme_help": "Pour plus d'informations sur la création de thèmes de portail personnalisés, voir https://yunohost.org/theming",
"global_settings_setting_passwordless_sudo": "Permettre aux administrateurs d'utiliser 'sudo' sans retaper leur mot de passe"
"global_settings_setting_passwordless_sudo": "Permettre aux administrateurs d'utiliser 'sudo' sans retaper leur mot de passe",
"app_arch_not_supported": "Cette application ne peut être installée que sur les architectures {required}. L'architecture de votre serveur est {current}",
"app_resource_failed": "L'allocation automatique des ressources (provisioning), la suppression d'accès à ces ressources (déprovisioning) ou la mise à jour des ressources pour {app} a échoué : {error}",
"confirm_app_insufficient_ram": "ATTENTION ! Cette application requiert {required} de RAM pour l'installation/mise à niveau mais il n'y a que {current} de disponible actuellement. Même si cette application pouvait fonctionner, son processus d'installation/mise à niveau nécessite une grande quantité de RAM. Votre serveur pourrait donc geler et planter lamentablement. Si vous êtes prêt à prendre ce risque, tapez '{answers}'",
"app_not_enough_disk": "Cette application nécessite {required} d'espace libre.",
"app_not_enough_ram": "Cette application nécessite {required} de mémoire vive (RAM) pour être installée/mise à niveau mais seule {current} de mémoire est disponible actuellement.",
"app_yunohost_version_not_supported": "Cette application nécessite une version de YunoHost >= {required}. La version installée est {current}",
"confirm_notifications_read": "AVERTISSEMENT : Vous devriez vérifier les notifications de l'application susmentionnée avant de continuer, il pourrait y avoir des informations importantes à connaître. [{answers}]",
"invalid_shell": "Shell invalide : {shell}",
"global_settings_setting_dns_exposure": "Suites d'IP à prendre en compte pour la configuration et le diagnostic du DNS",
"global_settings_setting_dns_exposure_help": "NB : Ceci n'affecte que la configuration DNS recommandée et les vérifications de diagnostic. Cela n'affecte pas les configurations du système.",
"diagnosis_ip_no_ipv6_tip_important": "IPv6 devrait généralement être configuré automatiquement par le système ou par votre fournisseur d'accès à internet (FAI) s'il est disponible. Sinon, vous devrez peut-être configurer quelques éléments manuellement, comme expliqué dans la documentation ici : <a href='https://yunohost.org/#/ipv6'>https://yunohost.org/#/ipv6</a>.",
"domain_config_default_app_help": "Les personnes seront automatiquement redirigées vers cette application lorsqu'elles ouvriront ce domaine. Si aucune application n'est spécifiée, les personnes sont redirigées vers le formulaire de connexion du portail utilisateur.",
"domain_config_xmpp_help": "NB : certaines fonctions XMPP nécessiteront la mise à jour de vos enregistrements DNS et la régénération de votre certificat Lets Encrypt pour être activées",
"app_change_url_failed": "Impossible de modifier l'url de {app} : {error}",
"app_change_url_require_full_domain": "{app} ne peut pas être déplacée vers cette nouvelle URL car elle nécessite un domaine complet (c'est-à-dire avec un chemin = /)",
"app_change_url_script_failed": "Une erreur s'est produite dans le script de modification de l'url",
"app_failed_to_upgrade_but_continue": "La mise à jour de l'application {failed_app} a échoué, mais YunoHost va continuer avec les mises à jour suivantes comme demandé. Lancez 'yunohost log show {operation_logger_name}' pour voir le journal des échecs",
"app_not_upgraded_broken_system_continue": "L'application '{failed_app}' n'a pas réussi à se mettre à jour et a mis le système dans un état alternatif car quelque chose est au moins momentanément \"cassé\" (le paramètre --continue-on-failure est donc ignoré). La conséquence est que les mises à jour des applications suivantes ont été annulées : {apps}",
"app_not_upgraded_broken_system": "L'application '{failed_app}' n'a pas réussi à se mettre à jour et a mis le système dans un état alternatif car quelque chose est au moins momentanément \"cassé\". En conséquence, les mises à jour des applications suivantes ont été annulées : {apps}",
"apps_failed_to_upgrade": "Ces applications n'ont pas pu être mises à jour : {apps}",
"apps_failed_to_upgrade_line": "\n * {app_id} (pour voir le journal/log correspondant, faites un 'yunohost log show {operation_logger_name}')",
"app_failed_to_download_asset": "Échec du téléchargement de la ressource '{source_id}' ({url}) pour {app} : {out}",
"app_corrupt_source": "YunoHost a pu télécharger la ressource '{source_id}' ({url}) pour {app}, malheureusement celle-ci ne correspond pas à la somme de contrôle attendue. Cela peut signifier qu'une défaillance temporaire du réseau s'est produite sur votre serveur, OU que la ressource a été modifiée par le mainteneur de l'application en amont (ou un acteur malveillant ?) et que les responsables du paquet de cette application pour YunoHost doivent investiguer et mettre à jour le manifeste de l'application pour refléter ce changement.\n Somme de contrôle sha256 attendue : {expected_sha256}\n Somme de contrôle sha256 téléchargée : {computed_sha256}\n Taille du fichier téléchargé : {taille}"
}

View file

@ -82,7 +82,7 @@
"app_change_url_success": "A URL de {app} agora é {domain}{path}",
"app_change_url_no_script": "A app '{app_name}' non soporta o cambio de URL. Pode que debas actualizala.",
"app_change_url_identical_domains": "O antigo e o novo dominio/url_path son idénticos ('{domain}{path}'), nada que facer.",
"backup_deleted": "Copia de apoio eliminada",
"backup_deleted": "Copia eliminada: {name}",
"backup_delete_error": "Non se eliminou '{path}'",
"backup_custom_mount_error": "O método personalizado de copia non superou o paso 'mount'",
"backup_custom_backup_error": "O método personalizado da copia non superou o paso 'backup'",
@ -90,7 +90,7 @@
"backup_csv_addition_failed": "Non se engadiron os ficheiros a copiar ao ficheiro CSV",
"backup_creation_failed": "Non se puido crear o arquivo de copia de apoio",
"backup_create_size_estimation": "O arquivo vai conter arredor de {size} de datos.",
"backup_created": "Copia de apoio creada",
"backup_created": "Copia creada: {name}",
"backup_couldnt_bind": "Non se puido ligar {src} a {dest}.",
"backup_copying_to_organize_the_archive": "Copiando {size}MB para organizar o arquivo",
"backup_cleaning_failed": "Non se puido baleirar o cartafol temporal para a copia",
@ -347,7 +347,6 @@
"log_domain_remove": "Eliminar o dominio '{}' da configuración do sistema",
"log_domain_add": "Engadir dominio '{}' á configuración do sistema",
"log_remove_on_failed_install": "Eliminar '{}' tras unha instalación fallida",
"log_remove_on_failed_restore": "Eliminar '{}' tras un intento fallido de restablecemento desde copia",
"log_backup_restore_app": "Restablecer '{}' desde unha copia de apoio",
"log_backup_restore_system": "Restablecer o sistema desde unha copia de apoio",
"log_backup_create": "Crear copia de apoio",
@ -590,7 +589,6 @@
"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.",
"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}",
"diagnosis_http_special_use_tld": "O dominio {domain} baséase nun dominio de alto-nivel (TLD) especial como .local ou .test e por isto non é de agardar que esté exposto fóra da rede local.",
@ -604,7 +602,6 @@
"domain_dns_push_record_failed": "Fallou {action} do rexistro {type}/{name}: {error}",
"domain_dns_push_success": "Rexistros DNS actualizados!",
"domain_dns_push_failed": "Fallou completamente a actualización dos rexistros DNS.",
"domain_config_features_disclaimer": "Ata o momento, activar/desactivar as funcións de email ou XMPP só ten impacto na configuración automática da configuración DNS, non na configuración do sistema!",
"domain_config_mail_in": "Emails entrantes",
"domain_config_mail_out": "Emails saíntes",
"domain_config_xmpp": "Mensaxería instantánea (XMPP)",
@ -741,5 +738,29 @@
"domain_cannot_add_muc_upload": "Non podes engadir dominios que comecen por 'muc.'. Este tipo de dominio está reservado para as salas de conversa de XMPP integradas en YunoHost.",
"global_settings_setting_passwordless_sudo": "Permitir a Admins usar 'sudo' sen ter que volver a escribir o contrasinal",
"global_settings_setting_portal_theme": "Decorado do Portal",
"global_settings_setting_portal_theme_help": "Tes máis info acerca da creación de decorados para o portal de acceso en https://yunohost.org/theming"
"global_settings_setting_portal_theme_help": "Tes máis info acerca da creación de decorados para o portal de acceso en https://yunohost.org/theming",
"app_arch_not_supported": "Esta app só pode ser instalada e arquitecturas {required} pero a arquitectura do teu servidor é {current}",
"app_not_enough_disk": "Esta app precisa {required} de espazo libre.",
"app_yunohost_version_not_supported": "Esta app require YunoHost >= {required} pero a versión actual instalada é {current}",
"confirm_app_insufficient_ram": "PERIGO! Esta app precisa {required} de RAM para instalar/actualizar pero só hai {current} dispoñibles. Incluso se a app funcionase, o seu proceso de instalación/actualización require gran cantidade de RAM e o teu servidor podería colgarse e fallar. Se queres asumir o risco, escribe '{answers}'",
"confirm_notifications_read": "AVISO: Deberías comprobar as notificacións da app antes de continuar, poderías ter información importante que revisar. [{answers}]",
"app_not_enough_ram": "Esta app require {required} de RAM para instalar/actualizar pero só hai {current} dispoñible.",
"global_settings_setting_dns_exposure": "Versións de IP a ter en conta para a configuración DNS e diagnóstico",
"global_settings_setting_dns_exposure_help": "Nota: Esto só lle afecta á configuración DNS recomendada e diagnóstico do sistema. Non lle afecta aos axustes do sistema.",
"diagnosis_ip_no_ipv6_tip_important": "Se está dispoñible, IPv6 debería estar automáticamente configurado polo sistema ou o teu provedor. Se non, pode que teñas que facer algúns axustes manualmente tal como se explica na documentación: <a href='https://yunohost.org/#/ipv6'>https://yunohost.org/#/ipv6</a>.",
"domain_config_default_app_help": "As persoas serán automáticamente redirixidas a esta app ao abrir o dominio. Se non se indica ningunha, serán redirixidas ao formulario de acceso no portal de usuarias.",
"domain_config_xmpp_help": "Nota: algunhas características de XMPP para ser utilizadas precisan que teñas ao día os rexistros DNS e rexeneres os certificados Lets Encrypt",
"app_change_url_failed": "Non se cambiou o url para {app}: {error}",
"app_change_url_require_full_domain": "{app} non se pode mover a este novo URL porque require un dominio completo propio (ex. con ruta = /)",
"app_change_url_script_failed": "Algo fallou ao executar o script de cambio de url",
"apps_failed_to_upgrade_line": "\n * {app_id} (para ver o rexistro correspondente executa 'yunohost log show {operation_logger_name}')",
"app_failed_to_upgrade_but_continue": "Fallou a actualización de {failed_app}, seguimos coas demáis actualizacións. Executa 'yunohost log show {operation_logger_name}' para ver o rexistro do fallo",
"app_not_upgraded_broken_system": "Fallou a actualización de '{failed_app}' e estragou o sistema, como consecuencia cancelouse a actualización das seguintes apps: {apps}",
"app_not_upgraded_broken_system_continue": "Fallou a actualización de '{failed_app}' e estragou o sistema (polo que ignórase --continue-on-failure), como consecuencia cancelouse a actualización das seguintes apps: {apps}",
"apps_failed_to_upgrade": "Fallou a actualización das seguintes aplicacións:{apps}",
"invalid_shell": "Intérprete de ordes non válido: {shell}",
"log_resource_snippet": "Aprovisionamento/desaprovisionamento/actualización dun recurso",
"app_resource_failed": "Fallou o aprovisionamento, desaprovisionamento ou actualización de recursos para {app}: {error}",
"app_failed_to_download_asset": "Fallou a descarga do recurso '{source_id}' ({url}) para {app}: {out}",
"app_corrupt_source": "YunoHost foi quen de descargar o recurso '{source_id}' ({url}) para {app}, pero a suma de comprobación para o recurso non concorda. Pode significar que houbo un fallo temporal na conexión do servidor á rede, OU que o recurso sufreu, dalgún xeito, cambios desde que os desenvolvedores orixinais (ou unha terceira parte maliciosa?), o equipo de YunoHost ten que investigar e actualizar o manifesto da app para mostrar este cambio.\n Suma sha256 agardada: {expected_sha256} \n Suma sha256 do descargado: {computed_sha256}\n Tamaño do ficheiro: {size}"
}

View file

@ -1 +1 @@
{}
{}

View file

@ -233,7 +233,6 @@
"log_available_on_yunopaste": "Questo registro è ora disponibile via {url}",
"log_backup_restore_system": "Ripristina sistema da un archivio di backup",
"log_backup_restore_app": "Ripristina '{}' da un archivio di backup",
"log_remove_on_failed_restore": "Rimuovi '{}' dopo un ripristino fallito da un archivio di backup",
"log_remove_on_failed_install": "Rimuovi '{}' dopo un'installazione fallita",
"log_domain_add": "Aggiungi il dominio '{}' nella configurazione di sistema",
"log_domain_remove": "Rimuovi il dominio '{}' dalla configurazione di sistema",
@ -612,14 +611,12 @@
"domain_dns_push_success": "Record DNS aggiornati!",
"domain_dns_push_failed": "Laggiornamento dei record DNS è miseramente fallito.",
"domain_dns_push_partial_failure": "Record DNS parzialmente aggiornati: alcuni segnali/errori sono stati riportati.",
"domain_config_features_disclaimer": "Per ora, abilitare/disabilitare le impostazioni di posta o XMPP impatta unicamente sulle configurazioni DNS raccomandate o ottimizzate, non cambia quelle di sistema!",
"domain_config_mail_in": "Email in arrivo",
"domain_config_auth_application_key": "Chiave applicazione",
"domain_config_auth_application_secret": "Chiave segreta applicazione",
"domain_config_auth_consumer_key": "Chiave consumatore",
"ldap_attribute_already_exists": "Lattributo LDAP '{attribute}' esiste già con il valore '{value}'",
"config_validate_time": "È necessario inserire un orario valido, come HH:MM",
"config_version_not_supported": "Le versioni '{version}' del pannello di configurazione non sono supportate.",
"danger": "Attenzione:",
"log_domain_config_set": "Aggiorna la configurazione per il dominio '{}'",
"domain_dns_push_managed_in_parent_domain": "La configurazione automatica del DNS è gestita nel dominio genitore {parent_domain}.",
@ -640,5 +637,6 @@
"global_settings_setting_webadmin_allowlist_enabled_help": "Permetti solo ad alcuni IP di accedere al webadmin.",
"global_settings_setting_smtp_allow_ipv6_help": "Permetti l'utilizzo di IPv6 per ricevere e inviare mail",
"global_settings_setting_smtp_relay_enabled_help": "Utilizza SMTP relay per inviare mail al posto di questa instanza yunohost. Utile se sei in una di queste situazioni: la tua porta 25 è bloccata dal tuo provider ISP o VPS; hai un IP residenziale listato su DUHL; non sei puoi configurare il DNS inverso; oppure questo server non è direttamente esposto a Internet e vuoi usarne un'altro per spedire email.",
"domain_config_default_app": "Applicazione di default"
"domain_config_default_app": "Applicazione di default",
"app_change_url_failed": "Non è possibile cambiare l'URL per {app}:{error}"
}

1
locales/lt.json Normal file
View file

@ -0,0 +1 @@
{}

View file

@ -29,7 +29,6 @@
"downloading": "Laster ned…",
"dyndns_could_not_check_available": "Kunne ikke sjekke om {domain} er tilgjengelig på {provider}.",
"mail_domain_unknown": "Ukjent e-postadresse for domenet '{domain}'",
"log_remove_on_failed_restore": "Fjern '{}' etter mislykket gjenoppretting fra sikkerhetskopiarkiv",
"log_letsencrypt_cert_install": "Installer et Let's Encrypt-sertifikat på '{}'-domenet",
"log_letsencrypt_cert_renew": "Forny '{}'-Let's Encrypt-sertifikat",
"log_user_update": "Oppdater brukerinfo for '{}'",

View file

@ -139,4 +139,4 @@
"group_already_exist_on_system": "Groep {group} bestaat al in de systeemgroepen",
"good_practices_about_admin_password": "Je gaat nu een nieuw beheerderswachtwoordopgeven. Het wachtwoord moet minimaal 8 tekens lang zijn, hoewel het een goede gewoonte is om een langer wachtwoord te gebruiken (d.w.z. een wachtwoordzin) en/of een variatie van tekens te gebruiken (hoofdletters, kleine letters, cijfers en speciale tekens).",
"good_practices_about_user_password": "Je gaat nu een nieuw gebruikerswachtwoord pgeven. Het wachtwoord moet minimaal 8 tekens lang zijn, hoewel het een goede gewoonte is om een langer wachtwoord te gebruiken (d.w.z. een wachtwoordzin) en/of een variatie van tekens te gebruiken (hoofdletters, kleine letters, cijfers en speciale tekens)."
}
}

View file

@ -238,7 +238,6 @@
"log_available_on_yunopaste": "Lo jornal es ara disponible via {url}",
"log_backup_restore_system": "Restaurar lo sistèma a partir duna salvagarda",
"log_backup_restore_app": "Restaurar « {} » a partir duna salvagarda",
"log_remove_on_failed_restore": "Levar « {} » aprèp un fracàs de restauracion a partir duna salvagarda",
"log_remove_on_failed_install": "Tirar « {} » aprèp una installacion pas reüssida",
"log_domain_add": "Ajustar lo domeni « {} » dins la configuracion sistèma",
"log_domain_remove": "Tirar lo domeni « {} » da la configuracion sistèma",
@ -380,7 +379,7 @@
"diagnosis_services_bad_status": "Lo servici {service} es {status} :(",
"diagnosis_swap_ok": "Lo sistèma a {total} descambi !",
"diagnosis_regenconf_allgood": "Totes los fichièrs de configuracion son confòrmes a la configuracion recomandada !",
"diagnosis_regenconf_manually_modified": "Lo fichièr de configuracion {file} foguèt modificat manualament.",
"diagnosis_regenconf_manually_modified": "Lo fichièr de configuracion <code>{file}</code> foguèt modificat manualament.",
"diagnosis_regenconf_manually_modified_details": "Es probablament bon tan que sabètz çò que fasètz ;) !",
"diagnosis_security_vulnerable_to_meltdown": "Semblatz èsser vulnerable a la vulnerabilitat de seguretat critica de Meltdown",
"diagnosis_description_basesystem": "Sistèma de basa",

View file

@ -1,9 +1,183 @@
{
"password_too_simple_1": "Hasło musi mieć co najmniej 8 znaków",
"app_already_up_to_date": "{app} jest obecnie aktualna",
"app_already_installed": "{app} jest już zainstalowane",
"app_already_installed": "{app} jest już zainstalowana",
"already_up_to_date": "Nic do zrobienia. Wszystko jest obecnie aktualne.",
"admin_password": "Hasło administratora",
"action_invalid": "Nieprawidłowe działanie '{action:s}'",
"aborting": "Przerywanie."
"aborting": "Przerywanie.",
"domain_config_auth_consumer_key": "Klucz konsumenta",
"domain_config_cert_validity": "Ważność",
"visitors": "Odwiedzający",
"app_start_install": "Instalowanie {app}...",
"app_unknown": "Nieznana aplikacja",
"ask_main_domain": "Domena główna",
"backup_created": "Utworzono kopię zapasową: {name}",
"firewall_reloaded": "Przeładowano zaporę sieciową",
"user_created": "Utworzono użytkownika",
"yunohost_installing": "Instalowanie YunoHost...",
"global_settings_setting_smtp_allow_ipv6": "Zezwól na IPv6",
"user_deleted": "Usunięto użytkownika",
"domain_config_default_app": "Domyślna aplikacja",
"restore_complete": "Przywracanie zakończone",
"domain_deleted": "Usunięto domenę",
"domains_available": "Dostępne domeny:",
"domain_config_api_protocol": "API protokołu",
"domain_config_auth_application_key": "Klucz aplikacji",
"diagnosis_description_systemresources": "Zasoby systemu",
"log_user_import": "Importuj użytkowników",
"system_upgraded": "Zaktualizowano system",
"diagnosis_description_regenconf": "Konfiguracja systemu",
"diagnosis_description_apps": "Aplikacje",
"diagnosis_description_basesystem": "Podstawowy system",
"unlimit": "Brak limitu",
"global_settings_setting_pop3_enabled": "Włącz POP3",
"domain_created": "Utworzono domenę",
"ask_new_admin_password": "Nowe hasło administracyjne",
"ask_new_domain": "Nowa domena",
"ask_new_path": "Nowa ścieżka",
"downloading": "Pobieranie...",
"ask_password": "Hasło",
"backup_deleted": "Usunięto kopię zapasową: {name}.",
"done": "Gotowe",
"diagnosis_description_dnsrecords": "Rekordy DNS",
"diagnosis_description_ip": "Połączenie z internetem",
"diagnosis_description_mail": "Email",
"diagnosis_mail_ehlo_could_not_diagnose_details": "Błąd: {error}",
"diagnosis_mail_queue_unavailable_details": "Błąd: {error}",
"diagnosis_http_could_not_diagnose_details": "Błąd: {error}",
"installation_complete": "Instalacja zakończona",
"app_start_remove": "Usuwanie {app}...",
"app_start_restore": "Przywracanie {app}...",
"app_upgraded": "Zaktualizowano {app}",
"extracting": "Rozpakowywanie...",
"app_removed": "Odinstalowano {app}",
"upgrade_complete": "Aktualizacja zakończona",
"global_settings_setting_backup_compress_tar_archives": "Kompresuj kopie zapasowe",
"global_settings_setting_nginx_compatibility": "Kompatybilność z NGINX",
"global_settings_setting_nginx_redirect_to_https": "Wymuszaj HTTPS",
"ask_admin_username": "Nazwa użytkownika administratora",
"ask_fullname": "Pełne imię i nazwisko",
"upgrading_packages": "Aktualizowanie paczek...",
"admins": "Administratorzy",
"diagnosis_ports_could_not_diagnose_details": "Błąd: {error}",
"log_settings_set": "Zastosuj ustawienia",
"domain_config_cert_issuer": "Organ certyfikacji",
"domain_config_cert_summary": "Status certyfikatu",
"global_settings_setting_ssh_compatibility": "Kompatybilność z SSH",
"global_settings_setting_ssh_port": "Port SSH",
"log_settings_reset": "Resetuj ustawienia",
"log_tools_migrations_migrate_forward": "Uruchom migracje",
"app_action_cannot_be_ran_because_required_services_down": "Następujące usługi powinny być uruchomione, aby rozpocząć to działanie: {services}. Spróbuj uruchomić je ponownie aby kontynuować (i dowiedzieć się, dlaczego były one wyłączone)",
"app_argument_choice_invalid": "Wybierz poprawną wartość dla argumentu '{name}': '{value}' nie znajduje się w liście poprawnych opcji ({choices})",
"app_action_broke_system": "Wydaje się, że ta akcja przerwała te ważne usługi: {services}",
"additional_urls_already_removed": "Dodatkowy URL '{url}' już usunięty w dodatkowym URL dla uprawnienia '{permission}'",
"additional_urls_already_added": "Dodatkowy URL '{url}' już dodany w dodatkowym URL dla uprawnienia '{permission}'",
"app_arch_not_supported": "Ta aplikacja może być zainstalowana tylko na architekturach {required}, a twoja architektura serwera to {current}",
"app_argument_invalid": "Wybierz poprawną wartość dla argumentu '{name}': {error}",
"all_users": "Wszyscy użytkownicy YunoHost",
"app_action_failed": "Nie udało się uruchomić akcji {action} dla aplikacji {app}",
"app_already_installed_cant_change_url": "Ta aplikacja jest już zainstalowana. URL nie może zostać zmieniony przy użyciu tej funkcji. Sprawdź czy można zmienić w `app changeurl`",
"app_id_invalid": "Nieprawidłowy identyfikator aplikacji(ID)",
"app_change_url_require_full_domain": "Nie można przenieść aplikacji {app} na nowy adres URL, ponieważ wymaga ona pełnej domeny (tj. ze ścieżką = /)",
"app_install_files_invalid": "Tych plików nie można zainstalować",
"app_make_default_location_already_used": "Nie można ustawić '{app}' jako domyślnej aplikacji w domenie '{domain}' ponieważ jest już używana przez '{other_app}'",
"app_change_url_identical_domains": "Stara i nowa domena/ścieżka_url są identyczne („{domain}{path}”), nic nie trzeba robić.",
"app_config_unable_to_read": "Nie udało się odczytać wartości panelu konfiguracji.",
"app_config_unable_to_apply": "Nie udało się zastosować wartości panelu konfiguracji.",
"app_install_failed": "Nie udało się zainstalować {app}: {error}",
"apps_catalog_failed_to_download": "Nie można pobrać katalogu aplikacji app catalog: {error}",
"app_argument_required": "Argument „{name}” jest wymagany",
"app_not_properly_removed": "Aplikacja {app} nie została poprawnie usunięta",
"app_upgrade_failed": "Nie można uaktualnić {app}: {error}",
"backup_abstract_method": "Ta metoda tworzenia kopii zapasowych nie została jeszcze zaimplementowana",
"backup_actually_backuping": "Tworzenie archiwum kopii zapasowej z zebranych plików...",
"backup_applying_method_copy": "Kopiowanie wszystkich plików do kopii zapasowej...",
"backup_applying_method_tar": "Tworzenie kopii zapasowej archiwum TAR..",
"backup_archive_app_not_found": "Nie można znaleźć aplikacji {app} w archiwum kopii zapasowych",
"backup_archive_broken_link": "Nie można uzyskać dostępu do archiwum kopii zapasowych (broken link to {path})",
"backup_csv_addition_failed": "Nie udało się dodać plików do kopii zapasowej do pliku CSV.",
"backup_creation_failed": "Nie udało się utworzyć archiwum kopii zapasowej",
"backup_csv_creation_failed": "Nie udało się utworzyć wymaganego pliku CSV do przywracania.",
"backup_custom_mount_error": "Niestandardowa metoda tworzenia kopii zapasowej nie mogła przejść etapu „mount”",
"backup_applying_method_custom": "Wywołuję niestandardową metodę tworzenia kopii zapasowych '{method}'...",
"app_remove_after_failed_install": "Usuwanie aplikacji po niepowodzeniu instalacji...",
"app_upgrade_script_failed": "Wystąpił błąd w skrypcie aktualizacji aplikacji",
"apps_catalog_init_success": "Zainicjowano system katalogu aplikacji!",
"apps_catalog_obsolete_cache": "Pamięć podręczna katalogu aplikacji jest pusta lub przestarzała.",
"app_extraction_failed": "Nie można wyodrębnić plików instalacyjnych",
"app_packaging_format_not_supported": "Ta aplikacja nie może zostać zainstalowana, ponieważ jej format opakowania nie jest obsługiwany przez twoją wersję YunoHost. Prawdopodobnie powinieneś rozważyć aktualizację swojego systemu.",
"app_manifest_install_ask_domain": "Wybierz domenę, w której ta aplikacja ma zostać zainstalowana",
"app_manifest_install_ask_admin": "Wybierz użytkownika administratora dla tej aplikacji",
"app_manifest_install_ask_password": "Wybierz hasło administratora dla tej aplikacji",
"app_manifest_install_ask_is_public": "Czy ta aplikacja powinna być udostępniana anonimowym użytkownikom?",
"ask_user_domain": "Domena używana dla adresu e-mail użytkownika i konta XMPP",
"app_upgrade_app_name": "Aktualizuję {app}...",
"app_install_script_failed": "Wystąpił błąd w skrypcie instalacyjnym aplikacji",
"apps_catalog_update_success": "Katalog aplikacji został zaktualizowany!",
"apps_catalog_updating": "Aktualizowanie katalogu aplikacji...",
"app_label_deprecated": "To polecenie jest przestarzałe! Użyj nowego polecenia „yunohost user permission update”, aby zarządzać etykietą aplikacji.",
"app_change_url_no_script": "Aplikacja „{app_name}” nie obsługuje jeszcze modyfikacji adresów URL. Możesz spróbować ją zaaktualizować.",
"app_change_url_success": "Adres URL aplikacji {app} to teraz {domain}{path}",
"app_not_upgraded": "Nie udało się zaktualizować aplikacji „{failed_app}”, w związku z czym anulowano aktualizacje następujących aplikacji: {apps}",
"app_upgrade_several_apps": "Następujące aplikacje zostaną uaktualnione: {apps}",
"app_not_correctly_installed": "Wygląda na to, że aplikacja {app} jest nieprawidłowo zainstalowana",
"app_not_installed": "Nie można znaleźć aplikacji {app} na liście zainstalowanych aplikacji: {all_apps}",
"app_requirements_checking": "Sprawdzam wymagania dla aplikacji {app}...",
"app_upgrade_some_app_failed": "Niektórych aplikacji nie udało się zaktualizować",
"backup_app_failed": "Nie udało się utworzyć kopii zapasowej {app}",
"backup_archive_name_exists": "Archiwum kopii zapasowych o tej nazwie już istnieje.",
"backup_archive_open_failed": "Nie można otworzyć archiwum kopii zapasowej",
"backup_archive_writing_error": "Nie udało się dodać plików '{source}' (nazwanych w archiwum '{dest}') do utworzenia kopii zapasowej skompresowanego archiwum '{archive}'",
"backup_ask_for_copying_if_needed": "Czy chcesz wykonać kopię zapasową tymczasowo używając {size} MB? (Ta metoda jest stosowana, ponieważ niektóre pliki nie mogły zostać przygotowane przy użyciu bardziej wydajnej metody.)",
"backup_cant_mount_uncompress_archive": "Nie można zamontować nieskompresowanego archiwum jako chronione przed zapisem",
"backup_copying_to_organize_the_archive": "Kopiowanie {size} MB w celu zorganizowania archiwum",
"backup_couldnt_bind": "Nie udało się powiązać {src} z {dest}.",
"backup_archive_corrupted": "Wygląda na to, że archiwum kopii zapasowej '{archive}' jest uszkodzone: {error}",
"backup_cleaning_failed": "Nie udało się wyczyścić folderu tymczasowej kopii zapasowej",
"backup_create_size_estimation": "Archiwum będzie zawierać około {size} danych.",
"app_location_unavailable": "Ten adres URL jest niedostępny lub powoduje konflikt z już zainstalowanymi aplikacja(mi):\n{apps}",
"app_restore_failed": "Nie można przywrócić {app}: {error}",
"app_restore_script_failed": "Wystąpił błąd w skrypcie przywracania aplikacji",
"app_full_domain_unavailable": "Przepraszamy, ta aplikacja musi być zainstalowana we własnej domenie, ale inna aplikacja jest już zainstalowana w tej domenie „{domain}”. Zamiast tego możesz użyć subdomeny dedykowanej tej aplikacji.",
"app_resource_failed": "Nie udało się zapewnić, anulować obsługi administracyjnej lub zaktualizować zasobów aplikacji {app}: {error}",
"app_manifest_install_ask_path": "Wybierz ścieżkę adresu URL (po domenie), w której ta aplikacja ma zostać zainstalowana",
"app_not_enough_disk": "Ta aplikacja wymaga {required} wolnego miejsca.",
"app_not_enough_ram": "Ta aplikacja wymaga {required} pamięci RAM do zainstalowania/uaktualnienia, ale obecnie dostępna jest tylko {current}.",
"app_start_backup": "Zbieram pliki do utworzenia kopii zapasowej dla {app}...",
"app_yunohost_version_not_supported": "Ta aplikacja wymaga YunoHost >= {required}, ale aktualnie zainstalowana wersja to {current}",
"apps_already_up_to_date": "Wszystkie aplikacje są już aktualne",
"backup_archive_system_part_not_available": "Część systemowa '{part}' jest niedostępna w tej kopii zapasowej",
"backup_custom_backup_error": "Niestandardowa metoda tworzenia kopii zapasowej nie mogła przejść kroku 'backup'.",
"app_argument_password_no_default": "Błąd podczas analizowania argumentu hasła „{name}”: argument hasła nie może mieć wartości domyślnej ze względów bezpieczeństwa",
"app_sources_fetch_failed": "Nie można pobrać plików źródłowych, czy adres URL jest poprawny?",
"app_manifest_install_ask_init_admin_permission": "Kto powinien mieć dostęp do funkcji administracyjnych tej aplikacji? (Można to później zmienić)",
"app_manifest_install_ask_init_main_permission": "Kto powinien mieć dostęp do tej aplikacji? (Można to później zmienić)",
"ask_admin_fullname": "Pełne imię i nazwisko administratora",
"app_change_url_failed": "Nie udało się zmienić adresu URL aplikacji {app}: {error}",
"app_change_url_script_failed": "Wystąpił błąd w skrypcie zmiany adresu URL",
"app_failed_to_upgrade_but_continue": "Nie udało zaktualizować się aplikacji {failed_app}, przechodzenie do następnych aktualizacji według żądania. Uruchom komendę 'yunohost log show {operation_logger_name}', aby sprawdzić logi dotyczące błędów",
"certmanager_cert_signing_failed": "Nie udało się zarejestrować nowego certyfikatu",
"certmanager_cert_renew_success": "Pomyślne odnowienie certyfikatu Let's Encrypt dla domeny '{domain}'",
"backup_delete_error": "Nie udało się usunąć '{path}'",
"certmanager_attempt_to_renew_nonLE_cert": "Certyfikat dla domeny '{domain}' nie został wystawiony przez Let's Encrypt. Automatyczne odnowienie jest niemożliwe!",
"backup_archive_cant_retrieve_info_json": "Nieudane wczytanie informacji dla archiwum '{archive}'... Plik info.json nie może zostać odzyskany (lub jest niepoprawny).",
"backup_method_custom_finished": "Tworzenie kopii zapasowej według własnej metody '{method}' zakończone",
"backup_nothings_done": "Brak danych do zapisania",
"app_unsupported_remote_type": "Niewspierany typ zdalny użyty w aplikacji",
"backup_archive_name_unknown": "Nieznane, lokalne archiwum kopii zapasowej o nazwie '{name}'",
"backup_output_directory_not_empty": "Należy wybrać pusty katalog dla danych wyjściowych",
"certmanager_attempt_to_renew_valid_cert": "Certyfikat dla domeny '{domain}' nie jest bliski wygaśnięciu! (Możesz użyć komendy z dopiskiem --force jeśli wiesz co robisz)",
"certmanager_cert_install_success": "Pomyślna instalacja certyfikatu Let's Encrypt dla domeny '{domain}'",
"certmanager_attempt_to_replace_valid_cert": "Właśnie zamierzasz nadpisać dobry i poprawny certyfikat dla domeny '{domain}'! (Użyj komendy z dopiskiem --force, aby ominąć)",
"backup_method_copy_finished": "Zakończono tworzenie kopii zapasowej",
"certmanager_certificate_fetching_or_enabling_failed": "Próba użycia nowego certyfikatu dla {domain} zakończyła się niepowodzeniem...",
"backup_method_tar_finished": "Utworzono archiwum kopii zapasowej TAR",
"backup_mount_archive_for_restore": "Przygotowywanie archiwum do przywrócenia...",
"certmanager_cert_install_failed": "Nieudana instalacja certyfikatu Let's Encrypt dla {domains}",
"certmanager_cert_install_failed_selfsigned": "Nieudana instalacja certyfikatu self-signed dla {domains}",
"certmanager_cert_install_success_selfsigned": "Pomyślna instalacja certyfikatu self-signed dla domeny '{domain}'",
"certmanager_cert_renew_failed": "Nieudane odnowienie certyfikatu Let's Encrypt dla {domains}",
"apps_failed_to_upgrade": "Nieudana aktualizacja aplikacji: {apps}",
"backup_output_directory_required": "Musisz wybrać katalog dla kopii zapasowej"
}

View file

@ -204,7 +204,6 @@
"config_cant_set_value_on_section": "Você não pode setar um único valor na seção de configuração inteira.",
"config_validate_time": "Deve ser um horário válido como HH:MM",
"config_validate_url": "Deve ser uma URL válida",
"config_version_not_supported": "Versões do painel de configuração '{version}' não são suportadas.",
"danger": "Perigo:",
"diagnosis_basesystem_ynh_inconsistent_versions": "Você está executando versões inconsistentes dos pacotes YunoHost... provavelmente por causa de uma atualização parcial ou que falhou.",
"diagnosis_description_basesystem": "Sistema base",
@ -247,4 +246,4 @@
"certmanager_cert_renew_success": "Certificado Let's Encrypt renovado para o domínio '{domain}'",
"certmanager_warning_subdomain_dns_record": "O subdomínio '{subdomain}' não resolve para o mesmo IP que '{domain}'. Algumas funcionalidades não estarão disponíveis até que você conserte isto e regenere o certificado.",
"admins": "Admins"
}
}

View file

@ -1 +1 @@
{}
{}

View file

@ -106,7 +106,6 @@
"certmanager_domain_dns_ip_differs_from_public_ip": "DNS-записи для домена '{domain}' отличаются от IP этого сервера. Пожалуйста, проверьте категорию 'DNS-записи' (основные) в диагностике для получения дополнительной информации. Если вы недавно изменили свою A-запись, пожалуйста, подождите, пока она распространится (некоторые программы проверки распространения DNS доступны в интернете). (Если вы знаете, что делаете, используйте '--no-checks', чтобы отключить эти проверки.)",
"certmanager_domain_not_diagnosed_yet": "Для домена {domain} еще нет результатов диагностики. Пожалуйста, перезапустите диагностику для категорий 'DNS-записи' и 'Домены', чтобы проверить, готов ли домен к Let's Encrypt. (Или, если вы знаете, что делаете, используйте '--no-checks', чтобы отключить эти проверки.)",
"config_validate_url": "Должна быть правильная ссылка",
"config_version_not_supported": "Версии конфигурационной панели '{version}' не поддерживаются.",
"confirm_app_install_danger": "ОПАСНО! Это приложение все еще является экспериментальным (если не сказать, что оно явно не работает)! Вам НЕ следует устанавливать его, если вы НЕ знаете, что делаете. Если это приложение не будет работать или сломает вашу систему, мы НЕ будем оказывать техническую поддержку... Если вы все равно готовы рискнуть, введите '{answers}'",
"confirm_app_install_thirdparty": "ВАЖНО! Это приложение не входит в каталог приложений YunoHost. Установка сторонних приложений может нарушить целостность и безопасность вашей системы. Вам НЕ следует устанавливать его, если вы НЕ знаете, что делаете. Если это приложение не будет работать или сломает вашу систему, мы НЕ будем оказывать техническую поддержку... Если вы все равно готовы рискнуть, введите '{answers}'",
"config_apply_failed": "Не удалось применить новую конфигурацию: {error}",

View file

@ -144,7 +144,6 @@
"config_validate_email": "Toto by mal byť platný e-mail",
"config_validate_time": "Toto by mal byť platný čas vo formáte HH:MM",
"config_validate_url": "Toto by mala byť platná URL adresa webu",
"config_version_not_supported": "Verzie konfiguračného panela '{version}' nie sú podporované.",
"danger": "Nebezpečenstvo:",
"confirm_app_install_danger": "NEBEZPEČENSTVO! Táto aplikácia je experimentálna (ak vôbec funguje)! Pravdepodobne by ste ju NEMALI inštalovať, pokiaľ si nie ste istý, čo robíte. NEPOSKYTNEME VÁM ŽIADNU POMOC, ak táto aplikácia nebude fungovať alebo rozbije Váš systém… Ak sa rozhodnete i napriek tomu podstúpiť toto riziko, zadajte '{answers}'",
"confirm_app_install_thirdparty": "NEBEZPEČENSTVO! Táto aplikácia nie je súčasťou katalógu aplikácií YunoHost. Inštalovaním aplikácií tretích strán môžete ohroziť integritu a bezpečnosť Vášho systému. Pravdepodobne by ste NEMALI pokračovať v inštalácií, pokiaľ neviete, čo robíte. NEPOSKYTNEME VÁM ŽIADNU POMOC, ak táto aplikácia nebude fungovať alebo rozbije Váš systém… Ak sa rozhodnete i napriek tomu podstúpiť toto riziko, zadajte '{answers}'",
@ -250,4 +249,4 @@
"all_users": "Všetci používatelia YunoHost",
"app_manifest_install_ask_init_main_permission": "Kto má mať prístup k tejto aplikácii? (Nastavenie môžete neskôr zmeniť)",
"certmanager_cert_install_failed": "Inštalácia Let's Encrypt certifikátu pre {domains} skončila s chybou"
}
}

View file

@ -5,5 +5,15 @@
"already_up_to_date": "Yapılacak yeni bir şey yok. Her şey zaten güncel.",
"app_action_broke_system": "Bu işlem bazı hizmetleri bozmuş olabilir: {services}",
"good_practices_about_user_password": "Şimdi yeni bir kullanıcı şifresi tanımlamak üzeresiniz. Parola en az 8 karakter uzunluğunda olmalıdır - ancak daha uzun bir parola (yani bir parola) ve/veya çeşitli karakterler (büyük harf, küçük harf, rakamlar ve özel karakterler) daha iyidir.",
"aborting": "İptal ediliyor."
"aborting": "İptal ediliyor.",
"app_action_failed": "{app} uygulaması için {action} eylemini çalıştırma başarısız",
"admins": "Yöneticiler",
"all_users": "Tüm YunoHost kullanıcıları",
"app_already_up_to_date": "{app} zaten güncel",
"app_already_installed": "{app} zaten kurulu",
"app_already_installed_cant_change_url": "Bu uygulama zaten kurulu. URL yalnızca bu işlev kullanarak değiştirilemez. Eğer varsa `app changeurl`'i kontrol edin.",
"additional_urls_already_added": "Ek URL '{url}' zaten '{permission}' izni için ek URL'ye eklendi",
"additional_urls_already_removed": "Ek URL '{url}', '{permission}' izni için ek URL'de zaten kaldırıldı",
"app_action_cannot_be_ran_because_required_services_down": "Bu eylemi gerçekleştirmek için şu servisler çalışıyor olmalıdır: {services}. Devam etmek için onları yeniden başlatın (ve muhtemelen neden çalışmadığını araştırın).",
"app_arch_not_supported": "Bu uygulama yalnızca {required} işlemci mimarisi üzerine kurulabilir ancak sunucunuzun işlemci mimarisi {current}."
}

View file

@ -191,7 +191,6 @@
"log_domain_remove": "Вилучення домену '{}' з конфігурації системи",
"log_domain_add": "Додавання домену '{}' в конфігурацію системи",
"log_remove_on_failed_install": "Вилучення '{}' після невдалого встановлення",
"log_remove_on_failed_restore": "Вилучення '{}' після невдалого відновлення з резервного архіву",
"log_backup_restore_app": "Відновлення '{}' з архіву резервних копій",
"log_backup_restore_system": "Відновлення системи з резервного архіву",
"log_backup_create": "Створення резервного архіву",
@ -235,7 +234,7 @@
"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_setting_smtp_relay_password": "Пароль SMTP-ретрансляції",
"global_settings_setting_smtp_relay_user": "Користувач SMTP-ретрансляції",
"global_settings_setting_smtp_relay_port": "Порт SMTP-ретрансляції",
@ -279,7 +278,7 @@
"domain_cannot_remove_main": "Ви не можете вилучити '{domain}', бо це основний домен, спочатку вам потрібно встановити інший домен в якості основного за допомогою 'yunohost domain main-domain -n <inshyi-domen>'; ось список доменів-кандидатів: {other_domains}",
"disk_space_not_sufficient_update": "Недостатньо місця на диску для оновлення цього застосунку",
"disk_space_not_sufficient_install": "Недостатньо місця на диску для встановлення цього застосунку",
"diagnosis_sshd_config_inconsistent_details": "Будь ласка, виконайте команду <cmd>yunohost settings set security.ssh.ssh port -v YOUR_SSH_PORT</cmd>, щоб визначити порт SSH, і перевірте<cmd>yunohost tools regen-conf ssh --dry-run --with-diff</cmd> і <cmd>yunohost tools regen-conf ssh --force</cmd>, щоб скинути ваш конфіг на рекомендований YunoHost.",
"diagnosis_sshd_config_inconsistent_details": "Будь ласка, виконайте команду <cmd>yunohost settings set security.ssh.ssh port -v ВАШ_SSH_ПОРТ</cmd>, щоб визначити порт SSH, і перевірте<cmd>yunohost tools regen-conf ssh --dry-run --with-diff</cmd> і <cmd>yunohost tools regen-conf ssh --force</cmd>, щоб скинути ваш конфіг на рекомендований YunoHost.",
"diagnosis_sshd_config_inconsistent": "Схоже, що порт SSH був уручну змінений в /etc/ssh/sshd_config. Починаючи з версії YunoHost 4.2, доступний новий глобальний параметр 'security.ssh.ssh port', що дозволяє уникнути ручного редагування конфігурації.",
"diagnosis_sshd_config_insecure": "Схоже, що конфігурація SSH була змінена вручну і є небезпечною, оскільки не містить директив 'AllowGroups' або 'AllowUsers' для обмеження доступу авторизованих користувачів.",
"diagnosis_processes_killed_by_oom_reaper": "Деякі процеси було недавно вбито системою через брак пам'яті. Зазвичай це є симптомом нестачі пам'яті в системі або процесу, який з'їв дуже багато пам'яті. Зведення убитих процесів:\n{kills_summary}",
@ -347,7 +346,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 diagnosis run' в командному рядку);\n - прочитання розділів 'Завершення встановлення' і 'Знайомство з YunoHost' у документації адміністратора: https://yunohost.org/admindoc.",
"yunohost_not_installed": "YunoHost установлений неправильно. Будь ласка, запустіть 'yunohost tools postinstall'",
"yunohost_installing": "Установлення YunoHost...",
"yunohost_configured": "YunoHost вже налаштовано",
@ -489,7 +488,7 @@
"backup_method_custom_finished": "Користувацький спосіб резервного копіювання '{method}' завершено",
"backup_method_copy_finished": "Резервне копіювання завершено",
"backup_hook_unknown": "Гачок (hook) резервного копіювання '{hook}' невідомий",
"backup_deleted": "Резервна копія видалена",
"backup_deleted": "Резервна копія '{name}' видалена",
"backup_delete_error": "Не вдалося видалити '{path}'",
"backup_custom_mount_error": "Користувацький спосіб резервного копіювання не зміг пройти етап 'монтування'",
"backup_custom_backup_error": "Користувацький спосіб резервного копіювання не зміг пройти етап 'резервне копіювання'",
@ -497,7 +496,7 @@
"backup_csv_addition_failed": "Не вдалося додати файли для резервного копіювання в CSV-файл",
"backup_creation_failed": "Не вдалося створити архів резервного копіювання",
"backup_create_size_estimation": "Архів буде містити близько {size} даних.",
"backup_created": "Резервна копія створена",
"backup_created": "Резервна копія '{name}' створена",
"backup_couldnt_bind": "Не вдалося зв'язати {src} з {dest}.",
"backup_copying_to_organize_the_archive": "Копіювання {size} МБ для організації архіву",
"backup_cleaning_failed": "Не вдалося очистити тимчасовий каталог резервного копіювання",
@ -587,7 +586,6 @@
"config_validate_email": "Е-пошта має бути дійсною",
"config_validate_time": "Час має бути дійсним, наприклад ГГ:ХХ",
"config_validate_url": "Вебадреса має бути дійсною",
"config_version_not_supported": "Версії конфігураційної панелі '{version}' не підтримуються.",
"danger": "Небезпека:",
"invalid_number_min": "Має бути більшим за {min}",
"invalid_number_max": "Має бути меншим за {max}",
@ -614,7 +612,6 @@
"domain_dns_push_failed_to_authenticate": "Неможливо пройти автентифікацію на API реєстратора для домену '{domain}'. Ймовірно, облікові дані недійсні? (Помилка: {error})",
"domain_dns_push_failed_to_list": "Не вдалося скласти список поточних записів за допомогою API реєстратора: {error}",
"domain_dns_push_record_failed": "Не вдалося виконати дію {action} запису {type}/{name} : {error}",
"domain_config_features_disclaimer": "Поки що вмикання/вимикання функцій пошти або XMPP впливає тільки на рекомендовану та автоконфігурацію DNS, але не на конфігурацію системи!",
"domain_config_xmpp": "Миттєвий обмін повідомленнями (XMPP)",
"domain_config_auth_key": "Ключ автентифікації",
"domain_config_auth_secret": "Секрет автентифікації",
@ -657,7 +654,7 @@
"global_settings_setting_admin_strength": "Надійність пароля адміністратора",
"global_settings_setting_user_strength": "Надійність пароля користувача",
"global_settings_setting_postfix_compatibility_help": "Компроміс між сумісністю і безпекою для сервера Postfix. Впливає на шифри (і інші аспекти, пов'язані з безпекою)",
"global_settings_setting_ssh_compatibility_help": "Компроміс між сумісністю і безпекою для SSH-сервера. Впливає на шифри (і інші аспекти, пов'язані з безпекою)",
"global_settings_setting_ssh_compatibility_help": "Компроміс між сумісністю і безпекою для SSH-сервера. Впливає на шифри (і інші аспекти, пов'язані з безпекою).",
"global_settings_setting_ssh_password_authentication_help": "Дозволити автентифікацію паролем для SSH",
"global_settings_setting_ssh_port": "SSH-порт",
"global_settings_setting_webadmin_allowlist_help": "IP-адреси, яким дозволений доступ до вебадмініструванні. Через кому.",
@ -738,5 +735,30 @@
"visitors": "Відвідувачі",
"password_confirmation_not_the_same": "Пароль і його підтвердження не збігаються",
"password_too_long": "Будь ласка, виберіть пароль коротший за 127 символів",
"pattern_fullname": "Має бути дійсне повне ім’я (принаймні 3 символи)"
}
"pattern_fullname": "Має бути дійсне повне ім’я (принаймні 3 символи)",
"app_failed_to_upgrade_but_continue": "Застосунок {failed_app} не вдалося оновити, продовжуйте наступні оновлення відповідно до запиту. Запустіть 'yunohost log show {operation_logger_name}', щоб побачити журнал помилок",
"app_not_upgraded_broken_system": "Застосунок '{failed_app}' не зміг оновитися і перевів систему в неробочий стан, і як наслідок, оновлення наступних застосунків було скасовано: {apps}",
"app_not_upgraded_broken_system_continue": "Застосунок '{failed_app}' не зміг оновитися і перевів систему у неробочий стан (тому --continue-on-failure ігнорується), і як наслідок, оновлення наступних застосунків було скасовано: {apps}",
"confirm_app_insufficient_ram": "НЕБЕЗПЕКА! Цей застосунок вимагає {required} оперативної пам'яті для встановлення/оновлення, але зараз доступно лише {current}. Навіть якби цей застосунок можна було б запустити, процес його встановлення/оновлення вимагає великої кількості оперативної пам'яті, тому ваш сервер може зависнути і вийти з ладу. Якщо ви все одно готові піти на цей ризик, введіть '{answers}'",
"invalid_shell": "Недійсна оболонка: {shell}",
"domain_config_default_app_help": "Користувачі будуть автоматично перенаправлятися на цей застосунок при відкритті цього домену. Якщо застосунок не вказано, люди будуть перенаправлені на форму входу на портал користувача.",
"domain_config_xmpp_help": "Примітка: для ввімкнення деяких функцій XMPP потрібно оновити записи DNS та відновити сертифікат Lets Encrypt",
"global_settings_setting_dns_exposure_help": "Примітка: Це стосується лише рекомендованої конфігурації DNS і діагностичних перевірок. Це не впливає на конфігурацію системи.",
"global_settings_setting_passwordless_sudo": "Дозвіл адміністраторам використовувати \"sudo\" без повторного введення пароля",
"app_change_url_failed": "Не вдалося змінити url для {app}: {error}",
"app_change_url_require_full_domain": "{app} не може бути переміщено на цю нову URL-адресу, оскільки для цього потрібен повний домен (тобто зі шляхом = /)",
"app_change_url_script_failed": "Виникла помилка всередині скрипта зміни URL-адреси",
"app_yunohost_version_not_supported": "Для роботи застосунку потрібен YunoHost мінімум версії {required}, але поточна встановлена версія {current}",
"app_arch_not_supported": "Цей застосунок можна встановити лише на архітектурах {required}, але архітектура вашого сервера {current}",
"global_settings_setting_dns_exposure": "Версії IP, які слід враховувати при конфігурації та діагностиці DNS",
"domain_cannot_add_muc_upload": "Ви не можете додавати домени, що починаються на 'muc.'. Такі імена зарезервовані для багатокористувацького чату XMPP, інтегрованого в YunoHost.",
"confirm_notifications_read": "ПОПЕРЕДЖЕННЯ: Перш ніж продовжити, перевірте сповіщення застосунку вище, там можуть бути важливі повідомлення. [{answers}]",
"global_settings_setting_portal_theme": "Тема порталу",
"global_settings_setting_portal_theme_help": "Подробиці щодо створення користувацьких тем порталу на https://yunohost.org/theming",
"diagnosis_ip_no_ipv6_tip_important": "Зазвичай IPv6 має бути автоматично налаштований системою або вашим провайдером, якщо він доступний. В іншому випадку, можливо, вам доведеться налаштувати деякі речі вручну, як описано в документації тут: <a href='https://yunohost.org/#/ipv6'>https://yunohost.org/#/ipv6</a>.",
"app_not_enough_disk": "Цей застосунок вимагає {required} вільного місця.",
"app_not_enough_ram": "Для встановлення/оновлення цього застосунку потрібно {required} оперативної пам'яті, але наразі доступно лише {current}.",
"app_resource_failed": "Не вдалося надати, позбавити або оновити ресурси для {app}: {error}",
"apps_failed_to_upgrade": "Ці застосунки не вдалося оновити:{apps}",
"apps_failed_to_upgrade_line": "\n * {app_id} (щоб побачити відповідний журнал, виконайте 'yunohost log show {operation_logger_name}')"
}

View file

@ -28,9 +28,9 @@
"diagnosis_basesystem_hardware_model": "服务器型号为 {model}",
"diagnosis_basesystem_hardware": "服务器硬件架构为{virt} {arch}",
"custom_app_url_required": "您必须提供URL才能升级自定义应用 {app}",
"confirm_app_install_thirdparty": "危险! 该应用程序不是YunoHost的应用程序目录的一部分。 安装第三方应用程序可能会损害系统的完整性和安全性。 除非您知道自己在做什么,否则可能不应该安装它, 如果此应用无法运行或无法正常使用系统,将不会提供任何支持。如果您仍然愿意承担此风险,请输入'{answers}'",
"confirm_app_install_thirdparty": "危险! 该应用不是YunoHost的应用目录的一部分。 安装第三方应用可能会损害系统的完整性和安全性。 除非您知道自己在做什么,否则可能不应该安装它, 如果此应用无法运行或无法正常使用系统,将不会提供任何支持。如果您仍然愿意承担此风险,请输入'{answers}'",
"confirm_app_install_danger": "危险! 已知此应用仍处于实验阶段(如果未明确无法正常运行)! 除非您知道自己在做什么,否则可能不应该安装它。 如果此应用无法运行或无法正常使用系统,将不会提供任何支持。如果您仍然愿意承担此风险,请输入'{answers}'",
"confirm_app_install_warning": "警告:此应用程序可能可以运行但未与YunoHost很好地集成。某些功能例如单点登录和备份/还原)可能不可用, 仍要安装吗? [{answers}] ",
"confirm_app_install_warning": "警告:此应用可能可以运行但未与YunoHost很好地集成。某些功能例如单点登录和备份/还原)可能不可用, 仍要安装吗? [{answers}] ",
"certmanager_unable_to_parse_self_CA_name": "无法解析自签名授权的名称 (file: {file})",
"certmanager_self_ca_conf_file_not_found": "找不到用于自签名授权的配置文件(file: {file})",
"certmanager_no_cert_file": "无法读取域{domain}的证书文件(file: {file})",
@ -50,7 +50,7 @@
"certmanager_attempt_to_renew_valid_cert": "域'{domain}'的证书不会过期!(如果知道自己在做什么,则可以使用--force",
"certmanager_attempt_to_renew_nonLE_cert": "“Let's Encrypt”未颁发域'{domain}'的证书,无法自动续订!",
"certmanager_acme_not_configured_for_domain": "目前无法针对{domain}运行ACME挑战因为其nginx conf缺少相应的代码段...请使用“yunohost tools regen-conf nginx --dry-run --with-diff”确保您的nginx配置是最新的。",
"backup_with_no_restore_script_for_app": "{app} 没有还原脚本,您将无法自动还原该应用程序的备份。",
"backup_with_no_restore_script_for_app": "{app} 没有还原脚本,您将无法自动还原该应用的备份。",
"backup_with_no_backup_script_for_app": "应用'{app}'没有备份脚本。无视。",
"backup_unable_to_organize_files": "无法使用快速方法来组织档案中的文件",
"backup_system_part_failed": "无法备份'{part}'系统部分",
@ -101,36 +101,36 @@
"ask_new_admin_password": "新的管理密码",
"ask_main_domain": "主域",
"ask_user_domain": "用户的电子邮件地址和XMPP帐户要使用的域",
"apps_catalog_update_success": "应用程序目录已更新!",
"apps_catalog_obsolete_cache": "应用程序目录缓存为空或已过时。",
"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": "所有应用程序都是最新的",
"apps_already_up_to_date": "所有应用都是最新的",
"app_packaging_format_not_supported": "无法安装此应用因为您的YunoHost版本不支持其打包格式。 您应该考虑升级系统。",
"app_upgraded": "{app}upgraded",
"app_upgrade_some_app_failed": "某些应用无法升级",
"app_upgrade_script_failed": "应用升级脚本内部发生错误",
"app_upgrade_app_name": "现在升级{app} ...",
"app_upgrade_several_apps": "以下应用将被升级: {apps}",
"app_unsupported_remote_type": "应用程序使用的远程类型不受支持",
"app_unsupported_remote_type": "应用使用的远程类型不受支持",
"app_start_backup": "正在收集要备份的文件,用于{app} ...",
"app_start_install": "{app}安装中...",
"app_sources_fetch_failed": "无法获取源文件URL是否正确",
"app_restore_script_failed": "应用还原脚本内部发生错误",
"app_restore_failed": "无法还原 {app}: {error}",
"app_remove_after_failed_install": "安装失败后删除应用程序...",
"app_remove_after_failed_install": "安装失败后删除应用...",
"app_requirements_checking": "正在检查{app}所需的软件包...",
"app_removed": "{app} 已卸载",
"app_not_properly_removed": "{app} 未正确删除",
"app_not_correctly_installed": "{app} 似乎安装不正确",
"app_not_upgraded": "应用程序'{failed_app}'升级失败,因此以下应用程序的升级已被取消: {apps}",
"app_not_upgraded": "应用'{failed_app}'升级失败,因此以下应用的升级已被取消: {apps}",
"app_manifest_install_ask_is_public": "该应用是否应该向匿名访问者公开?",
"app_manifest_install_ask_admin": "选择此应用的管理员用户",
"app_manifest_install_ask_password": "选择此应用的管理密码",
"additional_urls_already_removed": "权限'{permission}'的其他URL中已经删除了附加URL'{url}'",
"app_manifest_install_ask_path": "选择安装此应用的路径(在域名之后)",
"app_manifest_install_ask_domain": "选择应安装此应用程序的域",
"app_manifest_install_ask_domain": "选择应安装此应用的域",
"app_location_unavailable": "该URL不可用或与已安装的应用冲突\n{apps}",
"app_label_deprecated": "不推荐使用此命令!请使用新命令 'yunohost user permission update'来管理应用标签。",
"app_make_default_location_already_used": "无法将'{app}' 设置为域上的默认应用,'{other_app}'已在使用'{domain}'",
@ -138,10 +138,10 @@
"app_install_failed": "无法安装 {app}: {error}",
"app_install_files_invalid": "这些文件无法安装",
"additional_urls_already_added": "附加URL '{url}' 已添加到权限'{permission}'的附加URL中",
"app_full_domain_unavailable": "抱歉,此应用必须安装在其自己的域中,但其他应用已安装在域“ {domain}”上。 您可以改用专用于此应用程序的子域。",
"app_full_domain_unavailable": "抱歉,此应用必须安装在其自己的域中,但其他应用已安装在域“ {domain}”上。 您可以改用专用于此应用的子域。",
"app_extraction_failed": "无法解压缩安装文件",
"app_change_url_success": "{app} URL现在为 {domain}{path}",
"app_change_url_no_script": "应用程序'{app_name}'尚不支持URL修改. 也许您应该升级它。",
"app_change_url_no_script": "应用'{app_name}'尚不支持URL修改. 也许您应该升级它。",
"app_change_url_identical_domains": "新旧domain / url_path是相同的('{domain}{path}'),无需执行任何操作。",
"app_argument_required": "参数'{name}'为必填项",
"app_argument_password_no_default": "解析密码参数'{name}'时出错:出于安全原因,密码参数不能具有默认值",
@ -156,7 +156,7 @@
"port_already_opened": "{ip_version}个连接的端口 {port} 已打开",
"port_already_closed": "{ip_version}个连接的端口 {port} 已关闭",
"permission_require_account": "权限{permission}只对有账户的用户有意义,因此不能对访客启用。",
"permission_protected": "权限{permission}是受保护的。不能向/从这个权限添加或删除访问者组。",
"permission_protected": "权限{permission}是受保护的。不能向/从这个权限添加或删除访问者组。",
"permission_updated": "权限 '{permission}' 已更新",
"permission_update_failed": "无法更新权限 '{permission}': {error}",
"permission_not_found": "找不到权限'{permission}'",
@ -210,8 +210,8 @@
"service_description_rspamd": "过滤垃圾邮件和其他与电子邮件相关的功能",
"service_description_redis-server": "用于快速数据访问,任务队列和程序之间通信的专用数据库",
"service_description_postfix": "用于发送和接收电子邮件",
"service_description_nginx": "为的服务器上托管的所有网站提供服务或访问",
"service_description_mysql": "存储应用程序数据SQL数据库",
"service_description_nginx": "为的服务器上托管的所有网站提供服务或访问",
"service_description_mysql": "存储应用数据SQL数据库",
"service_description_metronome": "管理XMPP即时消息传递帐户",
"service_description_fail2ban": "防止来自互联网的暴力攻击和其他类型的攻击",
"service_description_dovecot": "允许电子邮件客户端访问/获取电子邮件通过IMAP和POP3",
@ -234,7 +234,7 @@
"system_username_exists": "用户名已存在于系统用户列表中",
"system_upgraded": "系统升级",
"ssowat_conf_generated": "SSOwat配置已重新生成",
"show_tile_cant_be_enabled_for_regex": "不能启用'show_tile',因为权限'{permission}'的URL是一个重合词",
"show_tile_cant_be_enabled_for_regex": "不能启用'show_tile',因为权限'{permission}'的URL是一个重合词",
"show_tile_cant_be_enabled_for_url_not_defined": "您现在无法启用 'show_tile' ,因为您必须先为权限'{permission}'定义一个URL",
"service_unknown": "未知服务 '{service}'",
"service_stopped": "服务'{service}' 已停止",
@ -266,7 +266,7 @@
"upnp_enabled": "UPnP已启用",
"upnp_disabled": "UPnP已禁用",
"yunohost_not_installed": "YunoHost没有正确安装请运行 'yunohost tools postinstall'",
"yunohost_postinstall_end_tip": "后期安装完成! 为了最终完成的设置,请考虑:\n -通过webadmin的“用户”部分添加第一个用户或在命令行中'yunohost user create <username>' );\n -通过网络管理员的“诊断”部分(或命令行中的'yunohost diagnosis run')诊断潜在问题;\n -阅读管理文档中的“完成安装设置”和“了解YunoHost”部分: https://yunohost.org/admindoc.",
"yunohost_postinstall_end_tip": "后期安装完成! 为了最终完成的设置,请考虑:\n -通过webadmin的“用户”部分添加第一个用户或在命令行中'yunohost user create <username>' );\n -通过网络管理员的“诊断”部分(或命令行中的'yunohost diagnosis run')诊断潜在问题;\n -阅读管理文档中的“完成安装设置”和“了解YunoHost”部分: https://yunohost.org/admindoc.",
"operation_interrupted": "该操作是否被手动中断?",
"invalid_regex": "无效的正则表达式:'{regex}'",
"installation_complete": "安装完成",
@ -318,13 +318,13 @@
"downloading": "下载中…",
"done": "完成",
"domains_available": "可用域:",
"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}]",
"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}]",
"domain_hostname_failed": "无法设置新的主机名。稍后可能会引起问题(可能没问题)。",
"domain_exists": "该域已存在",
"domain_dyndns_root_unknown": "未知的DynDNS根域",
"domain_dyndns_already_subscribed": "您已经订阅了DynDNS域",
"domain_dns_conf_is_just_a_recommendation": "本页向你展示了*推荐的*配置。它并*不*为你配置DNS。你有责任根据该建议在你的DNS注册商处配置你的DNS区域。",
"domain_dns_conf_is_just_a_recommendation": "本页向您展示了*推荐的*配置。它并*不*为您配置DNS。您有责任根据该建议在您的DNS注册商处配置您的DNS区域。",
"domain_deletion_failed": "无法删除域 {domain}: {error}",
"domain_deleted": "域已删除",
"domain_creation_failed": "无法创建域 {domain}: {error}",
@ -369,7 +369,7 @@
"diagnosis_description_ip": "互联网连接",
"diagnosis_description_basesystem": "基本系统",
"diagnosis_security_vulnerable_to_meltdown_details": "要解决此问题您应该升级系统并重新启动以加载新的Linux内核如果无法使用请与您的服务器提供商联系。有关更多信息请参见https://meltdownattack.com/。",
"diagnosis_security_vulnerable_to_meltdown": "似乎容易受到Meltdown关键安全漏洞的影响",
"diagnosis_security_vulnerable_to_meltdown": "似乎容易受到Meltdown关键安全漏洞的影响",
"diagnosis_regenconf_manually_modified": "配置文件 <code>{file}</code> 似乎已被手动修改。",
"diagnosis_regenconf_allgood": "所有配置文件均符合建议的配置!",
"diagnosis_mail_queue_too_big": "邮件队列中的待处理电子邮件过多({nb_pending} emails)",
@ -420,35 +420,35 @@
"diagnosis_ip_connected_ipv4": "服务器通过IPv4连接到Internet",
"diagnosis_no_cache": "尚无类别 '{category}'的诊断缓存",
"diagnosis_failed": "无法获取类别 '{category}'的诊断结果: {error}",
"diagnosis_package_installed_from_sury_details": "一些软件包被无意中从一个名为Sury的第三方仓库安装。YunoHost团队改进了处理这些软件包的策略但预计一些安装了PHP7.3应用程序的设置在仍然使用Stretch的情况下还有一些不一致的地方。为了解决这种情况应该尝试运行以下命令:<cmd>{cmd_to_fix}</cmd>",
"diagnosis_package_installed_from_sury_details": "一些软件包被无意中从一个名为Sury的第三方仓库安装。YunoHost团队改进了处理这些软件包的策略但预计一些安装了PHP7.3应用的设置在仍然使用Stretch的情况下还有一些不一致的地方。为了解决这种情况应该尝试运行以下命令:<cmd>{cmd_to_fix}</cmd>",
"app_not_installed": "在已安装的应用列表中找不到 {app}:{all_apps}",
"app_already_installed_cant_change_url": "这个应用程序已经被安装。URL不能仅仅通过这个函数来改变。在`app changeurl`中检查是否可用。",
"app_already_installed_cant_change_url": "这个应用已经被安装。URL不能仅仅通过这个函数来改变。在`app changeurl`中检查是否可用。",
"restore_not_enough_disk_space": "没有足够的空间(空间: {free_space} B需要的空间: {needed_space} B,安全系数: {margin} B)",
"regenconf_pending_applying": "正在为类别'{category}'应用挂起的配置..",
"regenconf_up_to_date": "类别'{category}'的配置已经是最新的",
"regenconf_file_kept_back": "配置文件'{conf}'预计将被regen-conf类别{category})删除,但被保留了下来。",
"good_practices_about_user_password": "现在,您将设置一个新的管理员密码。 密码至少应包含8个字符。并且出于安全考虑建议使用较长的密码同时尽可能使用各种字符大写小写数字和特殊字符",
"domain_cannot_remove_main_add_new_one": "你不能删除'{domain}',因为它是主域和你唯一的域,你需要先用'yunohost domain add <another-domain.com>'添加另一个域,然后用'yunohost domain main-domain -n <another-domain.com>'设置为主域,然后可以用'yunohost domain remove {domain}'删除域",
"domain_cannot_add_xmpp_upload": "不能添加以'xmpp-upload.'开头的域名。这种名称是为YunoHost中集成的XMPP上传功能保留的。",
"domain_cannot_remove_main": "你不能删除'{domain}',因为它是主域,你首先需要用'yunohost domain main-domain -n <another-domain>'设置另一个域作为主域;这里是候选域的列表: {other_domains}",
"domain_cannot_remove_main_add_new_one": "您不能删除'{domain}',因为它是主域和您唯一的域,您需要先用'yunohost domain add <another-domain.com>'添加另一个域,然后用'yunohost domain main-domain -n <another-domain.com>'设置为主域,然后可以用'yunohost domain remove {domain}'删除域",
"domain_cannot_add_xmpp_upload": "不能添加以'xmpp-upload.'开头的域名。这种名称是为YunoHost中集成的XMPP上传功能保留的。",
"domain_cannot_remove_main": "您不能删除'{domain}',因为它是主域,您首先需要用'yunohost domain main-domain -n <another-domain>'设置另一个域作为主域;这里是候选域的列表: {other_domains}",
"diagnosis_sshd_config_inconsistent_details": "请运行<cmd>yunohost settings set security.ssh.port -v YOUR_SSH_PORT</cmd>来定义SSH端口并检查<cmd>yunohost tools regen-conf ssh --dry-run --with-diff</cmd>和<cmd>yunohost tools regen-conf ssh --force</cmd>将您的配置重置为YunoHost建议。",
"diagnosis_http_bad_status_code": "它看起来像另一台机器(也许是你的互联网路由器)回答,而不是你的服务器。<br>1。这个问题最常见的原因是80端口和443端口<a href='https://yunohost.org/isp_box_config'>没有正确转发到您的服务器</a>。<br>2.在更复杂的设置中:确保没有防火墙或反向代理的干扰。",
"diagnosis_http_timeout": "当试图从外部联系的服务器时,出现了超时。它似乎是不可达的。<br>1. 这个问题最常见的原因是80端口和443端口<a href='https://yunohost.org/isp_box_config'>没有正确转发到你的服务器</a>。<br>2.你还应该确保nginx服务正在运行<br>3.对于更复杂的设置:确保没有防火墙或反向代理的干扰。",
"diagnosis_http_bad_status_code": "它看起来像另一台机器(也许是您的互联网路由器)回答,而不是您的服务器。<br>1。这个问题最常见的原因是80端口和443端口<a href='https://yunohost.org/isp_box_config'>没有正确转发到您的服务器</a>。<br>2.在更复杂的设置中:确保没有防火墙或反向代理的干扰。",
"diagnosis_http_timeout": "当试图从外部联系的服务器时,出现了超时。它似乎是不可达的。<br>1. 这个问题最常见的原因是80端口和443端口<a href='https://yunohost.org/isp_box_config'>没有正确转发到您的服务器</a>。<br>2.您还应该确保nginx服务正在运行<br>3.对于更复杂的设置:确保没有防火墙或反向代理的干扰。",
"diagnosis_rootfstotalspace_critical": "根文件系统总共只有{space}这很令人担忧您可能很快就会用完磁盘空间建议根文件系统至少有16 GB。",
"diagnosis_rootfstotalspace_warning": "根文件系统总共只有{space}。这可能没问题,但要小心,因为最终您可能很快会用完磁盘空间...建议根文件系统至少有16 GB。",
"diagnosis_regenconf_manually_modified_details": "如果知道自己在做什么的话,这可能是可以的! YunoHost会自动停止更新这个文件... 但是请注意YunoHost的升级可能包含重要的推荐变化。如果你想,你可以用<cmd>yunohost tools regen-conf {category} --dry-run --with-diff</cmd>检查差异,然后用<cmd>yunohost tools regen-conf {category} --force</cmd>强制设置为推荐配置",
"diagnosis_mail_fcrdns_nok_alternatives_6": "有些供应商不会让你配置你的反向DNS或者他们的功能可能被破坏......。如果你的反向DNS正确配置为IPv4可以尝试在发送邮件时禁用IPv6方法是运<cmd>yunohost settings set smtp.allow_ipv6 -v off</cmd>。注意:这应视为最后一个解决方案因为这意味着将无法从少数只使用IPv6的服务器发送或接收电子邮件。",
"diagnosis_mail_fcrdns_nok_alternatives_4": "有些供应商不会让你配置你的反向DNS或者他们的功能可能被破坏......)。如果您因此而遇到问题,请考虑以下解决方案:<br>- 一些ISP提供了<a href='https://yunohost.org/#/email_configure_relay'>使用邮件服务器中转</a>的选择,尽管这意味着中转将能够监视您的电子邮件流量。<br>- 一个有利于隐私的选择是使用VPN*与专用公共IP*来绕过这类限制。见<a href='https://yunohost.org/#/vpn_advantage'>https://yunohost.org/#/vpn_advantage</a><br>- 或者可以<a href='https://yunohost.org/#/isp'>切换到另一个供应商</a>",
"diagnosis_mail_ehlo_wrong_details": "远程诊断器在IPv{ipversion}中收到的EHLO与的服务器的域名不同。<br>收到的EHLO: <code>{wrong_ehlo}</code><br>预期的: <code>{right_ehlo}</code><br>这个问题最常见的原因是端口25<a href='https://yunohost.org/isp_box_config'>没有正确转发到的服务器</a>。另外,请确保没有防火墙或反向代理的干扰。",
"diagnosis_mail_ehlo_unreachable_details": "在IPv{ipversion}中无法打开与您服务器的25端口连接。它似乎是不可达的。<br>1. 这个问题最常见的原因是端口25<a href='https://yunohost.org/isp_box_config'>没有正确转发到你的服务器</a>。<br>2.你还应该确保postfix服务正在运行。<br>3.在更复杂的设置中:确保没有防火墙或反向代理的干扰。",
"diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "一些供应商不会让解除对出站端口25的封锁因为他们不关心网络中立性。<br>- 其中一些供应商提供了<a href='https://yunohost.org/#/email_configure_relay'>使用邮件服务器中继</a>的替代方案,尽管这意味着中继将能够监视的电子邮件流量。<br>- 一个有利于隐私的替代方案是使用VPN*用一个专用的公共IP*绕过这种限制。见<a href='https://yunohost.org/#/vpn_advantage'>https://yunohost.org/#/vpn_advantage</a><br>- 也可以考虑切换到<a href='https://yunohost.org/#/isp'>一个更有利于网络中立的供应商</a>",
"diagnosis_regenconf_manually_modified_details": "如果知道自己在做什么的话,这可能是可以的! YunoHost会自动停止更新这个文件... 但是请注意YunoHost的升级可能包含重要的推荐变化。如果您想,您可以用<cmd>yunohost tools regen-conf {category} --dry-run --with-diff</cmd>检查差异,然后用<cmd>yunohost tools regen-conf {category} --force</cmd>强制设置为推荐配置",
"diagnosis_mail_fcrdns_nok_alternatives_6": "有些供应商不会让您配置您的反向DNS或者他们的功能可能被破坏......。如果您的反向DNS正确配置为IPv4可以尝试在发送邮件时禁用IPv6方法是运<cmd>yunohost settings set smtp.allow_ipv6 -v off</cmd>。注意:这应视为最后一个解决方案因为这意味着将无法从少数只使用IPv6的服务器发送或接收电子邮件。",
"diagnosis_mail_fcrdns_nok_alternatives_4": "有些供应商不会让您配置您的反向DNS或者他们的功能可能被破坏......)。如果您因此而遇到问题,请考虑以下解决方案:<br>- 一些ISP提供了<a href='https://yunohost.org/#/email_configure_relay'>使用邮件服务器中转</a>的选择,尽管这意味着中转将能够监视您的电子邮件流量。<br>- 一个有利于隐私的选择是使用VPN*与专用公共IP*来绕过这类限制。见<a href='https://yunohost.org/#/vpn_advantage'>https://yunohost.org/#/vpn_advantage</a><br>- 或者可以<a href='https://yunohost.org/#/isp'>切换到另一个供应商</a>",
"diagnosis_mail_ehlo_wrong_details": "远程诊断器在IPv{ipversion}中收到的EHLO与的服务器的域名不同。<br>收到的EHLO: <code>{wrong_ehlo}</code><br>预期的: <code>{right_ehlo}</code><br>这个问题最常见的原因是端口25<a href='https://yunohost.org/isp_box_config'>没有正确转发到的服务器</a>。另外,请确保没有防火墙或反向代理的干扰。",
"diagnosis_mail_ehlo_unreachable_details": "在IPv{ipversion}中无法打开与您服务器的25端口连接。它似乎是不可达的。<br>1. 这个问题最常见的原因是端口25<a href='https://yunohost.org/isp_box_config'>没有正确转发到您的服务器</a>。<br>2.您还应该确保postfix服务正在运行。<br>3.在更复杂的设置中:确保没有防火墙或反向代理的干扰。",
"diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "一些供应商不会让解除对出站端口25的封锁因为他们不关心网络中立性。<br>- 其中一些供应商提供了<a href='https://yunohost.org/#/email_configure_relay'>使用邮件服务器中继</a>的替代方案,尽管这意味着中继将能够监视的电子邮件流量。<br>- 一个有利于隐私的替代方案是使用VPN*用一个专用的公共IP*绕过这种限制。见<a href='https://yunohost.org/#/vpn_advantage'>https://yunohost.org/#/vpn_advantage</a><br>- 也可以考虑切换到<a href='https://yunohost.org/#/isp'>一个更有利于网络中立的供应商</a>",
"diagnosis_ram_ok": "系统在{total}中仍然有 {available} ({available_percent}%) RAM可用。",
"diagnosis_ram_low": "系统有 {available} ({available_percent}%) RAM可用共{total}个)可用。小心。",
"diagnosis_ram_verylow": "系统只有 {available} ({available_percent}%) 内存可用! (在{total}中)",
"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}%) 的空间。({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>如果没有效果可以看看webadmin中的<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>如果没有效果可以看看webadmin中的<a href='#/services/{service}'>服务日志</a>(从命令行,可以用<cmd>yunohost service restart {service}</cmd>和<cmd>yunohost service log {service}</cmd>)来做。",
"diagnosis_dns_try_dyndns_update_force": "该域的DNS配置应由YunoHost自动管理如果不是这种情况您可以尝试使用 <cmd>yunohost dyndns update --force</cmd>强制进行更新。",
"diagnosis_dns_point_to_doc": "如果您需要有关配置DNS记录的帮助请查看<a href='https://yunohost.org/dns_config'> https://yunohost.org/dns_config </a>上的文档。",
"diagnosis_dns_discrepancy": "以下DNS记录似乎未遵循建议的配置:<br>类型: <code>{type}</code><br>名称: <code>{name}</code><br>代码> 当前值: <code>{current}期望值: <code>{value}</code>",
@ -467,8 +467,8 @@
"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。你要么在一个容器中要么你的内核不支持它",
"ip6tables_unavailable": "你不能在这里使用ip6tables。你要么在一个容器中要么你的内核不支持它",
"iptables_unavailable": "您不能在这里使用iptables。您要么在一个容器中要么您的内核不支持它",
"ip6tables_unavailable": "您不能在这里使用ip6tables。您要么在一个容器中要么您的内核不支持它",
"log_regen_conf": "重新生成系统配置'{}'",
"log_letsencrypt_cert_renew": "续订'{}'的“Let's Encrypt”证书",
"log_selfsigned_cert_install": "在 '{}'域上安装自签名证书",
@ -481,10 +481,9 @@
"log_domain_remove": "从系统配置中删除 '{}' 域",
"log_domain_add": "将 '{}'域添加到系统配置中",
"log_remove_on_failed_install": "安装失败后删除 '{}'",
"log_remove_on_failed_restore": "从备份存档还原失败后,删除 '{}'",
"log_backup_restore_app": "从备份存档还原 '{}'",
"log_backup_restore_system": "从备份档案还原系统",
"permission_currently_allowed_for_all_users": "这个权限目前除了授予其他组以外,还授予所有用户。可能想删除'all_users'权限或删除目前授予它的其他组。",
"permission_currently_allowed_for_all_users": "这个权限目前除了授予其他组以外,还授予所有用户。可能想删除'all_users'权限或删除目前授予它的其他组。",
"permission_creation_failed": "无法创建权限'{permission}': {error}",
"permission_created": "权限'{permission}'已创建",
"permission_cannot_remove_main": "不允许删除主要权限",
@ -529,7 +528,7 @@
"migration_ldap_rollback_success": "系统回滚。",
"migration_ldap_migration_failed_trying_to_rollback": "无法迁移...试图回滚系统。",
"migration_ldap_can_not_backup_before_migration": "迁移失败之前,无法完成系统的备份。错误: {error}",
"migration_ldap_backup_before_migration": "在实际迁移之前请创建LDAP数据库和应用程序设置的备份。",
"migration_ldap_backup_before_migration": "在实际迁移之前请创建LDAP数据库和应用设置的备份。",
"main_domain_changed": "主域已更改",
"main_domain_change_failed": "无法更改主域",
"mail_unavailable": "该电子邮件地址是保留的,并且将自动分配给第一个用户",
@ -541,7 +540,7 @@
"log_tools_reboot": "重新启动服务器",
"log_tools_shutdown": "关闭服务器",
"log_tools_upgrade": "升级系统软件包",
"log_tools_postinstall": "安装好的YunoHost服务器后",
"log_tools_postinstall": "安装好的YunoHost服务器后",
"log_tools_migrations_migrate_forward": "运行迁移",
"log_domain_main_domain": "将 '{}' 设为主要域",
"log_user_permission_reset": "重置权限'{}'",
@ -554,16 +553,16 @@
"log_user_create": "添加用户'{}'",
"domain_registrar_is_not_configured": "尚未为域 {domain} 配置注册商。",
"domain_dns_push_not_applicable": "的自动DNS配置的特征是不适用域{domain}。您应该按照 https://yunohost.org/dns_config 上的文档手动配置DNS 记录。",
"disk_space_not_sufficient_update": "没有足够的磁盘空间来更新此应用程序",
"disk_space_not_sufficient_update": "没有足够的磁盘空间来更新此应用",
"diagnosis_high_number_auth_failures": "最近出现了大量可疑的失败身份验证。您的fail2ban正在运行且配置正确或使用自定义端口的SSH作为https://yunohost.org/解释的安全性。",
"diagnosis_apps_not_in_app_catalog": "此应用程序不在 YunoHost 的应用程序目录中。如果它过去有被删除过,您应该考虑卸载此应用程,因为它不会更新,并且可能会损害您系统的完整和安全性。",
"diagnosis_apps_not_in_app_catalog": "此应用不在 YunoHost 的应用目录中。如果它过去有被删除过,您应该考虑卸载此应用程,因为它不会更新,并且可能会损害您系统的完整和安全性。",
"app_config_unable_to_apply": "无法应用配置面板值。",
"app_config_unable_to_read": "无法读取配置面板值。",
"config_forbidden_keyword": "关键字“{keyword}”是保留的,您不能创建或使用带有此 ID 的问题的配置面板。",
"config_no_panel": "未找到配置面板。",
"config_unknown_filter_key": "该过滤器钥匙“{filter_key}”有误。",
"diagnosis_apps_outdated_ynh_requirement": "此应用程序的安装 版本只需要 yunohost >= 2.x这往往表明它与推荐的打包实践和帮助程序不是最新的。真的应该考虑更新它。",
"disk_space_not_sufficient_install": "没有足够的磁盘空间来安装此应用程序",
"diagnosis_apps_outdated_ynh_requirement": "此应用的安装 版本只需要 yunohost >= 2.x这往往表明它与推荐的打包实践和帮助程序不是最新的。真的应该考虑更新它。",
"disk_space_not_sufficient_install": "没有足够的磁盘空间来安装此应用",
"config_apply_failed": "应用新配置 失败:{error}",
"config_cant_set_value_on_section": "无法在整个配置部分设置单个值 。",
"config_validate_color": "是有效的 RGB 十六进制颜色",
@ -571,10 +570,9 @@
"config_validate_email": "是有效的电子邮件",
"config_validate_time": "应该是像 HH:MM 这样的有效时间",
"config_validate_url": "应该是有效的URL",
"config_version_not_supported": "不支持配置面板版本“{ version }”。",
"danger": "警告:",
"diagnosis_apps_allgood": "所有已安装的应用程序都遵守基本的打包原则",
"diagnosis_apps_deprecated_practices": "此应用程序的安装 版本仍然使用一些超旧的弃用打包原则。推荐您升级它。",
"diagnosis_apps_allgood": "所有已安装的应用都遵守基本的打包原则",
"diagnosis_apps_deprecated_practices": "此应用的安装 版本仍然使用一些超旧的弃用打包原则。推荐您升级它。",
"diagnosis_apps_issue": "发现应用{ app } 存在问题",
"diagnosis_description_apps": "应用",
"global_settings_setting_backup_compress_tar_archives_help": "创建新备份时,请压缩档案(.tar.gz) ,而不要压缩未压缩的档案(.tar)。注意启用此选项意味着创建较小的备份存档但是初始备份过程将明显更长且占用大量CPU。",
@ -585,12 +583,12 @@
"global_settings_setting_ssh_compatibility_help": "SSH服务器的兼容性与安全性的权衡。影响密码以及其他与安全性有关的方面",
"global_settings_setting_ssh_port": "SSH端口",
"global_settings_setting_smtp_allow_ipv6_help": "允许使用IPv6接收和发送邮件",
"global_settings_setting_smtp_relay_enabled_help": "使用SMTP中继主机来代替这个YunoHost实例发送邮件。如果你有以下情况,就很有用:你的25端口被你的ISP或VPS提供商封锁你有一个住宅IP列在DUHL上你不能配置反向DNS或者这个服务器没有直接暴露在互联网上想使用其他服务器来发送邮件。",
"global_settings_setting_smtp_relay_enabled_help": "使用SMTP中继主机来代替这个YunoHost实例发送邮件。如果您有以下情况,就很有用:您的25端口被您的ISP或VPS提供商封锁您有一个住宅IP列在DUHL上您不能配置反向DNS或者这个服务器没有直接暴露在互联网上想使用其他服务器来发送邮件。",
"all_users": "所有的YunoHost用户",
"app_manifest_install_ask_init_admin_permission": "谁应该有权访问此应用程序的管理功能?(此配置可以稍后更改)",
"app_manifest_install_ask_init_admin_permission": "谁应该有权访问此应用的管理功能?(此配置可以稍后更改)",
"app_action_failed": "对应用{app}执行动作{action}失败",
"app_manifest_install_ask_init_main_permission": "谁应该有权访问此应用程序?(此配置稍后可以更改)",
"app_manifest_install_ask_init_main_permission": "谁应该有权访问此应用?(此配置稍后可以更改)",
"ask_admin_fullname": "管理员全名",
"ask_admin_username": "管理员用户名",
"ask_fullname": "全名"
}
}

View file

@ -32,7 +32,6 @@ def autofix_i18n_placeholders():
# We iterate over all keys/string in en.json
for key, string in reference.items():
# Ignore check if there's no translation yet for this key
if key not in this_locale:
continue
@ -89,7 +88,6 @@ Please fix it manually !
def autofix_orthotypography_and_standardized_words():
def reformat(lang, transformations):
locale = open(f"{LOCALE_FOLDER}{lang}.json").read()
for pattern, replace in transformations.items():
locale = re.compile(pattern).sub(replace, locale)
@ -146,11 +144,9 @@ def autofix_orthotypography_and_standardized_words():
def remove_stale_translated_strings():
reference = json.loads(open(LOCALE_FOLDER + "en.json").read())
for locale_file in TRANSLATION_FILES:
print(locale_file)
this_locale = json.loads(
open(LOCALE_FOLDER + locale_file).read(), object_pairs_hook=OrderedDict

View file

@ -19,7 +19,6 @@ REFERENCE_FILE = LOCALE_FOLDER + "en.json"
def find_expected_string_keys():
# Try to find :
# m18n.n( "foo"
# YunohostError("foo"
@ -197,7 +196,6 @@ undefined_keys = sorted(undefined_keys)
mode = sys.argv[1].strip("-")
if mode == "check":
# Unused keys are not too problematic, will be automatically
# removed by the other autoreformat script,
# but still informative to display them

View file

@ -72,7 +72,7 @@ user:
ask: ask_fullname
required: False
pattern: &pattern_fullname
- !!str ^([^\W\d_]{1,30}[ ,.'-]{0,3})+$
- !!str ^([^\W_]{1,30}[ ,.'-]{0,3})+$
- "pattern_fullname"
-f:
full: --firstname
@ -116,6 +116,11 @@ user:
pattern: &pattern_mailbox_quota
- !!str ^(\d+[bkMGT])|0$
- "pattern_mailbox_quota"
-s:
full: --loginShell
help: The login shell used
default: "/bin/bash"
### user_delete()
delete:
@ -195,6 +200,10 @@ user:
metavar: "{SIZE|0}"
extra:
pattern: *pattern_mailbox_quota
-s:
full: --loginShell
help: The login shell used
default: "/bin/bash"
### user_info()
info:
@ -961,6 +970,10 @@ app:
full: --no-safety-backup
help: Disable the safety backup during upgrade
action: store_true
-c:
full: --continue-on-failure
help: Continue to upgrade apps event if one or more upgrade failed
action: store_true
### app_change_url()
change-url:

View file

@ -9,8 +9,6 @@ name = "Features"
type = "app"
filter = "is_webapp"
default = "_none"
# FIXME: i18n
help = "People will automatically be redirected to this app when opening this domain. If no app is specified, people are redirected to the user portal login form."
[feature.mail]
@ -27,8 +25,6 @@ name = "Features"
[feature.xmpp.xmpp]
type = "boolean"
default = 0
# FIXME: i18n
help = "NB: some XMPP features will require that you update your DNS records and regenerate your Lets Encrypt certificate to be enabled"
[dns]
name = "DNS"
@ -64,24 +60,23 @@ name = "Certificate"
[cert.cert.acme_eligible_explain]
type = "alert"
style = "warning"
visible = "acme_eligible == false || acme_elligible == null"
visible = "acme_eligible == false || acme_eligible == null"
[cert.cert.cert_no_checks]
ask = "Ignore diagnosis checks"
type = "boolean"
default = false
visible = "acme_eligible == false || acme_elligible == null"
visible = "acme_eligible == false || acme_eligible == null"
[cert.cert.cert_install]
type = "button"
icon = "star"
style = "success"
visible = "issuer != 'letsencrypt'"
visible = "cert_issuer != 'letsencrypt'"
enabled = "acme_eligible || cert_no_checks"
[cert.cert.cert_renew]
type = "button"
icon = "refresh"
style = "warning"
visible = "issuer == 'letsencrypt'"
visible = "cert_issuer == 'letsencrypt'"
enabled = "acme_eligible || cert_no_checks"

View file

@ -160,3 +160,12 @@ name = "Other"
[misc.backup.backup_compress_tar_archives]
type = "boolean"
default = false
[misc.network]
name = "Network"
[misc.network.dns_exposure]
type = "select"
choices.both = "Both"
choices.ipv4 = "IPv4 Only"
choices.ipv6 = "IPv6 Only"
default = "both"

View file

@ -501,6 +501,15 @@
[pointhq.auth_token]
type = "string"
redact = true
[porkbun]
[porkbun.auth_key]
type = "string"
redact = true
[porkbun.auth_secret]
type = "string"
redact = true
[powerdns]
[powerdns.auth_token]

View file

@ -1,6 +1,6 @@
#! /usr/bin/python
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -32,7 +32,6 @@ def is_installed():
def cli(debug, quiet, output_as, timeout, args, parser):
init_logging(interface="cli", debug=debug, quiet=quiet)
# Check that YunoHost is installed
@ -51,7 +50,6 @@ def cli(debug, quiet, output_as, timeout, args, parser):
def api(debug, host, port):
init_logging(interface="api", debug=debug)
def is_installed_api():
@ -71,7 +69,6 @@ def api(debug, host, port):
def check_command_is_valid_before_postinstall(args):
allowed_if_not_postinstalled = [
"tools postinstall",
"tools versions",
@ -109,7 +106,6 @@ def init_i18n():
def init_logging(interface="cli", debug=False, quiet=False, logdir="/var/log/yunohost"):
logfile = os.path.join(logdir, "yunohost-%s.log" % interface)
if not os.path.isdir(logdir):

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -29,7 +29,7 @@ import subprocess
import tempfile
import copy
from collections import OrderedDict
from typing import List, Tuple, Dict, Any, Iterator
from typing import List, Tuple, Dict, Any, Iterator, Optional
from packaging import version
from moulinette import Moulinette, m18n
@ -48,9 +48,8 @@ from moulinette.utils.filesystem import (
chmod,
)
from yunohost.utils.config import (
ConfigPanel,
ask_questions_and_parse_answers,
from yunohost.utils.configpanel import ConfigPanel, ask_questions_and_parse_answers
from yunohost.utils.form import (
DomainQuestion,
PathQuestion,
hydrate_questions_with_choices,
@ -62,6 +61,7 @@ from yunohost.utils.system import (
dpkg_is_broken,
get_ynh_package_version,
system_arch,
debian_version,
human_to_binary,
binary_to_human,
ram_available,
@ -238,7 +238,6 @@ def app_info(app, full=False, upgradable=False):
def _app_upgradable(app_infos):
# Determine upgradability
app_in_catalog = app_infos.get("from_catalog")
@ -374,7 +373,6 @@ def app_map(app=None, raw=False, user=None):
)
for url in perm_all_urls:
# Here, we decide to completely ignore regex-type urls ...
# Because :
# - displaying them in regular "yunohost app map" output creates
@ -413,7 +411,7 @@ def app_change_url(operation_logger, app, domain, path):
path -- New path at which the application will be move
"""
from yunohost.hook import hook_exec, hook_callback
from yunohost.hook import hook_exec_with_script_debug_if_failure, hook_callback
from yunohost.service import service_reload_or_restart
installed = _is_installed(app)
@ -447,6 +445,8 @@ def app_change_url(operation_logger, app, domain, path):
_validate_webpath_requirement(
{"domain": domain, "path": path}, path_requirement, ignore_app=app
)
if path_requirement == "full_domain" and path != "/":
raise YunohostValidationError("app_change_url_require_full_domain", app=app)
tmp_workdir_for_app = _make_tmp_workdir_for_app(app=app)
@ -454,46 +454,93 @@ def app_change_url(operation_logger, app, domain, path):
env_dict = _make_environment_for_app_script(
app, workdir=tmp_workdir_for_app, action="change_url"
)
env_dict["YNH_APP_OLD_DOMAIN"] = old_domain
env_dict["YNH_APP_OLD_PATH"] = old_path
env_dict["YNH_APP_NEW_DOMAIN"] = domain
env_dict["YNH_APP_NEW_PATH"] = path
env_dict["old_domain"] = old_domain
env_dict["old_path"] = old_path
env_dict["new_domain"] = domain
env_dict["new_path"] = path
env_dict["change_path"] = "1" if old_path != path else "0"
env_dict["change_domain"] = "1" if old_domain != domain else "0"
if domain != old_domain:
operation_logger.related_to.append(("domain", old_domain))
operation_logger.extra.update({"env": env_dict})
operation_logger.start()
old_nginx_conf_path = f"/etc/nginx/conf.d/{old_domain}.d/{app}.conf"
new_nginx_conf_path = f"/etc/nginx/conf.d/{domain}.d/{app}.conf"
old_nginx_conf_backup = None
if not os.path.exists(old_nginx_conf_path):
logger.warning(
f"Current nginx config file {old_nginx_conf_path} doesn't seem to exist ... wtf ?"
)
else:
old_nginx_conf_backup = read_file(old_nginx_conf_path)
change_url_script = os.path.join(tmp_workdir_for_app, "scripts/change_url")
# Execute App change_url script
ret = hook_exec(change_url_script, env=env_dict)[0]
if ret != 0:
msg = f"Failed to change '{app}' url."
logger.error(msg)
operation_logger.error(msg)
change_url_failed = True
try:
(
change_url_failed,
failure_message_with_debug_instructions,
) = hook_exec_with_script_debug_if_failure(
change_url_script,
env=env_dict,
operation_logger=operation_logger,
error_message_if_script_failed=m18n.n("app_change_url_script_failed"),
error_message_if_failed=lambda e: m18n.n(
"app_change_url_failed", app=app, error=e
),
)
finally:
shutil.rmtree(tmp_workdir_for_app)
# restore values modified by app_checkurl
# see begining of the function
app_setting(app, "domain", value=old_domain)
app_setting(app, "path", value=old_path)
return
shutil.rmtree(tmp_workdir_for_app)
if change_url_failed:
logger.warning("Restoring initial nginx config file")
if old_nginx_conf_path != new_nginx_conf_path and os.path.exists(
new_nginx_conf_path
):
rm(new_nginx_conf_path, force=True)
if old_nginx_conf_backup:
write_to_file(old_nginx_conf_path, old_nginx_conf_backup)
service_reload_or_restart("nginx")
# this should idealy be done in the change_url script but let's avoid common mistakes
app_setting(app, "domain", value=domain)
app_setting(app, "path", value=path)
# restore values modified by app_checkurl
# see begining of the function
app_setting(app, "domain", value=old_domain)
app_setting(app, "path", value=old_path)
raise YunohostError(failure_message_with_debug_instructions, raw_msg=True)
else:
# make sure the domain/path setting are propagated
app_setting(app, "domain", value=domain)
app_setting(app, "path", value=path)
app_ssowatconf()
app_ssowatconf()
service_reload_or_restart("nginx")
service_reload_or_restart("nginx")
logger.success(m18n.n("app_change_url_success", app=app, domain=domain, path=path))
logger.success(
m18n.n("app_change_url_success", app=app, domain=domain, path=path)
)
hook_callback("post_app_change_url", env=env_dict)
hook_callback("post_app_change_url", env=env_dict)
def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False):
def app_upgrade(
app=[],
url=None,
file=None,
force=False,
no_safety_backup=False,
continue_on_failure=False,
):
"""
Upgrade app
@ -545,6 +592,7 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False
logger.info(m18n.n("app_upgrade_several_apps", apps=", ".join(apps)))
notifications = {}
failed_to_upgrade_apps = []
for number, app_instance_name in enumerate(apps):
logger.info(m18n.n("app_upgrade_app_name", app=app_instance_name))
@ -649,7 +697,9 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False
safety_backup_name = f"{app_instance_name}-pre-upgrade2"
other_safety_backup_name = f"{app_instance_name}-pre-upgrade1"
backup_create(name=safety_backup_name, apps=[app_instance_name])
backup_create(
name=safety_backup_name, apps=[app_instance_name], system=None
)
if safety_backup_name in backup_list()["archives"]:
# if the backup suceeded, delete old safety backup to save space
@ -679,11 +729,17 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False
env_dict = _make_environment_for_app_script(
app_instance_name, workdir=extracted_app_folder, action="upgrade"
)
env_dict["YNH_APP_UPGRADE_TYPE"] = upgrade_type
env_dict["YNH_APP_MANIFEST_VERSION"] = str(app_new_version)
env_dict["YNH_APP_CURRENT_VERSION"] = str(app_current_version)
env_dict_more = {
"YNH_APP_UPGRADE_TYPE": upgrade_type,
"YNH_APP_MANIFEST_VERSION": str(app_new_version),
"YNH_APP_CURRENT_VERSION": str(app_current_version),
}
if manifest["packaging_format"] < 2:
env_dict["NO_BACKUP_UPGRADE"] = "1" if no_safety_backup else "0"
env_dict_more["NO_BACKUP_UPGRADE"] = "1" if no_safety_backup else "0"
env_dict.update(env_dict_more)
# Start register change on system
related_to = [("app", app_instance_name)]
@ -698,8 +754,20 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False
).apply(
rollback_and_raise_exception_if_failure=True,
operation_logger=operation_logger,
action="upgrade",
)
# Boring stuff : the resource upgrade may have added/remove/updated setting
# so we need to reflect this in the env_dict used to call the actual upgrade script x_x
# Or: the old manifest may be in v1 and the new in v2, so force to add the setting in env
env_dict = _make_environment_for_app_script(
app_instance_name,
workdir=extracted_app_folder,
action="upgrade",
force_include_app_settings=True,
)
env_dict.update(env_dict_more)
# Execute the app upgrade script
upgrade_failed = True
try:
@ -716,7 +784,6 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False
),
)
finally:
# If upgrade failed, try to restore the safety backup
if (
upgrade_failed
@ -727,7 +794,7 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False
"Upgrade failed ... attempting to restore the satefy backup (Yunohost first need to remove the app for this) ..."
)
app_remove(app_instance_name)
app_remove(app_instance_name, force_workdir=extracted_app_folder)
backup_restore(
name=safety_backup_name, apps=[app_instance_name], force=True
)
@ -762,21 +829,51 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False
# If upgrade failed or broke the system,
# raise an error and interrupt all other pending upgrades
if upgrade_failed or broke_the_system:
if not continue_on_failure or broke_the_system:
# display this if there are remaining apps
if apps[number + 1 :]:
not_upgraded_apps = apps[number:]
if broke_the_system and not continue_on_failure:
logger.error(
m18n.n(
"app_not_upgraded_broken_system",
failed_app=app_instance_name,
apps=", ".join(not_upgraded_apps),
)
)
elif broke_the_system and continue_on_failure:
logger.error(
m18n.n(
"app_not_upgraded_broken_system_continue",
failed_app=app_instance_name,
apps=", ".join(not_upgraded_apps),
)
)
else:
logger.error(
m18n.n(
"app_not_upgraded",
failed_app=app_instance_name,
apps=", ".join(not_upgraded_apps),
)
)
# display this if there are remaining apps
if apps[number + 1 :]:
not_upgraded_apps = apps[number:]
logger.error(
m18n.n(
"app_not_upgraded",
failed_app=app_instance_name,
apps=", ".join(not_upgraded_apps),
)
raise YunohostError(
failure_message_with_debug_instructions, raw_msg=True
)
raise YunohostError(
failure_message_with_debug_instructions, raw_msg=True
)
else:
operation_logger.close()
logger.error(
m18n.n(
"app_failed_to_upgrade_but_continue",
failed_app=app_instance_name,
operation_logger_name=operation_logger.name,
)
)
failed_to_upgrade_apps.append(
(app_instance_name, operation_logger.name)
)
# Otherwise we're good and keep going !
now = int(time.time())
@ -838,12 +935,22 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False
logger.success(m18n.n("upgrade_complete"))
if failed_to_upgrade_apps:
apps = ""
for app_id, operation_logger_name in failed_to_upgrade_apps:
apps += m18n.n(
"apps_failed_to_upgrade_line",
app_id=app_id,
operation_logger_name=operation_logger_name,
)
logger.warning(m18n.n("apps_failed_to_upgrade", apps=apps))
if Moulinette.interface.type == "api":
return {"notifications": {"POST_UPGRADE": notifications}}
def app_manifest(app, with_screenshot=False):
manifest, extracted_app_folder = _extract_app(app)
raw_questions = manifest.get("install", {}).values()
@ -886,7 +993,6 @@ def app_manifest(app, with_screenshot=False):
def _confirm_app_install(app, force=False):
# Ignore if there's nothing for confirm (good quality app), if --force is used
# or if request on the API (confirm already implemented on the API side)
if force or Moulinette.interface.type == "api":
@ -1036,8 +1142,8 @@ def app_install(
# If packaging_format v2+, save all install questions as settings
if packaging_format >= 2:
for question in questions:
# Except user-provider passwords
# ... which we need to reinject later in the env_dict
if question.type == "password":
continue
@ -1062,10 +1168,15 @@ def app_install(
if packaging_format >= 2:
from yunohost.utils.resources import AppResourceManager
AppResourceManager(app_instance_name, wanted=manifest, current={}).apply(
rollback_and_raise_exception_if_failure=True,
operation_logger=operation_logger,
)
try:
AppResourceManager(app_instance_name, wanted=manifest, current={}).apply(
rollback_and_raise_exception_if_failure=True,
operation_logger=operation_logger,
action="install",
)
except (KeyboardInterrupt, EOFError, Exception) as e:
shutil.rmtree(app_setting_path)
raise e
else:
# Initialize the main permission for the app
# The permission is initialized with no url associated, and with tile disabled
@ -1085,11 +1196,22 @@ def app_install(
app_instance_name, args=args, workdir=extracted_app_folder, action="install"
)
# If packaging_format v2+, save all install questions as settings
if packaging_format >= 2:
for question in questions:
# Reinject user-provider passwords which are not in the app settings
# (cf a few line before)
if question.type == "password":
env_dict[question.name] = question.value
# We want to hav the env_dict in the log ... but not password values
env_dict_for_logging = env_dict.copy()
for question in questions:
# Or should it be more generally question.redact ?
if question.type == "password":
del env_dict_for_logging[f"YNH_APP_ARG_{question.name.upper()}"]
if question.name in env_dict_for_logging:
del env_dict_for_logging[question.name]
operation_logger.extra.update({"env": env_dict_for_logging})
@ -1135,7 +1257,6 @@ def app_install(
# If the install failed or broke the system, we remove it
if install_failed or broke_the_system:
# This option is meant for packagers to debug their apps more easily
if no_remove_on_failure:
raise YunohostError(
@ -1183,7 +1304,7 @@ def app_install(
AppResourceManager(
app_instance_name, wanted={}, current=manifest
).apply(rollback_and_raise_exception_if_failure=False)
).apply(rollback_and_raise_exception_if_failure=False, action="remove")
else:
# Remove all permission in LDAP
for permission_name in user_permission_list()["permissions"].keys():
@ -1243,14 +1364,14 @@ def app_install(
@is_unit_operation()
def app_remove(operation_logger, app, purge=False):
def app_remove(operation_logger, app, purge=False, force_workdir=None):
"""
Remove app
Keyword arguments:
app -- App(s) to delete
purge -- Remove with all app data
force_workdir -- Special var to force the working directoy to use, in context such as remove-after-failed-upgrade or remove-after-failed-restore
"""
from yunohost.utils.legacy import _patch_legacy_php_versions, _patch_legacy_helpers
from yunohost.hook import hook_exec, hook_remove, hook_callback
@ -1269,7 +1390,6 @@ def app_remove(operation_logger, app, purge=False):
operation_logger.start()
logger.info(m18n.n("app_start_remove", app=app))
app_setting_path = os.path.join(APPS_SETTING_PATH, app)
# Attempt to patch legacy helpers ...
@ -1279,8 +1399,20 @@ def app_remove(operation_logger, app, purge=False):
# script might date back from jessie install)
_patch_legacy_php_versions(app_setting_path)
manifest = _get_manifest_of_app(app_setting_path)
tmp_workdir_for_app = _make_tmp_workdir_for_app(app=app)
if force_workdir:
# This is when e.g. calling app_remove() from the upgrade-failed case
# where we want to remove using the *new* remove script and not the old one
# and also get the new manifest
# It's especially important during v1->v2 app format transition where the
# setting names change (e.g. install_dir instead of final_path) and
# running the old remove script doesnt make sense anymore ...
tmp_workdir_for_app = tempfile.mkdtemp(prefix="app_", dir=APP_TMP_WORKDIRS)
os.system(f"cp -a {force_workdir}/* {tmp_workdir_for_app}/")
else:
tmp_workdir_for_app = _make_tmp_workdir_for_app(app=app)
manifest = _get_manifest_of_app(tmp_workdir_for_app)
remove_script = f"{tmp_workdir_for_app}/scripts/remove"
env_dict = {}
@ -1311,7 +1443,9 @@ def app_remove(operation_logger, app, purge=False):
from yunohost.utils.resources import AppResourceManager
AppResourceManager(app, wanted={}, current=manifest).apply(
rollback_and_raise_exception_if_failure=False, purge_data_dir=purge
rollback_and_raise_exception_if_failure=False,
purge_data_dir=purge,
action="remove",
)
else:
# Remove all permission in LDAP
@ -1390,7 +1524,6 @@ def app_setting(app, key, value=None, delete=False):
)
if is_legacy_permission_setting:
from yunohost.permission import (
user_permission_list,
user_permission_update,
@ -1433,7 +1566,6 @@ def app_setting(app, key, value=None, delete=False):
# SET
else:
urls = value
# If the request is about the root of the app (/), ( = the vast majority of cases)
# we interpret this as a change for the main permission
@ -1445,7 +1577,6 @@ def app_setting(app, key, value=None, delete=False):
else:
user_permission_update(app + ".main", remove="visitors")
else:
urls = urls.split(",")
if key.endswith("_regex"):
urls = ["re:" + url for url in urls]
@ -1595,8 +1726,15 @@ def app_ssowatconf():
}
redirected_urls = {}
for app in _installed_apps():
apps_using_remote_user_var_in_nginx = (
check_output(
"grep -nri '$remote_user' /etc/yunohost/apps/*/conf/*nginx*conf | awk -F/ '{print $5}' || true"
)
.strip()
.split("\n")
)
for app in _installed_apps():
app_settings = read_yaml(APPS_SETTING_PATH + app + "/settings.yml") or {}
# Redirected
@ -1622,7 +1760,6 @@ def app_ssowatconf():
# New permission system
for perm_name, perm_info in all_permissions.items():
uris = (
[]
+ ([perm_info["url"]] if perm_info["url"] else [])
@ -1633,7 +1770,11 @@ def app_ssowatconf():
if not uris:
continue
app_id = perm_name.split(".")[0]
permissions[perm_name] = {
"use_remote_user_var_in_nginx_conf": app_id
in apps_using_remote_user_var_in_nginx,
"users": perm_info["corresponding_users"],
"label": perm_info["label"],
"show_tile": perm_info["show_tile"]
@ -1682,13 +1823,11 @@ def app_change_label(app, new_label):
def app_action_list(app):
return AppConfigPanel(app).list_actions()
@is_unit_operation()
def app_action_run(operation_logger, app, action, args=None, args_file=None):
return AppConfigPanel(app).run_action(
action, args=args, args_file=args_file, operation_logger=operation_logger
)
@ -2024,12 +2163,10 @@ def _get_manifest_of_app(path):
def _parse_app_doc_and_notifications(path):
doc = {}
notification_names = ["PRE_INSTALL", "POST_INSTALL", "PRE_UPGRADE", "POST_UPGRADE"]
for filepath in glob.glob(os.path.join(path, "doc") + "/*.md"):
# to be improved : [a-z]{2,3} is a clumsy way of parsing the
# lang code ... some lang code are more complex that this é_è
m = re.match("([A-Z]*)(_[a-z]{2,3})?.md", filepath.split("/")[-1])
@ -2047,7 +2184,12 @@ def _parse_app_doc_and_notifications(path):
if pagename not in doc:
doc[pagename] = {}
doc[pagename][lang] = read_file(filepath).strip()
try:
doc[pagename][lang] = read_file(filepath).strip()
except Exception as e:
logger.error(e)
continue
notifications = {}
@ -2061,7 +2203,11 @@ def _parse_app_doc_and_notifications(path):
lang = m.groups()[0].strip("_") if m.groups()[0] else "en"
if pagename not in notifications[step]:
notifications[step][pagename] = {}
notifications[step][pagename][lang] = read_file(filepath).strip()
try:
notifications[step][pagename][lang] = read_file(filepath).strip()
except Exception as e:
logger.error(e)
continue
for filepath in glob.glob(os.path.join(path, "doc", f"{step}.d") + "/*.md"):
m = re.match(
@ -2073,27 +2219,29 @@ def _parse_app_doc_and_notifications(path):
lang = lang.strip("_") if lang else "en"
if pagename not in notifications[step]:
notifications[step][pagename] = {}
notifications[step][pagename][lang] = read_file(filepath).strip()
try:
notifications[step][pagename][lang] = read_file(filepath).strip()
except Exception as e:
logger.error(e)
continue
return doc, notifications
def _hydrate_app_template(template, data):
stuff_to_replace = set(re.findall(r"__[A-Z0-9]+?[A-Z0-9_]*?[A-Z0-9]*?__", template))
for stuff in stuff_to_replace:
varname = stuff.strip("_").lower()
if varname in data:
template = template.replace(stuff, data[varname])
template = template.replace(stuff, str(data[varname]))
return template
def _convert_v1_manifest_to_v2(manifest):
manifest = copy.deepcopy(manifest)
if "upstream" not in manifest:
@ -2174,7 +2322,6 @@ def _convert_v1_manifest_to_v2(manifest):
def _set_default_ask_questions(questions, script_name="install"):
# arguments is something like
# { "domain":
# {
@ -2232,7 +2379,6 @@ def _set_default_ask_questions(questions, script_name="install"):
def _is_app_repo_url(string: str) -> bool:
string = string.strip()
# Dummy test for ssh-based stuff ... should probably be improved somehow
@ -2249,7 +2395,6 @@ def _app_quality(src: str) -> str:
raw_app_catalog = _load_apps_catalog()["apps"]
if src in raw_app_catalog or _is_app_repo_url(src):
# If we got an app name directly (e.g. just "wordpress"), we gonna test this name
if src in raw_app_catalog:
app_name_to_test = src
@ -2262,7 +2407,6 @@ def _app_quality(src: str) -> str:
return "thirdparty"
if app_name_to_test in raw_app_catalog:
state = raw_app_catalog[app_name_to_test].get("state", "notworking")
level = raw_app_catalog[app_name_to_test].get("level", None)
if state in ["working", "validated"]:
@ -2300,19 +2444,21 @@ def _extract_app(src: str) -> Tuple[Dict, str]:
url = app_info["git"]["url"]
branch = app_info["git"]["branch"]
revision = str(app_info["git"]["revision"])
return _extract_app_from_gitrepo(url, branch, revision, app_info)
return _extract_app_from_gitrepo(
url, branch=branch, revision=revision, app_info=app_info
)
# App is a git repo url
elif _is_app_repo_url(src):
url = src.strip().strip("/")
branch = "master"
revision = "HEAD"
# gitlab urls may look like 'https://domain/org/group/repo/-/tree/testing'
# compated to github urls looking like 'https://domain/org/repo/tree/testing'
if "/-/" in url:
url = url.replace("/-/", "/")
if "/tree/" in url:
url, branch = url.split("/tree/", 1)
return _extract_app_from_gitrepo(url, branch, revision, {})
else:
branch = None
return _extract_app_from_gitrepo(url, branch=branch)
# App is a local folder
elif os.path.exists(src):
return _extract_app_from_folder(src)
@ -2342,6 +2488,10 @@ def _extract_app_from_folder(path: str) -> Tuple[Dict, str]:
if path[-1] != "/":
path = path + "/"
cp(path, extracted_app_folder, recursive=True)
# Change the last edit time which is used in _make_tmp_workdir_for_app
# to cleanup old dir ... otherwise it may end up being incorrectly removed
# at the end of the safety-backup-before-upgrade :/
os.system(f"touch {extracted_app_folder}")
else:
try:
shutil.unpack_archive(path, extracted_app_folder)
@ -2369,8 +2519,43 @@ def _extract_app_from_folder(path: str) -> Tuple[Dict, str]:
def _extract_app_from_gitrepo(
url: str, branch: str, revision: str, app_info: Dict = {}
url: str, branch: Optional[str] = None, revision: str = "HEAD", app_info: Dict = {}
) -> Tuple[Dict, str]:
logger.debug("Checking default branch")
try:
git_ls_remote = check_output(
["git", "ls-remote", "--symref", url, "HEAD"],
env={"GIT_TERMINAL_PROMPT": "0", "LC_ALL": "C"},
shell=False,
)
except Exception as e:
logger.error(str(e))
raise YunohostError("app_sources_fetch_failed")
if not branch:
default_branch = None
try:
for line in git_ls_remote.split("\n"):
# Look for the line formated like :
# ref: refs/heads/master HEAD
if "ref: refs/heads/" in line:
line = line.replace("/", " ").replace("\t", " ")
default_branch = line.split()[3]
except Exception:
pass
if not default_branch:
logger.warning("Failed to parse default branch, trying 'main'")
branch = "main"
else:
if default_branch in ["testing", "dev"]:
logger.warning(
f"Trying 'master' branch instead of default '{default_branch}'"
)
branch = "master"
else:
branch = default_branch
logger.debug(m18n.n("downloading"))
@ -2522,7 +2707,7 @@ def _check_manifest_requirements(
yield (
"arch",
arch_requirement in ["all", "?"] or arch in arch_requirement,
{"current": arch, "required": arch_requirement},
{"current": arch, "required": ", ".join(arch_requirement)},
"app_arch_not_supported", # i18n: app_arch_not_supported
)
@ -2585,7 +2770,6 @@ def _check_manifest_requirements(
def _guess_webapp_path_requirement(app_folder: str) -> str:
# If there's only one "domain" and "path", validate that domain/path
# is an available url and normalize the path.
@ -2608,22 +2792,33 @@ def _guess_webapp_path_requirement(app_folder: str) -> str:
if len(domain_questions) == 1 and len(path_questions) == 1:
return "domain_and_path"
if len(domain_questions) == 1 and len(path_questions) == 0:
# This is likely to be a full-domain app...
if manifest.get("packaging_format", 0) < 2:
# This is likely to be a full-domain app...
# Confirm that this is a full-domain app This should cover most cases
# ... though anyway the proper solution is to implement some mechanism
# in the manifest for app to declare that they require a full domain
# (among other thing) so that we can dynamically check/display this
# requirement on the webadmin form and not miserably fail at submit time
# Confirm that this is a full-domain app This should cover most cases
# ... though anyway the proper solution is to implement some mechanism
# in the manifest for app to declare that they require a full domain
# (among other thing) so that we can dynamically check/display this
# requirement on the webadmin form and not miserably fail at submit time
# Full-domain apps typically declare something like path_url="/" or path=/
# and use ynh_webpath_register or yunohost_app_checkurl inside the install script
install_script_content = read_file(os.path.join(app_folder, "scripts/install"))
# Full-domain apps typically declare something like path_url="/" or path=/
# and use ynh_webpath_register or yunohost_app_checkurl inside the install script
install_script_content = read_file(
os.path.join(app_folder, "scripts/install")
)
if re.search(
r"\npath(_url)?=[\"']?/[\"']?", install_script_content
) and re.search(r"ynh_webpath_register", install_script_content):
return "full_domain"
if re.search(
r"\npath(_url)?=[\"']?/[\"']?", install_script_content
) and re.search(r"ynh_webpath_register", install_script_content):
return "full_domain"
else:
# For packaging v2 apps, check if there's a permission with url being a string
perm_resource = manifest.get("resources", {}).get("permissions")
if perm_resource is not None and isinstance(
perm_resource.get("main", {}).get("url"), str
):
return "full_domain"
return "?"
@ -2631,7 +2826,6 @@ def _guess_webapp_path_requirement(app_folder: str) -> str:
def _validate_webpath_requirement(
args: Dict[str, Any], path_requirement: str, ignore_app=None
) -> None:
domain = args.get("domain")
path = args.get("path")
@ -2679,7 +2873,6 @@ def _get_conflicting_apps(domain, path, ignore_app=None):
def _assert_no_conflicting_apps(domain, path, ignore_app=None, full_domain=False):
conflicts = _get_conflicting_apps(domain, path, ignore_app)
if conflicts:
@ -2696,12 +2889,17 @@ def _assert_no_conflicting_apps(domain, path, ignore_app=None, full_domain=False
def _make_environment_for_app_script(
app, args={}, args_prefix="APP_ARG_", workdir=None, action=None
app,
args={},
args_prefix="APP_ARG_",
workdir=None,
action=None,
force_include_app_settings=False,
):
app_setting_path = os.path.join(APPS_SETTING_PATH, app)
manifest = _get_manifest_of_app(app_setting_path)
manifest = _get_manifest_of_app(workdir if workdir else app_setting_path)
app_id, app_instance_nb = _parse_app_instance_name(app)
env_dict = {
@ -2711,6 +2909,7 @@ def _make_environment_for_app_script(
"YNH_APP_MANIFEST_VERSION": manifest.get("version", "?"),
"YNH_APP_PACKAGING_FORMAT": str(manifest["packaging_format"]),
"YNH_ARCH": system_arch(),
"YNH_DEBIAN_VERSION": debian_version(),
}
if workdir:
@ -2724,10 +2923,9 @@ def _make_environment_for_app_script(
env_dict[f"YNH_{args_prefix}{arg_name_upper}"] = str(arg_value)
# If packaging format v2, load all settings
if manifest["packaging_format"] >= 2:
if manifest["packaging_format"] >= 2 or force_include_app_settings:
env_dict["app"] = app
for setting_name, setting_value in _get_app_settings(app).items():
# Ignore special internal settings like checksum__
# (not a huge deal to load them but idk...)
if setting_name.startswith("checksum__"):
@ -2772,7 +2970,6 @@ def _parse_app_instance_name(app_instance_name: str) -> Tuple[str, int]:
def _next_instance_number_for_app(app):
# Get list of sibling apps, such as {app}, {app}__2, {app}__4
apps = _installed_apps()
sibling_app_ids = [a for a in apps if a == app or a.startswith(f"{app}__")]
@ -2790,7 +2987,6 @@ def _next_instance_number_for_app(app):
def _make_tmp_workdir_for_app(app=None):
# Create parent dir if it doesn't exists yet
if not os.path.exists(APP_TMP_WORKDIRS):
os.makedirs(APP_TMP_WORKDIRS)
@ -2820,12 +3016,10 @@ def _make_tmp_workdir_for_app(app=None):
def unstable_apps():
output = []
deprecated_apps = ["mailman", "ffsync"]
for infos in app_list(full=True)["apps"]:
if (
not infos.get("from_catalog")
or infos.get("from_catalog").get("state")
@ -2841,7 +3035,6 @@ def unstable_apps():
def _assert_system_is_sane_for_app(manifest, when):
from yunohost.service import service_status
logger.debug("Checking that required services are up and running...")
@ -2904,7 +3097,6 @@ def _assert_system_is_sane_for_app(manifest, when):
def app_dismiss_notification(app, name):
assert isinstance(name, str)
name = name.lower()
assert name in ["post_install", "post_upgrade"]

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -157,7 +157,6 @@ def _read_apps_catalog_list():
def _actual_apps_catalog_api_url(base_url):
return f"{base_url}/v{APPS_CATALOG_API_VERSION}/apps.json"
@ -269,7 +268,6 @@ def _load_apps_catalog():
merged_catalog = {"apps": {}, "categories": [], "antifeatures": []}
for apps_catalog_id in [L["id"] for L in _read_apps_catalog_list()]:
# Let's load the json from cache for this catalog
cache_file = f"{APPS_CATALOG_CACHE}/{apps_catalog_id}.json"
@ -298,7 +296,6 @@ def _load_apps_catalog():
# Add apps from this catalog to the output
for app, info in apps_catalog_content["apps"].items():
# (N.B. : there's a small edge case where multiple apps catalog could be listing the same apps ...
# in which case we keep only the first one found)
if app in merged_catalog["apps"]:

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -38,14 +38,12 @@ AUTH_DN = "uid={uid},ou=users,dc=yunohost,dc=org"
class Authenticator(BaseAuthenticator):
name = "ldap_admin"
def __init__(self, *args, **kwargs):
pass
def _authenticate_credentials(self, credentials=None):
try:
admins = (
_get_ldap_interface()
@ -125,7 +123,6 @@ class Authenticator(BaseAuthenticator):
con.unbind_s()
def set_session_cookie(self, infos):
from bottle import response
assert isinstance(infos, dict)
@ -145,7 +142,6 @@ class Authenticator(BaseAuthenticator):
)
def get_session_cookie(self, raise_if_no_session_exists=True):
from bottle import request
try:
@ -174,7 +170,6 @@ class Authenticator(BaseAuthenticator):
return infos
def delete_session_cookie(self):
from bottle import response
response.set_cookie("yunohost.admin", "", max_age=-1)

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -32,6 +32,7 @@ from functools import reduce
from packaging import version
from moulinette import Moulinette, m18n
from moulinette.utils.text import random_ascii
from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import (
read_file,
@ -51,6 +52,7 @@ from yunohost.app import (
_make_environment_for_app_script,
_make_tmp_workdir_for_app,
_get_manifest_of_app,
app_remove,
)
from yunohost.hook import (
hook_list,
@ -93,7 +95,6 @@ class BackupRestoreTargetsManager:
"""
def __init__(self):
self.targets = {}
self.results = {"system": {}, "apps": {}}
@ -349,7 +350,6 @@ class BackupManager:
if not os.path.isdir(self.work_dir):
mkdir(self.work_dir, 0o750, parents=True)
elif self.is_tmp_work_dir:
logger.debug(
"temporary directory for backup '%s' already exists... attempting to clean it",
self.work_dir,
@ -887,7 +887,6 @@ class RestoreManager:
@property
def success(self):
successful_apps = self.targets.list("apps", include=["Success", "Warning"])
successful_system = self.targets.list("system", include=["Success", "Warning"])
@ -939,7 +938,17 @@ class RestoreManager:
)
logger.debug("executing the post-install...")
tools_postinstall(domain, "Yunohost", True)
# Use a dummy password which is not gonna be saved anywhere
# because the next thing to happen should be that a full restore of the LDAP db will happen
tools_postinstall(
domain,
"tmpadmin",
"Tmp Admin",
password=random_ascii(70),
ignore_dyndns=True,
overwrite_root_password=False,
)
def clean(self):
"""
@ -1187,7 +1196,8 @@ class RestoreManager:
self._restore_apps()
except Exception as e:
raise YunohostError(
f"The following critical error happened during restoration: {e}"
f"The following critical error happened during restoration: {e}",
raw_msg=True,
)
finally:
self.clean()
@ -1366,8 +1376,6 @@ class RestoreManager:
from yunohost.user import user_group_list
from yunohost.permission import (
permission_create,
permission_delete,
user_permission_list,
permission_sync_to_user,
)
@ -1443,7 +1451,6 @@ class RestoreManager:
existing_groups = user_group_list()["groups"]
for permission_name, permission_infos in permissions.items():
if "allowed" not in permission_infos:
logger.warning(
f"'allowed' key corresponding to allowed groups for permission {permission_name} not found when restoring app {app_instance_name} … You might have to reconfigure permissions yourself."
@ -1521,6 +1528,7 @@ class RestoreManager:
AppResourceManager(app_instance_name, wanted=manifest, current={}).apply(
rollback_and_raise_exception_if_failure=True,
operation_logger=operation_logger,
action="restore",
)
# Execute the app install script
@ -1547,39 +1555,9 @@ class RestoreManager:
self.targets.set_result("apps", app_instance_name, "Success")
operation_logger.success()
else:
self.targets.set_result("apps", app_instance_name, "Error")
remove_script = os.path.join(app_scripts_in_archive, "remove")
# Setup environment for remove script
env_dict_remove = _make_environment_for_app_script(
app_instance_name, workdir=app_workdir
)
remove_operation_logger = OperationLogger(
"remove_on_failed_restore",
[("app", app_instance_name)],
env=env_dict_remove,
)
remove_operation_logger.start()
# Execute remove script
if hook_exec(remove_script, env=env_dict_remove)[0] != 0:
msg = m18n.n("app_not_properly_removed", app=app_instance_name)
logger.warning(msg)
remove_operation_logger.error(msg)
else:
remove_operation_logger.success()
# Cleaning app directory
shutil.rmtree(app_settings_new_path, ignore_errors=True)
# Remove all permission in LDAP for this app
for permission_name in user_permission_list()["permissions"].keys():
if permission_name.startswith(app_instance_name + "."):
permission_delete(permission_name, force=True)
# TODO Cleaning app hooks
app_remove(app_instance_name, force_workdir=app_workdir)
logger.error(failure_message_with_debug_instructions)
@ -1938,12 +1916,10 @@ class CopyBackupMethod(BackupMethod):
class TarBackupMethod(BackupMethod):
method_name = "tar"
@property
def _archive_file(self):
if isinstance(self.manager, BackupManager) and settings_get(
"misc.backup.backup_compress_tar_archives"
):
@ -2302,7 +2278,7 @@ def backup_create(
)
backup_manager.backup()
logger.success(m18n.n("backup_created"))
logger.success(m18n.n("backup_created", name=backup_manager.name))
operation_logger.success()
return {
@ -2400,6 +2376,7 @@ def backup_list(with_info=False, human_readable=False):
# (we do a realpath() to resolve symlinks)
archives = glob(f"{ARCHIVES_PATH}/*.tar.gz") + glob(f"{ARCHIVES_PATH}/*.tar")
archives = {os.path.realpath(archive) for archive in archives}
archives = {archive for archive in archives if os.path.exists(archive)}
archives = sorted(archives, key=lambda x: os.path.getctime(x))
# Extract only filename without the extension
@ -2430,7 +2407,6 @@ def backup_list(with_info=False, human_readable=False):
def backup_download(name):
if Moulinette.interface.type != "api":
logger.error(
"This option is only meant for the API/webadmin and doesn't make sense for the command line."
@ -2571,7 +2547,6 @@ def backup_info(name, with_details=False, human_readable=False):
if "size_details" in info.keys():
for category in ["apps", "system"]:
for name, key_info in info[category].items():
if category == "system":
# Stupid legacy fix for weird format between 3.5 and 3.6
if isinstance(key_info, dict):
@ -2631,7 +2606,7 @@ def backup_delete(name):
hook_callback("post_backup_delete", args=[name])
logger.success(m18n.n("backup_deleted"))
logger.success(m18n.n("backup_deleted", name=name))
#

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -20,7 +20,7 @@ import os
import sys
import shutil
import subprocess
import glob
from glob import glob
from datetime import datetime
@ -124,10 +124,8 @@ def certificate_install(domain_list, force=False, no_checks=False, self_signed=F
def _certificate_install_selfsigned(domain_list, force=False):
failed_cert_install = []
for domain in domain_list:
operation_logger = OperationLogger(
"selfsigned_cert_install", [("domain", domain)], args={"force": force}
)
@ -238,7 +236,6 @@ def _certificate_install_letsencrypt(domains, force=False, no_checks=False):
# certificates
if domains == []:
for domain in domain_list()["domains"]:
status = _get_status(domain)
if status["CA_type"] != "selfsigned":
continue
@ -260,7 +257,6 @@ def _certificate_install_letsencrypt(domains, force=False, no_checks=False):
# Actual install steps
failed_cert_install = []
for domain in domains:
if not no_checks:
try:
_check_domain_is_ready_for_ACME(domain)
@ -317,7 +313,6 @@ def certificate_renew(domains, force=False, no_checks=False, email=False):
# certificates
if domains == []:
for domain in domain_list()["domains"]:
# Does it have a Let's Encrypt cert?
status = _get_status(domain)
if status["CA_type"] != "letsencrypt":
@ -342,7 +337,6 @@ def certificate_renew(domains, force=False, no_checks=False, email=False):
# Else, validate the domain list given
else:
for domain in domains:
# Is it in Yunohost domain list?
_assert_domain_exists(domain)
@ -369,7 +363,6 @@ def certificate_renew(domains, force=False, no_checks=False, email=False):
# Actual renew steps
failed_cert_install = []
for domain in domains:
if not no_checks:
try:
_check_domain_is_ready_for_ACME(domain)
@ -468,13 +461,11 @@ investigate :
def _check_acme_challenge_configuration(domain):
domain_conf = f"/etc/nginx/conf.d/{domain}.conf"
return "include /etc/nginx/conf.d/acme-challenge.conf.inc" in read_file(domain_conf)
def _fetch_and_enable_new_certificate(domain, no_checks=False):
if not os.path.exists(ACCOUNT_KEY_FILE):
_generate_account_key()
@ -628,7 +619,6 @@ def _prepare_certificate_signing_request(domain, key_file, output_folder):
def _get_status(domain):
cert_file = os.path.join(CERT_FOLDER, domain, "crt.pem")
if not os.path.isfile(cert_file):
@ -744,10 +734,10 @@ def _enable_certificate(domain, new_cert_folder):
logger.debug("Restarting services...")
for service in ("dovecot", "metronome"):
# Ugly trick to not restart metronome if it's not installed
if (
service == "metronome"
and os.system("dpkg --list | grep -q 'ii *metronome'") != 0
# Ugly trick to not restart metronome if it's not installed or no domain configured for XMPP
if service == "metronome" and (
os.system("dpkg --list | grep -q 'ii *metronome'") != 0
or not glob("/etc/metronome/conf.d/*.cfg.lua")
):
continue
_run_service_command("restart", service)
@ -777,7 +767,6 @@ def _backup_current_cert(domain):
def _check_domain_is_ready_for_ACME(domain):
from yunohost.domain import _get_parent_domain_of
from yunohost.dns import _get_dns_zone_for_domain
from yunohost.utils.dns import is_yunohost_dyndns_domain
@ -864,9 +853,8 @@ def _regen_dnsmasq_if_needed():
do_regen = False
# For all domain files in DNSmasq conf...
domainsconf = glob.glob("/etc/dnsmasq.d/*.*")
domainsconf = glob("/etc/dnsmasq.d/*.*")
for domainconf in domainsconf:
# Look for the IP, it's in the lines with this format :
# host-record=the.domain.tld,11.22.33.44
for line in open(domainconf).readlines():

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -35,13 +35,11 @@ logger = log.getActionLogger("yunohost.diagnosis")
class MyDiagnoser(Diagnoser):
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
cache_duration = 600
dependencies: List[str] = []
def run(self):
virt = system_virt()
if virt.lower() == "none":
virt = "bare-metal"
@ -193,7 +191,6 @@ class MyDiagnoser(Diagnoser):
)
def bad_sury_packages(self):
packages_to_check = ["openssl", "libssl1.1", "libssl-dev"]
for package in packages_to_check:
cmd = "dpkg --list | grep '^ii' | grep gbp | grep -q -w %s" % package
@ -209,12 +206,10 @@ class MyDiagnoser(Diagnoser):
yield (package, version_to_downgrade_to)
def backports_in_sources_list(self):
cmd = "grep -q -nr '^ *deb .*-backports' /etc/apt/sources.list*"
return os.system(cmd) == 0
def number_of_recent_auth_failure(self):
# Those syslog facilities correspond to auth and authpriv
# c.f. https://unix.stackexchange.com/a/401398
# and https://wiki.archlinux.org/title/Systemd/Journal#Facility

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -28,18 +28,17 @@ from moulinette.utils.filesystem import read_file
from yunohost.diagnosis import Diagnoser
from yunohost.utils.network import get_network_interfaces
from yunohost.settings import settings_get
logger = log.getActionLogger("yunohost.diagnosis")
class MyDiagnoser(Diagnoser):
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
cache_duration = 600
dependencies: List[str] = []
def run(self):
# ############################################################ #
# PING : Check that we can ping outside at least in ipv4 or v6 #
# ############################################################ #
@ -118,10 +117,17 @@ class MyDiagnoser(Diagnoser):
else:
return local_ip
def is_ipvx_important(x):
return settings_get("misc.network.dns_exposure") in ["both", "ipv" + str(x)]
yield dict(
meta={"test": "ipv4"},
data={"global": ipv4, "local": get_local_ip("ipv4")},
status="SUCCESS" if ipv4 else "ERROR",
status="SUCCESS"
if ipv4
else "ERROR"
if is_ipvx_important(4)
else "WARNING",
summary="diagnosis_ip_connected_ipv4" if ipv4 else "diagnosis_ip_no_ipv4",
details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv4 else None,
)
@ -129,17 +135,24 @@ class MyDiagnoser(Diagnoser):
yield dict(
meta={"test": "ipv6"},
data={"global": ipv6, "local": get_local_ip("ipv6")},
status="SUCCESS" if ipv6 else "WARNING",
status="SUCCESS"
if ipv6
else "ERROR"
if settings_get("misc.network.dns_exposure") == "ipv6"
else "WARNING",
summary="diagnosis_ip_connected_ipv6" if ipv6 else "diagnosis_ip_no_ipv6",
details=["diagnosis_ip_global", "diagnosis_ip_local"]
if ipv6
else ["diagnosis_ip_no_ipv6_tip"],
else [
"diagnosis_ip_no_ipv6_tip_important"
if is_ipvx_important(6)
else "diagnosis_ip_no_ipv6_tip"
],
)
# TODO / FIXME : add some attempt to detect ISP (using whois ?) ?
def can_ping_outside(self, protocol=4):
assert protocol in [
4,
6,
@ -218,7 +231,6 @@ class MyDiagnoser(Diagnoser):
return len(content) == 1 and content[0].split() == ["nameserver", "127.0.0.1"]
def get_public_ip(self, protocol=4):
# FIXME - TODO : here we assume that DNS resolution for ip.yunohost.org is working
# but if we want to be able to diagnose DNS resolution issues independently from
# internet connectivity, we gotta rely on fixed IPs first....

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -43,13 +43,11 @@ logger = log.getActionLogger("yunohost.diagnosis")
class MyDiagnoser(Diagnoser):
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
cache_duration = 600
dependencies: List[str] = ["ip"]
def run(self):
main_domain = _get_maindomain()
major_domains = domain_list(exclude_subdomains=True)["domains"]
@ -77,7 +75,6 @@ class MyDiagnoser(Diagnoser):
yield report
def check_domain(self, domain, is_main_domain):
if is_special_use_tld(domain):
yield dict(
meta={"domain": domain},
@ -97,13 +94,11 @@ class MyDiagnoser(Diagnoser):
categories = ["basic", "mail", "xmpp", "extra"]
for category in categories:
records = expected_configuration[category]
discrepancies = []
results = {}
for r in records:
id_ = r["type"] + ":" + r["name"]
fqdn = r["name"] + "." + base_dns_zone if r["name"] != "@" else domain
@ -182,7 +177,6 @@ class MyDiagnoser(Diagnoser):
yield output
def get_current_record(self, fqdn, type_):
success, answers = dig(fqdn, type_, resolvers="force_external")
if success != "ok":

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -21,16 +21,15 @@ from typing import List
from yunohost.diagnosis import Diagnoser
from yunohost.service import _get_services
from yunohost.settings import settings_get
class MyDiagnoser(Diagnoser):
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
cache_duration = 600
dependencies: List[str] = ["ip"]
def run(self):
# TODO: report a warning if port 53 or 5353 is exposed to the outside world...
# This dict is something like :
@ -46,7 +45,10 @@ class MyDiagnoser(Diagnoser):
ipversions = []
ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {}
if ipv4.get("status") == "SUCCESS":
if (
ipv4.get("status") == "SUCCESS"
or settings_get("misc.network.dns_exposure") != "ipv6"
):
ipversions.append(4)
# To be discussed: we could also make this check dependent on the
@ -120,7 +122,10 @@ class MyDiagnoser(Diagnoser):
for record in dnsrecords.get("items", [])
)
if failed == 4 or ipv6_is_important():
if (
failed == 4
and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]
) or (failed == 6 and ipv6_is_important()):
yield dict(
meta={"port": port},
data={

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -26,22 +26,20 @@ from moulinette.utils.filesystem import read_file, mkdir, rm
from yunohost.diagnosis import Diagnoser
from yunohost.domain import domain_list
from yunohost.utils.dns import is_special_use_tld
from yunohost.settings import settings_get
DIAGNOSIS_SERVER = "diagnosis.yunohost.org"
class MyDiagnoser(Diagnoser):
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
cache_duration = 600
dependencies: List[str] = ["ip"]
def run(self):
all_domains = domain_list()["domains"]
domains_to_check = []
for domain in all_domains:
# If the diagnosis location ain't defined, can't do diagnosis,
# probably because nginx conf manually modified...
nginx_conf = "/etc/nginx/conf.d/%s.conf" % domain
@ -76,7 +74,9 @@ class MyDiagnoser(Diagnoser):
ipversions = []
ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {}
if ipv4.get("status") == "SUCCESS":
if ipv4.get("status") == "SUCCESS" and settings_get(
"misc.network.dns_exposure"
) in ["both", "ipv4"]:
ipversions.append(4)
# To be discussed: we could also make this check dependent on the
@ -96,7 +96,10 @@ class MyDiagnoser(Diagnoser):
# "curl --head the.global.ip" will simply timeout...
if self.do_hairpinning_test:
global_ipv4 = ipv4.get("data", {}).get("global", None)
if global_ipv4:
if global_ipv4 and settings_get("misc.network.dns_exposure") in [
"both",
"ipv4",
]:
try:
requests.head("http://" + global_ipv4, timeout=5)
except requests.exceptions.Timeout:
@ -113,7 +116,6 @@ class MyDiagnoser(Diagnoser):
pass
def test_http(self, domains, ipversions):
results = {}
for ipversion in ipversions:
try:
@ -138,7 +140,6 @@ class MyDiagnoser(Diagnoser):
return
for domain in domains:
# i18n: diagnosis_http_bad_status_code
# i18n: diagnosis_http_connection_error
# i18n: diagnosis_http_timeout
@ -147,7 +148,10 @@ class MyDiagnoser(Diagnoser):
if all(
results[ipversion][domain]["status"] == "ok" for ipversion in ipversions
):
if 4 in ipversions:
if 4 in ipversions and settings_get("misc.network.dns_exposure") in [
"both",
"ipv4",
]:
self.do_hairpinning_test = True
yield dict(
meta={"domain": domain},
@ -185,7 +189,9 @@ class MyDiagnoser(Diagnoser):
)
AAAA_status = dnsrecords.get("data", {}).get("AAAA:@")
return AAAA_status in ["OK", "WRONG"]
return AAAA_status in ["OK", "WRONG"] or settings_get(
"misc.network.dns_exposure"
) in ["both", "ipv6"]
if failed == 4 or ipv6_is_important_for_this_domain():
yield dict(

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -38,13 +38,11 @@ logger = log.getActionLogger("yunohost.diagnosis")
class MyDiagnoser(Diagnoser):
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
cache_duration = 600
dependencies: List[str] = ["ip"]
def run(self):
self.ehlo_domain = _get_maindomain()
self.mail_domains = domain_list()["domains"]
self.ipversions, self.ips = self.get_ips_checked()
@ -279,7 +277,7 @@ class MyDiagnoser(Diagnoser):
data={"error": str(e)},
status="ERROR",
summary="diagnosis_mail_queue_unavailable",
details="diagnosis_mail_queue_unavailable_details",
details=["diagnosis_mail_queue_unavailable_details"],
)
else:
if pending_emails > 100:
@ -301,13 +299,17 @@ class MyDiagnoser(Diagnoser):
outgoing_ipversions = []
outgoing_ips = []
ipv4 = Diagnoser.get_cached_report("ip", {"test": "ipv4"}) or {}
if ipv4.get("status") == "SUCCESS":
if ipv4.get("status") == "SUCCESS" and settings_get(
"misc.network.dns_exposure"
) in ["both", "ipv4"]:
outgoing_ipversions.append(4)
global_ipv4 = ipv4.get("data", {}).get("global", {})
if global_ipv4:
outgoing_ips.append(global_ipv4)
if settings_get("email.smtp.smtp_allow_ipv6"):
if settings_get("email.smtp.smtp_allow_ipv6") or settings_get(
"misc.network.dns_exposure"
) in ["both", "ipv6"]:
ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) or {}
if ipv6.get("status") == "SUCCESS":
outgoing_ipversions.append(6)

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -24,17 +24,14 @@ from yunohost.service import service_status
class MyDiagnoser(Diagnoser):
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
cache_duration = 300
dependencies: List[str] = []
def run(self):
all_result = service_status()
for service, result in sorted(all_result.items()):
item = dict(
meta={"service": service},
data={

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -28,13 +28,11 @@ from yunohost.diagnosis import Diagnoser
class MyDiagnoser(Diagnoser):
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
cache_duration = 300
dependencies: List[str] = []
def run(self):
MB = 1024**2
GB = MB * 1024
@ -189,7 +187,6 @@ class MyDiagnoser(Diagnoser):
return []
def analyzed_kern_log():
cmd = 'tail -n 10000 /var/log/kern.log | grep "oom_reaper: reaped process" || true'
out = check_output(cmd)
lines = out.split("\n") if out else []

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -27,13 +27,11 @@ from moulinette.utils.filesystem import read_file
class MyDiagnoser(Diagnoser):
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
cache_duration = 300
dependencies: List[str] = []
def run(self):
regenconf_modified_files = list(self.manually_modified_files())
if not regenconf_modified_files:
@ -82,7 +80,6 @@ class MyDiagnoser(Diagnoser):
)
def manually_modified_files(self):
for category, infos in _get_regenconf_infos().items():
for path, hash_ in infos["conffiles"].items():
if hash_ != _calculate_hash(path):

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -25,13 +25,11 @@ from yunohost.diagnosis import Diagnoser
class MyDiagnoser(Diagnoser):
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
cache_duration = 300
dependencies: List[str] = []
def run(self):
apps = app_list(full=True)["apps"]
for app in apps:
app["issues"] = list(self.issues(app))
@ -44,7 +42,6 @@ class MyDiagnoser(Diagnoser):
)
else:
for app in apps:
if not app["issues"]:
continue
@ -62,7 +59,6 @@ class MyDiagnoser(Diagnoser):
)
def issues(self, app):
# Check quality level in catalog
if not app.get("from_catalog") or app["from_catalog"].get("state") != "working":

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -45,7 +45,6 @@ def diagnosis_list():
def diagnosis_get(category, item):
# Get all the categories
all_categories_names = _list_diagnosis_categories()
@ -69,7 +68,6 @@ def diagnosis_get(category, item):
def diagnosis_show(
categories=[], issues=False, full=False, share=False, human_readable=False
):
if not os.path.exists(DIAGNOSIS_CACHE):
logger.warning(m18n.n("diagnosis_never_ran_yet"))
return
@ -90,7 +88,6 @@ def diagnosis_show(
# Fetch all reports
all_reports = []
for category in categories:
try:
report = Diagnoser.get_cached_report(category)
except Exception as e:
@ -139,7 +136,6 @@ def diagnosis_show(
def _dump_human_readable_reports(reports):
output = ""
for report in reports:
@ -159,7 +155,6 @@ def _dump_human_readable_reports(reports):
def diagnosis_run(
categories=[], force=False, except_if_never_ran_yet=False, email=False
):
if (email or except_if_never_ran_yet) and not os.path.exists(DIAGNOSIS_CACHE):
return
@ -263,7 +258,6 @@ def _diagnosis_ignore(add_filter=None, remove_filter=None, list=False):
return {"ignore_filters": configuration.get("ignore_filters", {})}
def validate_filter_criterias(filter_):
# Get all the categories
all_categories_names = _list_diagnosis_categories()
@ -286,7 +280,6 @@ def _diagnosis_ignore(add_filter=None, remove_filter=None, list=False):
return category, criterias
if add_filter:
category, criterias = validate_filter_criterias(add_filter)
# Fetch current issues for the requested category
@ -320,7 +313,6 @@ def _diagnosis_ignore(add_filter=None, remove_filter=None, list=False):
return
if remove_filter:
category, criterias = validate_filter_criterias(remove_filter)
# Make sure the subdicts/lists exists
@ -394,12 +386,10 @@ def add_ignore_flag_to_issues(report):
class Diagnoser:
def __init__(self):
self.cache_file = Diagnoser.cache_file(self.id_)
self.description = Diagnoser.get_description(self.id_)
def cached_time_ago(self):
if not os.path.exists(self.cache_file):
return 99999999
return time.time() - os.path.getmtime(self.cache_file)
@ -410,7 +400,6 @@ class Diagnoser:
return write_to_json(self.cache_file, report)
def diagnose(self, force=False):
if not force and self.cached_time_ago() < self.cache_duration:
logger.debug(f"Cache still valid : {self.cache_file}")
logger.info(
@ -548,7 +537,6 @@ class Diagnoser:
@staticmethod
def i18n(report, force_remove_html_tags=False):
# "Render" the strings with m18n.n
# N.B. : we do those m18n.n right now instead of saving the already-translated report
# because we can't be sure we'll redisplay the infos with the same locale as it
@ -558,7 +546,6 @@ class Diagnoser:
report["description"] = Diagnoser.get_description(report["id"])
for item in report["items"]:
# For the summary and each details, we want to call
# m18n() on the string, with the appropriate data for string
# formatting which can come from :
@ -597,7 +584,6 @@ class Diagnoser:
@staticmethod
def remote_diagnosis(uri, data, ipversion, timeout=30):
# Lazy loading for performance
import requests
import socket
@ -646,7 +632,6 @@ class Diagnoser:
def _list_diagnosis_categories():
paths = glob.glob(os.path.dirname(__file__) + "/diagnosers/??-*.py")
names = [
name.split("-")[-1]
@ -657,7 +642,6 @@ def _list_diagnosis_categories():
def _load_diagnoser(diagnoser_name):
logger.debug(f"Loading diagnoser {diagnoser_name}")
paths = glob.glob(os.path.dirname(__file__) + f"/diagnosers/??-{diagnoser_name}.py")

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -38,6 +38,7 @@ from yunohost.domain import (
from yunohost.utils.dns import dig, is_yunohost_dyndns_domain, is_special_use_tld
from yunohost.utils.error import YunohostValidationError, YunohostError
from yunohost.utils.network import get_public_ip
from yunohost.settings import settings_get
from yunohost.log import is_unit_operation
from yunohost.hook import hook_callback
@ -137,7 +138,7 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False):
{"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},
{"type": "CAA", "name": "@", "value": "0 issue \"letsencrypt.org\"", "ttl": 3600},
],
"example_of_a_custom_rule": [
{"type": "SRV", "name": "_matrix", "value": "domain.tld.", "ttl": 3600}
@ -168,7 +169,6 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False):
base_dns_zone = _get_dns_zone_for_domain(base_domain)
for domain, settings in domains_settings.items():
# Domain # Base DNS zone # Basename # Suffix #
# ------------------ # ----------------- # --------- # -------- #
# domain.tld # domain.tld # @ # #
@ -185,7 +185,7 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False):
###########################
# Basic ipv4/ipv6 records #
###########################
if ipv4:
if ipv4 and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]:
basic.append([basename, ttl, "A", ipv4])
if ipv6:
@ -240,7 +240,7 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False):
# Only recommend wildcard and CAA for the top level
if domain == base_domain:
if ipv4:
if ipv4 and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]:
extra.append([f"*{suffix}", ttl, "A", ipv4])
if ipv6:
@ -248,7 +248,7 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False):
elif include_empty_AAAA_if_no_ipv6:
extra.append([f"*{suffix}", ttl, "AAAA", None])
extra.append([basename, ttl, "CAA", '128 issue "letsencrypt.org"'])
extra.append([basename, ttl, "CAA", '0 issue "letsencrypt.org"'])
####################
# Standard records #
@ -461,7 +461,6 @@ def _get_dns_zone_for_domain(domain):
# We don't wan't to do A NS request on the tld
for parent in parent_list[0:-1]:
# Check if there's a NS record for that domain
answer = dig(parent, rdtype="NS", full_answers=True, resolvers="force_external")
@ -502,7 +501,6 @@ def _get_relative_name_for_dns_zone(domain, base_dns_zone):
def _get_registrar_config_section(domain):
from lexicon.providers.auto import _relevant_provider_for_domain
registrar_infos = {
@ -516,7 +514,6 @@ def _get_registrar_config_section(domain):
# If parent domain exists in yunohost
parent_domain = _get_parent_domain_of(domain, topest=True)
if parent_domain:
# Dirty hack to have a link on the webadmin
if Moulinette.interface.type == "api":
parent_domain_link = f"[{parent_domain}](#/domains/{parent_domain}/dns)"
@ -571,7 +568,6 @@ def _get_registrar_config_section(domain):
}
)
else:
registrar_infos["registrar"] = OrderedDict(
{
"type": "alert",
@ -595,7 +591,12 @@ def _get_registrar_config_section(domain):
# TODO : add a help tip with the link to the registar's API doc (c.f. Lexicon's README)
registrar_list = read_toml(DOMAIN_REGISTRAR_LIST_PATH)
registrar_credentials = registrar_list[registrar]
registrar_credentials = registrar_list.get(registrar)
if registrar_credentials is None:
logger.warning(
f"Registrar {registrar} unknown / Should be added to YunoHost's registrar_list.toml by the development team!"
)
registrar_credentials = {}
for credential, infos in registrar_credentials.items():
infos["default"] = infos.get("default", "")
infos["optional"] = infos.get("optional", "False")
@ -605,7 +606,6 @@ def _get_registrar_config_section(domain):
def _get_registar_settings(domain):
_assert_domain_exists(domain)
settings = domain_config_get(domain, key="dns.registrar", export=True)
@ -679,7 +679,6 @@ def domain_dns_push(operation_logger, domain, dry_run=False, force=False, purge=
wanted_records = []
for records in _build_dns_conf(domain).values():
for record in records:
# Make sure the name is a FQDN
name = (
f"{record['name']}.{base_dns_zone}"
@ -754,7 +753,6 @@ def domain_dns_push(operation_logger, domain, dry_run=False, force=False, purge=
]
for record in current_records:
# Try to get rid of weird stuff like ".domain.tld" or "@.domain.tld"
record["name"] = record["name"].strip("@").strip(".")
@ -804,7 +802,6 @@ def domain_dns_push(operation_logger, domain, dry_run=False, force=False, purge=
comparison[(record["type"], record["name"])]["wanted"].append(record)
for type_and_name, records in comparison.items():
#
# Step 1 : compute a first "diff" where we remove records which are the same on both sides
#
@ -948,9 +945,7 @@ def domain_dns_push(operation_logger, domain, dry_run=False, force=False, purge=
results = {"warnings": [], "errors": []}
for action in ["delete", "create", "update"]:
for record in changes[action]:
relative_name = _get_relative_name_for_dns_zone(
record["name"], base_dns_zone
)
@ -975,6 +970,9 @@ def domain_dns_push(operation_logger, domain, dry_run=False, force=False, purge=
f"Pushing {record['type']} records is not properly supported by Lexicon/Godaddy."
)
continue
elif registrar == "gandi":
if record["name"] == base_dns_zone:
record["name"] = "@." + record["name"]
record["action"] = action
query = (
@ -1035,7 +1033,6 @@ def _set_managed_dns_records_hashes(domain: str, hashes: list) -> None:
def _hash_dns_record(record: dict) -> int:
fields = ["name", "type", "content"]
record_ = {f: record.get(f) for f in fields}

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -33,7 +33,8 @@ from yunohost.app import (
_get_conflicting_apps,
)
from yunohost.regenconf import regen_conf, _force_clear_hashes, _process_regen_conf
from yunohost.utils.config import ConfigPanel, Question
from yunohost.utils.configpanel import ConfigPanel
from yunohost.utils.form import Question
from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.utils.dns import is_yunohost_dyndns_domain
from yunohost.log import is_unit_operation
@ -188,7 +189,6 @@ def _assert_domain_exists(domain):
def _list_subdomains_of(parent_domain):
_assert_domain_exists(parent_domain)
out = []
@ -200,7 +200,6 @@ def _list_subdomains_of(parent_domain):
def _get_parent_domain_of(domain, return_self=False, topest=False):
domains = _get_domains(exclude_subdomains=topest)
domain_ = domain
@ -657,7 +656,6 @@ class DomainConfigPanel(ConfigPanel):
regen_conf(names=stuff_to_regen_conf)
def _get_toml(self):
toml = super()._get_toml()
toml["feature"]["xmpp"]["xmpp"]["default"] = (
@ -679,7 +677,6 @@ class DomainConfigPanel(ConfigPanel):
# Cert stuff
if not filter_key or filter_key[0] == "cert":
from yunohost.certificate import certificate_status
status = certificate_status([self.entity], full=True)["certificates"][
@ -697,16 +694,29 @@ class DomainConfigPanel(ConfigPanel):
f"domain_config_cert_summary_{status['summary']}"
)
# Other specific strings used in config panels
# i18n: domain_config_cert_renew_help
# FIXME: Ugly hack to save the cert status and reinject it in _load_current_values ...
self.cert_status = status
return toml
def _load_current_values(self):
def get(self, key="", mode="classic"):
result = super().get(key=key, mode=mode)
if mode == "full":
for panel, section, option in self._iterate():
# This injects:
# i18n: domain_config_cert_renew_help
# i18n: domain_config_default_app_help
# i18n: domain_config_xmpp_help
if m18n.key_exists(self.config["i18n"] + "_" + option["id"] + "_help"):
option["help"] = m18n.n(
self.config["i18n"] + "_" + option["id"] + "_help"
)
return self.config
return result
def _load_current_values(self):
# TODO add mechanism to share some settings with other domains on the same zone
super()._load_current_values()
@ -724,7 +734,6 @@ class DomainConfigPanel(ConfigPanel):
def domain_action_run(domain, action, args=None):
import urllib.parse
if action == "cert.cert.cert_install":
@ -739,7 +748,6 @@ def domain_action_run(domain, action, args=None):
def _get_domain_settings(domain: str) -> dict:
_assert_domain_exists(domain)
if os.path.exists(f"{DOMAIN_SETTINGS_DIR}/{domain}.yml"):
@ -749,7 +757,6 @@ def _get_domain_settings(domain: str) -> dict:
def _set_domain_settings(domain: str, settings: dict) -> None:
_assert_domain_exists(domain)
write_to_yaml(f"{DOMAIN_SETTINGS_DIR}/{domain}.yml", settings)

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -329,7 +329,6 @@ def dyndns_update(
for dns_auth in DYNDNS_DNS_AUTH:
for type_ in ["A", "AAAA"]:
ok, result = dig(dns_auth, type_)
if ok == "ok" and len(result) and result[0]:
auth_resolvers.append(result[0])
@ -340,7 +339,6 @@ def dyndns_update(
)
def resolve_domain(domain, rdtype):
ok, result = dig(domain, rdtype, resolvers=auth_resolvers)
if ok == "ok":
return result[0] if len(result) else None

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -101,7 +101,9 @@ def firewall_allow(
# Update and reload firewall
_update_firewall_file(firewall)
if not no_reload or (reload_only_if_change and changed):
if (not reload_only_if_change and not no_reload) or (
reload_only_if_change and changed
):
return firewall_reload()
@ -180,7 +182,9 @@ def firewall_disallow(
# Update and reload firewall
_update_firewall_file(firewall)
if not no_reload or (reload_only_if_change and changed):
if (not reload_only_if_change and not no_reload) or (
reload_only_if_change and changed
):
return firewall_reload()
@ -415,7 +419,6 @@ def firewall_upnp(action="status", no_refresh=False):
for protocol in ["TCP", "UDP"]:
if protocol + "_TO_CLOSE" in firewall["uPnP"]:
for port in firewall["uPnP"][protocol + "_TO_CLOSE"]:
if not isinstance(port, int):
# FIXME : how should we handle port ranges ?
logger.warning("Can't use UPnP to close '%s'" % port)
@ -430,7 +433,6 @@ def firewall_upnp(action="status", no_refresh=False):
firewall["uPnP"][protocol + "_TO_CLOSE"] = []
for port in firewall["uPnP"][protocol]:
if not isinstance(port, int):
# FIXME : how should we handle port ranges ?
logger.warning("Can't use UPnP to open '%s'" % port)

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -339,7 +339,6 @@ def hook_exec(
raise YunohostError("file_does_not_exist", path=path)
def is_relevant_warning(msg):
# Ignore empty warning messages...
if not msg:
return False
@ -353,6 +352,31 @@ def hook_exec(
r"dpkg: warning: while removing .* not empty so not removed",
r"apt-key output should not be parsed",
r"update-rc.d: ",
r"update-alternatives: ",
# Postgresql boring messages -_-
r"Adding user postgres to group ssl-cert",
r"Building PostgreSQL dictionaries from .*",
r"Removing obsolete dictionary files",
r"Creating new PostgreSQL cluster",
r"/usr/lib/postgresql/13/bin/initdb",
r"The files belonging to this database system will be owned by user",
r"This user must also own the server process.",
r"The database cluster will be initialized with locale",
r"The default database encoding has accordingly been set to",
r"The default text search configuration will be set to",
r"Data page checksums are disabled.",
r"fixing permissions on existing directory /var/lib/postgresql/13/main ... ok",
r"creating subdirectories \.\.\. ok",
r"selecting dynamic .* \.\.\. ",
r"selecting default .* \.\.\. ",
r"creating configuration files \.\.\. ok",
r"running bootstrap script \.\.\. ok",
r"performing post-bootstrap initialization \.\.\. ok",
r"syncing data to disk \.\.\. ok",
r"Success. You can now start the database server using:",
r"pg_ctlcluster \d\d main start",
r"Ver\s*Cluster\s*Port\s*Status\s*Owner\s*Data\s*directory",
r"/var/lib/postgresql/\d\d/main /var/log/postgresql/postgresql-\d\d-main.log",
]
return all(not re.search(w, msg) for w in irrelevant_warnings)
@ -389,7 +413,6 @@ def hook_exec(
def _hook_exec_bash(path, args, chdir, env, user, return_format, loggers):
from moulinette.utils.process import call_async_output
# Construct command variables
@ -477,7 +500,6 @@ def _hook_exec_bash(path, args, chdir, env, user, return_format, loggers):
def _hook_exec_python(path, args, env, loggers):
dir_ = os.path.dirname(path)
name = os.path.splitext(os.path.basename(path))[0]
@ -497,7 +519,6 @@ def _hook_exec_python(path, args, env, loggers):
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")

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2022 YunoHost Contributors
# Copyright (c) 2023 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
@ -16,6 +16,7 @@
# 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 copy
import os
import re
import yaml
@ -95,7 +96,6 @@ def log_list(limit=None, with_details=False, with_suboperations=False):
logs = logs[: limit * 5]
for log in logs:
base_filename = log[: -len(METADATA_FILE_EXT)]
md_path = os.path.join(OPERATIONS_PATH, log)
@ -264,7 +264,6 @@ def log_show(
return
for filename in os.listdir(OPERATIONS_PATH):
if not filename.endswith(METADATA_FILE_EXT):
continue
@ -438,7 +437,6 @@ class RedactingFormatter(Formatter):
return msg
def identify_data_to_redact(self, record):
# Wrapping this in a try/except because we don't want this to
# break everything in case it fails miserably for some reason :s
try:
@ -497,7 +495,6 @@ class OperationLogger:
os.makedirs(self.path)
def parent_logger(self):
# If there are other operation logger instances
for instance in reversed(self._instances):
# Is one of these operation logger started but not yet done ?
@ -598,7 +595,17 @@ class OperationLogger:
Write or rewrite the metadata file with all metadata known
"""
dump = yaml.safe_dump(self.metadata, default_flow_style=False)
metadata = copy.copy(self.metadata)
# Remove lower-case keys ... this is because with the new v2 app packaging,
# all settings are included in the env but we probably don't want to dump all of these
# which may contain various secret/private data ...
if "env" in metadata:
metadata["env"] = {
k: v for k, v in metadata["env"].items() if k == k.upper()
}
dump = yaml.safe_dump(metadata, default_flow_style=False)
for data in self.data_to_redact:
# N.B. : we need quotes here, otherwise yaml isn't happy about loading the yml later
dump = dump.replace(data, "'**********'")
@ -732,7 +739,6 @@ class OperationLogger:
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()
@ -774,7 +780,6 @@ class OperationLogger:
def _get_datetime_from_name(name):
# Filenames are expected to follow the format:
# 20200831-170740-short_description-and-stuff

View file

@ -72,13 +72,11 @@ def _backup_pip_freeze_for_python_app_venvs():
class MyMigration(Migration):
"Upgrade the system to Debian Bullseye and Yunohost 11.x"
mode = "manual"
def run(self):
self.check_assertions()
logger.info(m18n.n("migration_0021_start"))
@ -389,7 +387,6 @@ class MyMigration(Migration):
return int(get_ynh_package_version("yunohost")["version"].split(".")[0])
def check_assertions(self):
# Be on buster (10.x) and yunohost 4.x
# NB : we do both check to cover situations where the upgrade crashed
# in the middle and debian version could be > 9.x but yunohost package
@ -453,7 +450,6 @@ class MyMigration(Migration):
@property
def disclaimer(self):
# Avoid having a super long disclaimer + uncessary check if we ain't
# on buster / yunohost 4.x anymore
# NB : we do both check to cover situations where the upgrade crashed
@ -494,7 +490,6 @@ class MyMigration(Migration):
return message
def patch_apt_sources_list(self):
sources_list = glob.glob("/etc/apt/sources.list.d/*.list")
if os.path.exists("/etc/apt/sources.list"):
sources_list.append("/etc/apt/sources.list")
@ -516,7 +511,6 @@ class MyMigration(Migration):
os.system(command)
def get_apps_equivs_packages(self):
command = (
"dpkg --get-selections"
" | grep -v deinstall"

View file

@ -27,7 +27,6 @@ MIGRATION_COMMENT = (
class MyMigration(Migration):
"Migrate php7.3-fpm 'pool' conf files to php7.4"
dependencies = ["migrate_to_bullseye"]
@ -43,7 +42,6 @@ class MyMigration(Migration):
oldphp_pool_files = [f for f in oldphp_pool_files if f != "www.conf"]
for pf in oldphp_pool_files:
# Copy the files to the php7.3 pool
src = "{}/{}".format(OLDPHP_POOLS, pf)
dest = "{}/{}".format(NEWPHP_POOLS, pf)

Some files were not shown because too many files have changed in this diff Show more