From f790bde1013fc6c5def7705f4b1a6f8f6dfd5032 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 12 Mar 2021 03:14:34 +0100 Subject: [PATCH 01/31] We don't need these wrapper classes, just call HTTPResponse directly --- moulinette/interfaces/api.py | 54 ++++++++++++------------------------ 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/moulinette/interfaces/api.py b/moulinette/interfaces/api.py index a3427a2b..33734f14 100644 --- a/moulinette/interfaces/api.py +++ b/moulinette/interfaces/api.py @@ -252,7 +252,7 @@ class _ActionsMapPlugin(object): try: kwargs["password"] = request.POST["password"] except KeyError: - raise HTTPBadRequestResponse("Missing password parameter") + raise HTTPResponse("Missing password parameter", 400) kwargs["profile"] = request.POST.get("profile", "default") return callback(**kwargs) @@ -387,7 +387,7 @@ class _ActionsMapPlugin(object): self.logout(profile) except: pass - raise HTTPUnauthorizedResponse(e.strerror) + raise HTTPResponse(e.strerror, 401) else: # Update dicts with new values s_tokens[profile] = s_new_token @@ -420,7 +420,7 @@ class _ActionsMapPlugin(object): if profile not in request.get_cookie( "session.tokens", secret=s_secret, default={} ): - raise HTTPUnauthorizedResponse(m18n.g("not_logged_in")) + raise HTTPResponse(m18n.g("not_logged_in"), 401) else: del self.secrets[s_id] authenticator = self.actionsmap.get_authenticator_for_profile(profile) @@ -448,7 +448,7 @@ class _ActionsMapPlugin(object): wsock = request.environ.get("wsgi.websocket") if not wsock: - raise HTTPErrorResponse(m18n.g("websocket_request_expected")) + raise HTTPResponse(m18n.g("websocket_request_expected"), 500) while True: item = queue.get() @@ -484,7 +484,7 @@ class _ActionsMapPlugin(object): try: ret = self.actionsmap.process(arguments, timeout=30, route=_route) except MoulinetteError as e: - raise HTTPBadRequestResponse(e) + raise moulinette_error_to_http_response(e) except Exception as e: if isinstance(e, HTTPResponse): raise e @@ -492,7 +492,7 @@ class _ActionsMapPlugin(object): tb = traceback.format_exc() logs = {"route": _route, "arguments": arguments, "traceback": tb} - return HTTPErrorResponse(json_encode(logs)) + return HTTPResponse(json_encode(logs), 500) else: return format_for_response(ret) finally: @@ -520,7 +520,7 @@ class _ActionsMapPlugin(object): ] except KeyError: msg = m18n.g("authentication_required") - raise HTTPUnauthorizedResponse(msg) + raise HTTPResponse(msg, 401) else: return authenticator(token=(s_id, s_token)) @@ -546,37 +546,17 @@ class _ActionsMapPlugin(object): # HTTP Responses ------------------------------------------------------- +def moulinette_error_to_http_response(self): -class HTTPOKResponse(HTTPResponse): - def __init__(self, output=""): - super(HTTPOKResponse, self).__init__(output, 200) - - -class HTTPBadRequestResponse(HTTPResponse): - def __init__(self, error=""): - - if isinstance(error, MoulinetteError): - content = error.content() - if isinstance(content, dict): - super(HTTPBadRequestResponse, self).__init__( - json_encode(content), - 400, - headers={"Content-type": "application/json"}, - ) - else: - super(HTTPBadRequestResponse, self).__init__(content, 400) - else: - super(HTTPBadRequestResponse, self).__init__(error, 400) - - -class HTTPUnauthorizedResponse(HTTPResponse): - def __init__(self, output=""): - super(HTTPUnauthorizedResponse, self).__init__(output, 401) - - -class HTTPErrorResponse(HTTPResponse): - def __init__(self, output=""): - super(HTTPErrorResponse, self).__init__(output, 500) + content = error.content() + if isinstance(content, dict): + return HTTPResponse( + json_encode(content), + 400, + headers={"Content-type": "application/json"}, + ) + else: + return HTTPResponse(content, 400) def format_for_response(content): From d6f82c91b8a6f2ed7ceb840152fcee4af878dd01 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 12 Mar 2021 03:18:36 +0100 Subject: [PATCH 02/31] These doc generators havent been updated in 6 years and most likely ain't used / relevant anymore ... --- generate_api_doc.py | 181 --------------------------------------- generate_function_doc.py | 114 ------------------------ 2 files changed, 295 deletions(-) delete mode 100644 generate_api_doc.py delete mode 100644 generate_function_doc.py diff --git a/generate_api_doc.py b/generate_api_doc.py deleted file mode 100644 index d4a006fe..00000000 --- a/generate_api_doc.py +++ /dev/null @@ -1,181 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" License - - Copyright (C) 2013 YunoHost - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program; if not, see http://www.gnu.org/licenses - -""" - -""" - Generate JSON specification files API -""" -import os -import sys -import yaml -import json -import requests -from yunohost import str_to_func, __version__ - -def main(): - """ - - """ - with open('action_map.yml') as f: - action_map = yaml.load(f) - - try: - with open('/etc/yunohost/current_host', 'r') as f: - domain = f.readline().rstrip() - except IOError: - domain = requests.get('http://ip.yunohost.org').text - - with open('action_map.yml') as f: - action_map = yaml.load(f) - - resource_list = { - 'apiVersion': __version__, - 'swaggerVersion': '1.1', - 'basePath': 'http://'+ domain + ':6767', - 'apis': [] - } - - resources = {} - - del action_map['general_arguments'] - for category, category_params in action_map.items(): - if 'category_help' not in category_params: category_params['category_help'] = '' - resource_path = '/api/'+ category - resource_list['apis'].append({ - 'path': resource_path, - 'description': category_params['category_help'] - }) - resources[category] = { - 'apiVersion': __version__, - 'swaggerVersion': '1.1', - 'basePath': 'http://'+ domain + ':6767', - 'apis': [] - } - - resources[category]['resourcePath'] = resource_path - - registered_paths = {} - - for action, action_params in category_params['actions'].items(): - if 'action_help' not in action_params: - action_params['action_help'] = '' - if 'api' not in action_params: - action_params['api'] = 'GET /'+ category +'/'+ action - - method, path = action_params['api'].split(' ') - key_param = '' - if '{' in path: - key_param = path[path.find("{")+1:path.find("}")] - - notes = '' - if str_to_func('yunohost_'+ category +'.'+ category +'_'+ action) is None: - notes = 'Not yet implemented' - - operation = { - 'httpMethod': method, - 'nickname': category +'_'+ action, - 'summary': action_params['action_help'], - 'notes': notes, - 'errorResponses': [] - } - - if 'arguments' in action_params: - operation['parameters'] = [] - for arg_name, arg_params in action_params['arguments'].items(): - if 'help' not in arg_params: - arg_params['help'] = '' - param_type = 'query' - allow_multiple = False - required = True - allowable_values = None - name = arg_name.replace('-', '_') - if name[0] == '_': - required = False - if 'full' in arg_params: - name = arg_params['full'][2:] - else: - name = name[2:] - name = name.replace('-', '_') - - if 'nargs' in arg_params: - if arg_params['nargs'] == '*': - allow_multiple = True - required = False - if arg_params['nargs'] == '+': - allow_multiple = True - required = True - else: - allow_multiple = False - if 'choices' in arg_params: - allowable_values = { - 'valueType': 'LIST', - 'values': arg_params['choices'] - } - if 'action' in arg_params and arg_params['action'] == 'store_true': - allowable_values = { - 'valueType': 'LIST', - 'values': ['true', 'false'] - } - - if name == key_param: - param_type = 'path' - required = True - allow_multiple = False - - parameters = { - 'paramType': param_type, - 'name': name, - 'description': arg_params['help'], - 'dataType': 'string', - 'required': required, - 'allowMultiple': allow_multiple - } - if allowable_values is not None: - parameters['allowableValues'] = allowable_values - - operation['parameters'].append(parameters) - - - if path in registered_paths: - resources[category]['apis'][registered_paths[path]]['operations'].append(operation) - resources[category]['apis'][registered_paths[path]]['description'] = '' - else: - registered_paths[path] = len(resources[category]['apis']) - resources[category]['apis'].append({ - 'path': path, - 'description': action_params['action_help'], - 'operations': [operation] - }) - - - try: os.listdir(os.getcwd() +'/doc') - except OSError: os.makedirs(os.getcwd() +'/doc') - - for category, api_dict in resources.items(): - with open(os.getcwd() +'/doc/'+ category +'.json', 'w') as f: - json.dump(api_dict, f) - - with open(os.getcwd() +'/doc/resources.json', 'w') as f: - json.dump(resource_list, f) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/generate_function_doc.py b/generate_function_doc.py deleted file mode 100644 index 66b63d8c..00000000 --- a/generate_function_doc.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" License - - Copyright (C) 2013 YunoHost - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program; if not, see http://www.gnu.org/licenses - -""" - -""" - Generate function header documentation -""" -import os -import sys -import yaml -import re - -def main(): - """ - - """ - with open('action_map.yml') as f: - action_map = yaml.load(f) - - resources = {} - - del action_map['general_arguments'] - for category, category_params in action_map.items(): - if 'category_help' not in category_params: category_params['category_help'] = '' - - with open('yunohost_'+ category +'.py', 'r') as f: - lines = f.readlines() - with open('yunohost_'+ category +'.py', 'w') as f: - in_block = False - for line in lines: - if in_block: - if re.search(r'^"""', line): - in_block = False - f.write('\n') - f.write(' '+ category_params['category_help'] +'\n') - f.write('"""\n') - else: - f.write(line) - - if re.search(r'^""" yunohost_'+ category, line): - in_block = True - - for action, action_params in category_params['actions'].items(): - if 'action_help' not in action_params: - action_params['action_help'] = '' - - help_lines = [ - ' """', - ' '+ action_params['action_help'], - '' - ] - - if 'arguments' in action_params: - help_lines.append(' Keyword argument:') - for arg_name, arg_params in action_params['arguments'].items(): - if 'help' in arg_params: - help = ' -- '+ arg_params['help'] - else: - help = '' - name = arg_name.replace('-', '_') - if name[0] == '_': - required = False - if 'full' in arg_params: - name = arg_params['full'][2:] - else: - name = name[2:] - name = name.replace('-', '_') - - help_lines.append(' '+ name + help) - - help_lines.append('') - help_lines.append(' """') - - with open('yunohost_'+ category +'.py', 'r') as f: - lines = f.readlines() - with open('yunohost_'+ category +'.py', 'w') as f: - in_block = False - first_quotes = True - for line in lines: - if in_block: - if re.search(r'^ """', line): - if first_quotes: - first_quotes = False - else: - in_block = False - for help_line in help_lines: - f.write(help_line +'\n') - else: - f.write(line) - - if re.search(r'^def '+ category +'_'+ action +'\(', line): - in_block = True - - -if __name__ == '__main__': - sys.exit(main()) From bc1bdbb2474cf1b899274e7f034ad13ed6decc3f Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 12 Mar 2021 03:55:52 +0100 Subject: [PATCH 03/31] Introduce validation errors, authentication errors, corresponding http codes --- moulinette/actionsmap.py | 8 ++++---- moulinette/authenticators/__init__.py | 14 +++++++------- moulinette/authenticators/ldap.py | 4 ++-- moulinette/core.py | 12 ++++++++++++ moulinette/interfaces/api.py | 12 ++++++------ moulinette/interfaces/cli.py | 10 +++++----- 6 files changed, 36 insertions(+), 24 deletions(-) diff --git a/moulinette/actionsmap.py b/moulinette/actionsmap.py index d4a5f079..64d00bd7 100644 --- a/moulinette/actionsmap.py +++ b/moulinette/actionsmap.py @@ -14,7 +14,7 @@ from importlib import import_module from moulinette import m18n, msignals from moulinette.cache import open_cachefile from moulinette.globals import init_moulinette_env -from moulinette.core import MoulinetteError, MoulinetteLock +from moulinette.core import MoulinetteError, MoulinetteLock, MoulinetteAuthenticationError, MoulinetteValidationError from moulinette.interfaces import BaseActionsMapParser, GLOBAL_SECTION, TO_RETURN_PROP from moulinette.utils.log import start_action_logging @@ -207,7 +207,7 @@ class PatternParameter(_ExtraParameter): if msg == message: msg = m18n.g(message) - raise MoulinetteError("invalid_argument", argument=arg_name, error=msg) + raise MoulinetteValidationError("invalid_argument", argument=arg_name, error=msg) return arg_value @staticmethod @@ -238,7 +238,7 @@ class RequiredParameter(_ExtraParameter): def __call__(self, required, arg_name, arg_value): if required and (arg_value is None or arg_value == ""): logger.warning("argument '%s' is required", arg_name) - raise MoulinetteError("argument_required", argument=arg_name) + raise MoulinetteValidationError("argument_required", argument=arg_name) return arg_value @staticmethod @@ -497,7 +497,7 @@ class ActionsMap(object): auth = msignals.authenticate(authenticator) if not auth.is_authenticated: - raise MoulinetteError("authentication_required_long") + raise MoulinetteAuthenticationError("authentication_required_long") def process(self, args, timeout=None, **kwargs): """ diff --git a/moulinette/authenticators/__init__.py b/moulinette/authenticators/__init__.py index 0170d345..e004db0a 100644 --- a/moulinette/authenticators/__init__.py +++ b/moulinette/authenticators/__init__.py @@ -6,7 +6,7 @@ import hashlib import hmac from moulinette.cache import open_cachefile, get_cachedir, cachefile_exists -from moulinette.core import MoulinetteError +from moulinette.core import MoulinetteError, MoulinetteAuthenticationError logger = logging.getLogger("moulinette.authenticator") @@ -105,7 +105,7 @@ class BaseAuthenticator(object): self.vendor, e, ) - raise MoulinetteError("unable_authenticate") + raise MoulinetteAuthenticationError("unable_authenticate") self.is_authenticated = True @@ -139,7 +139,7 @@ class BaseAuthenticator(object): self.vendor, e, ) - raise MoulinetteError("unable_authenticate") + raise MoulinetteAuthenticationError("unable_authenticate") else: self.is_authenticated = True @@ -147,7 +147,7 @@ class BaseAuthenticator(object): # No credentials given, can't authenticate # else: - raise MoulinetteError("unable_authenticate") + raise MoulinetteAuthenticationError("unable_authenticate") return self @@ -175,7 +175,7 @@ class BaseAuthenticator(object): def _authenticate_session(self, session_id, session_token): """Checks session and token against the stored session token""" if not self._session_exists(session_id): - raise MoulinetteError("session_expired") + raise MoulinetteAuthenticationError("session_expired") try: # FIXME : shouldn't we also add a check that this session file # is not too old ? e.g. not older than 24 hours ? idk... @@ -184,7 +184,7 @@ class BaseAuthenticator(object): stored_hash = f.read() except IOError as e: logger.debug("unable to retrieve session", exc_info=1) - raise MoulinetteError("unable_retrieve_session", exception=e) + raise MoulinetteAuthenticationError("unable_retrieve_session", exception=e) else: # # session_id (or just id) : This is unique id for the current session from the user. Not too important @@ -206,7 +206,7 @@ class BaseAuthenticator(object): hash_ = hashlib.sha256(to_hash).hexdigest() if not hmac.compare_digest(hash_, stored_hash): - raise MoulinetteError("invalid_token") + raise MoulinetteAuthenticationError("invalid_token") else: return diff --git a/moulinette/authenticators/ldap.py b/moulinette/authenticators/ldap.py index 13c635a3..93cf0717 100644 --- a/moulinette/authenticators/ldap.py +++ b/moulinette/authenticators/ldap.py @@ -10,7 +10,7 @@ import time import ldap.modlist as modlist from moulinette import m18n -from moulinette.core import MoulinetteError, MoulinetteLdapIsDownError +from moulinette.core import MoulinetteError, MoulinetteAuthenticationError, MoulinetteLdapIsDownError from moulinette.authenticators import BaseAuthenticator logger = logging.getLogger("moulinette.authenticator.ldap") @@ -86,7 +86,7 @@ class Authenticator(BaseAuthenticator): try: con = _reconnect() except ldap.INVALID_CREDENTIALS: - raise MoulinetteError("invalid_password") + raise MoulinetteAuthenticationError("invalid_password") except ldap.SERVER_DOWN: # ldap is down, attempt to restart it before really failing logger.warning(m18n.g("ldap_server_is_down_restart_it")) diff --git a/moulinette/core.py b/moulinette/core.py index c41b7d21..800b8540 100644 --- a/moulinette/core.py +++ b/moulinette/core.py @@ -382,6 +382,8 @@ class MoulinetteSignals(object): class MoulinetteError(Exception): + http_code = 500 + """Moulinette base exception""" def __init__(self, key, raw_msg=False, *args, **kwargs): @@ -396,6 +398,16 @@ class MoulinetteError(Exception): return self.strerror +class MoulinetteValidationError(MoulinetteError): + + http_code = 400 + + +class MoulinetteAuthenticationError(MoulinetteError): + + http_code = 401 + + class MoulinetteLdapIsDownError(MoulinetteError): """Used when ldap is down""" diff --git a/moulinette/interfaces/api.py b/moulinette/interfaces/api.py index 33734f14..0b333e90 100644 --- a/moulinette/interfaces/api.py +++ b/moulinette/interfaces/api.py @@ -15,7 +15,7 @@ from bottle import abort from moulinette import msignals, m18n, env from moulinette.actionsmap import ActionsMap -from moulinette.core import MoulinetteError +from moulinette.core import MoulinetteError, MoulinetteValidationError from moulinette.interfaces import ( BaseActionsMapParser, BaseInterface, @@ -546,17 +546,17 @@ class _ActionsMapPlugin(object): # HTTP Responses ------------------------------------------------------- -def moulinette_error_to_http_response(self): +def moulinette_error_to_http_response(error): content = error.content() if isinstance(content, dict): return HTTPResponse( json_encode(content), - 400, + error.http_code, headers={"Content-type": "application/json"}, ) else: - return HTTPResponse(content, 400) + return HTTPResponse(content, error.http_code) def format_for_response(content): @@ -673,7 +673,7 @@ class ActionsMapParser(BaseActionsMapParser): e, ) logger.error(error_message) - raise MoulinetteError(error_message, raw_msg=True) + raise MoulinetteValidationError(error_message, raw_msg=True) if self.get_conf(tid, "authenticate"): authenticator = self.get_conf(tid, "authenticator") @@ -702,7 +702,7 @@ class ActionsMapParser(BaseActionsMapParser): except KeyError as e: error_message = "no argument parser found for route '%s': %s" % (route, e) logger.error(error_message) - raise MoulinetteError(error_message, raw_msg=True) + raise MoulinetteValidationError(error_message, raw_msg=True) ret = argparse.Namespace() # TODO: Catch errors? diff --git a/moulinette/interfaces/cli.py b/moulinette/interfaces/cli.py index 19505365..f21cb499 100644 --- a/moulinette/interfaces/cli.py +++ b/moulinette/interfaces/cli.py @@ -13,7 +13,7 @@ import argcomplete from moulinette import msignals, m18n from moulinette.actionsmap import ActionsMap -from moulinette.core import MoulinetteError +from moulinette.core import MoulinetteError, MoulinetteValidationError from moulinette.interfaces import ( BaseActionsMapParser, BaseInterface, @@ -411,7 +411,7 @@ class ActionsMapParser(BaseActionsMapParser): e, ) logger.exception(error_message) - raise MoulinetteError(error_message, raw_msg=True) + raise MoulinetteValidationError(error_message, raw_msg=True) tid = getattr(ret, "_tid", None) if self.get_conf(tid, "authenticate"): @@ -439,7 +439,7 @@ class ActionsMapParser(BaseActionsMapParser): e, ) logger.exception(error_message) - raise MoulinetteError(error_message, raw_msg=True) + raise MoulinetteValidationError(error_message, raw_msg=True) else: self.prepare_action_namespace(getattr(ret, "_tid", None), ret) self._parser.dequeue_callbacks(ret) @@ -490,7 +490,7 @@ class Interface(BaseInterface): """ if output_as and output_as not in ["json", "plain", "none"]: - raise MoulinetteError("invalid_usage") + raise MoulinetteValidationError("invalid_usage") # auto-complete argcomplete.autocomplete(self.actionsmap.parser._parser) @@ -555,7 +555,7 @@ class Interface(BaseInterface): if confirm: m = message[0].lower() + message[1:] if prompt(m18n.g("confirm", prompt=m)) != value: - raise MoulinetteError("values_mismatch") + raise MoulinetteValidationError("values_mismatch") return value From b17a6fa627cac2bd23ae9dd1961d833055921d85 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 23 Mar 2021 00:12:15 +0100 Subject: [PATCH 04/31] Attempt to fix test: handle argparse errors as validation errors --- moulinette/interfaces/api.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/moulinette/interfaces/api.py b/moulinette/interfaces/api.py index 0b333e90..4bb4ef41 100644 --- a/moulinette/interfaces/api.py +++ b/moulinette/interfaces/api.py @@ -207,8 +207,7 @@ class _HTTPArgumentParser(object): return self._parser.dequeue_callbacks(*args, **kwargs) def _error(self, message): - # TODO: Raise a proper exception - raise MoulinetteError(message, raw_msg=True) + raise MoulinetteValidationError(message, raw_msg=True) class _ActionsMapPlugin(object): From e22aac9af09bd9376e44d7f168f6df0ed7660a4a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 23 Mar 2021 00:24:33 +0100 Subject: [PATCH 05/31] Black --- moulinette/actionsmap.py | 11 +++++++++-- moulinette/authenticators/ldap.py | 6 +++++- moulinette/interfaces/api.py | 1 + 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/moulinette/actionsmap.py b/moulinette/actionsmap.py index 64d00bd7..90656e61 100644 --- a/moulinette/actionsmap.py +++ b/moulinette/actionsmap.py @@ -14,7 +14,12 @@ from importlib import import_module from moulinette import m18n, msignals from moulinette.cache import open_cachefile from moulinette.globals import init_moulinette_env -from moulinette.core import MoulinetteError, MoulinetteLock, MoulinetteAuthenticationError, MoulinetteValidationError +from moulinette.core import ( + MoulinetteError, + MoulinetteLock, + MoulinetteAuthenticationError, + MoulinetteValidationError, +) from moulinette.interfaces import BaseActionsMapParser, GLOBAL_SECTION, TO_RETURN_PROP from moulinette.utils.log import start_action_logging @@ -207,7 +212,9 @@ class PatternParameter(_ExtraParameter): if msg == message: msg = m18n.g(message) - raise MoulinetteValidationError("invalid_argument", argument=arg_name, error=msg) + raise MoulinetteValidationError( + "invalid_argument", argument=arg_name, error=msg + ) return arg_value @staticmethod diff --git a/moulinette/authenticators/ldap.py b/moulinette/authenticators/ldap.py index 93cf0717..2cd1dfc2 100644 --- a/moulinette/authenticators/ldap.py +++ b/moulinette/authenticators/ldap.py @@ -10,7 +10,11 @@ import time import ldap.modlist as modlist from moulinette import m18n -from moulinette.core import MoulinetteError, MoulinetteAuthenticationError, MoulinetteLdapIsDownError +from moulinette.core import ( + MoulinetteError, + MoulinetteAuthenticationError, + MoulinetteLdapIsDownError, +) from moulinette.authenticators import BaseAuthenticator logger = logging.getLogger("moulinette.authenticator.ldap") diff --git a/moulinette/interfaces/api.py b/moulinette/interfaces/api.py index 4bb4ef41..9ab34fb2 100644 --- a/moulinette/interfaces/api.py +++ b/moulinette/interfaces/api.py @@ -545,6 +545,7 @@ class _ActionsMapPlugin(object): # HTTP Responses ------------------------------------------------------- + def moulinette_error_to_http_response(error): content = error.content() From d2d008c1fbc5c3467fb0a4a3f1064dfc0cd016d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milo=C5=A1=20Kroul=C3=ADk?= Date: Sat, 23 Jan 2021 21:05:01 +0000 Subject: [PATCH 06/31] Translated using Weblate (Czech) Currently translated at 3.5% (2 of 56 strings) Translation: YunoHost/moulinette Translate-URL: https://translate.yunohost.org/projects/yunohost/moulinette/cs/ --- locales/cs.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/locales/cs.json b/locales/cs.json index c7272b61..b9c7b688 100644 --- a/locales/cs.json +++ b/locales/cs.json @@ -1,3 +1,4 @@ { - "password": "Heslo" + "password": "Heslo", + "logged_out": "Jste odhlášen/a" } From a6547b0a03126ba070a74123fa58612365467048 Mon Sep 17 00:00:00 2001 From: Achal Agrawal Date: Sun, 7 Feb 2021 06:09:58 +0000 Subject: [PATCH 07/31] Translated using Weblate (Hindi) Currently translated at 60.7% (34 of 56 strings) Translation: YunoHost/moulinette Translate-URL: https://translate.yunohost.org/projects/yunohost/moulinette/hi/ --- locales/hi.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/locales/hi.json b/locales/hi.json index 8ddc1a11..4d4d12d9 100644 --- a/locales/hi.json +++ b/locales/hi.json @@ -6,14 +6,14 @@ "colon": "{}: ", "confirm": "पुष्टि करें {prompt}", "deprecated_command": "'{prog}' '{command}' का प्रयोग न करे, भविष्य में इसे हटा दिया जाएगा", - "deprecated_command_alias": "'{prog} {old}' का प्रयोग न करे ,भविष्य में इसे हटा दिया जाएगा।इस की जगह '{prog} {new}' का प्रोयोग करे।", + "deprecated_command_alias": "'{prog} {old}' अब पुराना हो गया है और इसे भविष्य में हटा दिया जाएगा, इस की जगह '{prog} {new}' का प्रयोग करें", "error": "गलती:", "error_see_log": "एक त्रुटि पाई गई। कृपया विवरण के लिए लॉग देखें।", "file_exists": "फ़ाइल पहले से ही मौजूद है:'{path}'", "file_not_exist": "फ़ाइल मौजूद नहीं है: '{path}'", "folder_exists": "फ़ोल्डर में पहले से ही मौजूद है: '{path}'", - "folder_not_exist": "फ़ोल्डर मौजूद नहीं है।", - "instance_already_running": "आवृत्ति पहले से चल रही है।", + "folder_not_exist": "फ़ोल्डर मौजूद नहीं है", + "instance_already_running": "यूनोहोस्ट का एक कार्य पहले से चल रहा है। कृपया इस कार्य के समाप्त होने का इंतज़ार करें।", "invalid_argument": "अवैध तर्क '{argument}':'{error}'", "invalid_password": "अवैध पासवर्ड", "invalid_usage": "अवैध उपयोग, सहायता देखने के लिए --help साथ लिखे।", @@ -35,5 +35,6 @@ "unknown_user": "अज्ञात उपयोगकर्ता: '{user}'", "values_mismatch": "वैल्यूज मेल नहीं खाती।", "warning": "चेतावनी:", - "websocket_request_expected": "एक WebSocket अनुरोध की उम्मीद।" + "websocket_request_expected": "एक WebSocket अनुरोध की उम्मीद।", + "info": "सूचना:" } From aee0224572979f6254188ea7989169d45f0d1422 Mon Sep 17 00:00:00 2001 From: Radek S Date: Sat, 6 Mar 2021 13:36:39 +0000 Subject: [PATCH 08/31] Translated using Weblate (Czech) Currently translated at 100.0% (56 of 56 strings) Translation: YunoHost/moulinette Translate-URL: https://translate.yunohost.org/projects/yunohost/moulinette/cs/ --- locales/cs.json | 56 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/locales/cs.json b/locales/cs.json index b9c7b688..fbf73da8 100644 --- a/locales/cs.json +++ b/locales/cs.json @@ -1,4 +1,58 @@ { "password": "Heslo", - "logged_out": "Jste odhlášen/a" + "logged_out": "Jste odhlášen/a", + "ldap_server_is_down_restart_it": "LDAP služba neběží, probíhá pokus o její nastartování...", + "warn_the_user_that_lock_is_acquired": "Předchozí operace dokončena, nyní spouštíme tuto", + "warn_the_user_about_waiting_lock_again": "Stále čekáme...", + "warn_the_user_about_waiting_lock": "Jiná YunoHost operace právě probíhá, před spuštěním této čekáme na její dokončení", + "command_unknown": "Příkaz '{command:s}' neznámý?", + "download_bad_status_code": "{url:s} vrátil stavový kód {code:s}", + "download_unknown_error": "Chyba při stahování dat z {url:s}: {error:s}", + "download_timeout": "{url:s} příliš dlouho neodpovídá, akce přerušena.", + "download_ssl_error": "SSL chyba při spojení s {url:s}", + "invalid_url": "Špatný odkaz {url:s} (je vůbec dostupný?)", + "error_changing_file_permissions": "Chyba při nastavování oprávnění pro {path:s}: {error:s}", + "error_removing": "Chyba při přesunu {path:s}: {error:s}", + "error_writing_file": "Chyba při zápisu souboru/ů {file:s}: {error:s}", + "corrupted_toml": "Nepodařilo se načíst TOML z {ressource:s} (reason: {error:s})", + "corrupted_yaml": "Nepodařilo se načíst YAML z {ressource:s} (reason: {error:s})", + "corrupted_json": "Nepodařilo se načíst JSON {ressource:s} (reason: {error:s})", + "unknown_error_reading_file": "Vyskytla se neznámá chyba při čtení souboru/ů {file:s} (reason: {error:s})", + "cannot_write_file": "Nelze zapsat soubor/y {file:s} (reason: {error:s})", + "cannot_open_file": "Nelze otevřít soubor/y {file:s} (reason: {error:s})", + "websocket_request_expected": "Očekáván WebSocket požadavek", + "warning": "Varování:", + "values_mismatch": "Hodnoty nesouhlasí", + "unknown_user": "Neznámý '{user}' uživatel", + "unknown_group": "Neznámá '{group}' skupina", + "session_expired": "Sezení vypršelo. Přihlašte se znovu, prosím.", + "unable_retrieve_session": "Není možné obdržet sezení neboť '{exception}'", + "unable_authenticate": "Není možné ověřit", + "success": "Zadařilo se!", + "server_already_running": "Na tomto portu je server již provozován", + "root_required": "Pro provedení této akce musíte být root", + "pattern_not_match": "Neodpovídá výrazu", + "operation_interrupted": "Operace přerušena", + "not_logged_in": "Nejste přihlášen", + "logged_in": "Přihlášení", + "ldap_server_down": "Spojení s LDAP serverem se nezdařilo", + "ldap_attribute_already_exists": "Atribut '{attribute}' již obsahuje hodnotu '{value}'", + "invalid_usage": "Nesprávné použití, pass --help pro zobrazení nápovědy", + "invalid_token": "Nesprávný token - ověřte se prosím", + "invalid_password": "Nesprávné heslo", + "invalid_argument": "Nesprávný argument '{argument}': {error}", + "instance_already_running": "Právě probíhá jiná YunoHost operace. Před spuštěním další operace vyčkejte na její dokončení.", + "info": "Info:", + "folder_not_exist": "Adresář neexistuje", + "folder_exists": "Adresář již existuje: '{path}'", + "file_not_exist": "Soubor neexistuje: '{path}'", + "file_exists": "Soubor již existuje: '{path}'", + "error": "Chyba:", + "deprecated_command_alias": "'{prog} {old}' je zastaralý a bude odebrán v budoucích verzích, použijte '{prog} {new}'", + "deprecated_command": "'{prog} {command}' je zastaralý a bude odebrán v budoucích verzích", + "confirm": "Potvrdit {prompt}", + "colon": "{}: ", + "authentication_required_long": "K provedení této akce je vyžadováno ověření", + "authentication_required": "Vyžadováno ověření", + "argument_required": "Je vyžadován argument '{argument}'" } From facf3fc3e5b4580c27ed4dd144a8239dc9a86c47 Mon Sep 17 00:00:00 2001 From: Krzysztof Nowakowski Date: Mon, 22 Mar 2021 21:21:59 +0000 Subject: [PATCH 09/31] Translated using Weblate (Polish) Currently translated at 100.0% (56 of 56 strings) Translation: YunoHost/moulinette Translate-URL: https://translate.yunohost.org/projects/yunohost/moulinette/pl/ --- locales/pl.json | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/locales/pl.json b/locales/pl.json index 2d97b0aa..39338410 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -1,10 +1,10 @@ { "logged_out": "Wylogowano", "password": "Hasło", - "warn_the_user_that_lock_is_acquired": "drugie polecenie właśnie się zakończyło, teraz uruchamiając to polecenie", + "warn_the_user_that_lock_is_acquired": "Inne polecenie właśnie się zakończyło, teraz uruchamiam to polecenie", "warn_the_user_about_waiting_lock_again": "Wciąż czekam...", "warn_the_user_about_waiting_lock": "Kolejne polecenie YunoHost jest teraz uruchomione, czekamy na jego zakończenie przed uruchomieniem tego", - "command_unknown": "Polecenie „{command:s}” jest nieznane?", + "command_unknown": "Polecenie '{command:s}' jest nieznane?", "download_bad_status_code": "{url:s} zwrócił kod stanu {code:s}", "download_unknown_error": "Błąd podczas pobierania danych z {url:s}: {error:s}", "download_timeout": "{url:s} odpowiedział zbyt długo, poddał się.", @@ -13,17 +13,17 @@ "error_changing_file_permissions": "Błąd podczas zmiany uprawnień dla {path:s}: {error:s}", "error_removing": "Błąd podczas usuwania {path:s}: {error:s}", "error_writing_file": "Błąd podczas zapisywania pliku {file:s}: {error:s}", - "corrupted_toml": "Uszkodzony toml z {ressource: s} (powód: {error:s})", - "corrupted_yaml": "Uszkodzony yaml odczytany z {ressource:s} (powód: {error:s})", - "corrupted_json": "Uszkodzony json odczytany z {ressource:s} (powód: {error:s})", + "corrupted_toml": "Uszkodzony TOML z {ressource: s} (reason: {error:s})", + "corrupted_yaml": "Uszkodzony YAML odczytany z {ressource:s} (reason: {error:s})", + "corrupted_json": "Uszkodzony JSON odczytany z {ressource:s} (reason: {error:s})", "unknown_error_reading_file": "Nieznany błąd podczas próby odczytania pliku {file:s} (przyczyna: {error:s})", "cannot_write_file": "Nie można zapisać pliku {file:s} (przyczyna: {error:s})", "cannot_open_file": "Nie można otworzyć pliku {file:s} (przyczyna: {error:s})", "websocket_request_expected": "Oczekiwano żądania WebSocket", "warning": "Ostrzeżenie:", "values_mismatch": "Wartości nie pasują", - "unknown_user": "Nieznany użytkownik „{user}”", - "unknown_group": "Nieznana grupa „{group}”", + "unknown_user": "Nieznany użytkownik '{user}'", + "unknown_group": "Nieznana grupa '{group}'", "unable_retrieve_session": "Nie można pobrać sesji, ponieważ „{exception}”", "unable_authenticate": "Nie można uwierzytelnić", "success": "Sukces!", @@ -53,5 +53,7 @@ "colon": "{}: ", "authentication_required_long": "Do wykonania tej czynności wymagane jest uwierzytelnienie", "authentication_required": "Wymagane uwierzytelnienie", - "argument_required": "Argument „{argument}” jest wymagany" + "argument_required": "Argument „{argument}” jest wymagany", + "ldap_server_is_down_restart_it": "Usługa LDAP nie działa, próba restartu...", + "session_expired": "Sesja wygasła. Zaloguj się ponownie." } From ebb2bda235c3c13d7389b0650d30fdf7963ec838 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 25 Mar 2021 01:09:19 +0100 Subject: [PATCH 10/31] Update changelog for 4.2 (#272) * Update changelog for 4.2 * changelog: Improving error semantic --- debian/changelog | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 60e70747..958abd3b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,13 @@ -moulinette (4.2) unstable; urgency=low +moulinette (4.2.0) testing; urgency=low - - Placeholder for 4.2 to satisfy CI / debian build during dev + - [mod] Python2 -> python3([#228](https://github.com/YunoHost/moulinette/pull/228), 8e70561f, 570e5323, 3758b811, 90f894b5, [#269](https://github.com/YunoHost/moulinette/pull/269), e85b9f71, cafe68f3) + - [mod] Code formatting, test fixing, cleanup (677efcf6, 0de15467, [#268](https://github.com/YunoHost/moulinette/pull/268), affb54f8, f7199f7a, d6f82c91) + - [enh] Improve error semantic such that the webadmin shall be able to redirect to the proper log view ([#257](https://github.com/YunoHost/moulinette/pull/257), [#271](https://github.com/YunoHost/moulinette/pull/271)) + - [fix] Simpler and more consistent logging initialization ([#263](https://github.com/YunoHost/moulinette/pull/263)) - -- Alexandre Aubin Wed, 20 Jan 2021 05:19:58 +0100 + Thanks to all contributors <3 ! (Kay0u, Laurent Peuch) + + -- Alexandre Aubin Fri, 19 Mar 2021 18:39:42 +0100 moulinette (4.1.4) stable; urgency=low From 135fae95a801c86f86db383bc760bb8b55cfa745 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 16 Apr 2021 00:06:42 +0200 Subject: [PATCH 11/31] For some reason yunohost-api don't want to start due to recent changes in actionamp, apply this trick for subcategories just like we do for categories --- moulinette/actionsmap.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/moulinette/actionsmap.py b/moulinette/actionsmap.py index 90656e61..6b162868 100644 --- a/moulinette/actionsmap.py +++ b/moulinette/actionsmap.py @@ -778,6 +778,9 @@ class ActionsMap(object): # No parser for the action continue + if action_parser is None: # No parser for the action + continue + # Store action identifier and add arguments action_parser.set_defaults(_tid=tid) action_parser.add_arguments( From e364e03fb9ba3622386e38db877abae470802936 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 17 Apr 2021 04:59:33 +0200 Subject: [PATCH 12/31] Update changelog for 4.2.1 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 958abd3b..9e096c18 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +moulinette (4.2.1) testing; urgency=low + + - Fix weird technical thing in actionmap sucategories loading, related to recent changes in Yunohost actionmap (135fae95) + + -- Alexandre Aubin Sat, 17 Apr 2021 04:58:10 +0200 + moulinette (4.2.0) testing; urgency=low - [mod] Python2 -> python3([#228](https://github.com/YunoHost/moulinette/pull/228), 8e70561f, 570e5323, 3758b811, 90f894b5, [#269](https://github.com/YunoHost/moulinette/pull/269), e85b9f71, cafe68f3) From fe4fc35bcca4dbe0dd27165b8228d12951169836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Blah=C3=B3?= Date: Thu, 8 Apr 2021 11:22:24 +0000 Subject: [PATCH 13/31] Translated using Weblate (Hungarian) Currently translated at 30.3% (17 of 56 strings) Translation: YunoHost/moulinette Translate-URL: https://translate.yunohost.org/projects/yunohost/moulinette/hu/ --- locales/hu.json | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/locales/hu.json b/locales/hu.json index 42bb7781..629abc0f 100644 --- a/locales/hu.json +++ b/locales/hu.json @@ -1,4 +1,19 @@ { "logged_out": "Kilépett", - "password": "Jelszó" + "password": "Jelszó", + "download_timeout": "{url:s} régóta nem válaszol, folyamat megszakítva.", + "invalid_url": "Helytelen URL: {url:s} (biztos létezik az oldal?)", + "cannot_open_file": "{file:s} megnyitása sikertelen (Oka: {error:s})", + "unknown_user": "Ismeretlen felhasználó: '{user}'", + "unknown_group": "Ismeretlen csoport: '{group}'", + "server_already_running": "Egy szerver már fut ezen a porton", + "logged_in": "Bejelentkezve", + "success": "Siker!", + "values_mismatch": "Eltérő értékek", + "warning": "Figyelem:", + "invalid_password": "Helytelen jelszó", + "info": "Információ:", + "file_not_exist": "A fájl nem létezik: '{path}'", + "file_exists": "A fájl már létezik: '{path}'", + "error": "Hiba:" } From 3b7043e973a081398df0b920624b58a3f8c17197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= Date: Sat, 10 Apr 2021 12:31:20 +0000 Subject: [PATCH 14/31] Translated using Weblate (French) Currently translated at 100.0% (56 of 56 strings) Translation: YunoHost/moulinette Translate-URL: https://translate.yunohost.org/projects/yunohost/moulinette/fr/ --- locales/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/fr.json b/locales/fr.json index 29a7c6b5..9eb5edb1 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -56,6 +56,6 @@ "warn_the_user_about_waiting_lock_again": "Toujours en attente...", "warn_the_user_that_lock_is_acquired": "La commande précédente vient de se terminer, lancement de cette nouvelle commande", "invalid_token": "Jeton non valide - veuillez vous authentifier", - "ldap_server_is_down_restart_it": "Le service LDAP s'est arrêté, une tentative de redémarrage est en cours ...", + "ldap_server_is_down_restart_it": "Le service LDAP s'est arrêté, une tentative de redémarrage est en cours...", "session_expired": "La session a expiré. Merci de vous ré-authentifier." } From b5784c6d080a31c532a0df2e979ee6828d124a98 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 8 May 2021 14:51:11 +0200 Subject: [PATCH 15/31] Remove requirement section in the README, the requirements are in debian/control ... --- README.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/README.md b/README.md index b6f8b03d..f69b212e 100644 --- a/README.md +++ b/README.md @@ -45,13 +45,6 @@ Dev Documentation https://moulinette.readthedocs.org -Requirements ------------- - -* Python 2.7 -* python-bottle (>= 0.10) -* python-ldap (>= 2.4) -* PyYAML Testing ------- From 55e555aff59ca573e54ec21a05ef4dd6a4680e45 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 8 May 2021 15:12:31 +0200 Subject: [PATCH 16/31] Update changelog for 4.2.2 --- debian/changelog | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 9e096c18..c6332bc2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +moulinette (4.2.2) stable; urgency=low + + - [i18n] Translations updated for French, Hungarian + - Release as stable + + Thanks to all contributors <3 ! (Dominik Blahó, Éric Gaspar) + + -- Alexandre Aubin Sat, 08 May 2021 15:10:01 +0200 + moulinette (4.2.1) testing; urgency=low - Fix weird technical thing in actionmap sucategories loading, related to recent changes in Yunohost actionmap (135fae95) @@ -6,7 +15,7 @@ moulinette (4.2.1) testing; urgency=low moulinette (4.2.0) testing; urgency=low - - [mod] Python2 -> python3([#228](https://github.com/YunoHost/moulinette/pull/228), 8e70561f, 570e5323, 3758b811, 90f894b5, [#269](https://github.com/YunoHost/moulinette/pull/269), e85b9f71, cafe68f3) + - [mod] Python2 -> python3 ([#228](https://github.com/YunoHost/moulinette/pull/228), 8e70561f, 570e5323, 3758b811, 90f894b5, [#269](https://github.com/YunoHost/moulinette/pull/269), e85b9f71, cafe68f3) - [mod] Code formatting, test fixing, cleanup (677efcf6, 0de15467, [#268](https://github.com/YunoHost/moulinette/pull/268), affb54f8, f7199f7a, d6f82c91) - [enh] Improve error semantic such that the webadmin shall be able to redirect to the proper log view ([#257](https://github.com/YunoHost/moulinette/pull/257), [#271](https://github.com/YunoHost/moulinette/pull/271)) - [fix] Simpler and more consistent logging initialization ([#263](https://github.com/YunoHost/moulinette/pull/263)) From 04b7f7bc6fa44f594d085cd839a31d0b97b19891 Mon Sep 17 00:00:00 2001 From: Kayou Date: Thu, 13 May 2021 23:28:52 +0200 Subject: [PATCH 17/31] wait 1s for message in call_async_output --- moulinette/utils/process.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moulinette/utils/process.py b/moulinette/utils/process.py index e3a760d9..b8d5b915 100644 --- a/moulinette/utils/process.py +++ b/moulinette/utils/process.py @@ -77,7 +77,7 @@ def call_async_output(args, callback, **kwargs): while True: try: - callback, message = log_queue.get_nowait() + callback, message = log_queue.get(True, 1) except queue.Empty: break From d9789364b4dc66d76e76903a7e65e1de2d31d6e2 Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Mon, 17 May 2021 12:18:51 +0200 Subject: [PATCH 18/31] [fix] Unicode password doesn't log in --- moulinette/interfaces/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moulinette/interfaces/api.py b/moulinette/interfaces/api.py index 9ab34fb2..a1ae4d3e 100644 --- a/moulinette/interfaces/api.py +++ b/moulinette/interfaces/api.py @@ -249,7 +249,7 @@ class _ActionsMapPlugin(object): def wrapper(): kwargs = {} try: - kwargs["password"] = request.POST["password"] + kwargs["password"] = request.POST.password except KeyError: raise HTTPResponse("Missing password parameter", 400) From ad0786e6ea4f90673dd3c76bcf556602c190f67c Mon Sep 17 00:00:00 2001 From: Weblate Date: Sun, 9 May 2021 13:11:53 +0000 Subject: [PATCH 19/31] Added translation using Weblate (Finnish) --- locales/fi.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 locales/fi.json diff --git a/locales/fi.json b/locales/fi.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/locales/fi.json @@ -0,0 +1 @@ +{} From a1b5a7a6db15752c53c5054babf6022379f4e38c Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 10 May 2021 08:53:04 +0000 Subject: [PATCH 20/31] Added translation using Weblate (Galician) --- locales/gl.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 locales/gl.json diff --git a/locales/gl.json b/locales/gl.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/locales/gl.json @@ -0,0 +1 @@ +{} From 26c8f282d3295218d6998941015957c0325063c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20M?= Date: Tue, 11 May 2021 05:20:50 +0000 Subject: [PATCH 21/31] Translated using Weblate (Galician) Currently translated at 37.5% (21 of 56 strings) Translation: YunoHost/moulinette Translate-URL: https://translate.yunohost.org/projects/yunohost/moulinette/gl/ --- locales/gl.json | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/locales/gl.json b/locales/gl.json index 0967ef42..9a2f4513 100644 --- a/locales/gl.json +++ b/locales/gl.json @@ -1 +1,23 @@ -{} +{ + "ldap_attribute_already_exists": "O atributo '{attribute}' xa existe e ten o valor '{value}'", + "invalid_usage": "Uso non válido, pass --help para ver a axuda", + "invalid_token": "Token non válido - por favor autentícate", + "invalid_password": "Contrasinal non válido", + "invalid_argument": "Argumento non válido '{argument}': {error}", + "instance_already_running": "Hai unha operación de YunoHost en execución. Por favor agarda a que remate antes de realizar unha nova.", + "info": "Info:", + "folder_not_exist": "O cartafol non existe", + "folder_exists": "Xa existe o cartafol: '{path}'", + "file_not_exist": "Non existe o ficheiro: '{path}'", + "file_exists": "Xa existe o ficheiro: '{path}'", + "error": "Erro:", + "deprecated_command_alias": "'{prog} {old}' xa non se utiliza e será eliminado no futuro, usa '{prog} {new}' no seu lugar", + "deprecated_command": "'{prog} {command}' xa non se utiliza e xa non se usará no futuro", + "confirm": "Confirma {prompt}", + "colon": "{}: ", + "authentication_required_long": "Requírese autenticación para realizar esta acción", + "authentication_required": "Autenticación requerida", + "argument_required": "O argumento '{argument}' é requerido", + "logged_out": "Sesión pechada", + "password": "Contrasinal" +} From 4437ea3d315c35763ccb80ef7bb7204f01ced4fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20M?= Date: Wed, 12 May 2021 12:22:45 +0000 Subject: [PATCH 22/31] Translated using Weblate (Galician) Currently translated at 64.2% (36 of 56 strings) Translation: YunoHost/moulinette Translate-URL: https://translate.yunohost.org/projects/yunohost/moulinette/gl/ --- locales/gl.json | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/locales/gl.json b/locales/gl.json index 9a2f4513..67094006 100644 --- a/locales/gl.json +++ b/locales/gl.json @@ -19,5 +19,20 @@ "authentication_required": "Autenticación requerida", "argument_required": "O argumento '{argument}' é requerido", "logged_out": "Sesión pechada", - "password": "Contrasinal" + "password": "Contrasinal", + "warning": "Aviso:", + "values_mismatch": "Non concordan os valores", + "unknown_user": "Usuaria '{user}' descoñecida", + "unknown_group": "Grupo '{group}' descoñecido", + "session_expired": "A sesión caducou. Volve a conectar por favor.", + "unable_retrieve_session": "Non se puido obter a sesión porque '{exception}'", + "unable_authenticate": "Non se puido autenticar", + "success": "Ben feito!", + "server_already_running": "Xa hai un servidor a funcionar nese porto", + "root_required": "Tes que ser root para facer esta acción", + "pattern_not_match": "Non concorda co patrón", + "operation_interrupted": "Interrumpeuse a operación", + "not_logged_in": "Non estás conectada", + "logged_in": "Conectada", + "ldap_server_down": "Non se puido acadar o servidor LDAP" } From 60be338585d33223b9b7105ea6ea20dc8d194a84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20M?= Date: Thu, 13 May 2021 13:16:43 +0000 Subject: [PATCH 23/31] Translated using Weblate (Galician) Currently translated at 100.0% (56 of 56 strings) Translation: YunoHost/moulinette Translate-URL: https://translate.yunohost.org/projects/yunohost/moulinette/gl/ --- locales/gl.json | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/locales/gl.json b/locales/gl.json index 67094006..30112570 100644 --- a/locales/gl.json +++ b/locales/gl.json @@ -34,5 +34,25 @@ "operation_interrupted": "Interrumpeuse a operación", "not_logged_in": "Non estás conectada", "logged_in": "Conectada", - "ldap_server_down": "Non se puido acadar o servidor LDAP" + "ldap_server_down": "Non se puido acadar o servidor LDAP", + "ldap_server_is_down_restart_it": "O servizo LDAP está caído, intentando reinicialo...", + "warn_the_user_that_lock_is_acquired": "O outro comando rematou, agora executarase este", + "warn_the_user_about_waiting_lock_again": "Agardando...", + "warn_the_user_about_waiting_lock": "Estase executando outro comando de YunoHost neste intre, estamos agardando a que remate para executar este", + "command_unknown": "Comando '{command:s}' descoñecido?", + "download_bad_status_code": "{url:s} devolveu o código de estado {code:s}", + "download_unknown_error": "Erro ao descargar os datos desde {url:s}: {error:s}", + "download_timeout": "{url:s} está tardando en responder, deixámolo.", + "download_ssl_error": "Erro SSL ao conectar con {url:s}", + "invalid_url": "URL non válido {url:s} (existe esta web?)", + "error_changing_file_permissions": "Erro ao cambiar os permisos de {path:s}: {error:s}", + "error_removing": "Erro ao eliminar {path:s}: {error:s}", + "error_writing_file": "Erro ao escribir o ficheiro {file:s}: {error:s}", + "corrupted_toml": "Lectura corrupta de datos TOML de {ressource:s} (razón: {error:s})", + "corrupted_yaml": "Lectura corrupta dos datos YAML de {ressource:s} (razón: {error:s})", + "corrupted_json": "Lectura corrupta dos datos JSON de {ressource:s} (razón: {error:s})", + "unknown_error_reading_file": "Erro descoñecido ao intentar ler o ficheiro {file:s} (razón: {error:s})", + "cannot_write_file": "Non se puido escribir o ficheiro {file:s} (razón: {error:s})", + "cannot_open_file": "Non se puido abrir o ficheiro {file:s} (razón: {error:s})", + "websocket_request_expected": "Agardábase unha solicitude WebSocket" } From a0c86188d07d4b32f2cbbfca970cc925259744a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?yahoo=EF=BD=9E=EF=BD=9E?= Date: Wed, 19 May 2021 14:22:01 +0000 Subject: [PATCH 24/31] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (56 of 56 strings) Translation: YunoHost/moulinette Translate-URL: https://translate.yunohost.org/projects/yunohost/moulinette/zh_Hans/ --- locales/cmn.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/cmn.json b/locales/cmn.json index 3ae5a036..98883a6b 100644 --- a/locales/cmn.json +++ b/locales/cmn.json @@ -4,10 +4,10 @@ "authentication_required": "需要验证", "authentication_required_long": "此操作需要验证", "colon": "{} ", - "confirm": "确认{prompt}", + "confirm": "确认 {prompt}", "deprecated_command": "{prog}{command}已经放弃使用,将来会删除", "deprecated_command_alias": "{prog}{old}已经放弃使用,将来会删除,请使用{prog}{new}代替", - "error": "错误:", + "error": "错误:", "error_see_log": "发生错误。请参看日志文件获取错误详情,日志文件位于 /var/log/yunohost/。", "file_exists": "文件已存在:{path}", "file_not_exist": "文件不存在:{path}", From 923aa7d9636c0282a50c5b55a3c4f7db9dd47b0a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 24 May 2021 17:35:27 +0200 Subject: [PATCH 25/31] Update changelog for 4.2.3 --- debian/changelog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/debian/changelog b/debian/changelog index c6332bc2..83629061 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +moulinette (4.2.3) stable; urgency=low + + - [fix] Unicode password doesn't log in ([#276](https://github.com/YunoHost/moulinette/pull/276)) + - [i18n] Translations updated for Chinese (Simplified), Galician + + Thanks to all contributors <3 ! (José M, ljf, yahoo~~) + + -- Alexandre Aubin Mon, 24 May 2021 17:34:19 +0200 + moulinette (4.2.2) stable; urgency=low - [i18n] Translations updated for French, Hungarian From f91fad08daffc5c49100a366a32ebeda0c04b8a1 Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Tue, 25 May 2021 13:35:04 +0200 Subject: [PATCH 26/31] [fix] Request params not decoded --- moulinette/interfaces/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moulinette/interfaces/api.py b/moulinette/interfaces/api.py index a1ae4d3e..777c00ae 100644 --- a/moulinette/interfaces/api.py +++ b/moulinette/interfaces/api.py @@ -320,7 +320,7 @@ class _ActionsMapPlugin(object): for a in args: params[a] = True # Append other request params - for k, v in request.params.dict.items(): + for k, v in dict(request.params.decode()).items(): v = _format(v) if k not in params.keys(): params[k] = v From b512c56b1847b60b65cf8eaf07d37c393510e721 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 25 May 2021 18:59:51 +0200 Subject: [PATCH 27/31] Update changelog for 4.2.3.1 --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index 83629061..89cecded 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +moulinette (4.2.3.1) stable; urgency=low + + - [fix] Request params not decoded ([#277](https://github.com/YunoHost/moulinette/pull/277)) + + Thanks to all contributors <3 ! (ljf) + + -- Alexandre Aubin Tue, 25 May 2021 18:59:01 +0200 + moulinette (4.2.3) stable; urgency=low - [fix] Unicode password doesn't log in ([#276](https://github.com/YunoHost/moulinette/pull/276)) From 037a17085371403cd2993fe7fcf664ac6c2eb481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?yahoo=EF=BD=9E=EF=BD=9E?= Date: Wed, 26 May 2021 09:27:25 +0000 Subject: [PATCH 28/31] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (56 of 56 strings) Translation: YunoHost/moulinette Translate-URL: https://translate.yunohost.org/projects/yunohost/moulinette/zh_Hans/ --- locales/cmn.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/locales/cmn.json b/locales/cmn.json index 98883a6b..6752eb4f 100644 --- a/locales/cmn.json +++ b/locales/cmn.json @@ -9,9 +9,9 @@ "deprecated_command_alias": "{prog}{old}已经放弃使用,将来会删除,请使用{prog}{new}代替", "error": "错误:", "error_see_log": "发生错误。请参看日志文件获取错误详情,日志文件位于 /var/log/yunohost/。", - "file_exists": "文件已存在:{path}", - "file_not_exist": "文件不存在:{path}", - "folder_exists": "目录已存在:{path}", + "file_exists": "文件已存在: '{path}'", + "file_not_exist": "文件不存在: '{path}'", + "folder_exists": "目录已存在: '{path}'", "folder_not_exist": "目录不存在", "info": "信息:", "instance_already_running": "已经有一个YunoHost操作正在运行。 请等待它完成再运行另一个。", From fcc9bfd4d10271f497724b5913e6eed391215aba Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 2 Jun 2021 20:24:20 +0200 Subject: [PATCH 29/31] Update changelog for 4.2.3.2 --- debian/changelog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/debian/changelog b/debian/changelog index 89cecded..d5a6f11c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +moulinette (4.2.3.2) stable; urgency=low + + - [fix] wait 1s for message in call_async_output, prevent CPU overload ([#275](https://github.com/YunoHost/moulinette/pull/275)) + - [i18n] Translations updated for Chinese (Simplified) + + Thanks to all contributors <3 ! (Kayou, yahoo~~) + + -- Alexandre Aubin Wed, 02 Jun 2021 20:23:31 +0200 + moulinette (4.2.3.1) stable; urgency=low - [fix] Request params not decoded ([#277](https://github.com/YunoHost/moulinette/pull/277)) From 2c9ec9f6383508e0d2a012c49e1b496659609e62 Mon Sep 17 00:00:00 2001 From: ljf Date: Thu, 3 Jun 2021 18:01:43 +0200 Subject: [PATCH 30/31] [fix] Damn array args bug --- moulinette/interfaces/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moulinette/interfaces/api.py b/moulinette/interfaces/api.py index 777c00ae..3a61939b 100644 --- a/moulinette/interfaces/api.py +++ b/moulinette/interfaces/api.py @@ -320,7 +320,7 @@ class _ActionsMapPlugin(object): for a in args: params[a] = True # Append other request params - for k, v in dict(request.params.decode()).items(): + for k, v in request.params.decode().dict.items(): v = _format(v) if k not in params.keys(): params[k] = v From 47673ea72865f7f3a4801ae99c131574a80fc900 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 3 Jun 2021 18:40:42 +0200 Subject: [PATCH 31/31] Update changelog for 4.2.3.3 --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index d5a6f11c..a929320d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +moulinette (4.2.3.3) stable; urgency=low + + - [fix] Damn array args bug (2c9ec9f6) + + Thanks to all contributors <3 ! (ljf) + + -- Alexandre Aubin Thu, 03 Jun 2021 18:40:18 +0200 + moulinette (4.2.3.2) stable; urgency=low - [fix] wait 1s for message in call_async_output, prevent CPU overload ([#275](https://github.com/YunoHost/moulinette/pull/275))