From 6a0959dd1d7ba58b1bfa19de9ae9e2d7881ad556 Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Sat, 20 Jul 2019 06:32:08 +0200 Subject: [PATCH 001/127] [fix] moulinette logs were never displayed #lol --- bin/yunohost | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/yunohost b/bin/yunohost index 10a21a9da..672c1b539 100755 --- a/bin/yunohost +++ b/bin/yunohost @@ -145,7 +145,7 @@ def _init_moulinette(debug=False, quiet=False): }, 'moulinette': { 'level': level, - 'handlers': [], + 'handlers': handlers, 'propagate': True, }, 'moulinette.interface': { From cc59501b55b269747be983aacc392f9d99aa8522 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 15 Sep 2019 16:59:34 +0200 Subject: [PATCH 002/127] Naive implementation of visitors group (without any relation to the ssowat conf yet) --- data/other/ldap_scheme.yml | 6 ++++++ locales/en.json | 3 +++ .../0011_setup_group_permission.py | 4 ++++ src/yunohost/permission.py | 13 +++++++++---- src/yunohost/user.py | 15 ++++++++++----- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/data/other/ldap_scheme.yml b/data/other/ldap_scheme.yml index caa8fffb2..660d6fbb5 100644 --- a/data/other/ldap_scheme.yml +++ b/data/other/ldap_scheme.yml @@ -57,6 +57,12 @@ children: objectClass: - posixGroup - groupOfNamesYnh + cn=visitors,ou=groups: + cn: visitors + gidNumber: "4003" + objectClass: + - posixGroup + - groupOfNamesYnh depends_children: cn=mail.main,ou=permission: diff --git a/locales/en.json b/locales/en.json index ae349edf3..5df21b684 100644 --- a/locales/en.json +++ b/locales/en.json @@ -230,6 +230,9 @@ "group_already_exist_on_system": "Group {group} already exists in the system group", "group_created": "Group '{group}' successfully created", "group_creation_failed": "Failed to create group {group}: {error}", + "group_cannot_edit_all_users": "The group 'all_users' cannot be edited manually. It is a special group meant to contain all users registered in Yunohost", + "group_cannot_edit_visitors": "The group 'visitors' cannot be edited manually. It is a special group representing anonymous visitors", + "group_cannot_edit_primary_group": "The group '{group}' cannot be edited manually. It is the primary group meant to contain only one specific user.", "group_cannot_be_edited": "The group {group} cannot be edited manually.", "group_cannot_be_deleted": "The group {group} cannot be deleted manually.", "group_deleted": "Group '{group}' deleted", diff --git a/src/yunohost/data_migrations/0011_setup_group_permission.py b/src/yunohost/data_migrations/0011_setup_group_permission.py index 8949239e0..b3e11cb14 100644 --- a/src/yunohost/data_migrations/0011_setup_group_permission.py +++ b/src/yunohost/data_migrations/0011_setup_group_permission.py @@ -63,6 +63,7 @@ class MyMigration(Migration): self.remove_if_exists("cn=sftpusers,ou=groups") self.remove_if_exists("ou=permission") self.remove_if_exists('cn=all_users,ou=groups') + self.remove_if_exists('cn=visitors,ou=groups') attr_dict = ldap_map['parents']['ou=permission'] ldap.add('ou=permission', attr_dict) @@ -70,6 +71,9 @@ class MyMigration(Migration): attr_dict = ldap_map['children']['cn=all_users,ou=groups'] ldap.add('cn=all_users,ou=groups', attr_dict) + attr_dict = ldap_map['children']['cn=visitors,ou=groups'] + ldap.add('cn=visitors,ou=groups', attr_dict) + for rdn, attr_dict in ldap_map['depends_children'].items(): ldap.add(rdn, attr_dict) except Exception as e: diff --git a/src/yunohost/permission.py b/src/yunohost/permission.py index 1472f4b88..dbfc6e6f5 100644 --- a/src/yunohost/permission.py +++ b/src/yunohost/permission.py @@ -142,10 +142,15 @@ def user_permission_update(operation_logger, permission, add=None, remove=None, # we shall warn the users that they should probably choose between one or the other, # because the current situation is probably not what they expect / is temporary ? - if len(new_allowed_groups) > 1 and "all_users" in new_allowed_groups: - # FIXME : i18n - # FIXME : write a better explanation ? - logger.warning("This permission is currently enabled for all users in addition to other groups. You probably want to either remove the 'all_users' permission or remove the specific groups currently allowed.") + if len(new_allowed_groups) > 1: + if "all_users" in new_allowed_groups: + # FIXME : i18n + # FIXME : write a better explanation ? + logger.warning("This permission is currently enabled for all users in addition to other groups. You probably want to either remove the 'all_users' permission or remove the other groups currently allowed.") + if "visitors" in new_allowed_groups: + # FIXME : i18n + # FIXME : write a better explanation ? + logger.warning("This permission is currently enabled for visitors in addition to other groups. You probably want to either remove the 'visitors' permission or remove the other groups currently allowed.") # Don't update LDAP if we update exactly the same values if set(new_allowed_groups) == set(current_allowed_groups): diff --git a/src/yunohost/user.py b/src/yunohost/user.py index c6413d7e1..581354f77 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -635,7 +635,7 @@ def user_group_delete(operation_logger, groupname, force=False, sync_perm=True): # # We also can't delete "all_users" because that's a special group... existing_users = user_list()['users'].keys() - undeletable_groups = existing_users + ["all_users", "admins"] + undeletable_groups = existing_users + ["all_users", "visitors"] if groupname in undeletable_groups and not force: raise YunohostError('group_cannot_be_deleted', group=groupname) @@ -670,13 +670,18 @@ def user_group_update(operation_logger, groupname, add=None, remove=None, force= from yunohost.permission import permission_sync_to_user from yunohost.utils.ldap import _get_ldap_interface + existing_users = user_list()['users'].keys() + # Refuse to edit a primary group of a user (e.g. group 'sam' related to user 'sam') # Those kind of group should only ever contain the user (e.g. sam) and only this one. # We also can't edit "all_users" without the force option because that's a special group... - existing_users = user_list()['users'].keys() - uneditable_groups = existing_users + ["all_users", "admins"] - if groupname in uneditable_groups and not force: - raise YunohostError('group_cannot_be_edited', group=groupname) + if not force: + if groupname == "all_users": + raise YunohostError('group_cannot_edit_all_users') + elif groupname == "all_users": + raise YunohostError('group_cannot_edit_visitors') + elif groupname in existing_users: + raise YunohostError('group_cannot_edit_primary_group', group=groupname) # We extract the uid for each member of the group to keep a simple flat list of members current_group = user_group_info(groupname)["members"] From 95a8dfa71c22103152a9241bc508de96f04cfe19 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 15 Sep 2019 16:59:44 +0200 Subject: [PATCH 003/127] Simplify part of app_ssowatconf --- src/yunohost/app.py | 49 ++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index ab290cb4d..a9c91aaf5 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -41,7 +41,7 @@ from datetime import datetime from moulinette import msignals, m18n, msettings from moulinette.utils.log import getActionLogger -from moulinette.utils.filesystem import read_json, read_toml +from moulinette.utils.filesystem import read_json, read_toml, read_yaml from yunohost.service import service_log, service_status, _run_service_command from yunohost.utils import packages @@ -1366,34 +1366,29 @@ def app_ssowatconf(): return s.split(',') if s else [] for app in apps_list: - with open(APPS_SETTING_PATH + app['id'] + '/settings.yml') as f: - app_settings = yaml.load(f) - if 'no_sso' in app_settings: - continue + app_settings = read_yaml(APPS_SETTING_PATH + app['id'] + '/settings.yml') - for item in _get_setting(app_settings, 'skipped_uris'): - if item[-1:] == '/': - item = item[:-1] - skipped_urls.append(app_settings['domain'] + app_settings['path'].rstrip('/') + item) - for item in _get_setting(app_settings, 'skipped_regex'): - skipped_regex.append(item) - for item in _get_setting(app_settings, 'unprotected_uris'): - if item[-1:] == '/': - item = item[:-1] - unprotected_urls.append(app_settings['domain'] + app_settings['path'].rstrip('/') + item) - for item in _get_setting(app_settings, 'unprotected_regex'): - unprotected_regex.append(item) - for item in _get_setting(app_settings, 'protected_uris'): - if item[-1:] == '/': - item = item[:-1] - protected_urls.append(app_settings['domain'] + app_settings['path'].rstrip('/') + item) - for item in _get_setting(app_settings, 'protected_regex'): - protected_regex.append(item) - if 'redirected_urls' in app_settings: - redirected_urls.update(app_settings['redirected_urls']) - if 'redirected_regex' in app_settings: - redirected_regex.update(app_settings['redirected_regex']) + if 'no_sso' in app_settings: + continue + + app_root_webpath = app_settings['domain'] + app_settings['path'].rstrip('/') + + # Skipped + skipped_urls += [app_root_webpath + uri.rstrip("/") for uri in _get_setting(app_settings, 'skipped_uris')] + skipped_regex += _get_setting(app_settings, 'skipped_regex') + + # Unprotected + unprotected_urls += [app_root_webpath + uri.rstrip("/") for uri in _get_setting(app_settings, 'unprotected_uris')] + unprotected_regex += _get_setting(app_settings, 'unprotected_regex') + + # Protected + unprotected_urls += [app_root_webpath + uri.rstrip("/") for uri in _get_setting(app_settings, 'protected_uris')] + unprotected_regex += _get_setting(app_settings, 'protected_regex') + + # Redirected + redirected_urls.update(app_settings.get('redirected_urls', {})) + redirected_regex.update(app_settings.get('redirected_regex', {})) for domain in domains: skipped_urls.extend([domain + '/yunohost/admin', domain + '/yunohost/api']) From 8abfd2a6e60bfd53d6fb398261e002e223a0c217 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 15 Sep 2019 17:58:41 +0200 Subject: [PATCH 004/127] Naive implementation of protected/unprotected inplementation using the visitors group --- src/yunohost/app.py | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index a9c91aaf5..52371ff29 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -1345,6 +1345,7 @@ def app_ssowatconf(): main_domain = _get_maindomain() domains = domain_list()['domains'] + all_permissions = user_permission_list(full=True)['permissions'] skipped_urls = [] skipped_regex = [] @@ -1378,18 +1379,32 @@ def app_ssowatconf(): skipped_urls += [app_root_webpath + uri.rstrip("/") for uri in _get_setting(app_settings, 'skipped_uris')] skipped_regex += _get_setting(app_settings, 'skipped_regex') - # Unprotected - unprotected_urls += [app_root_webpath + uri.rstrip("/") for uri in _get_setting(app_settings, 'unprotected_uris')] - unprotected_regex += _get_setting(app_settings, 'unprotected_regex') - - # Protected - unprotected_urls += [app_root_webpath + uri.rstrip("/") for uri in _get_setting(app_settings, 'protected_uris')] - unprotected_regex += _get_setting(app_settings, 'protected_regex') - # Redirected redirected_urls.update(app_settings.get('redirected_urls', {})) redirected_regex.update(app_settings.get('redirected_regex', {})) + # Legacy permission system using (un)protected_uris and _regex managed in app settings... + unprotected_urls += [app_root_webpath + uri.rstrip("/") for uri in _get_setting(app_settings, 'unprotected_uris')] + unprotected_urls += [app_root_webpath + uri.rstrip("/") for uri in _get_setting(app_settings, 'protected_uris')] + unprotected_regex += _get_setting(app_settings, 'unprotected_regex') + unprotected_regex += _get_setting(app_settings, 'protected_regex') + + # New permission system + this_app_perms = {name: info for name, info in all_permissions.items if name.startswith(app + ".")} + for perm_name, perm_info in this_app_perms: + urls = [url.rstrip("/") for url in perm_info["urls"]] + if "visitors" in perm_info["allowed"]: + unprotected_urls += urls + + # Legacy stuff : we remove now unprotected-urls that might have been declared as protected earlier... + protected_urls = [u for u in protected_urls if u not in urls] + else: + # TODO : small optimization to implement : we don't need to explictly add all the app roots + protected_urls += urls + + # Legacy stuff : we remove now unprotected-urls that might have been declared as protected earlier... + unprotected_urls = [u for u in unprotected_urls if u not in urls] + for domain in domains: skipped_urls.extend([domain + '/yunohost/admin', domain + '/yunohost/api']) @@ -1397,8 +1412,10 @@ def app_ssowatconf(): skipped_regex.append("^[^/]*/%.well%-known/acme%-challenge/.*$") skipped_regex.append("^[^/]*/%.well%-known/autoconfig/mail/config%-v1%.1%.xml.*$") + + permissions_per_url = {} - for permission_name, permission_infos in user_permission_list(full=True)['permissions'].items(): + for permission_name, permission_infos in all_permissions.items(): for url in permission_infos["urls"]: permissions_per_url[url] = permission_infos['corresponding_users'] From c4743398e687738a8b55bd500f219f7a69afe28e Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 15 Sep 2019 18:10:58 +0200 Subject: [PATCH 005/127] Deprecate (un)protected_uris and _regex settings + more explicit deprecation warning for app_add/remove/clearaccess --- data/helpers.d/setting | 4 +++- src/yunohost/app.py | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/data/helpers.d/setting b/data/helpers.d/setting index 502da1ed7..d083ed563 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -176,6 +176,8 @@ else: elif action == "set": if key in ['redirected_urls', 'redirected_regex']: value = yaml.load(value) + if key in ["unprotected_uris", "unprotected_regex", "protected_uris", "protected_regex"]: + logger.warning("/!\\ Packagers ! This app is using the legacy permission system. Please delete these legacy settings and use the new helpers ynh_permission_{create,urls,update,delete} and the 'visitors' group to manage public/private access.") settings[key] = value else: raise ValueError("action should either be get, set or delete") @@ -249,7 +251,7 @@ ynh_permission_create() { # Remove a permission for the app (note that when the app is removed all permission is automatically removed) # -# usage: ynh_permission_remove --permission "permission" +# usage: ynh_permission_delete --permission "permission" # | arg: permission - the name for the permission (by default a permission named "main" is removed automatically when the app is removed) # # example: ynh_permission_delete --permission editors diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 52371ff29..8b0c99d46 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -1037,6 +1037,8 @@ def app_addaccess(apps, users=[]): """ from yunohost.permission import user_permission_update + logger.warning("/!\\ Packagers ! This app is using the legacy permission system. Please use the new helpers ynh_permission_{create,urls,update,delete} and the 'visitors' group to manage permissions.") + output = {} for app in apps: permission = user_permission_update(app+".main", add=users) @@ -1056,6 +1058,8 @@ def app_removeaccess(apps, users=[]): """ from yunohost.permission import user_permission_update + logger.warning("/!\\ Packagers ! This app is using the legacy permission system. Please use the new helpers ynh_permission_{create,urls,update,delete} and the 'visitors' group to manage permissions.") + output = {} for app in apps: permission = user_permission_update(app+".main", remove=users) @@ -1074,6 +1078,8 @@ def app_clearaccess(apps): """ from yunohost.permission import user_permission_reset + logger.warning("/!\\ Packagers ! This app is using the legacy permission system. Please use the new helpers ynh_permission_{create,urls,update,delete} and the 'visitors' group to manage permissions.") + output = {} for app in apps: permission = user_permission_reset(app+".main") @@ -1181,6 +1187,8 @@ def app_setting(app, key, value=None, delete=False): # FIXME: Allow multiple values for some keys? if key in ['redirected_urls', 'redirected_regex']: value = yaml.load(value) + if key in ["unprotected_uris", "unprotected_regex", "protected_uris", "protected_regex"]: + logger.warning("/!\ Packagers ! This app is using the legacy permission system. Please delete these legacy settings and use the new helpers ynh_permission_{create,urls,update,delete} and the 'visitors' group to manage public/private access.") app_settings[key] = value _set_app_settings(app, app_settings) From b2a26a64a74d2f7289d857b7bb780ac2f91741ce Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 15 Sep 2019 18:33:31 +0200 Subject: [PATCH 006/127] Naively migrate legacy and classical unprotected_uris = / that sets the app as public --- src/yunohost/app.py | 8 +++++++- .../data_migrations/0011_setup_group_permission.py | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 8b0c99d46..537616e68 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -733,7 +733,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu from yunohost.hook import hook_add, hook_remove, hook_exec, hook_callback from yunohost.log import OperationLogger - from yunohost.permission import user_permission_list, permission_create, permission_urls, permission_delete, permission_sync_to_user + from yunohost.permission import user_permission_list, permission_create, permission_urls, permission_delete, permission_sync_to_user, user_permission_update # Fetch or extract sources if not os.path.exists(INSTALL_TMP): @@ -952,7 +952,13 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu domain = app_settings.get('domain', None) path = app_settings.get('path', None) if domain and path: + # FIXME : might want to move this to before running the install script because some app need to run install script during initialization etc (idk) ? permission_urls(app_instance_name+".main", add=[domain+path], sync_perm=False) + + # Migrate classic public app still using the legacy unprotected_uris + if app_settings.get("unprotected_uris", None) == "/": + user_permission_update(app_instance_name+".main", remove="all_users", add="visitors", sync_perm=False) + permission_sync_to_user() logger.success(m18n.n('installation_complete')) diff --git a/src/yunohost/data_migrations/0011_setup_group_permission.py b/src/yunohost/data_migrations/0011_setup_group_permission.py index b3e11cb14..c79d80e0c 100644 --- a/src/yunohost/data_migrations/0011_setup_group_permission.py +++ b/src/yunohost/data_migrations/0011_setup_group_permission.py @@ -113,6 +113,12 @@ class MyMigration(Migration): user_permission_update(app+".main", remove="all_users", add=allowed_group, sync_perm=False) app_setting(app, 'allowed_users', delete=True) + # Migrate classic public app still using the legacy unprotected_uris + if app_setting(app, "unprotected_uris") == "/": + user_permission_update(app+".main", remove="all_users", add="visitors", sync_perm=False) + + permission_sync_to_user() + def run(self): # FIXME : what do we really want to do here ... From 821a3ac4ff0f3180ff5b5884f020c02b3a982b34 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 15 Sep 2019 18:53:25 +0200 Subject: [PATCH 007/127] Draft tests to check that permissions are actually propagated and effective on the SSO --- src/yunohost/tests/test_permission.py | 55 ++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/yunohost/tests/test_permission.py b/src/yunohost/tests/test_permission.py index 94728505d..1c81e015f 100644 --- a/src/yunohost/tests/test_permission.py +++ b/src/yunohost/tests/test_permission.py @@ -333,7 +333,7 @@ def test_permission_remove_url_not_added(): def test_permission_app_install(): app_install("./tests/apps/permissions_app_ynh", - args="domain=%s&path=%s&admin=%s" % (maindomain, "/urlpermissionapp", "alice"), force=True) + args="domain=%s&path=%s&is_public=0&admin=%s" % (maindomain, "/urlpermissionapp", "alice"), force=True) res = user_permission_list(full=True)['permissions'] assert "permissions_app.main" in res @@ -361,7 +361,7 @@ def test_permission_app_install(): def test_permission_app_remove(): app_install("./tests/apps/permissions_app_ynh", - args="domain=%s&path=%s&admin=%s" % (maindomain, "/urlpermissionapp", "alice"), force=True) + args="domain=%s&path=%s&is_public=0&admin=%s" % (maindomain, "/urlpermissionapp", "alice"), force=True) app_remove("permissions_app") # Check all permissions for this app got deleted @@ -383,3 +383,54 @@ def test_permission_app_change_url(): assert res['permissions_app.main']['urls'] == [maindomain + "/newchangeurl"] assert res['permissions_app.admin']['urls'] == [maindomain + "/newchangeurl/admin"] assert res['permissions_app.dev']['urls'] == [maindomain + "/newchangeurl/dev"] + + +def test_permission_app_propagation_on_ssowat(): + + # TODO / FIXME : To be actually implemented later .... + raise NotImplementedError + + app_install("./tests/apps/permissions_app_ynh", + args="domain=%s&path=%s&is_public=1&admin=%s" % (maindomain, "/urlpermissionapp", "alice"), force=True) + + res = user_permission_list(full=True)['permissions'] + assert res['permissions_app.main']['allowed'] == ["all_users"] + + assert can_access(maindomain + "/urlpermissionapp", logged_as=None) + assert can_access(maindomain + "/urlpermissionapp", logged_as="alice") + + user_permission_update("permissions_app.main", remove="visitors", add="bob") + res = user_permission_list(full=True)['permissions'] + + assert cannot_access(maindomain + "/urlpermissionapp", logged_as=None) + assert cannot_access(maindomain + "/urlpermissionapp", logged_as="alice") + assert can_access(maindomain + "/urlpermissionapp", logged_as="bob") + + # Test admin access, as configured during install, only alice should be able to access it + + assert cannot_access(maindomain + "/urlpermissionapp/admin", logged_as=None) + assert cannot_access(maindomain + "/urlpermissionapp/admin", logged_as="alice") + assert can_access(maindomain + "/urlpermissionapp/admin", logged_as="bob") + +def test_permission_legacy_app_propagation_on_ssowat(): + + # TODO / FIXME : To be actually implemented later .... + raise NotImplementedError + + app_install("./tests/apps/legacy_app_ynh", + args="domain=%s&path=%s" % (maindomain, "/legacy"), force=True) + + # App is configured as public by default using the legacy unprotected_uri mechanics + # It should automatically be migrated during the install + assert res['permissions_app.main']['allowed'] == ["visitors"] + + assert can_access(maindomain + "/legacy", logged_as=None) + assert can_access(maindomain + "/legacy", logged_as="alice") + + # Try to update the permission and check that permissions are still consistent + user_permission_update("legacy_app.main", remove="visitors", add="bob") + res = user_permission_list(full=True)['permissions'] + + assert cannot_access(maindomain + "/legacy", logged_as=None) + assert cannot_access(maindomain + "/legacy", logged_as="alice") + assert can_access(maindomain + "/legacy", logged_as="bob") From 64e388fa7d952690c3f35d8b13f67d52869bb383 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 17 Sep 2019 23:38:17 +0200 Subject: [PATCH 008/127] Implement helper function to test if we're able to access a webpage being logged in (or not) as user --- src/yunohost/tests/test_permission.py | 56 ++++++++++++++++++++------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/src/yunohost/tests/test_permission.py b/src/yunohost/tests/test_permission.py index 1c81e015f..51bf6a4c6 100644 --- a/src/yunohost/tests/test_permission.py +++ b/src/yunohost/tests/test_permission.py @@ -1,3 +1,4 @@ +import requests import pytest from yunohost.app import app_install, app_remove, app_change_url, app_list, app_map @@ -11,6 +12,7 @@ from yunohost.utils.error import YunohostError # Get main domain maindomain = _get_maindomain() +dummy_password = "test123Ynh" def clean_user_groups_permission(): for u in user_list()['users']: @@ -27,8 +29,8 @@ def clean_user_groups_permission(): def setup_function(function): clean_user_groups_permission() - user_create("alice", "Alice", "White", "alice@" + maindomain, "test123Ynh") - user_create("bob", "Bob", "Snow", "bob@" + maindomain, "test123Ynh") + user_create("alice", "Alice", "White", "alice@" + maindomain, dummy_password) + user_create("bob", "Bob", "Snow", "bob@" + maindomain, dummy_password) permission_create("wiki.main", urls=[maindomain + "/wiki"], sync_perm=False) permission_create("blog.main", sync_perm=False) user_permission_update("blog.main", remove="all_users", add="alice") @@ -156,6 +158,30 @@ def check_permission_for_apps(): assert installed_apps == app_perms_prefix + +def can_access_webpage(webpath, logged_as=None): + + webpath = webpath.rstrip("/") + webroot = webpath.rsplit("/", 1)[0] + sso_url = webroot+"/yunohost/sso" + + # Anonymous access + if not logged_as: + r = requests.get(webpath, verify=False) + # Login as a user using dummy password + else: + with requests.Session() as session: + session.post(sso_url, + data={"user": logged_as, + "password": dummy_password}, + headers={"Referer": sso_url, + "Content-Type": "application/x-www-form-urlencoded"}, + verify=False) + r = session.get(webpath, verify=False) + + # If we can't access it, we got redirected to the sso + return not r.url.startswith(sso_url) + # # List functions # @@ -396,21 +422,21 @@ def test_permission_app_propagation_on_ssowat(): res = user_permission_list(full=True)['permissions'] assert res['permissions_app.main']['allowed'] == ["all_users"] - assert can_access(maindomain + "/urlpermissionapp", logged_as=None) - assert can_access(maindomain + "/urlpermissionapp", logged_as="alice") + assert can_access_webpage(maindomain + "/urlpermissionapp", logged_as=None) + assert can_access_webpage(maindomain + "/urlpermissionapp", logged_as="alice") user_permission_update("permissions_app.main", remove="visitors", add="bob") res = user_permission_list(full=True)['permissions'] - assert cannot_access(maindomain + "/urlpermissionapp", logged_as=None) - assert cannot_access(maindomain + "/urlpermissionapp", logged_as="alice") - assert can_access(maindomain + "/urlpermissionapp", logged_as="bob") + assert not can_access_webpage(maindomain + "/urlpermissionapp", logged_as=None) + assert not can_access_webpage(maindomain + "/urlpermissionapp", logged_as="alice") + assert can_access_webpage(maindomain + "/urlpermissionapp", logged_as="bob") # Test admin access, as configured during install, only alice should be able to access it - assert cannot_access(maindomain + "/urlpermissionapp/admin", logged_as=None) - assert cannot_access(maindomain + "/urlpermissionapp/admin", logged_as="alice") - assert can_access(maindomain + "/urlpermissionapp/admin", logged_as="bob") + assert not can_access_webpage(maindomain + "/urlpermissionapp/admin", logged_as=None) + assert not can_access_webpage(maindomain + "/urlpermissionapp/admin", logged_as="alice") + assert can_access_webpage(maindomain + "/urlpermissionapp/admin", logged_as="bob") def test_permission_legacy_app_propagation_on_ssowat(): @@ -424,13 +450,13 @@ def test_permission_legacy_app_propagation_on_ssowat(): # It should automatically be migrated during the install assert res['permissions_app.main']['allowed'] == ["visitors"] - assert can_access(maindomain + "/legacy", logged_as=None) - assert can_access(maindomain + "/legacy", logged_as="alice") + assert can_access_webpage(maindomain + "/legacy", logged_as=None) + assert can_access_webpage(maindomain + "/legacy", logged_as="alice") # Try to update the permission and check that permissions are still consistent user_permission_update("legacy_app.main", remove="visitors", add="bob") res = user_permission_list(full=True)['permissions'] - assert cannot_access(maindomain + "/legacy", logged_as=None) - assert cannot_access(maindomain + "/legacy", logged_as="alice") - assert can_access(maindomain + "/legacy", logged_as="bob") + assert not can_access_webpage(maindomain + "/legacy", logged_as=None) + assert not can_access_webpage(maindomain + "/legacy", logged_as="alice") + assert can_access_webpage(maindomain + "/legacy", logged_as="bob") From 00795a7a0156d5d45aeabb63819ab3d6511270e5 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 18 Sep 2019 18:38:47 +0200 Subject: [PATCH 009/127] Make migration re-run even more robust --- src/yunohost/data_migrations/0011_setup_group_permission.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/yunohost/data_migrations/0011_setup_group_permission.py b/src/yunohost/data_migrations/0011_setup_group_permission.py index c79d80e0c..a99dfb7c1 100644 --- a/src/yunohost/data_migrations/0011_setup_group_permission.py +++ b/src/yunohost/data_migrations/0011_setup_group_permission.py @@ -62,12 +62,14 @@ class MyMigration(Migration): try: self.remove_if_exists("cn=sftpusers,ou=groups") self.remove_if_exists("ou=permission") - self.remove_if_exists('cn=all_users,ou=groups') - self.remove_if_exists('cn=visitors,ou=groups') + self.remove_if_exists('ou=groups') attr_dict = ldap_map['parents']['ou=permission'] ldap.add('ou=permission', attr_dict) + attr_dict = ldap_map['parents']['ou=groups'] + ldap.add('ou=groups', attr_dict) + attr_dict = ldap_map['children']['cn=all_users,ou=groups'] ldap.add('cn=all_users,ou=groups', attr_dict) From 8d01a816f3cd0fd07f570cd2d9f290d01f100ed9 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 18 Sep 2019 18:39:05 +0200 Subject: [PATCH 010/127] Typo fixes following tests --- src/yunohost/app.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 537616e68..7938d6786 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -1404,8 +1404,8 @@ def app_ssowatconf(): unprotected_regex += _get_setting(app_settings, 'protected_regex') # New permission system - this_app_perms = {name: info for name, info in all_permissions.items if name.startswith(app + ".")} - for perm_name, perm_info in this_app_perms: + this_app_perms = {name: info for name, info in all_permissions.items() if name.startswith(app['id'] + ".")} + for perm_name, perm_info in this_app_perms.items(): urls = [url.rstrip("/") for url in perm_info["urls"]] if "visitors" in perm_info["allowed"]: unprotected_urls += urls @@ -1414,6 +1414,7 @@ def app_ssowatconf(): protected_urls = [u for u in protected_urls if u not in urls] else: # TODO : small optimization to implement : we don't need to explictly add all the app roots + protected_urls += urls # Legacy stuff : we remove now unprotected-urls that might have been declared as protected earlier... From 87050276b4a217acea21b7f45820bdfaead1194d Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Sep 2019 19:26:41 +0200 Subject: [PATCH 011/127] Finish to implement first visitor test + fixes following test ... --- src/yunohost/app.py | 12 +++++------ src/yunohost/tests/test_permission.py | 29 +++++++++++++-------------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 7938d6786..bba5fb104 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -429,8 +429,10 @@ def app_map(app=None, raw=False, user=None): continue if 'no_sso' in app_settings: # I don't think we need to check for the value here continue - if user and user not in permissions[app_id + ".main"]["corresponding_users"]: - continue + if user: + main_perm = permissions[app_id + ".main"] + if user not in main_perm["corresponding_users"] and "visitors" not in main_perm["allowed"]: + continue domain = app_settings['domain'] path = app_settings['path'] @@ -2613,10 +2615,8 @@ def _parse_args_in_yunohost_format(args, action_args): if arg_value not in domain_list()['domains']: raise YunohostError('app_argument_invalid', name=arg_name, error=m18n.n('domain_unknown')) elif arg_type == 'user': - try: - user_info(arg_value) - except YunohostError as e: - raise YunohostError('app_argument_invalid', name=arg_name, error=e) + if not arg_value in user_list()["users"].keys(): + raise YunohostError('app_argument_invalid', name=arg_name, error=m18n.n('user_unknown', user=arg_value)) elif arg_type == 'app': if not _is_installed(arg_value): raise YunohostError('app_argument_invalid', name=arg_name, error=m18n.n('app_unknown')) diff --git a/src/yunohost/tests/test_permission.py b/src/yunohost/tests/test_permission.py index 51bf6a4c6..bef042be1 100644 --- a/src/yunohost/tests/test_permission.py +++ b/src/yunohost/tests/test_permission.py @@ -19,7 +19,7 @@ def clean_user_groups_permission(): user_delete(u) for g in user_group_list()['groups']: - if g != "all_users": + if g not in ["all_users", "visitors"]: user_group_delete(g) for p in user_permission_list()['permissions']: @@ -162,8 +162,7 @@ def check_permission_for_apps(): def can_access_webpage(webpath, logged_as=None): webpath = webpath.rstrip("/") - webroot = webpath.rsplit("/", 1)[0] - sso_url = webroot+"/yunohost/sso" + sso_url = "https://"+maindomain+"/yunohost/sso/" # Anonymous access if not logged_as: @@ -177,6 +176,8 @@ def can_access_webpage(webpath, logged_as=None): headers={"Referer": sso_url, "Content-Type": "application/x-www-form-urlencoded"}, verify=False) + # We should have some cookies related to authentication now + assert session.cookies r = session.get(webpath, verify=False) # If we can't access it, we got redirected to the sso @@ -413,30 +414,28 @@ def test_permission_app_change_url(): def test_permission_app_propagation_on_ssowat(): - # TODO / FIXME : To be actually implemented later .... - raise NotImplementedError - app_install("./tests/apps/permissions_app_ynh", args="domain=%s&path=%s&is_public=1&admin=%s" % (maindomain, "/urlpermissionapp", "alice"), force=True) res = user_permission_list(full=True)['permissions'] - assert res['permissions_app.main']['allowed'] == ["all_users"] + assert res['permissions_app.main']['allowed'] == ["visitors"] - assert can_access_webpage(maindomain + "/urlpermissionapp", logged_as=None) - assert can_access_webpage(maindomain + "/urlpermissionapp", logged_as="alice") + app_webroot = "https://%s/urlpermissionapp" % maindomain + assert can_access_webpage(app_webroot, logged_as=None) + assert can_access_webpage(app_webroot, logged_as="alice") user_permission_update("permissions_app.main", remove="visitors", add="bob") res = user_permission_list(full=True)['permissions'] - assert not can_access_webpage(maindomain + "/urlpermissionapp", logged_as=None) - assert not can_access_webpage(maindomain + "/urlpermissionapp", logged_as="alice") - assert can_access_webpage(maindomain + "/urlpermissionapp", logged_as="bob") + assert not can_access_webpage(app_webroot, logged_as=None) + assert not can_access_webpage(app_webroot, logged_as="alice") + assert can_access_webpage(app_webroot, logged_as="bob") # Test admin access, as configured during install, only alice should be able to access it - assert not can_access_webpage(maindomain + "/urlpermissionapp/admin", logged_as=None) - assert not can_access_webpage(maindomain + "/urlpermissionapp/admin", logged_as="alice") - assert can_access_webpage(maindomain + "/urlpermissionapp/admin", logged_as="bob") + assert not can_access_webpage(app_webroot+"/admin", logged_as=None) + assert can_access_webpage(app_webroot+"/admin", logged_as="alice") + assert not can_access_webpage(app_webroot+"/admin", logged_as="bob") def test_permission_legacy_app_propagation_on_ssowat(): From eb57a4ad9e982eea6a5dc0c7543c61a437265568 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Sep 2019 19:51:27 +0200 Subject: [PATCH 012/127] Get rid of etckeeper --- data/hooks/conf_regen/01-yunohost | 3 -- data/templates/yunohost/etckeeper.conf | 43 -------------------------- debian/control | 2 +- 3 files changed, 1 insertion(+), 47 deletions(-) delete mode 100644 data/templates/yunohost/etckeeper.conf diff --git a/data/hooks/conf_regen/01-yunohost b/data/hooks/conf_regen/01-yunohost index faf041110..f22de7a53 100755 --- a/data/hooks/conf_regen/01-yunohost +++ b/data/hooks/conf_regen/01-yunohost @@ -53,9 +53,6 @@ do_pre_regen() { else sudo cp services.yml /etc/yunohost/services.yml fi - - mkdir -p "$pending_dir"/etc/etckeeper/ - cp etckeeper.conf "$pending_dir"/etc/etckeeper/ } _update_services() { diff --git a/data/templates/yunohost/etckeeper.conf b/data/templates/yunohost/etckeeper.conf deleted file mode 100644 index 2d11c3dc6..000000000 --- a/data/templates/yunohost/etckeeper.conf +++ /dev/null @@ -1,43 +0,0 @@ -# The VCS to use. -#VCS="hg" -VCS="git" -#VCS="bzr" -#VCS="darcs" - -# Options passed to git commit when run by etckeeper. -GIT_COMMIT_OPTIONS="--quiet" - -# Options passed to hg commit when run by etckeeper. -HG_COMMIT_OPTIONS="" - -# Options passed to bzr commit when run by etckeeper. -BZR_COMMIT_OPTIONS="" - -# Options passed to darcs record when run by etckeeper. -DARCS_COMMIT_OPTIONS="-a" - -# Uncomment to avoid etckeeper committing existing changes -# to /etc automatically once per day. -#AVOID_DAILY_AUTOCOMMITS=1 - -# Uncomment the following to avoid special file warning -# (the option is enabled automatically by cronjob regardless). -#AVOID_SPECIAL_FILE_WARNING=1 - -# Uncomment to avoid etckeeper committing existing changes to -# /etc before installation. It will cancel the installation, -# so you can commit the changes by hand. -#AVOID_COMMIT_BEFORE_INSTALL=1 - -# The high-level package manager that's being used. -# (apt, pacman-g2, yum, zypper etc) -HIGHLEVEL_PACKAGE_MANAGER=apt - -# The low-level package manager that's being used. -# (dpkg, rpm, pacman, pacman-g2, etc) -LOWLEVEL_PACKAGE_MANAGER=dpkg - -# To push each commit to a remote, put the name of the remote here. -# (eg, "origin" for git). Space-separated lists of multiple remotes -# also work (eg, "origin gitlab github" for git). -PUSH_REMOTE="" diff --git a/debian/control b/debian/control index 64c7cd31d..c0604d90e 100644 --- a/debian/control +++ b/debian/control @@ -31,7 +31,7 @@ Depends: ${python:Depends}, ${misc:Depends} , equivs, lsof Recommends: yunohost-admin , openssh-server, ntp, inetutils-ping | iputils-ping - , bash-completion, rsyslog, etckeeper + , bash-completion, rsyslog , php-gd, php-curl, php-gettext, php-mcrypt , python-pip , unattended-upgrades From ebf2fb9a141da65954d1855bc025f0cf362c6f99 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 20 Sep 2019 20:13:51 +0200 Subject: [PATCH 013/127] Use relative urls by default for permissions while still supporting absolute urls ... --- src/yunohost/app.py | 18 +++++------- .../0011_setup_group_permission.py | 2 +- src/yunohost/permission.py | 29 ++++++++++--------- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index bba5fb104..231568439 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -553,8 +553,6 @@ def app_change_url(operation_logger, app, domain, path): app_setting(app, 'domain', value=domain) app_setting(app, 'path', value=path) - permission_urls(app+".main", add=[domain+path], remove=[old_domain+old_path], sync_perm=True) - # avoid common mistakes if _run_service_command("reload", "nginx") is False: # grab nginx errors @@ -868,10 +866,9 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu if os.path.exists(os.path.join(extracted_app_folder, file_to_copy)): os.system('cp -R %s/%s %s' % (extracted_app_folder, file_to_copy, app_setting_path)) - # Create permission before the install (useful if the install script redefine the permission) - # Note that sync_perm is disabled to avoid triggering a whole bunch of code and messages - # can't be sure that we don't have one case when it's needed - permission_create(app_instance_name+".main", sync_perm=False) + # Initialize the main permission for the app + # After the install, if apps don't have a domain and path defined, the default url '/' is removed from the permission + permission_create(app_instance_name+".main", urls=["/"]) # Execute the app install script install_retcode = 1 @@ -949,17 +946,16 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu os.system('chown -R root: %s' % app_setting_path) os.system('chown -R admin: %s/scripts' % app_setting_path) - # Add path in permission if it's defined in the app install script + # If an app doesn't have at least a domain and a path, assume it's not a webapp and remove the default "/" permission app_settings = _get_app_settings(app_instance_name) domain = app_settings.get('domain', None) path = app_settings.get('path', None) - if domain and path: - # FIXME : might want to move this to before running the install script because some app need to run install script during initialization etc (idk) ? - permission_urls(app_instance_name+".main", add=[domain+path], sync_perm=False) + if not (domain and path): + permission_urls(app_instance_name + ".main", remove=["/"], sync_perm=False) # Migrate classic public app still using the legacy unprotected_uris if app_settings.get("unprotected_uris", None) == "/": - user_permission_update(app_instance_name+".main", remove="all_users", add="visitors", sync_perm=False) + user_permission_update(app_instance_name + ".main", remove="all_users", add="visitors", sync_perm=False) permission_sync_to_user() diff --git a/src/yunohost/data_migrations/0011_setup_group_permission.py b/src/yunohost/data_migrations/0011_setup_group_permission.py index a99dfb7c1..dd5b3c274 100644 --- a/src/yunohost/data_migrations/0011_setup_group_permission.py +++ b/src/yunohost/data_migrations/0011_setup_group_permission.py @@ -108,7 +108,7 @@ class MyMigration(Migration): path = app_setting(app, 'path') domain = app_setting(app, 'domain') - urls = [domain + path] if domain and path else None + urls = "/" if domain and path else None permission_create(app+".main", urls=urls, sync_perm=False) if permission: allowed_group = permission.split(',') diff --git a/src/yunohost/permission.py b/src/yunohost/permission.py index dbfc6e6f5..5f9a88e11 100644 --- a/src/yunohost/permission.py +++ b/src/yunohost/permission.py @@ -268,7 +268,18 @@ def permission_create(operation_logger, permission, urls=None, sync_perm=True): Keyword argument: permission -- Name of the permission (e.g. mail or nextcloud or wordpress.editors) - urls -- list of urls to specify for the permission + urls -- list of urls to specify for the permission. + + Urls are assumed to be relative to the app domain/path if they start with '/'. + For example: + / -> domain.tld/app + /admin -> domain.tld/app/admin + domain.tld/app/api -> domain.tld/app/api + + Urls can be later treated as regexes when they start with "re:". + For example: + re:/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ + re:domain.tld/app/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ """ from yunohost.utils.ldap import _get_ldap_interface @@ -302,7 +313,7 @@ def permission_create(operation_logger, permission, urls=None, sync_perm=True): attr_dict['groupPermission'] = ['cn=all_users,ou=groups,dc=yunohost,dc=org'] if urls: - attr_dict['URL'] = [_normalize_url(url) for url in urls] + attr_dict['URL'] = urls operation_logger.related_to.append(('app', permission.split(".")[0])) operation_logger.start() @@ -326,8 +337,8 @@ def permission_urls(operation_logger, permission, add=None, remove=None, sync_pe Keyword argument: permission -- Name of the permission (e.g. mail or nextcloud or wordpress.editors) - add -- List of urls to add - remove -- List of urls to remove + add -- List of urls to add (c.f. permission_create for documentation about their format) + remove -- List of urls to remove (c.f. permission_create for documentation about their format) """ from yunohost.utils.ldap import _get_ldap_interface @@ -345,11 +356,9 @@ def permission_urls(operation_logger, permission, add=None, remove=None, sync_pe if add: urls_to_add = [add] if not isinstance(add, list) else add - urls_to_add = [_normalize_url(url) for url in urls_to_add] new_urls += urls_to_add if remove: urls_to_remove = [remove] if not isinstance(remove, list) else remove - urls_to_remove = [_normalize_url(url) for url in urls_to_remove] new_urls = [u for u in new_urls if u not in urls_to_remove] if set(new_urls) == set(existing_permission["urls"]): @@ -457,11 +466,3 @@ def permission_sync_to_user(): # Reload unscd, otherwise the group ain't propagated to the LDAP database os.system('nscd --invalidate=passwd') os.system('nscd --invalidate=group') - - -def _normalize_url(url): - from yunohost.domain import _normalize_domain_path - domain = url[:url.index('/')] - path = url[url.index('/'):] - domain, path = _normalize_domain_path(domain, path) - return domain + path From 2b51d247fb5a1a66c152c13a6ad83e97fdaceee3 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 20 Sep 2019 20:14:14 +0200 Subject: [PATCH 014/127] Propagate changes on app helpers + tests --- data/helpers.d/setting | 22 +++++++++--- src/yunohost/tests/test_backuprestore.py | 12 +++---- src/yunohost/tests/test_permission.py | 45 ++++++++++++------------ 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/data/helpers.d/setting b/data/helpers.d/setting index d083ed563..9deba2dc0 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -232,11 +232,24 @@ ynh_webpath_register () { # Create a new permission for the app # +# example: ynh_permission_create --permission admin --urls /admin +# # usage: ynh_permission_create --permission "permission" [--urls "url" ["url" ...]] # | arg: permission - the name for the permission (by default a permission named "main" already exist) # | arg: urls - (optional) a list of FULL urls for the permission (e.g. domain.tld/apps/admin) +# | arg: urls - (optional) a list of urls to specify for the permission. +# +# Urls are assumed to be relative to the app domain/path if they start with '/'. +# For example: +# / -> domain.tld/app +# /admin -> domain.tld/app/admin +# domain.tld/app/api -> domain.tld/app/api +# +# Urls can be treated as regexes when they start with "re:". +# For example: +# re:/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ +# re:domain.tld/app/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ # -# example: ynh_permission_create --permission admin --urls domain.tld/blog/admin ynh_permission_create() { declare -Ar args_array=( [p]=permission= [u]=urls= ) local permission @@ -251,10 +264,11 @@ ynh_permission_create() { # Remove a permission for the app (note that when the app is removed all permission is automatically removed) # +# example: ynh_permission_delete --permission editors +# # usage: ynh_permission_delete --permission "permission" # | arg: permission - the name for the permission (by default a permission named "main" is removed automatically when the app is removed) # -# example: ynh_permission_delete --permission editors ynh_permission_delete() { declare -Ar args_array=( [p]=permission= ) local permission @@ -267,8 +281,8 @@ ynh_permission_delete() { # # usage: ynh_permission_urls --permission "permission" --add "url" ["url" ...] --remove "url" ["url" ...] # | arg: permission - the name for the permission (by default a permission named "main" is removed automatically when the app is removed) -# | arg: add - (optional) a list of FULL urls to add to the permission (e.g. domain.tld/apps/admin) -# | arg: remove - (optional) a list of FULL urls to remove from the permission (e.g. other.tld/apps/admin) +# | arg: add - (optional) a list of urls to add to the permission (see permission_create for details regarding their format) +# | arg: remove - (optional) a list of urls to remove from the permission (see permission_create for details regarding their format) # ynh_permission_urls() { declare -Ar args_array=([p]=permission= [a]=add= [r]=remove=) diff --git a/src/yunohost/tests/test_backuprestore.py b/src/yunohost/tests/test_backuprestore.py index bdaf25299..cab98089b 100644 --- a/src/yunohost/tests/test_backuprestore.py +++ b/src/yunohost/tests/test_backuprestore.py @@ -529,9 +529,9 @@ def test_backup_and_restore_permission_app(): assert "permissions_app.main" in res assert "permissions_app.admin" in res assert "permissions_app.dev" in res - assert res['permissions_app.main']['urls'] == [maindomain + "/urlpermissionapp"] - assert res['permissions_app.admin']['urls'] == [maindomain + "/urlpermissionapp/admin"] - assert res['permissions_app.dev']['urls'] == [maindomain + "/urlpermissionapp/dev"] + assert res['permissions_app.main']['urls'] == ["/"] + assert res['permissions_app.admin']['urls'] == ["/admin"] + assert res['permissions_app.dev']['urls'] == ["/dev"] assert res['permissions_app.main']['allowed'] == ["all_users"] assert res['permissions_app.admin']['allowed'] == ["alice"] @@ -543,9 +543,9 @@ def test_backup_and_restore_permission_app(): assert "permissions_app.main" in res assert "permissions_app.admin" in res assert "permissions_app.dev" in res - assert res['permissions_app.main']['urls'] == [maindomain + "/urlpermissionapp"] - assert res['permissions_app.admin']['urls'] == [maindomain + "/urlpermissionapp/admin"] - assert res['permissions_app.dev']['urls'] == [maindomain + "/urlpermissionapp/dev"] + assert res['permissions_app.main']['urls'] == ["/"] + assert res['permissions_app.admin']['urls'] == ["/admin"] + assert res['permissions_app.dev']['urls'] == ["/dev"] assert res['permissions_app.main']['allowed'] == ["all_users"] assert res['permissions_app.admin']['allowed'] == ["alice"] diff --git a/src/yunohost/tests/test_permission.py b/src/yunohost/tests/test_permission.py index bef042be1..a8b6b8258 100644 --- a/src/yunohost/tests/test_permission.py +++ b/src/yunohost/tests/test_permission.py @@ -31,7 +31,7 @@ def setup_function(function): user_create("alice", "Alice", "White", "alice@" + maindomain, dummy_password) user_create("bob", "Bob", "Snow", "bob@" + maindomain, dummy_password) - permission_create("wiki.main", urls=[maindomain + "/wiki"], sync_perm=False) + permission_create("wiki.main", urls=["/"], sync_perm=False) permission_create("blog.main", sync_perm=False) user_permission_update("blog.main", remove="all_users", add="alice") @@ -198,7 +198,7 @@ def test_permission_list(): assert res['blog.main']['allowed'] == ["alice"] assert set(res['wiki.main']['corresponding_users']) == set(["alice", "bob"]) assert res['blog.main']['corresponding_users'] == ["alice"] - assert res['wiki.main']['urls'] == [maindomain + "/wiki"] + assert res['wiki.main']['urls'] == ["/"] # # Create - Remove functions @@ -322,37 +322,37 @@ def test_permission_update_permission_that_doesnt_exist(): # Permission url management def test_permission_add_url(): - permission_urls("blog.main", add=[maindomain + "/testA"]) + permission_urls("blog.main", add=["/testA"]) res = user_permission_list(full=True)['permissions'] - assert res["blog.main"]["urls"] == [maindomain + "/testA"] + assert res["blog.main"]["urls"] == ["/testA"] -def test_permission_add_second_url(): - permission_urls("wiki.main", add=[maindomain + "/testA"]) +def test_permission_add_another_url(): + permission_urls("wiki.main", add=["/testA"]) res = user_permission_list(full=True)['permissions'] - assert set(res["wiki.main"]["urls"]) == set([maindomain + "/testA", maindomain + "/wiki"]) + assert set(res["wiki.main"]["urls"]) == set(["/", "/testA"]) def test_permission_remove_url(): - permission_urls("wiki.main", remove=[maindomain + "/wiki"]) + permission_urls("wiki.main", remove=["/"]) res = user_permission_list(full=True)['permissions'] assert res["wiki.main"]["urls"] == [] def test_permission_add_url_already_added(): res = user_permission_list(full=True)['permissions'] - assert res["wiki.main"]["urls"] == [maindomain + "/wiki"] + assert res["wiki.main"]["urls"] == ["/"] - permission_urls("wiki.main", add=[maindomain + "/wiki"]) + permission_urls("wiki.main", add=["/"]) res = user_permission_list(full=True)['permissions'] - assert res["wiki.main"]["urls"] == [maindomain + "/wiki"] + assert res["wiki.main"]["urls"] == ["/"] def test_permission_remove_url_not_added(): - permission_urls("wiki.main", remove=[maindomain + "/doesnt_exist"]) + permission_urls("wiki.main", remove=["/doesnt_exist"]) res = user_permission_list(full=True)['permissions'] - assert res['wiki.main']['urls'] == [maindomain + "/wiki"] + assert res['wiki.main']['urls'] == ["/"] # # Application interaction @@ -366,9 +366,9 @@ def test_permission_app_install(): assert "permissions_app.main" in res assert "permissions_app.admin" in res assert "permissions_app.dev" in res - assert res['permissions_app.main']['urls'] == [maindomain + "/urlpermissionapp"] - assert res['permissions_app.admin']['urls'] == [maindomain + "/urlpermissionapp/admin"] - assert res['permissions_app.dev']['urls'] == [maindomain + "/urlpermissionapp/dev"] + assert res['permissions_app.main']['urls'] == ["/"] + assert res['permissions_app.admin']['urls'] == ["/admin"] + assert res['permissions_app.dev']['urls'] == ["/dev"] assert res['permissions_app.main']['allowed'] == ["all_users"] assert set(res['permissions_app.main']['corresponding_users']) == set(["alice", "bob"]) @@ -399,17 +399,18 @@ def test_permission_app_change_url(): app_install("./tests/apps/permissions_app_ynh", args="domain=%s&path=%s&admin=%s" % (maindomain, "/urlpermissionapp", "alice"), force=True) + # FIXME : should rework this test to look for differences in the generated app map / app tiles ... res = user_permission_list(full=True)['permissions'] - assert res['permissions_app.main']['urls'] == [maindomain + "/urlpermissionapp"] - assert res['permissions_app.admin']['urls'] == [maindomain + "/urlpermissionapp/admin"] - assert res['permissions_app.dev']['urls'] == [maindomain + "/urlpermissionapp/dev"] + assert res['permissions_app.main']['urls'] == ["/"] + assert res['permissions_app.admin']['urls'] == ["/admin"] + assert res['permissions_app.dev']['urls'] == ["/dev"] app_change_url("permissions_app", maindomain, "/newchangeurl") res = user_permission_list(full=True)['permissions'] - assert res['permissions_app.main']['urls'] == [maindomain + "/newchangeurl"] - assert res['permissions_app.admin']['urls'] == [maindomain + "/newchangeurl/admin"] - assert res['permissions_app.dev']['urls'] == [maindomain + "/newchangeurl/dev"] + assert res['permissions_app.main']['urls'] == ["/"] + assert res['permissions_app.admin']['urls'] == ["/admin"] + assert res['permissions_app.dev']['urls'] == ["/dev"] def test_permission_app_propagation_on_ssowat(): From 7102c5d0ca1ce36a3ff90e3fcb688d4a5be0d221 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 20 Sep 2019 20:14:44 +0200 Subject: [PATCH 015/127] Propagate the new relative url stuff to app_ssowatconf and actuall implement the whole permission system thing in app_map (related to ssowatconf) --- src/yunohost/app.py | 126 ++++++++++++++++++++++---- src/yunohost/tests/test_permission.py | 3 + 2 files changed, 113 insertions(+), 16 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 231568439..51030021f 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -427,25 +427,97 @@ def app_map(app=None, raw=False, user=None): if 'path' not in app_settings: # we assume that an app that doesn't have a path doesn't have an HTTP api continue + # This 'no_sso' settings sound redundant to not having $path defined .... + # At least from what I can see, all apps using it don't have a path defined ... if 'no_sso' in app_settings: # I don't think we need to check for the value here continue + # Users must at least have access to the main permission to have access to extra permissions if user: main_perm = permissions[app_id + ".main"] if user not in main_perm["corresponding_users"] and "visitors" not in main_perm["allowed"]: continue domain = app_settings['domain'] - path = app_settings['path'] + path = app_settings['path'].rstrip('/') + label = app_settings['label'] - if raw: - if domain not in result: - result[domain] = {} - result[domain][path] = { - 'label': app_settings['label'], - 'id': app_settings['id'] - } - else: - result[domain + path] = app_settings['label'] + def _sanitized_absolute_url(perm_url): + # Nominal case : url is relative to the app's path + if perm_url.startswith("/"): + perm_domain = domain + perm_path = path + perm_url.rstrip("/") + # Otherwise, the urls starts with a domain name, like domain.tld/foo/bar + # We want perm_domain = domain.tld and perm_path = "/foo/bar" + else: + perm_domain, perm_path = perm_url.split("/", 1) + perm_path = "/" + perm_path.rstrip("/") + + return perm_domain, perm_path + + this_app_perms = {p: i for p, i in permissions.items() if p.startswith(app_id + ".") and i["urls"]} + for perm_name, perm_info in this_app_perms.items(): + # If we're building the map for a specific user, check the user + # actually is allowed for this specific perm + if user and user not in perm_info["corresponding_users"] and "visitors" not in perm_info["allowed"]: + continue + if len(perm_info["urls"]) > 1 or perm_info["urls"][0].startswith("re:"): + # + # Here we have a big conceptual issue about the sso ... + # Let me take a sip of coffee and turn off the music... + # + # Let's say we have an app foo which created a permission + # 'foo.admin' and added as url "/admin" and "/api" This + # permission got defined somehow as only accessible for group + # "admins". So both "/admin" and "/api" are protected. Good! + # + # Now if we really want users in group "admins" to access those + # uris, then each users in group "admins" need to have these + # urls in the ssowat dict for this user. Which corresponds to a + # tile. To put it otherwise : in the current code of ssowat, a + # permission = a tile = a url ! + # + # We also have an issue if the url define is a regex, because + # the url we want to add to the dict is going to be turned into + # a clickable link (or analyzed by other parts of yunohost + # code...). To put it otherwise : in the current code of ssowat, + # you can't give access a user to a regex + # + # Instead, as drafted by Josue, we could rework the ssowat logic + # about how routes and their permissions are defined. So for example, + # have a dict of + # { "/route1": ["visitors", "user1", "user2", ...], # Public route + # "/route2_with_a_regex$": ["user1", "user2"], # Private route + # "/route3": None, # Skipped route idk + # } + # then each time a user try to request and url, we only keep the + # longest matching rule and check the user is allowed etc... + # + # The challenge with this is (beside actually implementing it) + # is that it creates a whole new mechanism that ultimately + # replace all the existing logic about + # protected/unprotected/skipped uris and regexes and we gotta + # handle / migrate all the legacy stuff somehow if we don't + # want to end up with a total mess in the future idk + logger.error("Permission %s can't be added to the SSOwat configuration because it uses multiple urls and/or uses a regex url" % perm_name) + continue + + perm_domain, perm_path = _sanitized_absolute_url(perm_info["urls"][0]) + + if perm_name.endswith(".main"): + perm_label = label + else: + # e.g. if perm_name is wordpress.admin, we want "Blog (Admin)" (where Blog is the label of this app) + perm_label = "%s (%s)" % (label, perm_name.rsplit(".")[-1].replace("_", " ").title()) + + if raw: + if domain not in result: + result[perm_domain] = {} + result[perm_domain][perm_path] = { + 'label': perm_label, + 'id': app_id + } + else: + result[perm_domain + perm_path] = perm_label return result @@ -1382,13 +1454,34 @@ def app_ssowatconf(): app_settings = read_yaml(APPS_SETTING_PATH + app['id'] + '/settings.yml') + if 'domain' not in app_settings: + continue + if 'path' not in app_settings: + continue + + # This 'no_sso' settings sound redundant to not having $path defined .... + # At least from what I can see, all apps using it don't have a path defined ... if 'no_sso' in app_settings: continue - app_root_webpath = app_settings['domain'] + app_settings['path'].rstrip('/') + domain = app_settings['domain'] + path = app_settings['path'].rstrip('/') + + def _sanitized_absolute_url(perm_url): + # Nominal case : url is relative to the app's path + if perm_url.startswith("/"): + perm_domain = domain + perm_path = path + perm_url.rstrip("/") + # Otherwise, the urls starts with a domain name, like domain.tld/foo/bar + # We want perm_domain = domain.tld and perm_path = "/foo/bar" + else: + perm_domain, perm_path = perm_url.split("/", 1) + perm_path = "/" + perm_path.rstrip("/") + + return perm_domain + perm_path # Skipped - skipped_urls += [app_root_webpath + uri.rstrip("/") for uri in _get_setting(app_settings, 'skipped_uris')] + skipped_urls += [_sanitized_absolute_url(uri) for uri in _get_setting(app_settings, 'skipped_uris')] skipped_regex += _get_setting(app_settings, 'skipped_regex') # Redirected @@ -1396,15 +1489,16 @@ def app_ssowatconf(): redirected_regex.update(app_settings.get('redirected_regex', {})) # Legacy permission system using (un)protected_uris and _regex managed in app settings... - unprotected_urls += [app_root_webpath + uri.rstrip("/") for uri in _get_setting(app_settings, 'unprotected_uris')] - unprotected_urls += [app_root_webpath + uri.rstrip("/") for uri in _get_setting(app_settings, 'protected_uris')] + unprotected_urls += [_sanitized_absolute_url(uri) for uri in _get_setting(app_settings, 'unprotected_uris')] + protected_urls += [_sanitized_absolute_url(uri) for uri in _get_setting(app_settings, 'protected_uris')] unprotected_regex += _get_setting(app_settings, 'unprotected_regex') - unprotected_regex += _get_setting(app_settings, 'protected_regex') + protected_regex += _get_setting(app_settings, 'protected_regex') # New permission system this_app_perms = {name: info for name, info in all_permissions.items() if name.startswith(app['id'] + ".")} for perm_name, perm_info in this_app_perms.items(): - urls = [url.rstrip("/") for url in perm_info["urls"]] + # FIXME : gotta handle regex-urls here... meh + urls = [_sanitized_absolute_url(url) for url in perm_info["urls"]] if "visitors" in perm_info["allowed"]: unprotected_urls += urls diff --git a/src/yunohost/tests/test_permission.py b/src/yunohost/tests/test_permission.py index a8b6b8258..4dc021496 100644 --- a/src/yunohost/tests/test_permission.py +++ b/src/yunohost/tests/test_permission.py @@ -434,6 +434,9 @@ def test_permission_app_propagation_on_ssowat(): # Test admin access, as configured during install, only alice should be able to access it + # alice gotta be allowed on the main permission to access the admin tho + user_permission_update("permissions_app.main", remove="bob", add="all_users") + assert not can_access_webpage(app_webroot+"/admin", logged_as=None) assert can_access_webpage(app_webroot+"/admin", logged_as="alice") assert not can_access_webpage(app_webroot+"/admin", logged_as="bob") From 2a5053b66bfc7bd48cd8f7668db1ee93b1103fe7 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 21 Sep 2019 13:32:40 +0200 Subject: [PATCH 016/127] Misc wording and orthotypography... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Allan Nordhøy --- data/helpers.d/setting | 8 ++++---- locales/en.json | 2 +- src/yunohost/permission.py | 12 ++++++------ src/yunohost/tests/test_permission.py | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/data/helpers.d/setting b/data/helpers.d/setting index 9deba2dc0..b2a647993 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -177,7 +177,7 @@ else: if key in ['redirected_urls', 'redirected_regex']: value = yaml.load(value) if key in ["unprotected_uris", "unprotected_regex", "protected_uris", "protected_regex"]: - logger.warning("/!\\ Packagers ! This app is using the legacy permission system. Please delete these legacy settings and use the new helpers ynh_permission_{create,urls,update,delete} and the 'visitors' group to manage public/private access.") + logger.warning("/!\\ Packagers! This app is using the legacy permission system. Please delete these legacy settings and use the new helpers 'ynh_permission_{create,urls,update,delete}' and the 'visitors' group to manage public/private access.") settings[key] = value else: raise ValueError("action should either be get, set or delete") @@ -237,15 +237,15 @@ ynh_webpath_register () { # usage: ynh_permission_create --permission "permission" [--urls "url" ["url" ...]] # | arg: permission - the name for the permission (by default a permission named "main" already exist) # | arg: urls - (optional) a list of FULL urls for the permission (e.g. domain.tld/apps/admin) -# | arg: urls - (optional) a list of urls to specify for the permission. +# | arg: urls - (optional) a list of URLs to specify for the permission. # -# Urls are assumed to be relative to the app domain/path if they start with '/'. +# URLs are assumed to be relative to the app domain/path if they start with '/'. # For example: # / -> domain.tld/app # /admin -> domain.tld/app/admin # domain.tld/app/api -> domain.tld/app/api # -# Urls can be treated as regexes when they start with "re:". +# URLs can be treated as regexes when they start with "re:". # For example: # re:/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ # re:domain.tld/app/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ diff --git a/locales/en.json b/locales/en.json index 5df21b684..70b9fa626 100644 --- a/locales/en.json +++ b/locales/en.json @@ -230,7 +230,7 @@ "group_already_exist_on_system": "Group {group} already exists in the system group", "group_created": "Group '{group}' successfully created", "group_creation_failed": "Failed to create group {group}: {error}", - "group_cannot_edit_all_users": "The group 'all_users' cannot be edited manually. It is a special group meant to contain all users registered in Yunohost", + "group_cannot_edit_all_users": "The group 'all_users' cannot be edited manually. It is a special group meant to contain all users registered in YunoHost", "group_cannot_edit_visitors": "The group 'visitors' cannot be edited manually. It is a special group representing anonymous visitors", "group_cannot_edit_primary_group": "The group '{group}' cannot be edited manually. It is the primary group meant to contain only one specific user.", "group_cannot_be_edited": "The group {group} cannot be edited manually.", diff --git a/src/yunohost/permission.py b/src/yunohost/permission.py index 5f9a88e11..75e3f6037 100644 --- a/src/yunohost/permission.py +++ b/src/yunohost/permission.py @@ -146,11 +146,11 @@ def user_permission_update(operation_logger, permission, add=None, remove=None, if "all_users" in new_allowed_groups: # FIXME : i18n # FIXME : write a better explanation ? - logger.warning("This permission is currently enabled for all users in addition to other groups. You probably want to either remove the 'all_users' permission or remove the other groups currently allowed.") + logger.warning("This permission is currently granted to all users in addition to other groups. You probably want to either remove the 'all_users' permission or remove the other groups it is currently granted to.") if "visitors" in new_allowed_groups: # FIXME : i18n # FIXME : write a better explanation ? - logger.warning("This permission is currently enabled for visitors in addition to other groups. You probably want to either remove the 'visitors' permission or remove the other groups currently allowed.") + logger.warning("This permission is currently granted to visitors in addition to other groups. You probably want to either remove the 'visitors' permission or remove the other groups it is currently granted to.") # Don't update LDAP if we update exactly the same values if set(new_allowed_groups) == set(current_allowed_groups): @@ -268,7 +268,7 @@ def permission_create(operation_logger, permission, urls=None, sync_perm=True): Keyword argument: permission -- Name of the permission (e.g. mail or nextcloud or wordpress.editors) - urls -- list of urls to specify for the permission. + urls -- list of URLs to specify for the permission. Urls are assumed to be relative to the app domain/path if they start with '/'. For example: @@ -276,7 +276,7 @@ def permission_create(operation_logger, permission, urls=None, sync_perm=True): /admin -> domain.tld/app/admin domain.tld/app/api -> domain.tld/app/api - Urls can be later treated as regexes when they start with "re:". + URLs can be later treated as regexes when they start with "re:". For example: re:/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ re:domain.tld/app/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ @@ -337,8 +337,8 @@ def permission_urls(operation_logger, permission, add=None, remove=None, sync_pe Keyword argument: permission -- Name of the permission (e.g. mail or nextcloud or wordpress.editors) - add -- List of urls to add (c.f. permission_create for documentation about their format) - remove -- List of urls to remove (c.f. permission_create for documentation about their format) + add -- List of URLs to add (c.f. permission_create for documentation about their format) + remove -- List of URLs to remove (c.f. permission_create for documentation about their format) """ from yunohost.utils.ldap import _get_ldap_interface diff --git a/src/yunohost/tests/test_permission.py b/src/yunohost/tests/test_permission.py index 4dc021496..f17313fa1 100644 --- a/src/yunohost/tests/test_permission.py +++ b/src/yunohost/tests/test_permission.py @@ -180,7 +180,7 @@ def can_access_webpage(webpath, logged_as=None): assert session.cookies r = session.get(webpath, verify=False) - # If we can't access it, we got redirected to the sso + # If we can't access it, we got redirected to the SSO return not r.url.startswith(sso_url) # From 61fb0be7735dcc8369c03de4e066776aefad83e6 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 23 Sep 2019 20:57:59 +0200 Subject: [PATCH 017/127] More accurate tests with explicit exception/message excepted to be triggered --- src/yunohost/tests/conftest.py | 23 +++ src/yunohost/tests/test_backuprestore.py | 184 ++++++++++------------- src/yunohost/tests/test_permission.py | 128 ++++++++++------ src/yunohost/tests/test_user-group.py | 146 +++++++++++------- src/yunohost/utils/error.py | 4 +- 5 files changed, 285 insertions(+), 200 deletions(-) diff --git a/src/yunohost/tests/conftest.py b/src/yunohost/tests/conftest.py index a2dc585bd..e23110d1a 100644 --- a/src/yunohost/tests/conftest.py +++ b/src/yunohost/tests/conftest.py @@ -1,9 +1,32 @@ +import pytest import sys import moulinette +from moulinette import m18n +from yunohost.utils.error import YunohostError +from contextlib import contextmanager + sys.path.append("..") + +@contextmanager +def message(mocker, key, **kwargs): + mocker.spy(m18n, "n") + yield + m18n.n.assert_any_call(key, **kwargs) + + +@contextmanager +def raiseYunohostError(mocker, key, **kwargs): + with pytest.raises(YunohostError) as e_info: + yield + assert e_info._excinfo[1].key == key + if kwargs: + assert e_info._excinfo[1].kwargs == kwargs + + + def pytest_addoption(parser): parser.addoption("--yunodebug", action="store_true", default=False) diff --git a/src/yunohost/tests/test_backuprestore.py b/src/yunohost/tests/test_backuprestore.py index cab98089b..ce3e28401 100644 --- a/src/yunohost/tests/test_backuprestore.py +++ b/src/yunohost/tests/test_backuprestore.py @@ -2,14 +2,13 @@ import pytest import os import shutil import subprocess -from mock import ANY -from moulinette import m18n +from conftest import message, raiseYunohostError + from yunohost.app import app_install, app_remove, app_ssowatconf from yunohost.app import _is_installed from yunohost.backup import backup_create, backup_restore, backup_list, backup_info, backup_delete, _recursive_umount from yunohost.domain import _get_maindomain -from yunohost.utils.error import YunohostError from yunohost.user import user_permission_list, user_create, user_list, user_delete from yunohost.tests.test_permission import check_LDAP_db_integrity, check_permission_for_apps @@ -206,10 +205,11 @@ def add_archive_system_from_2p4(): # -def test_backup_only_ldap(): +def test_backup_only_ldap(mocker): # Create the backup - backup_create(system=["conf_ldap"], apps=None) + with message(mocker, "backup_created"): + backup_create(system=["conf_ldap"], apps=None) archives = backup_list()["archives"] assert len(archives) == 1 @@ -222,24 +222,22 @@ def test_backup_only_ldap(): def test_backup_system_part_that_does_not_exists(mocker): - mocker.spy(m18n, "n") - # Create the backup - with pytest.raises(YunohostError): - backup_create(system=["yolol"], apps=None) + with message(mocker, 'backup_hook_unknown', hook="doesnt_exist"): + with raiseYunohostError(mocker, "backup_nothings_done"): + backup_create(system=["doesnt_exist"], apps=None) - m18n.n.assert_any_call('backup_hook_unknown', hook="yolol") - m18n.n.assert_any_call('backup_nothings_done') # # System backup and restore # # -def test_backup_and_restore_all_sys(): +def test_backup_and_restore_all_sys(mocker): # Create the backup - backup_create(system=[], apps=None) + with message(mocker, "backup_created"): + backup_create(system=[], apps=None) archives = backup_list()["archives"] assert len(archives) == 1 @@ -255,8 +253,9 @@ def test_backup_and_restore_all_sys(): assert not os.path.exists("/etc/ssowat/conf.json") # Restore the backup - backup_restore(name=archives[0], force=True, - system=[], apps=None) + with message(mocker, "restore_complete"): + backup_restore(name=archives[0], force=True, + system=[], apps=None) # Check ssowat conf is back assert os.path.exists("/etc/ssowat/conf.json") @@ -270,16 +269,18 @@ def test_backup_and_restore_all_sys(): def test_restore_system_from_Ynh2p4(monkeypatch, mocker): # Backup current system - backup_create(system=[], apps=None) + with message(mocker, "backup_created"): + backup_create(system=[], apps=None) archives = backup_list()["archives"] assert len(archives) == 2 # Restore system archive from 2.4 try: - backup_restore(name=backup_list()["archives"][1], - system=[], - apps=None, - force=True) + with message(mocker, "restore_complete"): + backup_restore(name=backup_list()["archives"][1], + system=[], + apps=None, + force=True) finally: # Restore system as it was backup_restore(name=backup_list()["archives"][0], @@ -306,12 +307,10 @@ def test_backup_script_failure_handling(monkeypatch, mocker): # call with monkeypatch). We also patch m18n to check later it's been called # with the expected error message key monkeypatch.setattr("yunohost.backup.hook_exec", custom_hook_exec) - mocker.spy(m18n, "n") - with pytest.raises(YunohostError): - backup_create(system=None, apps=["backup_recommended_app"]) - - m18n.n.assert_any_call('backup_app_failed', app='backup_recommended_app') + with message(mocker, 'backup_app_failed', app='backup_recommended_app'): + with raiseYunohostError(mocker, 'backup_nothings_done'): + backup_create(system=None, apps=["backup_recommended_app"]) @pytest.mark.with_backup_recommended_app_installed @@ -327,25 +326,17 @@ def test_backup_not_enough_free_space(monkeypatch, mocker): monkeypatch.setattr("yunohost.backup.free_space_in_directory", custom_free_space_in_directory) - mocker.spy(m18n, "n") - - with pytest.raises(YunohostError): + with raiseYunohostError(mocker, 'not_enough_disk_space'): backup_create(system=None, apps=["backup_recommended_app"]) - m18n.n.assert_any_call('not_enough_disk_space', path=ANY) - def test_backup_app_not_installed(mocker): assert not _is_installed("wordpress") - mocker.spy(m18n, "n") - - with pytest.raises(YunohostError): - backup_create(system=None, apps=["wordpress"]) - - m18n.n.assert_any_call("unbackup_app", app="wordpress") - m18n.n.assert_any_call('backup_nothings_done') + with message(mocker, "unbackup_app", app="wordpress"): + with raiseYunohostError(mocker, 'backup_nothings_done'): + backup_create(system=None, apps=["wordpress"]) @pytest.mark.with_backup_recommended_app_installed @@ -355,13 +346,9 @@ def test_backup_app_with_no_backup_script(mocker): os.system("rm %s" % backup_script) assert not os.path.exists(backup_script) - mocker.spy(m18n, "n") - - with pytest.raises(YunohostError): - backup_create(system=None, apps=["backup_recommended_app"]) - - m18n.n.assert_any_call("backup_with_no_backup_script_for_app", app="backup_recommended_app") - m18n.n.assert_any_call('backup_nothings_done') + with message(mocker, "backup_with_no_backup_script_for_app", app="backup_recommended_app"): + with raiseYunohostError(mocker, 'backup_nothings_done'): + backup_create(system=None, apps=["backup_recommended_app"]) @pytest.mark.with_backup_recommended_app_installed @@ -371,23 +358,21 @@ def test_backup_app_with_no_restore_script(mocker): os.system("rm %s" % restore_script) assert not os.path.exists(restore_script) - mocker.spy(m18n, "n") - # Backuping an app with no restore script will only display a warning to the # user... - backup_create(system=None, apps=["backup_recommended_app"]) - - m18n.n.assert_any_call("backup_with_no_restore_script_for_app", app="backup_recommended_app") + with message(mocker, "backup_with_no_restore_script_for_app", app="backup_recommended_app"): + backup_create(system=None, apps=["backup_recommended_app"]) @pytest.mark.clean_opt_dir -def test_backup_with_different_output_directory(): +def test_backup_with_different_output_directory(mocker): # Create the backup - backup_create(system=["conf_ssh"], apps=None, - output_directory="/opt/test_backup_output_directory", - name="backup") + with message(mocker, "backup_created"): + backup_create(system=["conf_ssh"], apps=None, + output_directory="/opt/test_backup_output_directory", + name="backup") assert os.path.exists("/opt/test_backup_output_directory/backup.tar.gz") @@ -401,12 +386,14 @@ def test_backup_with_different_output_directory(): @pytest.mark.clean_opt_dir -def test_backup_with_no_compress(): +def test_backup_with_no_compress(mocker): + # Create the backup - backup_create(system=["conf_nginx"], apps=None, - output_directory="/opt/test_backup_output_directory", - no_compress=True, - name="backup") + with message(mocker, "backup_created"): + backup_create(system=["conf_nginx"], apps=None, + output_directory="/opt/test_backup_output_directory", + no_compress=True, + name="backup") assert os.path.exists("/opt/test_backup_output_directory/info.json") @@ -416,10 +403,11 @@ def test_backup_with_no_compress(): # @pytest.mark.with_wordpress_archive_from_2p4 -def test_restore_app_wordpress_from_Ynh2p4(): +def test_restore_app_wordpress_from_Ynh2p4(mocker): - backup_restore(system=None, name=backup_list()["archives"][0], - apps=["wordpress"]) + with message(mocker, "restore_complete"): + backup_restore(system=None, name=backup_list()["archives"][0], + apps=["wordpress"]) @pytest.mark.with_wordpress_archive_from_2p4 @@ -431,16 +419,14 @@ def test_restore_app_script_failure_handling(monkeypatch, mocker): raise Exception monkeypatch.setattr("yunohost.backup.hook_exec", custom_hook_exec) - mocker.spy(m18n, "n") assert not _is_installed("wordpress") - with pytest.raises(YunohostError): - backup_restore(system=None, name=backup_list()["archives"][0], - apps=["wordpress"]) + with message(mocker, 'restore_app_failed', app='wordpress'): + with raiseYunohostError(mocker, 'restore_nothings_done'): + backup_restore(system=None, name=backup_list()["archives"][0], + apps=["wordpress"]) - m18n.n.assert_any_call('restore_app_failed', app='wordpress') - m18n.n.assert_any_call('restore_nothings_done') assert not _is_installed("wordpress") @@ -452,18 +438,13 @@ def test_restore_app_not_enough_free_space(monkeypatch, mocker): monkeypatch.setattr("yunohost.backup.free_space_in_directory", custom_free_space_in_directory) - mocker.spy(m18n, "n") assert not _is_installed("wordpress") - with pytest.raises(YunohostError): + with raiseYunohostError(mocker, 'restore_not_enough_disk_space'): backup_restore(system=None, name=backup_list()["archives"][0], apps=["wordpress"]) - m18n.n.assert_any_call('restore_not_enough_disk_space', - free_space=0, - margin=ANY, - needed_space=ANY) assert not _is_installed("wordpress") @@ -473,13 +454,11 @@ def test_restore_app_not_in_backup(mocker): assert not _is_installed("wordpress") assert not _is_installed("yoloswag") - mocker.spy(m18n, "n") + with message(mocker, 'backup_archive_app_not_found', app="yoloswag"): + with raiseYunohostError(mocker, 'restore_nothings_done'): + backup_restore(system=None, name=backup_list()["archives"][0], + apps=["yoloswag"]) - with pytest.raises(YunohostError): - backup_restore(system=None, name=backup_list()["archives"][0], - apps=["yoloswag"]) - - m18n.n.assert_any_call('backup_archive_app_not_found', app="yoloswag") assert not _is_installed("wordpress") assert not _is_installed("yoloswag") @@ -489,38 +468,36 @@ def test_restore_app_already_installed(mocker): assert not _is_installed("wordpress") - backup_restore(system=None, name=backup_list()["archives"][0], - apps=["wordpress"]) - - assert _is_installed("wordpress") - - mocker.spy(m18n, "n") - with pytest.raises(YunohostError): + with message(mocker, "restore_complete"): backup_restore(system=None, name=backup_list()["archives"][0], apps=["wordpress"]) - m18n.n.assert_any_call('restore_already_installed_app', app="wordpress") - m18n.n.assert_any_call('restore_nothings_done') + assert _is_installed("wordpress") + + with message(mocker, 'restore_already_installed_app', app="wordpress"): + with raiseYunohostError(mocker, 'restore_nothings_done'): + backup_restore(system=None, name=backup_list()["archives"][0], + apps=["wordpress"]) assert _is_installed("wordpress") @pytest.mark.with_legacy_app_installed -def test_backup_and_restore_legacy_app(): +def test_backup_and_restore_legacy_app(mocker): - _test_backup_and_restore_app("legacy_app") + _test_backup_and_restore_app(mocker, "legacy_app") @pytest.mark.with_backup_recommended_app_installed -def test_backup_and_restore_recommended_app(): +def test_backup_and_restore_recommended_app(mocker): - _test_backup_and_restore_app("backup_recommended_app") + _test_backup_and_restore_app(mocker, "backup_recommended_app") @pytest.mark.with_backup_recommended_app_installed_with_ynh_restore -def test_backup_and_restore_with_ynh_restore(): +def test_backup_and_restore_with_ynh_restore(mocker): - _test_backup_and_restore_app("backup_recommended_app") + _test_backup_and_restore_app(mocker, "backup_recommended_app") @pytest.mark.with_permission_app_installed def test_backup_and_restore_permission_app(): @@ -552,10 +529,11 @@ def test_backup_and_restore_permission_app(): assert res['permissions_app.dev']['allowed'] == [] -def _test_backup_and_restore_app(app): +def _test_backup_and_restore_app(mocker, app): # Create a backup of this app - backup_create(system=None, apps=[app]) + with message(mocker, "backup_created"): + backup_create(system=None, apps=[app]) archives = backup_list()["archives"] assert len(archives) == 1 @@ -571,8 +549,9 @@ def _test_backup_and_restore_app(app): assert app+".main" not in user_permission_list()['permissions'] # Restore the app - backup_restore(system=None, name=archives[0], - apps=[app]) + with message(mocker, "restore_complete"): + backup_restore(system=None, name=archives[0], + apps=[app]) assert app_is_installed(app) @@ -593,13 +572,11 @@ def test_restore_archive_with_no_json(mocker): assert "badbackup" in backup_list()["archives"] - mocker.spy(m18n, "n") - with pytest.raises(YunohostError): + with raiseYunohostError(mocker, 'backup_invalid_archive'): backup_restore(name="badbackup", force=True) - m18n.n.assert_any_call('backup_invalid_archive') -def test_backup_binds_are_readonly(monkeypatch): +def test_backup_binds_are_readonly(mocker, monkeypatch): def custom_mount_and_backup(self, backup_manager): self.manager = backup_manager @@ -620,4 +597,5 @@ def test_backup_binds_are_readonly(monkeypatch): custom_mount_and_backup) # Create the backup - backup_create(system=[]) + with message(mocker, "backup_created"): + backup_create(system=[]) diff --git a/src/yunohost/tests/test_permission.py b/src/yunohost/tests/test_permission.py index f17313fa1..0f3fb63e0 100644 --- a/src/yunohost/tests/test_permission.py +++ b/src/yunohost/tests/test_permission.py @@ -1,19 +1,20 @@ import requests import pytest -from yunohost.app import app_install, app_remove, app_change_url, app_list, app_map +from conftest import message, raiseYunohostError -from yunohost.user import user_list, user_info, user_create, user_delete, user_update, \ - user_group_list, user_group_create, user_group_delete, user_group_update, user_group_info +from yunohost.app import app_install, app_remove, app_change_url, app_list, app_map +from yunohost.user import user_list, user_create, user_delete, \ + user_group_list, user_group_delete from yunohost.permission import user_permission_update, user_permission_list, user_permission_reset, \ permission_create, permission_urls, permission_delete from yunohost.domain import _get_maindomain -from yunohost.utils.error import YunohostError # Get main domain maindomain = _get_maindomain() dummy_password = "test123Ynh" + def clean_user_groups_permission(): for u in user_list()['users']: user_delete(u) @@ -26,6 +27,7 @@ def clean_user_groups_permission(): if any(p.startswith(name) for name in ["wiki", "blog", "site", "permissions_app"]): permission_delete(p, force=True, sync_perm=False) + def setup_function(function): clean_user_groups_permission() @@ -35,6 +37,7 @@ def setup_function(function): permission_create("blog.main", sync_perm=False) user_permission_update("blog.main", remove="all_users", add="alice") + def teardown_function(function): clean_user_groups_permission() try: @@ -42,12 +45,14 @@ def teardown_function(function): except: pass + @pytest.fixture(autouse=True) def check_LDAP_db_integrity_call(): check_LDAP_db_integrity() yield check_LDAP_db_integrity() + def check_LDAP_db_integrity(): # Here we check that all attributes in all object are sychronized. # Here is the list of attributes per object: @@ -162,7 +167,7 @@ def check_permission_for_apps(): def can_access_webpage(webpath, logged_as=None): webpath = webpath.rstrip("/") - sso_url = "https://"+maindomain+"/yunohost/sso/" + sso_url = "https://" + maindomain + "/yunohost/sso/" # Anonymous access if not logged_as: @@ -183,6 +188,7 @@ def can_access_webpage(webpath, logged_as=None): # If we can't access it, we got redirected to the SSO return not r.url.startswith(sso_url) + # # List functions # @@ -204,8 +210,10 @@ def test_permission_list(): # Create - Remove functions # -def test_permission_create_main(): - permission_create("site.main") + +def test_permission_create_main(mocker): + with message(mocker, "permission_created", permission="site.main"): + permission_create("site.main") res = user_permission_list(full=True)['permissions'] assert "site.main" in res @@ -213,8 +221,9 @@ def test_permission_create_main(): assert set(res['site.main']['corresponding_users']) == set(["alice", "bob"]) -def test_permission_create_extra(): - permission_create("site.test") +def test_permission_create_extra(mocker): + with message(mocker, "permission_created", permission="site.test"): + permission_create("site.test") res = user_permission_list(full=True)['permissions'] assert "site.test" in res @@ -222,8 +231,10 @@ def test_permission_create_extra(): assert "all_users" not in res['site.test']['allowed'] assert res['site.test']['corresponding_users'] == [] -def test_permission_delete(): - permission_delete("wiki.main", force=True) + +def test_permission_delete(mocker): + with message(mocker, "permission_deleted", permission="wiki.main"): + permission_delete("wiki.main", force=True) res = user_permission_list()['permissions'] assert "wiki.main" not in res @@ -232,12 +243,14 @@ def test_permission_delete(): # Error on create - remove function # -def test_permission_create_already_existing(): - with pytest.raises(YunohostError): + +def test_permission_create_already_existing(mocker): + with raiseYunohostError(mocker, "permission_already_exist"): permission_create("wiki.main") -def test_permission_delete_doesnt_existing(): - with pytest.raises(YunohostError): + +def test_permission_delete_doesnt_existing(mocker): + with raiseYunohostError(mocker, "permission_not_found"): permission_delete("doesnt.exist", force=True) res = user_permission_list()['permissions'] @@ -246,8 +259,9 @@ def test_permission_delete_doesnt_existing(): assert "mail.main" in res assert "xmpp.main" in res -def test_permission_delete_main_without_force(): - with pytest.raises(YunohostError): + +def test_permission_delete_main_without_force(mocker): + with raiseYunohostError(mocker, "permission_cannot_remove_main"): permission_delete("blog.main") res = user_permission_list()['permissions'] @@ -259,44 +273,55 @@ def test_permission_delete_main_without_force(): # user side functions -def test_permission_add_group(): - user_permission_update("wiki.main", add="alice") + +def test_permission_add_group(mocker): + with message(mocker, "permission_updated", permission="wiki.main"): + user_permission_update("wiki.main", add="alice") res = user_permission_list(full=True)['permissions'] assert set(res['wiki.main']['allowed']) == set(["all_users", "alice"]) assert set(res['wiki.main']['corresponding_users']) == set(["alice", "bob"]) -def test_permission_remove_group(): - user_permission_update("blog.main", remove="alice") + +def test_permission_remove_group(mocker): + with message(mocker, "permission_updated", permission="blog.main"): + user_permission_update("blog.main", remove="alice") res = user_permission_list(full=True)['permissions'] assert res['blog.main']['allowed'] == [] assert res['blog.main']['corresponding_users'] == [] -def test_permission_add_and_remove_group(): - user_permission_update("wiki.main", add="alice", remove="all_users") + +def test_permission_add_and_remove_group(mocker): + with message(mocker, "permission_updated", permission="wiki.main"): + user_permission_update("wiki.main", add="alice", remove="all_users") res = user_permission_list(full=True)['permissions'] assert res['wiki.main']['allowed'] == ["alice"] assert res['wiki.main']['corresponding_users'] == ["alice"] -def test_permission_add_group_already_allowed(): - user_permission_update("blog.main", add="alice") + +def test_permission_add_group_already_allowed(mocker): + with message(mocker, "permission_already_allowed", permission="blog.main", group="alice"): + user_permission_update("blog.main", add="alice") res = user_permission_list(full=True)['permissions'] assert res['blog.main']['allowed'] == ["alice"] assert res['blog.main']['corresponding_users'] == ["alice"] -def test_permission_remove_group_already_not_allowed(): - user_permission_update("blog.main", remove="bob") + +def test_permission_remove_group_already_not_allowed(mocker): + with message(mocker, "permission_already_disallowed", permission="blog.main", group="bob"): + user_permission_update("blog.main", remove="bob") res = user_permission_list(full=True)['permissions'] assert res['blog.main']['allowed'] == ["alice"] assert res['blog.main']['corresponding_users'] == ["alice"] -def test_permission_reset(): - # Reset permission - user_permission_reset("blog.main") + +def test_permission_reset(mocker): + with message(mocker, "permission_updated", permission="blog.main"): + user_permission_reset("blog.main") res = user_permission_list(full=True)['permissions'] assert res['blog.main']['allowed'] == ["all_users"] @@ -306,50 +331,62 @@ def test_permission_reset(): # Error on update function # -def test_permission_add_group_that_doesnt_exist(): - with pytest.raises(YunohostError): + +def test_permission_add_group_that_doesnt_exist(mocker): + with raiseYunohostError(mocker, "group_unknown"): user_permission_update("blog.main", add="doesnt_exist") res = user_permission_list(full=True)['permissions'] assert res['blog.main']['allowed'] == ["alice"] assert res['blog.main']['corresponding_users'] == ["alice"] -def test_permission_update_permission_that_doesnt_exist(): - with pytest.raises(YunohostError): + +def test_permission_update_permission_that_doesnt_exist(mocker): + with raiseYunohostError(mocker, "permission_not_found"): user_permission_update("doesnt.exist", add="alice") # Permission url management -def test_permission_add_url(): - permission_urls("blog.main", add=["/testA"]) + +def test_permission_add_url(mocker): + with message(mocker, "permission_updated", permission="blog.main"): + permission_urls("blog.main", add=["/testA"]) res = user_permission_list(full=True)['permissions'] assert res["blog.main"]["urls"] == ["/testA"] -def test_permission_add_another_url(): - permission_urls("wiki.main", add=["/testA"]) + +def test_permission_add_another_url(mocker): + with message(mocker, "permission_updated", permission="wiki.main"): + permission_urls("wiki.main", add=["/testA"]) res = user_permission_list(full=True)['permissions'] assert set(res["wiki.main"]["urls"]) == set(["/", "/testA"]) -def test_permission_remove_url(): - permission_urls("wiki.main", remove=["/"]) + +def test_permission_remove_url(mocker): + with message(mocker, "permission_updated", permission="wiki.main"): + permission_urls("wiki.main", remove=["/"]) res = user_permission_list(full=True)['permissions'] assert res["wiki.main"]["urls"] == [] -def test_permission_add_url_already_added(): + +def test_permission_add_url_already_added(mocker): res = user_permission_list(full=True)['permissions'] assert res["wiki.main"]["urls"] == ["/"] - permission_urls("wiki.main", add=["/"]) + with message(mocker, "permission_update_nothing_to_do"): + permission_urls("wiki.main", add=["/"]) res = user_permission_list(full=True)['permissions'] assert res["wiki.main"]["urls"] == ["/"] -def test_permission_remove_url_not_added(): - permission_urls("wiki.main", remove=["/doesnt_exist"]) + +def test_permission_remove_url_not_added(mocker): + with message(mocker, "permission_update_nothing_to_do"): + permission_urls("wiki.main", remove=["/doesnt_exist"]) res = user_permission_list(full=True)['permissions'] assert res['wiki.main']['urls'] == ["/"] @@ -358,6 +395,7 @@ def test_permission_remove_url_not_added(): # Application interaction # + def test_permission_app_install(): app_install("./tests/apps/permissions_app_ynh", args="domain=%s&path=%s&is_public=0&admin=%s" % (maindomain, "/urlpermissionapp", "alice"), force=True) @@ -395,6 +433,7 @@ def test_permission_app_remove(): res = user_permission_list(full=True)['permissions'] assert not any(p.startswith("permissions_app.") for p in res.keys()) + def test_permission_app_change_url(): app_install("./tests/apps/permissions_app_ynh", args="domain=%s&path=%s&admin=%s" % (maindomain, "/urlpermissionapp", "alice"), force=True) @@ -441,6 +480,7 @@ def test_permission_app_propagation_on_ssowat(): assert can_access_webpage(app_webroot+"/admin", logged_as="alice") assert not can_access_webpage(app_webroot+"/admin", logged_as="bob") + def test_permission_legacy_app_propagation_on_ssowat(): # TODO / FIXME : To be actually implemented later .... diff --git a/src/yunohost/tests/test_user-group.py b/src/yunohost/tests/test_user-group.py index 30bdeb017..695f09477 100644 --- a/src/yunohost/tests/test_user-group.py +++ b/src/yunohost/tests/test_user-group.py @@ -1,22 +1,25 @@ import pytest +from conftest import message, raiseYunohostError + from yunohost.user import user_list, user_info, user_create, user_delete, user_update, \ - user_group_list, user_group_create, user_group_delete, user_group_update, user_group_info + user_group_list, user_group_create, user_group_delete, user_group_update from yunohost.domain import _get_maindomain -from yunohost.utils.error import YunohostError from yunohost.tests.test_permission import check_LDAP_db_integrity # Get main domain maindomain = _get_maindomain() + def clean_user_groups(): for u in user_list()['users']: user_delete(u) for g in user_group_list()['groups']: - if g != "all_users": + if g not in ["all_users", "visitors"]: user_group_delete(g) + def setup_function(function): clean_user_groups() @@ -29,9 +32,11 @@ def setup_function(function): user_group_update("dev", add=["alice"]) user_group_update("apps", add=["bob"]) + def teardown_function(function): clean_user_groups() + @pytest.fixture(autouse=True) def check_LDAP_db_integrity_call(): check_LDAP_db_integrity() @@ -42,6 +47,7 @@ def check_LDAP_db_integrity_call(): # List functions # + def test_list_users(): res = user_list()['users'] @@ -49,6 +55,7 @@ def test_list_users(): assert "bob" in res assert "jack" in res + def test_list_groups(): res = user_group_list()['groups'] @@ -65,8 +72,11 @@ def test_list_groups(): # Create - Remove functions # -def test_create_user(): - user_create("albert", "Albert", "Good", "alber@" + maindomain, "test123Ynh") + +def test_create_user(mocker): + + with message(mocker, "user_created"): + user_create("albert", "Albert", "Good", "alber@" + maindomain, "test123Ynh") group_res = user_group_list()['groups'] assert "albert" in user_list()['users'] @@ -74,24 +84,33 @@ def test_create_user(): assert "albert" in group_res['albert']['members'] assert "albert" in group_res['all_users']['members'] -def test_del_user(): - user_delete("alice") + +def test_del_user(mocker): + + with message(mocker, "user_deleted"): + user_delete("alice") group_res = user_group_list()['groups'] assert "alice" not in user_list() assert "alice" not in group_res assert "alice" not in group_res['all_users']['members'] -def test_create_group(): - user_group_create("adminsys") + +def test_create_group(mocker): + + with message(mocker, "group_created", group="adminsys"): + user_group_create("adminsys") group_res = user_group_list()['groups'] assert "adminsys" in group_res assert "members" in group_res['adminsys'].keys() assert group_res["adminsys"]["members"] == [] -def test_del_group(): - user_group_delete("dev") + +def test_del_group(mocker): + + with message(mocker, "group_deleted", group="dev"): + user_group_delete("dev") group_res = user_group_list()['groups'] assert "dev" not in group_res @@ -100,75 +119,94 @@ def test_del_group(): # Error on create / remove function # -def test_create_user_with_mail_address_already_taken(): - with pytest.raises(YunohostError): + +def test_create_user_with_mail_address_already_taken(mocker): + with raiseYunohostError(mocker, "user_creation_failed"): user_create("alice2", "Alice", "White", "alice@" + maindomain, "test123Ynh") -def test_create_user_with_password_too_simple(): - with pytest.raises(YunohostError): + +def test_create_user_with_password_too_simple(mocker): + with raiseYunohostError(mocker, "password_listed"): user_create("other", "Alice", "White", "other@" + maindomain, "12") -def test_create_user_already_exists(): - with pytest.raises(YunohostError): + +def test_create_user_already_exists(mocker): + with raiseYunohostError(mocker, "user_already_exists"): user_create("alice", "Alice", "White", "other@" + maindomain, "test123Ynh") -def test_update_user_with_mail_address_already_taken(): - with pytest.raises(YunohostError): - user_update("bob", add_mailalias="alice@" + maindomain) -def test_del_user_that_does_not_exist(): - with pytest.raises(YunohostError): +def test_update_user_with_mail_address_already_taken(mocker): + with raiseYunohostError(mocker, "user_update_failed"): + user_update("bob", add_mailalias="alice@" + maindomain) + + +def test_del_user_that_does_not_exist(mocker): + with raiseYunohostError(mocker, "user_unknown"): user_delete("doesnt_exist") -def test_create_group_all_users(): + +def test_create_group_all_users(mocker): # Check groups already exist with special group "all_users" - with pytest.raises(YunohostError): + with raiseYunohostError(mocker, "group_already_exist"): user_group_create("all_users") -def test_create_group_already_exists(): + +def test_create_group_already_exists(mocker): # Check groups already exist (regular groups) - with pytest.raises(YunohostError): + with raiseYunohostError(mocker, "group_already_exist"): user_group_create("dev") -def test_del_group_all_users(): - with pytest.raises(YunohostError): + +def test_del_group_all_users(mocker): + with raiseYunohostError(mocker, "group_cannot_be_deleted"): user_group_delete("all_users") -def test_del_group_that_does_not_exist(): - with pytest.raises(YunohostError): + +def test_del_group_that_does_not_exist(mocker): + with raiseYunohostError(mocker, "group_unknown"): user_group_delete("doesnt_exist") # # Update function # -def test_update_user(): - user_update("alice", firstname="NewName", lastname="NewLast") + +def test_update_user(mocker): + with message(mocker, "user_updated"): + user_update("alice", firstname="NewName", lastname="NewLast") info = user_info("alice") assert info['firstname'] == "NewName" assert info['lastname'] == "NewLast" -def test_update_group_add_user(): - user_group_update("dev", add=["bob"]) + +def test_update_group_add_user(mocker): + with message(mocker, "group_updated", group="dev"): + user_group_update("dev", add=["bob"]) group_res = user_group_list()['groups'] assert set(group_res['dev']['members']) == set(["alice", "bob"]) -def test_update_group_add_user_already_in(): - user_group_update("apps", add=["bob"]) + +def test_update_group_add_user_already_in(mocker): + with message(mocker, "group_user_already_in_group", user="bob", group="apps"): + user_group_update("apps", add=["bob"]) group_res = user_group_list()['groups'] assert group_res['apps']['members'] == ["bob"] -def test_update_group_remove_user(): - user_group_update("apps", remove=["bob"]) + +def test_update_group_remove_user(mocker): + with message(mocker, "group_updated", group="apps"): + user_group_update("apps", remove=["bob"]) group_res = user_group_list()['groups'] assert group_res['apps']['members'] == [] -def test_update_group_remove_user_not_already_in(): - user_group_update("apps", remove=["jack"]) + +def test_update_group_remove_user_not_already_in(mocker): + with message(mocker, "group_user_not_in_group", user="jack", group="apps"): + user_group_update("apps", remove=["jack"]) group_res = user_group_list()['groups'] assert group_res['apps']['members'] == ["bob"] @@ -177,29 +215,33 @@ def test_update_group_remove_user_not_already_in(): # Error on update functions # -def test_update_user_that_doesnt_exist(): - with pytest.raises(YunohostError): + +def test_update_user_that_doesnt_exist(mocker): + with raiseYunohostError(mocker, "user_unknown"): user_update("doesnt_exist", firstname="NewName", lastname="NewLast") -def test_update_group_that_doesnt_exist(): - # Check groups not found - with pytest.raises(YunohostError): + +def test_update_group_that_doesnt_exist(mocker): + with raiseYunohostError(mocker, "group_unknown"): user_group_update("doesnt_exist", add=["alice"]) -def test_update_group_all_users_manually(): - with pytest.raises(YunohostError): + +def test_update_group_all_users_manually(mocker): + with raiseYunohostError(mocker, "group_cannot_edit_all_users"): user_group_update("all_users", remove=["alice"]) assert "alice" in user_group_list()["groups"]["all_users"]["members"] -def test_update_group_primary_manually(): - with pytest.raises(YunohostError): + +def test_update_group_primary_manually(mocker): + with raiseYunohostError(mocker, "group_cannot_edit_primary_group"): user_group_update("alice", remove=["alice"]) + assert "alice" in user_group_list()["groups"]["alice"]["members"] -def test_update_group_add_user_that_doesnt_exist(): - # Check add bad user in group - with pytest.raises(YunohostError): + +def test_update_group_add_user_that_doesnt_exist(mocker): + with raiseYunohostError(mocker, "user_unknown"): user_group_update("dev", add=["doesnt_exist"]) assert "doesnt_exist" not in user_group_list()["groups"]["dev"]["members"] diff --git a/src/yunohost/utils/error.py b/src/yunohost/utils/error.py index aeffabcf0..75cf35093 100644 --- a/src/yunohost/utils/error.py +++ b/src/yunohost/utils/error.py @@ -27,12 +27,14 @@ class YunohostError(MoulinetteError): """ Yunohost base exception - + The (only?) main difference with MoulinetteError being that keys are translated via m18n.n (namespace) instead of m18n.g (global?) """ def __init__(self, key, raw_msg=False, *args, **kwargs): + self.key = key # Saving the key is useful for unit testing + self.kwargs = kwargs # Saving the key is useful for unit testing if raw_msg: msg = key else: From 50fbfb0372f4478cf373ea67b883cbaa1ba9c6c7 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 24 Sep 2019 23:18:05 +0200 Subject: [PATCH 018/127] Fucking ugly workaround for the goddamn dependency nighmare from sury djeezus kraiste --- data/helpers.d/apt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index b4bf60c1f..f5590b38d 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -218,6 +218,27 @@ ynh_install_app_dependencies () { fi local dep_app=${app//_/-} # Replace all '_' by '-' + # + # Epic ugly hack to fix the goddamn dependency nightmare of sury + # Sponsored by the "Djeezusse Fokin Kraiste Why Do Adminsys Has To Be So Fucking Complicated I Should Go Grow Potatoes Instead Of This Shit" collective + # https://github.com/YunoHost/issues/issues/1407 + # + # If we require to install php dependency + if echo $dependencies | grep -q 'php'; + then + # And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33+1 on debian) + if dpkg --list | grep php | grep -q "7.0.33-10" + then + # And sury ain't already installed + if ! grep -nrq "sury" /etc/apt/sources.list* + then + # Re-add sury + echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/sury.list + wget -O /etc/apt/trusted.gpg.d/sury.gpg https://packages.sury.org/php/apt.gpg + fi + fi + fi + cat > /tmp/${dep_app}-ynh-deps.control << EOF # Make a control file for equivs-build Section: misc Priority: optional From 35bfe97d50b1a6bb44f16ccddaf376723e304c57 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 25 Sep 2019 22:08:47 +0200 Subject: [PATCH 019/127] Copy pasta typo : all_users -> visitors Co-Authored-By: Josue-T --- src/yunohost/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/user.py b/src/yunohost/user.py index 581354f77..312b131b9 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -678,7 +678,7 @@ def user_group_update(operation_logger, groupname, add=None, remove=None, force= if not force: if groupname == "all_users": raise YunohostError('group_cannot_edit_all_users') - elif groupname == "all_users": + elif groupname == "visitors": raise YunohostError('group_cannot_edit_visitors') elif groupname in existing_users: raise YunohostError('group_cannot_edit_primary_group', group=groupname) From 24cc26d85a35ccd38c5af369e7bd9c739fca441c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 26 Sep 2019 14:23:01 +0200 Subject: [PATCH 020/127] Support logfiles not ending with .log in logrotate ... --- data/helpers.d/logrotate | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/data/helpers.d/logrotate b/data/helpers.d/logrotate index 47ce46cf6..82cdee6a5 100644 --- a/data/helpers.d/logrotate +++ b/data/helpers.d/logrotate @@ -40,10 +40,13 @@ ynh_use_logrotate () { fi if [ $# -gt 0 ] && [ "$(echo ${1:0:1})" != "-" ]; then - if [ "$(echo ${1##*.})" == "log" ]; then # Keep only the extension to check if it's a logfile - local logfile=$1 # In this case, focus logrotate on the logfile + # If the given logfile parameter already exists as a file, or if it ends up with ".log", + # we just want to manage a single file + if [ -f "$1" ] || [ "$(echo ${1##*.})" == "log" ]; then + local logfile=$1 + # Otherwise we assume we want to manage a directory and all its .log file inside else - local logfile=$1/*.log # Else, uses the directory and all logfile into it. + local logfile=$1/*.log fi fi # LEGACY CODE @@ -54,7 +57,7 @@ ynh_use_logrotate () { fi if [ -n "$logfile" ] then - if [ "$(echo ${logfile##*.})" != "log" ]; then # Keep only the extension to check if it's a logfile + if [ ! -f "$1" ] && [ "$(echo ${logfile##*.})" != "log" ]; then # Keep only the extension to check if it's a logfile local logfile="$logfile/*.log" # Else, uses the directory and all logfile into it. fi else From 274888c79fce9ee52a45a7a82db73fb118505a64 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 26 Sep 2019 16:19:43 +0200 Subject: [PATCH 021/127] Better handling of remove failure (and in particular, catch manual interrupts to still perform the rest of the cleaning) --- src/yunohost/app.py | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 5a51e57bb..05e1bdf4b 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -944,10 +944,21 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu env=env_dict_remove) operation_logger_remove.start() - remove_retcode = hook_exec( - os.path.join(extracted_app_folder, 'scripts/remove'), - args=[app_instance_name], env=env_dict_remove - )[0] + # Try to remove the app + try: + remove_retcode = hook_exec( + os.path.join(extracted_app_folder, 'scripts/remove'), + args=[app_instance_name], env=env_dict_remove + )[0] + # Here again, calling hook_exec could failed miserably, or get + # manually interrupted (by mistake or because script was stuck) + # In that case we still want to proceed with the rest of the + # removal (permissions, /etc/yunohost/apps/{app} ...) + except (KeyboardInterrupt, EOFError, Exception): + remove_retcode = -1 + import traceback + logger.exception(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())) + # Remove all permission in LDAP result = ldap.search(base='ou=permission,dc=yunohost,dc=org', filter='(&(objectclass=permissionYnh)(cn=*.%s))' % app_instance_name, attrs=['cn']) @@ -1057,11 +1068,24 @@ def app_remove(operation_logger, app): operation_logger.extra.update({'env': env_dict}) operation_logger.flush() - if hook_exec('/tmp/yunohost_remove/scripts/remove', args=args_list, - env=env_dict)[0] == 0: - logger.success(m18n.n('app_removed', app=app)) + try: + ret = hook_exec('/tmp/yunohost_remove/scripts/remove', + args=args_list, + env=env_dict)[0] + # Here again, calling hook_exec could failed miserably, or get + # manually interrupted (by mistake or because script was stuck) + # In that case we still want to proceed with the rest of the + # removal (permissions, /etc/yunohost/apps/{app} ...) + except (KeyboardInterrupt, EOFError, Exception): + ret = -1 + import traceback + logger.exception(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())) + if ret == 0: + logger.success(m18n.n('app_removed', app=app)) hook_callback('post_app_remove', args=args_list, env=env_dict) + else: + logger.warning(m18n.n('app_not_properly_removed', app=app)) if os.path.exists(app_setting_path): shutil.rmtree(app_setting_path) From 47bdfd8654548d1ddde537fa1d8cf1594a860265 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 26 Sep 2019 16:21:22 +0200 Subject: [PATCH 022/127] Clarify the handling of install script failures... --- locales/en.json | 1 + src/yunohost/app.py | 37 +++++++++++++++++++++++-------------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/locales/en.json b/locales/en.json index 61fdcfa9b..a182c7559 100644 --- a/locales/en.json +++ b/locales/en.json @@ -22,6 +22,7 @@ "app_id_invalid": "Invalid app ID", "app_incompatible": "The app {app} is incompatible with your YunoHost version", "app_install_files_invalid": "These files cannot be installed", + "app_install_failed": "Could not install {app}", "app_location_already_used": "The app '{app}' is already installed in ({path})", "app_make_default_location_already_used": "Can't make the app '{app}' the default on the domain, {domain} is already in use by the other app '{other_app}'", "app_location_install_failed": "Cannot install the app there because it conflicts with the app '{other_app}' already installed in '{other_path}'", diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 05e1bdf4b..af6c5d522 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -908,29 +908,42 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu permission_add(app=app_instance_name, permission="main", sync_perm=False) # Execute the app install script - install_retcode = 1 + install_failed = True try: install_retcode = hook_exec( os.path.join(extracted_app_folder, 'scripts/install'), args=args_list, env=env_dict )[0] + # "Common" app install failure : the script failed and returned exit code != 0 + install_failed = (install_retcode != 0) + if install_failed: + error = m18n.n('unexpected_error', error='shell command return code: %s' % install_retcode) + logger.exception(error) + operation_logger.error(error) + # Script got manually interrupted ... N.B. : KeyboardInterrupt does not inherit from Exception except (KeyboardInterrupt, EOFError): - install_retcode = -1 - except Exception: + error = m18n.n('operation_interrupted') + logger.exception(error) + operation_logger.error(error) + # Something wrong happened in Yunohost's code (most probably hook_exec) + except Exception as e : import traceback - logger.exception(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())) + error = m18n.n('unexpected_error', error=u"\n" + traceback.format_exc()) + logger.exception(error) + operation_logger.error(error) finally: + # Whatever happened (install success or failure) we check if it broke the system + # and warn the user about it try: broke_the_system = False _assert_system_is_sane_for_app(manifest, "post") except Exception as e: broke_the_system = True - error_msg = operation_logger.error(str(e)) + logger.exception(str(e)) + operation_logger.error(str(e)) - if install_retcode != 0: - error_msg = operation_logger.error(m18n.n('unexpected_error', error='shell command return code: %s' % install_retcode)) - - if install_retcode != 0 or broke_the_system: + # If the install failed or broke the system, we remove it + if install_failed or broke_the_system: if not no_remove_on_failure: # Setup environment for remove script env_dict_remove = {} @@ -985,11 +998,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu app_ssowatconf() - if install_retcode == -1: - msg = m18n.n('operation_interrupted') + " " + error_msg - raise YunohostError(msg, raw_msg=True) - msg = error_msg - raise YunohostError(msg, raw_msg=True) + raise YunohostError("app_install_failed", app=app_id) # Clean hooks and add new ones hook_remove(app_instance_name) From 9331f44b343ae192bd86ec5ccf87f855bee7ba16 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 26 Sep 2019 16:33:15 +0200 Subject: [PATCH 023/127] This message about shell command return code is too technical and uninformative. Let's explain what happen, which is that some error occured inside the install script (and details are in the debug log). --- locales/en.json | 1 + src/yunohost/app.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index a182c7559..ba0d7e3cd 100644 --- a/locales/en.json +++ b/locales/en.json @@ -23,6 +23,7 @@ "app_incompatible": "The app {app} is incompatible with your YunoHost version", "app_install_files_invalid": "These files cannot be installed", "app_install_failed": "Could not install {app}", + "app_install_script_failed": "An error occured inside the app installation script.", "app_location_already_used": "The app '{app}' is already installed in ({path})", "app_make_default_location_already_used": "Can't make the app '{app}' the default on the domain, {domain} is already in use by the other app '{other_app}'", "app_location_install_failed": "Cannot install the app there because it conflicts with the app '{other_app}' already installed in '{other_path}'", diff --git a/src/yunohost/app.py b/src/yunohost/app.py index af6c5d522..57df36713 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -917,7 +917,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu # "Common" app install failure : the script failed and returned exit code != 0 install_failed = (install_retcode != 0) if install_failed: - error = m18n.n('unexpected_error', error='shell command return code: %s' % install_retcode) + error = m18n.n('app_install_script_failed') logger.exception(error) operation_logger.error(error) # Script got manually interrupted ... N.B. : KeyboardInterrupt does not inherit from Exception From ccc49a2b2824d8aedfb642e4e9e273fa85431eac Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 26 Sep 2019 16:34:14 +0200 Subject: [PATCH 024/127] Simplify that indentation madness --- src/yunohost/app.py | 90 +++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 57df36713..f2eea5646 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -944,53 +944,57 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu # If the install failed or broke the system, we remove it if install_failed or broke_the_system: - if not no_remove_on_failure: - # Setup environment for remove script - env_dict_remove = {} - env_dict_remove["YNH_APP_ID"] = app_id - env_dict_remove["YNH_APP_INSTANCE_NAME"] = app_instance_name - env_dict_remove["YNH_APP_INSTANCE_NUMBER"] = str(instance_number) - # Execute remove script - operation_logger_remove = OperationLogger('remove_on_failed_install', - [('app', app_instance_name)], - env=env_dict_remove) - operation_logger_remove.start() + # This option is meant for packagers to debug their apps more easily + if no_remove_on_failure: + raise YunohostError("The installation of %s failed, but was not cleaned up as requested by --no-remove-on-failure." % app_id, raw_msg=True) - # Try to remove the app + # Setup environment for remove script + env_dict_remove = {} + env_dict_remove["YNH_APP_ID"] = app_id + env_dict_remove["YNH_APP_INSTANCE_NAME"] = app_instance_name + env_dict_remove["YNH_APP_INSTANCE_NUMBER"] = str(instance_number) + + # Execute remove script + operation_logger_remove = OperationLogger('remove_on_failed_install', + [('app', app_instance_name)], + env=env_dict_remove) + operation_logger_remove.start() + + # Try to remove the app + try: + remove_retcode = hook_exec( + os.path.join(extracted_app_folder, 'scripts/remove'), + args=[app_instance_name], env=env_dict_remove + )[0] + # Here again, calling hook_exec could failed miserably, or get + # manually interrupted (by mistake or because script was stuck) + # In that case we still want to proceed with the rest of the + # removal (permissions, /etc/yunohost/apps/{app} ...) + except (KeyboardInterrupt, EOFError, Exception): + remove_retcode = -1 + import traceback + logger.exception(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())) + + # Remove all permission in LDAP + result = ldap.search(base='ou=permission,dc=yunohost,dc=org', + filter='(&(objectclass=permissionYnh)(cn=*.%s))' % app_instance_name, attrs=['cn']) + permission_list = [p['cn'][0] for p in result] + for l in permission_list: + permission_remove(app_instance_name, l.split('.')[0], force=True) + + if remove_retcode != 0: + msg = m18n.n('app_not_properly_removed', + app=app_instance_name) + logger.warning(msg) + operation_logger_remove.error(msg) + else: try: - remove_retcode = hook_exec( - os.path.join(extracted_app_folder, 'scripts/remove'), - args=[app_instance_name], env=env_dict_remove - )[0] - # Here again, calling hook_exec could failed miserably, or get - # manually interrupted (by mistake or because script was stuck) - # In that case we still want to proceed with the rest of the - # removal (permissions, /etc/yunohost/apps/{app} ...) - except (KeyboardInterrupt, EOFError, Exception): - remove_retcode = -1 - import traceback - logger.exception(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())) - - # Remove all permission in LDAP - result = ldap.search(base='ou=permission,dc=yunohost,dc=org', - filter='(&(objectclass=permissionYnh)(cn=*.%s))' % app_instance_name, attrs=['cn']) - permission_list = [p['cn'][0] for p in result] - for l in permission_list: - permission_remove(app_instance_name, l.split('.')[0], force=True) - - if remove_retcode != 0: - msg = m18n.n('app_not_properly_removed', - app=app_instance_name) - logger.warning(msg) - operation_logger_remove.error(msg) + _assert_system_is_sane_for_app(manifest, "post") + except Exception as e: + operation_logger_remove.error(e) else: - try: - _assert_system_is_sane_for_app(manifest, "post") - except Exception as e: - operation_logger_remove.error(e) - else: - operation_logger_remove.success() + operation_logger_remove.success() # Clean tmp folders shutil.rmtree(app_setting_path) From d159f7ff07d20734d50594cf1e8eacde7f77f1ad Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 28 Sep 2019 16:11:44 +0200 Subject: [PATCH 025/127] Misc typo / wording / readability Co-Authored-By: decentral1se --- locales/en.json | 2 +- src/yunohost/app.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/locales/en.json b/locales/en.json index ba0d7e3cd..f9194bb42 100644 --- a/locales/en.json +++ b/locales/en.json @@ -23,7 +23,7 @@ "app_incompatible": "The app {app} is incompatible with your YunoHost version", "app_install_files_invalid": "These files cannot be installed", "app_install_failed": "Could not install {app}", - "app_install_script_failed": "An error occured inside the app installation script.", + "app_install_script_failed": "An error occured inside the app installation script", "app_location_already_used": "The app '{app}' is already installed in ({path})", "app_make_default_location_already_used": "Can't make the app '{app}' the default on the domain, {domain} is already in use by the other app '{other_app}'", "app_location_install_failed": "Cannot install the app there because it conflicts with the app '{other_app}' already installed in '{other_path}'", diff --git a/src/yunohost/app.py b/src/yunohost/app.py index f2eea5646..8c7d37f92 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -915,7 +915,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu args=args_list, env=env_dict )[0] # "Common" app install failure : the script failed and returned exit code != 0 - install_failed = (install_retcode != 0) + install_failed = True if install_retcode != 0 else False if install_failed: error = m18n.n('app_install_script_failed') logger.exception(error) @@ -967,7 +967,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu os.path.join(extracted_app_folder, 'scripts/remove'), args=[app_instance_name], env=env_dict_remove )[0] - # Here again, calling hook_exec could failed miserably, or get + # Here again, calling hook_exec could fail miserably, or get # manually interrupted (by mistake or because script was stuck) # In that case we still want to proceed with the rest of the # removal (permissions, /etc/yunohost/apps/{app} ...) @@ -1085,7 +1085,7 @@ def app_remove(operation_logger, app): ret = hook_exec('/tmp/yunohost_remove/scripts/remove', args=args_list, env=env_dict)[0] - # Here again, calling hook_exec could failed miserably, or get + # Here again, calling hook_exec could fail miserably, or get # manually interrupted (by mistake or because script was stuck) # In that case we still want to proceed with the rest of the # removal (permissions, /etc/yunohost/apps/{app} ...) From f93e2b307904d1ac5c6dd86c4bf52cc22fda48d2 Mon Sep 17 00:00:00 2001 From: Julien Jershon Date: Sat, 5 Oct 2019 09:55:03 +0200 Subject: [PATCH 026/127] Better error message for invalid email domain. Fix https://github.com/YunoHost/issues/issues/1365. --- locales/en.json | 2 +- locales/fr.json | 2 +- locales/pt.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/locales/en.json b/locales/en.json index 98cbf22e9..2069ee6a6 100644 --- a/locales/en.json +++ b/locales/en.json @@ -286,7 +286,7 @@ "ldap_initialized": "LDAP initialized", "license_undefined": "undefined", "mail_alias_remove_failed": "Could not remove e-mail alias '{mail:s}'", - "mail_domain_unknown": "Unknown e-mail address for domain '{domain:s}'", + "mail_domain_unknown": "Invalid e-mail address for domain '{domain:s}'. Please, use a domain administrated by this server.", "mail_forward_remove_failed": "Could not remove e-mail forwarding '{mail:s}'", "mailbox_disabled": "E-mail turned off for user {user:s}", "mailbox_used_space_dovecot_down": "The Dovecot mailbox service needs to be up, if you want to fetch used mailbox space", diff --git a/locales/fr.json b/locales/fr.json index 8bffec8b2..7a2d299f8 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -120,7 +120,7 @@ "ldap_initialized": "L’annuaire LDAP initialisé", "license_undefined": "indéfinie", "mail_alias_remove_failed": "Impossible de supprimer l’alias de courriel '{mail:s}'", - "mail_domain_unknown": "Le domaine '{domain:s}' pour l'adresse de courriel est inconnu", + "mail_domain_unknown": "Le domaine '{domain:s}' de cette adress de courriel n'est pas valide. Merci d'utiliser un domain administré par ce serveur.", "mail_forward_remove_failed": "Impossible de supprimer le courriel de transfert '{mail:s}'", "maindomain_change_failed": "Impossible de modifier le domaine principal", "maindomain_changed": "Le domaine principal modifié", diff --git a/locales/pt.json b/locales/pt.json index 80a0d5ddd..b8c9d2eb3 100644 --- a/locales/pt.json +++ b/locales/pt.json @@ -72,7 +72,7 @@ "ldap_initialized": "LDAP inicializada com êxito", "license_undefined": "indefinido", "mail_alias_remove_failed": "Não foi possível remover a etiqueta de correio '{mail:s}'", - "mail_domain_unknown": "Domínio de endereço de correio desconhecido '{domain:s}'", + "mail_domain_unknown": "Domínio de endereço de correio '{domain:s}' inválido. Por favor, usa um domínio administrado per esse servidor.", "mail_forward_remove_failed": "Não foi possível remover o reencaminhamento de correio '{mail:s}'", "maindomain_change_failed": "Incapaz alterar o domínio raiz", "maindomain_changed": "Domínio raiz alterado com êxito", From a1822e2f42aa1a7ff516ff76ea5dee1def233a20 Mon Sep 17 00:00:00 2001 From: Luke Murphy Date: Sun, 6 Oct 2019 11:25:01 +0200 Subject: [PATCH 027/127] Use str instead of strerror (not present) See https://forum.yunohost.org/t/cant-create-a-user-after-post-intsallation/9190. --- src/yunohost/user.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yunohost/user.py b/src/yunohost/user.py index c6413d7e1..fe27492f4 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -199,7 +199,7 @@ def user_create(operation_logger, username, firstname, lastname, mail, password, with open('/etc/ssowat/conf.json.persistent') as json_conf: ssowat_conf = json.loads(str(json_conf.read())) except ValueError as e: - raise YunohostError('ssowat_persistent_conf_read_error', error=e.strerror) + raise YunohostError('ssowat_persistent_conf_read_error', error=str(e)) except IOError: ssowat_conf = {} @@ -209,7 +209,7 @@ def user_create(operation_logger, username, firstname, lastname, mail, password, with open('/etc/ssowat/conf.json.persistent', 'w+') as f: json.dump(ssowat_conf, f, sort_keys=True, indent=4) except IOError as e: - raise YunohostError('ssowat_persistent_conf_write_error', error=e.strerror) + raise YunohostError('ssowat_persistent_conf_write_error', error=str(e)) try: ldap.add('uid=%s,ou=users' % username, attr_dict) From 2642b64af5bccb6f93a8612a42365edd68e9b118 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 16 Sep 2019 23:17:46 +0200 Subject: [PATCH 028/127] Detect and warn early about unavailable full domain requirement... --- locales/en.json | 1 + src/yunohost/app.py | 37 +++++++++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/locales/en.json b/locales/en.json index 61fdcfa9b..4e9675cac 100644 --- a/locales/en.json +++ b/locales/en.json @@ -19,6 +19,7 @@ "app_change_url_no_script": "This application '{app_name:s}' doesn't support URL modification yet. Maybe you should upgrade it.", "app_change_url_success": "{app:s} URL is now {domain:s}{path:s}", "app_extraction_failed": "Could not extract the installation files", + "app_full_domain_unavailable": "Sorry, this application requires a full domain to be installed on, but some other apps are already installed on {domain}. One possible solution is to add a subdomain dedicated to this application.", "app_id_invalid": "Invalid app ID", "app_incompatible": "The app {app} is incompatible with your YunoHost version", "app_install_files_invalid": "These files cannot be installed", diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 5a51e57bb..6f5c1dabe 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -847,6 +847,9 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu args_list = [ value[0] for value in args_odict.values() ] args_list.append(app_instance_name) + # Validate domain / path availability for webapps + _validate_and_normalize_webpath(manifest, args_odict, extracted_app_folder) + # Prepare env. var. to pass to script env_dict = _make_environment_dict(args_odict) env_dict["YNH_APP_ID"] = app_id @@ -2547,8 +2550,7 @@ def _parse_args_for_action(action, args={}): def _parse_args_in_yunohost_format(args, action_args): """Parse arguments store in either manifest.json or actions.json """ - from yunohost.domain import (domain_list, _get_maindomain, - _get_conflicting_apps, _normalize_domain_path) + from yunohost.domain import domain_list, _get_maindomain from yunohost.user import user_info, user_list args_dict = OrderedDict() @@ -2666,13 +2668,18 @@ def _parse_args_in_yunohost_format(args, action_args): assert_password_is_strong_enough('user', arg_value) args_dict[arg_name] = (arg_value, arg_type) - # END loop over action_args... + return args_dict + + +def _validate_and_normalize_webpath(manifest, args_dict, app_folder): + + from yunohost.domain import _get_conflicting_apps, _normalize_domain_path # If there's only one "domain" and "path", validate that domain/path # is an available url and normalize the path. - domain_args = [ (name, value[0]) for name, value in args_dict.items() if value[1] == "domain" ] - path_args = [ (name, value[0]) for name, value in args_dict.items() if value[1] == "path" ] + domain_args = [(name, value[0]) for name, value in args_dict.items() if value[1] == "domain"] + path_args = [(name, value[0]) for name, value in args_dict.items() if value[1] == "path"] if len(domain_args) == 1 and len(path_args) == 1: @@ -2698,7 +2705,25 @@ def _parse_args_in_yunohost_format(args, action_args): # standard path format to deal with no matter what the user inputted) args_dict[path_args[0][0]] = (path, "path") - return args_dict + # This is likely to be a full-domain app... + elif len(domain_args) == 1 and len(path_args) == 0: + + # 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 = open(os.path.join(app_folder, 'scripts/install')).read() + if re.search(r"\npath(_url)?=[\"']?/[\"']?\n", install_script_content) \ + and re.search(r"(ynh_webpath_register|yunohost app checkurl)"): + + domain = domain_args[0][1] + conflicts = _get_conflicting_apps(domain, "/") + + raise YunohostError('app_full_domain_unavailable', domain) def _make_environment_dict(args_dict, prefix="APP_ARG_"): From 0d90133bb7a0181621824477a855f01256885ae6 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 8 Oct 2019 18:18:27 +0200 Subject: [PATCH 029/127] Improve message --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 4e9675cac..1be7d1151 100644 --- a/locales/en.json +++ b/locales/en.json @@ -19,7 +19,7 @@ "app_change_url_no_script": "This application '{app_name:s}' doesn't support URL modification yet. Maybe you should upgrade it.", "app_change_url_success": "{app:s} URL is now {domain:s}{path:s}", "app_extraction_failed": "Could not extract the installation files", - "app_full_domain_unavailable": "Sorry, this application requires a full domain to be installed on, but some other apps are already installed on {domain}. One possible solution is to add a subdomain dedicated to this application.", + "app_full_domain_unavailable": "Sorry, this application requires a full domain to be installed on, but some other apps are already installed on domain '{domain}'. One possible solution is to add and use a subdomain dedicated to this application instead.", "app_id_invalid": "Invalid app ID", "app_incompatible": "The app {app} is incompatible with your YunoHost version", "app_install_files_invalid": "These files cannot be installed", From 342fe2d4be0a1300dddf0e747906cb4e16b9b091 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 8 Oct 2019 18:19:50 +0200 Subject: [PATCH 030/127] Add unit test for full-domain apps --- src/yunohost/tests/test_apps.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/yunohost/tests/test_apps.py b/src/yunohost/tests/test_apps.py index 9c85df1e9..fc44ef105 100644 --- a/src/yunohost/tests/test_apps.py +++ b/src/yunohost/tests/test_apps.py @@ -36,16 +36,22 @@ def clean(): if _is_installed("legacy_app"): app_remove("legacy_app") + if _is_installed("full_domain_app"): + app_remove("full_domain_app") + to_remove = [] to_remove += glob.glob("/etc/nginx/conf.d/*.d/*legacy*") + to_remove += glob.glob("/etc/nginx/conf.d/*.d/*full_domain*") to_remove += glob.glob("/etc/nginx/conf.d/*.d/*break_yo_system*") for filepath in to_remove: os.remove(filepath) to_remove = [] to_remove += glob.glob("/etc/yunohost/apps/*legacy_app*") + to_remove += glob.glob("/etc/yunohost/apps/*full_domain_app*") to_remove += glob.glob("/etc/yunohost/apps/*break_yo_system*") to_remove += glob.glob("/var/www/*legacy*") + to_remove += glob.glob("/var/www/*full_domain*") for folderpath in to_remove: shutil.rmtree(folderpath, ignore_errors=True) @@ -120,6 +126,13 @@ def install_legacy_app(domain, path): force=True) +def install_full_domain_app(domain): + + app_install("./tests/apps/full_domain_app_ynh", + args="domain=%s" % domain, + force=True) + + def install_break_yo_system(domain, breakwhat): app_install("./tests/apps/break_yo_system_ynh", @@ -272,6 +285,22 @@ def test_legacy_app_failed_remove(secondary_domain): assert app_is_not_installed(secondary_domain, "legacy") +def test_full_domain_app(secondary_domain): + + install_full_domain_app(secondary_domain) + + assert app_is_exposed_on_http(secondary_domain, "/", "This is a dummy app") + + +def test_full_domain_app_with_conflicts(secondary_domain): + + install_legacy_app(secondary_domain, "/legacy") + + # TODO : once #808 is merged, add test that the message raised is 'app_full_domain_unavailable' + with pytest.raises(YunohostError): + install_full_domain_app(secondary_domain) + + def test_systemfuckedup_during_app_install(secondary_domain): with pytest.raises(YunohostError): From c70418c4b25952f9308b69d88e47b8a2490781c1 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 8 Oct 2019 18:21:04 +0200 Subject: [PATCH 031/127] Fixes following tests --- src/yunohost/app.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 6f5c1dabe..8596f7297 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2717,13 +2717,14 @@ def _validate_and_normalize_webpath(manifest, args_dict, app_folder): # 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 = open(os.path.join(app_folder, 'scripts/install')).read() + if re.search(r"\npath(_url)?=[\"']?/[\"']?\n", install_script_content) \ - and re.search(r"(ynh_webpath_register|yunohost app checkurl)"): + and re.search(r"(ynh_webpath_register|yunohost app checkurl)", install_script_content): domain = domain_args[0][1] conflicts = _get_conflicting_apps(domain, "/") - raise YunohostError('app_full_domain_unavailable', domain) + raise YunohostError('app_full_domain_unavailable', domain=domain) def _make_environment_dict(args_dict, prefix="APP_ARG_"): From fc787009041069f7ffd83b1d7f8467a8d98e1c44 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 8 Oct 2019 18:30:18 +0200 Subject: [PATCH 032/127] More accurate greps to identify that sury packages are installed --- data/helpers.d/apt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index f5590b38d..d84520daf 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -226,8 +226,8 @@ ynh_install_app_dependencies () { # If we require to install php dependency if echo $dependencies | grep -q 'php'; then - # And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33+1 on debian) - if dpkg --list | grep php | grep -q "7.0.33-10" + # And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33-0 on debian) + if dpkg --list | grep "php7.0" | grep -q -v "7.0.33-0+deb9u5" then # And sury ain't already installed if ! grep -nrq "sury" /etc/apt/sources.list* From 077e5c463c8c4d6befc28d9c0c79bdc21ed2b3cb Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 24 Sep 2019 23:18:05 +0200 Subject: [PATCH 033/127] Fucking ugly workaround for the goddamn dependency nighmare from sury djeezus kraiste --- data/helpers.d/apt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index 9d5ad3ac2..fed585d95 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -218,6 +218,27 @@ ynh_install_app_dependencies () { fi local dep_app=${app//_/-} # Replace all '_' by '-' + # + # Epic ugly hack to fix the goddamn dependency nightmare of sury + # Sponsored by the "Djeezusse Fokin Kraiste Why Do Adminsys Has To Be So Fucking Complicated I Should Go Grow Potatoes Instead Of This Shit" collective + # https://github.com/YunoHost/issues/issues/1407 + # + # If we require to install php dependency + if echo $dependencies | grep -q 'php'; + then + # And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33+1 on debian) + if dpkg --list | grep php | grep -q "7.0.33-10" + then + # And sury ain't already installed + if ! grep -nrq "sury" /etc/apt/sources.list* + then + # Re-add sury + echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/sury.list + wget -O /etc/apt/trusted.gpg.d/sury.gpg https://packages.sury.org/php/apt.gpg + fi + fi + fi + cat > /tmp/${dep_app}-ynh-deps.control << EOF # Make a control file for equivs-build Section: misc Priority: optional From 0e3a131095afe4893d10629271c1ce6c6b177624 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 8 Oct 2019 18:30:18 +0200 Subject: [PATCH 034/127] More accurate greps to identify that sury packages are installed --- data/helpers.d/apt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index fed585d95..d772c6855 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -226,8 +226,8 @@ ynh_install_app_dependencies () { # If we require to install php dependency if echo $dependencies | grep -q 'php'; then - # And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33+1 on debian) - if dpkg --list | grep php | grep -q "7.0.33-10" + # And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33-0 on debian) + if dpkg --list | grep "php7.0" | grep -q -v "7.0.33-0+deb9u5" then # And sury ain't already installed if ! grep -nrq "sury" /etc/apt/sources.list* From 1c5220f7cbe029b4cf03011cb451426d755697f8 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 26 Sep 2019 14:23:01 +0200 Subject: [PATCH 035/127] Support logfiles not ending with .log in logrotate ... --- data/helpers.d/logrotate | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/data/helpers.d/logrotate b/data/helpers.d/logrotate index 47ce46cf6..82cdee6a5 100644 --- a/data/helpers.d/logrotate +++ b/data/helpers.d/logrotate @@ -40,10 +40,13 @@ ynh_use_logrotate () { fi if [ $# -gt 0 ] && [ "$(echo ${1:0:1})" != "-" ]; then - if [ "$(echo ${1##*.})" == "log" ]; then # Keep only the extension to check if it's a logfile - local logfile=$1 # In this case, focus logrotate on the logfile + # If the given logfile parameter already exists as a file, or if it ends up with ".log", + # we just want to manage a single file + if [ -f "$1" ] || [ "$(echo ${1##*.})" == "log" ]; then + local logfile=$1 + # Otherwise we assume we want to manage a directory and all its .log file inside else - local logfile=$1/*.log # Else, uses the directory and all logfile into it. + local logfile=$1/*.log fi fi # LEGACY CODE @@ -54,7 +57,7 @@ ynh_use_logrotate () { fi if [ -n "$logfile" ] then - if [ "$(echo ${logfile##*.})" != "log" ]; then # Keep only the extension to check if it's a logfile + if [ ! -f "$1" ] && [ "$(echo ${logfile##*.})" != "log" ]; then # Keep only the extension to check if it's a logfile local logfile="$logfile/*.log" # Else, uses the directory and all logfile into it. fi else From 5623689a2728a875880dd41b614fffd818a0597d Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 16 Sep 2019 23:17:46 +0200 Subject: [PATCH 036/127] Detect and warn early about unavailable full domain requirement... --- locales/en.json | 1 + src/yunohost/app.py | 37 +++++++++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/locales/en.json b/locales/en.json index d1203c757..55735d760 100644 --- a/locales/en.json +++ b/locales/en.json @@ -19,6 +19,7 @@ "app_change_url_no_script": "This application '{app_name:s}' doesn't support url modification yet. Maybe you should upgrade the application.", "app_change_url_success": "Successfully changed {app:s} url to {domain:s}{path:s}", "app_extraction_failed": "Unable to extract installation files", + "app_full_domain_unavailable": "Sorry, this application requires a full domain to be installed on, but some other apps are already installed on {domain}. One possible solution is to add a subdomain dedicated to this application.", "app_id_invalid": "Invalid app id", "app_incompatible": "The app {app} is incompatible with your YunoHost version", "app_install_files_invalid": "Invalid installation files", diff --git a/src/yunohost/app.py b/src/yunohost/app.py index d9a349579..c982c3418 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -802,6 +802,9 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu args_list = [ value[0] for value in args_odict.values() ] args_list.append(app_instance_name) + # Validate domain / path availability for webapps + _validate_and_normalize_webpath(manifest, args_odict, extracted_app_folder) + # Prepare env. var. to pass to script env_dict = _make_environment_dict(args_odict) env_dict["YNH_APP_ID"] = app_id @@ -2394,8 +2397,7 @@ def _parse_args_for_action(action, args={}): def _parse_args_in_yunohost_format(args, action_args): """Parse arguments store in either manifest.json or actions.json """ - from yunohost.domain import (domain_list, _get_maindomain, - _get_conflicting_apps, _normalize_domain_path) + from yunohost.domain import domain_list, _get_maindomain from yunohost.user import user_info, user_list args_dict = OrderedDict() @@ -2513,13 +2515,18 @@ def _parse_args_in_yunohost_format(args, action_args): assert_password_is_strong_enough('user', arg_value) args_dict[arg_name] = (arg_value, arg_type) - # END loop over action_args... + return args_dict + + +def _validate_and_normalize_webpath(manifest, args_dict, app_folder): + + from yunohost.domain import _get_conflicting_apps, _normalize_domain_path # If there's only one "domain" and "path", validate that domain/path # is an available url and normalize the path. - domain_args = [ (name, value[0]) for name, value in args_dict.items() if value[1] == "domain" ] - path_args = [ (name, value[0]) for name, value in args_dict.items() if value[1] == "path" ] + domain_args = [(name, value[0]) for name, value in args_dict.items() if value[1] == "domain"] + path_args = [(name, value[0]) for name, value in args_dict.items() if value[1] == "path"] if len(domain_args) == 1 and len(path_args) == 1: @@ -2545,7 +2552,25 @@ def _parse_args_in_yunohost_format(args, action_args): # standard path format to deal with no matter what the user inputted) args_dict[path_args[0][0]] = (path, "path") - return args_dict + # This is likely to be a full-domain app... + elif len(domain_args) == 1 and len(path_args) == 0: + + # 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 = open(os.path.join(app_folder, 'scripts/install')).read() + if re.search(r"\npath(_url)?=[\"']?/[\"']?\n", install_script_content) \ + and re.search(r"(ynh_webpath_register|yunohost app checkurl)"): + + domain = domain_args[0][1] + conflicts = _get_conflicting_apps(domain, "/") + + raise YunohostError('app_full_domain_unavailable', domain) def _make_environment_dict(args_dict, prefix="APP_ARG_"): From 75742216ea93e45c6679310fa9a02724775dd838 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 8 Oct 2019 18:18:27 +0200 Subject: [PATCH 037/127] Improve message --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 55735d760..4bb049db3 100644 --- a/locales/en.json +++ b/locales/en.json @@ -19,7 +19,7 @@ "app_change_url_no_script": "This application '{app_name:s}' doesn't support url modification yet. Maybe you should upgrade the application.", "app_change_url_success": "Successfully changed {app:s} url to {domain:s}{path:s}", "app_extraction_failed": "Unable to extract installation files", - "app_full_domain_unavailable": "Sorry, this application requires a full domain to be installed on, but some other apps are already installed on {domain}. One possible solution is to add a subdomain dedicated to this application.", + "app_full_domain_unavailable": "Sorry, this application requires a full domain to be installed on, but some other apps are already installed on domain '{domain}'. One possible solution is to add and use a subdomain dedicated to this application instead.", "app_id_invalid": "Invalid app id", "app_incompatible": "The app {app} is incompatible with your YunoHost version", "app_install_files_invalid": "Invalid installation files", From 7ecefaf8dc78cc0d4ddb1f0fabc5eab6ff2bb176 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 8 Oct 2019 18:21:04 +0200 Subject: [PATCH 038/127] Fixes following tests --- src/yunohost/app.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index c982c3418..421be9b60 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2564,13 +2564,14 @@ def _validate_and_normalize_webpath(manifest, args_dict, app_folder): # 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 = open(os.path.join(app_folder, 'scripts/install')).read() + if re.search(r"\npath(_url)?=[\"']?/[\"']?\n", install_script_content) \ - and re.search(r"(ynh_webpath_register|yunohost app checkurl)"): + and re.search(r"(ynh_webpath_register|yunohost app checkurl)", install_script_content): domain = domain_args[0][1] conflicts = _get_conflicting_apps(domain, "/") - raise YunohostError('app_full_domain_unavailable', domain) + raise YunohostError('app_full_domain_unavailable', domain=domain) def _make_environment_dict(args_dict, prefix="APP_ARG_"): From bf1ad164dafc996c0bf9d1a3b19de7dc2d089003 Mon Sep 17 00:00:00 2001 From: "J. Doe" Date: Thu, 19 Sep 2019 13:01:22 +0200 Subject: [PATCH 039/127] change maxretry of fail2ban from 6 to 10 --- data/templates/fail2ban/yunohost-jails.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/templates/fail2ban/yunohost-jails.conf b/data/templates/fail2ban/yunohost-jails.conf index bf3bcb6e3..fdbd7990b 100644 --- a/data/templates/fail2ban/yunohost-jails.conf +++ b/data/templates/fail2ban/yunohost-jails.conf @@ -29,4 +29,4 @@ protocol = tcp filter = yunohost logpath = /var/log/nginx/*error.log /var/log/nginx/*access.log -maxretry = 6 +maxretry = 10 From 115513c6503de63a7f970d1f2dae216839b7f46d Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 8 Oct 2019 19:03:32 +0200 Subject: [PATCH 040/127] Update changelog for 3.6.5 --- debian/changelog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/debian/changelog b/debian/changelog index 3eb347456..4b8c26471 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +yunohost (3.6.5) stable; urgency=low + + - [enh] Detect and warn early about unavailable full domains... (#798) + - [mod] Change maxretry of fail2ban from 6 to 10 (#802) + - [fix] Epicly ugly workaround for the goddamn dependency nighmare about sury fucking up php7.0 dependencies (#809) + - [fix] Support logfiles not ending with .log in logrotate ... (#810) + + -- Alexandre Aubin Mon, 08 Oct 2019 19:00:00 +0000 + yunohost (3.6.4.6) stable; urgency=low - [fix] Hopefully fix the issue about corrupted logs metadata files (d507d447, 1cec9d78) From fe8fd1b2c58993211e016fecb74d6fc026482bd1 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 8 Oct 2019 20:04:08 +0200 Subject: [PATCH 041/127] Change from #802 was only about the yunohost jail ... this should be global >.> --- data/templates/fail2ban/jail.conf | 2 +- data/templates/fail2ban/yunohost-jails.conf | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/data/templates/fail2ban/jail.conf b/data/templates/fail2ban/jail.conf index 9b4d39f17..bd522c4ba 100644 --- a/data/templates/fail2ban/jail.conf +++ b/data/templates/fail2ban/jail.conf @@ -63,7 +63,7 @@ bantime = 600 findtime = 600 # "maxretry" is the number of failures before a host get banned. -maxretry = 5 +maxretry = 10 # "backend" specifies the backend used to get files modification. # Available options are "pyinotify", "gamin", "polling", "systemd" and "auto". diff --git a/data/templates/fail2ban/yunohost-jails.conf b/data/templates/fail2ban/yunohost-jails.conf index fdbd7990b..e1e464b1a 100644 --- a/data/templates/fail2ban/yunohost-jails.conf +++ b/data/templates/fail2ban/yunohost-jails.conf @@ -29,4 +29,3 @@ protocol = tcp filter = yunohost logpath = /var/log/nginx/*error.log /var/log/nginx/*access.log -maxretry = 10 From 826429cf0b5c8dc72cb2c3898c42cf0f20971cb4 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 8 Oct 2019 20:04:08 +0200 Subject: [PATCH 042/127] Change from #802 was only about the yunohost jail ... this should be global >.> --- data/templates/fail2ban/jail.conf | 2 +- data/templates/fail2ban/yunohost-jails.conf | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/data/templates/fail2ban/jail.conf b/data/templates/fail2ban/jail.conf index 9b4d39f17..bd522c4ba 100644 --- a/data/templates/fail2ban/jail.conf +++ b/data/templates/fail2ban/jail.conf @@ -63,7 +63,7 @@ bantime = 600 findtime = 600 # "maxretry" is the number of failures before a host get banned. -maxretry = 5 +maxretry = 10 # "backend" specifies the backend used to get files modification. # Available options are "pyinotify", "gamin", "polling", "systemd" and "auto". diff --git a/data/templates/fail2ban/yunohost-jails.conf b/data/templates/fail2ban/yunohost-jails.conf index fdbd7990b..e1e464b1a 100644 --- a/data/templates/fail2ban/yunohost-jails.conf +++ b/data/templates/fail2ban/yunohost-jails.conf @@ -29,4 +29,3 @@ protocol = tcp filter = yunohost logpath = /var/log/nginx/*error.log /var/log/nginx/*access.log -maxretry = 10 From c45b0edd39e47d66201c9b9223923abfd93f3a58 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 8 Oct 2019 20:21:11 +0200 Subject: [PATCH 043/127] Update changelog for 3.6.5.1 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 4b8c26471..6d5a16f2c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +yunohost (3.6.5.1) stable; urgency=low + + - [mod] Change maxretry of fail2ban from 6 to 10 (fe8fd1b) + + -- Alexandre Aubin Mon, 08 Oct 2019 20:00:00 +0000 + yunohost (3.6.5) stable; urgency=low - [enh] Detect and warn early about unavailable full domains... (#798) From 4a14cbd6e0bc092c7bf3ed94f994d9330dc1c1a0 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 9 Oct 2019 18:42:17 +0200 Subject: [PATCH 044/127] Fix / implement remaining test --- src/yunohost/tests/test_permission.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/yunohost/tests/test_permission.py b/src/yunohost/tests/test_permission.py index f17313fa1..a9e16cfc6 100644 --- a/src/yunohost/tests/test_permission.py +++ b/src/yunohost/tests/test_permission.py @@ -41,6 +41,10 @@ def teardown_function(function): app_remove("permissions_app") except: pass + try: + app_remove("legacy_app") + except: + pass @pytest.fixture(autouse=True) def check_LDAP_db_integrity_call(): @@ -443,23 +447,22 @@ def test_permission_app_propagation_on_ssowat(): def test_permission_legacy_app_propagation_on_ssowat(): - # TODO / FIXME : To be actually implemented later .... - raise NotImplementedError - app_install("./tests/apps/legacy_app_ynh", args="domain=%s&path=%s" % (maindomain, "/legacy"), force=True) # App is configured as public by default using the legacy unprotected_uri mechanics # It should automatically be migrated during the install - assert res['permissions_app.main']['allowed'] == ["visitors"] + res = user_permission_list(full=True)['permissions'] + assert res['legacy_app.main']['allowed'] == ["visitors"] - assert can_access_webpage(maindomain + "/legacy", logged_as=None) - assert can_access_webpage(maindomain + "/legacy", logged_as="alice") + app_webroot = "https://%s/legacy" % maindomain + + assert can_access_webpage(app_webroot, logged_as=None) + assert can_access_webpage(app_webroot, logged_as="alice") # Try to update the permission and check that permissions are still consistent user_permission_update("legacy_app.main", remove="visitors", add="bob") - res = user_permission_list(full=True)['permissions'] - assert not can_access_webpage(maindomain + "/legacy", logged_as=None) - assert not can_access_webpage(maindomain + "/legacy", logged_as="alice") - assert can_access_webpage(maindomain + "/legacy", logged_as="bob") + assert not can_access_webpage(app_webroot, logged_as=None) + assert not can_access_webpage(app_webroot, logged_as="alice") + assert can_access_webpage(app_webroot, logged_as="bob") From df49af0ad001b99086083798a2b6e888c9352a80 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 9 Oct 2019 18:55:11 +0200 Subject: [PATCH 045/127] Redundant operation considering we're deleting all groups right after --- src/yunohost/data_migrations/0011_setup_group_permission.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/yunohost/data_migrations/0011_setup_group_permission.py b/src/yunohost/data_migrations/0011_setup_group_permission.py index dd5b3c274..ae5a8bfb9 100644 --- a/src/yunohost/data_migrations/0011_setup_group_permission.py +++ b/src/yunohost/data_migrations/0011_setup_group_permission.py @@ -60,7 +60,6 @@ class MyMigration(Migration): ldap_map = read_yaml('/usr/share/yunohost/yunohost-config/moulinette/ldap_scheme.yml') try: - self.remove_if_exists("cn=sftpusers,ou=groups") self.remove_if_exists("ou=permission") self.remove_if_exists('ou=groups') From 96bc95656c6ad29fa59ae337a0f9f4f04c097261 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 9 Oct 2019 19:22:31 +0200 Subject: [PATCH 046/127] Allow the migration to proceed if slapd config was manually modified, warn the user about where the conf will be backuped --- locales/en.json | 2 +- src/yunohost/data_migrations/0011_setup_group_permission.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/locales/en.json b/locales/en.json index 5c3595782..3e1054069 100644 --- a/locales/en.json +++ b/locales/en.json @@ -346,7 +346,7 @@ "migration_0011_can_not_backup_before_migration": "The backup of the system before the migration failed. Migration failed. Error: {error:s}", "migration_0011_create_group": "Creating a group for each user…", "migration_0011_done": "Migration successful. You are now able to manage usergroups.", - "migration_0011_LDAP_config_dirty": "It look like that you customized your LDAP configuration. For this migration the LDAP configuration needs to be updated.\nYou need to save your current configuration, reintialize the original configuration by running 'yunohost tools regen-conf -f' and retry the migration", + "migration_0011_slapd_config_will_be_overwritten": "It looks like you manually edited the slapd configuration. For this critical migration, YunoHost needs to force the update of the slapd configuration. The original files will be backuped in {conf_backup_folder}.", "migration_0011_LDAP_update_failed": "Could not update LDAP. Error: {error:s}", "migration_0011_migrate_permission": "Migrating permissions from apps settings to LDAP…", "migration_0011_migration_failed_trying_to_rollback": "Migration failed… trying to roll back the system.", diff --git a/src/yunohost/data_migrations/0011_setup_group_permission.py b/src/yunohost/data_migrations/0011_setup_group_permission.py index ae5a8bfb9..de28a3ad7 100644 --- a/src/yunohost/data_migrations/0011_setup_group_permission.py +++ b/src/yunohost/data_migrations/0011_setup_group_permission.py @@ -9,7 +9,7 @@ from moulinette.utils.filesystem import read_yaml from yunohost.tools import Migration from yunohost.user import user_group_create, user_group_update from yunohost.app import app_setting, app_list -from yunohost.regenconf import regen_conf +from yunohost.regenconf import regen_conf, BACKUP_CONF_DIR from yunohost.permission import permission_create, user_permission_update, permission_sync_to_user logger = getActionLogger('yunohost.migration') @@ -130,7 +130,7 @@ class MyMigration(Migration): ldap_regen_conf_status = regen_conf(names=['slapd'], dry_run=True) # By this we check if the have been customized if ldap_regen_conf_status and ldap_regen_conf_status['slapd']['pending']: - raise YunohostError("migration_0011_LDAP_config_dirty") + logger.warning("migration_0011_slapd_config_will_be_overwritten", conf_backup_folder=BACKUP_CONF_DIR) # Backup LDAP and the apps settings before to do the migration logger.info(m18n.n("migration_0011_backup_before_migration")) From 9cecd71437d050696a5e98e676532c21e8396749 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 9 Oct 2019 19:39:37 +0200 Subject: [PATCH 047/127] Fix permission_reset idempotency --- src/yunohost/permission.py | 4 ++++ src/yunohost/tests/test_permission.py | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/yunohost/permission.py b/src/yunohost/permission.py index 75e3f6037..97e5b4122 100644 --- a/src/yunohost/permission.py +++ b/src/yunohost/permission.py @@ -217,6 +217,10 @@ def user_permission_reset(operation_logger, permission, sync_perm=True): if existing_permission is None: raise YunohostError('permission_not_found', permission=permission) + if existing_permission["allowed"] == ["all_users"]: + logger.warning("The permission was not updated all addition/removal requests already match the current state.") + return + # Update permission with default (all_users) operation_logger.related_to.append(('app', permission.split(".")[0])) diff --git a/src/yunohost/tests/test_permission.py b/src/yunohost/tests/test_permission.py index a9e16cfc6..0ddda4cec 100644 --- a/src/yunohost/tests/test_permission.py +++ b/src/yunohost/tests/test_permission.py @@ -306,6 +306,17 @@ def test_permission_reset(): assert res['blog.main']['allowed'] == ["all_users"] assert set(res['blog.main']['corresponding_users']) == set(["alice", "bob"]) + +def test_permission_reset_idempotency(): + # Reset permission + user_permission_reset("blog.main") + user_permission_reset("blog.main") + + res = user_permission_list(full=True)['permissions'] + assert res['blog.main']['allowed'] == ["all_users"] + assert set(res['blog.main']['corresponding_users']) == set(["alice", "bob"]) + + # # Error on update function # From 88794805eba3ececc5bc04aac2d41b4d09241bf7 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 9 Oct 2019 22:08:12 +0200 Subject: [PATCH 048/127] We probably don't need to have multiple urls per permissions ... --- data/helpers.d/setting | 62 ++++++++--------- locales/en.json | 2 +- src/yunohost/app.py | 68 ++++++++----------- src/yunohost/backup.py | 6 +- .../0011_setup_group_permission.py | 4 +- src/yunohost/permission.py | 38 ++++------- src/yunohost/tests/test_backuprestore.py | 16 ++--- src/yunohost/tests/test_permission.py | 56 +++++---------- 8 files changed, 105 insertions(+), 147 deletions(-) diff --git a/data/helpers.d/setting b/data/helpers.d/setting index b2a647993..c911c5811 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -232,34 +232,36 @@ ynh_webpath_register () { # Create a new permission for the app # -# example: ynh_permission_create --permission admin --urls /admin +# example: ynh_permission_create --permission admin --url /admin # -# usage: ynh_permission_create --permission "permission" [--urls "url" ["url" ...]] +# usage: ynh_permission_create --permission "permission" [--url "url"] # | arg: permission - the name for the permission (by default a permission named "main" already exist) -# | arg: urls - (optional) a list of FULL urls for the permission (e.g. domain.tld/apps/admin) -# | arg: urls - (optional) a list of URLs to specify for the permission. +# | arg: url - (optional) URL for which access will be allowed/forbidden # -# URLs are assumed to be relative to the app domain/path if they start with '/'. -# For example: -# / -> domain.tld/app -# /admin -> domain.tld/app/admin -# domain.tld/app/api -> domain.tld/app/api +# If provided, 'url' is assumed to be relative to the app domain/path if they +# start with '/'. For example: +# / -> domain.tld/app +# /admin -> domain.tld/app/admin +# domain.tld/app/api -> domain.tld/app/api # -# URLs can be treated as regexes when they start with "re:". -# For example: -# re:/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ -# re:domain.tld/app/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ +# 'url' can be later treated as a regex if it starts with "re:". +# For example: +# re:/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ +# re:domain.tld/app/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ # ynh_permission_create() { - declare -Ar args_array=( [p]=permission= [u]=urls= ) + declare -Ar args_array=( [p]=permission= [u]=url= ) local permission local urls ynh_handle_getopts_args "$@" - if [[ -n ${urls:-} ]]; then - urls=",urls=['${urls//';'/"','"}']" + if [[ -n ${url:-} ]]; then + url="'$url'" + else + url="None" fi - yunohost tools shell -c "from yunohost.permission import permission_create; permission_create('$app.$permission' ${urls:-}, sync_perm=False)" + + yunohost tools shell -c "from yunohost.permission import permission_create; permission_create('$app.$permission', url=$url, sync_perm=False)" } # Remove a permission for the app (note that when the app is removed all permission is automatically removed) @@ -277,30 +279,28 @@ ynh_permission_delete() { yunohost tools shell -c "from yunohost.permission import permission_delete; permission_delete('$app.$permission', sync_perm=False)" } -# Manage urls related to a permission +# Redefine the url associated to a permission # -# usage: ynh_permission_urls --permission "permission" --add "url" ["url" ...] --remove "url" ["url" ...] +# usage: ynh_permission_url --permission "permission" --url "url" # | arg: permission - the name for the permission (by default a permission named "main" is removed automatically when the app is removed) -# | arg: add - (optional) a list of urls to add to the permission (see permission_create for details regarding their format) -# | arg: remove - (optional) a list of urls to remove from the permission (see permission_create for details regarding their format) +# | arg: url - (optional) URL for which access will be allowed/forbidden # -ynh_permission_urls() { - declare -Ar args_array=([p]=permission= [a]=add= [r]=remove=) +ynh_permission_url() { + declare -Ar args_array=([p]=permission= [u]=url=) local permission - local add - local remove + local url ynh_handle_getopts_args "$@" - if [[ -n ${add:-} ]]; then - add=",add=['${add//';'/"','"}']" - fi - if [[ -n ${remove:-} ]]; then - remove=",remove=['${remove//';'/"','"}']" + if [[ -n ${url:-} ]]; then + url="'$url'" + else + url="None" fi - yunohost tools shell -c "from yunohost.permission import permission_urls; permission_urls('$app.$permission' ${add:-} ${remove:-})" + yunohost tools shell -c "from yunohost.permission import permission_url; permission_url('$app.$permission', url=$url)" } + # Update a permission for the app # # usage: ynh_permission_update --permission "permission" --add "group" ["group" ...] --remove "group" ["group" ...] diff --git a/locales/en.json b/locales/en.json index 3e1054069..e3911a334 100644 --- a/locales/en.json +++ b/locales/en.json @@ -268,7 +268,7 @@ "log_letsencrypt_cert_install": "Install a Let's encrypt certificate on '{}' domain", "log_permission_create": "Create permission '{}'", "log_permission_delete": "Delete permission '{}'", - "log_permission_urls": "Update urls related to permission '{}'", + "log_permission_url": "Update url related to permission '{}'", "log_selfsigned_cert_install": "Install self signed certificate on '{}' domain", "log_letsencrypt_cert_renew": "Renew '{}' Let's encrypt certificate", "log_regen_conf": "Regenerate system configurations '{}'", diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 4bda9ccf6..abb4387e5 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -454,33 +454,18 @@ def app_map(app=None, raw=False, user=None): return perm_domain, perm_path - this_app_perms = {p: i for p, i in permissions.items() if p.startswith(app_id + ".") and i["urls"]} + this_app_perms = {p: i for p, i in permissions.items() if p.startswith(app_id + ".") and i["url"]} for perm_name, perm_info in this_app_perms.items(): # If we're building the map for a specific user, check the user # actually is allowed for this specific perm if user and user not in perm_info["corresponding_users"] and "visitors" not in perm_info["allowed"]: continue - if len(perm_info["urls"]) > 1 or perm_info["urls"][0].startswith("re:"): - # - # Here we have a big conceptual issue about the sso ... - # Let me take a sip of coffee and turn off the music... - # - # Let's say we have an app foo which created a permission - # 'foo.admin' and added as url "/admin" and "/api" This - # permission got defined somehow as only accessible for group - # "admins". So both "/admin" and "/api" are protected. Good! - # - # Now if we really want users in group "admins" to access those - # uris, then each users in group "admins" need to have these - # urls in the ssowat dict for this user. Which corresponds to a - # tile. To put it otherwise : in the current code of ssowat, a - # permission = a tile = a url ! - # - # We also have an issue if the url define is a regex, because + if perm_info["url"].startswith("re:"): + # Here, we have an issue if the chosen url is a regex, because # the url we want to add to the dict is going to be turned into # a clickable link (or analyzed by other parts of yunohost # code...). To put it otherwise : in the current code of ssowat, - # you can't give access a user to a regex + # you can't give access a user to a regex. # # Instead, as drafted by Josue, we could rework the ssowat logic # about how routes and their permissions are defined. So for example, @@ -498,10 +483,10 @@ def app_map(app=None, raw=False, user=None): # protected/unprotected/skipped uris and regexes and we gotta # handle / migrate all the legacy stuff somehow if we don't # want to end up with a total mess in the future idk - logger.error("Permission %s can't be added to the SSOwat configuration because it uses multiple urls and/or uses a regex url" % perm_name) + logger.error("Permission %s can't be added to the SSOwat configuration because it doesn't support regexes so far..." % perm_name) continue - perm_domain, perm_path = _sanitized_absolute_url(perm_info["urls"][0]) + perm_domain, perm_path = _sanitized_absolute_url(perm_info["url"]) if perm_name.endswith(".main"): perm_label = label @@ -535,7 +520,6 @@ def app_change_url(operation_logger, app, domain, path): """ from yunohost.hook import hook_exec, hook_callback from yunohost.domain import _normalize_domain_path, _get_conflicting_apps - from yunohost.permission import permission_urls installed = _is_installed(app) if not installed: @@ -835,7 +819,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu from yunohost.hook import hook_add, hook_remove, hook_exec, hook_callback from yunohost.log import OperationLogger - from yunohost.permission import user_permission_list, permission_create, permission_urls, permission_delete, permission_sync_to_user, user_permission_update + from yunohost.permission import user_permission_list, permission_create, permission_url, permission_delete, permission_sync_to_user, user_permission_update # Fetch or extract sources if not os.path.exists(INSTALL_TMP): @@ -994,7 +978,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu # Initialize the main permission for the app # After the install, if apps don't have a domain and path defined, the default url '/' is removed from the permission - permission_create(app_instance_name+".main", urls=["/"]) + permission_create(app_instance_name+".main", url="/") # Execute the app install script install_retcode = 1 @@ -1088,7 +1072,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu domain = app_settings.get('domain', None) path = app_settings.get('path', None) if not (domain and path): - permission_urls(app_instance_name + ".main", remove=["/"], sync_perm=False) + permission_url(app_instance_name + ".main", url=None, sync_perm=False) # Migrate classic public app still using the legacy unprotected_uris if app_settings.get("unprotected_uris", None) == "/": @@ -1178,7 +1162,7 @@ def app_addaccess(apps, users=[]): """ from yunohost.permission import user_permission_update - logger.warning("/!\\ Packagers ! This app is using the legacy permission system. Please use the new helpers ynh_permission_{create,urls,update,delete} and the 'visitors' group to manage permissions.") + logger.warning("/!\\ Packagers ! This app is using the legacy permission system. Please use the new helpers ynh_permission_{create,url,update,delete} and the 'visitors' group to manage permissions.") output = {} for app in apps: @@ -1199,7 +1183,7 @@ def app_removeaccess(apps, users=[]): """ from yunohost.permission import user_permission_update - logger.warning("/!\\ Packagers ! This app is using the legacy permission system. Please use the new helpers ynh_permission_{create,urls,update,delete} and the 'visitors' group to manage permissions.") + logger.warning("/!\\ Packagers ! This app is using the legacy permission system. Please use the new helpers ynh_permission_{create,url,update,delete} and the 'visitors' group to manage permissions.") output = {} for app in apps: @@ -1219,7 +1203,7 @@ def app_clearaccess(apps): """ from yunohost.permission import user_permission_reset - logger.warning("/!\\ Packagers ! This app is using the legacy permission system. Please use the new helpers ynh_permission_{create,urls,update,delete} and the 'visitors' group to manage permissions.") + logger.warning("/!\\ Packagers ! This app is using the legacy permission system. Please use the new helpers ynh_permission_{create,url,update,delete} and the 'visitors' group to manage permissions.") output = {} for app in apps: @@ -1329,7 +1313,7 @@ def app_setting(app, key, value=None, delete=False): if key in ['redirected_urls', 'redirected_regex']: value = yaml.load(value) if key in ["unprotected_uris", "unprotected_regex", "protected_uris", "protected_regex"]: - logger.warning("/!\ Packagers ! This app is using the legacy permission system. Please delete these legacy settings and use the new helpers ynh_permission_{create,urls,update,delete} and the 'visitors' group to manage public/private access.") + logger.warning("/!\ Packagers ! This app is using the legacy permission system. Please delete these legacy settings and use the new helpers ynh_permission_{create,url,update,delete} and the 'visitors' group to manage public/private access.") app_settings[key] = value _set_app_settings(app, app_settings) @@ -1562,20 +1546,24 @@ def app_ssowatconf(): # New permission system this_app_perms = {name: info for name, info in all_permissions.items() if name.startswith(app['id'] + ".")} for perm_name, perm_info in this_app_perms.items(): + + # Ignore permissions for which there's no url defined + if not perm_info["url"]: + continue + # FIXME : gotta handle regex-urls here... meh - urls = [_sanitized_absolute_url(url) for url in perm_info["urls"]] + url = _sanitized_absolute_url(perm_info["url"]) if "visitors" in perm_info["allowed"]: - unprotected_urls += urls + unprotected_urls.append(url) # Legacy stuff : we remove now unprotected-urls that might have been declared as protected earlier... - protected_urls = [u for u in protected_urls if u not in urls] + protected_urls = [u for u in protected_urls if u != url] else: # TODO : small optimization to implement : we don't need to explictly add all the app roots - - protected_urls += urls + protected_urls.append(url) # Legacy stuff : we remove now unprotected-urls that might have been declared as protected earlier... - unprotected_urls = [u for u in unprotected_urls if u not in urls] + unprotected_urls = [u for u in unprotected_urls if u != url] for domain in domains: skipped_urls.extend([domain + '/yunohost/admin', domain + '/yunohost/api']) @@ -1585,11 +1573,13 @@ def app_ssowatconf(): skipped_regex.append("^[^/]*/%.well%-known/autoconfig/mail/config%-v1%.1%.xml.*$") - permissions_per_url = {} - for permission_name, permission_infos in all_permissions.items(): - for url in permission_infos["urls"]: - permissions_per_url[url] = permission_infos['corresponding_users'] + for perm_name, perm_info in all_permissions.items(): + # Ignore permissions for which there's no url defined + if not perm_info["url"]: + continue + permissions_per_url[perm_info["url"]] = perm_info['corresponding_users'] + conf_dict = { 'portal_domain': main_domain, diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index c28160342..dcdb1adec 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -1189,7 +1189,7 @@ class RestoreManager(): return from yunohost.user import user_group_list - from yunohost.permission import permission_create, permission_delete, user_permission_update, user_permission_list + from yunohost.permission import permission_create, permission_delete, user_permission_update, user_permission_list, permission_sync_to_user # Backup old permission for apps # We need to do that because in case of an app is installed we can't remove the permission for this app @@ -1251,7 +1251,7 @@ class RestoreManager(): for permission_name, permission_infos in old_apps_permission.items(): app_name = permission_name.split(".")[0] if _is_installed(app_name): - permission_create(permission_name, urls=permission_infos["urls"], sync_perm=False) + permission_create(permission_name, url=permission_infos["url"], sync_perm=False) user_permission_update(permission_name, remove="all_users", add=permission_infos["allowed"]) def _restore_apps(self): @@ -1362,7 +1362,7 @@ class RestoreManager(): for permission_name, permission_infos in permissions.items(): - permission_create(permission_name, urls=permission_infos.get("urls", [])) + permission_create(permission_name, url=permission_infos.get("url", None)) if "allowed" not in permission_infos: logger.warning("'allowed' key corresponding to allowed groups for permission %s not found when restoring app %s … You might have to reconfigure permissions yourself." % (permission_name, app_instance_name)) diff --git a/src/yunohost/data_migrations/0011_setup_group_permission.py b/src/yunohost/data_migrations/0011_setup_group_permission.py index de28a3ad7..880c5f54b 100644 --- a/src/yunohost/data_migrations/0011_setup_group_permission.py +++ b/src/yunohost/data_migrations/0011_setup_group_permission.py @@ -107,8 +107,8 @@ class MyMigration(Migration): path = app_setting(app, 'path') domain = app_setting(app, 'domain') - urls = "/" if domain and path else None - permission_create(app+".main", urls=urls, sync_perm=False) + url = "/" if domain and path else None + permission_create(app+".main", url=url, sync_perm=False) if permission: allowed_group = permission.split(',') user_permission_update(app+".main", remove="all_users", add=allowed_group, sync_perm=False) diff --git a/src/yunohost/permission.py b/src/yunohost/permission.py index 97e5b4122..6f9d63d69 100644 --- a/src/yunohost/permission.py +++ b/src/yunohost/permission.py @@ -73,7 +73,7 @@ def user_permission_list(short=False, full=False, ignore_system_perms=False): if full: permissions[name]["corresponding_users"] = [_ldap_path_extract(p, "uid") for p in infos.get('inheritPermission', [])] - permissions[name]["urls"] = infos.get("URL", []) + permissions[name]["url"] = infos.get("URL", [None])[0] if short: permissions = permissions.keys() @@ -260,27 +260,27 @@ def user_permission_reset(operation_logger, permission, sync_perm=True): # # The followings methods are *not* directly exposed. # They are used to create/delete the permissions (e.g. during app install/remove) -# and by some app helpers to possibly add additional permissions and tweak the urls +# and by some app helpers to possibly add additional permissions # # @is_unit_operation() -def permission_create(operation_logger, permission, urls=None, sync_perm=True): +def permission_create(operation_logger, permission, url=None, sync_perm=True): """ Create a new permission for a specific application Keyword argument: permission -- Name of the permission (e.g. mail or nextcloud or wordpress.editors) - urls -- list of URLs to specify for the permission. + url -- (optional) URL for which access will be allowed/forbidden - Urls are assumed to be relative to the app domain/path if they start with '/'. - For example: + If provided, 'url' is assumed to be relative to the app domain/path if they + start with '/'. For example: / -> domain.tld/app /admin -> domain.tld/app/admin domain.tld/app/api -> domain.tld/app/api - URLs can be later treated as regexes when they start with "re:". + 'url' can be later treated as a regex if it starts with "re:". For example: re:/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ re:domain.tld/app/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ @@ -316,8 +316,8 @@ def permission_create(operation_logger, permission, urls=None, sync_perm=True): if permission.endswith(".main"): attr_dict['groupPermission'] = ['cn=all_users,ou=groups,dc=yunohost,dc=org'] - if urls: - attr_dict['URL'] = urls + if url: + attr_dict['URL'] = url operation_logger.related_to.append(('app', permission.split(".")[0])) operation_logger.start() @@ -335,15 +335,13 @@ def permission_create(operation_logger, permission, urls=None, sync_perm=True): @is_unit_operation() -def permission_urls(operation_logger, permission, add=None, remove=None, sync_perm=True): +def permission_url(operation_logger, permission, url=None, sync_perm=True): """ Update urls related to a permission for a specific application Keyword argument: permission -- Name of the permission (e.g. mail or nextcloud or wordpress.editors) - add -- List of URLs to add (c.f. permission_create for documentation about their format) - remove -- List of URLs to remove (c.f. permission_create for documentation about their format) - + url -- (optional) URL for which access will be allowed/forbidden """ from yunohost.utils.ldap import _get_ldap_interface ldap = _get_ldap_interface() @@ -355,17 +353,9 @@ def permission_urls(operation_logger, permission, add=None, remove=None, sync_pe raise YunohostError('permission_not_found', permission=permission) # Compute new url list + old_url = existing_permission["url"] - new_urls = copy.copy(existing_permission["urls"]) - - if add: - urls_to_add = [add] if not isinstance(add, list) else add - new_urls += urls_to_add - if remove: - urls_to_remove = [remove] if not isinstance(remove, list) else remove - new_urls = [u for u in new_urls if u not in urls_to_remove] - - if set(new_urls) == set(existing_permission["urls"]): + if old_url == url: logger.warning(m18n.n('permission_update_nothing_to_do')) return existing_permission @@ -375,7 +365,7 @@ def permission_urls(operation_logger, permission, add=None, remove=None, sync_pe operation_logger.start() try: - ldap.update('cn=%s,ou=permission' % permission, {'URL': new_urls}) + ldap.update('cn=%s,ou=permission' % permission, {'URL': [url]}) except Exception as e: raise YunohostError('permission_update_failed', permission=permission, error=e) diff --git a/src/yunohost/tests/test_backuprestore.py b/src/yunohost/tests/test_backuprestore.py index cab98089b..82d3da660 100644 --- a/src/yunohost/tests/test_backuprestore.py +++ b/src/yunohost/tests/test_backuprestore.py @@ -529,11 +529,11 @@ def test_backup_and_restore_permission_app(): assert "permissions_app.main" in res assert "permissions_app.admin" in res assert "permissions_app.dev" in res - assert res['permissions_app.main']['urls'] == ["/"] - assert res['permissions_app.admin']['urls'] == ["/admin"] - assert res['permissions_app.dev']['urls'] == ["/dev"] + assert res['permissions_app.main']['url'] == "/" + assert res['permissions_app.admin']['url'] == "/admin" + assert res['permissions_app.dev']['url'] == "/dev" - assert res['permissions_app.main']['allowed'] == ["all_users"] + assert res['permissions_app.main']['allowed'] == ["visitors"] assert res['permissions_app.admin']['allowed'] == ["alice"] assert res['permissions_app.dev']['allowed'] == [] @@ -543,11 +543,11 @@ def test_backup_and_restore_permission_app(): assert "permissions_app.main" in res assert "permissions_app.admin" in res assert "permissions_app.dev" in res - assert res['permissions_app.main']['urls'] == ["/"] - assert res['permissions_app.admin']['urls'] == ["/admin"] - assert res['permissions_app.dev']['urls'] == ["/dev"] + assert res['permissions_app.main']['url'] == "/" + assert res['permissions_app.admin']['url'] == "/admin" + assert res['permissions_app.dev']['url'] == "/dev" - assert res['permissions_app.main']['allowed'] == ["all_users"] + assert res['permissions_app.main']['allowed'] == ["visitors"] assert res['permissions_app.admin']['allowed'] == ["alice"] assert res['permissions_app.dev']['allowed'] == [] diff --git a/src/yunohost/tests/test_permission.py b/src/yunohost/tests/test_permission.py index 0ddda4cec..8e536ec9e 100644 --- a/src/yunohost/tests/test_permission.py +++ b/src/yunohost/tests/test_permission.py @@ -6,7 +6,7 @@ from yunohost.app import app_install, app_remove, app_change_url, app_list, app_ from yunohost.user import user_list, user_info, user_create, user_delete, user_update, \ user_group_list, user_group_create, user_group_delete, user_group_update, user_group_info from yunohost.permission import user_permission_update, user_permission_list, user_permission_reset, \ - permission_create, permission_urls, permission_delete + permission_create, permission_delete, permission_url from yunohost.domain import _get_maindomain from yunohost.utils.error import YunohostError @@ -31,7 +31,7 @@ def setup_function(function): user_create("alice", "Alice", "White", "alice@" + maindomain, dummy_password) user_create("bob", "Bob", "Snow", "bob@" + maindomain, dummy_password) - permission_create("wiki.main", urls=["/"], sync_perm=False) + permission_create("wiki.main", url="/", sync_perm=False) permission_create("blog.main", sync_perm=False) user_permission_update("blog.main", remove="all_users", add="alice") @@ -202,7 +202,7 @@ def test_permission_list(): assert res['blog.main']['allowed'] == ["alice"] assert set(res['wiki.main']['corresponding_users']) == set(["alice", "bob"]) assert res['blog.main']['corresponding_users'] == ["alice"] - assert res['wiki.main']['urls'] == ["/"] + assert res['wiki.main']['url'] == "/" # # Create - Remove functions @@ -333,41 +333,19 @@ def test_permission_update_permission_that_doesnt_exist(): with pytest.raises(YunohostError): user_permission_update("doesnt.exist", add="alice") - # Permission url management -def test_permission_add_url(): - permission_urls("blog.main", add=["/testA"]) +def test_permission_redefine_url(): + permission_url("blog.main", url="/pwet") res = user_permission_list(full=True)['permissions'] - assert res["blog.main"]["urls"] == ["/testA"] - -def test_permission_add_another_url(): - permission_urls("wiki.main", add=["/testA"]) - - res = user_permission_list(full=True)['permissions'] - assert set(res["wiki.main"]["urls"]) == set(["/", "/testA"]) + assert res["blog.main"]["url"] == "/pwet" def test_permission_remove_url(): - permission_urls("wiki.main", remove=["/"]) + permission_url("blog.main", url=None) res = user_permission_list(full=True)['permissions'] - assert res["wiki.main"]["urls"] == [] - -def test_permission_add_url_already_added(): - res = user_permission_list(full=True)['permissions'] - assert res["wiki.main"]["urls"] == ["/"] - - permission_urls("wiki.main", add=["/"]) - - res = user_permission_list(full=True)['permissions'] - assert res["wiki.main"]["urls"] == ["/"] - -def test_permission_remove_url_not_added(): - permission_urls("wiki.main", remove=["/doesnt_exist"]) - - res = user_permission_list(full=True)['permissions'] - assert res['wiki.main']['urls'] == ["/"] + assert res["blog.main"]["url"] is None # # Application interaction @@ -381,9 +359,9 @@ def test_permission_app_install(): assert "permissions_app.main" in res assert "permissions_app.admin" in res assert "permissions_app.dev" in res - assert res['permissions_app.main']['urls'] == ["/"] - assert res['permissions_app.admin']['urls'] == ["/admin"] - assert res['permissions_app.dev']['urls'] == ["/dev"] + assert res['permissions_app.main']['url'] == "/" + assert res['permissions_app.admin']['url'] == "/admin" + assert res['permissions_app.dev']['url'] == "/dev" assert res['permissions_app.main']['allowed'] == ["all_users"] assert set(res['permissions_app.main']['corresponding_users']) == set(["alice", "bob"]) @@ -416,16 +394,16 @@ def test_permission_app_change_url(): # FIXME : should rework this test to look for differences in the generated app map / app tiles ... res = user_permission_list(full=True)['permissions'] - assert res['permissions_app.main']['urls'] == ["/"] - assert res['permissions_app.admin']['urls'] == ["/admin"] - assert res['permissions_app.dev']['urls'] == ["/dev"] + assert res['permissions_app.main']['url'] == "/" + assert res['permissions_app.admin']['url'] == "/admin" + assert res['permissions_app.dev']['url'] == "/dev" app_change_url("permissions_app", maindomain, "/newchangeurl") res = user_permission_list(full=True)['permissions'] - assert res['permissions_app.main']['urls'] == ["/"] - assert res['permissions_app.admin']['urls'] == ["/admin"] - assert res['permissions_app.dev']['urls'] == ["/dev"] + assert res['permissions_app.main']['url'] == "/" + assert res['permissions_app.admin']['url'] == "/admin" + assert res['permissions_app.dev']['url'] == "/dev" def test_permission_app_propagation_on_ssowat(): From 2617fd2487d8940309b7a19cb3011985eff3a327 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 9 Oct 2019 22:11:19 +0200 Subject: [PATCH 049/127] Fix issues related to regerating ssowat conf while hacking permissions... --- src/yunohost/backup.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index dcdb1adec..90f795ea5 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -1245,14 +1245,17 @@ class RestoreManager(): # Remove all permission for all app which is still in the LDAP for permission_name in user_permission_list(ignore_system_perms=True)["permissions"].keys(): - permission_delete(permission_name, force=True) + permission_delete(permission_name, force=True, sync_perm=False) # Restore permission for the app which is installed for permission_name, permission_infos in old_apps_permission.items(): app_name = permission_name.split(".")[0] if _is_installed(app_name): permission_create(permission_name, url=permission_infos["url"], sync_perm=False) - user_permission_update(permission_name, remove="all_users", add=permission_infos["allowed"]) + user_permission_update(permission_name, remove="all_users", add=permission_infos["allowed"], sync_perm=False) + + permission_sync_to_user() + def _restore_apps(self): """Restore all apps targeted""" @@ -1290,7 +1293,7 @@ class RestoreManager(): restore_app_failed -- Raised if the restore bash script failed """ from yunohost.user import user_group_list - from yunohost.permission import permission_create, permission_delete, user_permission_list, user_permission_update + from yunohost.permission import permission_create, permission_delete, user_permission_list, user_permission_update, permission_sync_to_user def copytree(src, dst, symlinks=False, ignore=None): for item in os.listdir(src): @@ -1362,7 +1365,7 @@ class RestoreManager(): for permission_name, permission_infos in permissions.items(): - permission_create(permission_name, url=permission_infos.get("url", None)) + permission_create(permission_name, url=permission_infos.get("url", None), sync_perm=False) if "allowed" not in permission_infos: logger.warning("'allowed' key corresponding to allowed groups for permission %s not found when restoring app %s … You might have to reconfigure permissions yourself." % (permission_name, app_instance_name)) @@ -1370,7 +1373,9 @@ class RestoreManager(): should_be_allowed = [g for g in permission_infos["allowed"] if g in existing_groups] current_allowed = user_permission_list()["permissions"][permission_name]["allowed"] if should_be_allowed != current_allowed: - user_permission_update(permission_name, remove=current_allowed, add=should_be_allowed) + user_permission_update(permission_name, remove=current_allowed, add=should_be_allowed, sync_perm=False) + + permission_sync_to_user() os.remove('%s/permissions.yml' % app_settings_new_path) else: From c315df926999376fd79b81dd32072d8d3f06e4a9 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 9 Oct 2019 22:48:47 +0200 Subject: [PATCH 050/127] Wokay, getting tired of breaking the entire permission/group ecosystem because of bugs when developing. --- src/yunohost/app.py | 3 +++ src/yunohost/user.py | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index abb4387e5..75bf12f3d 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -433,6 +433,9 @@ def app_map(app=None, raw=False, user=None): continue # Users must at least have access to the main permission to have access to extra permissions if user: + if not app_id + ".main" in permissions: + logger.warning("Uhoh, no main permission was found for app %s ... sounds like an app was only partially removed due to another bug :/" % app_id) + continue main_perm = permissions[app_id + ".main"] if user not in main_perm["corresponding_users"] and "visitors" not in main_perm["allowed"]: continue diff --git a/src/yunohost/user.py b/src/yunohost/user.py index f4e550230..72aa36184 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -268,7 +268,12 @@ def user_delete(operation_logger, username, purge=False): # remove the member from the group if username != group and username in infos["members"]: user_group_update(group, remove=username, sync_perm=False) - user_group_delete(username, force=True, sync_perm=True) + + # Delete primary group if it exists (why wouldnt it exists ? because some + # epic bug happened somewhere else and only a partial removal was + # performed...) + if username in user_group_list()['groups'].keys(): + user_group_delete(username, force=True, sync_perm=True) ldap = _get_ldap_interface() try: From e7d1cc5f9449f77bf575c82f9faae5f2f2168b41 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 9 Oct 2019 22:55:06 +0200 Subject: [PATCH 051/127] Allow to specify right away what groups to allow for a permission when creating it --- data/helpers.d/setting | 16 +++++++++++----- src/yunohost/app.py | 2 +- src/yunohost/backup.py | 11 ++++------- .../0011_setup_group_permission.py | 8 +++++--- src/yunohost/permission.py | 16 ++++++++++++++-- src/yunohost/tests/test_permission.py | 9 +++++++++ 6 files changed, 44 insertions(+), 18 deletions(-) diff --git a/data/helpers.d/setting b/data/helpers.d/setting index c911c5811..a8d2919a4 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -232,11 +232,12 @@ ynh_webpath_register () { # Create a new permission for the app # -# example: ynh_permission_create --permission admin --url /admin +# example: ynh_permission_create --permission admin --url /admin --allowed alice bob # -# usage: ynh_permission_create --permission "permission" [--url "url"] +# usage: ynh_permission_create --permission "permission" [--url "url"] [--allowed group1 group2] # | arg: permission - the name for the permission (by default a permission named "main" already exist) # | arg: url - (optional) URL for which access will be allowed/forbidden +# | arg: allowed - (optional) A list of group/user to allow for the permission # # If provided, 'url' is assumed to be relative to the app domain/path if they # start with '/'. For example: @@ -250,9 +251,10 @@ ynh_webpath_register () { # re:domain.tld/app/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ # ynh_permission_create() { - declare -Ar args_array=( [p]=permission= [u]=url= ) + declare -Ar args_array=( [p]=permission= [u]=url= [a]=allowed= ) local permission - local urls + local url + local allowed ynh_handle_getopts_args "$@" if [[ -n ${url:-} ]]; then @@ -261,7 +263,11 @@ ynh_permission_create() { url="None" fi - yunohost tools shell -c "from yunohost.permission import permission_create; permission_create('$app.$permission', url=$url, sync_perm=False)" + if [[ -n ${allowed:-} ]]; then + allowed=",allowed=['${allowed//';'/"','"}']" + fi + + yunohost tools shell -c "from yunohost.permission import permission_create; permission_create('$app.$permission', url=$url ${allowed:-} , sync_perm=False)" } # Remove a permission for the app (note that when the app is removed all permission is automatically removed) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 75bf12f3d..7235535cd 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -981,7 +981,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu # Initialize the main permission for the app # After the install, if apps don't have a domain and path defined, the default url '/' is removed from the permission - permission_create(app_instance_name+".main", url="/") + permission_create(app_instance_name+".main", url="/", allowed=["all_users"]) # Execute the app install script install_retcode = 1 diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index 90f795ea5..c57ab6685 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -1251,8 +1251,7 @@ class RestoreManager(): for permission_name, permission_infos in old_apps_permission.items(): app_name = permission_name.split(".")[0] if _is_installed(app_name): - permission_create(permission_name, url=permission_infos["url"], sync_perm=False) - user_permission_update(permission_name, remove="all_users", add=permission_infos["allowed"], sync_perm=False) + permission_create(permission_name, url=permission_infos["url"], allowed=permission_infos["allowed"], sync_perm=False) permission_sync_to_user() @@ -1365,15 +1364,13 @@ class RestoreManager(): for permission_name, permission_infos in permissions.items(): - permission_create(permission_name, url=permission_infos.get("url", None), sync_perm=False) - if "allowed" not in permission_infos: logger.warning("'allowed' key corresponding to allowed groups for permission %s not found when restoring app %s … You might have to reconfigure permissions yourself." % (permission_name, app_instance_name)) + should_be_allowed = ["all_users"] else: should_be_allowed = [g for g in permission_infos["allowed"] if g in existing_groups] - current_allowed = user_permission_list()["permissions"][permission_name]["allowed"] - if should_be_allowed != current_allowed: - user_permission_update(permission_name, remove=current_allowed, add=should_be_allowed, sync_perm=False) + + permission_create(permission_name, url=permission_infos.get("url", None), allowed=should_be_allowed, sync_perm=False) permission_sync_to_user() diff --git a/src/yunohost/data_migrations/0011_setup_group_permission.py b/src/yunohost/data_migrations/0011_setup_group_permission.py index 880c5f54b..3114817b9 100644 --- a/src/yunohost/data_migrations/0011_setup_group_permission.py +++ b/src/yunohost/data_migrations/0011_setup_group_permission.py @@ -108,10 +108,12 @@ class MyMigration(Migration): domain = app_setting(app, 'domain') url = "/" if domain and path else None - permission_create(app+".main", url=url, sync_perm=False) if permission: - allowed_group = permission.split(',') - user_permission_update(app+".main", remove="all_users", add=allowed_group, sync_perm=False) + allowed_groups = permission.split(',') + else: + allowed_groups = ["all_users"] + permission_create(app+".main", url=url, allowed=allowed_groups, sync_perm=False) + app_setting(app, 'allowed_users', delete=True) # Migrate classic public app still using the legacy unprotected_uris diff --git a/src/yunohost/permission.py b/src/yunohost/permission.py index 6f9d63d69..426ecd10f 100644 --- a/src/yunohost/permission.py +++ b/src/yunohost/permission.py @@ -266,13 +266,14 @@ def user_permission_reset(operation_logger, permission, sync_perm=True): @is_unit_operation() -def permission_create(operation_logger, permission, url=None, sync_perm=True): +def permission_create(operation_logger, permission, url=None, allowed=None, sync_perm=True): """ Create a new permission for a specific application Keyword argument: permission -- Name of the permission (e.g. mail or nextcloud or wordpress.editors) url -- (optional) URL for which access will be allowed/forbidden + allowed -- (optional) A list of group/user to allow for the permission If provided, 'url' is assumed to be relative to the app domain/path if they start with '/'. For example: @@ -286,6 +287,7 @@ def permission_create(operation_logger, permission, url=None, sync_perm=True): re:domain.tld/app/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ """ + from yunohost.user import user_group_list from yunohost.utils.ldap import _get_ldap_interface ldap = _get_ldap_interface() @@ -312,8 +314,18 @@ def permission_create(operation_logger, permission, url=None, sync_perm=True): 'gidNumber': gid, } + # If who should be allowed is explicitly provided, use this info + if allowed: + if not isinstance(allowed, list): + allowed = [allowed] + # (though first we validate that the targets actually exist) + all_existing_groups = user_group_list()['groups'].keys() + for g in allowed: + if g not in all_existing_groups: + raise YunohostError('group_unknown', group=g) + attr_dict['groupPermission'] = ['cn=%s,ou=groups,dc=yunohost,dc=org' % g for g in allowed] # For main permission, we add all users by default - if permission.endswith(".main"): + elif permission.endswith(".main"): attr_dict['groupPermission'] = ['cn=all_users,ou=groups,dc=yunohost,dc=org'] if url: diff --git a/src/yunohost/tests/test_permission.py b/src/yunohost/tests/test_permission.py index 8e536ec9e..5e1246793 100644 --- a/src/yunohost/tests/test_permission.py +++ b/src/yunohost/tests/test_permission.py @@ -226,6 +226,15 @@ def test_permission_create_extra(): assert "all_users" not in res['site.test']['allowed'] assert res['site.test']['corresponding_users'] == [] + +def test_permission_create_with_allowed(): + permission_create("site.test", allowed=["alice"]) + + res = user_permission_list(full=True)['permissions'] + assert "site.test" in res + assert res['site.test']['allowed'] == ["alice"] + + def test_permission_delete(): permission_delete("wiki.main", force=True) From 4bdcfb4373bfc0ce44931df209fb5d949a3d3768 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 9 Oct 2019 23:16:07 +0200 Subject: [PATCH 052/127] Implement / fix i18n strings --- locales/en.json | 3 +++ .../data_migrations/0011_setup_group_permission.py | 2 +- src/yunohost/permission.py | 13 ++++--------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/locales/en.json b/locales/en.json index e3911a334..c6a6a440e 100644 --- a/locales/en.json +++ b/locales/en.json @@ -415,9 +415,12 @@ "permission_already_allowed": "Group '{group}' already has permission '{permission}' enabled'", "permission_already_disallowed": "Group '{group}' already has permission '{permission}' disabled'", "permission_already_exist": "Permission '{permission}' already exists", + "permission_already_up_to_date": "The permission was not updated because the addition/removal requests already match the current state.", "permission_cannot_remove_main": "Removing a main permission is not allowed", "permission_created": "Permission '{permission:s}' created", "permission_creation_failed": "Could not create permission '{permission}': {error}", + "permission_currently_allowed_for_visitors": "This permission is currently granted to visitors in addition to other groups. You probably want to either remove the 'visitors' permission or remove the other groups it is currently granted to.", + "permission_currently_allowed_for_all_users": "This permission is currently granted to all users in addition to other groups. You probably want to either remove the 'all_users' permission or remove the other groups it is currently granted to.", "permission_deleted": "Permission '{permission:s}' deleted", "permission_deletion_failed": "Could not delete permission '{permission}': {error}", "permission_not_found": "Permission '{permission:s}' not found", diff --git a/src/yunohost/data_migrations/0011_setup_group_permission.py b/src/yunohost/data_migrations/0011_setup_group_permission.py index 3114817b9..9ba2268d9 100644 --- a/src/yunohost/data_migrations/0011_setup_group_permission.py +++ b/src/yunohost/data_migrations/0011_setup_group_permission.py @@ -132,7 +132,7 @@ class MyMigration(Migration): ldap_regen_conf_status = regen_conf(names=['slapd'], dry_run=True) # By this we check if the have been customized if ldap_regen_conf_status and ldap_regen_conf_status['slapd']['pending']: - logger.warning("migration_0011_slapd_config_will_be_overwritten", conf_backup_folder=BACKUP_CONF_DIR) + logger.warning(m18n.n("migration_0011_slapd_config_will_be_overwritten", conf_backup_folder=BACKUP_CONF_DIR)) # Backup LDAP and the apps settings before to do the migration logger.info(m18n.n("migration_0011_backup_before_migration")) diff --git a/src/yunohost/permission.py b/src/yunohost/permission.py index 426ecd10f..4cfbc214f 100644 --- a/src/yunohost/permission.py +++ b/src/yunohost/permission.py @@ -144,18 +144,13 @@ def user_permission_update(operation_logger, permission, add=None, remove=None, if len(new_allowed_groups) > 1: if "all_users" in new_allowed_groups: - # FIXME : i18n - # FIXME : write a better explanation ? - logger.warning("This permission is currently granted to all users in addition to other groups. You probably want to either remove the 'all_users' permission or remove the other groups it is currently granted to.") + logger.warning(m18n.n("permission_currently_allowed_for_all_users")) if "visitors" in new_allowed_groups: - # FIXME : i18n - # FIXME : write a better explanation ? - logger.warning("This permission is currently granted to visitors in addition to other groups. You probably want to either remove the 'visitors' permission or remove the other groups it is currently granted to.") + logger.warning(m18n.n("permission_currently_allowed_for_visitors")) # Don't update LDAP if we update exactly the same values if set(new_allowed_groups) == set(current_allowed_groups): - # FIXME : i18n - logger.warning("The permission was not updated all addition/removal requests already match the current state.") + logger.warning("permission_already_up_to_date") return # Commit the new allowed group list @@ -218,7 +213,7 @@ def user_permission_reset(operation_logger, permission, sync_perm=True): raise YunohostError('permission_not_found', permission=permission) if existing_permission["allowed"] == ["all_users"]: - logger.warning("The permission was not updated all addition/removal requests already match the current state.") + logger.warning(m18n.n("permission_already_up_to_date")) return # Update permission with default (all_users) From e4163136bbe6c7eff26102767400c0a99cb702c0 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 9 Oct 2019 23:40:50 +0200 Subject: [PATCH 053/127] Don't attempt to delete the 'visitors' group during user/group tests --- src/yunohost/tests/test_user-group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/tests/test_user-group.py b/src/yunohost/tests/test_user-group.py index 30bdeb017..53fded94c 100644 --- a/src/yunohost/tests/test_user-group.py +++ b/src/yunohost/tests/test_user-group.py @@ -14,7 +14,7 @@ def clean_user_groups(): user_delete(u) for g in user_group_list()['groups']: - if g != "all_users": + if g not in ["all_users", "visitors"]: user_group_delete(g) def setup_function(function): From e48036a0829ed2754d2c39e033c78dd8b6d07c84 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 10 Oct 2019 00:05:20 +0200 Subject: [PATCH 054/127] Fix test about private app installs --- src/yunohost/tests/test_apps.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/yunohost/tests/test_apps.py b/src/yunohost/tests/test_apps.py index fc44ef105..fb2f13c3f 100644 --- a/src/yunohost/tests/test_apps.py +++ b/src/yunohost/tests/test_apps.py @@ -119,10 +119,10 @@ def app_is_exposed_on_http(domain, path, message_in_page): return False -def install_legacy_app(domain, path): +def install_legacy_app(domain, path, public=True): app_install("./tests/apps/legacy_app_ynh", - args="domain=%s&path=%s" % (domain, path), + args="domain=%s&path=%s&is_public=%s" % (domain, path, 1 if public else 0), force=True) @@ -180,13 +180,7 @@ def test_legacy_app_install_secondary_domain_on_root(secondary_domain): def test_legacy_app_install_private(secondary_domain): - install_legacy_app(secondary_domain, "/legacy") - - settings = open("/etc/yunohost/apps/legacy_app/settings.yml", "r").read() - new_settings = settings.replace("\nunprotected_uris: /", "") - assert new_settings != settings - open("/etc/yunohost/apps/legacy_app/settings.yml", "w").write(new_settings) - app_ssowatconf() + install_legacy_app(secondary_domain, "/legacy", public=False) assert app_is_installed(secondary_domain, "legacy_app") assert not app_is_exposed_on_http(secondary_domain, "/legacy", "This is a dummy app") From 2623d38567d18980265b8b30cdf1786f89355ad5 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 10 Oct 2019 00:06:36 +0200 Subject: [PATCH 055/127] Annnnnd Alex was drunk and released an epic stupid bug in stable --- src/yunohost/app.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 421be9b60..88204f3ff 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2569,9 +2569,8 @@ def _validate_and_normalize_webpath(manifest, args_dict, app_folder): and re.search(r"(ynh_webpath_register|yunohost app checkurl)", install_script_content): domain = domain_args[0][1] - conflicts = _get_conflicting_apps(domain, "/") - - raise YunohostError('app_full_domain_unavailable', domain=domain) + if _get_conflicting_apps(domain, "/"): + raise YunohostError('app_full_domain_unavailable', domain=domain) def _make_environment_dict(args_dict, prefix="APP_ARG_"): From f2db3d34dd21fdf8d170fbd3eaea42ddb11283c9 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 10 Oct 2019 00:08:47 +0200 Subject: [PATCH 056/127] Update changelog for 3.6.5.2 --- debian/changelog | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 6d5a16f2c..1d13b6290 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,14 @@ +yunohost (3.6.5.2) stable; urgency=low + + - [fix] Alex was drunk and released an epic stupid bug in stable (2623d385) + + -- Alexandre Aubin Thu, 10 Oct 2019 01:00:00 +0000 + yunohost (3.6.5.1) stable; urgency=low - [mod] Change maxretry of fail2ban from 6 to 10 (fe8fd1b) - -- Alexandre Aubin Mon, 08 Oct 2019 20:00:00 +0000 + -- Alexandre Aubin Tue, 08 Oct 2019 20:00:00 +0000 yunohost (3.6.5) stable; urgency=low @@ -11,7 +17,7 @@ yunohost (3.6.5) stable; urgency=low - [fix] Epicly ugly workaround for the goddamn dependency nighmare about sury fucking up php7.0 dependencies (#809) - [fix] Support logfiles not ending with .log in logrotate ... (#810) - -- Alexandre Aubin Mon, 08 Oct 2019 19:00:00 +0000 + -- Alexandre Aubin Tue, 08 Oct 2019 19:00:00 +0000 yunohost (3.6.4.6) stable; urgency=low From 38fd969f94c90a64e9119ee3b78c8f2c62c169e0 Mon Sep 17 00:00:00 2001 From: amirale qt Date: Mon, 7 Oct 2019 05:19:53 +0000 Subject: [PATCH 057/127] Translated using Weblate (Esperanto) Currently translated at 100.0% (553 of 553 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eo/ --- locales/eo.json | 422 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 420 insertions(+), 2 deletions(-) diff --git a/locales/eo.json b/locales/eo.json index 1d367260d..d27c0171c 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -106,7 +106,7 @@ "app_package_need_update": "La pakaĵo {app} devas esti ĝisdatigita por sekvi YunoHost-ŝanĝojn", "backup_nothings_done": "Nenio por ŝpari", "backup_applying_method_custom": "Nomante la kutiman rezervan metodon '{metodo:s}' …", - "appslist_fetched": "Ĝisdatigita aplika listo {appslist:s} elprenita", + "appslist_fetched": "Ĝisdatigita aplika listo {appslist:s}", "backup_app_failed": "Ne eblis rezervi la programon '{app:s}'", "app_upgrade_some_app_failed": "Iuj aplikoj ne povis esti altgradigitaj", "app_start_remove": "Forigo de apliko {app} …", @@ -134,5 +134,423 @@ "ask_path": "Pado", "app_upgraded": "{app:s} altgradigita", "backup_deleted": "Rezerva forigita", - "backup_csv_addition_failed": "Ne povis aldoni dosierojn al sekurkopio en la CSV-dosiero" + "backup_csv_addition_failed": "Ne povis aldoni dosierojn al sekurkopio en la CSV-dosiero", + "dpkg_lock_not_available": "Ĉi tiu komando ne povas funkcii nun ĉar alia programo uzas la seruron de dpkg (la administrilo de paka sistemo)", + "migration_0003_yunohost_upgrade": "Komenci la ĝisdatigon de YunoHost-pako ... La migrado finiĝos, sed la efektiva ĝisdatigo okazos tuj poste. Post kiam la operacio finiĝos, vi eble devos ensaluti denove sur la retpaĝo.", + "domain_dyndns_root_unknown": "Nekonata radika domajno DynDNS", + "field_invalid": "Nevalida kampo '{:s}'", + "log_app_makedefault": "Faru '{}' la defaŭlta apliko", + "migration_0003_still_on_jessie_after_main_upgrade": "Io okazis malbone dum la ĉefa ĝisdatigo: Ĉu la sistemo ankoraŭ estas en Jessie‽ Por esplori la aferon, bonvolu rigardi {log}:s …", + "migration_0011_can_not_backup_before_migration": "La sekurkopio de la sistemo antaŭ la migrado malsukcesis. Migrado malsukcesis. Eraro: {error:s}", + "migration_0011_create_group": "Krei grupon por ĉiu uzanto…", + "backup_system_part_failed": "Ne eblis sekurkopi la sistemon de '{part:s}'", + "global_settings_setting_security_postfix_compatibility": "Kongruo vs sekureca kompromiso por la Postfix-servilo. Afektas la ĉifradojn (kaj aliajn aspektojn pri sekureco)", + "group_unknown": "La grupo '{group:s}' estas nekonata", + "mailbox_disabled": "Retpoŝto malŝaltita por uzanto {user:s}", + "migration_description_0011_setup_group_permission": "Agordu uzantogrupon kaj starigu permeson por programoj kaj servoj", + "migration_0011_backup_before_migration": "Krei sekurkopion de LDAP-datumbazo kaj agordojn antaŭ la efektiva migrado.", + "migration_0011_LDAP_config_dirty": "Similas ke vi agordis vian LDAP-agordon. Por ĉi tiu migrado la LDAP-agordo bezonas esti ĝisdatigita.\nVi devas konservi vian aktualan agordon, reintaligi la originalan agordon per funkciado de \"yunohost iloj regen-conf -f\" kaj reprovi la migradon", + "migration_0011_migrate_permission": "Migrado de permesoj de agordoj al aplikoj al LDAP…", + "migration_0011_migration_failed_trying_to_rollback": "Migrado malsukcesis ... provante reverti la sistemon.", + "migrations_dependencies_not_satisfied": "Ne eblas kuri migradon {id} ĉar unue vi devas ruli ĉi tiujn migradojn: {dependencies_id}", + "migrations_failed_to_load_migration": "Ne povis ŝarĝi migradon {id}: {error}", + "migrations_exclusive_options": "'--auto', '--skip' kaj '--force-rerun' estas reciproke ekskluzivaj ebloj.", + "migrations_must_provide_explicit_targets": "Vi devas provizi eksplicitajn celojn kiam vi uzas '--skip' aŭ '--force-rerun'", + "permission_update_failed": "Ne povis ĝisdatigi permeson '{permission}': {error}", + "permission_updated": "Ĝisdatigita \"{permission:s}\" rajtigita", + "permission_update_nothing_to_do": "Neniuj permesoj ĝisdatigi", + "tools_upgrade_cant_hold_critical_packages": "Ne povis teni kritikajn pakojn…", + "upnp_dev_not_found": "Neniu UPnP-aparato trovita", + "migration_description_0012_postgresql_password_to_md5_authentication": "Devigu PostgreSQL-aŭtentigon uzi MD5 por lokaj ligoj", + "migration_0011_done": "Migrado sukcesis. Vi nun kapablas administri uzantajn grupojn.", + "migration_0011_LDAP_update_failed": "Ne povis ĝisdatigi LDAP. Eraro: {error:s}", + "pattern_password": "Devas esti almenaŭ 3 signoj longaj", + "root_password_desynchronized": "La pasvorta administranto estis ŝanĝita, sed YunoHost ne povis propagandi ĉi tion al la radika pasvorto!", + "service_remove_failed": "Ne povis forigi la servon '{service:s}'", + "migration_0003_fail2ban_upgrade": "Komenci la ĝisdatigon Fail2Ban…", + "backup_permission": "Rezerva permeso por app {app:s}", + "log_user_group_delete": "Forigi grupon '{}'", + "log_user_group_update": "Ĝisdatigi grupon '{}'", + "migration_0005_postgresql_94_not_installed": "PostgreSQL ne estis instalita en via sistemo. Nenio por fari.", + "dyndns_provider_unreachable": "Ne povas atingi Dyndns-provizanton {provider}: ĉu via YunoHost ne estas ĝuste konektita al la interreto aŭ la dynette-servilo malŝaltiĝas.", + "good_practices_about_user_password": "Vi nun estas por difini novan uzantan pasvorton. La pasvorto devas esti almenaŭ 8 signoj - kvankam estas bone praktiki uzi pli longan pasvorton (t.e. pasfrazon) kaj / aŭ variaĵon de signoj (majuskloj, minuskloj, ciferoj kaj specialaj signoj).", + "group_updated": "Ĝisdatigita \"{group}\" grupo", + "group_already_exist": "Grupo {group} jam ekzistas", + "group_already_exist_on_system": "Grupo {group} jam ekzistas en la sistemaj grupoj", + "group_cannot_be_edited": "La grupo {group} ne povas esti redaktita permane.", + "group_cannot_be_deleted": "La grupo {group} ne povas esti forigita permane.", + "group_update_failed": "Ne povis ĝisdatigi la grupon '{group}': {error}", + "group_user_already_in_group": "Uzanto {user} jam estas en grupo {group}", + "group_user_not_in_group": "Uzanto {user} ne estas en grupo {group}", + "installation_complete": "Kompleta instalado", + "log_category_404": "La loga kategorio '{category}' ne ekzistas", + "log_permission_create": "Krei permeson '{}'", + "log_permission_delete": "Forigi permeson '{}'", + "log_permission_urls": "Ĝisdatigu URLojn rilatajn al permeso '{}'", + "log_user_group_create": "Krei grupon '{}'", + "log_user_permission_update": "Mise à jour des accès pour la permission '{}'", + "log_user_permission_reset": "Restarigi permeson '{}'", + "mail_forward_remove_failed": "Ne povis forigi retpoŝton plusendante '{mail:s}'", + "migration_0011_rollback_success": "Sistemo ruliĝis reen.", + "migration_0011_update_LDAP_database": "Ĝisdatigante LDAP-datumbazon…", + "migration_0011_update_LDAP_schema": "Ĝisdatigante LDAP-skemon…", + "migration_0011_failed_to_remove_stale_object": "Malsukcesis forigi neokazan objekton {dn}: {error}", + "migrations_already_ran": "Tiuj migradoj estas jam faritaj: {ids}", + "migrations_no_such_migration": "Estas neniu migrado nomata {id}", + "permission_already_allowed": "Grupo '{group}' jam havas permeson '{permission}' ebligita'", + "permission_already_disallowed": "Grupo '{group}' jam havas permeson '{permission}' malebligita'", + "permission_cannot_remove_main": "Forigo de ĉefa permeso ne rajtas", + "permission_creation_failed": "Ne povis krei permeson '{permission}': {error}", + "tools_update_failed_to_app_fetchlist": "Ne povis ĝisdatigi la aparatojn de YunoHost ĉar: {error}", + "user_already_exists": "Uzanto {uzanto} jam ekzistas", + "migrations_pending_cant_rerun": "Tiuj migradoj ankoraŭ estas pritraktataj, do ne plu rajtas esti ekzekutitaj: {ids}", + "migrations_running_forward": "Kuranta migrado {id}…", + "migrations_success_forward": "Migrado {id} kompletigita", + "operation_interrupted": "La operacio estis permane interrompita?", + "permission_created": "Permesita '{permission:s}' kreita", + "permission_deleted": "Permesita \"{permission:s}\" forigita", + "permission_deletion_failed": "Ne povis forigi permeson '{permission}': {error}", + "permission_not_found": "Permesita \"{permission:s}\" ne trovita", + "restore_not_enough_disk_space": "Ne sufiĉa spaco (spaco: {free_space:d} B, necesa spaco: {needed_space:d} B, sekureca marĝeno: {margin:d} B)", + "tools_upgrade_regular_packages": "Nun ĝisdatigi 'regulajn' (ne-yunohost-rilatajn) pakojn …", + "tools_upgrade_special_packages_explanation": "Ĉi tiu ago finiĝos, sed la fakta speciala ĝisdatigo daŭros en fono. Bonvolu ne komenci iun alian agon en via servilo en la sekvaj ~ 10 minutoj (depende de via aparata rapideco). Unufoje mi plenumis, vi eble devos ensaluti en la retpaĝo. La ĝisdatiga registro estos havebla en Iloj → Madero (sur la retpaĝo) aŭ tra 'yunohost-registro-listo' (el la komandlinio).", + "unrestore_app": "App '{app:s}' ne restarigos", + "group_created": "Grupo '{group}' kreita", + "group_creation_failed": "Ne povis krei la grupon '{group}': {error}", + "group_deleted": "Grupo '{group}' forigita", + "group_deletion_failed": "Ne povis forigi la grupon '{group}': {error}", + "migrations_not_pending_cant_skip": "Tiuj migradoj ankoraŭ ne estas pritraktataj, do ne eblas preterlasi: {ids}", + "permission_already_exist": "Permesita '{permission}' jam ekzistas", + "domain_created": "Domajno kreita", + "migrate_tsig_wait_2": "2 minutoj …", + "log_user_create": "Aldonu uzanton '{}'", + "ip6tables_unavailable": "Vi ne povas ludi kun ip6tabloj ĉi tie. Vi estas en ujo aŭ via kerno ne subtenas ĝin", + "mail_unavailable": "Ĉi tiu retpoŝta adreso estas rezervita kaj aŭtomate estos atribuita al la unua uzanto", + "certmanager_domain_dns_ip_differs_from_public_ip": "La DNS 'A' rekordo por la domajno '{domain:s}' diferencas de ĉi tiu IP-servilo. Se vi lastatempe modifis vian A-registron, bonvolu atendi ĝin propagandi (iuj DNS-disvastigaj kontroliloj estas disponeblaj interrete). (Se vi scias, kion vi faras, uzu '--no-checks' por malŝalti tiujn ĉekojn.)", + "tools_upgrade_special_packages_completed": "Plenumis la ĝisdatigon de pakaĵoj de YunoHost.\nPremu [Enter] por retrovi la komandlinion", + "log_remove_on_failed_install": "Forigu '{}' post malsukcesa instalado", + "regenconf_file_manually_modified": "La agorddosiero '{conf}' estis modifita permane kaj ne estos ĝisdatigita", + "regenconf_would_be_updated": "La agordo estus aktualigita por la kategorio '{category}'", + "certmanager_cert_install_success_selfsigned": "Mem-subskribita atestilo nun instalita por la domajno '{domain:s}'", + "global_settings_unknown_setting_from_settings_file": "Nekonata ŝlosilo en agordoj: '{setting_key:s}', forĵetu ĝin kaj konservu ĝin en /etc/yunohost/settings-unknown.json", + "regenconf_file_backed_up": "Agordodosiero '{conf}' estis rezervita al '{backup}'", + "migration_0007_cannot_restart": "SSH ne rekomencas post provi nuligi la migradan numeron 6.", + "migration_description_0006_sync_admin_and_root_passwords": "Sinkronigu admin kaj radikajn pasvortojn", + "updating_app_lists": "Akirante haveblajn ĝisdatigojn por aplikoj…", + "iptables_unavailable": "Vi ne povas ludi kun iptables ĉi tie. Vi estas en ujo aŭ via kerno ne subtenas ĝin", + "global_settings_cant_write_settings": "Ne eblis konservi agordojn, tial: {reason:s}", + "service_added": "La servo '{service:s}' aldonis", + "upnp_disabled": "UPnP malŝaltis", + "service_started": "Servo '{service:s}' komenciĝis", + "port_already_opened": "Haveno {port:d} estas jam malfermita por {ip_version:s} rilatoj", + "installation_failed": "Io okazis malbone kun la instalado", + "network_check_mx_ko": "DNS MX-rekordo ne estas agordita", + "migrate_tsig_wait_3": "1 minuto …", + "certmanager_conflicting_nginx_file": "Ne povis prepari domajnon por ACME-defio: la agordo de NGINX {filepath:s} konfliktas kaj unue devas esti forigita", + "upgrading_packages": "Ĝisdatigi pakojn…", + "custom_app_url_required": "Vi devas provizi URL por altgradigi vian kutimon app {app: s}", + "service_reload_failed": "Ne povis reŝargi la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}", + "packages_upgrade_failed": "Ne povis ĝisdatigi ĉiujn pakojn", + "hook_json_return_error": "Ne povis legi revenon de hoko {path:s}. Eraro: {msg:s}. Kruda enhavo: {raw_content}", + "dyndns_cron_removed": "DynDNS cron-laboro forigita", + "dyndns_key_not_found": "DNS-ŝlosilo ne trovita por la domajno", + "custom_appslist_name_required": "Vi devas doni nomon por via kutima app-listo", + "tools_upgrade_regular_packages_failed": "Ne povis ĝisdatigi pakojn: {packages_list}", + "service_start_failed": "Ne povis komenci la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}", + "service_reloaded": "Servo '{service:s}' reŝargita", + "system_upgraded": "Sistemo ĝisdatigita", + "domain_deleted": "Domajno forigita", + "certmanager_acme_not_configured_for_domain": "Atestilo por la domajno '{domain:s}' ne ŝajnas esti ĝuste instalita. Bonvolu ekzekuti 'cert-instali' por ĉi tiu regado unue.", + "migration_description_0009_decouple_regenconf_from_services": "Malkonstruu la regen-konf-mekanismon de servoj", + "user_update_failed": "Ne povis ĝisdatigi uzanton {user}: {error}", + "migration_description_0008_ssh_conf_managed_by_yunohost_step2": "Lasu la SSH-agordon estu administrata de YunoHost (paŝo 2, manlibro)", + "restore_confirm_yunohost_installed": "Ĉu vi vere volas restarigi jam instalitan sistemon? [{answers:s}]", + "pattern_positive_number": "Devas esti pozitiva nombro", + "monitor_stats_file_not_found": "Statistika dosiero ne trovita", + "certmanager_error_no_A_record": "Neniu DNS 'A' rekordo trovita por '{domain:s}'. Vi bezonas atentigi vian domajnan nomon al via maŝino por povi instali atestilon Lasu-Ĉifri. (Se vi scias, kion vi faras, uzu '--no-checks' por malŝalti tiujn ĉekojn.)", + "update_apt_cache_failed": "Ne eblis ĝisdatigi la kaŝmemoron de APT (paka administranto de Debian). Jen rubujo de la sources.list-linioj, kiuj povus helpi identigi problemajn liniojn:\n{sourcelist}", + "migrations_no_migrations_to_run": "Neniuj migradoj por funkcii", + "executing_command": "Plenumanta komandon '{command:s}' …", + "diagnosis_no_apps": "Neniu instalita apliko", + "certmanager_attempt_to_renew_nonLE_cert": "La atestilo por la domajno '{domain:s}' ne estas elsendita de Let's Encrypt. Ne eblas renovigi ĝin aŭtomate!", + "global_settings_setting_example_bool": "Ekzemplo bulea elekto", + "domain_dyndns_already_subscribed": "Vi jam abonis DynDNS-domajnon", + "log_letsencrypt_cert_renew": "Renovigu '{}' Ni ĉifru atestilon", + "migrate_tsig_start": "Detektita ŝlosila algoritmo nesufiĉa por TSIG-subskribo de la domajno '{domain}', komencanta migradon al la pli sekura HMAC-SHA-512", + "ldap_init_failed_to_create_admin": "LDAP-iniciato ne povis krei administran uzanton", + "backup_output_directory_required": "Vi devas provizi elirejan dosierujon por la sekurkopio", + "tools_upgrade_cant_unhold_critical_packages": "Ne povis malhelpi kritikajn pakojn…", + "diagnosis_monitor_disk_error": "Ne povis monitori diskojn: {error}", + "log_link_to_log": "Plena ŝtipo de ĉi tiu operacio: ' {desc} '", + "service_no_log": "Neniu registro por montri por servo '{service:s}'", + "global_settings_cant_serialize_settings": "Ne eblis serialigi datumojn pri agordoj, motivo: {reason:s}", + "backup_running_hooks": "Kurado de apogaj hokoj …", + "package_not_installed": "Pako '{pkgname}' ne estas instalita", + "certmanager_domain_unknown": "Nekonata domajno '{domain:s}'", + "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_persistent_conf_write_error": "Ne povis konservi konstantan SSOwat-agordon: {error:s}. Redakti /etc/ssowat/conf.json.persistent dosiero por ripari la Jaks-sintakson", + "migration_description_0007_ssh_conf_managed_by_yunohost_step1": "Lasu la SSH-agordon estu administrata de YunoHost (paŝo 1, aŭtomata)", + "migration_0009_not_needed": "Ĉi tiu migrado jam iel okazis ... (?) Saltado.", + "ssowat_conf_generated": "SSOwat-agordo generita", + "migrate_tsig_wait": "Atendante tri minutojn por ke la servilo DynDNS enkalkulu la novan ŝlosilon …", + "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`.", + "recommend_to_add_first_user": "La postinstalo finiĝis, sed YunoHost bezonas almenaŭ unu uzanton por funkcii ĝuste, vi devas aldoni unu uzante 'yunohost user create ' aŭ fari ĝin de la administra interfaco.", + "certmanager_cert_signing_failed": "Ne povis subskribi la novan atestilon", + "migration_description_0003_migrate_to_stretch": "Altgradigu la sistemon al Debian Stretch kaj YunoHost 3.0", + "log_tools_upgrade": "Ĝisdatigu sistemajn pakaĵojn", + "network_check_smtp_ko": "Ekstera retpoŝto (SMTP-haveno 25) ŝajnas esti blokita de via reto", + "log_available_on_yunopaste": "Ĉi tiu protokolo nun haveblas per {url}", + "certmanager_http_check_timeout": "Ekdifinita kiam servilo provis kontakti sin per HTTP per publika IP-adreso (domajno '{domain:s}' kun IP '{ip:s}'). Vi eble spertas haŭtoproblemon, aŭ la fajroŝirmilo / enkursigilo antaŭ via servilo miskonfiguras.", + "pattern_port_or_range": "Devas esti valida haveno-nombro (t.e. 0-65535) aŭ gamo da havenoj (t.e. 100:200)", + "migrations_loading_migration": "Ŝarĝante migradon {id}…", + "port_available": "Haveno {port:d} estas havebla", + "pattern_mailbox_quota": "Devas esti grandeco kun la sufikso b/k/M/G/T aŭ 0 por ne havi kvoton", + "migration_0008_general_disclaimer": "Por plibonigi la sekurecon de via servilo, rekomendas lasi YunoHost administri la SSH-agordon. Via nuna SSH-aranĝo diferencas de la rekomendo. Se vi lasas YunoHost agordi ĝin, la maniero per kiu vi konektas al via servilo per SSH ŝanĝiĝos tiel:", + "user_deletion_failed": "Ne povis forigi uzanton {user}: {error}", + "backup_with_no_backup_script_for_app": "La app '{app:s}' ne havas sekretan skripton. Ignorante.", + "service_regen_conf_is_deprecated": "'yunohost service regen-conf' malakceptas! Bonvolu uzi anstataŭe 'yunohost tools regen-conf'.", + "global_settings_key_doesnt_exists": "La ŝlosilo '{settings_key:s}' ne ekzistas en la tutmondaj agordoj, vi povas vidi ĉiujn disponeblajn klavojn per uzado de 'yunohost settings list'", + "dyndns_no_domain_registered": "Neniu domajno registrita ĉe DynDNS", + "dyndns_could_not_check_available": "Ne povis kontroli ĉu {domain:s} haveblas sur {provider:s}.", + "log_app_removelist": "Forigu aplikan liston", + "global_settings_setting_example_enum": "Ekzemplo enum elekto", + "hook_exec_not_terminated": "Skripto ne finiĝis ĝuste: {path:s}", + "service_stopped": "'{service:s}' servo ĉesis", + "restore_failed": "Ne povis restarigi sistemon", + "confirm_app_install_danger": "Danĝero! Ĉi tiu apliko estas konata ankoraŭ eksperimenta (se ne eksplicite ne funkcias)! Vi probable ne devas instali ĝin krom se vi scias kion vi faras. NENIU SUBTENO estos provizita se ĉi tiu app ne funkcias aŭ rompas vian sistemon ... Se vi pretas riski ĉiuokaze, tajpu '{answers: s}'", + "log_operation_unit_unclosed_properly": "Operaciumo ne estis fermita ĝuste", + "upgrade_complete": "Ĝisdatigo kompleta", + "upnp_enabled": "UPnP ŝaltis", + "mailbox_used_space_dovecot_down": "La retpoŝta servo de Dovecot devas funkcii, se vi volas akcepti uzitan poŝtan spacon", + "restore_system_part_failed": "Ne povis restarigi la sisteman parton '{part:s}'", + "diagnosis_monitor_system_error": "Ne povis monitori sistemon: {error}", + "service_stop_failed": "Ne povis maldaŭrigi la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}", + "unbackup_app": "App '{app:s}' ne konserviĝos", + "updating_apt_cache": "Akirante haveblajn ĝisdatigojn por sistemaj pakoj…", + "tools_upgrade_at_least_one": "Bonvolu specifi '--apps' aŭ '--system'", + "service_already_stopped": "La servo '{service:s}' jam ĉesis", + "unit_unknown": "Nekonata unuo '{unit:s}'", + "migration_0003_modified_files": "Bonvolu noti, ke la jenaj dosieroj estis trovitaj mane kaj modifitaj kaj povus esti anstataŭigitaj sekve de la ĝisdatigo: {manual_modified_files}", + "tools_upgrade_cant_both": "Ne eblas ĝisdatigi ambaŭ sistemon kaj programojn samtempe", + "restore_extracting": "Eltirante bezonatajn dosierojn el la ar theivo…", + "upnp_port_open_failed": "Ne povis malfermi havenon per UPnP", + "log_app_upgrade": "Ĝisdatigu la aplikon '{}'", + "log_help_to_get_failed_log": "La operacio '{desc}' ne povis finiĝi. Bonvolu dividi la plenan ŝtipon de ĉi tiu operacio per la komando 'yunohost log display {name} --share' por akiri helpon", + "migration_description_0002_migrate_to_tsig_sha256": "Plibonigu sekurecon de DynDNS TSIG-ĝisdatigoj per SHA-512 anstataŭ MD5", + "monitor_disabled": "Servila monitorado nun malŝaltis", + "pattern_port": "Devas esti valida havena numero (t.e. 0-65535)", + "port_already_closed": "Haveno {port:d} estas jam fermita por {ip_version:s} rilatoj", + "hook_name_unknown": "Nekonata hoko-nomo '{name:s}'", + "migration_0003_system_not_fully_up_to_date": "Via sistemo ne estas plene ĝisdata. Bonvolu plenumi regulan ĝisdatigon antaŭ ol ruli la migradon al Stretch.", + "dyndns_could_not_check_provide": "Ne povis kontroli ĉu {provider:s} povas provizi {domain:s}.", + "dyndns_cron_remove_failed": "Ne povis forigi la cron-laboron DynDNS ĉar: {error}", + "pattern_listname": "Devas esti nur alfanumeraj kaj substrekaj signoj", + "restore_nothings_done": "Nenio estis restarigita", + "log_tools_postinstall": "Afiŝu vian servilon YunoHost", + "dyndns_unavailable": "La domajno '{domain:s}' ne haveblas.", + "experimental_feature": "Averto: Ĉi tiu funkcio estas eksperimenta kaj ne konsiderata stabila, vi ne uzu ĝin krom se vi scias kion vi faras.", + "root_password_replaced_by_admin_password": "Via radika pasvorto estis anstataŭigita per via administra pasvorto.", + "ssowat_persistent_conf_read_error": "Ne povis legi konstantan SSOwat-agordon: {error:s}. Redakti /etc/ssowat/conf.json.persistent dosiero por ripari la Jaks-sintakson", + "migration_description_0005_postgresql_9p4_to_9p6": "Migru datumbazojn de PostgreSQL 9.4 al 9.6", + "migration_0008_root": "• Vi ne povos konekti kiel radiko per SSH. Anstataŭe vi uzu la administran uzanton;", + "package_unknown": "Nekonata pako '{pkgname}'", + "domain_unknown": "Nekonata domajno", + "global_settings_setting_security_password_user_strength": "Uzanto pasvorta forto", + "restore_may_be_not_enough_disk_space": "Via sistemo ŝajnas ne havi sufiĉe da spaco (free:{free_space:d} B, necesa spaco: {needed_space:d} B, sekureca marĝeno: {margin:d} B)", + "log_corrupted_md_file": "La YAD-metadata dosiero asociita kun protokoloj estas damaĝita: '{md_file}\nEraro: {error} '", + "downloading": "Elŝutante …", + "user_deleted": "Uzanto forigita", + "service_enable_failed": "Ne eblis ŝalti la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}", + "tools_upgrade_special_packages": "Nun ĝisdatigi 'specialajn' (rilatajn al yunohost)…", + "domains_available": "Haveblaj domajnoj:", + "dyndns_registered": "Registrita domajno DynDNS", + "service_description_fail2ban": "Protektas kontraŭ bruta forto kaj aliaj specoj de atakoj de la interreto", + "file_does_not_exist": "La dosiero {path:s} ne ekzistas.", + "yunohost_not_installed": "YunoHost estas malĝuste aŭ ne ĝuste instalita. Bonvolu prilabori 'yunohost tools postinstall'", + "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 estas instalita, sed ne postgresql 9.6‽ Io stranga eble okazis en via sistemo: (…", + "restore_removing_tmp_dir_failed": "Ne povis forigi malnovan provizoran dosierujon", + "certmanager_cannot_read_cert": "Io malbona okazis, kiam mi provis malfermi aktualan atestilon por domajno {domain:s} (dosiero: {file:s}), kialo: {reason:s}", + "service_removed": "'{service:s}' servo forigita", + "certmanager_hit_rate_limit": "Tro multaj atestiloj jam eldonitaj por ĉi tiu ĝusta aro de domajnoj {domain:s} antaŭ nelonge. Bonvolu reprovi poste. Vidu https://letsencrypt.org/docs/rate-limits/ por pliaj detaloj", + "migration_0005_not_enough_space": "Disponigu sufiĉan spacon en {path} por ruli la migradon.", + "pattern_firstname": "Devas esti valida antaŭnomo", + "migration_description_0010_migrate_to_apps_json": "Forigu malvalorigitajn aparatojn kaj uzu anstataŭe la novan unuigitan liston \"apps.json\"", + "domain_cert_gen_failed": "Ne povis generi atestilon", + "regenconf_file_kept_back": "La agorda dosiero '{conf}' estas atendita forigi per regen-conf (kategorio {category}), sed ĝi estis konservita.", + "migrate_tsig_wait_4": "30 sekundoj …", + "backup_with_no_restore_script_for_app": "La apliko \"{app:s}\" ne havas restarigan skripton, vi ne povos aŭtomate restarigi la sekurkopion de ĉi tiu apliko.", + "log_letsencrypt_cert_install": "Instalu atestilon Ni ĉifru sur '{}' regado", + "log_dyndns_update": "Ĝisdatigu la IP asociita kun via subdominio YunoHost '{}'", + "firewall_reload_failed": "Ne eblis reŝargi la firewall", + "confirm_app_install_warning": "Averto: Ĉi tiu aplikaĵo povas funkcii, sed ne bone integras en YunoHost. Iuj funkcioj kiel ekzemple aliĝilo kaj sekurkopio / restarigo eble ne haveblos. Instali ĉiuokaze? [{answers: s}] ", + "log_user_delete": "Forigi uzanton '{}'", + "dyndns_ip_updated": "Ĝisdatigis vian IP sur DynDNS", + "regenconf_up_to_date": "La agordo jam estas ĝisdatigita por kategorio '{category}'", + "migration_0003_patching_sources_list": "Patching the sources.lists …", + "global_settings_setting_security_ssh_compatibility": "Kongruo vs sekureca kompromiso por la SSH-servilo. Afektas la ĉifradojn (kaj aliajn aspektojn pri sekureco)", + "migrations_need_to_accept_disclaimer": "Por funkciigi la migradon {id}, via devas akcepti la sekvan malakcepton:\n---\n{malavantaĝo}\n---\nSe vi akceptas funkcii la migradon, bonvolu rekonduki la komandon kun la opcio '--accept-disclaimer'.", + "regenconf_file_remove_failed": "Ne povis forigi la agordodosieron '{conf}'", + "not_enough_disk_space": "Ne sufiĉe libera spaco sur '{path:s}'", + "migration_0006_disclaimer": "YunoHost nun atendas ke pasvortoj kaj administrantoj estu sinkronigitaj. Per ekzekuto de ĉi tiu migrado, via radika pasvorto estos anstataŭigita per administra pasvorto.", + "dyndns_ip_update_failed": "Ne povis ĝisdatigi IP-adreson al DynDNS", + "migration_description_0004_php5_to_php7_pools": "Rekonfigu la PHP-naĝejojn por uzi PHP 7 anstataŭ 5", + "monitor_glances_con_failed": "Ne povis konektiĝi al servilo de Glances", + "ssowat_conf_updated": "SSOwat-agordo ĝisdatigita", + "log_link_to_failed_log": "Ne povis plenumi la operacion '{desc}'. Bonvolu provizi la plenan protokolon de ĉi tiu operacio per alklakante ĉi tie por akiri helpon", + "log_app_fetchlist": "Aldonu liston de aplikoj", + "user_home_creation_failed": "Ne povis krei dosierujon \"home\" por uzanto", + "pattern_backup_archive_name": "Devas esti valida dosiernomo kun maksimume 30 signoj, alfanombraj kaj -_. signoj nur", + "restore_cleaning_failed": "Ne eblis purigi la adresaron de provizora restarigo", + "dyndns_registration_failed": "Ne povis registri DynDNS-domajnon: {error:s}", + "migration_0003_not_jessie": "La nuna Debian-distribuo ne estas Jessie!", + "user_unknown": "Nekonata uzanto: {user:s}", + "migrations_to_be_ran_manually": "Migrado {id} devas funkcii permane. Bonvolu iri al Iloj → Migradoj en la retpaĝa paĝo, aŭ kuri `yunohost tools migrations migrate`.", + "migration_0008_warning": "Se vi komprenas tiujn avertojn kaj konsentas lasi YunoHost pretervidi vian nunan agordon, faru la migradon. Alie, vi ankaŭ povas salti la migradon - kvankam ĝi ne rekomendas.", + "certmanager_cert_renew_success": "Ni Ĉifru atestilon renovigitan por la domajno '{domain:s}'", + "global_settings_reset_success": "Antaŭaj agordoj nun estas rezervitaj al {path:s}", + "pattern_domain": "Devas esti valida domajna nomo (t.e. mia-domino.org)", + "package_unexpected_error": "Neatendita eraro okazis prilaborante la pakon '{pkgname}'", + "dyndns_key_generating": "Generi DNS-ŝlosilon ... Eble daŭros iom da tempo.", + "restore_running_app_script": "Restarigi la programon '{app:s}'…", + "migrations_skip_migration": "Salti migradon {id}…", + "mysql_db_init_failed": "MysQL-datumbazo init malsukcesis", + "regenconf_file_removed": "Agordodosiero '{conf}' forigita", + "log_tools_shutdown": "Enŝaltu vian servilon", + "password_too_simple_3": "La pasvorto bezonas almenaŭ 8 signojn kaj enhavas ciferon, majusklon, pli malaltan kaj specialajn signojn", + "migration_0003_general_warning": "Bonvolu noti, ke ĉi tiu migrado estas delikata operacio. La teamo de YunoHost faris sian plej bonan revizii kaj testi ĝin, sed la migrado eble ankoraŭ rompos partojn de la sistemo aŭ ĝiaj programoj.\n\nTial oni rekomendas al:\n - Elfari kopion de iuj kritikaj datumoj aŭ app. Pliaj informoj pri https://yunohost.org/backup;\n - Paciencu post lanĉo de la migrado: Depende de via interreta konekto kaj aparataro, eble daŭros kelkaj horoj ĝis ĉio ĝisdatigi.\n\nAldone, la haveno por SMTP, uzata de eksteraj retpoŝtaj klientoj (kiel Thunderbird aŭ K9-Mail) estis ŝanĝita de 465 (SSL / TLS) al 587 (STARTTLS). La malnova haveno (465) aŭtomate fermiĝos, kaj la nova haveno (587) malfermiĝos en la fajrejo. Vi kaj viaj uzantoj * devos adapti la agordon de viaj retpoŝtaj klientoj laŭe.", + "diagnosis_kernel_version_error": "Ne povis akiri la kernan version: {error}", + "global_settings_setting_example_int": "Ekzemple int elekto", + "backup_output_symlink_dir_broken": "Vi havas rompitan simbolon anstataŭ via arkiva dosierujo '{path:s}'. Vi eble havas specifan agordon por sekurkopi viajn datumojn en alia dosiersistemo, ĉi-kaze vi probable forgesis remeti aŭ enŝovi vian malmolan disko aŭ ŝlosilon USB.", + "good_practices_about_admin_password": "Vi nun estas por difini novan administran pasvorton. La pasvorto devas esti almenaŭ 8 signoj - kvankam estas bone praktiki uzi pli longan pasvorton (t.e. pasfrazon) kaj / aŭ uzi variaĵon de signoj (majuskloj, minuskloj, ciferoj kaj specialaj signoj).", + "certmanager_attempt_to_renew_valid_cert": "La atestilo por la domajno '{domain:s}' ne finiĝos! (Vi eble uzos --force se vi scias kion vi faras)", + "restore_running_hooks": "Kurantaj restarigaj hokoj…", + "regenconf_pending_applying": "Aplikante pritraktata agordo por kategorio '{category}'…", + "service_description_dovecot": "Permesas al retpoŝtaj klientoj aliri / serĉi retpoŝton (per IMAP kaj POP3)", + "domain_dns_conf_is_just_a_recommendation": "Ĉi tiu komando montras al vi la *rekomenditan* agordon. Ĝi efektive ne agordas la DNS-agordon por vi. Via respondeco agordi vian DNS-zonon en via registristo laŭ ĉi tiu rekomendo.", + "backup_php5_to_php7_migration_may_fail": "Ne povis konverti vian ar archiveivon por subteni PHP 7, vi eble ne povas restarigi viajn PHP-programojn (kialo: {error:s})", + "log_backup_restore_system": "Restarigi sistemon de rezerva arkivo", + "log_app_change_url": "Ŝanĝu la URL de apliko '{}'", + "service_already_started": "La servo '{service:s}' estas jam komencita", + "license_undefined": "nedifinita", + "global_settings_setting_security_password_admin_strength": "Admin pasvorta forto", + "service_reload_or_restart_failed": "Ne povis reŝargi aŭ rekomenci la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}", + "migrations_list_conflict_pending_done": "Vi ne povas uzi ambaŭ '--previous' kaj '--done' samtempe.", + "maindomain_changed": "La ĉefa domajno nun ŝanĝiĝis", + "server_shutdown_confirm": "La servilo haltos tuj, ĉu vi certas? [{answers:s}]", + "monitor_period_invalid": "Nevalida tempoperiodo", + "log_backup_restore_app": "Restarigu '{}' de rezerva ar archiveivo", + "log_does_exists": "Ne estas operacio-registro kun la nomo '{log}', uzu 'yunohost loglist' por vidi ĉiujn disponeblajn operaciojn", + "service_add_failed": "Ne povis aldoni la servon '{service:s}'", + "pattern_password_app": "Bedaŭrinde, pasvortoj ne povas enhavi jenajn signojn: {forbidden_chars}", + "this_action_broke_dpkg": "Ĉi tiu ago rompis dpkg / APT (la administrantoj pri la paka sistemo) ... Vi povas provi solvi ĉi tiun problemon per konekto per SSH kaj funkcianta `sudo dpkg --configure -a`.", + "log_regen_conf": "Regeneri sistemajn agordojn '{}'", + "restore_hook_unavailable": "La restariga skripto por '{part:s}' ne haveblas en via sistemo kaj ankaŭ ne en la ar theivo", + "network_check_smtp_ok": "Eksteren retpoŝto (SMTP-haveno 25) ne estas blokita", + "log_dyndns_subscribe": "Aboni al YunoHost-subdominio '{}'", + "password_too_simple_4": "La pasvorto bezonas almenaŭ 12 signojn kaj enhavas ciferon, majuskle, pli malaltan kaj specialajn signojn", + "migration_0003_main_upgrade": "Komencanta ĉefa ĝisdatigo …", + "user_info_failed": "Ne povis akiri informojn pri uzanto", + "regenconf_file_updated": "Agordodosiero '{conf}' ĝisdatigita", + "log_help_to_get_log": "Por vidi la protokolon de la operacio '{desc}', uzu la komandon 'yunohost log display {name}'", + "global_settings_setting_security_nginx_compatibility": "Kongruo vs sekureca kompromiso por la TTT-servilo NGINX. Afektas la ĉifradojn (kaj aliajn aspektojn pri sekureco)", + "no_internet_connection": "Servilo ne konektita al la interreto", + "migration_0008_dsa": "• La DSA-ŝlosilo estos malŝaltita. Tial vi eble bezonos nuligi spuran averton de via SSH-kliento kaj revizii la fingrospuron de via servilo;", + "migration_0003_restoring_origin_nginx_conf": "Fileia dosiero /etc/nginx/nginx.conf estis iel redaktita. La migrado reaperos unue al sia originala stato ... La antaŭa dosiero estos havebla kiel {backup_dest}.", + "migrate_tsig_end": "Migrado al HMAC-SHA-512 finiĝis", + "restore_complete": "Restarigita", + "certmanager_couldnt_fetch_intermediate_cert": "Ekvilibrigita kiam vi provis ricevi interajn atestilojn de Let's Encrypt. Atestita instalado / renovigo nuligita - bonvolu reprovi poste.", + "hook_exec_failed": "Ne povis funkcii skripto: {path:s}", + "global_settings_cant_open_settings": "Ne eblis malfermi agordojn, tial: {reason:s}", + "user_created": "Uzanto kreita", + "service_description_avahi-daemon": "Permesas al vi atingi vian servilon uzante 'yunohost.local' en via loka reto", + "certmanager_attempt_to_replace_valid_cert": "Vi provas anstataŭigi bonan kaj validan atestilon por domajno {domajno:s}! (Uzu --forte pretervidi)", + "monitor_stats_period_unavailable": "Ne ekzistas disponeblaj statistikoj por la periodo", + "regenconf_updated": "Agordo por kategorio '{category}' ĝisdatigita", + "update_apt_cache_warning": "Io iris malbone dum la ĝisdatigo de la kaŝmemoro de APT (paka administranto de Debian). Jen rubujo de la sources.list-linioj, kiuj povus helpi identigi problemajn liniojn:\n{sourcelist}", + "regenconf_dry_pending_applying": "Kontrolado de pritraktata agordo, kiu estus aplikita por kategorio '{category}'…", + "regenconf_file_copy_failed": "Ne povis kopii la novan agordodosieron '{new}' al '{conf}'", + "global_settings_setting_example_string": "Ekzemple korda elekto", + "restore_already_installed_app": "App kun la ID '{app:s}' estas jam instalita", + "mountpoint_unknown": "Nekonata montpunkto", + "log_tools_maindomain": "Faru de '{}' la ĉefa domajno", + "maindomain_change_failed": "Ne povis ŝanĝi la ĉefan domajnon", + "mail_domain_unknown": "Nekonata retpoŝtadreso por domajno '{domain:s}'", + "migrations_cant_reach_migration_file": "Ne povis aliri migrajn dosierojn ĉe la vojo% s", + "pattern_email": "Devas esti valida retpoŝtadreso (t.e.iu@domain.org)", + "mail_alias_remove_failed": "Ne povis forigi retpoŝton alias '{mail:s}'", + "regenconf_file_manually_removed": "La dosiero de agordo '{conf}' estis forigita permane, kaj ne estos kreita", + "monitor_enabled": "Servila monitorado nun ŝaltis", + "domain_exists": "La domajno jam ekzistas", + "migration_description_0001_change_cert_group_to_sslcert": "Ŝanĝu grupajn permesojn de 'metronomo' al 'ssl-cert'", + "mysql_db_creation_failed": "MySQL-datumbazkreado malsukcesis", + "ldap_initialized": "LDAP inicializis", + "migrate_tsig_not_needed": "Vi ne ŝajnas uzi DynDNS-domajnon, do neniu migrado necesas.", + "certmanager_domain_cert_not_selfsigned": "La atestilo por domajno {domajno:s} ne estas mem-subskribita. Ĉu vi certas, ke vi volas anstataŭigi ĝin? (Uzu '--force' por fari tion.)", + "certmanager_unable_to_parse_self_CA_name": "Ne povis trapasi nomon de mem-subskribinta aŭtoritato (dosiero: {file: s})", + "log_selfsigned_cert_install": "Instalu mem-subskribitan atestilon sur '{}' domajno", + "log_tools_reboot": "Reklamu vian servilon", + "certmanager_cert_install_success": "Ni Ĉifru atestilon nun instalitan por la domajno '{domain:s}'", + "global_settings_bad_choice_for_enum": "Malbona elekto por agordo {setting:s}, ricevita '{choice:s}', sed disponeblaj elektoj estas: {available_choices:s}", + "server_shutdown": "La servilo haltos", + "log_tools_migrations_migrate_forward": "Migri antaŭen", + "migration_0008_no_warning": "Neniu grava risko identigita pri superregado de via SSH-agordo, tamen oni ne povas esti absolute certa;)! Ekfunkciu la migradon por superregi ĝin. Alie, vi ankaŭ povas salti la migradon - kvankam ĝi ne rekomendas.", + "regenconf_now_managed_by_yunohost": "La agorda dosiero '{conf}' nun estas administrata de YunoHost (kategorio {category}).", + "server_reboot_confirm": "Ĉu la servilo rekomencos tuj, ĉu vi certas? [{answers:s}]", + "log_app_install": "Instalu la aplikon '{}'", + "service_description_dnsmasq": "Traktas rezolucion de domajna nomo (DNS)", + "global_settings_unknown_type": "Neatendita situacio, la agordo {setting:s} ŝajnas havi la tipon {unknown_type:s} sed ĝi ne estas tipo subtenata de la sistemo.", + "migration_0003_problematic_apps_warning": "Bonvolu noti, ke la sekvaj eventuale problemaj instalitaj apps estis detektitaj. Ĝi aspektas, ke tiuj ne estis instalitaj de aparato aŭ ne estas markitaj kiel \"funkciantaj\". Tial ne eblas garantii, ke ili ankoraŭ funkcios post la ĝisdatigo: {problematic_apps}", + "domain_hostname_failed": "Ne povis agordi novan gastigilon. Ĉi tio eble kaŭzos problemon poste (eble bone).", + "server_reboot": "La servilo rekomenciĝos", + "regenconf_failed": "Ne povis regeneri la agordon por kategorio(j): {categories}", + "domain_uninstall_app_first": "Unu aŭ pluraj programoj estas instalitaj en ĉi tiu domajno. Bonvolu malinstali ilin antaŭ ol daŭrigi la domajnan forigon", + "port_unavailable": "Haveno {port:d} ne haveblas", + "service_unknown": "Nekonata servo '{service:s}'", + "migration_0003_start": "Komencante migradon al Stretch. La protokoloj haveblos en {logfile}.", + "monitor_stats_no_update": "Neniuj monitoradaj statistikoj ĝisdatigi", + "domain_deletion_failed": "Ne povis forigi domajnon {domain}: {error}", + "log_user_update": "Ĝisdatigu uzantinformojn de '{}'", + "user_creation_failed": "Ne povis krei uzanton {user}: {error}", + "migrations_migration_has_failed": "Migrado {id} ne kompletigis, abolis. Eraro: {exception}", + "done": "Farita", + "log_domain_remove": "Forigi domon '{}' de agordo de sistemo", + "monitor_not_enabled": "Servila monitorado estas malŝaltita", + "diagnosis_debian_version_error": "Ne povis retrovi la Debianan version: {error}", + "hook_list_by_invalid": "Ĉi tiu posedaĵo ne povas esti uzata por listigi hokojn", + "confirm_app_install_thirdparty": "Danĝero! Ĉi tiu apliko ne estas parto de la aplika katalogo de Yunohost. Instali triajn aplikojn povas kompromiti la integrecon kaj sekurecon de via sistemo. Vi probable ne devas instali ĝin krom se vi scias kion vi faras. NENIU SUBTENO estos provizita se ĉi tiu app ne funkcias aŭ rompas vian sistemon ... Se vi pretas riski ĉiuokaze, tajpu '{answers: s}'", + "global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Permesu uzon de (malaktuala) DSA-hostkey por la agordo de daemon SSH", + "dyndns_domain_not_provided": "Provizanto DynDNS {provider:s} ne povas provizi domajnon {domain:s}.", + "backup_unable_to_organize_files": "Ne povis uzi la rapidan metodon por organizi dosierojn en la ar archiveivo", + "password_too_simple_2": "La pasvorto bezonas almenaŭ 8 signojn kaj enhavas ciferon, majusklojn kaj minusklojn", + "executing_script": "Plenumanta skripto '{script:s}' …", + "service_cmd_exec_failed": "Ne povis plenumi la komandon '{command:s}'", + "migration_0007_cancelled": "YunoHost ne plibonigis la administradon de via SSH-konf.", + "migrate_tsig_failed": "Ne povis migri la DynDNS-domajnon '{domain}' al HMAC-SHA-512, ruliĝante. Eraro: {error_code}, {error}", + "pattern_lastname": "Devas esti valida familinomo", + "service_enabled": "'{service:s}' servo malŝaltita", + "certmanager_no_cert_file": "Ne povis legi la atestan dosieron por la domajno {domain:s} (dosiero: {file:s})", + "migration_0008_port": "• Vi devos konekti uzante la havenon 22 anstataŭ via nuna kutimo SSH-haveno. Sentu vin libera reconfiguri ĝin;", + "domain_creation_failed": "Ne povis krei domajnon {domain}: {error}", + "certmanager_domain_http_not_working": "Ŝajnas ke la domajno {domain:s} ne atingeblas per HTTP. Kontrolu, ke via DNS kaj NGINX-agordo ĝustas", + "domain_cannot_remove_main": "Ne eblas forigi ĉefan domajnon. Fiksu unu unue", + "service_reloaded_or_restarted": "'{service:s}' servo reŝarĝis aŭ rekomencis", + "mysql_db_initialized": "La datumbazo MySQL jam estas pravalorizita", + "log_domain_add": "Aldonu '{}' domajnon en sisteman agordon", + "global_settings_bad_type_for_setting": "Malbona tipo por agordo {setting:s}, ricevita {received_type:s}, atendata {expected_type:s}", + "unlimit": "Neniu kvoto", + "dyndns_cron_installed": "Kreita laboro DynDNS cron", + "system_username_exists": "Uzantnomo jam ekzistas en la listo de uzantoj de sistemo", + "firewall_reloaded": "Fajroŝirmilo reŝarĝis", + "service_restarted": "'{service:s}' servo rekomencis", + "pattern_username": "Devas esti minuskulaj literoj kaj minuskloj nur", + "extracting": "Eltirante…", + "restore_app_failed": "Ne povis restarigi la programon '{app:s}'", + "yunohost_configured": "YunoHost nun agordis", + "certmanager_self_ca_conf_file_not_found": "Ne povis trovi agorddosieron por mem-subskriba aŭtoritato (dosiero: {file:s})", + "log_app_remove": "Forigu la aplikon '{}'", + "service_restart_failed": "Ne povis rekomenci la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}", + "firewall_rules_cmd_failed": "Iuj komandoj pri fajroŝirmilo malsukcesis. Pliaj informoj en ensaluto.", + "certmanager_certificate_fetching_or_enabling_failed": "Provante uzi la novan atestilon por {domain:s} ne funkciis …" } From 8cdea18991b60e4489d93d2b861434ca3103bd53 Mon Sep 17 00:00:00 2001 From: advocatux Date: Fri, 4 Oct 2019 18:14:15 +0000 Subject: [PATCH 058/127] Translated using Weblate (Spanish) Currently translated at 100.0% (553 of 553 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/es/ --- locales/es.json | 59 +++++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/locales/es.json b/locales/es.json index 02f46652b..aeee0ff7a 100644 --- a/locales/es.json +++ b/locales/es.json @@ -29,7 +29,7 @@ "app_unsupported_remote_type": "Tipo remoto no soportado por la aplicación", "app_upgrade_failed": "No se pudo actualizar {app:s}", "app_upgraded": "Actualizado {app:s}", - "appslist_fetched": "Obtenida lista de aplicaciones {appslist:s} actualizada", + "appslist_fetched": "Lista de aplicaciones {appslist:s} actualizada", "appslist_removed": "Eliminada la lista de aplicaciones {appslist:s}", "appslist_retrieve_error": "No se puede recuperar la lista remota de aplicaciones {appslist:s}: {error:s}", "appslist_unknown": "Lista de aplicaciones {appslist:s} desconocida.", @@ -74,9 +74,9 @@ "dnsmasq_isnt_installed": "Parece que dnsmasq no está instalado, ejecute «apt-get remove bind9 && apt-get install it»", "domain_cert_gen_failed": "No se pudo generar el certificado", "domain_created": "Dominio creado", - "domain_creation_failed": "No se pudo crear el dominio", + "domain_creation_failed": "No se pudo crear el dominio {domain}: {error}", "domain_deleted": "Dominio eliminado", - "domain_deletion_failed": "No se pudo eliminar el dominio", + "domain_deletion_failed": "No se pudo eliminar el dominio {domain}: {error}", "domain_dyndns_already_subscribed": "Ya se ha suscrito a un dominio de DynDNS", "domain_dyndns_invalid": "Este dominio no se puede usar con DynDNS", "domain_dyndns_root_unknown": "Dominio raíz de DynDNS desconocido", @@ -228,13 +228,13 @@ "upnp_enabled": "UPnP activado", "upnp_port_open_failed": "No se pudo abrir el puerto vía UPnP", "user_created": "Usuario creado", - "user_creation_failed": "No se pudo crear el usuario", + "user_creation_failed": "No se pudo crear el usuario {user}: {error}", "user_deleted": "Usuario eliminado", - "user_deletion_failed": "No se pudo eliminar el usuario", + "user_deletion_failed": "No se pudo eliminar el usuario {user}: {error}", "user_home_creation_failed": "No se pudo crear la carpeta «home» para el usuario", "user_info_failed": "No se pudo obtener la información del usuario", "user_unknown": "Usuario desconocido: {user:s}", - "user_update_failed": "No se pudo cambiar la información del usuario", + "user_update_failed": "No se pudo actualizar el usuario {user}: {error}", "user_updated": "Cambiada la información de usuario", "yunohost_already_installed": "YunoHost ya está instalado", "yunohost_ca_creation_failed": "No se pudo crear la autoridad de certificación", @@ -398,16 +398,16 @@ "remove_main_permission_not_allowed": "No se permite eliminar el permiso principal", "recommend_to_add_first_user": "La posinstalación ha terminado pero YunoHost necesita al menos un usuario para funcionar correctamente, debe añadir uno ejecutando «yunohost user create » o usando la interfaz de administración.", "permission_update_nothing_to_do": "No hay permisos para actualizar", - "permission_updated": "Actualizado el permiso «{permission:s}» para la aplicación «{app:s}»", + "permission_updated": "Actualizado el permiso «{permission:s}»", "permission_generated": "Actualizada la base de datos de permisos", - "permission_update_failed": "No se pudo actualizar el permiso", + "permission_update_failed": "No se pudo actualizar el permiso «{permission}» : {error}", "permission_name_not_valid": "Elija un nombre de permiso permitido para «{permission:s}", - "permission_not_found": "No se encontró el permiso «{permission:s}» para la aplicación «{app:s}»", - "permission_deletion_failed": "Falta el permiso «{permission:s}» para eliminar la aplicación «{app:s}»", - "permission_deleted": "Eliminado el permiso «{permission:s}» para la aplicación {app:s}", - "permission_creation_failed": "No se pudo conceder el permiso", - "permission_created": "Creado el permiso «{permission:s}» para la aplicación {app:s}", - "permission_already_exist": "El permiso «{permission:s}» para la aplicación {app:s} ya existe", + "permission_not_found": "No se encontró el permiso «{permission:s}»", + "permission_deletion_failed": "No se pudo eliminar el permiso «{permission}»: {error}", + "permission_deleted": "Eliminado el permiso «{permission:s}»", + "permission_creation_failed": "No se pudo crear el permiso «{permission}»: {error}", + "permission_created": "Creado el permiso «{permission:s}»", + "permission_already_exist": "El permiso «{permission}» ya existe", "permission_already_clear": "El permiso «{permission:s}» ya está definido para la aplicación {app:s}", "pattern_password_app": "Las contraseñas no pueden incluir los siguientes caracteres: {forbidden_chars}", "need_define_permission_before": "Redefina los permisos ejecutando «yunohost user permission add -u USUARIO» antes de eliminar un grupo permitido", @@ -438,7 +438,7 @@ "migration_0011_LDAP_config_dirty": "Parece que ha personalizado la configuración de LDAP. Para esta migración se necesita actualizar la configuración de LDAP.\nNecesita guardar su configuración actual, reiniciar la configuración original ejecutando «yunohost tools regen-conf -f» y reintentar la migración", "migration_0011_done": "Migración correcta. Ahora puede gestionar los grupos de usuarios.", "migration_0011_create_group": "Creando un grupo para cada usuario…", - "migration_0011_can_not_backup_before_migration": "No se pudo respaldar el sistema antes de la migración. Error: {error:s}", + "migration_0011_can_not_backup_before_migration": "Falló el respaldo del sistema antes de la migración. Fallo de migración. Error: {error:s}", "migration_0011_backup_before_migration": "Creando un respaldo de la base de datos de LDAP y de la configuración de las aplicaciones antes de la migración real.", "migration_0009_not_needed": "La migración ya ocurrió de algún modo… (?) Omitiendo.", "migration_0008_no_warning": "No se ha detectado ningún riesgo importante con respecto a la anulación de su configuración SSH ¡sin embargo uno nunca puede estar absolutamente seguro ;)! Ejecute la migración para anularla. Por otra parte, puede omitir la migración aunque no esté recomendado.", @@ -536,14 +536,14 @@ "log_category_404": "La categoría de registro «{category}» no existe", "log_corrupted_md_file": "El archivo de metadatos YAML asociado con el registro está dañado: «{md_file}\nError: {error}»", "hook_json_return_error": "No se pudo leer la respuesta del gancho {path:s}. Error: {msg:s}. Contenido sin procesar: {raw_content}", - "group_update_failed": "No se pudo actualizar el grupo «{group}»", + "group_update_failed": "No se pudo actualizar el grupo «{group}»: {error}", "group_updated": "Grupo «{group}» actualizado", "group_unknown": "El grupo «{group:s}» es desconocido", "group_info_failed": "No se pudo mostrar la información del grupo", "group_deletion_not_allowed": "No se puede eliminar el grupo {group:s} manualmente.", - "group_deletion_failed": "No se pudo eliminar el grupo «{group}»", + "group_deletion_failed": "No se pudo eliminar el grupo «{group}»: {error}", "group_deleted": "Eliminado el grupo «{group}»", - "group_creation_failed": "No se pudo crear el grupo «{group}»", + "group_creation_failed": "No se pudo crear el grupo «{group}»: {error}", "group_created": "Creado el grupo «{group}»", "group_name_already_exist": "El grupo {name:s} ya existe", "group_already_disallowed": "El grupo «{group:s}» ya tiene desactivado el permiso «{permission:s}» para la aplicación «{app:s}»", @@ -577,8 +577,8 @@ "domain_dns_conf_is_just_a_recommendation": "Esta orden muestra la configuración *recomendada*. No configura el DNS en realidad. Es su responsabilidad configurar la zona de DNS en su registrador según esta recomendación.", "dpkg_lock_not_available": "Esta orden no se puede ejecutar en este momento porque otro programa parece que 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 en un estado roto... Puede tratar de solucionar este problema conectando a través de SSH y ejecutando `sudo dpkg --configure -a`.", - "confirm_app_install_thirdparty": "¡AVISO! Instalar aplicaciones de terceros podría comprometer la integridad y seguridad de su sistema. Probablemente NO debería instalarlas salvo que sepa lo que está haciendo. ¿Está dispuesto a correr ese riesgo? [{answers:s}] ", - "confirm_app_install_danger": "¡AVISO! Esta aplicación es aún experimental (si no está funcionando expresamente) y ¡es probable que rompa su sistema! Probablemente NO debería instalarla salvo que sepa lo que está haciendo. ¿Está dispuesto a correr ese riesgo? [{answers:s}] ", + "confirm_app_install_thirdparty": "¡PELIGRO! Esta aplicación no forma parte del catálogo de aplicaciones de YunoHost. Instalar aplicaciones de terceros podría comprometer la integridad y seguridad de su sistema. Probablemente NO debería instalarla salvo que sepa lo que está haciendo. No tendrá NINGUNA AYUDA si esta aplicación no funciona o rompe su sistema... Si está dispuesto a aceptar ese riesgo de todas formas, escriba «{answers:s}»", + "confirm_app_install_danger": "¡PELIGRO! ¡Esta aplicación es conocida por ser aún experimental (o no funciona explícitamente)! Probablemente NO debería instalarla salvo que sepa lo que está haciendo. No tendrá NINGUNA AYUDA si esta aplicación no funciona o rompe su sistema... Si está dispuesto a aceptar ese riesgo de todas formas, escriba «{answers:s}»", "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:s}] ", "backup_unable_to_organize_files": "No se pudo usar el método rápido de organización de los archivos en el archivo", "backup_permission": "Permiso de respaldo para la aplicación {app:s}", @@ -608,5 +608,22 @@ "app_action_broke_system": "Esta acción parece que ha roto estos importantes servicios: {services}", "operation_interrupted": "¿Ha sido interrumpida la operación manualmente?", "apps_already_up_to_date": "Todas las aplicaciones están ya actualizadas", - "dyndns_provider_unreachable": "No se puede conectar con el proveedor de Dyndns {provider}: o su YunoHost no está correctamente conectado a Internet o el servidor de dynette está caído." + "dyndns_provider_unreachable": "No se puede conectar con el proveedor de Dyndns {provider}: o su YunoHost no está correctamente conectado a Internet o el servidor de dynette está caído.", + "group_already_exist": "El grupo {group} ya existe", + "group_already_exist_on_system": "El grupo {group} ya existe en los grupos del sistema", + "group_cannot_be_edited": "El grupo {group} no se puede editar manualmente.", + "group_cannot_be_deleted": "El grupo {group} no se puede eliminar manualmente.", + "group_user_already_in_group": "El usuario {user} ya está en el grupo {group}", + "group_user_not_in_group": "El usuario {user} no está en el grupo {group}", + "log_permission_create": "Crear permiso «{}»", + "log_permission_delete": "Eliminar permiso «{}»", + "log_permission_urls": "Actualizar URLs relacionadas con el permiso «{}»", + "log_user_group_create": "Crear grupo «{}»", + "log_user_permission_update": "Actualizar los accesos para el permiso «{}»", + "log_user_permission_reset": "Restablecer permiso «{}»", + "migration_0011_failed_to_remove_stale_object": "No se pudo eliminar el objeto obsoleto {dn}: {error}", + "permission_already_allowed": "El grupo «{group}» ya tiene el permiso «{permission}» activado", + "permission_already_disallowed": "El grupo «{group}» ya tiene el permiso «{permission}» desactivado", + "permission_cannot_remove_main": "No está permitido eliminar un permiso principal", + "user_already_exists": "El usuario {user} ya existe" } From 3e6ae5fb6835246141575c140897e7fd7a4db6c9 Mon Sep 17 00:00:00 2001 From: amirale qt Date: Sun, 6 Oct 2019 10:07:41 +0000 Subject: [PATCH 059/127] Translated using Weblate (French) Currently translated at 100.0% (553 of 553 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 61 +++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index 8bffec8b2..6b5e2a790 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -30,7 +30,7 @@ "app_unsupported_remote_type": "Ce type de commande à distance utilisé pour cette application n'est pas supporté", "app_upgrade_failed": "Impossible de mettre à jour {app:s}", "app_upgraded": "{app:s} mis à jour", - "appslist_fetched": "La liste d’applications {appslist:s} récupérée", + "appslist_fetched": "La liste d’applications mise à jour {appslist:s}", "appslist_removed": "La liste d’applications {appslist:s} a été supprimée", "appslist_retrieve_error": "Impossible de récupérer la liste d’applications distante {appslist:s} : {error:s}", "appslist_unknown": "La liste d’applications {appslist:s} est inconnue.", @@ -75,9 +75,9 @@ "dnsmasq_isnt_installed": "dnsmasq ne semble pas être installé, veuillez lancer 'apt-get remove bind9 && apt-get install dnsmasq'", "domain_cert_gen_failed": "Impossible de générer le certificat", "domain_created": "Le domaine a été créé", - "domain_creation_failed": "Impossible de créer le domaine", + "domain_creation_failed": "Impossible de créer le domaine {domain}: {error}", "domain_deleted": "Le domaine a été supprimé", - "domain_deletion_failed": "Impossible de supprimer le domaine", + "domain_deletion_failed": "Impossible de supprimer le domaine {domain}: {error}", "domain_dyndns_already_subscribed": "Vous avez déjà souscris à un domaine DynDNS", "domain_dyndns_invalid": "Domaine incorrect pour un usage avec DynDNS", "domain_dyndns_root_unknown": "Domaine DynDNS principal inconnu", @@ -236,13 +236,13 @@ "upnp_enabled": "UPnP activé", "upnp_port_open_failed": "Impossible d’ouvrir les ports UPnP", "user_created": "L’utilisateur créé", - "user_creation_failed": "Impossible de créer l’utilisateur", + "user_creation_failed": "Impossible de créer l’utilisateur {user}: {error}", "user_deleted": "L’utilisateur supprimé", - "user_deletion_failed": "Impossible de supprimer l’utilisateur", + "user_deletion_failed": "Impossible de supprimer l’utilisateur {user}: {error}", "user_home_creation_failed": "Impossible de créer le dossier personnel de l’utilisateur", "user_info_failed": "Impossible de récupérer les informations de l’utilisateur", "user_unknown": "L'utilisateur {user:s} est inconnu", - "user_update_failed": "Impossible de modifier l’utilisateur", + "user_update_failed": "Impossible de mettre à jour l'utilisateur {utilisateur}: {erreur}", "user_updated": "L’utilisateur a été modifié", "yunohost_already_installed": "YunoHost est déjà installé", "yunohost_ca_creation_failed": "Impossible de créer l’autorité de certification", @@ -493,8 +493,8 @@ "backup_actually_backuping": "Création d'une archive de sauvegarde à partir des fichiers collectés …", "backup_mount_archive_for_restore": "Préparation de l'archive pour restauration …", "confirm_app_install_warning": "Avertissement : cette application peut fonctionner mais n'est pas bien intégrée dans YunoHost. Certaines fonctionnalités telles que l'authentification unique et la sauvegarde/restauration peuvent ne pas être disponibles. L'installer quand même ? [{answers:s}] ", - "confirm_app_install_danger": "AVERTISSEMENT ! Cette application est encore expérimentale (explicitement, elle ne fonctionne pas) et risque de casser votre système ! Vous ne devriez probablement PAS l'installer sans savoir ce que vous faites. Êtes-vous prêt à prendre ce risque ? [{answers:s}] ", - "confirm_app_install_thirdparty": "AVERTISSEMENT ! L'installation d'applications tierces peut compromettre l'intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l'installer si vous ne savez pas ce que vous faites. Êtes-vous prêt à prendre ce risque ? [{answers:s}] ", + "confirm_app_install_danger": "DANGER! Cette application est connue pour être encore expérimentale (si elle ne fonctionne pas explicitement)! Vous ne devriez probablement PAS l'installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système ... Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers: s}'", + "confirm_app_install_thirdparty": "DANGER! Cette application ne fait pas partie du catalogue d'applications de Yunohost. L'installation d'applications tierces peut compromettre l'intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l'installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système ... Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers:s}'", "dpkg_is_broken": "Vous ne pouvez pas faire ça maintenant car dpkg/apt (le gestionnaire de paquets du système) semble avoir laissé des choses non configurées. Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a'.", "dyndns_could_not_check_available": "Impossible de vérifier si {domain:s} est disponible chez {provider:s}.", "file_does_not_exist": "Le fichier dont le chemin est {path:s} n'existe pas.", @@ -573,12 +573,12 @@ "group_info_failed": "L'information sur le groupe a échoué", "group_unknown": "Le groupe {group:s} est inconnu", "group_updated": "Le groupe '{group}' a été mis à jour", - "group_update_failed": "La mise à jour du groupe '{group}' a échoué", + "group_update_failed": "La mise à jour du groupe '{group}' a échoué : {error}", "group_already_allowed": "Le groupe '{group:s}' a déjà la permission '{permission:s}' activée pour l'application '{app:s}'", "group_already_disallowed": "Le groupe '{group:s}' a déjà la permission '{permission:s}' désactivée pour l'application '{app:s}'", "group_name_already_exist": "Le groupe {name:s} existe déjà", - "group_creation_failed": "Échec de la création du groupe '{group}'", - "group_deletion_failed": "Échec de la suppression du groupe '{group}'", + "group_creation_failed": "Échec de la création du groupe '{group}': {error}", + "group_deletion_failed": "Échec de la suppression du groupe '{group}': {error}", "edit_permission_with_group_all_users_not_allowed": "Vous n'êtes pas autorisé à modifier les permissions pour le groupe 'all_users', utilisez 'yunohost user permission clear APP' ou 'yunohost user permission add APP -u USER' à la place.", "log_permission_add": "Ajouter l'autorisation '{}' pour l'application '{}'", "log_permission_remove": "Supprimer l'autorisation '{}'", @@ -600,7 +600,7 @@ "migration_description_0012_postgresql_password_to_md5_authentication": "Forcer l'authentification PostgreSQL à utiliser MD5 pour les connexions locales", "migrations_exclusive_options": "'auto', '--skip' et '--force-rerun' sont des options mutuellement exclusives.", "migrations_not_pending_cant_skip": "Ces migrations ne sont pas en attente et ne peuvent donc pas être ignorées: {ids}", - "migration_0011_can_not_backup_before_migration": "Impossible de sauvegarder le système avant la migration. Erreur: {error: s}", + "migration_0011_can_not_backup_before_migration": "La sauvegarde du système avant la migration a échoué. La migration a échoué. Erreur: {error: s}", "migration_0011_migrate_permission": "Migration des autorisations des paramètres des applications vers LDAP…", "migration_0011_migration_failed_trying_to_rollback": "La migration a échoué… essayait de restauration du système.", "migration_0011_rollback_success": "Système restauré.", @@ -610,11 +610,11 @@ "user_already_in_group": "L'utilisateur '{user:}' est déjà dans le groupe '{group: s}'", "user_not_in_group": "L'utilisateur '{user: s}' ne fait pas partie du groupe {group: s}", "migration_0011_backup_before_migration": "Création d'une sauvegarde des paramètres de la base de données LDAP et des applications avant la migration.", - "permission_not_found": "Autorisation '{permission: s}' non trouvée pour l'application '{app: s}'", + "permission_not_found": "Autorisation '{permission:s}' introuvable", "permission_name_not_valid": "Choisissez un nom d'autorisation autorisé pour '{permission: s}'", - "permission_update_failed": "Impossible de mettre à jour la permission", + "permission_update_failed": "Impossible de mettre à jour la permission '{permission}': {error}", "permission_generated": "Base de données des autorisations mise à jour", - "permission_updated": "Permission '{permission: s}' pour l'application '{app: s}' mise à jour", + "permission_updated": "Permission '{permission:s}' mise à jour", "permission_update_nothing_to_do": "Aucune autorisation pour mettre à jour", "remove_main_permission_not_allowed": "Supprimer l'autorisation principale n'est pas autorisé", "dyndns_provider_unreachable": "Impossible d’atteindre le fournisseur Dyndns {provider}: votre YunoHost n’est pas correctement connecté à Internet ou le serveur Dynette est en panne.", @@ -627,13 +627,30 @@ "need_define_permission_before": "Redéfinissez l'autorisation à l'aide de 'yunohost user permission add -u USER' avant de supprimer un groupe autorisé", "operation_interrupted": "L'opération a été interrompue manuellement", "permission_already_clear": "L'autorisation '{permission: s}' est déjà vide pour l'application {app: s}", - "permission_already_exist": "L'autorisation '{permission: s}' pour l'application {app: s} existe déjà", - "permission_created": "Permission '{permission: s}' pour l'application {app: s} créée", - "permission_creation_failed": "Impossible d'accorder la permission", - "permission_deleted": "Permission '{permission: s}' pour app {app: s} supprimée", - "permission_deletion_failed": "Autorisation manquante '{permission: s}' pour supprimer l'application '{app: s}'", + "permission_already_exist": "L'autorisation '{permission}' existe déjà", + "permission_created": "Permission '{permission:s}' créée", + "permission_creation_failed": "Impossible de créer l'autorisation '{permission}': {erreur}", + "permission_deleted": "Permission '{permission:s}' supprimée", + "permission_deletion_failed": "Impossible de supprimer la permission '{permission}': {error}", "remove_user_of_group_not_allowed": "Vous n'êtes pas autorisé à supprimer l'utilisateur '{utilisateur: s}' dans le groupe '{groupe: s}'", "migration_description_0011_setup_group_permission": "Configurer le groupe d'utilisateurs et configurer les autorisations pour les applications et les services", - "migration_0011_LDAP_config_dirty": "Il semble que vous ayez personnalisé votre configuration LDAP. Pour cette migration, la configuration LDAP doit être mise à jour.\nVous devez enregistrer votre configuration actuelle, réintialiser la configuration d'origine en exécutant 'yunohost tools regen-conf -f', puis réessayer la migration", - "migration_0011_LDAP_update_failed": "Impossible de mettre à jour LDAP. Erreur: {error: s}" + "migration_0011_LDAP_config_dirty": "Il semble que vous ayez personnalisé votre configuration LDAP. Pour cette migration, la configuration LDAP doit être mise à jour.\nVous devez enregistrer votre configuration actuelle, réintialiser la configuration d'origine en exécutant 'yunohost tools regen-conf -f', puis réessayer la migration.", + "migration_0011_LDAP_update_failed": "Impossible de mettre à jour LDAP. Erreur: {error: s}", + "group_already_exist": "Le groupe {group} existe déjà", + "group_already_exist_on_system": "Le groupe {group} existe déjà dans les groupes système", + "group_cannot_be_edited": "Le groupe {group} ne peut pas être édité manuellement.", + "group_cannot_be_deleted": "Le groupe {group} ne peut pas être supprimé manuellement.", + "group_user_already_in_group": "L'utilisateur {user} est déjà dans le groupe {group}", + "group_user_not_in_group": "L'utilisateur {user} n'est pas dans le groupe {group}", + "log_permission_create": "Créer permission '{}'", + "log_permission_delete": "supprimer permission '{}'", + "log_permission_urls": "Mettre à jour les URL liées à la permission '{}'", + "log_user_group_create": "Créer '{}' groupe", + "log_user_permission_update": "Mise à jour des accès pour la permission '{}'", + "log_user_permission_reset": "Réinitialiser la permission '{}'", + "migration_0011_failed_to_remove_stale_object": "Impossible de supprimer un objet obsolète {dn}: {error}", + "permission_already_allowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' activée '", + "permission_already_disallowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' désactivé '", + "permission_cannot_remove_main": "Supprimer une autorisation principale n'est pas autorisé", + "user_already_exists": "L'utilisateur {user} existe déjà" } From d8468f77bc0d8554fcc17e61d228d3466007ee5c Mon Sep 17 00:00:00 2001 From: advocatux Date: Tue, 8 Oct 2019 17:07:51 +0000 Subject: [PATCH 060/127] Translated using Weblate (Spanish) Currently translated at 100.0% (554 of 554 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/es/ --- locales/es.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/locales/es.json b/locales/es.json index aeee0ff7a..80b17673a 100644 --- a/locales/es.json +++ b/locales/es.json @@ -625,5 +625,6 @@ "permission_already_allowed": "El grupo «{group}» ya tiene el permiso «{permission}» activado", "permission_already_disallowed": "El grupo «{group}» ya tiene el permiso «{permission}» desactivado", "permission_cannot_remove_main": "No está permitido eliminar un permiso principal", - "user_already_exists": "El usuario {user} ya existe" + "user_already_exists": "El usuario {user} ya existe", + "app_full_domain_unavailable": "Lamentablemente esta aplicación necesita un dominio completo para ser instalada pero ya hay otras aplicaciones instaladas en el dominio «{domain}». Una solución posible es añadir y usar un subdominio dedicado a esta aplicación." } From 5e477dd3f2d8df0ad74dcc9d7e7c96a8e1bb830f Mon Sep 17 00:00:00 2001 From: Lukas Dohn Date: Wed, 9 Oct 2019 08:31:31 +0000 Subject: [PATCH 061/127] Translated using Weblate (German) Currently translated at 39.2% (217 of 554 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/de/ --- locales/de.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/de.json b/locales/de.json index d03226187..1fe279d6b 100644 --- a/locales/de.json +++ b/locales/de.json @@ -282,7 +282,7 @@ "appslist_name_already_tracked": "Es gibt bereits eine registrierte App-Liste mit Namen {name:s}.", "appslist_url_already_tracked": "Es gibt bereits eine registrierte Anwendungsliste mit der URL {url:s}.", "appslist_migrating": "Migriere Anwendungsliste {appslist:s} …", - "appslist_could_not_migrate": "Konnte Anwendungsliste {appslist:s} nicht migrieren. Konnte die URL nicht verarbeiten... Der alte Cron-Job wurde unter {bkp_file:s} beibehalten.", + "appslist_could_not_migrate": "Konnte die Anwendungsliste {appslist:s} nicht migrieren. Konnte die URL nicht verarbeiten... Der alte Cron-Job wurde unter {bkp_file:s} beibehalten.", "appslist_corrupted_json": "Anwendungslisten konnte nicht geladen werden. Es scheint, dass {filename:s} beschädigt ist.", "yunohost_ca_creation_success": "Die lokale Zertifizierungs-Authorität wurde angelegt.", "app_already_installed_cant_change_url": "Diese Application ist bereits installiert. Die URL kann durch diese Funktion nicht modifiziert werden. Überprüfe ob `app changeurl` verfügbar ist.", From a6a104677cb0ef723645734bd4b67c0c95dbc66a Mon Sep 17 00:00:00 2001 From: amirale qt Date: Wed, 9 Oct 2019 11:20:08 +0000 Subject: [PATCH 062/127] Translated using Weblate (French) Currently translated at 100.0% (554 of 554 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index 6b5e2a790..62f6d6965 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -634,7 +634,7 @@ "permission_deletion_failed": "Impossible de supprimer la permission '{permission}': {error}", "remove_user_of_group_not_allowed": "Vous n'êtes pas autorisé à supprimer l'utilisateur '{utilisateur: s}' dans le groupe '{groupe: s}'", "migration_description_0011_setup_group_permission": "Configurer le groupe d'utilisateurs et configurer les autorisations pour les applications et les services", - "migration_0011_LDAP_config_dirty": "Il semble que vous ayez personnalisé votre configuration LDAP. Pour cette migration, la configuration LDAP doit être mise à jour.\nVous devez enregistrer votre configuration actuelle, réintialiser la configuration d'origine en exécutant 'yunohost tools regen-conf -f', puis réessayer la migration.", + "migration_0011_LDAP_config_dirty": "Il semble que vous ayez personnalisé votre configuration LDAP. Pour cette migration, la configuration LDAP doit être mise à jour.\nVous devez enregistrer votre configuration actuelle, réintialiser la configuration d'origine en exécutant 'yunohost tools regen-conf -f', puis réessayer la migration", "migration_0011_LDAP_update_failed": "Impossible de mettre à jour LDAP. Erreur: {error: s}", "group_already_exist": "Le groupe {group} existe déjà", "group_already_exist_on_system": "Le groupe {group} existe déjà dans les groupes système", @@ -652,5 +652,6 @@ "permission_already_allowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' activée '", "permission_already_disallowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' désactivé '", "permission_cannot_remove_main": "Supprimer une autorisation principale n'est pas autorisé", - "user_already_exists": "L'utilisateur {user} existe déjà" + "user_already_exists": "L'utilisateur {user} existe déjà", + "app_full_domain_unavailable": "Désolé, cette application nécessite l'installation d'un domaine complet, mais d'autres applications sont déjà installées sur le domaine '{domain}'. Une solution possible consiste à ajouter et à utiliser un sous-domaine dédié à cette application." } From 5ac863c906f6858f3433fbc2082fc3f544faee1a Mon Sep 17 00:00:00 2001 From: amirale qt Date: Wed, 9 Oct 2019 11:21:54 +0000 Subject: [PATCH 063/127] Translated using Weblate (Esperanto) Currently translated at 100.0% (554 of 554 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eo/ --- locales/eo.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/locales/eo.json b/locales/eo.json index d27c0171c..0d8d13fe8 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -552,5 +552,6 @@ "log_app_remove": "Forigu la aplikon '{}'", "service_restart_failed": "Ne povis rekomenci la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}", "firewall_rules_cmd_failed": "Iuj komandoj pri fajroŝirmilo malsukcesis. Pliaj informoj en ensaluto.", - "certmanager_certificate_fetching_or_enabling_failed": "Provante uzi la novan atestilon por {domain:s} ne funkciis …" + "certmanager_certificate_fetching_or_enabling_failed": "Provante uzi la novan atestilon por {domain:s} ne funkciis …", + "app_full_domain_unavailable": "Bedaŭrinde, ĉi tiu apliko postulas plenan domajnon esti instalita, sed iuj aliaj programoj jam estas instalitaj sur '{domain}'. Unu ebla solvo estas aldoni kaj uzi subdomajnon dediĉitan al ĉi tiu aplikaĵo anstataŭe." } From 08d97172369f0bb959398e539aba880a95dd7330 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 14 Oct 2019 20:26:59 +0200 Subject: [PATCH 064/127] Improve test accuracy for apps --- src/yunohost/tests/test_apps.py | 78 ++++++++++++++++----------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/yunohost/tests/test_apps.py b/src/yunohost/tests/test_apps.py index fb2f13c3f..5a6db43c9 100644 --- a/src/yunohost/tests/test_apps.py +++ b/src/yunohost/tests/test_apps.py @@ -4,6 +4,8 @@ import pytest import shutil import requests +from conftest import message, raiseYunohostError + from moulinette import m18n from moulinette.utils.filesystem import mkdir @@ -113,9 +115,9 @@ def app_is_not_installed(domain, app): def app_is_exposed_on_http(domain, path, message_in_page): try: - r = requests.get("http://127.0.0.1" + path + "/", headers={"Host": domain}, timeout=10) + r = requests.get("http://127.0.0.1" + path + "/", headers={"Host": domain}, timeout=10, verify=False) return r.status_code == 200 and message_in_page in r.text - except Exception: + except Exception as e: return False @@ -190,11 +192,11 @@ def test_legacy_app_install_private(secondary_domain): assert app_is_not_installed(secondary_domain, "legacy_app") -def test_legacy_app_install_unknown_domain(): +def test_legacy_app_install_unknown_domain(mocker): with pytest.raises(YunohostError): - install_legacy_app("whatever.nope", "/legacy") - # TODO check error message + with message(mocker, "app_argument_invalid"): + install_legacy_app("whatever.nope", "/legacy") assert app_is_not_installed("whatever.nope", "legacy_app") @@ -221,55 +223,51 @@ def test_legacy_app_install_multiple_instances(secondary_domain): assert app_is_not_installed(secondary_domain, "legacy_app__2") -def test_legacy_app_install_path_unavailable(secondary_domain): +def test_legacy_app_install_path_unavailable(mocker, secondary_domain): # These will be removed in teardown install_legacy_app(secondary_domain, "/legacy") with pytest.raises(YunohostError): - install_legacy_app(secondary_domain, "/") - # TODO check error message + with message(mocker, "app_location_unavailable"): + install_legacy_app(secondary_domain, "/") assert app_is_installed(secondary_domain, "legacy_app") assert app_is_not_installed(secondary_domain, "legacy_app__2") -def test_legacy_app_install_bad_args(): - - with pytest.raises(YunohostError): - install_legacy_app("this.domain.does.not.exists", "/legacy") - - -def test_legacy_app_install_with_nginx_down(secondary_domain): +def test_legacy_app_install_with_nginx_down(mocker, secondary_domain): os.system("systemctl stop nginx") - with pytest.raises(YunohostError): + with raiseYunohostError(mocker, "app_action_cannot_be_ran_because_required_services_down"): install_legacy_app(secondary_domain, "/legacy") -def test_legacy_app_failed_install(secondary_domain): +def test_legacy_app_failed_install(mocker, secondary_domain): # This will conflict with the folder that the app # attempts to create, making the install fail mkdir("/var/www/legacy_app/", 0o750) with pytest.raises(YunohostError): - install_legacy_app(secondary_domain, "/legacy") - # TODO check error message + with message(mocker, 'app_install_script_failed'): + install_legacy_app(secondary_domain, "/legacy") assert app_is_not_installed(secondary_domain, "legacy_app") -def test_legacy_app_failed_remove(secondary_domain): +def test_legacy_app_failed_remove(mocker, secondary_domain): install_legacy_app(secondary_domain, "/legacy") # The remove script runs with set -eu and attempt to remove this # file without -f, so will fail if it's not there ;) os.remove("/etc/nginx/conf.d/%s.d/%s.conf" % (secondary_domain, "legacy_app")) - with pytest.raises(YunohostError): - app_remove("legacy") + + # TODO / FIXME : can't easily validate that 'app_not_properly_removed' + # is triggered for weird reasons ... + app_remove("legacy_app") # # Well here, we hit the classical issue where if an app removal script @@ -286,59 +284,61 @@ def test_full_domain_app(secondary_domain): assert app_is_exposed_on_http(secondary_domain, "/", "This is a dummy app") -def test_full_domain_app_with_conflicts(secondary_domain): +def test_full_domain_app_with_conflicts(mocker, secondary_domain): install_legacy_app(secondary_domain, "/legacy") - # TODO : once #808 is merged, add test that the message raised is 'app_full_domain_unavailable' - with pytest.raises(YunohostError): + with raiseYunohostError(mocker, "app_full_domain_unavailable"): install_full_domain_app(secondary_domain) -def test_systemfuckedup_during_app_install(secondary_domain): +def test_systemfuckedup_during_app_install(mocker, secondary_domain): with pytest.raises(YunohostError): - install_break_yo_system(secondary_domain, breakwhat="install") - os.system("nginx -t") - os.system("systemctl status nginx") + with message(mocker, "app_install_failed"): + with message(mocker, 'app_action_broke_system'): + install_break_yo_system(secondary_domain, breakwhat="install") assert app_is_not_installed(secondary_domain, "break_yo_system") -def test_systemfuckedup_during_app_remove(secondary_domain): +def test_systemfuckedup_during_app_remove(mocker, secondary_domain): install_break_yo_system(secondary_domain, breakwhat="remove") with pytest.raises(YunohostError): - app_remove("break_yo_system") - os.system("nginx -t") - os.system("systemctl status nginx") + with message(mocker, 'app_action_broke_system'): + with message(mocker, 'app_removed'): + app_remove("break_yo_system") assert app_is_not_installed(secondary_domain, "break_yo_system") -def test_systemfuckedup_during_app_install_and_remove(secondary_domain): +def test_systemfuckedup_during_app_install_and_remove(mocker, secondary_domain): with pytest.raises(YunohostError): - install_break_yo_system(secondary_domain, breakwhat="everything") + with message(mocker, "app_install_failed"): + with message(mocker, 'app_action_broke_system'): + install_break_yo_system(secondary_domain, breakwhat="everything") assert app_is_not_installed(secondary_domain, "break_yo_system") -def test_systemfuckedup_during_app_upgrade(secondary_domain): +def test_systemfuckedup_during_app_upgrade(mocker, secondary_domain): install_break_yo_system(secondary_domain, breakwhat="upgrade") with pytest.raises(YunohostError): - app_upgrade("break_yo_system", file="./tests/apps/break_yo_system_ynh") + with message(mocker, 'app_action_broke_system'): + app_upgrade("break_yo_system", file="./tests/apps/break_yo_system_ynh") -def test_failed_multiple_app_upgrade(secondary_domain): +def test_failed_multiple_app_upgrade(mocker, secondary_domain): install_legacy_app(secondary_domain, "/legacy") install_break_yo_system(secondary_domain, breakwhat="upgrade") - with pytest.raises(YunohostError): + with raiseYunohostError(mocker, 'app_not_upgraded'): app_upgrade(["break_yo_system", "legacy_app"], file={"break_yo_system": "./tests/apps/break_yo_system_ynh", "legacy": "./tests/apps/legacy_app_ynh"}) From 61931f2c4b47f1e08479b3e46e09e8b3d7ab5f13 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 14 Oct 2019 20:28:16 +0200 Subject: [PATCH 065/127] We don't want this to call .error() for legit logs already completed --- src/yunohost/log.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/yunohost/log.py b/src/yunohost/log.py index 8b0f893e8..0f5ff784c 100644 --- a/src/yunohost/log.py +++ b/src/yunohost/log.py @@ -502,7 +502,10 @@ class OperationLogger(object): The missing of the message below could help to see an electrical shortage. """ - self.error(m18n.n('log_operation_unit_unclosed_properly')) + if self.ended_at is not None or self.started_at is None: + return + else: + self.error(m18n.n('log_operation_unit_unclosed_properly')) def _get_description_from_name(name): From f12ff6ade8388917d6be6aae437023d3734bd610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Allan=20Nordh=C3=B8y?= Date: Mon, 14 Oct 2019 20:04:59 +0000 Subject: [PATCH 066/127] Language reworked 2 --- locales/en.json | 160 ++++++++++++++++++++++++------------------------ 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/locales/en.json b/locales/en.json index a341a6b4f..54966135f 100644 --- a/locales/en.json +++ b/locales/en.json @@ -6,7 +6,7 @@ "admin_password_changed": "The administration password got changed", "admin_password_too_long": "Please choose a password shorter than 127 characters", "already_up_to_date": "Nothing to do. Everything is already up-to-date.", - "app_action_cannot_be_ran_because_required_services_down": "This app requires some services which are currently down. Before continuing, you should try to restart the following services (and possibly investigate why they are down): {services}", + "app_action_cannot_be_ran_because_required_services_down": "This app requires more services to run. Before continuing, try to restart the following services (and possibly investigate why they are down): {services}", "app_action_broke_system": "This action seem to have broke these important services: {services}", "app_already_installed": "{app:s} is already installed", "app_already_installed_cant_change_url": "This app is already installed. The URL cannot be changed just by this function. Look into `app changeurl` if it's available.", @@ -16,24 +16,24 @@ "app_argument_required": "Argument '{name:s}' is required", "app_change_url_failed_nginx_reload": "Could not reload NGINX. Here is the output of 'nginx -t':\n{nginx_errors:s}", "app_change_url_identical_domains": "The old and new domain/url_path are identical ('{domain:s}{path:s}'), nothing to do.", - "app_change_url_no_script": "This application '{app_name:s}' doesn't support URL modification yet. Maybe you should upgrade it.", + "app_change_url_no_script": "The app '{app_name:s}' doesn't support URL modification yet. Maybe you should upgrade it.", "app_change_url_success": "{app:s} URL is now {domain:s}{path:s}", "app_extraction_failed": "Could not extract the installation files", - "app_full_domain_unavailable": "Sorry, this application requires a full domain to be installed on, but some other apps are already installed on domain '{domain}'. One possible solution is to add and use a subdomain dedicated to this application instead.", + "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_incompatible": "The app {app} is incompatible with your YunoHost version", "app_install_files_invalid": "These files cannot be installed", "app_install_failed": "Could not install {app}", - "app_install_script_failed": "An error occured inside the app installation script", + "app_install_script_failed": "An error occurred inside the app installation script", "app_location_already_used": "The app '{app}' is already installed in ({path})", - "app_make_default_location_already_used": "Can't make the app '{app}' the default on the domain, {domain} is already in use by the other app '{other_app}'", + "app_make_default_location_already_used": "Can't make the app '{app}' the default on the domain, '{domain}' is already in use by the other app '{other_app}'", "app_location_install_failed": "Cannot install the app there because it conflicts with the app '{other_app}' already installed in '{other_path}'", "app_location_unavailable": "This URL is either unavailable, or conflicts with the already installed app(s):\n{apps:s}", "app_manifest_invalid": "Something is wrong with the app manifest: {error}", "app_not_upgraded": "The app '{failed_app}' failed to upgrade, and as a consequence the following apps upgrades have been cancelled: {apps}", - "app_upgrade_stopped": "The upgrade of all applications has been stopped to prevent possible damage because the previous application failed to upgrade", + "app_upgrade_stopped": "Upgrading all apps was stopped to prevent possible damage because one app could not be upgraded", "app_not_correctly_installed": "{app:s} seems to be incorrectly installed", - "app_not_installed": "Could not find the application '{app:s}' in the list of installed apps: {all_apps}", + "app_not_installed": "Could not find the app '{app:s}' in the list of installed apps: {all_apps}", "app_not_properly_removed": "{app:s} has not been properly removed", "app_package_need_update": "The app {app} package needs to be updated to follow YunoHost changes", "app_removed": "{app:s} removed", @@ -41,29 +41,29 @@ "app_requirements_failed": "Some requirements are not met for {app}: {error}", "app_requirements_unmeet": "Requirements are not met for {app}, the package {pkgname} ({version}) must be {spec}", "app_sources_fetch_failed": "Could not fetch sources files, is the URL correct?", - "app_start_install": "Installing application {app}…", - "app_start_remove": "Removing application {app}…", - "app_start_backup": "Collecting files to be backed up for {app}…", - "app_start_restore": "Restoring application {app}…", + "app_start_install": "Installing the app '{app}'…", + "app_start_remove": "Removing the app '{app}'…", + "app_start_backup": "Collecting files to be backed up for the app '{app}'…", + "app_start_restore": "Restoring the app '{app}'…", "app_unknown": "Unknown app", "app_unsupported_remote_type": "Unsupported remote type used for the app", "app_upgrade_several_apps": "The following apps will be upgraded: {apps}", "app_upgrade_app_name": "Now upgrading {app}…", "app_upgrade_failed": "Could not upgrade {app:s}", - "app_upgrade_some_app_failed": "Some applications could not be upgraded", + "app_upgrade_some_app_failed": "Some apps could not be upgraded", "app_upgraded": "{app:s} upgraded", - "apps_already_up_to_date": "All applications are already up-to-date", + "apps_already_up_to_date": "All apps are already up-to-date", "apps_permission_not_found": "No permission found for the installed apps", - "appslist_corrupted_json": "Could not load the application lists. It looks like {filename:s} is damaged.", - "appslist_could_not_migrate": "Could not migrate the app list {appslist:s}! Could not parse the URL… The old cron job was kept kept in {bkp_file:s}.", - "appslist_fetched": "Updated application list {appslist:s}", - "appslist_migrating": "Migrating application list {appslist:s}…", - "appslist_name_already_tracked": "A registered application list with name {name:s} already exists.", - "appslist_removed": "{appslist:s} application list removed", - "appslist_retrieve_bad_format": "Could not read the fetched application list {appslist:s}", - "appslist_retrieve_error": "Cannot retrieve the remote application list {appslist:s}: {error:s}", - "appslist_unknown": "Application list {appslist:s} unknown.", - "appslist_url_already_tracked": "There is already a registered application list with the URL {url:s}.", + "appslist_corrupted_json": "Could not load the app lists. It looks like {filename:s} is damaged.", + "appslist_could_not_migrate": "Could not migrate the app list '{appslist:s}'! Could not parse the URL… The old cron job was kept kept in {bkp_file:s}.", + "appslist_fetched": "Updated the app list '{appslist:s}'", + "appslist_migrating": "Migrating the app list '{appslist:s}'…", + "appslist_name_already_tracked": "A registered app list with the name {name:s} already exists.", + "appslist_removed": "The '{appslist:s}' app list was removed", + "appslist_retrieve_bad_format": "Could not read the fetched app list '{appslist:s}'", + "appslist_retrieve_error": "Cannot retrieve the remote app list '{appslist:s}': {error:s}", + "appslist_unknown": "The app list '{appslist:s}' is unknown.", + "appslist_url_already_tracked": "There is already a registered app list with the URL {url:s}.", "ask_current_admin_password": "Current administration password", "ask_email": "E-mail address", "ask_firstname": "First name", @@ -89,7 +89,7 @@ "backup_archive_open_failed": "Could not open the backup archive", "backup_archive_system_part_not_available": "System part '{part:s}' unavailable in this backup", "backup_archive_writing_error": "Could not add the files '{source:s}' (named in the archive '{dest:s}') to be backed up into the compressed archive '{archive:s}'", - "backup_ask_for_copying_if_needed": "Some files could not be prepared for backup using the method that avoids temporarily wasting space on the system. To perform the backup, {size:s}MB will be temporarily. Do you agree?", + "backup_ask_for_copying_if_needed": "Do you want to perform the backup using {size:s} MB temporarily due to inability to prepare some files for backup using a more efficient method?", "backup_borg_not_implemented": "The Borg backup method is not yet implemented", "backup_cant_mount_uncompress_archive": "Could not mount the uncompressed archive as write protected", "backup_cleaning_failed": "Could not clean-up the temporary backup folder", @@ -115,7 +115,7 @@ "backup_output_directory_forbidden": "Pick a different output directory. Backups can not be created in /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var or /home/yunohost.backup/archives sub-folders", "backup_output_directory_not_empty": "You should pick an empty output directory", "backup_output_directory_required": "You must provide an output directory for the backup", - "backup_output_symlink_dir_broken": "You have a broken symlink in place of your archive directory '{path:s}'. You may have a specific setup to backup your data on another filesystem, in this case you probably forgot to remount or plug in your hard-drive or USB key.", + "backup_output_symlink_dir_broken": "Your archive directory '{path:s}' only contains a broken symlink. Maybe you forgot to re/mount or plug in the storage medium it points to.", "backup_permission": "Backup permission for app {app:s}", "backup_php5_to_php7_migration_may_fail": "Could not convert your archive to support PHP 7, you may be unable to restore your PHP apps (reason: {error:s})", "backup_running_hooks": "Running backup hooks…", @@ -145,16 +145,16 @@ "certmanager_no_cert_file": "Could not read the certificate file for the domain {domain:s} (file: {file:s})", "certmanager_self_ca_conf_file_not_found": "Could not find configuration file for self-signing authority (file: {file:s})", "certmanager_unable_to_parse_self_CA_name": "Could not parse name of self-signing authority (file: {file:s})", - "confirm_app_install_warning": "Warning: This application may work, but is not well-integrated in YunoHost. Some features such as single sign-on and backup/restore might not be available. Install anyway? [{answers:s}] ", - "confirm_app_install_danger": "DANGER! This application 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 break your system... If you are willing to take that risk anyway, type '{answers:s}'", - "confirm_app_install_thirdparty": "DANGER! This application is not part of Yunohost's application catalog. Installing third-party applications 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 break your system... If you are willing to take that risk anyway, type '{answers:s}'", + "confirm_app_install_warning": "Warning: This app may work, but is not well-integrated in YunoHost. Some features such as single sign-on and backup/restore might not be available. Install anyway? [{answers:s}] ", + "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 break your system… If you are willing to take that risk anyway, type '{answers:s}'", + "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 break your system… If you are willing to take that risk anyway, type '{answers:s}'", "custom_app_url_required": "You must provide a URL to upgrade your custom app {app:s}", "custom_appslist_name_required": "You must provide a name for your custom app list", "diagnosis_debian_version_error": "Could not retrieve the Debian version: {error}", "diagnosis_kernel_version_error": "Could not retrieve kernel version: {error}", "diagnosis_monitor_disk_error": "Could not monitor disks: {error}", "diagnosis_monitor_system_error": "Could not monitor system: {error}", - "diagnosis_no_apps": "No installed application", + "diagnosis_no_apps": "No such installed app", "dpkg_is_broken": "You cannot do this right now because dpkg/APT (the system package managers) seems to be in a broken state… You can try to solve this issue by connecting through SSH and running `sudo dpkg --configure -a`.", "dpkg_lock_not_available": "This command can't be ran right now because another program seems to be using the lock of dpkg (the system package manager)", "domain_cannot_remove_main": "Cannot remove main domain. Set one first", @@ -236,7 +236,7 @@ "hook_json_return_error": "Could not read return from hook {path:s}. Error: {msg:s}. Raw content: {raw_content}", "hook_list_by_invalid": "This property can not be used to list hooks", "hook_name_unknown": "Unknown hook name '{name:s}'", - "installation_complete": "Installation complete", + "installation_complete": "Installation completed", "installation_failed": "Something went wrong with the installation", "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", @@ -248,13 +248,13 @@ "log_help_to_get_failed_log": "The operation '{desc}' could not be completed. Please share the full log of this operation using the command 'yunohost log display {name} --share' to get help", "log_does_exists": "There is not operation log with the name '{log}', use 'yunohost log list' to see all available operation logs", "log_operation_unit_unclosed_properly": "Operation unit has not been closed properly", - "log_app_fetchlist": "Add an application list", - "log_app_removelist": "Remove an application list", - "log_app_change_url": "Change the URL of '{}' application", - "log_app_install": "Install the '{}' application", - "log_app_remove": "Remove the '{}' application", - "log_app_upgrade": "Upgrade the '{}' application", - "log_app_makedefault": "Make '{}' the default application", + "log_app_fetchlist": "Add an app list", + "log_app_removelist": "Remove an app list", + "log_app_change_url": "Change the URL of the '{}' app", + "log_app_install": "Install the '{}' app", + "log_app_remove": "Remove the '{}' app", + "log_app_upgrade": "Upgrade the '{}' app", + "log_app_makedefault": "Make '{}' the default app", "log_available_on_yunopaste": "This log is now available via {url}", "log_backup_restore_system": "Restore system from a backup archive", "log_backup_restore_app": "Restore '{}' from a backup archive", @@ -264,12 +264,12 @@ "log_domain_remove": "Remove '{}' domain from system configuration", "log_dyndns_subscribe": "Subscribe to a YunoHost subdomain '{}'", "log_dyndns_update": "Update the IP associated with your YunoHost subdomain '{}'", - "log_letsencrypt_cert_install": "Install a Let's encrypt certificate on '{}' domain", + "log_letsencrypt_cert_install": "Install a Let's Encrypt certificate on '{}' domain", "log_permission_create": "Create permission '{}'", "log_permission_delete": "Delete permission '{}'", "log_permission_urls": "Update urls related to permission '{}'", "log_selfsigned_cert_install": "Install self signed certificate on '{}' domain", - "log_letsencrypt_cert_renew": "Renew '{}' Let's encrypt certificate", + "log_letsencrypt_cert_renew": "Renew '{}' Let's Encrypt certificate", "log_regen_conf": "Regenerate system configurations '{}'", "log_user_create": "Add '{}' user", "log_user_delete": "Delete '{}' user", @@ -331,31 +331,31 @@ "migration_0005_postgresql_94_not_installed": "PostgreSQL was not installed on your system. Nothing to do.", "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 is installed, but not postgresql 9.6‽ Something weird might have happened on your system:(…", "migration_0005_not_enough_space": "Make sufficient space available in {path} to run the migration.", - "migration_0006_disclaimer": "YunoHost now expects admin and root passwords to be synchronized. By running this migration, your root password is going to be replaced by the admin password.", - "migration_0007_cancelled": "YunoHost has failed to improve the way your SSH conf is managed.", + "migration_0006_disclaimer": "YunoHost now expects the admin and root passwords to be synchronized. This migration, replaces your root password with the admin password.", + "migration_0007_cancelled": "Could not improve the way your SSH configuration is managed.", "migration_0007_cannot_restart": "SSH can't be restarted after trying to cancel migration number 6.", "migration_0008_general_disclaimer": "To improve the security of your server, it is recommended to let YunoHost manage the SSH configuration. Your current SSH setup differs from the recommendation. If you let YunoHost reconfigure it, the way you connect to your server through SSH will change thusly:", "migration_0008_port": "• You will have to connect using port 22 instead of your current custom SSH port. Feel free to reconfigure it;", "migration_0008_root": "• You will not be able to connect as root through SSH. Instead you should use the admin user;", "migration_0008_dsa": "• The DSA key will be turned off. Hence, you might need to invalidate a spooky warning from your SSH client, and recheck the fingerprint of your server;", - "migration_0008_warning": "If you understand those warnings and agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.", - "migration_0008_no_warning": "No major risk indentified concerning overriding your SSH configuration—one can however not be absolutely sure ;)! Run the migration to override it. Otherwise, you can also skip the migration - though it is not recommended.", + "migration_0008_warning": "If you understand those warnings and want YunoHost to override your current configuration, run the migration. Otherwise, you can also skip the migration, though it is not recommended.", + "migration_0008_no_warning": "Overriding your SSH configuration should be safe, though this can not be promised! Run the migration to override it. Otherwise, you can also skip the migration, though it is not recommended.", "migration_0009_not_needed": "This migration already happened somehow… (?) Skipping.", "migration_0011_backup_before_migration": "Creating a backup of LDAP database and apps settings prior to the actual migration.", - "migration_0011_can_not_backup_before_migration": "The backup of the system before the migration failed. Migration failed. Error: {error:s}", + "migration_0011_can_not_backup_before_migration": "The backup of the system could not be completed before the migration failed. Error: {error:s}", "migration_0011_create_group": "Creating a group for each user…", - "migration_0011_done": "Migration successful. You are now able to manage usergroups.", - "migration_0011_LDAP_config_dirty": "It look like that you customized your LDAP configuration. For this migration the LDAP configuration needs to be updated.\nYou need to save your current configuration, reintialize the original configuration by running 'yunohost tools regen-conf -f' and retry the migration", + "migration_0011_done": "Migration completed. You are now able to manage usergroups.", + "migration_0011_LDAP_config_dirty": "Save your current custom LDAP conguration, and reintialize the original one by running 'yunohost tools regen-conf -f' and retry the migration.", "migration_0011_LDAP_update_failed": "Could not update LDAP. Error: {error:s}", "migration_0011_migrate_permission": "Migrating permissions from apps settings to LDAP…", - "migration_0011_migration_failed_trying_to_rollback": "Migration failed… trying to roll back the system.", + "migration_0011_migration_failed_trying_to_rollback": "Could not migrate… trying to roll back the system.", "migration_0011_rollback_success": "System rolled back.", "migration_0011_update_LDAP_database": "Updating LDAP database…", "migration_0011_update_LDAP_schema": "Updating LDAP schema…", - "migration_0011_failed_to_remove_stale_object": "Failed to remove stale object {dn}: {error}", + "migration_0011_failed_to_remove_stale_object": "Could not remove stale object {dn}: {error}", "migrations_already_ran": "Those migrations are already done: {ids}", - "migrations_cant_reach_migration_file": "Could not access migrations files at path %s", - "migrations_dependencies_not_satisfied": "Cannot run migration {id} because first you need to run these migrations: {dependencies_id}", + "migrations_cant_reach_migration_file": "Could not access migrations files at the path '%s'", + "migrations_dependencies_not_satisfied": "Run these migrations: '{dependencies_id}', before migration {id}.", "migrations_failed_to_load_migration": "Could not load migration {id}: {error}", "migrations_exclusive_options": "'--auto', '--skip', and '--force-rerun' are mutually exclusive options.", "migrations_list_conflict_pending_done": "You cannot use both '--previous' and '--done' at the same time.", @@ -364,32 +364,32 @@ "migrations_must_provide_explicit_targets": "You must provide explicit targets when using '--skip' or '--force-rerun'", "migrations_need_to_accept_disclaimer": "To run the migration {id}, your must accept the following disclaimer:\n---\n{disclaimer}\n---\nIf you accept to run the migration, please re-run the command with the option '--accept-disclaimer'.", "migrations_no_migrations_to_run": "No migrations to run", - "migrations_no_such_migration": "There is no migration called {id}", + "migrations_no_such_migration": "There is no migration called '{id}'", "migrations_not_pending_cant_skip": "Those migrations are not pending, so cannot be skipped: {ids}", "migrations_pending_cant_rerun": "Those migrations are still pending, so cannot be run again: {ids}", "migrations_running_forward": "Running migration {id}…", "migrations_skip_migration": "Skipping migration {id}…", "migrations_success_forward": "Migration {id} completed", "migrations_to_be_ran_manually": "Migration {id} has to be run manually. Please go to Tools → Migrations on the webadmin page, or run `yunohost tools migrations migrate`.", - "monitor_disabled": "Server monitoring now turned off", - "monitor_enabled": "Server monitoring now turned on", + "monitor_disabled": "Server monitoring now off", + "monitor_enabled": "Server monitoring now on", "monitor_glances_con_failed": "Could not connect to Glances server", "monitor_not_enabled": "Server monitoring is off", "monitor_period_invalid": "Invalid time period", - "monitor_stats_file_not_found": "Statistics file not found", + "monitor_stats_file_not_found": "Could not find the statistics file", "monitor_stats_no_update": "No monitoring statistics to update", "monitor_stats_period_unavailable": "No available statistics for the period", "mountpoint_unknown": "Unknown mountpoint", - "mysql_db_creation_failed": "MySQL database creation failed", - "mysql_db_init_failed": "MySQL database init failed", - "mysql_db_initialized": "The MySQL database now initialized", + "mysql_db_creation_failed": "Could not create MySQL database", + "mysql_db_init_failed": "Could not initialize MySQL database", + "mysql_db_initialized": "The MySQL database is now initialized", "network_check_mx_ko": "DNS MX record is not set", "network_check_smtp_ko": "Outbound e-mail (SMTP port 25) seems to be blocked by your network", "network_check_smtp_ok": "Outbound e-mail (SMTP port 25) is not blocked", - "no_internet_connection": "Server not connected to the Internet", + "no_internet_connection": "The server is not connected to the Internet", "not_enough_disk_space": "Not enough free space on '{path:s}'", - "operation_interrupted": "The operation was manually interrupted?", - "package_not_installed": "Package '{pkgname}' is not installed", + "operation_interrupted": "Was the operation manually interrupted?", + "package_not_installed": "The package '{pkgname}' is not installed", "package_unexpected_error": "An unexpected error occurred processing the package '{pkgname}'", "package_unknown": "Unknown package '{pkgname}'", "packages_upgrade_failed": "Could not upgrade all the packages", @@ -400,7 +400,7 @@ "password_too_simple_4": "The password needs to be at least 12 characters long and contain a digit, upper, lower and special characters", "pattern_backup_archive_name": "Must be a valid filename with max 30 characters, alphanumeric and -_. characters only", "pattern_domain": "Must be a valid domain name (e.g. my-domain.org)", - "pattern_email": "Must be a valid email address (e.g. someone@domain.org)", + "pattern_email": "Must be a valid e-mail address (e.g. someone@example.com)", "pattern_firstname": "Must be a valid first name", "pattern_lastname": "Must be a valid last name", "pattern_listname": "Must be alphanumeric and underscore characters only", @@ -466,7 +466,7 @@ "server_reboot_confirm": "The server will reboot immediatly, are you sure? [{answers:s}]", "service_add_failed": "Could not add the service '{service:s}'", "service_added": "The service '{service:s}' added", - "service_already_started": "The service '{service:s}' has already been started", + "service_already_started": "The service '{service:s}' is running already", "service_already_stopped": "The service '{service:s}' has already been stopped", "service_cmd_exec_failed": "Could not execute the command '{command:s}'", "service_description_avahi-daemon": "Allows you to reach your server using 'yunohost.local' in your local network", @@ -475,10 +475,10 @@ "service_description_fail2ban": "Protects against brute-force and other kinds of attacks from the Internet", "service_description_glances": "Monitors system info on your server", "service_description_metronome": "Manage XMPP instant messaging accounts", - "service_description_mysql": "Stores applications data (SQL database)", + "service_description_mysql": "Stores app data (SQL database)", "service_description_nginx": "Serves or provides access to all the websites hosted on your server", "service_description_nslcd": "Handles YunoHost user shell connection", - "service_description_php7.0-fpm": "Runs applications written in PHP with NGINX", + "service_description_php7.0-fpm": "Runs apps written in PHP with NGINX", "service_description_postfix": "Used to send and receive e-mails", "service_description_redis-server": "A specialized database used for rapid data access, task queue, and communication between programs", "service_description_rmilter": "Checks various parameters in e-mails", @@ -486,42 +486,42 @@ "service_description_slapd": "Stores users, domains and related info", "service_description_ssh": "Allows you to connect remotely to your server via a terminal (SSH protocol)", "service_description_yunohost-api": "Manages interactions between the YunoHost web interface and the system", - "service_description_yunohost-firewall": "Manages open and close connexion ports to services", + "service_description_yunohost-firewall": "Manages open and close connection ports to services", "service_disable_failed": "Could not turn off the service '{service:s}'\n\nRecent service logs:{logs:s}", - "service_disabled": "'{service:s}' service turned off", + "service_disabled": "The '{service:s}' service was turned off", "service_enable_failed": "Could not turn on the service '{service:s}'\n\nRecent service logs:{logs:s}", - "service_enabled": "'{service:s}' service turned off", - "service_no_log": "No log to display for service '{service:s}'", + "service_enabled": "The '{service:s}' service was turned off", + "service_no_log": "No logs to display for the service '{service:s}'", "service_regen_conf_is_deprecated": "'yunohost service regen-conf' is deprecated! Please use 'yunohost tools regen-conf' instead.", "service_remove_failed": "Could not remove the service '{service:s}'", "service_removed": "'{service:s}' service removed", "service_reload_failed": "Could not reload the service '{service:s}'\n\nRecent service logs:{logs:s}", - "service_reloaded": "'{service:s}' service reloaded", + "service_reloaded": "The '{service:s}' service was reloaded", "service_restart_failed": "Could not restart the service '{service:s}'\n\nRecent service logs:{logs:s}", "service_restarted": "'{service:s}' service restarted", "service_reload_or_restart_failed": "Could not reload or restart the service '{service:s}'\n\nRecent service logs:{logs:s}", - "service_reloaded_or_restarted": "'{service:s}' service reloaded or restarted", + "service_reloaded_or_restarted": "The '{service:s}' service was reloaded or restarted", "service_start_failed": "Could not start the service '{service:s}'\n\nRecent service logs:{logs:s}", "service_started": "'{service:s}' service started", "service_stop_failed": "Could not stop the service '{service:s}'\n\nRecent service logs:{logs:s}", - "service_stopped": "'{service:s}' service stopped", + "service_stopped": "The '{service:s}' service stopped", "service_unknown": "Unknown service '{service:s}'", "ssowat_conf_generated": "SSOwat configuration generated", "ssowat_conf_updated": "SSOwat configuration updated", - "ssowat_persistent_conf_read_error": "Could not read persistent SSOwat configuration: {error:s}. Edit /etc/ssowat/conf.json.persistent file to fix the JSON syntax", - "ssowat_persistent_conf_write_error": "Could not save persistent SSOwat configuration: {error:s}. Edit /etc/ssowat/conf.json.persistent file to fix the JSON syntax", + "ssowat_persistent_conf_read_error": "Could not read persistent SSOwat configuration: {error:s}. Edit the /etc/ssowat/conf.json.persistent file to fix the JSON syntax", + "ssowat_persistent_conf_write_error": "Could not save persistent SSOwat configuration: {error:s}. Edit the /etc/ssowat/conf.json.persistent file to fix the JSON syntax", "system_upgraded": "System upgraded", "system_username_exists": "Username already exists in the list of system users", "this_action_broke_dpkg": "This action broke dpkg/APT (the system package managers)… You can try to solve this issue by connecting through SSH and running `sudo dpkg --configure -a`.", - "tools_update_failed_to_app_fetchlist": "Could not update YunoHost's applists because: {error}", + "tools_update_failed_to_app_fetchlist": "Could not update YunoHost's app lists because: {error}", "tools_upgrade_at_least_one": "Please specify '--apps', or '--system'", "tools_upgrade_cant_both": "Cannot upgrade both system and apps at the same time", "tools_upgrade_cant_hold_critical_packages": "Could not hold critical packages…", - "tools_upgrade_cant_unhold_critical_packages": "Could not to unhold critical packages…", + "tools_upgrade_cant_unhold_critical_packages": "Could not unhold critical packages…", "tools_upgrade_regular_packages": "Now upgrading 'regular' (non-yunohost-related) packages…", "tools_upgrade_regular_packages_failed": "Could not upgrade packages: {packages_list}", "tools_upgrade_special_packages": "Now upgrading 'special' (yunohost-related) packages…", - "tools_upgrade_special_packages_explanation": "This action will end, but the actual special upgrade will continue in background. Please don't start any other action on your server in the next ~10 minutes (depending on your hardware speed). Once it i done, you may have to log in on the webadmin page again. The upgrade log will be available in Tools → Log (on the webadmin page) or through 'yunohost log list' (from the command line).", + "tools_upgrade_special_packages_explanation": "This action will end, but the actual special upgrade will continue in background. Please don't start any other actions on your server the next ~10 minutes (depending on hardware speed). Once done, you may have to log in on the webadmin page again. The upgrade log will be available in Tools → Log (on the webadmin page) or through 'yunohost log list' (from the command-line).", "tools_upgrade_special_packages_completed": "YunoHost package upgrade completed.\nPress [Enter] to get the command line back", "unbackup_app": "App '{app:s}' will not be saved", "unexpected_error": "Something unexpected went wrong: {error}", @@ -531,14 +531,14 @@ "update_apt_cache_failed": "Could not to update the cache of APT (Debian's package manager). Here is a dump of the sources.list lines, which might help identify problematic lines: \n{sourceslist}", "update_apt_cache_warning": "Something went wrong while updating the cache of APT (Debian's package manager). Here is a dump of the sources.list lines, which might help identify problematic lines: \n{sourceslist}", "updating_apt_cache": "Fetching available upgrades for system packages…", - "updating_app_lists": "Fetching available upgrades for applications…", + "updating_app_lists": "Fetching available upgrades for apps…", "upgrade_complete": "Upgrade complete", "upgrading_packages": "Upgrading packages…", "upnp_dev_not_found": "No UPnP device found", "upnp_disabled": "UPnP turned off", "upnp_enabled": "UPnP turned on", "upnp_port_open_failed": "Could not open port via UPnP", - "user_already_exists": "User {user} already exists", + "user_already_exists": "The user '{user}' already exists", "user_created": "User created", "user_creation_failed": "Could not create user {user}: {error}", "user_deleted": "User deleted", @@ -552,7 +552,7 @@ "yunohost_already_installed": "YunoHost is already installed", "yunohost_ca_creation_failed": "Could not create certificate authority", "yunohost_ca_creation_success": "Local certification authority created.", - "yunohost_configured": "YunoHost now configured", + "yunohost_configured": "YunoHost is now configured", "yunohost_installing": "Installing YunoHost…", - "yunohost_not_installed": "YunoHost is incorrectly or not correctly installed. Please run 'yunohost tools postinstall'" + "yunohost_not_installed": "YunoHost is not correctly installed. Please run 'yunohost tools postinstall'" } From dcea6ae5fafcd9415ff8df34542286416797c859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Allan=20Nordh=C3=B8y?= Date: Mon, 14 Oct 2019 21:08:55 +0000 Subject: [PATCH 067/127] This migration, Co-Authored-By: Alexandre Aubin --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 54966135f..5859dca6c 100644 --- a/locales/en.json +++ b/locales/en.json @@ -331,7 +331,7 @@ "migration_0005_postgresql_94_not_installed": "PostgreSQL was not installed on your system. Nothing to do.", "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 is installed, but not postgresql 9.6‽ Something weird might have happened on your system:(…", "migration_0005_not_enough_space": "Make sufficient space available in {path} to run the migration.", - "migration_0006_disclaimer": "YunoHost now expects the admin and root passwords to be synchronized. This migration, replaces your root password with the admin password.", + "migration_0006_disclaimer": "YunoHost now expects the admin and root passwords to be synchronized. This migration replaces your root password with the admin password.", "migration_0007_cancelled": "Could not improve the way your SSH configuration is managed.", "migration_0007_cannot_restart": "SSH can't be restarted after trying to cancel migration number 6.", "migration_0008_general_disclaimer": "To improve the security of your server, it is recommended to let YunoHost manage the SSH configuration. Your current SSH setup differs from the recommendation. If you let YunoHost reconfigure it, the way you connect to your server through SSH will change thusly:", From aef8a38071433e0b528bfe14e3319ae007a35541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Allan=20Nordh=C3=B8y?= Date: Mon, 14 Oct 2019 21:10:46 +0000 Subject: [PATCH 068/127] is a broken symlink --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 5859dca6c..27b3bcaef 100644 --- a/locales/en.json +++ b/locales/en.json @@ -115,7 +115,7 @@ "backup_output_directory_forbidden": "Pick a different output directory. Backups can not be created in /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var or /home/yunohost.backup/archives sub-folders", "backup_output_directory_not_empty": "You should pick an empty output directory", "backup_output_directory_required": "You must provide an output directory for the backup", - "backup_output_symlink_dir_broken": "Your archive directory '{path:s}' only contains a broken symlink. Maybe you forgot to re/mount or plug in the storage medium it points to.", + "backup_output_symlink_dir_broken": "Your archive directory '{path:s}' is a broken symlink. Maybe you forgot to re/mount or plug in the storage medium it points to.", "backup_permission": "Backup permission for app {app:s}", "backup_php5_to_php7_migration_may_fail": "Could not convert your archive to support PHP 7, you may be unable to restore your PHP apps (reason: {error:s})", "backup_running_hooks": "Running backup hooks…", From af44f4c73e2d3689ec5355b132581ca871d358b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Allan=20Nordh=C3=B8y?= Date: Mon, 14 Oct 2019 21:13:19 +0000 Subject: [PATCH 069/127] This way is used, could not be prepared --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 27b3bcaef..9f9cb05ba 100644 --- a/locales/en.json +++ b/locales/en.json @@ -89,7 +89,7 @@ "backup_archive_open_failed": "Could not open the backup archive", "backup_archive_system_part_not_available": "System part '{part:s}' unavailable in this backup", "backup_archive_writing_error": "Could not add the files '{source:s}' (named in the archive '{dest:s}') to be backed up into the compressed archive '{archive:s}'", - "backup_ask_for_copying_if_needed": "Do you want to perform the backup using {size:s} MB temporarily due to inability to prepare some files for backup using a more efficient method?", + "backup_ask_for_copying_if_needed": "Do you want to perform the backup using {size:s} MB temporarily? (This way is used since some files could not be prepared using a more efficient method.)", "backup_borg_not_implemented": "The Borg backup method is not yet implemented", "backup_cant_mount_uncompress_archive": "Could not mount the uncompressed archive as write protected", "backup_cleaning_failed": "Could not clean-up the temporary backup folder", From a8deabc36976947be492ea2857bbfd25a6b17e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Allan=20Nordh=C3=B8y?= Date: Mon, 14 Oct 2019 21:17:11 +0000 Subject: [PATCH 070/127] Start all required --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 9f9cb05ba..ed7f08efd 100644 --- a/locales/en.json +++ b/locales/en.json @@ -6,7 +6,7 @@ "admin_password_changed": "The administration password got changed", "admin_password_too_long": "Please choose a password shorter than 127 characters", "already_up_to_date": "Nothing to do. Everything is already up-to-date.", - "app_action_cannot_be_ran_because_required_services_down": "This app requires more services to run. Before continuing, try to restart the following services (and possibly investigate why they are down): {services}", + "app_action_cannot_be_ran_because_required_services_down": "Start all required services to run this app. Try to restart the following ones (and possibly investigate why they are down): {services}", "app_action_broke_system": "This action seem to have broke these important services: {services}", "app_already_installed": "{app:s} is already installed", "app_already_installed_cant_change_url": "This app is already installed. The URL cannot be changed just by this function. Look into `app changeurl` if it's available.", From 7d0119ade48e9627be25e5857f9d0ff91bd65747 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 15 Oct 2019 01:06:04 +0200 Subject: [PATCH 071/127] Fix backup info.json format... --- src/yunohost/backup.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index c28160342..4bf8d8afc 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -602,10 +602,10 @@ class BackupManager(): env=env_dict, chdir=self.work_dir) - ret_succeed = {hook: {path:result["state"] for path, result in infos.items()} + ret_succeed = {hook: [path for path, result in infos.items() if result["state"] == "succeed"] for hook, infos in ret.items() if any(result["state"] == "succeed" for result in infos.values())} - ret_failed = {hook: {path:result["state"] for path, result in infos.items.items()} + ret_failed = {hook: [path for path, result in infos.items.items() if result["state"] == "failed"] for hook, infos in ret.items() if any(result["state"] == "failed" for result in infos.values())} @@ -2371,6 +2371,13 @@ 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(): + + # Stupid legacy fix for weird format between 3.5 and 3.6 + if isinstance(key_info, dict): + key_info = key_info.keys() + + info[category][name] = key_info = {"paths": key_info} + if name in info["size_details"][category].keys(): key_info["size"] = info["size_details"][category][name] if human_readable: From 6dc720f3cfbf5945d89614587f6333038d8dffa6 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 15 Oct 2019 02:36:12 +0200 Subject: [PATCH 072/127] [yolo] Use read_json / write_to_json helpers to read/write ssowat conf.json.persistent --- locales/en.json | 2 -- src/yunohost/app.py | 22 +++++++++------------- src/yunohost/tools.py | 16 ++++------------ src/yunohost/user.py | 21 +++++++++------------ 4 files changed, 22 insertions(+), 39 deletions(-) diff --git a/locales/en.json b/locales/en.json index a341a6b4f..cc73d658a 100644 --- a/locales/en.json +++ b/locales/en.json @@ -508,8 +508,6 @@ "service_unknown": "Unknown service '{service:s}'", "ssowat_conf_generated": "SSOwat configuration generated", "ssowat_conf_updated": "SSOwat configuration updated", - "ssowat_persistent_conf_read_error": "Could not read persistent SSOwat configuration: {error:s}. Edit /etc/ssowat/conf.json.persistent file to fix the JSON syntax", - "ssowat_persistent_conf_write_error": "Could not save persistent SSOwat configuration: {error:s}. Edit /etc/ssowat/conf.json.persistent file to fix the JSON syntax", "system_upgraded": "System upgraded", "system_username_exists": "Username already exists in the list of system users", "this_action_broke_dpkg": "This action broke dpkg/APT (the system package managers)… You can try to solve this issue by connecting through SSH and running `sudo dpkg --configure -a`.", diff --git a/src/yunohost/app.py b/src/yunohost/app.py index f0b4d3c25..8ac2bcb11 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -41,7 +41,7 @@ from datetime import datetime from moulinette import msignals, m18n, msettings from moulinette.utils.log import getActionLogger -from moulinette.utils.filesystem import read_json, read_toml +from moulinette.utils.filesystem import read_json, read_toml, write_to_json from yunohost.service import service_log, service_status, _run_service_command from yunohost.utils import packages @@ -1233,25 +1233,21 @@ def app_makedefault(operation_logger, app, domain=None): raise YunohostError('app_make_default_location_already_used', app=app, domain=app_domain, other_app=app_map(raw=True)[domain]["/"]["id"]) - try: - with open('/etc/ssowat/conf.json.persistent') as json_conf: - ssowat_conf = json.loads(str(json_conf.read())) - except ValueError as e: - raise YunohostError('ssowat_persistent_conf_read_error', error=e) - except IOError: + # TODO / FIXME : current trick is to add this to conf.json.persisten + # This is really not robust and should be improved + # e.g. have a flag in /etc/yunohost/apps/$app/ to say that this is the + # default app or idk... + if not os.path.exists('/etc/ssowat/conf.json.persistent'): ssowat_conf = {} + else: + ssowat_conf = read_json('/etc/ssowat/conf.json.persistent') if 'redirected_urls' not in ssowat_conf: ssowat_conf['redirected_urls'] = {} ssowat_conf['redirected_urls'][domain + '/'] = app_domain + app_path - try: - with open('/etc/ssowat/conf.json.persistent', 'w+') as f: - json.dump(ssowat_conf, f, sort_keys=True, indent=4) - except IOError as e: - raise YunohostError('ssowat_persistent_conf_write_error', error=e) - + write_to_json('/etc/ssowat/conf.json.persistent', ssowat_conf) os.system('chmod 644 /etc/ssowat/conf.json.persistent') logger.success(m18n.n('ssowat_conf_updated')) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 64689fe0c..679bf1190 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -350,25 +350,17 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False, os.system('hostname yunohost.yunohost.org') # Add a temporary SSOwat rule to redirect SSO to admin page - try: - with open('/etc/ssowat/conf.json.persistent') as json_conf: - ssowat_conf = json.loads(str(json_conf.read())) - except ValueError as e: - raise YunohostError('ssowat_persistent_conf_read_error', error=str(e)) - except IOError: + if not os.path.exists('/etc/ssowat/conf.json.persistent'): ssowat_conf = {} + else: + ssowat_conf = read_json('/etc/ssowat/conf.json.persistent') if 'redirected_urls' not in ssowat_conf: ssowat_conf['redirected_urls'] = {} ssowat_conf['redirected_urls']['/'] = domain + '/yunohost/admin' - try: - with open('/etc/ssowat/conf.json.persistent', 'w+') as f: - json.dump(ssowat_conf, f, sort_keys=True, indent=4) - except IOError as e: - raise YunohostError('ssowat_persistent_conf_write_error', error=str(e)) - + write_to_json('/etc/ssowat/conf.json.persistent', ssowat_conf) os.system('chmod 644 /etc/ssowat/conf.json.persistent') # Create SSL CA diff --git a/src/yunohost/user.py b/src/yunohost/user.py index fe27492f4..e12cccb9b 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -35,8 +35,10 @@ import subprocess import copy from moulinette import m18n -from yunohost.utils.error import YunohostError from moulinette.utils.log import getActionLogger +from moulinette.utils.filesystem import read_json, write_to_json, read_yaml, write_to_yaml + +from yunohost.utils.error import YunohostError from yunohost.service import service_status from yunohost.log import is_unit_operation @@ -195,21 +197,16 @@ def user_create(operation_logger, username, firstname, lastname, mail, password, attr_dict['mail'] = [attr_dict['mail']] + aliases # If exists, remove the redirection from the SSO - try: - with open('/etc/ssowat/conf.json.persistent') as json_conf: - ssowat_conf = json.loads(str(json_conf.read())) - except ValueError as e: - raise YunohostError('ssowat_persistent_conf_read_error', error=str(e)) - except IOError: + if not os.path.exists('/etc/ssowat/conf.json.persistent'): ssowat_conf = {} + else: + ssowat_conf = read_json('/etc/ssowat/conf.json.persistent') if 'redirected_urls' in ssowat_conf and '/' in ssowat_conf['redirected_urls']: del ssowat_conf['redirected_urls']['/'] - try: - with open('/etc/ssowat/conf.json.persistent', 'w+') as f: - json.dump(ssowat_conf, f, sort_keys=True, indent=4) - except IOError as e: - raise YunohostError('ssowat_persistent_conf_write_error', error=str(e)) + + write_to_json('/etc/ssowat/conf.json.persistent', ssowat_conf) + os.system('chmod 644 /etc/ssowat/conf.json.persistent') try: ldap.add('uid=%s,ou=users' % username, attr_dict) From 4def4dfa6a7cef4137498eaece55b4732f0559a8 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 15 Oct 2019 14:54:52 +0200 Subject: [PATCH 073/127] [yolofix] Should have a list of string to be able to join() later --- src/yunohost/tools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 679bf1190..28b507707 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -608,8 +608,8 @@ def tools_upgrade(operation_logger, apps=None, system=False): # randomly from yunohost itself... upgrading them is likely to critical_packages = ("moulinette", "yunohost", "yunohost-admin", "ssowat", "python") - critical_packages_upgradable = [p for p in upgradables if p["name"] in critical_packages] - noncritical_packages_upgradable = [p for p in upgradables if p["name"] not in critical_packages] + critical_packages_upgradable = [p["name"] for p in upgradables if p["name"] in critical_packages] + noncritical_packages_upgradable = [p["name"] for p in upgradables if p["name"] not in critical_packages] # Prepare dist-upgrade command dist_upgrade = "DEBIAN_FRONTEND=noninteractive" From f31c8c7475f054482852ac44d7b263fa5371d095 Mon Sep 17 00:00:00 2001 From: pitfd Date: Mon, 14 Oct 2019 09:14:40 +0000 Subject: [PATCH 074/127] Translated using Weblate (German) Currently translated at 39.4% (218 of 554 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/de/ --- locales/de.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/locales/de.json b/locales/de.json index 1fe279d6b..6699f508c 100644 --- a/locales/de.json +++ b/locales/de.json @@ -413,5 +413,6 @@ "global_settings_setting_security_password_admin_strength": "Stärke des Admin-Passworts", "global_settings_key_doesnt_exists": "Der Schlüssel'{settings_key:s}' existiert nicht in den globalen Einstellungen, du kannst alle verfügbaren Schlüssel sehen, indem du 'yunohost settings list' ausführst", "log_app_makedefault": "Mache '{}' zur Standard-Anwendung", - "hook_json_return_error": "Konnte die Rückkehr vom Einsprungpunkt {path:s} nicht lesen. Fehler: {msg:s}. Unformatierter Inhalt: {raw_content}" + "hook_json_return_error": "Konnte die Rückkehr vom Einsprungpunkt {path:s} nicht lesen. Fehler: {msg:s}. Unformatierter Inhalt: {raw_content}", + "app_full_domain_unavailable": "Es tut uns leid, aber diese Anwendung erfordert die Installation einer vollständigen Domäne, aber einige andere Anwendungen sind bereits auf der Domäne'{domain}' installiert. Eine mögliche Lösung ist das Hinzufügen und Verwenden einer Subdomain, die dieser Anwendung zugeordnet ist." } From 3aea7f6b04b26de1c634b8029fbe63da63a388ff Mon Sep 17 00:00:00 2001 From: xaloc33 Date: Thu, 10 Oct 2019 08:24:02 +0000 Subject: [PATCH 075/127] Translated using Weblate (Catalan) Currently translated at 100.0% (554 of 554 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ca/ --- locales/ca.json | 385 ++++++++++++++++++++++++++---------------------- 1 file changed, 209 insertions(+), 176 deletions(-) diff --git a/locales/ca.json b/locales/ca.json index f5c040670..1476d5fb5 100644 --- a/locales/ca.json +++ b/locales/ca.json @@ -1,31 +1,31 @@ { "action_invalid": "Acció '{action:s}' invàlida", "admin_password": "Contrasenya d'administració", - "admin_password_change_failed": "No s'ha pogut canviar la contrasenya", + "admin_password_change_failed": "No es pot canviar la contrasenya", "admin_password_changed": "S'ha canviat la contrasenya d'administració", "app_already_installed": "{app:s} ja està instal·lada", "app_already_installed_cant_change_url": "Aquesta aplicació ja està instal·lada. La URL no és pot canviar únicament amb aquesta funció. Mireu a \"app changeurl\" si està disponible.", "app_already_up_to_date": "{app:s} ja està actualitzada", - "app_argument_choice_invalid": "Aquesta opció no és vàlida per l'argument '{name:s}', ha de ser una de {choices:s}", - "app_argument_invalid": "Valor invàlid per l'argument '{name:s}':{error:s}", + "app_argument_choice_invalid": "Utilitzeu una de les opcions «{choices:s}» per l'argument «{name:s}»", + "app_argument_invalid": "Escolliu un valor vàlid per l'argument «{name:s}»: {error:s}", "app_argument_required": "Es necessita l'argument '{name:s}'", "app_change_no_change_url_script": "L'aplicació {app_name:s} encara no permet canviar la seva URL, es possible que s'hagi d'actualitzar.", - "app_change_url_failed_nginx_reload": "No s'ha pogut tornar a carregar nginx. Aquí teniu el resultat de \"nginx -t\":\n{nginx_errors:s}", + "app_change_url_failed_nginx_reload": "No s'ha pogut tornar a carregar NGINX. Aquí teniu el resultat de \"nginx -t\":\n{nginx_errors:s}", "app_change_url_identical_domains": "L'antic i el nou domini/camí són idèntics ('{domain:s}{path:s}'), no hi ha res per fer.", - "app_change_url_no_script": "Aquesta aplicació '{app_name:s}' encara no permet modificar la URL. Potser s'ha d'actualitzar l'aplicació.", - "app_change_url_success": "La URL de {app:s} s'ha canviat correctament a {domain:s}{path:s}", + "app_change_url_no_script": "Aquesta aplicació '{app_name:s}' encara no permet modificar la URL. Potser s'ha d'actualitzar.", + "app_change_url_success": "La URL de {app:s} ara és {domain:s}{path:s}", "app_extraction_failed": "No s'han pogut extreure els fitxers d'instal·lació", - "app_id_invalid": "Id de l'aplicació incorrecte", + "app_id_invalid": "ID de l'aplicació incorrecte", "app_incompatible": "L'aplicació {app} no és compatible amb la teva versió de YunoHost", - "app_install_files_invalid": "Fitxers d'instal·lació invàlids", - "app_location_already_used": "L'aplicació '{app}' ja està instal·lada en aquest camí ({path})", + "app_install_files_invalid": "Aquests fitxers no es poden instal·lar", + "app_location_already_used": "L'aplicació «{app}» ja està instal·lada en ({path})", "app_make_default_location_already_used": "No es pot fer l'aplicació '{app}' per defecte en el domini {domain} ja que ja és utilitzat per una altra aplicació '{other_app}'", - "app_location_install_failed": "No s'ha pogut instal·lar l'aplicació en aquest camí ja que entra en conflicte amb l'aplicació '{other_app}' ja instal·lada a '{other_path}'", - "app_location_unavailable": "Aquesta url no està disponible o entra en conflicte amb aplicacions ja instal·lades:\n{apps:s}", - "app_manifest_invalid": "Manifest d'aplicació incorrecte: {error}", + "app_location_install_failed": "No s'ha pogut instal·lar l'aplicació aquí ja que entra en conflicte amb l'aplicació «{other_app}» ja instal·lada a «{other_path}»", + "app_location_unavailable": "Aquesta URL no està disponible o entra en conflicte amb aplicacions ja instal·lades:\n{apps:s}", + "app_manifest_invalid": "Hi ha algun error amb el manifest de l'aplicació: {error}", "app_no_upgrade": "No hi ha cap aplicació per actualitzar", "app_not_correctly_installed": "{app:s} sembla estar mal instal·lada", - "app_not_installed": "L'aplicació «{app:s}» no està instal·lada. Aquí hi ha la llista d'aplicacions instal·lades: {all_apps}", + "app_not_installed": "No s'ha trobat l'aplicació «{app:s}» en la llista d'aplicacions instal·lades: {all_apps}", "app_not_properly_removed": "{app:s} no s'ha pogut suprimir correctament", "app_package_need_update": "El paquet de l'aplicació {app} ha de ser actualitzat per poder seguir els canvis de YunoHost", "app_removed": "{app:s} ha estat suprimida", @@ -35,22 +35,22 @@ "app_sources_fetch_failed": "No s'han pogut carregar els fitxers font, l'URL és correcta?", "app_unknown": "Aplicació desconeguda", "app_unsupported_remote_type": "El tipus remot utilitzat per l'aplicació no està suportat", - "app_upgrade_app_name": "Actualitzant l'aplicació {app}…", + "app_upgrade_app_name": "Actualitzant {app}…", "app_upgrade_failed": "No s'ha pogut actualitzar {app:s}", "app_upgrade_some_app_failed": "No s'han pogut actualitzar algunes aplicacions", - "app_upgraded": "{app:s} ha estat actualitzada", + "app_upgraded": "S'ha actualitzat {app:s}", "appslist_corrupted_json": "No s'han pogut carregar les llistes d'aplicacions. Sembla que {filename:s} està danyat.", "appslist_could_not_migrate": "No s'ha pogut migrar la llista d'aplicacions {appslist:s}! No s'ha pogut analitzar la URL... L'antic cronjob s'ha guardat a {bkp_file:s}.", - "appslist_fetched": "S'ha descarregat la llista d'aplicacions {appslist:s} correctament", + "appslist_fetched": "S'ha actualitzat la llista d'aplicacions {appslist:s}", "appslist_migrating": "Migrant la llista d'aplicacions {appslist:s}…", "appslist_name_already_tracked": "Ja hi ha una llista d'aplicacions registrada amb el nom {name:s}.", "appslist_removed": "S'ha eliminat la llista d'aplicacions {appslist:s}", - "appslist_retrieve_bad_format": "L'arxiu obtingut per la llista d'aplicacions {appslist:s} no és vàlid", + "appslist_retrieve_bad_format": "No s'ha pogut llegir la llista d'aplicacions obtinguda {appslist:s}", "appslist_retrieve_error": "No s'ha pogut obtenir la llista d'aplicacions remota {appslist:s}: {error:s}", "appslist_unknown": "La llista d'aplicacions {appslist:s} es desconeguda.", "appslist_url_already_tracked": "Ja hi ha una llista d'aplicacions registrada amb al URL {url:s}.", "ask_current_admin_password": "Contrasenya d'administrador actual", - "ask_email": "Correu electrònic", + "ask_email": "Adreça de correu electrònic", "ask_firstname": "Nom", "ask_lastname": "Cognom", "ask_list_to_remove": "Llista per a suprimir", @@ -58,31 +58,31 @@ "ask_new_admin_password": "Nova contrasenya d'administrador", "ask_password": "Contrasenya", "ask_path": "Camí", - "backup_abstract_method": "Encara no s'ha implementat aquest mètode de copia de seguretat", + "backup_abstract_method": "Encara està per implementar aquest mètode de còpia de seguretat", "backup_action_required": "S'ha d'especificar què s'ha de guardar", "backup_app_failed": "No s'ha pogut fer la còpia de seguretat de l'aplicació \"{app:s}\"", "backup_applying_method_borg": "Enviant tots els fitxers de la còpia de seguretat al repositori borg-backup…", "backup_applying_method_copy": "Còpia de tots els fitxers a la còpia de seguretat…", "backup_applying_method_custom": "Crida del mètode de còpia de seguretat personalitzat \"{method:s}\"…", - "backup_applying_method_tar": "Creació de l'arxiu tar de la còpia de seguretat…", - "backup_archive_app_not_found": "L'aplicació \"{app:s}\" no es troba dins l'arxiu de la còpia de seguretat", + "backup_applying_method_tar": "Creació de l'arxiu TAR de la còpia de seguretat…", + "backup_archive_app_not_found": "No s'ha pogut trobar l'aplicació «{app:s}» dins l'arxiu de la còpia de seguretat", "backup_archive_broken_link": "No s'ha pogut accedir a l'arxiu de la còpia de seguretat (enllaç invàlid cap a {path:s})", "backup_archive_mount_failed": "No s'ha pogut carregar l'arxiu de la còpia de seguretat", - "backup_archive_name_exists": "Ja hi ha una còpia de seguretat amb aquest nom", + "backup_archive_name_exists": "Ja hi ha una còpia de seguretat amb aquest nom.", "backup_archive_name_unknown": "Còpia de seguretat local \"{name:s}\" desconeguda", "backup_archive_open_failed": "No s'ha pogut obrir l'arxiu de la còpia de seguretat", - "backup_archive_system_part_not_available": "La part \"{part:s}\" del sistema no està disponible en aquesta copia de seguretat", - "backup_archive_writing_error": "No es poden afegir arxius a l'arxiu comprimit de la còpia de seguretat", + "backup_archive_system_part_not_available": "La part «{part:s}» del sistema no està disponible en aquesta copia de seguretat", + "backup_archive_writing_error": "No es poden afegir els arxius «{source:s}» (anomenats en l'arxiu «{dest:s}») a l'arxiu comprimit de la còpia de seguretat «{archive:s}»", "backup_ask_for_copying_if_needed": "Alguns fitxers no s'han pogut preparar per la còpia de seguretat utilitzant el mètode que evita malgastar espai del sistema temporalment. Per fer la còpia de seguretat, s'han d'utilitzar {size:s}MB temporalment. Hi esteu d'acord?", "backup_borg_not_implemented": "El mètode de còpia de seguretat Borg encara no està implementat", - "backup_cant_mount_uncompress_archive": "No es pot carregar en mode de lectura només el directori de l'arxiu descomprimit", + "backup_cant_mount_uncompress_archive": "No es pot carregar l'arxiu descomprimit com a protegit contra escriptura", "backup_cleaning_failed": "No s'ha pogut netejar el directori temporal de la còpia de seguretat", "backup_copying_to_organize_the_archive": "Copiant {size:s}MB per organitzar l'arxiu", "backup_couldnt_bind": "No es pot lligar {src:s} amb {dest:s}.", "backup_created": "S'ha creat la còpia de seguretat", "backup_creating_archive": "Creant l'arxiu de la còpia de seguretat…", "aborting": "Avortant.", - "app_not_upgraded": "Les següents aplicacions no s'han actualitzat: {apps}", + "app_not_upgraded": "L'aplicació «{failed_app}» no s'ha pogut actualitzar, i com a conseqüència l'actualització de les següents aplicacions ha estat cancel·lada: {apps}", "app_start_install": "instal·lant l'aplicació {app}…", "app_start_remove": "Eliminant l'aplicació {app}…", "app_start_backup": "Recuperant els fitxers pels que s'ha de fer una còpia de seguretat per {app}…", @@ -90,24 +90,24 @@ "app_upgrade_several_apps": "S'actualitzaran les següents aplicacions: {apps}", "ask_new_domain": "Nou domini", "ask_new_path": "Nou camí", - "backup_actually_backuping": "S'està creant un arxiu de còpia de seguretat a partir dels fitxers recuperats…", - "backup_creation_failed": "Ha fallat la creació de la còpia de seguretat", + "backup_actually_backuping": "Creant un arxiu de còpia de seguretat a partir dels fitxers recuperats…", + "backup_creation_failed": "No s'ha pogut crear l'arxiu de la còpia de seguretat", "backup_csv_addition_failed": "No s'han pogut afegir fitxers per a fer-ne la còpia de seguretat al fitxer CSV", - "backup_csv_creation_failed": "No s'ha pogut crear el fitxer CSV necessari per a futures operacions de recuperació", - "backup_custom_backup_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa \"backup\"", - "backup_custom_mount_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa \"mount\"", + "backup_csv_creation_failed": "No s'ha pogut crear el fitxer CSV necessari per a la restauració", + "backup_custom_backup_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa «backup»", + "backup_custom_mount_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa «mount»", "backup_custom_need_mount_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa \"need_mount\"", - "backup_delete_error": "No s'ha pogut suprimir \"{path:s}\"", + "backup_delete_error": "No s'ha pogut suprimir «{path:s}»", "backup_deleted": "S'ha suprimit la còpia de seguretat", "backup_extracting_archive": "Extraient l'arxiu de la còpia de seguretat…", - "backup_hook_unknown": "Script de còpia de seguretat \"{hook:s}\" desconegut", - "backup_invalid_archive": "Arxiu de còpia de seguretat no vàlid", - "backup_method_borg_finished": "La còpia de seguretat a borg ha acabat", + "backup_hook_unknown": "Script de còpia de seguretat «{hook:s}» desconegut", + "backup_invalid_archive": "Aquest no és un arxiu de còpia de seguretat", + "backup_method_borg_finished": "La còpia de seguretat a Borg ha acabat", "backup_method_copy_finished": "La còpia de la còpia de seguretat ha acabat", "backup_method_custom_finished": "El mètode de còpia de seguretat personalitzat \"{method:s}\" ha acabat", - "backup_method_tar_finished": "S'ha creat l'arxiu de còpia de seguretat tar", + "backup_method_tar_finished": "S'ha creat l'arxiu de còpia de seguretat TAR", "backup_mount_archive_for_restore": "Preparant l'arxiu per la restauració…", - "good_practices_about_user_password": "Esteu a punt de definir una nova contrasenya d'usuari. La contrasenya ha de tenir un mínim de 8 caràcters ; tot i que és de bona pràctica utilitzar una contrasenya més llarga (és a dir una frase de contrasenya) i/o utilitzar diferents tipus de caràcters (majúscules, minúscules, dígits i caràcters especials).", + "good_practices_about_user_password": "Esteu a punt de definir una nova contrasenya d'usuari. La contrasenya ha de tenir un mínim de 8 caràcters; tot i que és de bona pràctica utilitzar una contrasenya més llarga (és a dir una frase de contrasenya) i/o utilitzar diferents tipus de caràcters (majúscules, minúscules, dígits i caràcters especials).", "password_listed": "Aquesta contrasenya és una de les més utilitzades en el món. Si us plau utilitzeu-ne una més única.", "password_too_simple_1": "La contrasenya ha de tenir un mínim de 8 caràcters", "password_too_simple_2": "La contrasenya ha de tenir un mínim de 8 caràcters i ha de contenir dígits, majúscules i minúscules", @@ -115,42 +115,42 @@ "password_too_simple_4": "La contrasenya ha de tenir un mínim de 12 caràcters i tenir dígits, majúscules, minúscules i caràcters especials", "backup_no_uncompress_archive_dir": "El directori de l'arxiu descomprimit no existeix", "backup_nothings_done": "No hi ha res a guardar", - "backup_output_directory_forbidden": "Directori de sortida no permès. Les còpies de seguretat no es poden crear ni dins els directoris /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ni dins els subdirectoris /home/yunohost.backup/archives", - "backup_output_directory_not_empty": "El directori de sortida no està buit", + "backup_output_directory_forbidden": "Escolliu un directori de sortida different. Les còpies de seguretat no es poden crear ni dins els directoris /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ni dins els subdirectoris /home/yunohost.backup/archives", + "backup_output_directory_not_empty": "Heu d'escollir un directori de sortida buit", "backup_output_directory_required": "Heu d'especificar un directori de sortida per la còpia de seguretat", - "backup_output_symlink_dir_broken": "Teniu un enllaç simbòlic trencat en lloc del directori dels arxius '{path:s}'. Pot ser teniu una configuració per la còpia de seguretat específica en un altre sistema de fitxers, si és el cas segurament heu oblidat muntar o connectar el disc dur o la clau USB.", - "backup_php5_to_php7_migration_may_fail": "No s'ha pogut convertir l'arxiu per suportar php7, la restauració de les vostres aplicacions pot fallar (raó: {error:s})", + "backup_output_symlink_dir_broken": "Teniu un enllaç simbòlic trencat en lloc del directori del arxiu «{path:s}». Pot ser teniu una configuració per la còpia de seguretat específica en un altre sistema de fitxers, si és el cas segurament heu oblidat muntar o connectar el disc dur o la clau USB.", + "backup_php5_to_php7_migration_may_fail": "No s'ha pogut convertir l'arxiu per suportar PHP 7, pot ser que no es puguin restaurar les vostres aplicacions PHP (raó: {error:s})", "backup_running_hooks": "Executant els scripts de la còpia de seguretat…", "backup_system_part_failed": "No s'ha pogut fer la còpia de seguretat de la part \"{part:s}\" del sistema", - "backup_unable_to_organize_files": "No s'han pogut organitzar els fitxers dins de l'arxiu amb el mètode ràpid", - "backup_with_no_backup_script_for_app": "L'aplicació {app:s} no té un script de còpia de seguretat. Serà ignorat.", - "backup_with_no_restore_script_for_app": "L'aplicació {app:s} no té un script de restauració, no podreu restaurar automàticament la còpia de seguretat d'aquesta aplicació.", - "certmanager_acme_not_configured_for_domain": "El certificat pel domini {domain:s} sembla que no està instal·lat correctament. Si us plau executeu primer cert-install per aquest domini.", - "certmanager_attempt_to_renew_nonLE_cert": "El certificat pel domini {domain:s} no ha estat emès per Let's Encrypt. No es pot renovar automàticament!", - "certmanager_attempt_to_renew_valid_cert": "El certificat pel domini {domain:s} està a punt de caducar! (Utilitzeu --force si sabeu el que esteu fent)", + "backup_unable_to_organize_files": "No s'ha pogut utilitzar el mètode ràpid per organitzar els fitxers dins de l'arxiu", + "backup_with_no_backup_script_for_app": "L'aplicació «{app:s}» no té un script de còpia de seguretat. Serà ignorat.", + "backup_with_no_restore_script_for_app": "L'aplicació «{app:s}» no té un script de restauració, no podreu restaurar automàticament la còpia de seguretat d'aquesta aplicació.", + "certmanager_acme_not_configured_for_domain": "El certificat pel domini «{domain:s}» sembla que no està instal·lat correctament. Si us plau executeu primer «cert-install» per aquest domini.", + "certmanager_attempt_to_renew_nonLE_cert": "El certificat pel domini «{domain:s}» no ha estat emès per Let's Encrypt. No es pot renovar automàticament!", + "certmanager_attempt_to_renew_valid_cert": "El certificat pel domini «{domain:s}» està a punt de caducar! (Utilitzeu --force si sabeu el que esteu fent)", "certmanager_attempt_to_replace_valid_cert": "Esteu intentant sobreescriure un certificat correcte i vàlid pel domini {domain:s}! (Utilitzeu --force per ometre)", "certmanager_cannot_read_cert": "S'ha produït un error al intentar obrir el certificat actual pel domini {domain:s} (arxiu: {file:s}), raó: {reason:s}", - "certmanager_cert_install_success": "S'ha instal·lat correctament un certificat Let's Encrypt pel domini {domain:s}!", - "certmanager_cert_install_success_selfsigned": "S'ha instal·lat correctament un certificat auto-signat pel domini {domain:s}!", - "certmanager_cert_renew_success": "S'ha renovat correctament el certificat Let's Encrypt pel domini {domain:s}!", + "certmanager_cert_install_success": "S'ha instal·lat correctament un certificat Let's Encrypt pel domini «{domain:s}»", + "certmanager_cert_install_success_selfsigned": "S'ha instal·lat correctament un certificat auto-signat pel domini «{domain:s}»", + "certmanager_cert_renew_success": "S'ha renovat correctament el certificat Let's Encrypt pel domini «{domain:s}»", "certmanager_cert_signing_failed": "No s'ha pogut firmar el nou certificat", - "certmanager_certificate_fetching_or_enabling_failed": "Sembla que l'activació del nou certificat per {domain:s} ha fallat…", - "certmanager_conflicting_nginx_file": "No s'ha pogut preparar el domini per al desafiament ACME: l'arxiu de configuració nginx {filepath:s} entra en conflicte i s'ha d'eliminar primer", + "certmanager_certificate_fetching_or_enabling_failed": "Sembla que utilitzar el nou certificat per {domain:s} ha fallat…", + "certmanager_conflicting_nginx_file": "No s'ha pogut preparar el domini per al desafiament ACME: l'arxiu de configuració NGINX {filepath:s} entra en conflicte i s'ha d'eliminar primer", "certmanager_couldnt_fetch_intermediate_cert": "S'ha exhaurit el temps d'esperar al intentar recollir el certificat intermedi des de Let's Encrypt. La instal·lació/renovació del certificat s'ha cancel·lat - torneu a intentar-ho més tard.", - "certmanager_domain_cert_not_selfsigned": "El certificat pel domini {domain:s} no és auto-signat Esteu segur de voler canviar-lo? (Utilitzeu --force per fer-ho)", - "certmanager_domain_dns_ip_differs_from_public_ip": "El registre DNS \"A\" pel domini {domain:s} és diferent a l'adreça IP d'aquest servidor. Si heu modificat recentment el registre A, si us plau espereu a que es propagui (hi ha eines per verificar la propagació disponibles a internet). (Si sabeu el que esteu fent, podeu utilitzar --no-checks per desactivar aquestes comprovacions.)", - "certmanager_domain_http_not_working": "Sembla que el domini {domain:s} no és accessible via HTTP. Si us plau verifiqueu que les configuracions DNS i nginx siguin correctes", + "certmanager_domain_cert_not_selfsigned": "El certificat pel domini {domain:s} no és auto-signat Esteu segur de voler canviar-lo? (Utilitzeu «--force» per fer-ho)", + "certmanager_domain_dns_ip_differs_from_public_ip": "El registre DNS \"A\" pel domini «{domain:s}» és diferent a l'adreça IP d'aquest servidor. Si heu modificat recentment el registre A, si us plau espereu a que es propagui (hi ha eines per verificar la propagació disponibles a internet). (Si sabeu el que esteu fent, podeu utilitzar «--no-checks» per desactivar aquestes comprovacions.)", + "certmanager_domain_http_not_working": "Sembla que el domini {domain:s} no és accessible via HTTP. Verifiqueu que les configuracions DNS i NGINX siguin correctes", "certmanager_domain_not_resolved_locally": "El domini {domain:s} no es pot resoldre dins del vostre servidor YunoHost. Això pot passar si heu modificat recentment el registre DNS. Si és així, si us plau espereu unes hores per a que es propagui. Si el problema continua, considereu afegir {domain:s} a /etc/hosts. (Si sabeu el que esteu fent, podeu utilitzar --no-checks per desactivar aquestes comprovacions.)", - "certmanager_domain_unknown": "Domini desconegut {domain:s}", - "certmanager_error_no_A_record": "No s'ha trobat cap registre DNS \"A\" per {domain:s}. Heu de fer que el vostre nom de domini apunti cap a la vostra màquina per tal de poder instal·lar un certificat Let's Encrypt! (Si sabeu el que esteu fent, podeu utilitzar --no-checks per desactivar aquestes comprovacions.)", + "certmanager_domain_unknown": "Domini desconegut «{domain:s}»", + "certmanager_error_no_A_record": "No s'ha trobat cap registre DNS «A» per «{domain:s}». Heu de fer que el vostre nom de domini apunti cap a la vostra màquina per tal de poder instal·lar un certificat Let's Encrypt. (Si sabeu el que esteu fent, podeu utilitzar «--no-checks» per desactivar aquestes comprovacions.)", "certmanager_hit_rate_limit": "S'han emès massa certificats recentment per aquest mateix conjunt de dominis {domain:s}. Si us plau torneu-ho a intentar més tard. Consulteu https://letsencrypt.org/docs/rate-limits/ per obtenir més detalls", - "certmanager_http_check_timeout": "S'ha exhaurit el temps d'espera quan el servidor ha intentat contactar amb ell mateix via HTTP utilitzant la seva adreça IP pública (domini domain:s} amb IP {ip:s}). Pot ser degut a hairpinning o a que el talla focs/router al que està connectat el servidor estan mal configurats.", + "certmanager_http_check_timeout": "S'ha exhaurit el temps d'espera quan el servidor ha intentat contactar amb ell mateix via HTTP utilitzant la seva adreça IP pública (domini «{domain:s}» amb IP «{ip:s}»). Pot ser degut a hairpinning o a que el talla focs/router al que està connectat el servidor estan mal configurats.", "certmanager_no_cert_file": "No s'ha pogut llegir l'arxiu del certificat pel domini {domain:s} (fitxer: {file:s})", "certmanager_self_ca_conf_file_not_found": "No s'ha trobat el fitxer de configuració per l'autoritat del certificat auto-signat (fitxer: {file:s})", "certmanager_unable_to_parse_self_CA_name": "No s'ha pogut analitzar el nom de l'autoritat del certificat auto-signat (fitxer: {file:s})", - "confirm_app_install_warning": "Atenció: aquesta aplicació funciona però no està ben integrada amb YunoHost. Algunes característiques com la autenticació única i la còpia de seguretat/restauració poden no estar disponibles. Voleu instal·lar-la de totes maneres? [{answers:s}] ", - "confirm_app_install_danger": "ATENCIÓ! Aquesta aplicació encara és experimental (si no és que no funciona directament) i és probable que trenqui el sistema! No hauríeu d'instal·lar-la a no ser que sapigueu el que feu. Esteu segurs de voler córrer aquest risc? [{answers:s}] ", - "confirm_app_install_thirdparty": "ATENCIÓ! La instal·lació d'aplicacions de terceres parts pot comprometre la integritat i seguretat del seu sistema. Faci-ho sota la seva responsabilitat.No hauríeu d'instal·lar-ne a no ser que sapigueu el que feu. Esteu segurs de voler córrer aquest risc? [{answers:s}] ", + "confirm_app_install_warning": "Atenció: Aquesta aplicació funciona, però no està ben integrada amb YunoHost. Algunes característiques com la autenticació única i la còpia de seguretat/restauració poden no estar disponibles. Voleu instal·lar-la de totes maneres? [{answers:s}] ", + "confirm_app_install_danger": "PERILL! Aquesta aplicació encara és experimental (si no és que no funciona directament)! No hauríeu d'instal·lar-la a no ser que sapigueu el que feu. No obtindreu CAP AJUDA si l'aplicació no funciona o trenca el sistema... Si accepteu el risc, escriviu «{answers:s}»", + "confirm_app_install_thirdparty": "PERILL! Aquesta aplicació no es part del catàleg d'aplicacions de YunoHost. La instal·lació d'aplicacions de terceres parts pot comprometre la integritat i seguretat del seu sistema. No hauríeu d'instal·lar-ne a no ser que sapigueu el que feu. No obtindreu CAP AJUDA si l'aplicació no funciona o trenca el sistema… Si accepteu el risc, escriviu «{answers:s}»", "custom_app_url_required": "Heu de especificar una URL per actualitzar la vostra aplicació personalitzada {app:s}", "custom_appslist_name_required": "Heu d'especificar un nom per la vostra llista d'aplicacions personalitzada", "diagnosis_debian_version_error": "No s'ha pogut obtenir la versió Debian: {error}", @@ -160,22 +160,22 @@ "diagnosis_monitor_system_error": "No es pot monitorar el sistema: {error}", "diagnosis_no_apps": "No hi ha cap aplicació instal·lada", "admin_password_too_long": "Trieu una contrasenya de menys de 127 caràcters", - "dpkg_is_broken": "No es pot fer això en aquest instant perquè dpkg/apt (els gestors de paquets del sistema) sembla estar mal configurat... Podeu intentar solucionar-ho connectant-vos per ssh i executant \"sudo dpkg --configure -a\".", + "dpkg_is_broken": "No es pot fer això en aquest instant perquè dpkg/APT (els gestors de paquets del sistema) sembla estar mal configurat… Podeu intentar solucionar-ho connectant-vos per SSH i executant «sudo dpkg --configure -a».", "dnsmasq_isnt_installed": "sembla que dnsmasq no està instal·lat, executeu \"apt-get remove bind9 && apt-get install dnsmasq\"", "domain_cannot_remove_main": "No es pot eliminar el domini principal. S'ha d'establir un nou domini primer", "domain_cert_gen_failed": "No s'ha pogut generar el certificat", "domain_created": "S'ha creat el domini", - "domain_creation_failed": "No s'ha pogut crear el domini", + "domain_creation_failed": "No s'ha pogut crear el domini {domain}: {error}", "domain_deleted": "S'ha eliminat el domini", - "domain_deletion_failed": "No s'ha pogut eliminar el domini", + "domain_deletion_failed": "No s'ha pogut eliminar el domini {domini}: {error}", "domain_exists": "El domini ja existeix", - "app_action_cannot_be_ran_because_required_services_down": "Aquesta aplicació necessita serveis que estan aturats. Abans de continuar, hauríeu d'intentar arrancar de nou els serveis següents (i també investigar perquè estan aturats) : {services}", + "app_action_cannot_be_ran_because_required_services_down": "Aquesta aplicació necessita serveis que estan aturats. Abans de continuar, hauríeu d'intentar arrancar de nou els serveis següents (i també investigar perquè estan aturats): {services}", "domain_dns_conf_is_just_a_recommendation": "Aquesta ordre mostra la configuració *recomanada*. En cap cas fa la configuració del DNS. És la vostra responsabilitat configurar la zona DNS en el vostre registrar en acord amb aquesta recomanació.", "domain_dyndns_already_subscribed": "Ja us heu subscrit a un domini DynDNS", "domain_dyndns_dynette_is_unreachable": "No s'ha pogut abastar la dynette YunoHost, o bé YunoHost no està connectat a internet correctament o bé el servidor dynette està caigut. Error: {error}", "domain_dyndns_invalid": "Domini no vàlid per utilitzar amb DynDNS", "domain_dyndns_root_unknown": "Domini DynDNS principal desconegut", - "domain_hostname_failed": "No s'ha pogut establir un nou nom d'amfitrió. Això podria causar problemes més tard (no és segur ... podria no passar res).", + "domain_hostname_failed": "No s'ha pogut establir un nou nom d'amfitrió. Això podria causar problemes més tard (podria no passar res).", "domain_uninstall_app_first": "Hi ha una o més aplicacions instal·lades en aquest domini. Desinstal·leu les abans d'eliminar el domini", "domain_unknown": "Domini desconegut", "domain_zone_exists": "El fitxer de zona DNS ja existeix", @@ -187,61 +187,61 @@ "dyndns_could_not_check_available": "No s'ha pogut verificar la disponibilitat de {domain:s} a {provider:s}.", "dyndns_ip_update_failed": "No s'ha pogut actualitzar l'adreça IP al DynDNS", "dyndns_ip_updated": "S'ha actualitzat l'adreça IP al DynDNS", - "dyndns_key_generating": "S'està generant la clau DNS, això pot trigar una estona…", + "dyndns_key_generating": "S'està generant la clau DNS… això pot trigar una estona.", "dyndns_key_not_found": "No s'ha trobat la clau DNS pel domini", "dyndns_no_domain_registered": "No hi ha cap domini registrat amb DynDNS", "dyndns_registered": "S'ha registrat el domini DynDNS", "dyndns_registration_failed": "No s'ha pogut registrar el domini DynDNS: {error:s}", - "dyndns_domain_not_provided": "El proveïdor {provider:s} no pot oferir el domini {domain:s}.", + "dyndns_domain_not_provided": "El proveïdor de DynDNS {provider:s} no pot oferir el domini {domain:s}.", "dyndns_unavailable": "El domini {domain:s} no està disponible.", "executing_command": "Execució de l'ordre « {command:s} »…", "executing_script": "Execució de l'script « {script:s} »…", "extracting": "Extracció en curs…", - "dyndns_cron_installed": "S'ha instal·lat la tasca cron pel DynDNS", + "dyndns_cron_installed": "S'ha creat la tasca cron pel DynDNS", "dyndns_cron_remove_failed": "No s'ha pogut eliminar la tasca cron per a DynDNS: {error}", "dyndns_cron_removed": "S'ha eliminat la tasca cron pel DynDNS", - "experimental_feature": "Atenció: aquesta funcionalitat és experimental i no es considera estable, no s'ha d'utilitzar a excepció de saber el que esteu fent.", + "experimental_feature": "Atenció: Aquesta funcionalitat és experimental i no es considera estable, no s'ha d'utilitzar a excepció de saber el que esteu fent.", "field_invalid": "Camp incorrecte « {:s} »", "file_does_not_exist": "El camí {path:s} no existeix.", - "firewall_reload_failed": "No s'ha pogut tornar a carregar el tallafoc", - "firewall_reloaded": "S'ha tornat a carregar el tallafoc", - "firewall_rules_cmd_failed": "No s'han pogut aplicar algunes regles del tallafoc. Mireu el registre per a més informació.", + "firewall_reload_failed": "No s'ha pogut tornar a carregar el tallafocs", + "firewall_reloaded": "S'ha tornat a carregar el tallafocs", + "firewall_rules_cmd_failed": "No s'han pogut aplicar algunes regles del tallafocs. Més informació en el registre.", "format_datetime_short": "%d/%m/%Y %H:%M", - "global_settings_bad_choice_for_enum": "Opció pel paràmetre {setting:s} incorrecta, s'ha rebut «{choice:s}» però les opcions disponibles són: {available_choices:s}", + "global_settings_bad_choice_for_enum": "Opció pel paràmetre {setting:s} incorrecta, s'ha rebut «{choice:s}», però les opcions disponibles són: {available_choices:s}", "global_settings_bad_type_for_setting": "El tipus del paràmetre {setting:s} és incorrecte. S'ha rebut {received_type:s}, però s'esperava {expected_type:s}", "global_settings_cant_open_settings": "No s'ha pogut obrir el fitxer de configuració, raó: {reason:s}", "global_settings_cant_serialize_settings": "No s'ha pogut serialitzar les dades de configuració, raó: {reason:s}", "global_settings_cant_write_settings": "No s'ha pogut escriure el fitxer de configuració, raó: {reason:s}", "global_settings_key_doesnt_exists": "La clau « {settings_key:s} » no existeix en la configuració global, podeu veure totes les claus disponibles executant « yunohost settings list »", - "global_settings_reset_success": "Èxit. S'ha fet una còpia de seguretat de la configuració anterior a {path:s}", + "global_settings_reset_success": "S'ha fet una còpia de seguretat de la configuració anterior a {path:s}", "global_settings_setting_example_bool": "Exemple d'opció booleana", "global_settings_setting_example_enum": "Exemple d'opció de tipus enumeració", "global_settings_setting_example_int": "Exemple d'opció de tipus enter", "global_settings_setting_example_string": "Exemple d'opció de tipus cadena", - "global_settings_setting_security_nginx_compatibility": "Solució de compromís entre compatibilitat i seguretat pel servidor web nginx. Afecta els criptògrafs (i altres aspectes relacionats amb la seguretat)", + "global_settings_setting_security_nginx_compatibility": "Solució de compromís entre compatibilitat i seguretat pel servidor web NGINX. Afecta els criptògrafs (i altres aspectes relacionats amb la seguretat)", "global_settings_setting_security_password_admin_strength": "Robustesa de la contrasenya d'administrador", "global_settings_setting_security_password_user_strength": "Robustesa de la contrasenya de l'usuari", "global_settings_setting_security_ssh_compatibility": "Solució de compromís entre compatibilitat i seguretat pel servidor SSH. Afecta els criptògrafs (i altres aspectes relacionats amb la seguretat)", - "global_settings_unknown_setting_from_settings_file": "Clau de configuració desconeguda: «{setting_key:s}», refusant-la i guardant-la a /etc/yunohost/settings-unknown.json", + "global_settings_unknown_setting_from_settings_file": "Clau de configuració desconeguda: «{setting_key:s}», refusada i guardada a /etc/yunohost/settings-unknown.json", "global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Permetre la clau d'hoste DSA (obsolet) per la configuració del servei SSH", "global_settings_unknown_type": "Situació inesperada, la configuració {setting:s} sembla tenir el tipus {unknown_type:s} però no és un tipus reconegut pel sistema.", - "good_practices_about_admin_password": "Esteu a punt de definir una nova contrasenya d'administrador. La contrasenya ha de tenir un mínim de 8 caràcters ; tot i que és de bona pràctica utilitzar una contrasenya més llarga (és a dir una frase de contrasenya) i/o utilitzar diferents tipus de caràcters (majúscules, minúscules, dígits i caràcters especials).", - "hook_exec_failed": "No s'ha pogut executar l'script: {path:s}", - "hook_exec_not_terminated": "L'execució de l'script « {path:s} » no s'ha acabat correctament", - "hook_json_return_error": "No s'ha pogut llegir el retorn de l'script {path:s}. Error: {msg:s}. Contingut en brut: {raw_content}", - "hook_list_by_invalid": "Propietat per llistar les accions invàlida", + "good_practices_about_admin_password": "Esteu a punt de definir una nova contrasenya d'administrador. La contrasenya ha de tenir un mínim de 8 caràcters; tot i que és de bona pràctica utilitzar una contrasenya més llarga (és a dir una frase de contrasenya) i/o utilitzar diferents tipus de caràcters (majúscules, minúscules, dígits i caràcters especials).", + "hook_exec_failed": "No s'ha pogut executar el script: {path:s}", + "hook_exec_not_terminated": "El script no s'ha acabat correctament: {path:s}", + "hook_json_return_error": "No s'ha pogut llegir el retorn del script {path:s}. Error: {msg:s}. Contingut en brut: {raw_content}", + "hook_list_by_invalid": "Aquesta propietat no es pot utilitzar per llistar els hooks", "hook_name_unknown": "Nom de script « {name:s} » desconegut", "installation_complete": "Instal·lació completada", - "installation_failed": "Ha fallat la instal·lació", + "installation_failed": "Ha fallat alguna cosa amb la instal·lació", "invalid_url_format": "Format d'URL invàlid", "ip6tables_unavailable": "No podeu modificar les ip6tables aquí. O bé sou en un contenidor o bé el vostre nucli no és compatible amb aquesta opció", "iptables_unavailable": "No podeu modificar les iptables aquí. O bé sou en un contenidor o bé el vostre nucli no és compatible amb aquesta opció", - "log_corrupted_md_file": "El fitxer de metadades yaml associat amb els registres està malmès: « {md_file} »\nError: {error}", + "log_corrupted_md_file": "El fitxer de metadades YAML associat amb els registres està malmès: « {md_file} »\nError: {error}", "log_category_404": "La categoria de registres « {category} » no existeix", "log_link_to_log": "El registre complet d'aquesta operació: «{desc}»", "log_help_to_get_log": "Per veure el registre de l'operació « {desc} », utilitzeu l'ordre « yunohost log display {name} »", - "log_link_to_failed_log": "L'operació « {dec} » ha fallat! Per obtenir ajuda, proveïu el registre complete de l'operació clicant aquí", - "log_help_to_get_failed_log": "L'operació « {dec} » ha fallat! Per obtenir ajuda, compartiu el registre complete de l'operació utilitzant l'ordre « yunohost log display {name} --share »", + "log_link_to_failed_log": "No s'ha pogut completar l'operació « {desc} ». Per obtenir ajuda, proveïu el registre complete de l'operació clicant aquí", + "log_help_to_get_failed_log": "No s'ha pogut completar l'operació « {desc} ». Per obtenir ajuda, compartiu el registre complete de l'operació utilitzant l'ordre « yunohost log display {name} --share »", "log_does_exists": "No hi ha cap registre per l'operació amb el nom« {log} », utilitzeu « yunohost log list » per veure tots els registre d'operació disponibles", "log_operation_unit_unclosed_properly": "L'operació no s'ha tancat de forma correcta", "log_app_addaccess": "Afegir accés a « {} »", @@ -263,7 +263,7 @@ "log_domain_remove": "Elimina el domini « {} » de la configuració del sistema", "log_dyndns_subscribe": "Subscriure's a un subdomini YunoHost « {} »", "log_dyndns_update": "Actualitza la IP associada al subdomini YunoHost « {} »", - "log_letsencrypt_cert_install": "Instal·la el certificat Let's Encrypt al domini « {} »", + "log_letsencrypt_cert_install": "Instal·la un certificat Let's Encrypt al domini « {} »", "log_selfsigned_cert_install": "Instal·la el certificat autosignat al domini « {} »", "log_letsencrypt_cert_renew": "Renova el certificat Let's Encrypt de « {} »", "log_service_enable": "Activa el servei « {} »", @@ -278,79 +278,79 @@ "log_tools_upgrade": "Actualitza els paquets del sistema", "log_tools_shutdown": "Apaga el servidor", "log_tools_reboot": "Reinicia el servidor", - "already_up_to_date": "No hi ha res a fer! Tot està al dia!", + "already_up_to_date": "No hi ha res a fer. Tot està actualitzat.", "dpkg_lock_not_available": "No es pot utilitzar aquesta comanda en aquest moment ja que sembla que un altre programa està utilitzant el lock de dpkg (el gestor de paquets del sistema)", "global_settings_setting_security_postfix_compatibility": "Solució de compromís entre compatibilitat i seguretat pel servidor Postfix. Afecta els criptògrafs (i altres aspectes relacionats amb la seguretat)", "ldap_init_failed_to_create_admin": "La inicialització de LDAP no ha pogut crear l'usuari admin", "ldap_initialized": "S'ha iniciat LDAP", "license_undefined": "indefinit", - "mail_alias_remove_failed": "No s'han pogut eliminar els alias del correu «{mail:s}»", - "mail_domain_unknown": "Domini d'adreça de correu «{domain:s}» desconegut", + "mail_alias_remove_failed": "No s'han pogut eliminar els àlies del correu «{mail:s}»", + "mail_domain_unknown": "Domini d'adreça de correu per «{domain:s}» desconegut", "mail_forward_remove_failed": "No s'han pogut eliminar el reenviament de correu «{mail:s}»", - "mailbox_used_space_dovecot_down": "S'ha d'engegar el servei de correu Dovecot per poder obtenir l'espai utilitzat per la bústia de correu", - "mail_unavailable": "Aquesta adreça de correu esta reservada i ha de ser atribuïda automàticament el primer usuari", + "mailbox_used_space_dovecot_down": "S'ha d'engegar el servei de correu Dovecot, per poder obtenir l'espai utilitzat per la bústia de correu", + "mail_unavailable": "Aquesta adreça de correu està reservada i ha de ser atribuïda automàticament el primer usuari", "maindomain_change_failed": "No s'ha pogut canviar el domini principal", "maindomain_changed": "S'ha canviat el domini principal", - "migrate_tsig_end": "La migració cap a hmac-sha512 s'ha acabat", - "migrate_tsig_failed": "Ha fallat la migració del domini dyndns {domain} cap a hmac-sha512, anul·lant les modificacions. Error: {error_code} - {error}", - "migrate_tsig_start": "L'algoritme de generació de claus no es prou segur per a la signatura TSIG del domini «{domain}», començant la migració cap a un de més segur hmac-sha512", - "migrate_tsig_wait": "Esperar 3 minuts per a que el servidor dyndns tingui en compte la nova clau…", + "migrate_tsig_end": "La migració cap a HMAC-SHA-512 s'ha acabat", + "migrate_tsig_failed": "Ha fallat la migració del domini DynDNS «{domain}» cap a HMAC-SHA-512, anul·lant les modificacions. Error: {error_code}, {error}", + "migrate_tsig_start": "L'algoritme de generació de claus no es prou segur per a la signatura TSIG del domini «{domain}», començant la migració cap a un de més segur HMAC-SHA-512", + "migrate_tsig_wait": "Esperant tres minuts per a que el servidor DynDNS tingui en compte la nova clau…", "migrate_tsig_wait_2": "2 minuts…", "migrate_tsig_wait_3": "1 minut…", "migrate_tsig_wait_4": "30 segons…", - "migrate_tsig_not_needed": "Sembla que no s'utilitza cap domini dyndns, no és necessari fer cap migració!", + "migrate_tsig_not_needed": "Sembla que no s'utilitza cap domini DynDNS, no és necessari fer cap migració.", "migration_description_0001_change_cert_group_to_sslcert": "Canvia els permisos del grup dels certificats de «metronome» a «ssl-cert»", - "migration_description_0002_migrate_to_tsig_sha256": "Millora la seguretat de dyndns TSIG utilitzant SHA512 en lloc de MD5", + "migration_description_0002_migrate_to_tsig_sha256": "Millora la seguretat de DynDNS TSIG utilitzant SHA-512 en lloc de MD5", "migration_description_0003_migrate_to_stretch": "Actualització del sistema a Debian Stretch i YunoHost 3.0", "migration_description_0004_php5_to_php7_pools": "Tornar a configurar els pools PHP per utilitzar PHP 7 en lloc de PHP 5", - "migration_description_0005_postgresql_9p4_to_9p6": "Migració de les bases de dades de postgresql 9.4 a 9.6", + "migration_description_0005_postgresql_9p4_to_9p6": "Migració de les bases de dades de PostgreSQL 9.4 a 9.6", "migration_description_0006_sync_admin_and_root_passwords": "Sincronitzar les contrasenyes admin i root", "migration_description_0007_ssh_conf_managed_by_yunohost_step1": "La configuració SSH serà gestionada per YunoHost (pas 1, automàtic)", "migration_description_0008_ssh_conf_managed_by_yunohost_step2": "La configuració SSH serà gestionada per YunoHost (pas 2, manual)", "migration_description_0009_decouple_regenconf_from_services": "Desvincula el mecanisme regen-conf dels serveis", - "migration_description_0010_migrate_to_apps_json": "Elimina la appslists (desfasat) i utilitza la nova llista unificada «apps.json» en el seu lloc", + "migration_description_0010_migrate_to_apps_json": "Elimina les llistes d'aplicacions obsoletes i utilitza la nova llista unificada «apps.json» en el seu lloc", "migration_0003_backward_impossible": "La migració Stretch no és reversible.", "migration_0003_start": "Ha començat la migració a Stretch. Els registres estaran disponibles a {logfile}.", "migration_0003_patching_sources_list": "Modificant el fitxer sources.lists…", "migration_0003_main_upgrade": "Començant l'actualització principal…", - "migration_0003_fail2ban_upgrade": "Començant l'actualització de fail2ban…", + "migration_0003_fail2ban_upgrade": "Començant l'actualització de Fail2Ban…", "migration_0003_restoring_origin_nginx_conf": "El fitxer /etc/nginx/nginx.conf ha estat editat. La migració el tornarà al seu estat original... El fitxer anterior estarà disponible com a {backup_dest}.", - "migration_0003_yunohost_upgrade": "Començant l'actualització del paquet yunohost... La migració acabarà, però l'actualització actual es farà just després. Després de completar aquesta operació, pot ser que us hagueu de tornar a connectar a la web d'administració.", + "migration_0003_yunohost_upgrade": "Començant l'actualització del paquet YunoHost... La migració acabarà, però l'actualització actual es farà just després. Després de completar aquesta operació, pot ser que us hagueu de tornar a connectar a la web d'administració.", "migration_0003_not_jessie": "La distribució Debian actual no és Jessie!", "migration_0003_system_not_fully_up_to_date": "El vostre sistema no està completament actualitzat. S'ha de fer una actualització normal abans de fer la migració a Stretch.", - "migration_0003_still_on_jessie_after_main_upgrade": "Hi ha hagut un problema durant l'actualització principal: el sistema encara està amb Jessie!? Per investigar el problema, mireu el registres a {log}:s…", - "migration_0003_general_warning": "Tingueu en compte que la migració és una operació delicada. Tot i que l'equip de YunoHost a fet els possibles per revisar-la i provar-la, la migració pot provocar errors en parts del sistema o aplicacions.\n\nPer tant, recomanem:\n - Fer una còpia de seguretat de les dades o aplicacions importants. Més informació a https://yunohost.org/backup;\n - Sigueu pacient un cop llençada la migració: en funció de la connexió a internet i el maquinari, pot trigar fins a unes hores per actualitzar-ho tot.\n\nD'altra banda, el port per SMTP, utilitzat per clients de correu externs (com Thunderbird o K9-Mail) ha canviat de 465 (SSL/TLS) a 587 (STARTTLS). L'antic port 465 serà tancat automàticament i el nou port 587 serà obert en el tallafocs. Tots els usuaris *hauran* d'adaptar la configuració dels clients de correu en acord amb aquests canvis!", - "migration_0003_problematic_apps_warning": "Tingueu en compte que s'han detectat les aplicacions, possiblement, problemàtiques següents. Sembla que aquestes no s'han instal·lat des d'una applist o que no estan marcades com a «working». Per conseqüent, no podem garantir que segueixin funcionant després de l'actualització: {problematic_apps}", + "migration_0003_still_on_jessie_after_main_upgrade": "Hi ha hagut un problema durant l'actualització principal: El sistema encara està amb Jessie? Per investigar el problema, mireu el registres a {log}:s…", + "migration_0003_general_warning": "Tingueu en compte que la migració és una operació delicada. L'equip de YunoHost a fet els possibles per revisar-la i provar-la, però la migració pot provocar errors en parts del sistema o aplicacions.\n\nPer tant, es recomana:\n - Fer una còpia de seguretat de les dades o aplicacions importants. Més informació a https://yunohost.org/backup;\n - Sigueu pacient un cop llençada la migració: en funció de la connexió a internet i el maquinari, pot trigar fins a unes hores per actualitzar-ho tot.\n\nD'altra banda, el port per SMTP, utilitzat per clients de correu externs (com Thunderbird o K9-Mail) ha canviat de 465 (SSL/TLS) a 587 (STARTTLS). L'antic port (465) serà tancat automàticament, i el nou port (587) serà obert en el tallafocs. Tots els usuaris *hauran* d'adaptar la configuració dels clients de correu en acord amb aquests canvis.", + "migration_0003_problematic_apps_warning": "Tingueu en compte que s'han detectat les aplicacions, possiblement, problemàtiques següents. Sembla que aquestes no s'han instal·lat des d'una applist, o que no estan marcades com a «working». Per conseqüent, no podem garantir que segueixin funcionant després de l'actualització: {problematic_apps}", "migration_0003_modified_files": "Tingueu en compte que s'han detectat els següents fitxers que han estat modificats manualment i podrien sobreescriure's al final de l'actualització: {manually_modified_files}", - "migration_0005_postgresql_94_not_installed": "Postgresql no està instal·lat en el sistema. No hi ha res per fer!", - "migration_0005_postgresql_96_not_installed": "S'ha trobat Postgresql 9.4 instal·lat, però no Postgresql 9.6!? Alguna cosa estranya a passat en el sistema :( …", - "migration_0005_not_enough_space": "No hi ha prou espai disponible en {path} per fer la migració en aquest moment :(.", + "migration_0005_postgresql_94_not_installed": "PostgreSQL no està instal·lat en el sistema. No hi ha res per fer.", + "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 està instal·lat, però no PostgreSQL 9.6? Alguna cosa estranya a passat en el sistema :( …", + "migration_0005_not_enough_space": "Creu espai disponible en {path} per executar la migració.", "migration_0006_disclaimer": "YunoHost esperar que les contrasenyes admin i root estiguin sincronitzades. Fent aquesta migració, la contrasenya root serà reemplaçada per la contrasenya admin.", "migration_0007_cancelled": "YunoHost no ha pogut millorar la gestió de la configuració SSH.", "migration_0007_cannot_restart": "No es pot reiniciar SSH després d'haver intentat cancel·lar la migració numero 6.", "migration_0008_general_disclaimer": "Per millorar la seguretat del servidor, es recomana que sigui YunoHost qui gestioni la configuració SSH. La configuració SSH actual és diferent a la configuració recomanada. Si deixeu que YunoHost ho reconfiguri, la manera de connectar-se al servidor mitjançant SSH canviarà de la següent manera:", - "migration_0008_port": " - la connexió es farà utilitzant el port 22 en lloc del port SSH personalitzat actual. Es pot reconfigurar;", - "migration_0008_root": " - no es podrà connectar com a root a través de SSH. S'haurà d'utilitzar l'usuari admin per fer-ho;", - "migration_0008_dsa": " - es desactivarà la clau DSA. Per tant, es podria haver d'invalidar un missatge esgarrifós del client SSH, i tornar a verificar l'empremta digital del servidor;", + "migration_0008_port": "• La connexió es farà utilitzant el port 22 en lloc del port SSH personalitzat actual. Es pot reconfigurar;", + "migration_0008_root": "• No es podrà connectar com a root a través de SSH. S'haurà d'utilitzar l'usuari admin per fer-ho;", + "migration_0008_dsa": "• Es desactivarà la clau DSA. Per tant, es podria haver d'invalidar un missatge esgarrifós del client SSH, i tornar a verificar l'empremta digital del servidor;", "migration_0008_warning": "Si heu entès els avisos i accepteu que YunoHost sobreescrigui la configuració actual, comenceu la migració. Sinó, podeu saltar-vos la migració, tot i que no està recomanat.", - "migration_0008_no_warning": "No s'han detectat riscs importants per sobreescriure la configuració SSH, però no es pot estar del tot segur ;)! Si accepteu que YunoHost sobreescrigui la configuració actual, comenceu la migració. Sinó, podeu saltar-vos la migració, tot i que no està recomanat.", - "migration_0009_not_needed": "Sembla que ja s'ha fet aquesta migració? Ometent.", + "migration_0008_no_warning": "No s'han identificat riscs importants per sobreescriure la configuració SSH, però no es pot estar del tot segur ;)! Executetu la migració per sobreescriure-la. Sinó, podeu saltar-vos la migració, tot i que no està recomanat.", + "migration_0009_not_needed": "Sembla que ja s'ha fet aquesta migració… (?) Ometent.", "migrations_backward": "Migració cap enrere.", "migrations_bad_value_for_target": "Nombre invàlid pel paràmetre target, els nombres de migració disponibles són 0 o {}", "migrations_cant_reach_migration_file": "No s'ha pogut accedir als fitxers de migració al camí %s", "migrations_current_target": "La migració objectiu és {}", "migrations_error_failed_to_load_migration": "ERROR: no s'ha pogut carregar la migració {number} {name}", "migrations_forward": "Migració endavant", - "migrations_list_conflict_pending_done": "No es pot utilitzar --previous i --done al mateix temps.", - "migrations_loading_migration": "Carregant la migració {number} {name}…", - "migrations_migration_has_failed": "La migració {number} {name} ha fallat amb l'excepció {exception}, cancel·lant", + "migrations_list_conflict_pending_done": "No es pot utilitzar «--previous» i «--done» al mateix temps.", + "migrations_loading_migration": "Carregant la migració {id}…", + "migrations_migration_has_failed": "La migració {id} ha fallat, cancel·lant. Error: {exception}", "migrations_no_migrations_to_run": "No hi ha cap migració a fer", "migrations_show_currently_running_migration": "Fent la migració {number} {name}…", "migrations_show_last_migration": "L'última migració feta és {}", - "migrations_skip_migration": "Saltant migració {number} {name}…", + "migrations_skip_migration": "Saltant migració {id}…", "migrations_success": "S'ha completat la migració {number} {name} amb èxit!", - "migrations_to_be_ran_manually": "La migració {number} {name} s'ha de fer manualment. Aneu a Eines > Migracions a la interfície admin, o executeu «yunohost tools migrations migrate».", - "migrations_need_to_accept_disclaimer": "Per fer la migració {number} {name}, heu d'acceptar aquesta clàusula de no responsabilitat:\n---\n{disclaimer}\n---\nSi accepteu fer la migració, torneu a executar l'ordre amb l'opció --accept-disclaimer.", + "migrations_to_be_ran_manually": "La migració {id} s'ha de fer manualment. Aneu a Eines → Migracions a la interfície admin, o executeu «yunohost tools migrations migrate».", + "migrations_need_to_accept_disclaimer": "Per fer la migració {id}, heu d'acceptar aquesta clàusula de no responsabilitat:\n---\n{disclaimer}\n---\nSi accepteu fer la migració, torneu a executar l'ordre amb l'opció «--accept-disclaimer».", "monitor_disabled": "El monitoratge del servidor ha estat desactivat", "monitor_enabled": "El monitoratge del servidor ha estat activat", "monitor_glances_con_failed": "No s'ha pogut connectar al servidor Glances", @@ -384,18 +384,18 @@ "pattern_firstname": "Ha de ser un nom vàlid", "pattern_lastname": "Ha de ser un cognom vàlid", "pattern_listname": "Ha d'estar compost per caràcters alfanumèrics i guió baix exclusivament", - "pattern_mailbox_quota": "Ha de ser una mida amb el sufix b/k/M/G/T o 0 per desactivar la quota", + "pattern_mailbox_quota": "Ha de ser una mida amb el sufix b/k/M/G/T o 0 per no tenir quota", "pattern_password": "Ha de tenir un mínim de 3 caràcters", "pattern_port": "Ha de ser un número de port vàlid (i.e. 0-65535)", "pattern_port_or_range": "Ha de ser un número de port vàlid (i.e. 0-65535) o un interval de ports (ex. 100:200)", "pattern_positive_number": "Ha de ser un nombre positiu", "pattern_username": "Ha d'estar compost per caràcters alfanumèrics en minúscula i guió baix exclusivament", - "pattern_password_app": "Les contrasenyes no haurien de tenir els següents caràcters: {forbidden_chars}", + "pattern_password_app": "Les contrasenyes no poden de tenir els següents caràcters: {forbidden_chars}", "port_already_closed": "El port {port:d} ja està tancat per les connexions {ip_version:s}", "port_already_opened": "El port {port:d} ja està obert per les connexions {ip_version:s}", "port_available": "El port {port:d} està disponible", "port_unavailable": "El port {port:d} no està disponible", - "recommend_to_add_first_user": "La post instal·lació s'ha acabat, però YunoHost necessita com a mínim un usuari per funcionar correctament, hauríeu d'afegir un usuari executant «yunohost user create $username» o amb la interfície d'administració.", + "recommend_to_add_first_user": "La post instal·lació s'ha acabat, però YunoHost necessita com a mínim un usuari per funcionar correctament, hauríeu d'afegir un usuari executant «yunohost user create »; o fer-ho des de la interfície d'administració.", "regenconf_file_backed_up": "S'ha guardat una còpia de seguretat del fitxer de configuració «{conf}» a «{backup}»", "regenconf_file_copy_failed": "No s'ha pogut copiar el nou fitxer de configuració «{new}» a «{conf}»", "regenconf_file_kept_back": "S'espera que el fitxer de configuració «{conf}» sigui suprimit per regen-conf (categoria {category}) però s'ha mantingut.", @@ -406,26 +406,26 @@ "regenconf_file_updated": "El fitxer de configuració «{conf}» ha estat actualitzat", "regenconf_now_managed_by_yunohost": "El fitxer de configuració «{conf}» serà gestionat per YunoHost a partir d'ara (categoria {category}).", "regenconf_up_to_date": "La configuració ja està al dia per la categoria «{category}»", - "regenconf_updated": "La configuració ha estat actualitzada per la categoria «{category}»", + "regenconf_updated": "La configuració per la categoria «{category}» ha estat actualitzada", "regenconf_would_be_updated": "La configuració hagués estat actualitzada per la categoria «{category}»", "regenconf_dry_pending_applying": "Verificació de la configuració pendent que s'hauria d'haver aplicat per la categoria «{category}»…", "regenconf_failed": "No s'ha pogut regenerar la configuració per la/les categoria/es : {categories}", "regenconf_pending_applying": "Aplicació de la configuració pendent per la categoria «{category}»…", "restore_action_required": "S'ha d'especificar quelcom a restaurar", - "restore_already_installed_app": "Ja hi ha una aplicació instal·lada amb l'id «{app:s}»", + "restore_already_installed_app": "Una aplicació amb la ID «{app:s}» ja està instal·lada", "restore_app_failed": "No s'ha pogut restaurar l'aplicació «{app:s}»", "restore_cleaning_failed": "No s'ha pogut netejar el directori temporal de restauració", "restore_complete": "Restauració completada", "restore_confirm_yunohost_installed": "Esteu segur de voler restaurar un sistema ja instal·lat? [{answers:s}]", "restore_extracting": "Extracció dels fitxers necessaris de l'arxiu…", "restore_failed": "No s'ha pogut restaurar el sistema", - "restore_hook_unavailable": "L'script de restauració «{part:s}» no està disponible en el sistema i tampoc és en l'arxiu", - "restore_may_be_not_enough_disk_space": "Sembla que no hi ha prou espai disponible en el disc (espai lliure: {free_space:d} B, espai necessari: {needed_space:d} B, marge de seguretat: {margin:d} B)", + "restore_hook_unavailable": "El script de restauració «{part:s}» no està disponible en el sistema i tampoc és en l'arxiu", + "restore_may_be_not_enough_disk_space": "Sembla que no hi ha prou espai disponible en el sistema (lliure: {free_space:d} B, espai necessari: {needed_space:d} B, marge de seguretat: {margin:d} B)", "restore_mounting_archive": "Muntatge de l'arxiu a «{path:s}»", - "restore_not_enough_disk_space": "No hi ha prou espai disponible en el disc (espai lliure: {free_space:d} B, espai necessari: {needed_space:d} B, marge de seguretat: {margin:d} B)", + "restore_not_enough_disk_space": "No hi ha prou espai disponible (espai: {free_space:d} B, espai necessari: {needed_space:d} B, marge de seguretat: {margin:d} B)", "restore_nothings_done": "No s'ha restaurat res", "restore_removing_tmp_dir_failed": "No s'ha pogut eliminar un directori temporal antic", - "restore_running_app_script": "Execució de l'script de restauració de l'aplicació «{app:s}»…", + "restore_running_app_script": "Restaurant l'aplicació «{app:s}»…", "restore_running_hooks": "Execució dels hooks de restauració…", "restore_system_part_failed": "No s'ha pogut restaurar la part «{part:s}» del sistema", "root_password_desynchronized": "S'ha canviat la contrasenya d'administració, però YunoHost no ha pogut propagar-ho cap a la contrasenya root!", @@ -439,24 +439,24 @@ "service_already_started": "Ja s'ha iniciat el servei «{service:s}»", "service_already_stopped": "Ja s'ha aturat el servei «{service:s}»", "service_cmd_exec_failed": "No s'ha pogut executar l'ordre «{command:s}»", - "service_description_avahi-daemon": "permet accedir al servidor via yunohost.local en la xarxa local", - "service_description_dnsmasq": "gestiona la resolució del nom de domini (DNS)", - "service_description_dovecot": "permet als clients de correu accedir/recuperar correus (via IMAP i POP3)", - "service_description_fail2ban": "protegeix contra els atacs de força bruta i a altres atacs provinents d'Internet", - "service_description_glances": "monitora la informació del sistema en el servidor", - "service_description_metronome": "gestiona els comptes de missatgeria instantània XMPP", - "service_description_mysql": "guarda les dades de les aplicacions (base de dades SQL)", - "service_description_nginx": "serveix o permet l'accés a totes les pàgines web allotjades en el servidor", - "service_description_nslcd": "gestiona les connexions shell dels usuaris YunoHost", - "service_description_php7.0-fpm": "executa les aplicacions escrites en PHP amb nginx", - "service_description_postfix": "utilitzat per enviar i rebre correus", - "service_description_redis-server": "una base de dades especialitzada per l'accés ràpid a dades, files d'espera i comunicació entre programes", - "service_description_rmilter": "verifica diferents paràmetres en els correus", - "service_description_rspamd": "filtra el correu brossa, i altres funcionalitats relacionades al correu", - "service_description_slapd": "guarda el usuaris, dominis i informació relacionada", - "service_description_ssh": "permet la connexió remota al servidor via terminal (protocol SSH)", - "service_description_yunohost-api": "gestiona les interaccions entre la interfície web de YunoHost i el sistema", - "service_description_yunohost-firewall": "gestiona els ports de connexió oberts i tancats als serveis", + "service_description_avahi-daemon": "Permet accedir al servidor via «yunohost.local» en la xarxa local", + "service_description_dnsmasq": "Gestiona la resolució del nom de domini (DNS)", + "service_description_dovecot": "Permet als clients de correu accedir/recuperar correus (via IMAP i POP3)", + "service_description_fail2ban": "Protegeix contra els atacs de força bruta i a altres atacs provinents d'Internet", + "service_description_glances": "Monitora la informació del sistema en el servidor", + "service_description_metronome": "Gestiona els comptes de missatgeria instantània XMPP", + "service_description_mysql": "Guarda les dades de les aplicacions (base de dades SQL)", + "service_description_nginx": "Serveix o permet l'accés a totes les pàgines web allotjades en el servidor", + "service_description_nslcd": "Gestiona les connexions shell dels usuaris YunoHost", + "service_description_php7.0-fpm": "Executa les aplicacions escrites en PHP amb NGINX", + "service_description_postfix": "Utilitzat per enviar i rebre correus", + "service_description_redis-server": "Una base de dades especialitzada per l'accés ràpid a dades, files d'espera i comunicació entre programes", + "service_description_rmilter": "Verifica diferents paràmetres en els correus", + "service_description_rspamd": "Filtra el correu brossa, i altres funcionalitats relacionades amb el correu", + "service_description_slapd": "Guarda el usuaris, dominis i informació relacionada", + "service_description_ssh": "Permet la connexió remota al servidor via terminal (protocol SSH)", + "service_description_yunohost-api": "Gestiona les interaccions entre la interfície web de YunoHost i el sistema", + "service_description_yunohost-firewall": "Gestiona els ports de connexió oberts i tancats als serveis", "service_disable_failed": "No s'han pogut deshabilitar el servei «{service:s}»\n\nRegistres recents: {logs:s}", "service_disabled": "S'ha deshabilitat el servei {service:s}", "service_enable_failed": "No s'ha pogut activar el servei «{service:s}»\n\nRegistres recents: {log:s}", @@ -479,26 +479,26 @@ "service_unknown": "Servei «{service:s}» desconegut", "ssowat_conf_generated": "S'ha generat la configuració SSOwat", "ssowat_conf_updated": "S'ha actualitzat la configuració SSOwat", - "ssowat_persistent_conf_read_error": "Error en llegir la configuració persistent de SSOwat: {error:s}. Modifiqueu el fitxer /etc/ssowat/conf.json.persistent per arreglar la sintaxi JSON", - "ssowat_persistent_conf_write_error": "Error guardant la configuració persistent de SSOwat: {error:s}. Modifiqueu el fitxer /etc/ssowat/conf.json.persistent per arreglar la sintaxi JSON", + "ssowat_persistent_conf_read_error": "No s'ha pogut llegir la configuració persistent de SSOwat: {error:s}. Modifiqueu el fitxer /etc/ssowat/conf.json.persistent per arreglar la sintaxi JSON", + "ssowat_persistent_conf_write_error": "No s'ha pogut guardar la configuració persistent de SSOwat: {error:s}. Modifiqueu el fitxer /etc/ssowat/conf.json.persistent per arreglar la sintaxi JSON", "system_upgraded": "S'ha actualitzat el sistema", - "system_username_exists": "El nom d'usuari ja existeix en els usuaris de sistema", - "this_action_broke_dpkg": "Aquesta acció a trencat dpkg/apt (els gestors de paquets del sistema)… Podeu intentar resoldre el problema connectant-vos amb SSH i executant «sudo dpkg --configure -a».", - "tools_upgrade_at_least_one": "Especifiqueu --apps O --system", + "system_username_exists": "El nom d'usuari ja existeix en la llista d'usuaris de sistema", + "this_action_broke_dpkg": "Aquesta acció a trencat dpkg/APT (els gestors de paquets del sistema)… Podeu intentar resoldre el problema connectant-vos amb SSH i executant «sudo dpkg --configure -a».", + "tools_upgrade_at_least_one": "Especifiqueu «--apps», o «--system»", "tools_upgrade_cant_both": "No es poden actualitzar tant el sistema com les aplicacions al mateix temps", "tools_upgrade_cant_hold_critical_packages": "No es poden mantenir els paquets crítics…", "tools_upgrade_cant_unhold_critical_packages": "No es poden deixar de mantenir els paquets crítics…", "tools_upgrade_regular_packages": "Actualitzant els paquets «normals» (no relacionats amb YunoHost)…", "tools_upgrade_regular_packages_failed": "No s'han pogut actualitzar els paquets següents: {packages_list}", "tools_upgrade_special_packages": "Actualitzant els paquets «especials» (relacionats amb YunoHost)…", - "tools_upgrade_special_packages_explanation": "Aquesta acció s'acabarà, però l'actualització especial continuarà en segon pla. No comenceu cap altra acció al servidor en els pròxims ~10 minuts (depèn de la velocitat del maquinari). Un cop acabat, pot ser que us hagueu de tornar a connectar a la interfície d'administració. Els registres de l'actualització estaran disponibles a Eines > Registres (a la interfície d'administració) o amb «yunohost log list» (a la línia d'ordres).", - "tools_upgrade_special_packages_completed": "Actualització dels paquets YunoHost acabada!\nPremeu [Enter] per tornar a la línia d'ordres", + "tools_upgrade_special_packages_explanation": "Aquesta acció s'acabarà, però l'actualització especial continuarà en segon pla. No comenceu cap altra acció al servidor en els pròxims ~10 minuts (depèn de la velocitat del maquinari). Un cop acabat, pot ser que us hagueu de tornar a connectar a la interfície d'administració. Els registres de l'actualització estaran disponibles a Eines → Registres (a la interfície d'administració) o amb «yunohost log list» (des de la línia d'ordres).", + "tools_upgrade_special_packages_completed": "Actualització dels paquets YunoHost acabada.\nPremeu [Enter] per tornar a la línia d'ordres", "unbackup_app": "L'aplicació «{app:s}» no serà guardada", "unexpected_error": "Hi ha hagut un error inesperat: {error}", "unit_unknown": "Unitat desconeguda «{unit:s}»", "unlimit": "Sense quota", "unrestore_app": "L'aplicació «{app:s} no serà restaurada", - "update_apt_cache_failed": "No s'ha pogut actualitzar la memòria cau d'APT (el gestor de paquets de Debian). Aquí teniu les línies de sources.list que poden ajudar-vos a identificar les línies problemàtiques:\n{sourceslist}", + "update_apt_cache_failed": "No s'ha pogut actualitzar la memòria cau d'APT (el gestor de paquets de Debian). Aquí teniu les línies de sources.list, que poden ajudar-vos a identificar les línies problemàtiques:\n{sourceslist}", "update_apt_cache_warning": "Hi ha hagut errors al actualitzar la memòria cau d'APT (el gestor de paquets de Debian). Aquí teniu les línies de sources.list que poden ajudar-vos a identificar les línies problemàtiques:\n{sourceslist}", "updating_apt_cache": "Obtenció de les actualitzacions disponibles per als paquets del sistema…", "updating_app_lists": "Obtenció de les actualitzacions disponibles per a les aplicacions…", @@ -507,21 +507,21 @@ "upnp_dev_not_found": "No s'ha trobat cap dispositiu UPnP", "upnp_disabled": "S'ha desactivat UPnP", "upnp_enabled": "S'ha activat UPnP", - "upnp_port_open_failed": "No s'han pogut obrir els ports UPnP", + "upnp_port_open_failed": "No s'ha pogut obrir el port UPnP", "user_created": "S'ha creat l'usuari", - "user_creation_failed": "No s'ha pogut crear l'usuari", + "user_creation_failed": "No s'ha pogut crear l'usuari {user}: {error}", "user_deleted": "S'ha suprimit l'usuari", - "user_deletion_failed": "No s'ha pogut suprimir l'usuari", - "user_home_creation_failed": "No s'ha pogut crear la carpeta personal («home») de l'usuari", + "user_deletion_failed": "No s'ha pogut suprimir l'usuari {user}: {error}", + "user_home_creation_failed": "No s'ha pogut crear la carpeta personal «home» per l'usuari", "user_info_failed": "No s'ha pogut obtenir la informació de l'usuari", "user_unknown": "Usuari desconegut: {user:s}", - "user_update_failed": "No s'ha pogut actualitzar l'usuari", - "user_updated": "S'ha actualitzat l'usuari", + "user_update_failed": "No s'ha pogut actualitzar l'usuari {user}: {error}", + "user_updated": "S'ha canviat la informació de l'usuari", "users_available": "Usuaris disponibles:", "yunohost_already_installed": "YunoHost ja està instal·lat", "yunohost_ca_creation_failed": "No s'ha pogut crear l'autoritat de certificació", "yunohost_ca_creation_success": "S'ha creat l'autoritat de certificació local.", - "yunohost_configured": "S'ha configurat YunoHost", + "yunohost_configured": "YunoHost està configurat", "yunohost_installing": "Instal·lació de YunoHost…", "yunohost_not_installed": "YunoHost no està instal·lat o no està instal·lat correctament. Executeu «yunohost tools postinstall»", "apps_permission_not_found": "No s'ha trobat cap permís per les aplicacions instal·lades", @@ -534,14 +534,14 @@ "group_already_disallowed": "El grup «{group:s}» ja té els permisos «{permission:s}» desactivats per l'aplicació «{app:s}»", "group_name_already_exist": "El grup {name:s} ja existeix", "group_created": "S'ha creat el grup «{group}»", - "group_creation_failed": "No s'ha pogut crear el grup «{group}»", + "group_creation_failed": "No s'ha pogut crear el grup «{group}»: {error}", "group_deleted": "S'ha eliminat el grup «{group}»", - "group_deletion_failed": "No s'ha pogut eliminar el grup «{group}»", + "group_deletion_failed": "No s'ha pogut eliminar el grup «{group}»: {error}", "group_deletion_not_allowed": "El grup {group:s} no es pot eliminar manualment.", "group_info_failed": "Ha fallat la informació del grup", "group_unknown": "Grup {group:s} desconegut", "group_updated": "S'ha actualitzat el grup «{group}»", - "group_update_failed": "No s'ha pogut actualitzat el grup «{group}»", + "group_update_failed": "No s'ha pogut actualitzat el grup «{group}»: {error}", "log_permission_add": "Afegir el permís «{}» per l'aplicació «{}»", "log_permission_remove": "Suprimir el permís «{}»", "log_permission_update": "Actualitzar el permís «{}» per l'aplicació «{}»", @@ -550,31 +550,31 @@ "log_user_group_update": "Actualitzar grup «{}»", "log_user_permission_add": "Actualitzar el permís «{}»", "log_user_permission_remove": "Actualitzar el permís «{}»", - "mailbox_disabled": "La bústia de correu està desactivada per als usuaris {user:s}", + "mailbox_disabled": "La bústia de correu està desactivada per al usuari {user:s}", "migration_description_0011_setup_group_permission": "Configurar el grup d'usuaris i els permisos per les aplicacions i els serveis", "migration_0011_backup_before_migration": "Creant una còpia de seguretat de la base de dades LDAP i la configuració de les aplicacions abans d'efectuar la migració.", "migration_0011_can_not_backup_before_migration": "No s'ha pogut fer la còpia de seguretat abans de la migració. No s'ha pogut fer la migració. Error: {error:s}", "migration_0011_create_group": "Creant un grup per a cada usuari…", "migration_0011_done": "Migració completa. Ja podeu gestionar grups d'usuaris.", - "migration_0011_LDAP_config_dirty": "Sembla que heu modificat manualment la configuració LDAP. Per fer aquesta migració s'ha d'actualitzar la configuració LDAP.\nGuardeu la configuració actual, reinicieu la configuració original amb l'ordre «yunohost tools regen-conf -f» i torneu a intentar la migració", + "migration_0011_LDAP_config_dirty": "Sembla que heu modificat manualment la configuració LDAP. Per fer aquesta migració s'ha d'actualitzar la configuració LDAP.\nGuardeu la configuració actual, reinicieu la configuració original executant l'ordre «yunohost tools regen-conf -f» i torneu a intentar la migració", "migration_0011_LDAP_update_failed": "Ha fallat l'actualització de LDAP. Error: {error:s}", "migration_0011_migrate_permission": "Fent la migració dels permisos de la configuració de les aplicacions a LDAP…", - "migration_0011_migration_failed_trying_to_rollback": "La migració ha fallat … s'intenta tornar el sistema a l'estat anterior.", + "migration_0011_migration_failed_trying_to_rollback": "La migració ha fallat… s'intenta tornar el sistema a l'estat anterior.", "migration_0011_rollback_success": "S'ha tornat el sistema a l'estat anterior.", "migration_0011_update_LDAP_database": "Actualitzant la base de dades LDAP…", "migration_0011_update_LDAP_schema": "Actualitzant l'esquema LDAP…", "need_define_permission_before": "Heu de tornar a redefinir els permisos utilitzant «yunohost user permission add -u USER» abans d'eliminar un grup permès", "permission_already_clear": "Ja s'ha donat el permís «{permission:s}» per l'aplicació {app:s}", - "permission_already_exist": "El permís «{permission:s}» ja existeix per l'aplicació {app:s}", - "permission_created": "S'ha creat el permís «{permission:s}» per l'aplicació {app:s}", - "permission_creation_failed": "La creació del permís ha fallat", - "permission_deleted": "S'ha eliminat el permís «{permission:s}» per l'aplicació {app:s}", - "permission_deletion_failed": "L'eliminació del permís «{permission:s}» per l'aplicació {app:s} ha fallat", - "permission_not_found": "No s'ha trobat el permís «{permission:s}» per l'aplicació {app:s}", + "permission_already_exist": "El permís «{permission:s}» ja existeix", + "permission_created": "S'ha creat el permís «{permission:s}»", + "permission_creation_failed": "No s'ha pogut crear el permís «{permission}»: {error}", + "permission_deleted": "S'ha eliminat el permís «{permission:s}»", + "permission_deletion_failed": "No s'ha pogut eliminar el permís «{permission:s}»: {error}", + "permission_not_found": "No s'ha trobat el permís «{permission:s}»", "permission_name_not_valid": "El nom del permís «{permission:s}» no és vàlid", - "permission_update_failed": "L'actualització del permís ha fallat", + "permission_update_failed": "No s'ha pogut actualitzar el permís «{permission}»: {error}", "permission_generated": "S'ha actualitzat la base de dades del permís", - "permission_updated": "S'ha actualitzat el permís «{permission:s}» per l'aplicació {app:s}", + "permission_updated": "S'ha actualitzat el permís «{permission:s}»", "permission_update_nothing_to_do": "No hi ha cap permís per actualitzar", "remove_main_permission_not_allowed": "No es pot eliminar el permís principal", "remove_user_of_group_not_allowed": "No es pot eliminar l'usuari {user:s} del grup {group:s}", @@ -582,5 +582,38 @@ "tools_update_failed_to_app_fetchlist": "No s'ha pogut actualitzar la llista d'aplicacions de YunoHost a causa de: {error}", "user_already_in_group": "L'usuari {user:s} ja és en el grup {group:s}", "user_not_in_group": "L'usuari {user:s} no és en el grup {group:s}", - "migration_description_0012_postgresql_password_to_md5_authentication": "Força l'autenticació postgresql a fer servir md5 per a les connexions locals" + "migration_description_0012_postgresql_password_to_md5_authentication": "Força l'autenticació PostgreSQL a fer servir MD5 per a les connexions locals", + "app_full_domain_unavailable": "Aquesta aplicació requereix un domini sencer per ser instal·lada, però ja hi ha altres aplicacions instal·lades al domini «{domain}». Una possible solució és afegir i utilitzar un subdomini dedicat a aquesta aplicació.", + "migrations_not_pending_cant_skip": "Aquestes migracions no estan pendents, així que no poden ser omeses: {ids}", + "app_action_broke_system": "Aquesta acció sembla haver trencat els següents serveis importants: {services}", + "log_permission_urls": "Actualitzar les URLs relacionades amb el permís «{}»", + "log_user_group_create": "Crear grup «{}»", + "log_user_permission_update": "Actualitzar els accessos per al permís «{}»", + "log_user_permission_reset": "Restablir el permís «{}»", + "permission_already_disallowed": "El grup «{group}» ja té el permís «{permission}» desactivat", + "migrations_already_ran": "Aquestes migracions ja s'han fet: {ids}", + "migrations_dependencies_not_satisfied": "No s'ha pogut executar la migració {id} perquè s'han d'executar primer les següents migracions: {dependencies_id}", + "migrations_failed_to_load_migration": "No s'ha pogut carregar la migració {id}: {error}", + "migrations_exclusive_options": "«--auto», «--skip», i «--force-rerun» són opcions mútuament excloents.", + "migrations_must_provide_explicit_targets": "Heu de proporcionar objectius explícits al utilitzar «--skip» o «--force-rerun»", + "migrations_no_such_migration": "No hi ha cap migració anomenada {id}", + "migrations_pending_cant_rerun": "Aquestes migracions encara estan pendents, així que no es poden tornar a executar: {ids}", + "migrations_running_forward": "Executant la migració {id}…", + "migrations_success_forward": "Migració {id} completada", + "apps_already_up_to_date": "Ja estan actualitzades totes les aplicacions", + "dyndns_provider_unreachable": "No s'ha pogut connectar amb el proveïdor Dyndns {provider}: o el vostre YunoHost no està ben connectat a Internet o el servidor dynette està caigut.", + "operation_interrupted": "S'ha interromput manualment l'operació?", + "group_already_exist": "El grup {group} ja existeix", + "group_already_exist_on_system": "El grup {group} ja existeix en els grups del sistema", + "group_cannot_be_edited": "El grup {group} no es pot editar manualment.", + "group_cannot_be_deleted": "El grup {group} no es pot eliminar manualment.", + "group_user_already_in_group": "L'usuari {user} ja està en el grup {group}", + "group_user_not_in_group": "L'usuari {user} no està en el grup {group}", + "log_permission_create": "Crear el permís «{}»", + "log_permission_delete": "Eliminar el permís «{}»", + "migration_0011_failed_to_remove_stale_object": "No s'ha pogut eliminar l'objecte obsolet {dn}: {error}", + "permission_already_allowed": "El grup «{group}» ja té el permís «{permission}» activat", + "permission_cannot_remove_main": "No es permet eliminar un permís principal", + "user_already_exists": "L'usuari {user} ja existeix", + "app_upgrade_stopped": "S'ha aturat l'actualització de totes les aplicacions per prevenir els possibles danys ja que hi ha hagut un error en l'actualització de l'anterior aplicació" } From 3bd90c63b3ce9a352c74c295ef056cd650429741 Mon Sep 17 00:00:00 2001 From: advocatux Date: Mon, 14 Oct 2019 17:43:39 +0000 Subject: [PATCH 076/127] Translated using Weblate (Spanish) Currently translated at 100.0% (556 of 556 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/es/ --- locales/es.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/locales/es.json b/locales/es.json index 80b17673a..4f136460c 100644 --- a/locales/es.json +++ b/locales/es.json @@ -626,5 +626,7 @@ "permission_already_disallowed": "El grupo «{group}» ya tiene el permiso «{permission}» desactivado", "permission_cannot_remove_main": "No está permitido eliminar un permiso principal", "user_already_exists": "El usuario {user} ya existe", - "app_full_domain_unavailable": "Lamentablemente esta aplicación necesita un dominio completo para ser instalada pero ya hay otras aplicaciones instaladas en el dominio «{domain}». Una solución posible es añadir y usar un subdominio dedicado a esta aplicación." + "app_full_domain_unavailable": "Lamentablemente esta aplicación necesita un dominio completo para ser instalada pero ya hay otras aplicaciones instaladas en el dominio «{domain}». Una solución posible es añadir y usar un subdominio dedicado a esta aplicación.", + "app_install_failed": "No se pudo instalar {app}", + "app_install_script_failed": "Ha ocurrido un error en el guión de instalación de la aplicación" } From 57af2c7c45a3c621a7e52359e5e8fb11a1e608f8 Mon Sep 17 00:00:00 2001 From: xaloc33 Date: Mon, 14 Oct 2019 20:51:25 +0000 Subject: [PATCH 077/127] Translated using Weblate (Catalan) Currently translated at 100.0% (556 of 556 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ca/ --- locales/ca.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/locales/ca.json b/locales/ca.json index 1476d5fb5..592bc4592 100644 --- a/locales/ca.json +++ b/locales/ca.json @@ -615,5 +615,7 @@ "permission_already_allowed": "El grup «{group}» ja té el permís «{permission}» activat", "permission_cannot_remove_main": "No es permet eliminar un permís principal", "user_already_exists": "L'usuari {user} ja existeix", - "app_upgrade_stopped": "S'ha aturat l'actualització de totes les aplicacions per prevenir els possibles danys ja que hi ha hagut un error en l'actualització de l'anterior aplicació" + "app_upgrade_stopped": "S'ha aturat l'actualització de totes les aplicacions per prevenir els possibles danys ja que hi ha hagut un error en l'actualització de l'anterior aplicació", + "app_install_failed": "No s'ha pogut instal·lar {app}", + "app_install_script_failed": "Hi ha hagut un error en el script d'instal·lació de l'aplicació" } From a74ba4f112a824e15fc9aaac49470ff4d532df8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Allan=20Nordh=C3=B8y?= Date: Wed, 16 Oct 2019 00:03:50 +0000 Subject: [PATCH 078/127] services required, the action that failed --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 7fcaf0d04..c2aa0191b 100644 --- a/locales/en.json +++ b/locales/en.json @@ -6,7 +6,7 @@ "admin_password_changed": "The administration password got changed", "admin_password_too_long": "Please choose a password shorter than 127 characters", "already_up_to_date": "Nothing to do. Everything is already up-to-date.", - "app_action_cannot_be_ran_because_required_services_down": "Start all required services to run this app. Try to restart the following ones (and possibly investigate why they are down): {services}", + "app_action_cannot_be_ran_because_required_services_down": "Start all services required to run the action that failed. Try restarting the following ones (and possibly investigate why they are down): {services}", "app_action_broke_system": "This action seem to have broke these important services: {services}", "app_already_installed": "{app:s} is already installed", "app_already_installed_cant_change_url": "This app is already installed. The URL cannot be changed just by this function. Look into `app changeurl` if it's available.", From 77960fd40535df3ab7e9f5f19e815742b5bcb502 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 16 Oct 2019 16:40:26 +0200 Subject: [PATCH 079/127] Create FUNDING.yml --- .github/FUNDING.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..c3b460087 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# These are supported funding model platforms + +custom: https://donate.yunohost.org +liberapay: YunoHost From 6be15a62880338c007bb426007bfba626112e5bf Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 16 Oct 2019 17:32:19 +0200 Subject: [PATCH 080/127] Simplify the README, add cool shiny logo, badges and screenshots --- README.md | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index b860c27d7..5fb72e260 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,27 @@ +# YunoHost + [![Build status](https://travis-ci.org/YunoHost/yunohost.svg?branch=stretch-unstable)](https://travis-ci.org/YunoHost/yunohost) [![GitHub license](https://img.shields.io/github/license/YunoHost/yunohost)](https://github.com/YunoHost/yunohost/blob/stretch-unstable/LICENSE) +![Mastodon Follow](https://img.shields.io/mastodon/follow/28084) -# YunoHost core +This repository corresponds to the core code of YunoHost, mainly written in Python and Bash. -This repository is the core of YunoHost code. +You can learn more about what's YunoHost and its features [here](https://yunohost.org/#/whatsyunohost)! - [Project website](https://yunohost.org) -- [Bugtracker](https://github.com/YunoHost/issues). +- [Installation documentation](https://yunohost.org/install) +- [Issue tracker](https://github.com/YunoHost/issues) + +# Screenshots + +Webadmin ([Yunohost-Admin](https://github.com/YunoHost/yunohost-admin)) | Single-sign on user portal ([SSOwat](https://github.com/YunoHost/ssowat)) +--- | --- +![](https://raw.githubusercontent.com/YunoHost/doc/master/images/webadmin.png) | ![](https://raw.githubusercontent.com/YunoHost/doc/master/images/user_panel.png) + ## Contributing -- You can develop on this repository using [ynh-dev](https://github.com/YunoHost/ynh-dev) with `use-git` sub-command. -- On this repository we are [following this workflow](https://yunohost.org/#/build_system_en): `stable ← testing ← unstable ← your_branch`. -- Note: If you modify Python scripts, you will have to modifiy the actions map. +- You can learn how to get started with developing on YunoHost by reading [this piece of documentation](https://yunohost.org/dev). - You can help translate YunoHost on our [translation platform](https://translate.yunohost.org/engage/yunohost/?utm_source=widget) Translation status @@ -21,7 +30,7 @@ This repository is the core of YunoHost code. ## Repository content - [YunoHost core Python 2.7 scripts](./src/yunohost). -- [An actionsmap](./data/actionsmap/yunohost.yml) used by moulinette. +- [An actionsmap](./data/actionsmap/yunohost.yml) describing the CLI and API - [Services configuration templates](./data/templates). - [Hooks](./data/hooks). - [Locales](./locales) for translations of `yunohost` command. @@ -32,17 +41,10 @@ This repository is the core of YunoHost code. ## How does it work? - Python core scripts are accessible through two interfaces thanks to the [moulinette framework](https://github.com/YunoHost/moulinette): - - [CLI](https://en.wikipedia.org/wiki/Command-line_interface) for `yunohost` command. - - [API](https://en.wikipedia.org/wiki/Application_programming_interface) for [web administration module](https://github.com/YunoHost/yunohost-admin) (other modules could be implemented). + - the [CLI](https://en.wikipedia.org/wiki/Command-line_interface) corresponding to the `yunohost` command. + - the [API](https://en.wikipedia.org/wiki/Application_programming_interface) used by the [web administration interface](https://github.com/YunoHost/yunohost-admin) (other interfaces could be implemented). - You can find more details about how YunoHost works on this [documentation (in French)](https://yunohost.org/#/package_list_fr). -## Dependencies - -- [Python 2.7](https://www.python.org/download/releases/2.7) -- [Moulinette](https://github.com/YunoHost/moulinette) -- [Bash](https://www.gnu.org/software/bash/bash.html) -- [Debian Stretch](https://www.debian.org/releases/stretch) - ## License -As [other components of YunoHost core code](https://yunohost.org/#/faq_en), this repository is licensed GNU AGPL v3. +As [other components of YunoHost](https://yunohost.org/#/faq_en), this repository is licensed GNU AGPL v3. From a0febb0b2110041d58fdfdc61468fe62712ad496 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 16 Oct 2019 17:35:52 +0200 Subject: [PATCH 081/127] Uuuh small fixes for the README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5fb72e260..588878261 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build status](https://travis-ci.org/YunoHost/yunohost.svg?branch=stretch-unstable)](https://travis-ci.org/YunoHost/yunohost) [![GitHub license](https://img.shields.io/github/license/YunoHost/yunohost)](https://github.com/YunoHost/yunohost/blob/stretch-unstable/LICENSE) -![Mastodon Follow](https://img.shields.io/mastodon/follow/28084) +[![Mastodon Follow](https://img.shields.io/mastodon/follow/28084)](https://mastodon.social/@yunohost) This repository corresponds to the core code of YunoHost, mainly written in Python and Bash. @@ -14,7 +14,7 @@ You can learn more about what's YunoHost and its features [here](https://yunohos # Screenshots -Webadmin ([Yunohost-Admin](https://github.com/YunoHost/yunohost-admin)) | Single-sign on user portal ([SSOwat](https://github.com/YunoHost/ssowat)) +Webadmin ([Yunohost-Admin](https://github.com/YunoHost/yunohost-admin)) | Single sign-on user portal ([SSOwat](https://github.com/YunoHost/ssowat)) --- | --- ![](https://raw.githubusercontent.com/YunoHost/doc/master/images/webadmin.png) | ![](https://raw.githubusercontent.com/YunoHost/doc/master/images/user_panel.png) From d9990cd818ad0c8056ecb1c0f966f2a180be683c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 16 Oct 2019 18:59:23 +0200 Subject: [PATCH 082/127] Smarter regex to avoid redacting all --key=stuff when using setting helpers for example --- src/yunohost/log.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/yunohost/log.py b/src/yunohost/log.py index 0f5ff784c..72e497b5d 100644 --- a/src/yunohost/log.py +++ b/src/yunohost/log.py @@ -315,7 +315,8 @@ class RedactingFormatter(Formatter): try: # This matches stuff like db_pwd=the_secret or admin_password=other_secret # (the secret part being at least 3 chars to avoid catching some lines like just "db_pwd=") - match = re.search(r'(pwd|pass|password|secret|key|token)=(\S{3,})$', record.strip()) + # For 'key', we require to at least have one word char [a-zA-Z0-9_] before it to avoid catching "--key" used in many helpers + match = re.search(r'(pwd|pass|password|secret|\wkey|token)=(\S{3,})$', record.strip()) if match and match.group(2) not in self.data_to_redact: self.data_to_redact.append(match.group(2)) except Exception as e: From e2731955041b6cd37d4eeebf94b96edb66c0ce7a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 16 Oct 2019 20:22:29 +0200 Subject: [PATCH 083/127] [fix] Bad copypasta: logger doesn't exists in that context... --- data/helpers.d/setting | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/setting b/data/helpers.d/setting index a8d2919a4..fd2824997 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -159,7 +159,7 @@ ynh_add_protected_uris() { ynh_app_setting() { ACTION="$1" APP="$2" KEY="$3" VALUE="${4:-}" python - < Date: Fri, 18 Oct 2019 20:20:22 +0200 Subject: [PATCH 084/127] Remove app_debug, unused stuff, not really relevant, now basically superseded by the new log system... --- data/actionsmap/yunohost.yml | 8 -------- src/yunohost/app.py | 22 ---------------------- 2 files changed, 30 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 22037f05f..400599c48 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -754,14 +754,6 @@ app: full: --sql help: Initial SQL file - ### app_debug() - debug: - action_help: Display all debug informations for an application - api: GET /apps//debug - arguments: - app: - help: App name - ### app_makedefault() makedefault: action_help: Redirect domain root to an app diff --git a/src/yunohost/app.py b/src/yunohost/app.py index f4c504505..d8715b278 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -1253,28 +1253,6 @@ def app_clearaccess(apps): return {'allowed_users': output} -def app_debug(app): - """ - Display debug informations for an app - - Keyword argument: - app - """ - manifest = _get_manifest_of_app(os.path.join(APPS_SETTING_PATH, app)) - - return { - 'name': manifest['id'], - 'label': manifest['name'], - 'services': [{ - "name": x, - "logs": [{ - "file_name": y, - "file_content": "\n".join(z), - } for (y, z) in sorted(service_log(x).items(), key=lambda x: x[0])], - } for x in sorted(manifest.get("services", []))] - } - - @is_unit_operation() def app_makedefault(operation_logger, app, domain=None): """ From b8ce8e93923f450bfbb364758bdb37136d739ed2 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 19 Oct 2019 05:34:42 +0200 Subject: [PATCH 085/127] Try to make those debug messages sound less like an error --- src/yunohost/hook.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yunohost/hook.py b/src/yunohost/hook.py index 05c5a6b6b..40d3d114f 100644 --- a/src/yunohost/hook.py +++ b/src/yunohost/hook.py @@ -196,7 +196,7 @@ def hook_list(action, list_by='name', show_info=False): else: _append_folder(result, HOOK_FOLDER) except OSError: - logger.debug("system hook folder not found for action '%s' in %s", + logger.debug("No default hook for action '%s' in %s", action, HOOK_FOLDER) try: @@ -207,7 +207,7 @@ def hook_list(action, list_by='name', show_info=False): else: _append_folder(result, CUSTOM_HOOK_FOLDER) except OSError: - logger.debug("custom hook folder not found for action '%s' in %s", + logger.debug("No custom hook for action '%s' in %s", action, CUSTOM_HOOK_FOLDER) return {'hooks': result} From 7c99aff94e3bbbf66af8a2a6cd3cfa20b523e05a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 19 Oct 2019 18:04:55 +0200 Subject: [PATCH 086/127] Forgot the i18n --- src/yunohost/permission.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/permission.py b/src/yunohost/permission.py index 4cfbc214f..67d115bc7 100644 --- a/src/yunohost/permission.py +++ b/src/yunohost/permission.py @@ -150,7 +150,7 @@ def user_permission_update(operation_logger, permission, add=None, remove=None, # Don't update LDAP if we update exactly the same values if set(new_allowed_groups) == set(current_allowed_groups): - logger.warning("permission_already_up_to_date") + logger.warning(m18n.n("permission_already_up_to_date")) return # Commit the new allowed group list From 9362261d345b255eebf094b9adb14b271d851b23 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 19 Oct 2019 18:05:32 +0200 Subject: [PATCH 087/127] Ugh some apps uses skipped_uris sometimes instead of unprotected_uris... --- src/yunohost/app.py | 2 +- src/yunohost/data_migrations/0011_setup_group_permission.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index f4c504505..9074c90fd 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -1102,7 +1102,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu permission_url(app_instance_name + ".main", url=None, sync_perm=False) # Migrate classic public app still using the legacy unprotected_uris - if app_settings.get("unprotected_uris", None) == "/": + if app_settings.get("unprotected_uris", None) == "/" or app_settings.get("skipped_uris", None) == "/": user_permission_update(app_instance_name + ".main", remove="all_users", add="visitors", sync_perm=False) permission_sync_to_user() diff --git a/src/yunohost/data_migrations/0011_setup_group_permission.py b/src/yunohost/data_migrations/0011_setup_group_permission.py index 9ba2268d9..7a987899c 100644 --- a/src/yunohost/data_migrations/0011_setup_group_permission.py +++ b/src/yunohost/data_migrations/0011_setup_group_permission.py @@ -117,7 +117,7 @@ class MyMigration(Migration): app_setting(app, 'allowed_users', delete=True) # Migrate classic public app still using the legacy unprotected_uris - if app_setting(app, "unprotected_uris") == "/": + if app_setting(app, "unprotected_uris") == "/" or app_setting(app, "skipped_uris") == "/": user_permission_update(app+".main", remove="all_users", add="visitors", sync_perm=False) permission_sync_to_user() From 98d60a888bf19987cbb956648e777dcbf79dd047 Mon Sep 17 00:00:00 2001 From: ljf Date: Thu, 17 Oct 2019 02:30:23 +0200 Subject: [PATCH 088/127] [fix] HTTP API for permissions --- data/actionsmap/yunohost.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 22037f05f..245b3615d 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -285,7 +285,7 @@ user: ### user_permission_list() list: action_help: List permissions and corresponding accesses - api: GET /users/permissions/ + api: GET /users/permissions arguments: -s: full: --short @@ -300,7 +300,7 @@ user: ### user_permission_update() update: action_help: Manage group or user permissions - api: POST /users/permissions/ + api: PUT /users/permissions/ arguments: permission: help: Permission to manage (e.g. mail or nextcloud or wordpress.editors) From e005d94f82c2ef85d47083fd3ee76ed4ff4ffd37 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 19 Oct 2019 19:08:38 +0200 Subject: [PATCH 089/127] Messed up the message UX with a previous PR (did not have the message explaining how to debug at the very end) --- locales/en.json | 2 +- src/yunohost/app.py | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/locales/en.json b/locales/en.json index 03ecdbccd..1ad7361e9 100644 --- a/locales/en.json +++ b/locales/en.json @@ -23,7 +23,7 @@ "app_id_invalid": "Invalid app ID", "app_incompatible": "The app {app} is incompatible with your YunoHost version", "app_install_files_invalid": "These files cannot be installed", - "app_install_failed": "Could not install {app}", + "app_install_failed": "Could not install {app}: {error}", "app_install_script_failed": "An error occured inside the app installation script", "app_location_already_used": "The app '{app}' is already installed in ({path})", "app_make_default_location_already_used": "Can't make the app '{app}' the default on the domain, {domain} is already in use by the other app '{other_app}'", diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 9074c90fd..5b7202362 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -994,19 +994,19 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu install_failed = True if install_retcode != 0 else False if install_failed: error = m18n.n('app_install_script_failed') - logger.exception(error) - operation_logger.error(error) + logger.exception(m18n.n("app_install_failed", app=app_id, error=error)) + failure_message_with_debug_instructions = operation_logger.error(error) # Script got manually interrupted ... N.B. : KeyboardInterrupt does not inherit from Exception except (KeyboardInterrupt, EOFError): error = m18n.n('operation_interrupted') - logger.exception(error) - operation_logger.error(error) + logger.exception(m18n.n("app_install_failed", app=app_id, error=error)) + failure_message_with_debug_instructions = operation_logger.error(error) # Something wrong happened in Yunohost's code (most probably hook_exec) - except Exception as e : + except Exception as e: import traceback error = m18n.n('unexpected_error', error=u"\n" + traceback.format_exc()) - logger.exception(error) - operation_logger.error(error) + logger.exception(m18n.n("app_install_failed", app=app_id, error=error)) + failure_message_with_debug_instructions = operation_logger.error(error) finally: # Whatever happened (install success or failure) we check if it broke the system # and warn the user about it @@ -1015,8 +1015,8 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu _assert_system_is_sane_for_app(manifest, "post") except Exception as e: broke_the_system = True - logger.exception(str(e)) - operation_logger.error(str(e)) + logger.exception(m18n.n("app_install_failed", app=app_id, error=str(e))) + failure_message_with_debug_instructions = operation_logger.error(str(e)) # If the install failed or broke the system, we remove it if install_failed or broke_the_system: @@ -1076,7 +1076,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu app_ssowatconf() - raise YunohostError("app_install_failed", app=app_id) + raise YunohostError(failure_message_with_debug_instructions, raw_msg=True) # Clean hooks and add new ones hook_remove(app_instance_name) From 9beeb16077277ba5c181baad94bcdf70510ed3de Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 19 Oct 2019 19:18:19 +0200 Subject: [PATCH 090/127] Don't sync permission right away when deleting them, otherwise we get annoying warning because app_map thinks the app is still installed and expected a main permission --- src/yunohost/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 5b7202362..5cf812871 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -1055,7 +1055,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu # Remove all permission in LDAP for permission_name in user_permission_list()["permissions"].keys(): if permission_name.startswith(app_instance_name+"."): - permission_delete(permission_name, force=True) + permission_delete(permission_name, force=True, sync_perm=False) if remove_retcode != 0: msg = m18n.n('app_not_properly_removed', @@ -1074,7 +1074,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu shutil.rmtree(app_setting_path) shutil.rmtree(extracted_app_folder) - app_ssowatconf() + permission_sync_to_user() raise YunohostError(failure_message_with_debug_instructions, raw_msg=True) From 25afdd4d4109faebf8e2aeef78eb2f53587f3dfb Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 22 Oct 2019 15:50:41 +0200 Subject: [PATCH 091/127] Misc README improvements --- README.md | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 588878261..5b7d04750 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,24 @@ -# YunoHost +

+ YunoHost +

+ +

YunoHost

+ +
[![Build status](https://travis-ci.org/YunoHost/yunohost.svg?branch=stretch-unstable)](https://travis-ci.org/YunoHost/yunohost) [![GitHub license](https://img.shields.io/github/license/YunoHost/yunohost)](https://github.com/YunoHost/yunohost/blob/stretch-unstable/LICENSE) [![Mastodon Follow](https://img.shields.io/mastodon/follow/28084)](https://mastodon.social/@yunohost) +
+ +YunoHost is an operating system aiming to simplify as much as possible the administration of a server. + This repository corresponds to the core code of YunoHost, mainly written in Python and Bash. -You can learn more about what's YunoHost and its features [here](https://yunohost.org/#/whatsyunohost)! - +- [Project features](https://yunohost.org/#/whatsyunohost) - [Project website](https://yunohost.org) -- [Installation documentation](https://yunohost.org/install) +- [Install documentation](https://yunohost.org/install) - [Issue tracker](https://github.com/YunoHost/issues) # Screenshots @@ -22,6 +31,7 @@ Webadmin ([Yunohost-Admin](https://github.com/YunoHost/yunohost-admin)) | Single ## Contributing - You can learn how to get started with developing on YunoHost by reading [this piece of documentation](https://yunohost.org/dev). +- Come chat with us on the [dev chatroom](https://yunohost.org/#/chat_rooms) ! - You can help translate YunoHost on our [translation platform](https://translate.yunohost.org/engage/yunohost/?utm_source=widget) Translation status From 73741f6cd937061329f0b9a2bbd54c3699a1a7e4 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 22 Oct 2019 16:44:20 +0200 Subject: [PATCH 092/127] Simplify README, all those explanations are now in the dev documentation --- README.md | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 5b7d04750..aec5300e2 100644 --- a/README.md +++ b/README.md @@ -34,27 +34,10 @@ Webadmin ([Yunohost-Admin](https://github.com/YunoHost/yunohost-admin)) | Single - Come chat with us on the [dev chatroom](https://yunohost.org/#/chat_rooms) ! - You can help translate YunoHost on our [translation platform](https://translate.yunohost.org/engage/yunohost/?utm_source=widget) +

Translation status - - -## Repository content - -- [YunoHost core Python 2.7 scripts](./src/yunohost). -- [An actionsmap](./data/actionsmap/yunohost.yml) describing the CLI and API -- [Services configuration templates](./data/templates). -- [Hooks](./data/hooks). -- [Locales](./locales) for translations of `yunohost` command. -- [Shell helpers](./helpers.d) for [application packaging](https://yunohost.org/#/packaging_apps_helpers_en). -- [Modules for the XMPP server Metronome](./lib/metronome/modules). -- [Debian files](./debian) for package creation. - -## How does it work? - -- Python core scripts are accessible through two interfaces thanks to the [moulinette framework](https://github.com/YunoHost/moulinette): - - the [CLI](https://en.wikipedia.org/wiki/Command-line_interface) corresponding to the `yunohost` command. - - the [API](https://en.wikipedia.org/wiki/Application_programming_interface) used by the [web administration interface](https://github.com/YunoHost/yunohost-admin) (other interfaces could be implemented). -- You can find more details about how YunoHost works on this [documentation (in French)](https://yunohost.org/#/package_list_fr). +

## License -As [other components of YunoHost](https://yunohost.org/#/faq_en), this repository is licensed GNU AGPL v3. +As [other components of YunoHost](https://yunohost.org/#/faq_en), this repository is licensed under GNU AGPL v3. From ef65f82e4437b0c22249b8aebb88f8de9ef685b8 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 22 Oct 2019 20:32:08 +0200 Subject: [PATCH 093/127] Improve string app_action_cannot_be_ran_because_required_services_down --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 34d5f1ab7..1d68fb334 100644 --- a/locales/en.json +++ b/locales/en.json @@ -6,7 +6,7 @@ "admin_password_changed": "The administration password got changed", "admin_password_too_long": "Please choose a password shorter than 127 characters", "already_up_to_date": "Nothing to do. Everything is already up-to-date.", - "app_action_cannot_be_ran_because_required_services_down": "Start all services required to run the action that failed. Try restarting the following ones (and possibly investigate why they are down): {services}", + "app_action_cannot_be_ran_because_required_services_down": "These required services should be running to run this action: {services}. Try restarting them to continue (and possibly investigate why they are down).", "app_action_broke_system": "This action seem to have broke these important services: {services}", "app_already_installed": "{app:s} is already installed", "app_already_installed_cant_change_url": "This app is already installed. The URL cannot be changed just by this function. Look into `app changeurl` if it's available.", From 4f3fac60057ed537fb86f7b0e8c9ee53663ef4d3 Mon Sep 17 00:00:00 2001 From: amirale qt Date: Wed, 16 Oct 2019 06:21:31 +0000 Subject: [PATCH 094/127] Translated using Weblate (French) Currently translated at 100.0% (560 of 560 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/locales/fr.json b/locales/fr.json index 9abeb585c..9e64bcff5 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -653,5 +653,15 @@ "permission_already_disallowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' désactivé '", "permission_cannot_remove_main": "Supprimer une autorisation principale n'est pas autorisé", "user_already_exists": "L'utilisateur {user} existe déjà", - "app_full_domain_unavailable": "Désolé, cette application nécessite l'installation d'un domaine complet, mais d'autres applications sont déjà installées sur le domaine '{domain}'. Une solution possible consiste à ajouter et à utiliser un sous-domaine dédié à cette application." + "app_full_domain_unavailable": "Désolé, cette application nécessite l'installation d'un domaine complet, mais d'autres applications sont déjà installées sur le domaine '{domain}'. Une solution possible consiste à ajouter et à utiliser un sous-domaine dédié à cette application.", + "group_cannot_edit_all_users": "Le groupe 'all_users' ne peut pas être édité manuellement. C'est un groupe spécial destiné à contenir tous les utilisateurs enregistrés dans YunoHost", + "group_cannot_edit_visitors": "Le groupe 'visiteurs' ne peut pas être édité manuellement. C'est un groupe spécial représentant les visiteurs anonymes", + "group_cannot_edit_primary_group": "Le groupe '{group}' ne peut pas être édité manuellement. C'est le groupe principal destiné à ne contenir qu'un utilisateur spécifique.", + "log_permission_url": "Mise à jour de l'URL associée à l'autorisation '{}'", + "migration_0011_slapd_config_will_be_overwritten": "Il semble que vous ayez modifié manuellement la configuration de slapd. Pour cette migration critique, YunoHost doit forcer la mise à jour de la configuration de slapd. Les fichiers originaux seront sauvegardés dans {conf_backup_folder}.", + "permission_already_up_to_date": "L'autorisation n'a pas été mise à jour car les demandes d'ajout/suppression correspondent déjà à l'état actuel.", + "permission_currently_allowed_for_visitors": "Cette autorisation est actuellement accordée aux visiteurs en plus d'autres groupes. Vous voudrez probablement supprimer l'autorisation \"visiteurs\" ou supprimer les autres groupes auxquels il est actuellement attribué.", + "permission_currently_allowed_for_all_users": "Cette autorisation est actuellement accordée à tous les utilisateurs en plus des autres groupes. Vous voudrez probablement soit supprimer l'autorisation 'all_users', soit supprimer les autres groupes auxquels il est actuellement autorisé.", + "app_install_failed": "Impossible d'installer {app}", + "app_install_script_failed": "Une erreur est survenue dans le script d'installation de l'application" } From 2a30a97142f78bcec645f4db21cb63effcb0bdd0 Mon Sep 17 00:00:00 2001 From: xaloc33 Date: Wed, 16 Oct 2019 07:47:01 +0000 Subject: [PATCH 095/127] Translated using Weblate (Catalan) Currently translated at 100.0% (560 of 560 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ca/ --- locales/ca.json | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/locales/ca.json b/locales/ca.json index 592bc4592..b3831d929 100644 --- a/locales/ca.json +++ b/locales/ca.json @@ -285,7 +285,7 @@ "ldap_initialized": "S'ha iniciat LDAP", "license_undefined": "indefinit", "mail_alias_remove_failed": "No s'han pogut eliminar els àlies del correu «{mail:s}»", - "mail_domain_unknown": "Domini d'adreça de correu per «{domain:s}» desconegut", + "mail_domain_unknown": "El domini «{domain:s}» de l'adreça de correu no és vàlid. Utilitzeu un domini administrat per aquest servidor.", "mail_forward_remove_failed": "No s'han pogut eliminar el reenviament de correu «{mail:s}»", "mailbox_used_space_dovecot_down": "S'ha d'engegar el servei de correu Dovecot, per poder obtenir l'espai utilitzat per la bústia de correu", "mail_unavailable": "Aquesta adreça de correu està reservada i ha de ser atribuïda automàticament el primer usuari", @@ -617,5 +617,13 @@ "user_already_exists": "L'usuari {user} ja existeix", "app_upgrade_stopped": "S'ha aturat l'actualització de totes les aplicacions per prevenir els possibles danys ja que hi ha hagut un error en l'actualització de l'anterior aplicació", "app_install_failed": "No s'ha pogut instal·lar {app}", - "app_install_script_failed": "Hi ha hagut un error en el script d'instal·lació de l'aplicació" + "app_install_script_failed": "Hi ha hagut un error en el script d'instal·lació de l'aplicació", + "group_cannot_edit_all_users": "El grup «all_users» no es pot editar manualment. És un grup especial destinat a contenir els usuaris registrats a YunoHost", + "group_cannot_edit_visitors": "El grup «visitors» no es pot editar manualment. És un grup especial que representa els visitants anònims", + "group_cannot_edit_primary_group": "El grup «{group}» no es pot editar manualment. És el grup principal destinat a contenir un usuari específic.", + "log_permission_url": "Actualització de la URL associada al permís «{}»", + "migration_0011_slapd_config_will_be_overwritten": "Sembla que heu modificat manualment la configuració de sldap. Per aquesta migració crítica, YunoHost ha de forçar l'actualització de la configuració sldap. Es farà una còpia de seguretat a {conf_backup_folder}.", + "permission_already_up_to_date": "No s'ha actualitzat el permís perquè la petició d'afegir/eliminar ja corresponent a l'estat actual.", + "permission_currently_allowed_for_visitors": "El permís ja el tenen el grup de visitants a més d'altres grups. Segurament s'hauria de revocar el permís al grup dels visitants o eliminar els altres grups als que s'ha atribuït.", + "permission_currently_allowed_for_all_users": "El permís ha el té el grup de tots els usuaris (all_users) a més d'altres grups. Segurament s'hauria de revocar el permís a «all_users» o eliminar els altres grups als que s'ha atribuït." } From 889f4ef9ea7f35fe2ebf090decc9907e5f466c75 Mon Sep 17 00:00:00 2001 From: amirale qt Date: Wed, 16 Oct 2019 06:28:28 +0000 Subject: [PATCH 096/127] Translated using Weblate (Esperanto) Currently translated at 100.0% (560 of 560 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eo/ --- locales/eo.json | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/locales/eo.json b/locales/eo.json index 0d8d13fe8..237bdd1df 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -476,7 +476,7 @@ "mountpoint_unknown": "Nekonata montpunkto", "log_tools_maindomain": "Faru de '{}' la ĉefa domajno", "maindomain_change_failed": "Ne povis ŝanĝi la ĉefan domajnon", - "mail_domain_unknown": "Nekonata retpoŝtadreso por domajno '{domain:s}'", + "mail_domain_unknown": "Nevalida retadreso por domajno '{domain:s}'. Bonvolu uzi domajnon administritan de ĉi tiu servilo.", "migrations_cant_reach_migration_file": "Ne povis aliri migrajn dosierojn ĉe la vojo% s", "pattern_email": "Devas esti valida retpoŝtadreso (t.e.iu@domain.org)", "mail_alias_remove_failed": "Ne povis forigi retpoŝton alias '{mail:s}'", @@ -553,5 +553,15 @@ "service_restart_failed": "Ne povis rekomenci la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}", "firewall_rules_cmd_failed": "Iuj komandoj pri fajroŝirmilo malsukcesis. Pliaj informoj en ensaluto.", "certmanager_certificate_fetching_or_enabling_failed": "Provante uzi la novan atestilon por {domain:s} ne funkciis …", - "app_full_domain_unavailable": "Bedaŭrinde, ĉi tiu apliko postulas plenan domajnon esti instalita, sed iuj aliaj programoj jam estas instalitaj sur '{domain}'. Unu ebla solvo estas aldoni kaj uzi subdomajnon dediĉitan al ĉi tiu aplikaĵo anstataŭe." + "app_full_domain_unavailable": "Bedaŭrinde, ĉi tiu apliko postulas plenan domajnon esti instalita, sed iuj aliaj programoj jam estas instalitaj sur '{domain}'. Unu ebla solvo estas aldoni kaj uzi subdomajnon dediĉitan al ĉi tiu aplikaĵo anstataŭe.", + "migration_0011_slapd_config_will_be_overwritten": "Ŝajnas ke vi permane redaktis la slapd-agordon. Por ĉi tiu kritika migrado, YunoHost bezonas devigi la ĝisdatigon de la slapd-agordo. La originalaj dosieroj estos rezervitaj en {conf_backup_folder}.", + "group_cannot_edit_all_users": "La grupo 'all_users' ne povas esti redaktita permane. Ĝi estas speciala grupo celita enhavi ĉiujn uzantojn registritajn en YunoHost", + "group_cannot_edit_visitors": "La grupo 'vizitantoj' ne povas esti redaktita permane. Ĝi estas speciala grupo reprezentanta anonimajn vizitantojn", + "group_cannot_edit_primary_group": "La grupo '{group}' ne povas esti redaktita permane. Ĝi estas la primara grupo celita enhavi nur unu specifan uzanton.", + "log_permission_url": "Ĝisdatigu url-rilataj al permeso '{}'", + "permission_already_up_to_date": "La permeso ne estis ĝisdatigita ĉar la petoj pri aldono/forigo jam kongruas kun la aktuala stato.", + "permission_currently_allowed_for_visitors": "Ĉi tiu permeso estas nuntempe donita al vizitantoj aldone al aliaj grupoj. Vi probable volas aŭ forigi la permeson de \"vizitantoj\" aŭ forigi la aliajn grupojn al kiuj ĝi nun estas koncedita.", + "permission_currently_allowed_for_all_users": "Ĉi tiu permeso estas nuntempe donita al ĉiuj uzantoj aldone al aliaj grupoj. Vi probable volas aŭ forigi la permeson \"all_users\" aŭ forigi la aliajn grupojn, kiujn ĝi nuntempe donas.", + "app_install_failed": "Ne povis instali {app}", + "app_install_script_failed": "Eraro okazis en la skripto de instalado de la app" } From 82662167fc55becbc766fe4ac00dedc96ca5f7f2 Mon Sep 17 00:00:00 2001 From: advocatux Date: Thu, 17 Oct 2019 16:16:02 +0000 Subject: [PATCH 097/127] Translated using Weblate (Spanish) Currently translated at 100.0% (560 of 560 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/es/ --- locales/es.json | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/locales/es.json b/locales/es.json index 4f136460c..17c2998fa 100644 --- a/locales/es.json +++ b/locales/es.json @@ -119,7 +119,7 @@ "ldap_initialized": "Inicializado LDAP", "license_undefined": "indefinido", "mail_alias_remove_failed": "No se pudo eliminar el alias de correo «{mail:s}»", - "mail_domain_unknown": "Dirección de correo desconocida para el dominio «{domain:s}»", + "mail_domain_unknown": "Dirección de correo no válida para el dominio «{domain:s}». Use un dominio administrado por este servidor.", "mail_forward_remove_failed": "No se pudo eliminar el reenvío de correo «{mail:s}»", "maindomain_change_failed": "No se pudo cambiar el dominio principal", "maindomain_changed": "El dominio principal ha cambiado", @@ -628,5 +628,13 @@ "user_already_exists": "El usuario {user} ya existe", "app_full_domain_unavailable": "Lamentablemente esta aplicación necesita un dominio completo para ser instalada pero ya hay otras aplicaciones instaladas en el dominio «{domain}». Una solución posible es añadir y usar un subdominio dedicado a esta aplicación.", "app_install_failed": "No se pudo instalar {app}", - "app_install_script_failed": "Ha ocurrido un error en el guión de instalación de la aplicación" + "app_install_script_failed": "Ha ocurrido un error en el guión de instalación de la aplicación", + "group_cannot_edit_all_users": "El grupo «all_users» no se puede editar manualmente. Es un grupo especial destinado a contener todos los usuarios registrados en YunoHost", + "group_cannot_edit_visitors": "El grupo «visitors» no se puede editar manualmente. Es un grupo especial que representa a los visitantes anónimos", + "group_cannot_edit_primary_group": "El grupo «{group}» no se puede editar manualmente. Es el grupo primario destinado a contener solo un usuario específico.", + "log_permission_url": "Actualizar la URL relacionada con el permiso «{}»", + "migration_0011_slapd_config_will_be_overwritten": "Parece que ha editado manualmente la configuración de slapd. Para esta migración crítica, YunoHost necesita forzar la actualización de la configuración de slapd. Los archivos originales se respaldarán en {conf_backup_folder}.", + "permission_already_up_to_date": "El permiso no se ha actualizado porque las peticiones de incorporación o eliminación ya coinciden con el estado actual.", + "permission_currently_allowed_for_visitors": "Este permiso se concede actualmente a los visitantes además de otros grupos. Probablemente quiere o eliminar el permiso de «visitors» o eliminar los otros grupos a los que está otorgado actualmente.", + "permission_currently_allowed_for_all_users": "Este permiso se concede actualmente a todos los usuarios además de los otros grupos. Probablemente quiere o eliminar el permiso de «all_users» o eliminar los otros grupos a los que está otorgado actualmente." } From 88c8df2046997ddabbcf487c2a1dd5b622d29a25 Mon Sep 17 00:00:00 2001 From: advocatux Date: Mon, 21 Oct 2019 09:36:01 +0000 Subject: [PATCH 098/127] Translated using Weblate (Spanish) Currently translated at 100.0% (560 of 560 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/es/ --- locales/es.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/es.json b/locales/es.json index 17c2998fa..57e6de99d 100644 --- a/locales/es.json +++ b/locales/es.json @@ -627,7 +627,7 @@ "permission_cannot_remove_main": "No está permitido eliminar un permiso principal", "user_already_exists": "El usuario {user} ya existe", "app_full_domain_unavailable": "Lamentablemente esta aplicación necesita un dominio completo para ser instalada pero ya hay otras aplicaciones instaladas en el dominio «{domain}». Una solución posible es añadir y usar un subdominio dedicado a esta aplicación.", - "app_install_failed": "No se pudo instalar {app}", + "app_install_failed": "No se pudo instalar {app}: {error}", "app_install_script_failed": "Ha ocurrido un error en el guión de instalación de la aplicación", "group_cannot_edit_all_users": "El grupo «all_users» no se puede editar manualmente. Es un grupo especial destinado a contener todos los usuarios registrados en YunoHost", "group_cannot_edit_visitors": "El grupo «visitors» no se puede editar manualmente. Es un grupo especial que representa a los visitantes anónimos", From fd4e89e22cbed23b24af132ede6413a90218d5e5 Mon Sep 17 00:00:00 2001 From: amirale qt Date: Mon, 21 Oct 2019 07:44:05 +0000 Subject: [PATCH 099/127] Translated using Weblate (Esperanto) Currently translated at 100.0% (560 of 560 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eo/ --- locales/eo.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/eo.json b/locales/eo.json index 237bdd1df..3931c27d0 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -562,6 +562,6 @@ "permission_already_up_to_date": "La permeso ne estis ĝisdatigita ĉar la petoj pri aldono/forigo jam kongruas kun la aktuala stato.", "permission_currently_allowed_for_visitors": "Ĉi tiu permeso estas nuntempe donita al vizitantoj aldone al aliaj grupoj. Vi probable volas aŭ forigi la permeson de \"vizitantoj\" aŭ forigi la aliajn grupojn al kiuj ĝi nun estas koncedita.", "permission_currently_allowed_for_all_users": "Ĉi tiu permeso estas nuntempe donita al ĉiuj uzantoj aldone al aliaj grupoj. Vi probable volas aŭ forigi la permeson \"all_users\" aŭ forigi la aliajn grupojn, kiujn ĝi nuntempe donas.", - "app_install_failed": "Ne povis instali {app}", + "app_install_failed": "Ne povis instali {app} : {error}", "app_install_script_failed": "Eraro okazis en la skripto de instalado de la app" } From d52cbd127b296fc2a64c135a47c0b73e25eacf35 Mon Sep 17 00:00:00 2001 From: amirale qt Date: Mon, 21 Oct 2019 07:42:00 +0000 Subject: [PATCH 100/127] Translated using Weblate (French) Currently translated at 100.0% (560 of 560 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/fr.json b/locales/fr.json index 9e64bcff5..90eed4bee 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -662,6 +662,6 @@ "permission_already_up_to_date": "L'autorisation n'a pas été mise à jour car les demandes d'ajout/suppression correspondent déjà à l'état actuel.", "permission_currently_allowed_for_visitors": "Cette autorisation est actuellement accordée aux visiteurs en plus d'autres groupes. Vous voudrez probablement supprimer l'autorisation \"visiteurs\" ou supprimer les autres groupes auxquels il est actuellement attribué.", "permission_currently_allowed_for_all_users": "Cette autorisation est actuellement accordée à tous les utilisateurs en plus des autres groupes. Vous voudrez probablement soit supprimer l'autorisation 'all_users', soit supprimer les autres groupes auxquels il est actuellement autorisé.", - "app_install_failed": "Impossible d'installer {app}", + "app_install_failed": "Impossible d'installer {app}: {error}", "app_install_script_failed": "Une erreur est survenue dans le script d'installation de l'application" } From 5695e4d25e1b4d9bbb5ae3a7d9e9f124128239d9 Mon Sep 17 00:00:00 2001 From: xaloc33 Date: Sun, 20 Oct 2019 14:13:21 +0000 Subject: [PATCH 101/127] Translated using Weblate (Catalan) Currently translated at 100.0% (560 of 560 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ca/ --- locales/ca.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/ca.json b/locales/ca.json index b3831d929..04ee413b9 100644 --- a/locales/ca.json +++ b/locales/ca.json @@ -616,7 +616,7 @@ "permission_cannot_remove_main": "No es permet eliminar un permís principal", "user_already_exists": "L'usuari {user} ja existeix", "app_upgrade_stopped": "S'ha aturat l'actualització de totes les aplicacions per prevenir els possibles danys ja que hi ha hagut un error en l'actualització de l'anterior aplicació", - "app_install_failed": "No s'ha pogut instal·lar {app}", + "app_install_failed": "No s'ha pogut instal·lar {app}: {error}", "app_install_script_failed": "Hi ha hagut un error en el script d'instal·lació de l'aplicació", "group_cannot_edit_all_users": "El grup «all_users» no es pot editar manualment. És un grup especial destinat a contenir els usuaris registrats a YunoHost", "group_cannot_edit_visitors": "El grup «visitors» no es pot editar manualment. És un grup especial que representa els visitants anònims", From bd02678275320e52a82082fb3286ba05ecb85386 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 24 Oct 2019 17:47:43 +0200 Subject: [PATCH 102/127] Refuse to add visitors to mail / xmpp / ... permission as it doesnt make sense --- locales/en.json | 1 + src/yunohost/permission.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/locales/en.json b/locales/en.json index 1d68fb334..73b5c46fb 100644 --- a/locales/en.json +++ b/locales/en.json @@ -429,6 +429,7 @@ "permission_update_failed": "Could not update permission '{permission}' : {error}", "permission_updated": "Permission '{permission:s}' updated", "permission_update_nothing_to_do": "No permissions to update", + "permission_require_account": "Permission {permission} only makes sense for users having an account, and therefore cannot be enabled for visitors.", "port_already_closed": "Port {port:d} is already closed for {ip_version:s} connections", "port_already_opened": "Port {port:d} is already opened for {ip_version:s} connections", "port_available": "Port {port:d} is available", diff --git a/src/yunohost/permission.py b/src/yunohost/permission.py index 67d115bc7..226cc9050 100644 --- a/src/yunohost/permission.py +++ b/src/yunohost/permission.py @@ -100,6 +100,10 @@ def user_permission_update(operation_logger, permission, add=None, remove=None, if "." not in permission: permission = permission + ".main" + # Refuse to add "visitors" to mail, xmpp ... they require an account to make sense. + if add and "visitors" in add and permission.split(".")[0] in SYSTEM_PERMS: + raise YunohostError('permission_require_account', permission=permission) + # Fetch currently allowed groups for this permission existing_permission = user_permission_list(full=True)["permissions"].get(permission, None) From a9317487b3fb4fd0020dfd35b73d43693f6f9338 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 24 Oct 2019 17:58:34 +0200 Subject: [PATCH 103/127] Typo in string --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 73b5c46fb..202650edb 100644 --- a/locales/en.json +++ b/locales/en.json @@ -414,7 +414,7 @@ "pattern_positive_number": "Must be a positive number", "pattern_username": "Must be lower-case alphanumeric and underscore characters only", "pattern_password_app": "Sorry, passwords can not contain the following characters: {forbidden_chars}", - "permission_already_allowed": "Group '{group}' already has permission '{permission}' enabled'", + "permission_already_allowed": "Group '{group}' already has permission '{permission}' enabled", "permission_already_disallowed": "Group '{group}' already has permission '{permission}' disabled'", "permission_already_exist": "Permission '{permission}' already exists", "permission_already_up_to_date": "The permission was not updated because the addition/removal requests already match the current state.", From 936da7aa7948ddd9d27e1c7a5e520337b71a44e8 Mon Sep 17 00:00:00 2001 From: advocatux Date: Wed, 23 Oct 2019 09:03:22 +0000 Subject: [PATCH 104/127] Translated using Weblate (Spanish) Currently translated at 100.0% (560 of 560 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/es/ --- locales/es.json | 104 ++++++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/locales/es.json b/locales/es.json index 57e6de99d..afa323269 100644 --- a/locales/es.json +++ b/locales/es.json @@ -29,10 +29,10 @@ "app_unsupported_remote_type": "Tipo remoto no soportado por la aplicación", "app_upgrade_failed": "No se pudo actualizar {app:s}", "app_upgraded": "Actualizado {app:s}", - "appslist_fetched": "Lista de aplicaciones {appslist:s} actualizada", - "appslist_removed": "Eliminada la lista de aplicaciones {appslist:s}", - "appslist_retrieve_error": "No se puede recuperar la lista remota de aplicaciones {appslist:s}: {error:s}", - "appslist_unknown": "Lista de aplicaciones {appslist:s} desconocida.", + "appslist_fetched": "Lista de aplicaciones «{appslist:s}» actualizada", + "appslist_removed": "Eliminada la lista de aplicaciones «{appslist:s}»", + "appslist_retrieve_error": "No se puede recuperar la lista remota de aplicaciones «{appslist:s}»: {error:s}", + "appslist_unknown": "Lista de aplicaciones «{appslist:s}» desconocida.", "ask_current_admin_password": "Contraseña administrativa actual", "ask_email": "Dirección de correo electrónico", "ask_firstname": "Nombre", @@ -70,7 +70,7 @@ "diagnosis_monitor_disk_error": "No se pudieron monitorizar los discos: {error}", "diagnosis_monitor_network_error": "No se pudo monitorizar la red: {error}", "diagnosis_monitor_system_error": "No se pudo monitorizar el sistema: {error}", - "diagnosis_no_apps": "Aplicación no instalada", + "diagnosis_no_apps": "No hay tal aplicación instalada", "dnsmasq_isnt_installed": "Parece que dnsmasq no está instalado, ejecute «apt-get remove bind9 && apt-get install it»", "domain_cert_gen_failed": "No se pudo generar el certificado", "domain_created": "Dominio creado", @@ -123,8 +123,8 @@ "mail_forward_remove_failed": "No se pudo eliminar el reenvío de correo «{mail:s}»", "maindomain_change_failed": "No se pudo cambiar el dominio principal", "maindomain_changed": "El dominio principal ha cambiado", - "monitor_disabled": "Desactivada la monitorización del servidor", - "monitor_enabled": "Activada la monitorización del servidor", + "monitor_disabled": "La monitorización del servidor está ahora desactivada", + "monitor_enabled": "La monitorización del servidor está ahora activada", "monitor_glances_con_failed": "No se pudo conectar al servidor de Glances", "monitor_not_enabled": "La monitorización del servidor está apagada", "monitor_period_invalid": "Período de tiempo no válido", @@ -132,9 +132,9 @@ "monitor_stats_no_update": "No hay estadísticas de monitorización para actualizar", "monitor_stats_period_unavailable": "No hay estadísticas para el período", "mountpoint_unknown": "Punto de montaje desconocido", - "mysql_db_creation_failed": "Error al crear la base de datos de MySQL", - "mysql_db_init_failed": "Error al iniciar la base de datos de MySQL", - "mysql_db_initialized": "Inicializada la base de datos MySQL", + "mysql_db_creation_failed": "No se pudo crear la base de datos MySQL", + "mysql_db_init_failed": "No se pudo inicializar la base de datos MySQL", + "mysql_db_initialized": "La base de datos MySQL está ahora inicializada", "network_check_mx_ko": "El registro DNS MX no está configurado", "network_check_smtp_ko": "El correo saliente (SMTP puerto 25) parece estar bloqueado por su red", "network_check_smtp_ok": "El correo saliente (SMTP puerto 25) no está bloqueado", @@ -144,7 +144,7 @@ "no_ipv6_connectivity": "La conexión por IPv6 no está disponible", "no_restore_script": "No se ha encontrado un script de restauración para la aplicación '{app:s}'", "not_enough_disk_space": "No hay espacio libre suficiente en «{path:s}»", - "package_not_installed": "El paquete '{pkgname}' no está instalado", + "package_not_installed": "El paquete «{pkgname}» no está instalado", "package_unexpected_error": "Ha ocurrido un error inesperado procesando el paquete '{pkgname}'", "package_unknown": "Paquete desconocido '{pkgname}'", "packages_no_upgrade": "No hay paquetes para actualizar", @@ -153,7 +153,7 @@ "path_removal_failed": "No se pudo eliminar la ruta {:s}", "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 (por ejemplo, alguien@dominio.org)", + "pattern_email": "Debe ser una dirección de correo electrónico válida (p.ej. alguien@example.com)", "pattern_firstname": "Debe ser un nombre válido", "pattern_lastname": "Debe ser un apellido válido", "pattern_listname": "Solo se pueden usar caracteres alfanuméricos y el guion bajo", @@ -180,7 +180,7 @@ "restore_running_hooks": "Ejecutando los ganchos de restauración…", "service_add_failed": "No se pudo añadir el servicio «{service:s}»", "service_added": "Añadido el servicio «{service:s}»", - "service_already_started": "El servicio «{service:s}» ya ha sido iniciado", + "service_already_started": "El servicio «{service:s}» ya está funcionando", "service_already_stopped": "El servicio «{service:s}» ya ha sido detenido", "service_cmd_exec_failed": "No se pudo ejecutar la orden «{command:s}»", "service_conf_file_backed_up": "Se ha realizado una copia de seguridad del archivo de configuración '{conf}' en '{backup}'", @@ -195,10 +195,10 @@ "service_conf_updated": "La configuración ha sido actualizada para el servicio '{service}'", "service_conf_would_be_updated": "La configuración podría haber sido actualizada para el servicio '{service} 1'", "service_disable_failed": "No se pudo desactivar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}", - "service_disabled": "Desactivado el servicio «{service:s}»", + "service_disabled": "El servicio «{service:s}» ha sido desactivado", "service_enable_failed": "No se pudo activar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}", - "service_enabled": "Activado el servicio «{service:s}»", - "service_no_log": "No hay ningún registro para el servicio '{service:s}'", + "service_enabled": "El servicio «{service:s}» ha sido desactivado", + "service_no_log": "No hay ningún registro que mostrar para el servicio «{service:s}»", "service_regenconf_dry_pending_applying": "Comprobando configuración pendiente que podría haber sido aplicada al servicio '{service}'...", "service_regenconf_failed": "No se puede regenerar la configuración para el servicio(s): {services}", "service_regenconf_pending_applying": "Aplicando la configuración pendiente para el servicio '{service}'...", @@ -208,7 +208,7 @@ "service_started": "Iniciado el servicio «{service:s}»", "service_status_failed": "No se pudo determinar el estado del servicio «{service:s}»", "service_stop_failed": "No se pudo detener el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}", - "service_stopped": "Detenido el servicio «{service:s}»", + "service_stopped": "El servicio «{service:s}» se detuvo", "service_unknown": "Servicio desconocido '{service:s}'", "ssowat_conf_generated": "Generada la configuración de SSOwat", "ssowat_conf_updated": "Actualizada la configuración de SSOwat", @@ -238,7 +238,7 @@ "user_updated": "Cambiada la información de usuario", "yunohost_already_installed": "YunoHost ya está instalado", "yunohost_ca_creation_failed": "No se pudo crear la autoridad de certificación", - "yunohost_configured": "YunoHost está configurado", + "yunohost_configured": "YunoHost está ahora configurado", "yunohost_installing": "Instalando YunoHost…", "yunohost_not_installed": "YunoHost no está correctamente instalado. Ejecute «yunohost tools postinstall»", "ldap_init_failed_to_create_admin": "La inicialización de LDAP no pudo crear el usuario «admin»", @@ -272,25 +272,25 @@ "certmanager_acme_not_configured_for_domain": "El certificado para el dominio «{domain:s}» no parece que esté instalado correctamente. Ejecute primero «cert-install» para este dominio.", "certmanager_http_check_timeout": "Tiempo de espera agotado cuando el servidor intentaba conectarse consigo mismo a través de HTTP usando una dirección IP pública (dominio «{domain:s}» con IP «{ip:s}»). Puede que esté experimentando un problema de redirección («hairpinning»), o que el cortafuegos o el enrutador de su servidor esté mal configurado.", "certmanager_couldnt_fetch_intermediate_cert": "Tiempo de espera agotado intentando obtener el certificado intermedio de Let's Encrypt. Cancelada la instalación o renovación del certificado. Vuelva a intentarlo más tarde.", - "appslist_retrieve_bad_format": "No se pudo leer la lista de aplicaciones obtenida {appslist:s}", + "appslist_retrieve_bad_format": "No se pudo leer la lista de aplicaciones obtenida «{appslist:s}»", "domain_hostname_failed": "No se pudo establecer un nuevo nombre de anfitrión («hostname»). Esto podría causar problemas más tarde (no es seguro... podría ir bien).", "yunohost_ca_creation_success": "Creada la autoridad de certificación local.", "app_already_installed_cant_change_url": "Esta aplicación ya está instalada. No se puede cambiar el URL únicamente mediante esta función. Compruebe si está disponible la opción `app changeurl`.", "app_change_no_change_url_script": "La aplicacion {app_name:s} aún no permite cambiar su URL, es posible que deba actualizarla.", "app_change_url_failed_nginx_reload": "No se pudo recargar NGINX. Esta es la salida de «nginx -t»:\n{nginx_errors:s}", "app_change_url_identical_domains": "El antiguo y nuevo dominio/url_path son idénticos ('{domain:s} {path:s}'), no se realizarán cambios.", - "app_change_url_no_script": "Esta aplicación «{app_name:s}» aún no permite la modificación de URLs. Quizás debería actualizarla.", + "app_change_url_no_script": "La aplicación «{app_name:s}» aún no permite la modificación de URLs. Quizás debería actualizarla.", "app_change_url_success": "El URL de la aplicación {app:s} es ahora {domain:s} {path:s}", "app_location_unavailable": "Este URL o no está disponible o está en conflicto con otra(s) aplicación(es) instalada(s):\n{apps:s}", "app_already_up_to_date": "La aplicación {app:s} ya está actualizada", "appslist_name_already_tracked": "Ya existe una lista de aplicaciones registradas con el nombre {name:s}.", "appslist_url_already_tracked": "Ya existe una lista de aplicaciones registradas con el URL {url:s}.", - "appslist_migrating": "Migrando la lista de aplicaciones {appslist:s}…", - "appslist_could_not_migrate": "¡No se pudo migrar la lista de aplicaciones {appslist:s}! No se pudo analizar el URL… El antiguo trabajo de cron se mantuvo en {bkp_file:s}.", + "appslist_migrating": "Migrando la lista de aplicaciones «{appslist:s}»…", + "appslist_could_not_migrate": "¡No se pudo migrar la lista de aplicaciones «{appslist:s}»! No se pudo analizar el URL… El antiguo trabajo de cron se mantuvo en {bkp_file:s}.", "appslist_corrupted_json": "No se pudieron cargar las listas de aplicaciones. Parece que {filename:s} está dañado.", "invalid_url_format": "Algo va mal con el URL", "app_upgrade_some_app_failed": "No se pudieron actualizar algunas aplicaciones", - "app_make_default_location_already_used": "No puede hacer que la aplicación «{app}» sea la predeterminada en el dominio, {domain} ya está siendo usado por otra aplicación «{other_app}»", + "app_make_default_location_already_used": "No puede hacer que la aplicación «{app}» sea la predeterminada en el dominio, «{domain}» ya está siendo usado por otra aplicación «{other_app}»", "app_upgrade_app_name": "Actualizando ahora {app}…", "ask_path": "Camino", "backup_abstract_method": "Este método de respaldo aún no se ha implementado", @@ -301,7 +301,7 @@ "backup_archive_mount_failed": "No se pudo montar el archivo de respaldo", "backup_archive_system_part_not_available": "La parte del sistema «{part:s}» no está disponible en esta copia de seguridad", "backup_archive_writing_error": "No se pudieron añadir los archivos «{source:s}» (llamados en el archivo «{dest:s}») para ser respaldados en el archivo comprimido «{archive:s}»", - "backup_ask_for_copying_if_needed": "No se pudieron preparar algunos archivos para la copia de seguridad usando el método que evita desperdiciar espacio temporalmente en el sistema. Para hacer la copia de seguridad, {size:s}MB se usarán temporalmente. ¿Está de acuerdo?", + "backup_ask_for_copying_if_needed": "¿Quiere realizar la copia de seguridad usando {size:s} MB temporalmente? (Se usa este modo ya que algunos archivos no se pudieron preparar usando un método más eficiente.)", "backup_borg_not_implemented": "El método de respaldo de Borg aún no ha sido implementado", "backup_cant_mount_uncompress_archive": "No se pudo montar el archivo descomprimido como protegido contra escritura", "backup_copying_to_organize_the_archive": "Copiando {size:s}MB para organizar el archivo", @@ -331,22 +331,22 @@ "update_apt_cache_warning": "Algo fue mal durante la actualización de la caché de APT (gestor de paquetes de Debian). Aquí tiene un volcado de las líneas de sources.list que podría ayudarle a identificar las líneas problemáticas:\n{sourceslist}", "update_apt_cache_failed": "No se pudo actualizar la caché de APT (gestor de paquetes de Debian). Aquí tiene un volcado de las líneas de sources.list que podría ayudarle a identificar las líneas problemáticas:\n{sourceslist}", "tools_upgrade_special_packages_completed": "Actualización de paquetes de YunoHost completada.\nPulse [Intro] para regresar a la línea de órdenes", - "tools_upgrade_special_packages_explanation": "Esta acción terminará pero la actualización especial real continuará en segundo plano. No inicie ninguna otra acción en su servidor en aproximadamente 10 minutos (dependiendo de la velocidad de su hardware). Una vez que esté hecho, podría tener que volver a iniciar sesión en la administración web. El registro de actualización estará disponible en Herramientas → Registro (en la página de administración web) o mediante «yunohost log list» (desde la línea de órdenes).", + "tools_upgrade_special_packages_explanation": "Esta acción terminará pero la actualización especial real continuará en segundo plano. No inicie ninguna otra acción en su servidor en aproximadamente 10 minutos (dependiendo de la velocidad de su hardware). Una vez hecho, podría tener que volver a iniciar sesión en la administración web. El registro de actualización estará disponible en Herramientas → Registro (en la página de administración web) o mediante «yunohost log list» (desde la línea de órdenes).", "tools_upgrade_special_packages": "Actualizando ahora paquetes «especiales» (relacionados con YunoHost)…", "tools_upgrade_regular_packages_failed": "No se pudieron actualizar los paquetes: {packages_list}", "tools_upgrade_regular_packages": "Actualizando ahora paquetes «normales» (no relacionados con YunoHost)…", - "tools_upgrade_cant_unhold_critical_packages": "No se pudieron liberar los paquetes críticos…", + "tools_upgrade_cant_unhold_critical_packages": "No se pudo liberar los paquetes críticos…", "tools_upgrade_cant_hold_critical_packages": "No se pudieron retener los paquetes críticos…", "tools_upgrade_cant_both": "No se puede actualizar el sistema y las aplicaciones al mismo tiempo", "tools_upgrade_at_least_one": "Especifique «--apps», o «--system»", "tools_update_failed_to_app_fetchlist": "No se pudo actualizar la lista de aplicaciones de YunoHost porque: {error}", "this_action_broke_dpkg": "Esta acción rompió dpkg/APT(los gestores de paquetes del sistema)… Puede tratar de solucionar este problema conectando mediante SSH y ejecutando `sudo dpkg --configure -a`.", "system_groupname_exists": "El nombre de grupo ya existe en el grupo del sistema", - "service_reloaded_or_restarted": "Recargado o reiniciado el servicio «{service:s}»", + "service_reloaded_or_restarted": "El servicio «{service:s}» ha sido recargado o reiniciado", "service_reload_or_restart_failed": "No se pudo recargar o reiniciar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}", "service_restarted": "Reiniciado el servicio «{service:s}»", "service_restart_failed": "No se pudo reiniciar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}", - "service_reloaded": "Recargado el servicio «{service:s}»", + "service_reloaded": "El servicio «{service:s}» ha sido recargado", "service_reload_failed": "No se pudo recargar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}", "service_regen_conf_is_deprecated": "¡«yunohost service regen-conf» está obsoleto! Use «yunohost tools regen-conf» en su lugar.", "service_description_yunohost-firewall": "Gestiona los puertos de conexiones abiertos y cerrados a los servicios", @@ -360,7 +360,7 @@ "service_description_php7.0-fpm": "Ejecuta aplicaciones escritas en PHP con NGINX", "service_description_nslcd": "Maneja la conexión del intérprete de órdenes («shell») de usuario de YunoHost", "service_description_nginx": "Sirve o proporciona acceso a todos los sitios web alojados en su servidor", - "service_description_mysql": "Almacena los datos de las aplicaciones (base de datos SQL)", + "service_description_mysql": "Almacena los datos de la aplicación (base de datos SQL)", "service_description_metronome": "Gestionar las cuentas XMPP de mensajería instantánea", "service_description_glances": "Supervisa la información del sistema en su servidor", "service_description_fail2ban": "Protege contra ataques de fuerza bruta y otras clases de ataques desde Internet", @@ -417,7 +417,7 @@ "migrations_running_forward": "Ejecutando migración {id}…", "migrations_pending_cant_rerun": "Esas migraciones están aún pendientes, así que no se pueden volver a ejecutar: {ids}", "migrations_not_pending_cant_skip": "Esas migraciones no están pendientes, así que no pueden ser omitidas: {ids}", - "migrations_no_such_migration": "No hay ninguna migración llamada {id}", + "migrations_no_such_migration": "No hay ninguna migración llamada «{id}»", "migrations_no_migrations_to_run": "No hay migraciones que ejecutar", "migrations_need_to_accept_disclaimer": "Para ejecutar la migración {id} debe aceptar el siguiente descargo de responsabilidad:\n---\n{disclaimer}\n---\nSi acepta ejecutar la migración, vuelva a ejecutar la orden con la opción «--accept-disclaimer».", "migrations_must_provide_explicit_targets": "Necesita proporcionar objetivos explícitos al usar «--skip» or «--force-rerun»", @@ -426,30 +426,30 @@ "migrations_list_conflict_pending_done": "No puede usar «--previous» y «--done» al mismo tiempo.", "migrations_exclusive_options": "«--auto», «--skip», and «--force-rerun» son opciones mutuamente excluyentes.", "migrations_failed_to_load_migration": "No se pudo cargar la migración {id}: {error}", - "migrations_dependencies_not_satisfied": "No se puede ejecutar la migración {id} porque primero necesita ejecutar estas migraciones: {dependencies_id}", - "migrations_cant_reach_migration_file": "No se pudo acceder los archivos de migración en la ruta %s", + "migrations_dependencies_not_satisfied": "Ejecutar estas migraciones: «{dependencies_id}» antes de migrar {id}.", + "migrations_cant_reach_migration_file": "No se pudo acceder a los archivos de migración en la ruta «%s»", "migrations_already_ran": "Esas migraciones ya se han realizado: {ids}", "migration_0011_update_LDAP_schema": "Actualizando el esquema de LDAP…", "migration_0011_update_LDAP_database": "Actualizando la base de datos de LDAP…", "migration_0011_rollback_success": "Sistema revertido.", - "migration_0011_migration_failed_trying_to_rollback": "Migración fallida… intentando revertir el sistema.", + "migration_0011_migration_failed_trying_to_rollback": "No se pudo migrar… intentando revertir el sistema.", "migration_0011_migrate_permission": "Migrando permisos desde la configuración de las aplicaciones a LDAP…", "migration_0011_LDAP_update_failed": "No se pudo actualizar LDAP. Error: {error:s}", "migration_0011_LDAP_config_dirty": "Parece que ha personalizado la configuración de LDAP. Para esta migración se necesita actualizar la configuración de LDAP.\nNecesita guardar su configuración actual, reiniciar la configuración original ejecutando «yunohost tools regen-conf -f» y reintentar la migración", - "migration_0011_done": "Migración correcta. Ahora puede gestionar los grupos de usuarios.", + "migration_0011_done": "Migración finalizada. Ahora puede gestionar los grupos de usuarios.", "migration_0011_create_group": "Creando un grupo para cada usuario…", - "migration_0011_can_not_backup_before_migration": "Falló el respaldo del sistema antes de la migración. Fallo de migración. Error: {error:s}", + "migration_0011_can_not_backup_before_migration": "El respaldo del sistema no se pudo completar antes de que la migración fallase. Error: {error:s}", "migration_0011_backup_before_migration": "Creando un respaldo de la base de datos de LDAP y de la configuración de las aplicaciones antes de la migración real.", "migration_0009_not_needed": "La migración ya ocurrió de algún modo… (?) Omitiendo.", - "migration_0008_no_warning": "No se ha detectado ningún riesgo importante con respecto a la anulación de su configuración SSH ¡sin embargo uno nunca puede estar absolutamente seguro ;)! Ejecute la migración para anularla. Por otra parte, puede omitir la migración aunque no esté recomendado.", - "migration_0008_warning": "Si entiende esos avisos y permite a YunoHost anular su configuración actual, ejecute la migración. Por otra parte puede omitir la migración, aunque no se recomienda.", + "migration_0008_no_warning": "Ignorar su configuración SSH debería ser seguro ¡aunque esto no se puede prometer! Ejecute la migración para ignorarla. Por otra parte puede omitir la migración, aunque no se recomienda.", + "migration_0008_warning": "Si entiende esos avisos y quiere que YunoHost ignore su configuración actual, ejecute la migración. Por otra parte puede omitir la migración, aunque no se recomienda.", "migration_0008_dsa": "• Se desactivará la clave DSA. Así que podría tener que anular un aviso espeluznante de su cliente SSH y volver a comprobar la huella de su servidor;", "migration_0008_root": "• No podrá conectarse como «root» a través de SSH. En su lugar debe usar el usuario «admin»;", "migration_0008_port": "• Tendrá que conectarse usando el puerto 22 en vez de su actual puerto SSH personalizado. No dude en reconfigurarlo;", "migration_0008_general_disclaimer": "Para mejorar la seguridad de su servidor, es recomendable permitir a YunoHost gestionar la configuración de SSH. Su actual configuración de SSH difiere de la recomendación. Si permite a YunoHost reconfigurarla, la manera en la que conecta con su servidor a través de SSH cambiará así:", "migration_0007_cannot_restart": "No se puede reiniciar SSH después de intentar cancelar la migración número 6.", - "migration_0007_cancelled": "YunoHost no ha podido mejorar el modo en el que se gestiona su configuración de SSH.", - "migration_0006_disclaimer": "YunoHost espera ahora que las contraseñas de «admin» y «root» estén sincronizadas. Al ejecutar esta migración, su contraseña de «root» será reemplazada por la contraseña de administración.", + "migration_0007_cancelled": "No se pudo mejorar el modo en el que se gestiona su configuración de SSH.", + "migration_0006_disclaimer": "YunoHost espera ahora que las contraseñas de «admin» y «root» estén sincronizadas. Esta migración reemplaza su contraseña de «root» por la contraseña de «admin».", "migration_0005_not_enough_space": "Tenga suficiente espacio libre disponible en {path} para ejecutar la migración.", "migration_0005_postgresql_96_not_installed": "⸘PostgreSQL 9.4 está instalado pero no PostgreSQL 9.6‽ Algo raro podría haber ocurrido en su sistema:(…", "migration_0005_postgresql_94_not_installed": "PostgreSQL no estaba instalado en su sistema. Nada que hacer.", @@ -502,12 +502,12 @@ "log_user_delete": "Eliminar usuario «{}»", "log_user_create": "Añadir usuario «{}»", "log_regen_conf": "Regenerar la configuración del sistema «{}»", - "log_letsencrypt_cert_renew": "Renovar el certificado «{}» de Let's encrypt", + "log_letsencrypt_cert_renew": "Renovar el certificado «{}» de Let's Encrypt", "log_selfsigned_cert_install": "Instalar certificado autofirmado en el dominio «{}»", "log_permission_update": "Actualizar permiso «{}» para la aplicación «{}»", "log_permission_remove": "Eliminar permiso «{}»", "log_permission_add": "Añadir el permiso «{}» para la aplicación «{}»", - "log_letsencrypt_cert_install": "Instalar un certificado de Let's encrypt en el dominio «{}»", + "log_letsencrypt_cert_install": "Instalar un certificado de Let's Encrypt en el dominio «{}»", "log_dyndns_update": "Actualizar la IP asociada con su subdominio de YunoHost «{}»", "log_dyndns_subscribe": "Subscribirse a un subdomino de YunoHost «{}»", "log_domain_remove": "Eliminar el dominio «{}» de la configuración del sistema", @@ -577,12 +577,12 @@ "domain_dns_conf_is_just_a_recommendation": "Esta orden muestra la configuración *recomendada*. No configura el DNS en realidad. Es su responsabilidad configurar la zona de DNS en su registrador según esta recomendación.", "dpkg_lock_not_available": "Esta orden no se puede ejecutar en este momento porque otro programa parece que 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 en un estado roto... Puede tratar de solucionar este problema conectando a través de SSH y ejecutando `sudo dpkg --configure -a`.", - "confirm_app_install_thirdparty": "¡PELIGRO! Esta aplicación no forma parte del catálogo de aplicaciones de YunoHost. Instalar aplicaciones de terceros podría comprometer la integridad y seguridad de su sistema. Probablemente NO debería instalarla salvo que sepa lo que está haciendo. No tendrá NINGUNA AYUDA si esta aplicación no funciona o rompe su sistema... Si está dispuesto a aceptar ese riesgo de todas formas, escriba «{answers:s}»", - "confirm_app_install_danger": "¡PELIGRO! ¡Esta aplicación es conocida por ser aún experimental (o no funciona explícitamente)! Probablemente NO debería instalarla salvo que sepa lo que está haciendo. No tendrá NINGUNA AYUDA si esta aplicación no funciona o rompe su sistema... Si está dispuesto a aceptar ese riesgo de todas formas, escriba «{answers:s}»", + "confirm_app_install_thirdparty": "¡PELIGRO! Esta aplicación no forma parte del catálogo de aplicaciones de YunoHost. Instalar aplicaciones de terceros podría comprometer la integridad y seguridad de su sistema. Probablemente NO debería instalarla salvo que sepa lo que está haciendo. No tendrá NINGUNA AYUDA si esta aplicación no funciona o rompe su sistema… Si está dispuesto a aceptar ese riesgo de todas formas, escriba «{answers:s}»", + "confirm_app_install_danger": "¡PELIGRO! ¡Esta aplicación es conocida por ser aún experimental (o no funciona explícitamente)! Probablemente NO debería instalarla salvo que sepa lo que está haciendo. No tendrá NINGUNA AYUDA si esta aplicación no funciona o rompe su sistema… Si está dispuesto a aceptar ese riesgo de todas formas, escriba «{answers:s}»", "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:s}] ", "backup_unable_to_organize_files": "No se pudo usar el método rápido de organización de los archivos en el archivo", "backup_permission": "Permiso de respaldo para la aplicación {app:s}", - "backup_output_symlink_dir_broken": "Tiene un enlace simbólico roto en vez del directorio «{path:s}» de su archivo. Puede que tenga una configuración específica para respaldar sus datos en otro sistema de archivos, en este caso probablemente olvidó remontar o conectar su disco duro o clave USB.", + "backup_output_symlink_dir_broken": "El directorio de su archivo «{path:s}» es un enlace simbólico roto. Tal vez olvidó (re)montarlo o conectarlo al medio de almacenamiento al que apunta.", "backup_mount_archive_for_restore": "Preparando el archivo para la restauración…", "backup_method_tar_finished": "Creado el archivo TAR de respaldo", "backup_method_custom_finished": "Terminado el método «{method:s}» de respaldo personalizado", @@ -595,16 +595,16 @@ "apps_permission_restoration_failed": "Otorgar el permiso «{permission:s}» para restaurar {app:s}", "apps_permission_not_found": "No se han encontrado permisos para las aplicaciones instaladas", "app_upgrade_several_apps": "Las siguientes aplicaciones se actualizarán: {apps}", - "app_start_restore": "Restaurando aplicación {app}…", - "app_start_backup": "Obteniendo archivos para el respaldo de {app}…", - "app_start_remove": "Eliminando aplicación {app}…", - "app_start_install": "Instalando aplicación {app}…", + "app_start_restore": "Restaurando aplicación «{app}»…", + "app_start_backup": "Obteniendo archivos para el respaldo de «{app}»…", + "app_start_remove": "Eliminando aplicación «{app}»…", + "app_start_install": "Instalando aplicación «{app}»…", "app_not_upgraded": "Error al actualizar la aplicación «{failed_app}» y como consecuencia se han cancelado las actualizaciones de las siguientes aplicaciones: {apps}", - "app_action_cannot_be_ran_because_required_services_down": "Esta aplicación necesita algunos servicios que no están funcionando ahora. Antes de continuar, debería intentar reiniciar los siguientes servicios (y posiblemente investigar por qué no funcionan): {services}", + "app_action_cannot_be_ran_because_required_services_down": "Estos servicios necesarios deberían estar funcionando para ejecutar esta acción: {services}. Pruebe a reiniciarlos para continuar (y posiblemente investigar por qué están caídos).", "already_up_to_date": "Nada que hacer. Todo está actualizado.", "admin_password_too_long": "Elija una contraseña de menos de 127 caracteres", "aborting": "Cancelando.", - "app_upgrade_stopped": "Se ha detenido la actualización de todas las aplicaciones para prevenir un posible daño porque la aplicación anterior no se pudo actualizar", + "app_upgrade_stopped": "Se ha detenido la actualización de todas las aplicaciones para prevenir un posible daño porque una aplicación no se pudo actualizar", "app_action_broke_system": "Esta acción parece que ha roto estos importantes servicios: {services}", "operation_interrupted": "¿Ha sido interrumpida la operación manualmente?", "apps_already_up_to_date": "Todas las aplicaciones están ya actualizadas", @@ -625,8 +625,8 @@ "permission_already_allowed": "El grupo «{group}» ya tiene el permiso «{permission}» activado", "permission_already_disallowed": "El grupo «{group}» ya tiene el permiso «{permission}» desactivado", "permission_cannot_remove_main": "No está permitido eliminar un permiso principal", - "user_already_exists": "El usuario {user} ya existe", - "app_full_domain_unavailable": "Lamentablemente esta aplicación necesita un dominio completo para ser instalada pero ya hay otras aplicaciones instaladas en el dominio «{domain}». Una solución posible es añadir y usar un subdominio dedicado a esta aplicación.", + "user_already_exists": "El usuario «{user}» ya existe", + "app_full_domain_unavailable": "Lamentablemente esta aplicación tiene que instalarse en un dominio propio pero ya hay otras aplicaciones instaladas en el dominio «{domain}». Podría usar un subdomino dedicado a esta aplicación en su lugar.", "app_install_failed": "No se pudo instalar {app}: {error}", "app_install_script_failed": "Ha ocurrido un error en el guión de instalación de la aplicación", "group_cannot_edit_all_users": "El grupo «all_users» no se puede editar manualmente. Es un grupo especial destinado a contener todos los usuarios registrados en YunoHost", From 345747d2af3fd54599e6592b2a27820bfa3b3526 Mon Sep 17 00:00:00 2001 From: amirale qt Date: Thu, 24 Oct 2019 12:27:11 +0000 Subject: [PATCH 105/127] Translated using Weblate (Esperanto) Currently translated at 86.6% (485 of 560 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eo/ --- locales/eo.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/eo.json b/locales/eo.json index 3931c27d0..c78bf6269 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -56,7 +56,7 @@ "backup_actually_backuping": "Krei rezervan ar archiveivon el la kolektitaj dosieroj …", "backup_method_borg_finished": "Sekurkopio en Borg finiĝis", "appslist_removed": "{appslist:s} aplika listo forigita", - "app_change_url_no_script": "Ĉi tiu apliko '{app_name:s}' ankoraŭ ne subtenas URL-modifon. Eble vi devus altgradigi ĝin.", + "app_change_url_no_script": "La app '{app_name:s}' ankoraŭ ne subtenas URL-modifon. Eble vi devus altgradigi ĝin.", "app_start_install": "Instalanta aplikon {app} …", "backup_created": "Sekurkopio kreita", "app_make_default_location_already_used": "Ne povas igi la aplikon '{app}' defaŭlta sur la domajno, {domain} jam uziĝas de la alia app '{other_app}'", @@ -83,7 +83,7 @@ "backup_cant_mount_uncompress_archive": "Ne povis munti la nekompresitan ar archiveivon kiel protektita kontraŭ skribo", "appslist_retrieve_bad_format": "Ne povis legi la elprenitan liston {appslist:s}", "appslist_corrupted_json": "Ne povis ŝarĝi la aplikajn listojn. Ĝi aspektas kiel {filename:s} estas damaĝita.", - "app_action_cannot_be_ran_because_required_services_down": "Ĉi tiu app postulas iujn servojn, kiuj nuntempe malleviĝas. Antaŭ ol daŭrigi, vi provu rekomenci la jenajn servojn (kaj eventuale esploru kial ili malsukcesas): {services}", + "app_action_cannot_be_ran_because_required_services_down": "Ĉi tiuj postulataj servoj devas funkcii por funkciigi ĉi tiun agon: {services}. Provu rekomenci ilin por daŭrigi (kaj eble esploru, kial ili malsupreniras).", "backup_copying_to_organize_the_archive": "Kopiante {size:s} MB por organizi la ar archiveivon", "backup_output_directory_forbidden": "Elektu malsaman elirejan dosierujon. Sekurkopioj ne povas esti kreitaj en sub-dosierujoj / bin, / boot, / dev, / ktp, / lib, / root, / run, / sbin, / sys, / usr, / var aŭ /home/yunohost.backup/archives", "appslist_could_not_migrate": "Ne povis migri la liston de aplikoj {appslist:s}! Ne eblis analizi la URL ... La malnova cron-laboro konserviĝis en {bkp_file:s}.", From 258209bcd08406fcf55d0d8361e2d2cd6db0691e Mon Sep 17 00:00:00 2001 From: amirale qt Date: Thu, 24 Oct 2019 06:33:17 +0000 Subject: [PATCH 106/127] Translated using Weblate (French) Currently translated at 100.0% (560 of 560 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 82 ++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index 90eed4bee..37e5f95c1 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -30,10 +30,10 @@ "app_unsupported_remote_type": "Ce type de commande à distance utilisé pour cette application n'est pas supporté", "app_upgrade_failed": "Impossible de mettre à jour {app:s}", "app_upgraded": "{app:s} mis à jour", - "appslist_fetched": "La liste d’applications mise à jour {appslist:s}", - "appslist_removed": "La liste d’applications {appslist:s} a été supprimée", - "appslist_retrieve_error": "Impossible de récupérer la liste d’applications distante {appslist:s} : {error:s}", - "appslist_unknown": "La liste d’applications {appslist:s} est inconnue.", + "appslist_fetched": "La liste d’applications mise à jour '{appslist:s}'", + "appslist_removed": "La liste d'applications '{appslist:s}' a été supprimée", + "appslist_retrieve_error": "Impossible de récupérer la liste d’applications distante '{appslist:s}' : {error:s}", + "appslist_unknown": "La liste d’applications '{appslist:s}' est inconnue.", "ask_current_admin_password": "Mot de passe d’administration actuel", "ask_email": "Adresse de courriel", "ask_firstname": "Prénom", @@ -124,18 +124,18 @@ "mail_forward_remove_failed": "Impossible de supprimer le courriel de transfert '{mail:s}'", "maindomain_change_failed": "Impossible de modifier le domaine principal", "maindomain_changed": "Le domaine principal modifié", - "monitor_disabled": "La supervision du serveur a été désactivé", - "monitor_enabled": "La supervision du serveur a été activé", + "monitor_disabled": "Surveillance du serveur est maintenant arrêté", + "monitor_enabled": "La supervision du serveur est maintenant allumée", "monitor_glances_con_failed": "Impossible de se connecter au serveur Glances", "monitor_not_enabled": "Le suivi de l’état du serveur n’est pas activé", "monitor_period_invalid": "Période de temps incorrecte", - "monitor_stats_file_not_found": "Le fichier de statistiques est introuvable", + "monitor_stats_file_not_found": "Impossible de trouver le fichier de statistiques", "monitor_stats_no_update": "Aucune donnée de l’état du serveur à mettre à jour", "monitor_stats_period_unavailable": "Aucune statistique n’est disponible pour la période", "mountpoint_unknown": "Point de montage inconnu", "mysql_db_creation_failed": "Impossible de créer la base de données MySQL", - "mysql_db_init_failed": "Impossible d’initialiser la base de données MySQL", - "mysql_db_initialized": "La base de données MySQL a été initialisée", + "mysql_db_init_failed": "Impossible d'initialiser la base de données MySQL", + "mysql_db_initialized": "La base de données MySQL est maintenant initialisée", "network_check_mx_ko": "L’enregistrement DNS MX n’est pas défini", "network_check_smtp_ko": "Le trafic courriel sortant (port 25 SMTP) semble bloqué par votre réseau", "network_check_smtp_ok": "Le trafic courriel sortant (port 25 SMTP) n’est pas bloqué", @@ -155,7 +155,7 @@ "path_removal_failed": "Impossible de supprimer le chemin {:s}", "pattern_backup_archive_name": "Doit être un nom de fichier valide avec un maximum de 30 caractères, et composé de caractères alphanumériques et -_. uniquement", "pattern_domain": "Doit être un nom de domaine valide (ex : mon-domaine.fr)", - "pattern_email": "Doit être une adresse de courriel valide (ex. : pseudo@domaine.fr)", + "pattern_email": "Doit être une adresse de courriel valide (ex. : pseudo@example.com)", "pattern_firstname": "Doit être un prénom valide", "pattern_lastname": "Doit être un nom valide", "pattern_listname": "Doit être composé uniquement de caractères alphanumériques et de tirets bas (aussi appelé tiret du 8 ou underscore)", @@ -183,7 +183,7 @@ "service_add_configuration": "Ajout du fichier de configuration {file:s}", "service_add_failed": "Impossible d’ajouter le service '{service:s}'", "service_added": "Le service '{service:s}' ajouté", - "service_already_started": "Le service '{service:s}' est déjà démarré", + "service_already_started": "Le service '{service:s}' est déjà en cours d'exécution", "service_already_stopped": "Le service '{service:s}' est déjà arrêté", "service_cmd_exec_failed": "Impossible d’exécuter la commande '{command:s}'", "service_conf_file_backed_up": "Le fichier de configuration '{conf}' a été sauvegardé dans '{backup}'", @@ -204,7 +204,7 @@ "service_disabled": "Le service '{service:s}' a été désactivé", "service_enable_failed": "Impossible d’activer le service '{service:s}'\n\nJournaux historisés récents : {logs:s}", "service_enabled": "Le service '{service:s}' a été activé", - "service_no_log": "Aucun journal historisé à afficher pour le service '{service:s}'", + "service_no_log": "Aucun journal à afficher pour le service '{service:s}'", "service_regenconf_dry_pending_applying": "Vérification des configurations en attentes qui pourraient être appliquées au le service '{service}' …", "service_regenconf_failed": "Impossible de régénérer la configuration pour les services : {services}", "service_regenconf_pending_applying": "Application des configurations en attentes pour le service '{service}' …", @@ -246,9 +246,9 @@ "user_updated": "L’utilisateur a été modifié", "yunohost_already_installed": "YunoHost est déjà installé", "yunohost_ca_creation_failed": "Impossible de créer l’autorité de certification", - "yunohost_configured": "YunoHost maintenant configuré", + "yunohost_configured": "YunoHost est maintenant configuré", "yunohost_installing": "L'installation de YunoHost est en cours …", - "yunohost_not_installed": "YunoHost n’est pas ou pas correctement installé. Veuillez exécuter 'yunohost tools postinstall'", + "yunohost_not_installed": "YunoHost n'est pas correctement installé. S'il vous plaît exécuter 'yunohost tools postinstall'", "certmanager_attempt_to_replace_valid_cert": "Vous êtes en train de vouloir remplacer un certificat correct et valide pour le domaine {domain:s} ! (Utilisez --force pour contourner cela)", "certmanager_domain_unknown": "Domaine {domain:s} inconnu", "certmanager_domain_cert_not_selfsigned": "Le certificat du domaine {domain:s} n’est pas auto-signé. Voulez-vous vraiment le remplacer ? (Utilisez --force pour cela)", @@ -280,13 +280,13 @@ "certmanager_domain_not_resolved_locally": "Le domaine {domain:s} ne peut être résolu depuis votre serveur YunoHost. Cela peut se produire si vous avez récemment modifié votre enregistrement DNS. Si c'est le cas, merci d’attendre quelques heures qu’il se propage. Si le problème persiste, envisager d’ajouter {domain:s} au fichier /etc/hosts. (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces vérifications.)", "certmanager_http_check_timeout": "Expiration du délai lorsque le serveur a essayé de se contacter lui-même via HTTP en utilisant l'adresse IP public {ip:s} du domaine {domain:s}. Vous rencontrez peut-être un problème d’hairpinning ou alors le pare-feu/routeur en amont de votre serveur est mal configuré.", "certmanager_couldnt_fetch_intermediate_cert": "Expiration du délai lors de la tentative de récupération du certificat intermédiaire depuis Let’s Encrypt. L’installation ou le renouvellement du certificat a été annulé. Veuillez réessayer plus tard.", - "appslist_retrieve_bad_format": "Impossible de lire la liste des applications extraites {appslist: s}", + "appslist_retrieve_bad_format": "Impossible de lire la liste des applications extraites '{appslist: s}'", "domain_hostname_failed": "Échec de l’utilisation d’un nouveau nom d’hôte. Cela pourrait causer des soucis plus tard (peut-être que ça n’en causera pas).", "yunohost_ca_creation_success": "L’autorité de certification locale créée.", - "appslist_name_already_tracked": "Il y a déjà une liste d’applications enregistrée avec le nom {name:s} existe déjà.", + "appslist_name_already_tracked": "Une liste d'applications enregistrées portant le nom {name:s} existe déjà.", "appslist_url_already_tracked": "Il y a déjà une liste d’applications enregistrée avec l’URL {url:s}.", - "appslist_migrating": "Migration de la liste d’applications {appslist:s} …", - "appslist_could_not_migrate": "Impossible de migrer la liste {appslist:s} ! Impossible d’exploiter l’URL. L’ancienne tâche programmée a été conservée dans {bkp_file:s}.", + "appslist_migrating": "Migration de la liste d’applications '{appslist:s}' …", + "appslist_could_not_migrate": "Impossible de migrer la liste '{appslist:s}' ! Impossible d’exploiter l’URL. L’ancienne tâche programmée a été conservée dans {bkp_file:s}.", "appslist_corrupted_json": "Impossible de charger la liste d’applications. Il semble que {filename:s} soit endommager.", "app_already_installed_cant_change_url": "Cette application est déjà installée. L’URL ne peut pas être changé simplement par cette fonction. Regardez si cela est disponible avec `app changeurl`.", "app_change_no_change_url_script": "L’application {app_name:s} ne prend pas encore en charge le changement d’URL, vous pourriez avoir besoin de la mettre à jour.", @@ -320,7 +320,7 @@ "backup_archive_system_part_not_available": "La partie '{part:s}' du système n’est pas disponible dans cette sauvegarde", "backup_archive_mount_failed": "Le montage de l’archive de sauvegarde a échoué", "backup_archive_writing_error": "Impossible d'ajouter des fichiers '{source:s}' (nommés dans l'archive : '{dest:s}') à sauvegarder dans l'archive compressée '{archive:s}'", - "backup_ask_for_copying_if_needed": "Certains fichiers n’ont pas pu être préparés pour être sauvegardés en utilisant la méthode qui évite temporairement de gaspiller de l’espace sur le système. Pour réaliser la sauvegarde, {size:s} Mo doivent être temporairement utilisés. Acceptez-vous ?", + "backup_ask_for_copying_if_needed": "Voulez-vous effectuer la sauvegarde en utilisant {taille:s} temporairement? (Cette méthode est utilisée car certains fichiers n'ont pas pu être préparés avec une méthode plus efficace.)", "backup_borg_not_implemented": "La méthode de sauvegarde Borg n’est pas encore implémentée", "backup_cant_mount_uncompress_archive": "Impossible de monter en lecture seule le dossier de l’archive décompressée", "backup_copying_to_organize_the_archive": "Copie de {size:s} Mo pour organiser l’archive", @@ -350,7 +350,7 @@ "domain_dyndns_dynette_is_unreachable": "Impossible de contacter la dynette YunoHost. Soit YunoHost n’est pas correctement connecté à internet, soit le serveur de dynette est en panne. Erreur : {error}", "migrations_backward": "Migration en arrière.", "migrations_bad_value_for_target": "Nombre invalide pour le paramètre target, les numéros de migration sont 0 ou {}", - "migrations_cant_reach_migration_file": "Impossible d'accéder aux fichiers de migration sur le chemin% s", + "migrations_cant_reach_migration_file": "Impossible d'accéder aux fichiers de migration via le chemin '%s'", "migrations_current_target": "La cible de migration est {}", "migrations_error_failed_to_load_migration": "ERREUR : échec du chargement de migration {number} {name}", "migrations_forward": "Migration en avant", @@ -368,9 +368,9 @@ "ask_path": "Chemin", "dyndns_could_not_check_provide": "Impossible de vérifier si {provider:s} peut fournir {domain:s}.", "dyndns_domain_not_provided": "Le fournisseur DynDNS {provider:s} ne peut pas fournir le domaine {domain:s}.", - "app_make_default_location_already_used": "Impossible de configurer l’application '{app}' par défaut pour le domaine {domain} car il est déjà utilisé par l'application '{other_app}'", + "app_make_default_location_already_used": "Impossible de configurer l’application '{app}' par défaut pour le domaine '{domain}' car il est déjà utilisé par l'application '{other_app}'", "app_upgrade_app_name": "Mise à jour de l’application {app} …", - "backup_output_symlink_dir_broken": "Vous avez un lien symbolique cassé à la place de votre dossier d’archives « {path:s} ». Vous pourriez avoir une configuration personnalisée pour sauvegarder vos données sur un autre système de fichiers, dans ce cas vous avez probablement oublié de monter ou de connecter votre disque dur ou votre clé USB.", + "backup_output_symlink_dir_broken": "Votre répertoire d'archivage '{chemin:s}' est un lien symbolique brisé. Peut-être avez-vous oublié de re/monter ou de brancher le support de stockage sur lequel il pointe.", "migrate_tsig_end": "La migration à HMAC-SHA-512 est terminée", "migrate_tsig_failed": "La migration du domaine DynDNS {domain} à hmac-sha512 a échoué. Annulation des modifications. Erreur : {error_code} - {error}", "migrate_tsig_start": "L’algorithme de génération des clefs n’est pas suffisamment sécurisé pour la signature TSIG du domaine '{domain}', lancement de la migration vers HMAC-SHA-512 qui est plus sécurisé", @@ -473,7 +473,7 @@ "good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. 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 différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).", "good_practices_about_user_password": "Vous êtes maintenant 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 d’utiliser différents types de caractères tels que : majuscules, minuscules, chiffres et caractères spéciaux.", "migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root", - "migration_0006_disclaimer": "YunoHost s’attendra désormais à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.", + "migration_0006_disclaimer": "YunoHost s'attend maintenant à ce que les mots de passe administrateur et racine soient synchronisés. Cette migration remplace votre mot de passe root par le mot de passe administrateur.", "migration_0006_done": "Votre mot de passe root a été remplacé par celui de votre adminitrateur.", "password_listed": "Ce mot de passe est l'un des mots de passe les plus utilisés dans le monde. Veuillez choisir quelque chose d'un peu plus singulier.", "password_too_simple_1": "Le mot de passe doit comporter au moins 8 caractères", @@ -485,7 +485,7 @@ "app_not_upgraded": "L’application {failed_app} n’a pas été mise à jour et par conséquence les applications suivantes n’ont pas été mises à jour : {apps}", "app_start_install": "Installation de l'application {app} …", "app_start_remove": "Suppression de l'application {app} …", - "app_start_backup": "Collecte des fichiers devant être sauvegardés pour {app} …", + "app_start_backup": "Collecte des fichiers devant être sauvegardés pour l'application {app} …", "app_start_restore": "Restauration de l'application {app} …", "app_upgrade_several_apps": "Les applications suivantes seront mises à jour : {apps}", "ask_new_domain": "Nouveau domaine", @@ -504,14 +504,14 @@ "hook_json_return_error": "Échec de la lecture au retour du script {path:s}. Erreur : {msg:s}. Contenu brut : {raw_content}", "migration_description_0007_ssh_conf_managed_by_yunohost_step1": "La configuration SSH sera gérée par YunoHost (étape 1, automatique)", "migration_description_0008_ssh_conf_managed_by_yunohost_step2": "La configuration SSH sera gérée par YunoHost (étape 2, manuelle)", - "migration_0007_cancelled": "YunoHost n'a pas réussi à améliorer la façon dont est gérée votre configuration SSH.", + "migration_0007_cancelled": "Impossible d'améliorer la gestion de votre configuration SSH.", "migration_0007_cannot_restart": "SSH ne peut pas être redémarré après avoir essayé d'annuler la migration numéro 6.", "migration_0008_general_disclaimer": "Pour améliorer la sécurité de votre serveur, il est recommandé de laisser YunoHost gérer la configuration SSH. Votre configuration SSH actuelle diffère de la configuration recommandée. Si vous laissez YunoHost la reconfigurer, la façon dont vous vous connectez à votre serveur via SSH changera comme suit :", "migration_0008_port": "- Vous devrez vous connecter en utilisant le port 22 au lieu de votre actuel port SSH personnalisé. N'hésitez pas à le reconfigurer ;", "migration_0008_root": "- Vous ne pourrez pas vous connecter en tant que root via SSH. Au lieu de cela, vous devrez utiliser l'utilisateur admin ;", "migration_0008_dsa": "- La clé DSA sera désactivée. Par conséquent, il se peut que vous ayez besoin d'invalider un avertissement effrayant de votre client SSH afin de revérifier l'empreinte de votre serveur ;", - "migration_0008_warning": "Si vous comprenez ces avertissements et que vous acceptez de laisser YunoHost remplacer votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également passer la migration, bien que cela ne soit pas recommandé.", - "migration_0008_no_warning": "Aucun risque majeur n'a été identifié concernant l'écrasement de votre configuration SSH - mais nous ne pouvons pas en être absolument sûrs ;) ! Si vous acceptez de laisser YunoHost remplacer votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également passer la migration, bien que cela ne soit pas recommandé.", + "migration_0008_warning": "Si vous comprenez ces avertissements et souhaitez que YunoHost écrase votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.", + "migration_0008_no_warning": "Remplacer votre configuration SSH devrait être sûr, bien que cela ne puisse être promis! Exécutez la migration pour la remplacer. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.", "migrations_success": "Migration {number} {name} réussie !", "pattern_password_app": "Désolé, les mots de passe ne doivent pas contenir les caractères suivants : {forbidden_chars}", "root_password_replaced_by_admin_password": "Votre mot de passe root a été remplacé par votre mot de passe administrateur.", @@ -523,7 +523,7 @@ "service_reload_or_restart_failed": "Impossible de recharger ou de redémarrer le service '{service:s}'\n\nJournaux historisés récents de ce service : {logs:s}", "service_reloaded_or_restarted": "Le service '{service:s}' a été rechargé ou redémarré", "this_action_broke_dpkg": "Cette action a laissé des paquets non configurés par dpkg/apt (les gestionnaires de paquets système). Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a`.", - "app_action_cannot_be_ran_because_required_services_down": "Cette application requiert certains services qui sont actuellement arrêtés. Avant de continuer, vous devriez essayer de redémarrer les services suivants (et éventuellement rechercher pourquoi ils sont arrêtés) : {services}", + "app_action_cannot_be_ran_because_required_services_down": "Ces services requis doivent être en cours d'exécution pour exécuter cette action: {services}. Essayez de les redémarrer pour continuer (et éventuellement rechercher pourquoi ils sont en panne).", "admin_password_too_long": "Veuillez choisir un mot de passe de moins de 127 caractères", "log_regen_conf": "Régénérer les configurations du système '{}'", "migration_0009_not_needed": "Cette migration semble avoir déjà été jouée ? On l'ignore.", @@ -558,8 +558,8 @@ "tools_upgrade_special_packages_completed": "La mise à jour des paquets de YunoHost est finie!\nPressez [Entrée] pour revenir à la ligne de commande", "updating_app_lists": "Récupération des mises à jour des applications disponibles…", "dpkg_lock_not_available": "Cette commande ne peut être exécutée actuellement car un autre programme semble utiliser le verrou de dpkg (gestionnaire de paquets)", - "tools_upgrade_cant_unhold_critical_packages": "Impossible de dé-marquer les paquets critiques …", - "tools_upgrade_special_packages_explanation": "Cette opération prendra fin mais la mise à jour spécifique continuera en arrière-plan. Veuillez ne pas lancer d'autre action sur votre serveur dans les 10 prochaines minutes (en fonction de la vitesse de votre matériel). Une fois que c'est fait, vous devrez peut-être vous reconnecter sur le panel d'administration web. Le journal de la mise à jour sera disponible dans Outils > Log (dans le panel d'administration web) ou dans la liste des journaux YunoHost (en ligne de commande).", + "tools_upgrade_cant_unhold_critical_packages": "Impossible de conserver les paquets critiques…", + "tools_upgrade_special_packages_explanation": "Cette action se terminera, mais la mise à niveau spéciale réelle continuera en arrière-plan. Veuillez ne pas lancer d’autres actions sur votre serveur au cours des 10 prochaines minutes (en fonction de la vitesse du matériel). Une fois cela fait, vous devrez peut-être vous reconnecter à la page Webadmin. Le journal de mise à niveau sera disponible dans Outils → Journal (sur la page Webadmin) ou dans la \"liste des journaux yunohost\" (à partir de la ligne de commande).", "update_apt_cache_failed": "Impossible de mettre à jour le cache APT (gestionnaire de paquets Debian). Voici un extrait du fichier sources.list qui pourrait vous aider à identifier les lignes problématiques :\n{sourceslist}", "update_apt_cache_warning": "Des erreurs se sont produites lors de la mise à jour du cache APT (gestionnaire de paquets Debian). Voici un extrait des lignes du fichier sources.list qui pourrait vous aider à identifier les lignes problématiques :\n{sourceslist}", "apps_permission_not_found": "Aucune permission trouvée pour les applications installées", @@ -591,22 +591,22 @@ "mailbox_disabled": "La boîte aux lettres est désactivée pour l'utilisateur {user:s}", "app_action_broke_system": "Cette action semble avoir cassé des services important : {services}", "apps_already_up_to_date": "Toutes les applications sont déjà à jour", - "app_upgrade_stopped": "La mise à jour de toutes les applications a été arrêtée afin d’éviter d’éventuels dommages dus à l’échec de la mise à jour de l’application précédente", + "app_upgrade_stopped": "La mise à niveau de toutes les applications s'est arrêtée pour éviter tout dommage, car une application n'a pas pu être mise à niveau.", "migration_0011_create_group": "Créer un groupe pour chaque utilisateur…", - "migration_0011_done": "Migration réussie. Vous êtes maintenant en mesure de gérer des groupes d'utilisateurs.", + "migration_0011_done": "Migration terminée. Vous êtes maintenant en mesure de gérer des groupes d'utilisateurs.", "migrations_must_provide_explicit_targets": "Vous devez fournir des cibles explicites lorsque vous utilisez '--skip' ou '--force-rerun'", - "migrations_no_such_migration": "Il n'y a pas de migration appelée {id}", + "migrations_no_such_migration": "Il n'y a pas de migration appelée '{id}'", "migrations_pending_cant_rerun": "Ces migrations étant toujours en attente, vous ne pouvez pas les exécuter à nouveau: {ids}", "migration_description_0012_postgresql_password_to_md5_authentication": "Forcer l'authentification PostgreSQL à utiliser MD5 pour les connexions locales", "migrations_exclusive_options": "'auto', '--skip' et '--force-rerun' sont des options mutuellement exclusives.", "migrations_not_pending_cant_skip": "Ces migrations ne sont pas en attente et ne peuvent donc pas être ignorées: {ids}", - "migration_0011_can_not_backup_before_migration": "La sauvegarde du système avant la migration a échoué. La migration a échoué. Erreur: {error: s}", + "migration_0011_can_not_backup_before_migration": "La sauvegarde du système n'a pas pu être terminée avant l'échec de la migration. Erreur: {erreur:s}", "migration_0011_migrate_permission": "Migration des autorisations des paramètres des applications vers LDAP…", - "migration_0011_migration_failed_trying_to_rollback": "La migration a échoué… essayait de restauration du système.", + "migration_0011_migration_failed_trying_to_rollback": "Impossible de migrer… en essayant de restaurer le système.", "migration_0011_rollback_success": "Système restauré.", "migration_0011_update_LDAP_database": "Mise à jour de la base de données LDAP…", "system_groupname_exists": "Le nom de groupe existe déjà dans le groupe du systèmes", - "tools_update_failed_to_app_fetchlist": "Impossible de mettre à jour les applications de YunoHost car: {error}", + "tools_update_failed_to_app_fetchlist": "Impossible de mettre à jour les listes d'applications de YunoHost car: {error}", "user_already_in_group": "L'utilisateur '{user:}' est déjà dans le groupe '{group: s}'", "user_not_in_group": "L'utilisateur '{user: s}' ne fait pas partie du groupe {group: s}", "migration_0011_backup_before_migration": "Création d'une sauvegarde des paramètres de la base de données LDAP et des applications avant la migration.", @@ -620,12 +620,12 @@ "dyndns_provider_unreachable": "Impossible d’atteindre le fournisseur Dyndns {provider}: votre YunoHost n’est pas correctement connecté à Internet ou le serveur Dynette est en panne.", "migration_0011_update_LDAP_schema": "Mise à jour du schéma LDAP…", "migrations_already_ran": "Ces migrations sont déjà effectuées: {ids}", - "migrations_dependencies_not_satisfied": "Impossible d'exécuter la migration {id} car vous devez d'abord exécuter ces migrations: {dependencies_id}", + "migrations_dependencies_not_satisfied": "Exécutez ces migrations: '{dependencies_id}', avant migration {id}.", "migrations_failed_to_load_migration": "Impossible de charger la migration {id}: {error}", "migrations_running_forward": "Exécution de la migration {id}…", "migrations_success_forward": "Migration {id} terminée", "need_define_permission_before": "Redéfinissez l'autorisation à l'aide de 'yunohost user permission add -u USER' avant de supprimer un groupe autorisé", - "operation_interrupted": "L'opération a été interrompue manuellement", + "operation_interrupted": "L'opération a-t-elle été interrompue manuellement ?", "permission_already_clear": "L'autorisation '{permission: s}' est déjà vide pour l'application {app: s}", "permission_already_exist": "L'autorisation '{permission}' existe déjà", "permission_created": "Permission '{permission:s}' créée", @@ -648,12 +648,12 @@ "log_user_group_create": "Créer '{}' groupe", "log_user_permission_update": "Mise à jour des accès pour la permission '{}'", "log_user_permission_reset": "Réinitialiser la permission '{}'", - "migration_0011_failed_to_remove_stale_object": "Impossible de supprimer un objet obsolète {dn}: {error}", + "migration_0011_failed_to_remove_stale_object": "Impossible de supprimer un objet périmé {dn}: {error}", "permission_already_allowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' activée '", "permission_already_disallowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' désactivé '", "permission_cannot_remove_main": "Supprimer une autorisation principale n'est pas autorisé", - "user_already_exists": "L'utilisateur {user} existe déjà", - "app_full_domain_unavailable": "Désolé, cette application nécessite l'installation d'un domaine complet, mais d'autres applications sont déjà installées sur le domaine '{domain}'. Une solution possible consiste à ajouter et à utiliser un sous-domaine dédié à cette application.", + "user_already_exists": "L'utilisateur '{user}' existe déjà", + "app_full_domain_unavailable": "Désolé, cette application doit être installée sur un domaine qui lui est propre, mais d'autres applications sont déjà installées sur le domaine '{domain}'. Vous pouvez utiliser un sous-domaine dédié à cette application à la place.", "group_cannot_edit_all_users": "Le groupe 'all_users' ne peut pas être édité manuellement. C'est un groupe spécial destiné à contenir tous les utilisateurs enregistrés dans YunoHost", "group_cannot_edit_visitors": "Le groupe 'visiteurs' ne peut pas être édité manuellement. C'est un groupe spécial représentant les visiteurs anonymes", "group_cannot_edit_primary_group": "Le groupe '{group}' ne peut pas être édité manuellement. C'est le groupe principal destiné à ne contenir qu'un utilisateur spécifique.", From db7d68cf926455d22219aee65a561c6f6c5edd6f Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 26 Oct 2019 14:43:54 +0200 Subject: [PATCH 107/127] Fix weird fr string.. --- locales/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/fr.json b/locales/fr.json index 37e5f95c1..53a3f051e 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -248,7 +248,7 @@ "yunohost_ca_creation_failed": "Impossible de créer l’autorité de certification", "yunohost_configured": "YunoHost est maintenant configuré", "yunohost_installing": "L'installation de YunoHost est en cours …", - "yunohost_not_installed": "YunoHost n'est pas correctement installé. S'il vous plaît exécuter 'yunohost tools postinstall'", + "yunohost_not_installed": "YunoHost n'est pas correctement installé. Veuillez exécuter 'yunohost tools postinstall'", "certmanager_attempt_to_replace_valid_cert": "Vous êtes en train de vouloir remplacer un certificat correct et valide pour le domaine {domain:s} ! (Utilisez --force pour contourner cela)", "certmanager_domain_unknown": "Domaine {domain:s} inconnu", "certmanager_domain_cert_not_selfsigned": "Le certificat du domaine {domain:s} n’est pas auto-signé. Voulez-vous vraiment le remplacer ? (Utilisez --force pour cela)", From c2e5412a995fcbac02abc997314bcb501e124706 Mon Sep 17 00:00:00 2001 From: amirale qt Date: Fri, 25 Oct 2019 09:59:46 +0000 Subject: [PATCH 108/127] Translated using Weblate (French) Currently translated at 100.0% (561 of 561 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index 53a3f051e..3cb3c8fa9 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -649,7 +649,7 @@ "log_user_permission_update": "Mise à jour des accès pour la permission '{}'", "log_user_permission_reset": "Réinitialiser la permission '{}'", "migration_0011_failed_to_remove_stale_object": "Impossible de supprimer un objet périmé {dn}: {error}", - "permission_already_allowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' activée '", + "permission_already_allowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' activée", "permission_already_disallowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' désactivé '", "permission_cannot_remove_main": "Supprimer une autorisation principale n'est pas autorisé", "user_already_exists": "L'utilisateur '{user}' existe déjà", @@ -663,5 +663,6 @@ "permission_currently_allowed_for_visitors": "Cette autorisation est actuellement accordée aux visiteurs en plus d'autres groupes. Vous voudrez probablement supprimer l'autorisation \"visiteurs\" ou supprimer les autres groupes auxquels il est actuellement attribué.", "permission_currently_allowed_for_all_users": "Cette autorisation est actuellement accordée à tous les utilisateurs en plus des autres groupes. Vous voudrez probablement soit supprimer l'autorisation 'all_users', soit supprimer les autres groupes auxquels il est actuellement autorisé.", "app_install_failed": "Impossible d'installer {app}: {error}", - "app_install_script_failed": "Une erreur est survenue dans le script d'installation de l'application" + "app_install_script_failed": "Une erreur est survenue dans le script d'installation de l'application", + "permission_require_account": "Permission {permission} n'a de sens que pour les utilisateurs ayant un compte et ne peut donc pas être activé pour les visiteurs." } From af703bce47dce5d4925e553798504e9e37a361a7 Mon Sep 17 00:00:00 2001 From: advocatux Date: Thu, 24 Oct 2019 16:53:15 +0000 Subject: [PATCH 109/127] Translated using Weblate (Spanish) Currently translated at 100.0% (561 of 561 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/es/ --- locales/es.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/locales/es.json b/locales/es.json index afa323269..d216b8a9a 100644 --- a/locales/es.json +++ b/locales/es.json @@ -636,5 +636,6 @@ "migration_0011_slapd_config_will_be_overwritten": "Parece que ha editado manualmente la configuración de slapd. Para esta migración crítica, YunoHost necesita forzar la actualización de la configuración de slapd. Los archivos originales se respaldarán en {conf_backup_folder}.", "permission_already_up_to_date": "El permiso no se ha actualizado porque las peticiones de incorporación o eliminación ya coinciden con el estado actual.", "permission_currently_allowed_for_visitors": "Este permiso se concede actualmente a los visitantes además de otros grupos. Probablemente quiere o eliminar el permiso de «visitors» o eliminar los otros grupos a los que está otorgado actualmente.", - "permission_currently_allowed_for_all_users": "Este permiso se concede actualmente a todos los usuarios además de los otros grupos. Probablemente quiere o eliminar el permiso de «all_users» o eliminar los otros grupos a los que está otorgado actualmente." + "permission_currently_allowed_for_all_users": "Este permiso se concede actualmente a todos los usuarios además de los otros grupos. Probablemente quiere o eliminar el permiso de «all_users» o eliminar los otros grupos a los que está otorgado actualmente.", + "permission_require_account": "El permiso {permission} solo tiene sentido para usuarios con una cuenta y, por lo tanto, no se puede activar para visitantes." } From 6930fa82e71b07865c9549b3b7a11a46322e27e2 Mon Sep 17 00:00:00 2001 From: Filip Bengtsson Date: Fri, 25 Oct 2019 20:49:31 +0000 Subject: [PATCH 110/127] Translated using Weblate (Swedish) Currently translated at 0.2% (1 of 561 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/sv/ --- locales/sv.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/locales/sv.json b/locales/sv.json index 0967ef424..4960d43aa 100644 --- a/locales/sv.json +++ b/locales/sv.json @@ -1 +1,3 @@ -{} +{ + "password_too_simple_1": "Lösenordet måste bestå av minst åtta tecken" +} From 1b5c1c39bc5216dfb08173f0794aef94d5dac5c9 Mon Sep 17 00:00:00 2001 From: xaloc33 Date: Fri, 25 Oct 2019 17:27:26 +0000 Subject: [PATCH 111/127] Translated using Weblate (Catalan) Currently translated at 100.0% (561 of 561 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ca/ --- locales/ca.json | 77 +++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/locales/ca.json b/locales/ca.json index 04ee413b9..32bbfb50f 100644 --- a/locales/ca.json +++ b/locales/ca.json @@ -12,14 +12,14 @@ "app_change_no_change_url_script": "L'aplicació {app_name:s} encara no permet canviar la seva URL, es possible que s'hagi d'actualitzar.", "app_change_url_failed_nginx_reload": "No s'ha pogut tornar a carregar NGINX. Aquí teniu el resultat de \"nginx -t\":\n{nginx_errors:s}", "app_change_url_identical_domains": "L'antic i el nou domini/camí són idèntics ('{domain:s}{path:s}'), no hi ha res per fer.", - "app_change_url_no_script": "Aquesta aplicació '{app_name:s}' encara no permet modificar la URL. Potser s'ha d'actualitzar.", + "app_change_url_no_script": "L'aplicació '{app_name:s}' encara no permet modificar la URL. Potser s'ha d'actualitzar.", "app_change_url_success": "La URL de {app:s} ara és {domain:s}{path:s}", "app_extraction_failed": "No s'han pogut extreure els fitxers d'instal·lació", "app_id_invalid": "ID de l'aplicació incorrecte", "app_incompatible": "L'aplicació {app} no és compatible amb la teva versió de YunoHost", "app_install_files_invalid": "Aquests fitxers no es poden instal·lar", "app_location_already_used": "L'aplicació «{app}» ja està instal·lada en ({path})", - "app_make_default_location_already_used": "No es pot fer l'aplicació '{app}' per defecte en el domini {domain} ja que ja és utilitzat per una altra aplicació '{other_app}'", + "app_make_default_location_already_used": "No es pot fer l'aplicació '{app}' per defecte en el domini «{domain}» ja que ja és utilitzat per una altra aplicació '{other_app}'", "app_location_install_failed": "No s'ha pogut instal·lar l'aplicació aquí ja que entra en conflicte amb l'aplicació «{other_app}» ja instal·lada a «{other_path}»", "app_location_unavailable": "Aquesta URL no està disponible o entra en conflicte amb aplicacions ja instal·lades:\n{apps:s}", "app_manifest_invalid": "Hi ha algun error amb el manifest de l'aplicació: {error}", @@ -40,14 +40,14 @@ "app_upgrade_some_app_failed": "No s'han pogut actualitzar algunes aplicacions", "app_upgraded": "S'ha actualitzat {app:s}", "appslist_corrupted_json": "No s'han pogut carregar les llistes d'aplicacions. Sembla que {filename:s} està danyat.", - "appslist_could_not_migrate": "No s'ha pogut migrar la llista d'aplicacions {appslist:s}! No s'ha pogut analitzar la URL... L'antic cronjob s'ha guardat a {bkp_file:s}.", - "appslist_fetched": "S'ha actualitzat la llista d'aplicacions {appslist:s}", - "appslist_migrating": "Migrant la llista d'aplicacions {appslist:s}…", + "appslist_could_not_migrate": "No s'ha pogut migrar la llista d'aplicacions «{appslist:s}»! No s'ha pogut analitzar la URL... L'antic cronjob s'ha guardat a {bkp_file:s}.", + "appslist_fetched": "S'ha actualitzat la llista d'aplicacions «{appslist:s}»", + "appslist_migrating": "Migrant la llista d'aplicacions «{appslist:s}»…", "appslist_name_already_tracked": "Ja hi ha una llista d'aplicacions registrada amb el nom {name:s}.", - "appslist_removed": "S'ha eliminat la llista d'aplicacions {appslist:s}", - "appslist_retrieve_bad_format": "No s'ha pogut llegir la llista d'aplicacions obtinguda {appslist:s}", - "appslist_retrieve_error": "No s'ha pogut obtenir la llista d'aplicacions remota {appslist:s}: {error:s}", - "appslist_unknown": "La llista d'aplicacions {appslist:s} es desconeguda.", + "appslist_removed": "S'ha eliminat la llista d'aplicacions «{appslist:s}»", + "appslist_retrieve_bad_format": "No s'ha pogut llegir la llista d'aplicacions obtinguda «{appslist:s}»", + "appslist_retrieve_error": "No s'ha pogut obtenir la llista d'aplicacions remota «{appslist:s}»: {error:s}", + "appslist_unknown": "La llista d'aplicacions «{appslist:s}» es desconeguda.", "appslist_url_already_tracked": "Ja hi ha una llista d'aplicacions registrada amb al URL {url:s}.", "ask_current_admin_password": "Contrasenya d'administrador actual", "ask_email": "Adreça de correu electrònic", @@ -73,7 +73,7 @@ "backup_archive_open_failed": "No s'ha pogut obrir l'arxiu de la còpia de seguretat", "backup_archive_system_part_not_available": "La part «{part:s}» del sistema no està disponible en aquesta copia de seguretat", "backup_archive_writing_error": "No es poden afegir els arxius «{source:s}» (anomenats en l'arxiu «{dest:s}») a l'arxiu comprimit de la còpia de seguretat «{archive:s}»", - "backup_ask_for_copying_if_needed": "Alguns fitxers no s'han pogut preparar per la còpia de seguretat utilitzant el mètode que evita malgastar espai del sistema temporalment. Per fer la còpia de seguretat, s'han d'utilitzar {size:s}MB temporalment. Hi esteu d'acord?", + "backup_ask_for_copying_if_needed": "Voleu fer la còpia de seguretat utilitzant {size:s} MB temporalment? (S'utilitza aquest mètode ja que alguns dels fitxers no s'han pogut preparar utilitzar un mètode més eficient.)", "backup_borg_not_implemented": "El mètode de còpia de seguretat Borg encara no està implementat", "backup_cant_mount_uncompress_archive": "No es pot carregar l'arxiu descomprimit com a protegit contra escriptura", "backup_cleaning_failed": "No s'ha pogut netejar el directori temporal de la còpia de seguretat", @@ -83,10 +83,10 @@ "backup_creating_archive": "Creant l'arxiu de la còpia de seguretat…", "aborting": "Avortant.", "app_not_upgraded": "L'aplicació «{failed_app}» no s'ha pogut actualitzar, i com a conseqüència l'actualització de les següents aplicacions ha estat cancel·lada: {apps}", - "app_start_install": "instal·lant l'aplicació {app}…", - "app_start_remove": "Eliminant l'aplicació {app}…", - "app_start_backup": "Recuperant els fitxers pels que s'ha de fer una còpia de seguretat per {app}…", - "app_start_restore": "Recuperant l'aplicació {app}…", + "app_start_install": "instal·lant l'aplicació «{app}»…", + "app_start_remove": "Eliminant l'aplicació «{app}»…", + "app_start_backup": "Recuperant els fitxers pels que s'ha de fer una còpia de seguretat per «{app}»…", + "app_start_restore": "Recuperant l'aplicació «{app}»…", "app_upgrade_several_apps": "S'actualitzaran les següents aplicacions: {apps}", "ask_new_domain": "Nou domini", "ask_new_path": "Nou camí", @@ -118,7 +118,7 @@ "backup_output_directory_forbidden": "Escolliu un directori de sortida different. Les còpies de seguretat no es poden crear ni dins els directoris /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ni dins els subdirectoris /home/yunohost.backup/archives", "backup_output_directory_not_empty": "Heu d'escollir un directori de sortida buit", "backup_output_directory_required": "Heu d'especificar un directori de sortida per la còpia de seguretat", - "backup_output_symlink_dir_broken": "Teniu un enllaç simbòlic trencat en lloc del directori del arxiu «{path:s}». Pot ser teniu una configuració per la còpia de seguretat específica en un altre sistema de fitxers, si és el cas segurament heu oblidat muntar o connectar el disc dur o la clau USB.", + "backup_output_symlink_dir_broken": "El directori del arxiu «{path:s}» es un enllaç simbòlic trencat. Pot ser heu oblidat muntar, tornar a muntar o connectar el mitja d'emmagatzematge al que apunta.", "backup_php5_to_php7_migration_may_fail": "No s'ha pogut convertir l'arxiu per suportar PHP 7, pot ser que no es puguin restaurar les vostres aplicacions PHP (raó: {error:s})", "backup_running_hooks": "Executant els scripts de la còpia de seguretat…", "backup_system_part_failed": "No s'ha pogut fer la còpia de seguretat de la part \"{part:s}\" del sistema", @@ -149,7 +149,7 @@ "certmanager_self_ca_conf_file_not_found": "No s'ha trobat el fitxer de configuració per l'autoritat del certificat auto-signat (fitxer: {file:s})", "certmanager_unable_to_parse_self_CA_name": "No s'ha pogut analitzar el nom de l'autoritat del certificat auto-signat (fitxer: {file:s})", "confirm_app_install_warning": "Atenció: Aquesta aplicació funciona, però no està ben integrada amb YunoHost. Algunes característiques com la autenticació única i la còpia de seguretat/restauració poden no estar disponibles. Voleu instal·lar-la de totes maneres? [{answers:s}] ", - "confirm_app_install_danger": "PERILL! Aquesta aplicació encara és experimental (si no és que no funciona directament)! No hauríeu d'instal·lar-la a no ser que sapigueu el que feu. No obtindreu CAP AJUDA si l'aplicació no funciona o trenca el sistema... Si accepteu el risc, escriviu «{answers:s}»", + "confirm_app_install_danger": "PERILL! Aquesta aplicació encara és experimental (si no és que no funciona directament)! No hauríeu d'instal·lar-la a no ser que sapigueu el que feu. No obtindreu CAP AJUDA si l'aplicació no funciona o trenca el sistema… Si accepteu el risc, escriviu «{answers:s}»", "confirm_app_install_thirdparty": "PERILL! Aquesta aplicació no es part del catàleg d'aplicacions de YunoHost. La instal·lació d'aplicacions de terceres parts pot comprometre la integritat i seguretat del seu sistema. No hauríeu d'instal·lar-ne a no ser que sapigueu el que feu. No obtindreu CAP AJUDA si l'aplicació no funciona o trenca el sistema… Si accepteu el risc, escriviu «{answers:s}»", "custom_app_url_required": "Heu de especificar una URL per actualitzar la vostra aplicació personalitzada {app:s}", "custom_appslist_name_required": "Heu d'especificar un nom per la vostra llista d'aplicacions personalitzada", @@ -158,7 +158,7 @@ "diagnosis_monitor_disk_error": "No es poden monitorar els discs: {error}", "diagnosis_monitor_network_error": "No es pot monitorar la xarxa: {error}", "diagnosis_monitor_system_error": "No es pot monitorar el sistema: {error}", - "diagnosis_no_apps": "No hi ha cap aplicació instal·lada", + "diagnosis_no_apps": "Aquesta aplicació no està instal·lada", "admin_password_too_long": "Trieu una contrasenya de menys de 127 caràcters", "dpkg_is_broken": "No es pot fer això en aquest instant perquè dpkg/APT (els gestors de paquets del sistema) sembla estar mal configurat… Podeu intentar solucionar-ho connectant-vos per SSH i executant «sudo dpkg --configure -a».", "dnsmasq_isnt_installed": "sembla que dnsmasq no està instal·lat, executeu \"apt-get remove bind9 && apt-get install dnsmasq\"", @@ -169,7 +169,7 @@ "domain_deleted": "S'ha eliminat el domini", "domain_deletion_failed": "No s'ha pogut eliminar el domini {domini}: {error}", "domain_exists": "El domini ja existeix", - "app_action_cannot_be_ran_because_required_services_down": "Aquesta aplicació necessita serveis que estan aturats. Abans de continuar, hauríeu d'intentar arrancar de nou els serveis següents (i també investigar perquè estan aturats): {services}", + "app_action_cannot_be_ran_because_required_services_down": "Aquests serveis necessaris haurien d'estar funcionant per poder executar aquesta acció: {services} Intenteu reiniciar-los per continuar (i possiblement investigar perquè estan aturats).", "domain_dns_conf_is_just_a_recommendation": "Aquesta ordre mostra la configuració *recomanada*. En cap cas fa la configuració del DNS. És la vostra responsabilitat configurar la zona DNS en el vostre registrar en acord amb aquesta recomanació.", "domain_dyndns_already_subscribed": "Ja us heu subscrit a un domini DynDNS", "domain_dyndns_dynette_is_unreachable": "No s'ha pogut abastar la dynette YunoHost, o bé YunoHost no està connectat a internet correctament o bé el servidor dynette està caigut. Error: {error}", @@ -325,19 +325,19 @@ "migration_0005_postgresql_94_not_installed": "PostgreSQL no està instal·lat en el sistema. No hi ha res per fer.", "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 està instal·lat, però no PostgreSQL 9.6? Alguna cosa estranya a passat en el sistema :( …", "migration_0005_not_enough_space": "Creu espai disponible en {path} per executar la migració.", - "migration_0006_disclaimer": "YunoHost esperar que les contrasenyes admin i root estiguin sincronitzades. Fent aquesta migració, la contrasenya root serà reemplaçada per la contrasenya admin.", - "migration_0007_cancelled": "YunoHost no ha pogut millorar la gestió de la configuració SSH.", + "migration_0006_disclaimer": "YunoHost esperar que les contrasenyes de admin i root estiguin sincronitzades. Aquesta migració canvia la contrasenya root per la contrasenya admin.", + "migration_0007_cancelled": "No s'ha pogut millorar la gestió de la configuració SSH.", "migration_0007_cannot_restart": "No es pot reiniciar SSH després d'haver intentat cancel·lar la migració numero 6.", "migration_0008_general_disclaimer": "Per millorar la seguretat del servidor, es recomana que sigui YunoHost qui gestioni la configuració SSH. La configuració SSH actual és diferent a la configuració recomanada. Si deixeu que YunoHost ho reconfiguri, la manera de connectar-se al servidor mitjançant SSH canviarà de la següent manera:", "migration_0008_port": "• La connexió es farà utilitzant el port 22 en lloc del port SSH personalitzat actual. Es pot reconfigurar;", "migration_0008_root": "• No es podrà connectar com a root a través de SSH. S'haurà d'utilitzar l'usuari admin per fer-ho;", "migration_0008_dsa": "• Es desactivarà la clau DSA. Per tant, es podria haver d'invalidar un missatge esgarrifós del client SSH, i tornar a verificar l'empremta digital del servidor;", - "migration_0008_warning": "Si heu entès els avisos i accepteu que YunoHost sobreescrigui la configuració actual, comenceu la migració. Sinó, podeu saltar-vos la migració, tot i que no està recomanat.", - "migration_0008_no_warning": "No s'han identificat riscs importants per sobreescriure la configuració SSH, però no es pot estar del tot segur ;)! Executetu la migració per sobreescriure-la. Sinó, podeu saltar-vos la migració, tot i que no està recomanat.", + "migration_0008_warning": "Si heu entès els avisos i voleu que YunoHost sobreescrigui la configuració actual, comenceu la migració. Sinó, podeu saltar-vos la migració, tot i que no està recomanat.", + "migration_0008_no_warning": "Hauria de ser segur sobreescriure la configuració SSH, però no es pot estar del tot segur! Executetu la migració per sobreescriure-la. Sinó, podeu saltar-vos la migració, tot i que no està recomanat.", "migration_0009_not_needed": "Sembla que ja s'ha fet aquesta migració… (?) Ometent.", "migrations_backward": "Migració cap enrere.", "migrations_bad_value_for_target": "Nombre invàlid pel paràmetre target, els nombres de migració disponibles són 0 o {}", - "migrations_cant_reach_migration_file": "No s'ha pogut accedir als fitxers de migració al camí %s", + "migrations_cant_reach_migration_file": "No s'ha pogut accedir als fitxers de migració al camí «%s»", "migrations_current_target": "La migració objectiu és {}", "migrations_error_failed_to_load_migration": "ERROR: no s'ha pogut carregar la migració {number} {name}", "migrations_forward": "Migració endavant", @@ -351,8 +351,8 @@ "migrations_success": "S'ha completat la migració {number} {name} amb èxit!", "migrations_to_be_ran_manually": "La migració {id} s'ha de fer manualment. Aneu a Eines → Migracions a la interfície admin, o executeu «yunohost tools migrations migrate».", "migrations_need_to_accept_disclaimer": "Per fer la migració {id}, heu d'acceptar aquesta clàusula de no responsabilitat:\n---\n{disclaimer}\n---\nSi accepteu fer la migració, torneu a executar l'ordre amb l'opció «--accept-disclaimer».", - "monitor_disabled": "El monitoratge del servidor ha estat desactivat", - "monitor_enabled": "El monitoratge del servidor ha estat activat", + "monitor_disabled": "S'ha desactivat el monitoratge del servidor", + "monitor_enabled": "S'ha activat el monitoratge del sistema", "monitor_glances_con_failed": "No s'ha pogut connectar al servidor Glances", "monitor_not_enabled": "El monitoratge del servidor no està activat", "monitor_period_invalid": "Període de temps invàlid", @@ -436,7 +436,7 @@ "server_reboot_confirm": "Es reiniciarà el servidor immediatament, n'esteu segur? [{answers:s}]", "service_add_failed": "No s'ha pogut afegir el servei «{service:s}»", "service_added": "S'ha afegit el servei «{service:s}»", - "service_already_started": "Ja s'ha iniciat el servei «{service:s}»", + "service_already_started": "El servei «{service:s}» ja està funcionant", "service_already_stopped": "Ja s'ha aturat el servei «{service:s}»", "service_cmd_exec_failed": "No s'ha pogut executar l'ordre «{command:s}»", "service_description_avahi-daemon": "Permet accedir al servidor via «yunohost.local» en la xarxa local", @@ -458,9 +458,9 @@ "service_description_yunohost-api": "Gestiona les interaccions entre la interfície web de YunoHost i el sistema", "service_description_yunohost-firewall": "Gestiona els ports de connexió oberts i tancats als serveis", "service_disable_failed": "No s'han pogut deshabilitar el servei «{service:s}»\n\nRegistres recents: {logs:s}", - "service_disabled": "S'ha deshabilitat el servei {service:s}", + "service_disabled": "S'ha deshabilitat el servei «{service:s}»", "service_enable_failed": "No s'ha pogut activar el servei «{service:s}»\n\nRegistres recents: {log:s}", - "service_enabled": "S'ha activat el servei {service:s}", + "service_enabled": "S'ha activat el servei «{service:s}»", "service_no_log": "No hi ha cap registre pel servei «{service:s}»", "service_regen_conf_is_deprecated": "«yunohost service regen-conf» està desfasat! Utilitzeu «yunohost tools regen-conf» en el seu lloc.", "service_remove_failed": "No s'ha pogut eliminar el servei «{service:s}»", @@ -523,7 +523,7 @@ "yunohost_ca_creation_success": "S'ha creat l'autoritat de certificació local.", "yunohost_configured": "YunoHost està configurat", "yunohost_installing": "Instal·lació de YunoHost…", - "yunohost_not_installed": "YunoHost no està instal·lat o no està instal·lat correctament. Executeu «yunohost tools postinstall»", + "yunohost_not_installed": "YunoHost no està instal·lat correctament. Executeu «yunohost tools postinstall»", "apps_permission_not_found": "No s'ha trobat cap permís per les aplicacions instal·lades", "apps_permission_restoration_failed": "Ha fallat el permís «{permission:s}» per la restauració de l'aplicació {app:s}", "backup_permission": "Permís de còpia de seguretat per l'aplicació {app:s}", @@ -553,13 +553,13 @@ "mailbox_disabled": "La bústia de correu està desactivada per al usuari {user:s}", "migration_description_0011_setup_group_permission": "Configurar el grup d'usuaris i els permisos per les aplicacions i els serveis", "migration_0011_backup_before_migration": "Creant una còpia de seguretat de la base de dades LDAP i la configuració de les aplicacions abans d'efectuar la migració.", - "migration_0011_can_not_backup_before_migration": "No s'ha pogut fer la còpia de seguretat abans de la migració. No s'ha pogut fer la migració. Error: {error:s}", + "migration_0011_can_not_backup_before_migration": "No s'ha pogut completar la còpia de seguretat abans de que la migració fallés. Error: {error:s}", "migration_0011_create_group": "Creant un grup per a cada usuari…", - "migration_0011_done": "Migració completa. Ja podeu gestionar grups d'usuaris.", + "migration_0011_done": "Migració completada. Ja podeu gestionar grups d'usuaris.", "migration_0011_LDAP_config_dirty": "Sembla que heu modificat manualment la configuració LDAP. Per fer aquesta migració s'ha d'actualitzar la configuració LDAP.\nGuardeu la configuració actual, reinicieu la configuració original executant l'ordre «yunohost tools regen-conf -f» i torneu a intentar la migració", "migration_0011_LDAP_update_failed": "Ha fallat l'actualització de LDAP. Error: {error:s}", "migration_0011_migrate_permission": "Fent la migració dels permisos de la configuració de les aplicacions a LDAP…", - "migration_0011_migration_failed_trying_to_rollback": "La migració ha fallat… s'intenta tornar el sistema a l'estat anterior.", + "migration_0011_migration_failed_trying_to_rollback": "No s'ha pogut fer la migració… s'intenta tornar el sistema a l'estat anterior.", "migration_0011_rollback_success": "S'ha tornat el sistema a l'estat anterior.", "migration_0011_update_LDAP_database": "Actualitzant la base de dades LDAP…", "migration_0011_update_LDAP_schema": "Actualitzant l'esquema LDAP…", @@ -583,7 +583,7 @@ "user_already_in_group": "L'usuari {user:s} ja és en el grup {group:s}", "user_not_in_group": "L'usuari {user:s} no és en el grup {group:s}", "migration_description_0012_postgresql_password_to_md5_authentication": "Força l'autenticació PostgreSQL a fer servir MD5 per a les connexions locals", - "app_full_domain_unavailable": "Aquesta aplicació requereix un domini sencer per ser instal·lada, però ja hi ha altres aplicacions instal·lades al domini «{domain}». Una possible solució és afegir i utilitzar un subdomini dedicat a aquesta aplicació.", + "app_full_domain_unavailable": "Aquesta aplicació ha de ser instal·lada en el seu propi domini, però ja hi ha altres aplicacions instal·lades en el domini «{domain}». Podeu utilitzar un subdomini dedicat a aquesta aplicació.", "migrations_not_pending_cant_skip": "Aquestes migracions no estan pendents, així que no poden ser omeses: {ids}", "app_action_broke_system": "Aquesta acció sembla haver trencat els següents serveis importants: {services}", "log_permission_urls": "Actualitzar les URLs relacionades amb el permís «{}»", @@ -592,11 +592,11 @@ "log_user_permission_reset": "Restablir el permís «{}»", "permission_already_disallowed": "El grup «{group}» ja té el permís «{permission}» desactivat", "migrations_already_ran": "Aquestes migracions ja s'han fet: {ids}", - "migrations_dependencies_not_satisfied": "No s'ha pogut executar la migració {id} perquè s'han d'executar primer les següents migracions: {dependencies_id}", + "migrations_dependencies_not_satisfied": "Executeu aquestes migracions: «{dependencies_id}», abans la migració {id}.", "migrations_failed_to_load_migration": "No s'ha pogut carregar la migració {id}: {error}", "migrations_exclusive_options": "«--auto», «--skip», i «--force-rerun» són opcions mútuament excloents.", "migrations_must_provide_explicit_targets": "Heu de proporcionar objectius explícits al utilitzar «--skip» o «--force-rerun»", - "migrations_no_such_migration": "No hi ha cap migració anomenada {id}", + "migrations_no_such_migration": "No hi ha cap migració anomenada «{id}»", "migrations_pending_cant_rerun": "Aquestes migracions encara estan pendents, així que no es poden tornar a executar: {ids}", "migrations_running_forward": "Executant la migració {id}…", "migrations_success_forward": "Migració {id} completada", @@ -614,8 +614,8 @@ "migration_0011_failed_to_remove_stale_object": "No s'ha pogut eliminar l'objecte obsolet {dn}: {error}", "permission_already_allowed": "El grup «{group}» ja té el permís «{permission}» activat", "permission_cannot_remove_main": "No es permet eliminar un permís principal", - "user_already_exists": "L'usuari {user} ja existeix", - "app_upgrade_stopped": "S'ha aturat l'actualització de totes les aplicacions per prevenir els possibles danys ja que hi ha hagut un error en l'actualització de l'anterior aplicació", + "user_already_exists": "L'usuari «{user}» ja existeix", + "app_upgrade_stopped": "S'ha aturat l'actualització de totes les aplicacions per prevenir possibles danys ja que no s'ha pogut actualitzar una aplicació", "app_install_failed": "No s'ha pogut instal·lar {app}: {error}", "app_install_script_failed": "Hi ha hagut un error en el script d'instal·lació de l'aplicació", "group_cannot_edit_all_users": "El grup «all_users» no es pot editar manualment. És un grup especial destinat a contenir els usuaris registrats a YunoHost", @@ -625,5 +625,6 @@ "migration_0011_slapd_config_will_be_overwritten": "Sembla que heu modificat manualment la configuració de sldap. Per aquesta migració crítica, YunoHost ha de forçar l'actualització de la configuració sldap. Es farà una còpia de seguretat a {conf_backup_folder}.", "permission_already_up_to_date": "No s'ha actualitzat el permís perquè la petició d'afegir/eliminar ja corresponent a l'estat actual.", "permission_currently_allowed_for_visitors": "El permís ja el tenen el grup de visitants a més d'altres grups. Segurament s'hauria de revocar el permís al grup dels visitants o eliminar els altres grups als que s'ha atribuït.", - "permission_currently_allowed_for_all_users": "El permís ha el té el grup de tots els usuaris (all_users) a més d'altres grups. Segurament s'hauria de revocar el permís a «all_users» o eliminar els altres grups als que s'ha atribuït." + "permission_currently_allowed_for_all_users": "El permís ha el té el grup de tots els usuaris (all_users) a més d'altres grups. Segurament s'hauria de revocar el permís a «all_users» o eliminar els altres grups als que s'ha atribuït.", + "permission_require_account": "El permís {permission} només té sentit per als usuaris que tenen un compte, i per tant no es pot activar per als visitants." } From ec1fa46c9f3986e34e7695d9e691ac74d685dfb3 Mon Sep 17 00:00:00 2001 From: Kayou Date: Sat, 26 Oct 2019 23:12:11 +0900 Subject: [PATCH 112/127] iproute2 instead of iproute --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index c0604d90e..b0de9032b 100644 --- a/debian/control +++ b/debian/control @@ -17,7 +17,7 @@ Depends: ${python:Depends}, ${misc:Depends} , python-toml , glances, apt-transport-https , dnsutils, bind9utils, unzip, git, curl, cron, wget, jq - , ca-certificates, netcat-openbsd, iproute + , ca-certificates, netcat-openbsd, iproute2 , mariadb-server, php-mysql | php-mysqlnd , slapd, ldap-utils, sudo-ldap, libnss-ldapd, unscd, libpam-ldapd , postfix-ldap, postfix-policyd-spf-perl, postfix-pcre, procmail, mailutils, postsrsd From 17ce7bd95c097f8fceeee6f35873c89cd4b4b91c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 26 Oct 2019 17:35:00 +0200 Subject: [PATCH 113/127] Rework depreciation warning about legacy permission stuff --- data/helpers.d/setting | 4 ++-- src/yunohost/app.py | 21 +++++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/data/helpers.d/setting b/data/helpers.d/setting index fd2824997..d905b61dd 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -176,8 +176,8 @@ else: elif action == "set": if key in ['redirected_urls', 'redirected_regex']: value = yaml.load(value) - if key in ["unprotected_uris", "unprotected_regex", "protected_uris", "protected_regex"]: - sys.stderr.write("/!\\ Packagers! This app is using the legacy permission system. Please delete these legacy settings and use the new helpers 'ynh_permission_{create,urls,update,delete}' and the 'visitors' group to manage public/private access.\n") + if any(key.startswith(word+"_") for word in ["unprotected", "protected", "skipped"]): + sys.stderr.write("/!\\ Packagers! This app is still using the skipped/protected/unprotected_uris/regex settings which are now obsolete and deprecated... Instead, you should use the new helpers 'ynh_permission_{create,urls,update,delete}' and the 'visitors' group to initialize the public/private access. Check out the documentation at the bottom of yunohost.org/groups_and_permissions to learn how to use the new permission mechanism.\n") settings[key] = value else: raise ValueError("action should either be get, set or delete") diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 5cf812871..b1ad0f40c 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -1341,17 +1341,18 @@ def app_setting(app, key, value=None, delete=False): except Exception as e: logger.debug("cannot get app setting '%s' for '%s' (%s)", key, app, e) return None + + if delete and key in app_settings: + del app_settings[key] else: - if delete and key in app_settings: - del app_settings[key] - else: - # FIXME: Allow multiple values for some keys? - if key in ['redirected_urls', 'redirected_regex']: - value = yaml.load(value) - if key in ["unprotected_uris", "unprotected_regex", "protected_uris", "protected_regex"]: - logger.warning("/!\ Packagers ! This app is using the legacy permission system. Please delete these legacy settings and use the new helpers ynh_permission_{create,url,update,delete} and the 'visitors' group to manage public/private access.") - app_settings[key] = value - _set_app_settings(app, app_settings) + # FIXME: Allow multiple values for some keys? + if key in ['redirected_urls', 'redirected_regex']: + value = yaml.load(value) + if any(key.startswith(word+"_") for word in ["unprotected", "protected", "skipped"]): + logger.warning("/!\\ Packagers! This app is still using the skipped/protected/unprotected_uris/regex settings which are now obsolete and deprecated... Instead, you should use the new helpers 'ynh_permission_{create,urls,update,delete}' and the 'visitors' group to initialize the public/private access. Check out the documentation at the bottom of yunohost.org/groups_and_permissions to learn how to use the new permission mechanism.") + + app_settings[key] = value + _set_app_settings(app, app_settings) def app_checkport(port): From 9294664d6c60269a5c2dc3048d6994bd2944cb3d Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 26 Oct 2019 17:39:09 +0200 Subject: [PATCH 114/127] Fix permission backward compatibility for the case where an app needs to make the app temporarily public during install script... --- data/helpers.d/setting | 7 +++++++ src/yunohost/app.py | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/data/helpers.d/setting b/data/helpers.d/setting index d905b61dd..185e6111f 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -184,6 +184,13 @@ else: with open(setting_file, "w") as f: yaml.safe_dump(settings, f, default_flow_style=False) EOF + + # Fucking legacy permission management. + # We need this because app temporarily set the app as unprotected to configure it with curl... + if [[ "$3" =~ ^(unprotected|skipped)_ ]] && [[ "${4:-}" == "/" ]] + then + ynh_permission_update --permission "main" --remove "all_users" --add "visitors" + fi } # Check availability of a web path diff --git a/src/yunohost/app.py b/src/yunohost/app.py index b1ad0f40c..6d3da405f 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -1101,9 +1101,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu if not (domain and path): permission_url(app_instance_name + ".main", url=None, sync_perm=False) - # Migrate classic public app still using the legacy unprotected_uris - if app_settings.get("unprotected_uris", None) == "/" or app_settings.get("skipped_uris", None) == "/": - user_permission_update(app_instance_name + ".main", remove="all_users", add="visitors", sync_perm=False) + _migrate_legacy_permissions(app_instance_name) permission_sync_to_user() @@ -1112,6 +1110,34 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu hook_callback('post_app_install', args=args_list, env=env_dict) +def _migrate_legacy_permissions(app): + + from yunohost.permission import user_permission_list, user_permission_update + + # Check if app is apparently using the legacy permission management, defined by the presence of something like + # ynh_app_setting_set on unprotected_uris (or yunohost app setting) + install_script_path = os.path.join(APPS_SETTING_PATH, app, 'scripts/install') + install_script_content = open(install_script_path, "r").read() + if not re.search(r"(yunohost app setting|ynh_app_setting_set) .*(unprotected|skipped)_uris", install_script_content): + return + + app_settings = _get_app_settings(app) + app_perm_currently_allowed = user_permission_list()["permissions"][app + ".main"]["allowed"] + + # If the current permission says app is protected, but there are legacy rules saying it should be public... + if app_perm_currently_allowed == ["all_users"] \ + and (app_settings.get("unprotected_uris", None) == "/" + or app_settings.get("skipped_uris", None) == "/"): + # Make it public + user_permission_update(app + ".main", remove="all_users", add="visitors", sync_perm=False) + # If the current permission says app is public, but there are no setting saying it should be public... + if app_perm_currently_allowed == ["visitors"] \ + and (app_settings.get("unprotected_uris", None) is None + and app_settings.get("skipped_uris", None) is None): + # Make is private + user_permission_update(app + ".main", remove="visitors", add="all_users", sync_perm=False) + + @is_unit_operation() def app_remove(operation_logger, app): """ @@ -1354,6 +1380,12 @@ def app_setting(app, key, value=None, delete=False): app_settings[key] = value _set_app_settings(app, app_settings) + # Fucking legacy permission management. + # We need this because app temporarily set the app as unprotected to configure it with curl... + if key.startswith("unprotected_") or key.startswith("skipped_") and value == "/": + from permission import user_permission_update + user_permission_update(app + ".main", remove="all_users", add="visitors") + def app_checkport(port): """ From 854e52c21e0d5a6e10d122f8954b34c182c4de44 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 29 Oct 2019 15:46:22 +0100 Subject: [PATCH 115/127] More inclusive rule for this php/sury hack because php version got updated to deb9u6 --- data/helpers.d/apt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index d772c6855..cbf4e3e59 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -227,7 +227,7 @@ ynh_install_app_dependencies () { if echo $dependencies | grep -q 'php'; then # And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33-0 on debian) - if dpkg --list | grep "php7.0" | grep -q -v "7.0.33-0+deb9u5" + if dpkg --list | grep "php7.0" | grep -q -v "7.0.33-0+deb9" then # And sury ain't already installed if ! grep -nrq "sury" /etc/apt/sources.list* From 5a599f2ebf08245b9673487ce949d15543bd5f0f Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 29 Oct 2019 15:49:31 +0100 Subject: [PATCH 116/127] Update changelog for 3.6.5.3 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 1d13b6290..45dbadef5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +yunohost (3.6.5.3) stable; urgency=low + + - [fix] More general grep for the php/sury dependency nightmare fix (followup of #809) + + -- Alexandre Aubin Tue, 29 Oct 2019 03:48:00 +0000 + yunohost (3.6.5.2) stable; urgency=low - [fix] Alex was drunk and released an epic stupid bug in stable (2623d385) From 79627d79ccfbc4e5a23691e3fd7da80620a707cd Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 29 Oct 2019 16:18:31 +0100 Subject: [PATCH 117/127] [yolo] Cosmetic improvement for logs during system package upgrades --- src/yunohost/tools.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 28b507707..f4bb83c15 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -640,8 +640,11 @@ def tools_upgrade(operation_logger, apps=None, system=False): logger.debug("Running apt command :\n{}".format(dist_upgrade)) + def is_relevant(l): + return "Reading database ..." not in l.rstrip() + callbacks = ( - lambda l: logger.info("+" + l.rstrip() + "\r"), + lambda l: logger.info("+ " + l.rstrip() + "\r") if is_relevant(l) else logger.debug(l.rstrip() + "\r"), lambda l: logger.warning(l.rstrip()), ) returncode = call_async_output(dist_upgrade, callbacks, shell=True) From 71bc6a0fafce76e03de00133a4df0e570512f138 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 29 Oct 2019 16:38:15 +0100 Subject: [PATCH 118/127] We gotta regen the ssowat conf to propagate the change --- src/yunohost/app.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 6d3da405f..1eeb38924 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -612,6 +612,8 @@ def app_change_url(operation_logger, app, domain, path): app_setting(app, 'domain', value=domain) app_setting(app, 'path', value=path) + app_ssowatconf() + # avoid common mistakes if _run_service_command("reload", "nginx") is False: # grab nginx errors From 572b003e299428238546813f956ebbb23f800946 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 29 Oct 2019 17:17:43 +0100 Subject: [PATCH 119/127] We gotta return a permission structure here in all case, otherwise stuff like app_addaccess will miserably fail in these case --- src/yunohost/permission.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/permission.py b/src/yunohost/permission.py index 226cc9050..c53804d49 100644 --- a/src/yunohost/permission.py +++ b/src/yunohost/permission.py @@ -155,7 +155,7 @@ def user_permission_update(operation_logger, permission, add=None, remove=None, # Don't update LDAP if we update exactly the same values if set(new_allowed_groups) == set(current_allowed_groups): logger.warning(m18n.n("permission_already_up_to_date")) - return + return existing_permission # Commit the new allowed group list From 83b45d7894f49878d608071e7f27b3981ae896cc Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 29 Oct 2019 17:38:05 +0100 Subject: [PATCH 120/127] Fix the legacy permission fix after app install, sometimes the setting ain't None --- src/yunohost/app.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 1eeb38924..1e82b78ba 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -1126,16 +1126,16 @@ def _migrate_legacy_permissions(app): app_settings = _get_app_settings(app) app_perm_currently_allowed = user_permission_list()["permissions"][app + ".main"]["allowed"] + settings_say_it_should_be_public = (app_settings.get("unprotected_uris", None) == "/" + or app_settings.get("skipped_uris", None) == "/") + # If the current permission says app is protected, but there are legacy rules saying it should be public... - if app_perm_currently_allowed == ["all_users"] \ - and (app_settings.get("unprotected_uris", None) == "/" - or app_settings.get("skipped_uris", None) == "/"): + if app_perm_currently_allowed == ["all_users"] and settings_say_it_should_be_public: # Make it public user_permission_update(app + ".main", remove="all_users", add="visitors", sync_perm=False) + # If the current permission says app is public, but there are no setting saying it should be public... - if app_perm_currently_allowed == ["visitors"] \ - and (app_settings.get("unprotected_uris", None) is None - and app_settings.get("skipped_uris", None) is None): + if app_perm_currently_allowed == ["visitors"] and not settings_say_it_should_be_public: # Make is private user_permission_update(app + ".main", remove="visitors", add="all_users", sync_perm=False) From 9ee3d234e8db1080dd5d87f3bec0b802a1035943 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 29 Oct 2019 19:19:04 +0100 Subject: [PATCH 121/127] [ux] Add a message to explain that the app is being removed if the install fails --- locales/en.json | 1 + src/yunohost/app.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/locales/en.json b/locales/en.json index 202650edb..27f25e095 100644 --- a/locales/en.json +++ b/locales/en.json @@ -40,6 +40,7 @@ "app_requirements_checking": "Checking required packages for {app}…", "app_requirements_failed": "Some requirements are not met for {app}: {error}", "app_requirements_unmeet": "Requirements are not met for {app}, the package {pkgname} ({version}) must be {spec}", + "app_remove_after_failed_install": "Removing the app following the installation failure…", "app_sources_fetch_failed": "Could not fetch sources files, is the URL correct?", "app_start_install": "Installing the app '{app}'…", "app_start_remove": "Removing the app '{app}'…", diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 1e82b78ba..a4185b880 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -1026,6 +1026,8 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu # This option is meant for packagers to debug their apps more easily if no_remove_on_failure: raise YunohostError("The installation of %s failed, but was not cleaned up as requested by --no-remove-on-failure." % app_id, raw_msg=True) + else: + logger.warning(m18n.n("app_remove_after_failed_install")) # Setup environment for remove script env_dict_remove = {} From 4dadb9eb906eaef566b1cd08aa6755d6e8d9637c Mon Sep 17 00:00:00 2001 From: amirale qt Date: Mon, 28 Oct 2019 08:27:21 +0000 Subject: [PATCH 122/127] Translated using Weblate (French) Currently translated at 100.0% (561 of 561 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/fr.json b/locales/fr.json index 3cb3c8fa9..15f82baf1 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -370,7 +370,7 @@ "dyndns_domain_not_provided": "Le fournisseur DynDNS {provider:s} ne peut pas fournir le domaine {domain:s}.", "app_make_default_location_already_used": "Impossible de configurer l’application '{app}' par défaut pour le domaine '{domain}' car il est déjà utilisé par l'application '{other_app}'", "app_upgrade_app_name": "Mise à jour de l’application {app} …", - "backup_output_symlink_dir_broken": "Votre répertoire d'archivage '{chemin:s}' est un lien symbolique brisé. Peut-être avez-vous oublié de re/monter ou de brancher le support de stockage sur lequel il pointe.", + "backup_output_symlink_dir_broken": "Votre répertoire d'archivage '{path:s}' est un lien symbolique brisé. Peut-être avez-vous oublié de re/monter ou de brancher le support de stockage sur lequel il pointe.", "migrate_tsig_end": "La migration à HMAC-SHA-512 est terminée", "migrate_tsig_failed": "La migration du domaine DynDNS {domain} à hmac-sha512 a échoué. Annulation des modifications. Erreur : {error_code} - {error}", "migrate_tsig_start": "L’algorithme de génération des clefs n’est pas suffisamment sécurisé pour la signature TSIG du domaine '{domain}', lancement de la migration vers HMAC-SHA-512 qui est plus sécurisé", From dd9f1944af994ec2a44081c4d22a6798f5bd2047 Mon Sep 17 00:00:00 2001 From: amirale qt Date: Mon, 28 Oct 2019 08:04:16 +0000 Subject: [PATCH 123/127] Translated using Weblate (Esperanto) Currently translated at 93.0% (522 of 561 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eo/ --- locales/eo.json | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/locales/eo.json b/locales/eo.json index c78bf6269..720485ba6 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -40,7 +40,7 @@ "app_argument_choice_invalid": "Uzu unu el ĉi tiuj elektoj '{choices:s}' por la argumento '{name:s}'", "app_argument_invalid": "Elektu validan valoron por la argumento '{name:s}': {error:s}", "app_change_url_failed_nginx_reload": "Ne eblis reŝarĝi NGINX. Jen la eligo de 'nginx -t':\n{nginx_errors:s}", - "appslist_url_already_tracked": "Estas jam registrita aplika listo kun la URL {url:s}.", + "appslist_url_already_tracked": "Jam ekzistas registrita app-listo kun la URL {url:s}.", "ask_new_admin_password": "Nova administrada pasvorto", "app_action_broke_system": "Ĉi tiu ago ŝajne rompis ĉi tiujn gravajn servojn: {services}", "app_unsupported_remote_type": "Malkontrolita fora speco uzita por la apliko", @@ -50,16 +50,16 @@ "backup_abstract_method": "Ĉi tiu rezerva metodo ankoraŭ efektiviĝis", "apps_already_up_to_date": "Ĉiuj aplikoj estas jam ĝisdatigitaj", "backup_borg_not_implemented": "La kopia metodo de Borg ankoraŭ ne estas efektivigita", - "app_upgrade_stopped": "La ĝisdatigo de ĉiuj aplikoj estis ĉesigita por eviti eblajn damaĝojn ĉar la antaŭa apliko ne sukcesis ĝisdatigi", + "app_upgrade_stopped": "Ĝisdatigi ĉiujn aplikaĵojn estis ĉesigita por eviti eblajn damaĝojn ĉar unu app ne povis esti altgradigita", "app_location_unavailable": "Ĉi tiu URL aŭ ne haveblas, aŭ konfliktas kun la jam instalita (j) apliko (j):\n{apps:s}", "backup_archive_app_not_found": "Ne povis trovi la programon '{app:s}' en la rezerva ar archiveivo", "backup_actually_backuping": "Krei rezervan ar archiveivon el la kolektitaj dosieroj …", "backup_method_borg_finished": "Sekurkopio en Borg finiĝis", - "appslist_removed": "{appslist:s} aplika listo forigita", + "appslist_removed": "La listo de '{appslist:s}' estis forigita", "app_change_url_no_script": "La app '{app_name:s}' ankoraŭ ne subtenas URL-modifon. Eble vi devus altgradigi ĝin.", - "app_start_install": "Instalanta aplikon {app} …", + "app_start_install": "Instali la programon '{app}' …", "backup_created": "Sekurkopio kreita", - "app_make_default_location_already_used": "Ne povas igi la aplikon '{app}' defaŭlta sur la domajno, {domain} jam uziĝas de la alia app '{other_app}'", + "app_make_default_location_already_used": "Ne povas igi la aplikon '{app}' defaŭlta sur la domajno, '{domain}' jam uziĝas de la alia app '{other_app}'", "backup_method_copy_finished": "Rezerva kopio finis", "app_not_properly_removed": "{app:s} ne estis ĝuste forigita", "backup_archive_broken_link": "Ne povis aliri la rezervan ar archiveivon (rompita ligilo al {path:s})", @@ -78,15 +78,15 @@ "backup_custom_backup_error": "Propra rezerva metodo ne povis preterpasi la paŝon \"sekurkopio\"", "ask_main_domain": "Ĉefa domajno", "backup_method_tar_finished": "TAR-rezerva ar archiveivo kreita", - "appslist_unknown": "Aplika listo {appslist:s} nekonata.", + "appslist_unknown": "La app-listo '{appslist:s}' estas nekonata.", "ask_list_to_remove": "Listo por forigi", "backup_cant_mount_uncompress_archive": "Ne povis munti la nekompresitan ar archiveivon kiel protektita kontraŭ skribo", - "appslist_retrieve_bad_format": "Ne povis legi la elprenitan liston {appslist:s}", + "appslist_retrieve_bad_format": "Ne povis legi la elprenitan liston '{appslist:s}'", "appslist_corrupted_json": "Ne povis ŝarĝi la aplikajn listojn. Ĝi aspektas kiel {filename:s} estas damaĝita.", "app_action_cannot_be_ran_because_required_services_down": "Ĉi tiuj postulataj servoj devas funkcii por funkciigi ĉi tiun agon: {services}. Provu rekomenci ilin por daŭrigi (kaj eble esploru, kial ili malsupreniras).", "backup_copying_to_organize_the_archive": "Kopiante {size:s} MB por organizi la ar archiveivon", "backup_output_directory_forbidden": "Elektu malsaman elirejan dosierujon. Sekurkopioj ne povas esti kreitaj en sub-dosierujoj / bin, / boot, / dev, / ktp, / lib, / root, / run, / sbin, / sys, / usr, / var aŭ /home/yunohost.backup/archives", - "appslist_could_not_migrate": "Ne povis migri la liston de aplikoj {appslist:s}! Ne eblis analizi la URL ... La malnova cron-laboro konserviĝis en {bkp_file:s}.", + "appslist_could_not_migrate": "Ne povis migri la liston de aplikoj '{appslist:s}'! Ne eblis analizi la URL ... La malnova cron-laboro konserviĝis en {bkp_file:s}.", "app_requirements_failed": "Certaines exigences ne sont pas remplies pour {app}: {error}", "backup_no_uncompress_archive_dir": "Ne ekzistas tia nekompremita arkiva dosierujo", "password_too_simple_1": "Pasvorto devas esti almenaŭ 8 signojn longa", @@ -94,11 +94,11 @@ "app_upgrade_several_apps": "La sekvaj apliko estos altgradigitaj: {apps}", "backup_archive_open_failed": "Ne povis malfermi la rezervan ar archiveivon", "ask_lastname": "Familia nomo", - "app_start_backup": "Kolekti dosierojn por esti subtenata por {app} …", + "app_start_backup": "Kolekti dosierojn por esti subtenata por la '{app}' …", "backup_archive_name_exists": "Rezerva arkivo kun ĉi tiu nomo jam ekzistas.", "backup_applying_method_tar": "Krei la rezervan TAR-ar archiveivon …", "backup_method_custom_finished": "Propra rezerva metodo '{metodo:s}' finiĝis", - "appslist_retrieve_error": "Ne eblas retrovi la forajn aplikajn listojn {appslist:s}: {eraro:s}", + "appslist_retrieve_error": "Ne eblas akiri la forajn listojn '{appslist:s}': {eraro:s}", "app_already_installed_cant_change_url": "Ĉi tiu app estas jam instalita. La URL ne povas esti ŝanĝita nur per ĉi tiu funkcio. Rigardu \"app changeurl\" se ĝi haveblas.", "app_not_correctly_installed": "{app:s} ŝajnas esti malĝuste instalita", "app_removed": "{app:s} forigita", @@ -106,27 +106,27 @@ "app_package_need_update": "La pakaĵo {app} devas esti ĝisdatigita por sekvi YunoHost-ŝanĝojn", "backup_nothings_done": "Nenio por ŝpari", "backup_applying_method_custom": "Nomante la kutiman rezervan metodon '{metodo:s}' …", - "appslist_fetched": "Ĝisdatigita aplika listo {appslist:s}", + "appslist_fetched": "Ĝisdatigis la liston de aplikoj '{appslist:s}'", "backup_app_failed": "Ne eblis rezervi la programon '{app:s}'", "app_upgrade_some_app_failed": "Iuj aplikoj ne povis esti altgradigitaj", - "app_start_remove": "Forigo de apliko {app} …", + "app_start_remove": "Forigo de la apliko '{app}' …", "backup_output_directory_not_empty": "Vi devas elekti malplenan eligitan dosierujon", "backup_archive_writing_error": "Ne povis aldoni la dosierojn '{source:s}' (nomitaj en la ar theivo '{dest:s}') por esti rezervitaj en la kunpremita arkivo '{archive:s}'", "ask_email": "Retpoŝta adreso", - "app_start_restore": "Restarigi aplikon {app} …", + "app_start_restore": "Restarigi la programon '{app}' …", "backup_applying_method_copy": "Kopiante ĉiujn dosierojn al sekurkopio …", "backup_couldnt_bind": "Ne povis ligi {src:s} al {dest:s}.", "ask_password": "Pasvorto", "app_requirements_unmeet": "Postuloj ne estas renkontitaj por {app}, la pakaĵo {pkgname} ({version}) devas esti {spec}", "ask_firstname": "Antaŭnomo", - "backup_ask_for_copying_if_needed": "Iuj dosieroj ne povus esti pretigitaj por sekurkopio uzante la metodon, kiu evitas portempe malŝpari spacon en la sistemo. Por plenumi la sekurkopion, {size:s} MB estos provizore. Ĉu vi konsentas?", + "backup_ask_for_copying_if_needed": "Ĉu vi volas realigi la sekurkopion uzante {size:s} MB provizore? (Ĉi tiu maniero estas uzata ĉar iuj dosieroj ne povus esti pretigitaj per pli efika metodo.)", "backup_mount_archive_for_restore": "Preparante arkivon por restarigo …", - "appslist_migrating": "Migra aplika listo {appslist:s} …", + "appslist_migrating": "Migrado de la aplika listo '{appslist:s}' …", "backup_csv_creation_failed": "Ne povis krei la CSV-dosieron bezonatan por restarigo", "backup_archive_name_unknown": "Nekonata loka rezerva ar archiveivo nomata '{name:s}'", "backup_applying_method_borg": "Sendado de ĉiuj dosieroj al sekurkopio en borg-rezerva deponejo …", "app_sources_fetch_failed": "Ne povis akiri fontajn dosierojn, ĉu la URL estas ĝusta?", - "appslist_name_already_tracked": "Registrita aplika listo kun nomo {name:s} jam ekzistas.", + "appslist_name_already_tracked": "Registrita aplika listo kun la nomo {name:s} jam ekzistas.", "ask_new_domain": "Nova domajno", "app_unknown": "Nekonata apliko", "app_not_upgraded": "La aplikaĵo '{failed_app}' ne ĝisdatigis, kaj pro tio la sekvaj ĝisdatigoj de aplikoj estis nuligitaj: {apps}", @@ -271,11 +271,11 @@ "update_apt_cache_failed": "Ne eblis ĝisdatigi la kaŝmemoron de APT (paka administranto de Debian). Jen rubujo de la sources.list-linioj, kiuj povus helpi identigi problemajn liniojn:\n{sourcelist}", "migrations_no_migrations_to_run": "Neniuj migradoj por funkcii", "executing_command": "Plenumanta komandon '{command:s}' …", - "diagnosis_no_apps": "Neniu instalita apliko", + "diagnosis_no_apps": "Neniu tia instalita app", "certmanager_attempt_to_renew_nonLE_cert": "La atestilo por la domajno '{domain:s}' ne estas elsendita de Let's Encrypt. Ne eblas renovigi ĝin aŭtomate!", "global_settings_setting_example_bool": "Ekzemplo bulea elekto", "domain_dyndns_already_subscribed": "Vi jam abonis DynDNS-domajnon", - "log_letsencrypt_cert_renew": "Renovigu '{}' Ni ĉifru atestilon", + "log_letsencrypt_cert_renew": "Renovigu '{}' Let's Encrypt atestilon", "migrate_tsig_start": "Detektita ŝlosila algoritmo nesufiĉa por TSIG-subskribo de la domajno '{domain}', komencanta migradon al la pli sekura HMAC-SHA-512", "ldap_init_failed_to_create_admin": "LDAP-iniciato ne povis krei administran uzanton", "backup_output_directory_required": "Vi devas provizi elirejan dosierujon por la sekurkopio", @@ -381,7 +381,7 @@ "regenconf_file_kept_back": "La agorda dosiero '{conf}' estas atendita forigi per regen-conf (kategorio {category}), sed ĝi estis konservita.", "migrate_tsig_wait_4": "30 sekundoj …", "backup_with_no_restore_script_for_app": "La apliko \"{app:s}\" ne havas restarigan skripton, vi ne povos aŭtomate restarigi la sekurkopion de ĉi tiu apliko.", - "log_letsencrypt_cert_install": "Instalu atestilon Ni ĉifru sur '{}' regado", + "log_letsencrypt_cert_install": "Instalu atestilon Let's Encrypt sur '{}' regado", "log_dyndns_update": "Ĝisdatigu la IP asociita kun via subdominio YunoHost '{}'", "firewall_reload_failed": "Ne eblis reŝargi la firewall", "confirm_app_install_warning": "Averto: Ĉi tiu aplikaĵo povas funkcii, sed ne bone integras en YunoHost. Iuj funkcioj kiel ekzemple aliĝilo kaj sekurkopio / restarigo eble ne haveblos. Instali ĉiuokaze? [{answers: s}] ", @@ -393,7 +393,7 @@ "migrations_need_to_accept_disclaimer": "Por funkciigi la migradon {id}, via devas akcepti la sekvan malakcepton:\n---\n{malavantaĝo}\n---\nSe vi akceptas funkcii la migradon, bonvolu rekonduki la komandon kun la opcio '--accept-disclaimer'.", "regenconf_file_remove_failed": "Ne povis forigi la agordodosieron '{conf}'", "not_enough_disk_space": "Ne sufiĉe libera spaco sur '{path:s}'", - "migration_0006_disclaimer": "YunoHost nun atendas ke pasvortoj kaj administrantoj estu sinkronigitaj. Per ekzekuto de ĉi tiu migrado, via radika pasvorto estos anstataŭigita per administra pasvorto.", + "migration_0006_disclaimer": "YunoHost nun atendas, ke la pasvortoj de admin kaj radiko estos sinkronigitaj. Ĉi tiu migrado anstataŭigas vian radikan pasvorton kun la administran pasvorton.", "dyndns_ip_update_failed": "Ne povis ĝisdatigi IP-adreson al DynDNS", "migration_description_0004_php5_to_php7_pools": "Rekonfigu la PHP-naĝejojn por uzi PHP 7 anstataŭ 5", "monitor_glances_con_failed": "Ne povis konektiĝi al servilo de Glances", @@ -422,7 +422,7 @@ "migration_0003_general_warning": "Bonvolu noti, ke ĉi tiu migrado estas delikata operacio. La teamo de YunoHost faris sian plej bonan revizii kaj testi ĝin, sed la migrado eble ankoraŭ rompos partojn de la sistemo aŭ ĝiaj programoj.\n\nTial oni rekomendas al:\n - Elfari kopion de iuj kritikaj datumoj aŭ app. Pliaj informoj pri https://yunohost.org/backup;\n - Paciencu post lanĉo de la migrado: Depende de via interreta konekto kaj aparataro, eble daŭros kelkaj horoj ĝis ĉio ĝisdatigi.\n\nAldone, la haveno por SMTP, uzata de eksteraj retpoŝtaj klientoj (kiel Thunderbird aŭ K9-Mail) estis ŝanĝita de 465 (SSL / TLS) al 587 (STARTTLS). La malnova haveno (465) aŭtomate fermiĝos, kaj la nova haveno (587) malfermiĝos en la fajrejo. Vi kaj viaj uzantoj * devos adapti la agordon de viaj retpoŝtaj klientoj laŭe.", "diagnosis_kernel_version_error": "Ne povis akiri la kernan version: {error}", "global_settings_setting_example_int": "Ekzemple int elekto", - "backup_output_symlink_dir_broken": "Vi havas rompitan simbolon anstataŭ via arkiva dosierujo '{path:s}'. Vi eble havas specifan agordon por sekurkopi viajn datumojn en alia dosiersistemo, ĉi-kaze vi probable forgesis remeti aŭ enŝovi vian malmolan disko aŭ ŝlosilon USB.", + "backup_output_symlink_dir_broken": "Via arkiva dosierujo '{path:s}' estas rompita ligilo. Eble vi forgesis restarigi aŭ munti aŭ enŝovi la stokadon, al kiu ĝi notas.", "good_practices_about_admin_password": "Vi nun estas por difini novan administran pasvorton. La pasvorto devas esti almenaŭ 8 signoj - kvankam estas bone praktiki uzi pli longan pasvorton (t.e. pasfrazon) kaj / aŭ uzi variaĵon de signoj (majuskloj, minuskloj, ciferoj kaj specialaj signoj).", "certmanager_attempt_to_renew_valid_cert": "La atestilo por la domajno '{domain:s}' ne finiĝos! (Vi eble uzos --force se vi scias kion vi faras)", "restore_running_hooks": "Kurantaj restarigaj hokoj…", @@ -431,7 +431,7 @@ "domain_dns_conf_is_just_a_recommendation": "Ĉi tiu komando montras al vi la *rekomenditan* agordon. Ĝi efektive ne agordas la DNS-agordon por vi. Via respondeco agordi vian DNS-zonon en via registristo laŭ ĉi tiu rekomendo.", "backup_php5_to_php7_migration_may_fail": "Ne povis konverti vian ar archiveivon por subteni PHP 7, vi eble ne povas restarigi viajn PHP-programojn (kialo: {error:s})", "log_backup_restore_system": "Restarigi sistemon de rezerva arkivo", - "log_app_change_url": "Ŝanĝu la URL de apliko '{}'", + "log_app_change_url": "Ŝanĝu la URL de la apliko '{}'", "service_already_started": "La servo '{service:s}' estas jam komencita", "license_undefined": "nedifinita", "global_settings_setting_security_password_admin_strength": "Admin pasvorta forto", @@ -526,7 +526,7 @@ "password_too_simple_2": "La pasvorto bezonas almenaŭ 8 signojn kaj enhavas ciferon, majusklojn kaj minusklojn", "executing_script": "Plenumanta skripto '{script:s}' …", "service_cmd_exec_failed": "Ne povis plenumi la komandon '{command:s}'", - "migration_0007_cancelled": "YunoHost ne plibonigis la administradon de via SSH-konf.", + "migration_0007_cancelled": "Ne povis plibonigi la manieron kiel via SSH-agordo estas administrita.", "migrate_tsig_failed": "Ne povis migri la DynDNS-domajnon '{domain}' al HMAC-SHA-512, ruliĝante. Eraro: {error_code}, {error}", "pattern_lastname": "Devas esti valida familinomo", "service_enabled": "'{service:s}' servo malŝaltita", @@ -553,7 +553,7 @@ "service_restart_failed": "Ne povis rekomenci la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}", "firewall_rules_cmd_failed": "Iuj komandoj pri fajroŝirmilo malsukcesis. Pliaj informoj en ensaluto.", "certmanager_certificate_fetching_or_enabling_failed": "Provante uzi la novan atestilon por {domain:s} ne funkciis …", - "app_full_domain_unavailable": "Bedaŭrinde, ĉi tiu apliko postulas plenan domajnon esti instalita, sed iuj aliaj programoj jam estas instalitaj sur '{domain}'. Unu ebla solvo estas aldoni kaj uzi subdomajnon dediĉitan al ĉi tiu aplikaĵo anstataŭe.", + "app_full_domain_unavailable": "Bedaŭrinde, ĉi tiu app devas esti instalita sur propra domajno, sed aliaj programoj jam estas instalitaj sur la domajno '{domain}'. Vi povus uzi subdominon dediĉitan al ĉi tiu app anstataŭe.", "migration_0011_slapd_config_will_be_overwritten": "Ŝajnas ke vi permane redaktis la slapd-agordon. Por ĉi tiu kritika migrado, YunoHost bezonas devigi la ĝisdatigon de la slapd-agordo. La originalaj dosieroj estos rezervitaj en {conf_backup_folder}.", "group_cannot_edit_all_users": "La grupo 'all_users' ne povas esti redaktita permane. Ĝi estas speciala grupo celita enhavi ĉiujn uzantojn registritajn en YunoHost", "group_cannot_edit_visitors": "La grupo 'vizitantoj' ne povas esti redaktita permane. Ĝi estas speciala grupo reprezentanta anonimajn vizitantojn", From 40f48ff25ce1b76294d2d830b7237b898ed83d50 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 29 Oct 2019 21:38:43 +0100 Subject: [PATCH 124/127] zzzzz previous commit broke the info for apps, only system infos were affected --- src/yunohost/backup.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index 3f253c7ff..213f2cec1 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -2374,11 +2374,13 @@ def backup_info(name, with_details=False, human_readable=False): for category in ["apps", "system"]: for name, key_info in info[category].items(): - # Stupid legacy fix for weird format between 3.5 and 3.6 - if isinstance(key_info, dict): - key_info = key_info.keys() - - info[category][name] = key_info = {"paths": key_info} + if category == "system": + # Stupid legacy fix for weird format between 3.5 and 3.6 + if isinstance(key_info, dict): + key_info = key_info.keys() + info[category][name] = key_info = {"paths": key_info} + else: + info[category][name] = key_info if name in info["size_details"][category].keys(): key_info["size"] = info["size_details"][category][name] From 3f80fe4e932708820ccd180f861e99f52f331592 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 31 Oct 2019 18:14:20 +0100 Subject: [PATCH 125/127] Update changelog for 3.7.0 testing --- debian/changelog | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/debian/changelog b/debian/changelog index 45dbadef5..15b3c049c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,46 @@ +yunohost (3.7.0) testing; urgency=low + + # ~ Major stuff + + - [enh] Add group and permission mechanism (YunoHost#585, YunoHost#763, YunoHost#789, YunoHost#790, YunoHost#795, YunoHost#797, SSOwat#147, Moulinette#189, YunoHost-admin#257) + - [mod] Rework migration system to have independent migrations (YunoHost#768, YunoHost#774, YunoHost-admin#258) + - [enh] Many improvements in the way app action failures are handled (YunoHost#769, YunoHost#811) + - [enh] Improve checks for system anomalies after app operations (YunoHost#785) + - [mod] Spookier warnings for dangerous app installs (YunoHost#814, Moulinette/808f620) + - [enh] Support app manifests in toml (YunoHost#748, Moulinette#204, Moulinette/55515cb) + - [mod] Get rid of etckeeper (YunoHost#803) + - [enh] Quite a lot of messages improvements, string cleaning, language rework... (YunoHost#793, YunoHost#799, YunoHost#823, SSOwat#143, YunoHost#766, YunoHost#767, YunoHost/fd99ef0, YunoHost/92a6315, YunoHost-admin/10ea04a, Moulinette/599bec3, Moulinette#208, Moulinette#213, Moulinette/b7d415d, Moulinette/a8966b8, Moulinette/fdf9a71, Moulinette/d895ae3, Moulinette/bdf0a1c, YunoHost#817, YunoHost#823, YunoHost/79627d7, YunoHost/9ee3d23, YunoHost-admin#265) + - [i18n] Improved translations for Catalan, Occitan, French, Esperanto, Arabic, German, Spanish, Norwegian Bokmål, Portuguese + + # Smaller or pretty technical fix/enh + + - [enh] Add unit/functional tests for apps + improve other tests (YunoHost#779, YunoHost#808) + - [enh] Preparations for moulinette Python3 migration (Tox, Pytest and unit tests) (Moulinette#203, Moulinette#206, Moulinette#207, Moulinette#210, Moulinette#211 Moulinette#212, Moulinette/2403ee1, Moulinette/69b0d49, Moulinette/49c749c, Moulinette/2c84ee1, Moulinette/cef72f7, YunoHost/6365a26) + - [enh] Support python hooks (YunoHost#747) + - [enh] Upgrade n version + compatibility with arm64 (YunoHost#753) + - [enh] Add OpenLDAP TLS support (YunoHost#755, YunoHost/0a2d1c7, YunoHost/2dc8095) + - [enh] Improve PostgreSQL password security (YunoHost#762) + - [enh] Integrate actions/config-panel into operation logs (YunoHost#764) + - [mod] Assume that apps without any 'path' setting defined aren't webapps (YunoHost#765) + - [fix] Set dpkg vendor to YunoHost (YunoHost#749, YunoHost#772) + - [enh] Adding variable 'token' to data to redact from logs (YunoHost#783) + - [enh] Add --force and --dry-run options to 'yunohost dyndns update' (YunoHost#786) + - [fix] Don't throw a fatal error if we can't change the hostname (YunoHost/fe3ecd7) + - [enh] Dynamically evaluate proper mariadb-server- (YunoHost/f0440fb) + - [fix] Bad format for backup info.json ... (YunoHost/7d0119a) + - [fix] Inline buttons responsiveness on migration screen (YunoHost-admin#259) + - [enh] Add debug logs to SSOwat (SSOwat#145) + - [enh] Add a write_to_yaml utility similar to write_to_json (Moulinette/2e2e627) + - [enh] Warn the user about long locks (Moulinette#205) + - [mod] Tweak stuff about setuptools and moulinette deps? (Moulinette/b739f27, Moulinette/da00fc9, Moulinette/d8cbbb0) + - [fix] Misc micro bugfixes or improvements (YunoHost#743, YunoHost#792, YunoHost/6f48d1d, YunoHost/d516cf8, YunoHost#819, Moulinette/83d9e77, YunoHost/63d364e, YunoHost/68e9724, YunoHost/0849adb, YunoHost/19dbe87, YunoHost/61931f2, YunoHost/6dc720f, YunoHost/4def4df, SSOwat#140, SSOwat#141, YunoHost#829) + - [doc] Fix doc building + add doc build tests with Tox (Moulinette/f1ac5b8, Moulinette/df7d478, Moulinette/74c8f79, Moulinette/bcf92c7, Moulinette/af2c80c, Moulinette/d52a574, Moulinette/307f660, Moulinette/dced104, Moulinette/ed3823b) + - [enh] READMEs improvements (YunoHost/b3398e7, SSOwat/ee67b6f, Moulinette/1541b74, Moulinette/ad1eeef, YunoHost/25afdd4, YunoHost/73741f6) + + Thanks to all contributors <3 ! (accross all repo: Yunohost, Moulinette, SSOwat, Yunohost-admin) : advocatux, Aksel K., Aleks, Allan N., amirale qt, Armin P., Bram, ButterflyOfFire, Carles S. A., chema o. r., decentral1se, Emmanuel V., Etienne M., Filip B., Geoff M., htsr, Jibec, Josué, Julien J., Kayou, liberodark, ljf, lucaskev, Lukas D., madtibo, Martin D., Mélanie C., nr 458 h, pitfd, ppr, Quentí, sidddy, troll, tufek yamero, xaloc33, yalh76 + + -- Alexandre Aubin Thu, 31 Oct 2019 18:00:00 +0000 + yunohost (3.6.5.3) stable; urgency=low - [fix] More general grep for the php/sury dependency nightmare fix (followup of #809) From 089b3cf9739bbce8dfdf38a0a7fe7b88de4d31fc Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 31 Oct 2019 20:36:25 +0100 Subject: [PATCH 126/127] [fix] Sync permissions only after we're done migrating them, otherwise this triggers a shitload of warnings --- src/yunohost/data_migrations/0011_setup_group_permission.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/data_migrations/0011_setup_group_permission.py b/src/yunohost/data_migrations/0011_setup_group_permission.py index 7a987899c..e9ca32294 100644 --- a/src/yunohost/data_migrations/0011_setup_group_permission.py +++ b/src/yunohost/data_migrations/0011_setup_group_permission.py @@ -120,7 +120,7 @@ class MyMigration(Migration): if app_setting(app, "unprotected_uris") == "/" or app_setting(app, "skipped_uris") == "/": user_permission_update(app+".main", remove="all_users", add="visitors", sync_perm=False) - permission_sync_to_user() + permission_sync_to_user() def run(self): From 67a11b5b79689fb4c3ca784f6f0691988d48d523 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 31 Oct 2019 20:37:51 +0100 Subject: [PATCH 127/127] Update changelog for 3.7.0.1 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 15b3c049c..578a8e314 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +yunohost (3.7.0.1) testing; urgency=low + + - Hotfix to avoid having a shitload of warnings displayed during the permission migration + + -- Alexandre Aubin Thu, 31 Oct 2019 20:35:00 +0000 + yunohost (3.7.0) testing; urgency=low # ~ Major stuff