diff --git a/action_map.yml b/action_map.yml index 27b3467a..15110c6c 100644 --- a/action_map.yml +++ b/action_map.yml @@ -58,7 +58,6 @@ user: -f: full: --filter help: LDAP filter used to search - pattern: 'yayaya' -l: full: --limit help: Maximum number of user fetched @@ -75,15 +74,24 @@ user: -u: full: --username help: Must be unique + ask: "Username" + #pattern: '^[a-z0-9_]+$' + pattern: 'aza' -f: full: --firstname + ask: "Firstname" -l: full: --lastname + ask: "Lastname" -m: full: --mail help: Main mail address must be unique + ask: "Mail address" + pattern: '^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,6}$' -p: full: --password + ask: "User password" + password: yes ### user_delete() delete: diff --git a/parse_args b/parse_args index ca749278..e6941357 100755 --- a/parse_args +++ b/parse_args @@ -24,6 +24,7 @@ import os import sys import argparse import gettext +import getpass try: import yaml except ImportError: @@ -38,7 +39,7 @@ if not __debug__: gettext.install('YunoHost') try: - from yunohost import YunoHostError, YunoHostLDAP, str_to_func, colorize, pretty_print_dict, display_error, connect_services, disconnect_services, validate + from yunohost import YunoHostError, YunoHostLDAP, str_to_func, colorize, pretty_print_dict, display_error, validate except ImportError: sys.stderr.write('Error: Yunohost CLI Require YunoHost lib\n') sys.exit(1) @@ -59,6 +60,8 @@ def parse_dict(action_map): parsers = subparsers_category = subparsers_action = {} parsers['general'] = argparse.ArgumentParser() subparsers = parsers['general'].add_subparsers() + new_args = [] + patterns = {} # Add general arguments for arg_name, arg_params in action_map['general_arguments'].items(): @@ -88,28 +91,59 @@ def parse_dict(action_map): # Add arguments if 'arguments' in action_params: for arg_name, arg_params in action_params['arguments'].items(): + if 'password' in arg_params: + if arg_params['password']: is_password = True + del arg_params['password'] + else: is_password = False + if 'full' in arg_params: - arg_fullname = arg_params['full'] + arg_names = [arg_name, arg_params['full']] del arg_params['full'] - else: - arg_fullname = False + else: arg_names = [arg_name] + + if 'ask' in arg_params: + require_input = True + if (category != sys.argv[1]) or (action != sys.argv[2]): + require_input = False + for name in arg_names: + if name in sys.argv: require_input = False + + if require_input: + if is_password: + if os.isatty(1): + pwd1 = getpass.getpass(colorize(arg_params['ask'] + ': ', 'cyan')) + pwd2 = getpass.getpass(colorize('Retype ' + arg_params['ask'][0].lower() + arg_params['ask'][1:] + ': ', 'cyan')) + if pwd1 != pwd2: + raise YunoHostError(22, _("Passwords don't match")) + sys.exit(1) + else: + raise YunoHostError(22, _("Missing arguments") + ': ' + arg_name) + new_args.extend([arg_name, pwd1]) + else: + if os.isatty(1): + arg_value = raw_input(colorize(arg_params['ask'] + ': ', 'cyan')) + else: + raise YunoHostError(22, _("Missing arguments") + ': ' + arg_name) + new_args.extend([arg_name, arg_value]) + del arg_params['ask'] if 'pattern' in arg_params: - pattern = arg_params['pattern'] - del arg_params['pattern'] - def pmatch(string): - validate({ string : pattern }) - if arg_fullname: - parsers[category + '_' + action].add_argument(arg_name, arg_fullname, type=pmatch, **arg_params) - else: - parsers[category + '_' + action].add_argument(arg_name, type=pmatch, **arg_params) - else: - if arg_fullname: - parsers[category + '_' + action].add_argument(arg_name, arg_fullname, **arg_params) - else: - parsers[category + '_' + action].add_argument(arg_name, **arg_params) + if (category == sys.argv[1]) and (action == sys.argv[2]): + if 'dest' in arg_params: name = arg_params['dest'] + elif arg_fullname: name = arg_fullname + else: name = arg_name + patterns[name] = arg_params['pattern'] + del arg_params['pattern'] - return parsers['general'].parse_args() + parsers[category + '_' + action].add_argument(*arg_names, **arg_params) + + args = parsers['general'].parse_args(sys.argv.extend(new_args)) + args_dict = vars(args) + print patterns + for key, value in patterns.items(): + validate({ args_dict[key] : value }) + + return args def main(): @@ -126,13 +160,9 @@ def main(): with open('action_map.yml') as f: action_map = yaml.load(f) - args = parse_dict(action_map) - connections = connect_services(action_map) try: - if connections: - result = args.func(vars(args), connections) - else: - result = args.func(vars(args)) + args = parse_dict(action_map) + result = args.func(vars(args)) except TypeError, error: if not __debug__ : traceback.print_exc() @@ -148,8 +178,6 @@ def main(): pretty_print_dict(result) else: print(json.dumps(result)) - finally: - disconnect_services(connections) return 0 diff --git a/yunohost.py b/yunohost.py index 06adcf99..2942ff72 100644 --- a/yunohost.py +++ b/yunohost.py @@ -99,6 +99,7 @@ def validate(regex_dict): Boolean | YunoHostError """ + print regex_dict for attr, pattern in regex_dict.items(): if re.match(pattern, attr): continue @@ -242,27 +243,35 @@ class YunoHostError(Exception): self.desc = code -class YunoHostLDAP: +class YunoHostLDAP(object): """ Specific LDAP functions for YunoHost """ + conn = None - def __init__(self, password=False): + def __enter__(self, password=False): """ Connect to LDAP base Initialize to localhost, base yunohost.org, prompt for password """ - self.conn = ldap.initialize('ldap://localhost:389') - self.base = 'dc=yunohost,dc=org' - if password: - self.pwd = password - else: - self.pwd = getpass.getpass(colorize(_('Admin Password: '), 'yellow')) - try: - self.conn.simple_bind_s('cn=admin,' + self.base, self.pwd) - except ldap.INVALID_CREDENTIALS: - raise YunoHostError(13, _('Invalid credentials')) + if self.conn is None: + self.conn = ldap.initialize('ldap://localhost:389') + self.base = 'dc=yunohost,dc=org' + if password: + self.pwd = password + else: + try: + self.pwd = getpass.getpass(colorize(_('Admin Password: '), 'yellow')) + except KeyboardInterrupt, EOFError: + raise YunoHostError(125, _("Interrupted")) + try: + self.conn.simple_bind_s('cn=admin,' + self.base, self.pwd) + except ldap.INVALID_CREDENTIALS: + raise YunoHostError(13, _('Invalid credentials')) + return self + def __exit__(self, type, value, traceback): + self.disconnect() def disconnect(self): """ diff --git a/yunohost_user.py b/yunohost_user.py index ff5dccad..62c1296d 100644 --- a/yunohost_user.py +++ b/yunohost_user.py @@ -7,318 +7,300 @@ import crypt import random import string import getpass -from yunohost import YunoHostError, win_msg, colorize, validate, get_required_args +from yunohost import YunoHostError, YunoHostLDAP, win_msg, colorize, validate, get_required_args -def user_list(args, connections): +def user_list(args): """ List YunoHost users from LDAP Keyword argument: args -- Dictionnary of values (can be empty) - connections -- LDAP connection Returns: Dict """ - yldap = connections['ldap'] - user_attrs = ['uid', 'mail', 'cn', 'mailalias'] - attrs = [] - result_dict = {} - if args['offset']: offset = int(args['offset']) - else: offset = 0 - if args['limit']: limit = int(args['limit']) - else: limit = 1000 - if args['filter']: filter = args['filter'] - else: filter = 'uid=*' - if args['fields']: - for attr in args['fields']: - if attr in user_attrs: - attrs.append(attr) - continue - else: - raise YunoHostError(22, _("Invalid field : ") + attr) - else: - attrs = user_attrs + with YunoHostLDAP() as yldap: + user_attrs = ['uid', 'mail', 'cn', 'mailalias'] + attrs = [] + result_dict = {} + if args['offset']: offset = int(args['offset']) + else: offset = 0 + if args['limit']: limit = int(args['limit']) + else: limit = 1000 + if args['filter']: filter = args['filter'] + else: filter = 'uid=*' + if args['fields']: + for attr in args['fields']: + if attr in user_attrs: + attrs.append(attr) + continue + else: + raise YunoHostError(22, _("Invalid field : ") + attr) + else: + attrs = user_attrs - result = yldap.search('ou=users,dc=yunohost,dc=org', filter, attrs) - - if result and len(result) > (0 + offset) and limit > 0: - i = 0 + offset - for user in result[i:]: - if i < limit: - entry = { - 'Username': user['uid'], - 'Fullname': user['cn'], - 'Mail': user['mail'][0] - } - if len(user['mail']) > 1: - entry['Mail Forward'] = user['mail'][1:] - if 'mailalias' in user: - entry['Mail Aliases'] = user['mailalias'] - - result_dict[str(i)] = entry - i += 1 - else: - raise YunoHostError(167, _("No user found")) + result = yldap.search('ou=users,dc=yunohost,dc=org', filter, attrs) + + if result and len(result) > (0 + offset) and limit > 0: + i = 0 + offset + for user in result[i:]: + if i < limit: + entry = { + 'Username': user['uid'], + 'Fullname': user['cn'], + 'Mail': user['mail'][0] + } + if len(user['mail']) > 1: + entry['Mail Forward'] = user['mail'][1:] + if 'mailalias' in user: + entry['Mail Aliases'] = user['mailalias'] + + result_dict[str(i)] = entry + i += 1 + else: + raise YunoHostError(167, _("No user found")) return result_dict -def user_create(args, connections): +def user_create(args): """ Add user to LDAP Keyword argument: args -- Dictionnary of values (can be empty) - connections -- LDAP connections Returns: Dict """ - yldap = connections['ldap'] - args = get_required_args(args, { - 'username': _('Username'), - 'mail': _('Mail address'), - 'firstname': _('Firstname'), - 'lastname': _('Lastname'), - 'password': _('Password') - }, True) + print args + with YunoHostLDAP() as yldap: + # Validate password length + if len(args['password']) < 4: + raise YunoHostError(22, _("Password is too short")) - # Validate password length - if len(args['password']) < 4: - raise YunoHostError(22, _("Password is too short")) + yldap.validate_uniqueness({ + 'uid' : args['username'], + 'mail' : args['mail'], + 'mailalias' : args['mail'] + }) - # Validate other values TODO: validate all values - validate({ - args['username'] : r'^[a-z0-9_]+$', - args['mail'] : r'^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,6}$', - }) + # Check if unix user already exists (doesn't work) + #if not os.system("getent passwd " + args['username']): + # raise YunoHostError(17, _("Username not available")) - yldap.validate_uniqueness({ - 'uid' : args['username'], - 'mail' : args['mail'], - 'mailalias' : args['mail'] - }) + #TODO: check if mail belongs to a domain - # Check if unix user already exists (doesn't work) - #if not os.system("getent passwd " + args['username']): - # raise YunoHostError(17, _("Username not available")) + # Get random UID/GID + uid_check = gid_check = 0 + while uid_check == 0 and gid_check == 0: + uid = str(random.randint(200, 99999)) + uid_check = os.system("getent passwd " + uid) + gid_check = os.system("getent group " + uid) - #TODO: check if mail belongs to a domain + # Adapt values for LDAP + fullname = args['firstname'] + ' ' + args['lastname'] + rdn = 'uid=' + args['username'] + ',ou=users' + char_set = string.ascii_uppercase + string.digits + salt = ''.join(random.sample(char_set,8)) + salt = '$1$' + salt + '$' + pwd = '{CRYPT}' + crypt.crypt(str(args['password']), salt) + attr_dict = { + 'objectClass' : ['mailAccount', 'inetOrgPerson', 'posixAccount'], + 'givenName' : args['firstname'], + 'sn' : args['lastname'], + 'displayName' : fullname, + 'cn' : fullname, + 'uid' : args['username'], + 'mail' : args['mail'], + 'userPassword' : pwd, + 'gidNumber' : uid, + 'uidNumber' : uid, + 'homeDirectory' : '/home/' + args['username'], + 'loginShell' : '/bin/false' + } - # Get random UID/GID - uid_check = gid_check = 0 - while uid_check == 0 and gid_check == 0: - uid = str(random.randint(200, 99999)) - uid_check = os.system("getent passwd " + uid) - gid_check = os.system("getent group " + uid) - - # Adapt values for LDAP - fullname = args['firstname'] + ' ' + args['lastname'] - rdn = 'uid=' + args['username'] + ',ou=users' - char_set = string.ascii_uppercase + string.digits - salt = ''.join(random.sample(char_set,8)) - salt = '$1$' + salt + '$' - pwd = '{CRYPT}' + crypt.crypt(str(args['password']), salt) - attr_dict = { - 'objectClass' : ['mailAccount', 'inetOrgPerson', 'posixAccount'], - 'givenName' : args['firstname'], - 'sn' : args['lastname'], - 'displayName' : fullname, - 'cn' : fullname, - 'uid' : args['username'], - 'mail' : args['mail'], - 'userPassword' : pwd, - 'gidNumber' : uid, - 'uidNumber' : uid, - 'homeDirectory' : '/home/' + args['username'], - 'loginShell' : '/bin/false' - } - - if yldap.add(rdn, attr_dict): - # Create user /home directory by switching user - os.system("su - " + args['username'] + " -c ''") - #TODO: Send a welcome mail to user - win_msg(_("User successfully created")) - return { _("Fullname") : fullname, _("Username") : args['username'], _("Mail") : args['mail'] } - else: - raise YunoHostError(169, _("An error occured during user creation")) + if yldap.add(rdn, attr_dict): + # Create user /home directory by switching user + os.system("su - " + args['username'] + " -c ''") + #TODO: Send a welcome mail to user + win_msg(_("User successfully created")) + return { _("Fullname") : fullname, _("Username") : args['username'], _("Mail") : args['mail'] } + else: + raise YunoHostError(169, _("An error occured during user creation")) -def user_delete(args, connections): +def user_delete(args): """ Remove user from LDAP Keyword argument: args -- Dictionnary of values (can be empty) - connections -- LDAP connection Returns: Dict """ - yldap = connections['ldap'] - result = { 'Users' : [] } + with YunoHostLDAP() as yldap: + result = { 'Users' : [] } - args = get_required_args(args, { 'users' : _('User to delete') }) - if not isinstance(args['users'], list): - args['users'] = [ args['users'] ] + args = get_required_args(args, { 'users' : _('User to delete') }) + if not isinstance(args['users'], list): + args['users'] = [ args['users'] ] - for user in args['users']: - validate({ user : r'^[a-z0-9_]+$' }) - if yldap.remove('uid=' + user+ ',ou=users'): - if args['purge']: - os.system('rm -rf /home/' + user) - result['Users'].append(user) - continue - else: - raise YunoHostError(169, _("An error occured during user deletion")) + for user in args['users']: + validate({ user : r'^[a-z0-9_]+$' }) + if yldap.remove('uid=' + user+ ',ou=users'): + if args['purge']: + os.system('rm -rf /home/' + user) + result['Users'].append(user) + continue + else: + raise YunoHostError(169, _("An error occured during user deletion")) - win_msg(_("User(s) successfully deleted")) + win_msg(_("User(s) successfully deleted")) return result -def user_update(args, connections): +def user_update(args): """ Update user informations Keyword argument: args -- Dictionnary of values - connections -- LDAP connection Returns: Dict """ - yldap = connections['ldap'] - validate({ args['user'] : r'^[a-z0-9_]+$' }) - attrs_to_fetch = ['givenName', 'sn', 'mail', 'mailAlias'] - new_attr_dict = {} + with YunoHostLDAP() as yldap: + validate({ args['user'] : r'^[a-z0-9_]+$' }) + attrs_to_fetch = ['givenName', 'sn', 'mail', 'mailAlias'] + new_attr_dict = {} - # Populate user informations - result = yldap.search(base='ou=users,dc=yunohost,dc=org', filter='uid=' + args['user'], attrs=attrs_to_fetch) - if not result: - raise YunoHostError(167, _("No user found")) - user = result[0] + # Populate user informations + result = yldap.search(base='ou=users,dc=yunohost,dc=org', filter='uid=' + args['user'], attrs=attrs_to_fetch) + if not result: + raise YunoHostError(167, _("No user found")) + user = result[0] - # Get modifications from arguments - if args['firstname']: - new_attr_dict['givenName'] = args['firstname'] # TODO: Validate - new_attr_dict['cn'] = new_attr_dict['displayName'] = args['firstname'] + ' ' + user['sn'][0] + # Get modifications from arguments + if args['firstname']: + new_attr_dict['givenName'] = args['firstname'] # TODO: Validate + new_attr_dict['cn'] = new_attr_dict['displayName'] = args['firstname'] + ' ' + user['sn'][0] - if args['lastname']: - new_attr_dict['sn'] = args['lastname'] # TODO: Validate - new_attr_dict['cn'] = new_attr_dict['displayName'] = user['givenName'][0] + ' ' + args['lastname'] + if args['lastname']: + new_attr_dict['sn'] = args['lastname'] # TODO: Validate + new_attr_dict['cn'] = new_attr_dict['displayName'] = user['givenName'][0] + ' ' + args['lastname'] - if args['lastname'] and args['firstname']: - new_attr_dict['cn'] = new_attr_dict['displayName'] = args['firstname'] + ' ' + args['lastname'] + if args['lastname'] and args['firstname']: + new_attr_dict['cn'] = new_attr_dict['displayName'] = args['firstname'] + ' ' + args['lastname'] - if args['change_password']: - char_set = string.ascii_uppercase + string.digits - salt = ''.join(random.sample(char_set,8)) - salt = '$1$' + salt + '$' - new_attr_dict['userPassword'] = '{CRYPT}' + crypt.crypt(str(args['change_password']), salt) + if args['change_password']: + char_set = string.ascii_uppercase + string.digits + salt = ''.join(random.sample(char_set,8)) + salt = '$1$' + salt + '$' + new_attr_dict['userPassword'] = '{CRYPT}' + crypt.crypt(str(args['change_password']), salt) - if args['mail']: - validate({ args['mail'] : r'^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,6}$' }) - yldap.validate_uniqueness({ - 'mail' : args['mail'], - 'mailalias' : args['mail'] - }) - del user['mail'][0] - new_attr_dict['mail'] = [args['mail']] + user['mail'] - - if args['add_mailforward']: - if not isinstance(args['add_mailforward'], list): - args['add_mailforward'] = [ args['add_mailforward'] ] - for mail in args['add_mailforward']: - validate({ mail : r'^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,6}$' }) + if args['mail']: + validate({ args['mail'] : r'^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,6}$' }) yldap.validate_uniqueness({ - 'mail' : mail, - 'mailalias' : mail + 'mail' : args['mail'], + 'mailalias' : args['mail'] }) - user['mail'].append(mail) - new_attr_dict['mail'] = user['mail'] + del user['mail'][0] + new_attr_dict['mail'] = [args['mail']] + user['mail'] - if args['remove_mailforward']: - if not isinstance(args['remove_mailforward'], list): - args['remove_mailforward'] = [ args['remove_mailforward'] ] - for mail in args['remove_mailforward']: - if len(user['mail']) > 1 and mail in user['mail'][1:]: - user['mail'].remove(mail) - else: - raise YunoHostError(22, _("Invalid mail forward : ") + mail) - new_attr_dict['mail'] = user['mail'] + if args['add_mailforward']: + if not isinstance(args['add_mailforward'], list): + args['add_mailforward'] = [ args['add_mailforward'] ] + for mail in args['add_mailforward']: + validate({ mail : r'^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,6}$' }) + yldap.validate_uniqueness({ + 'mail' : mail, + 'mailalias' : mail + }) + user['mail'].append(mail) + new_attr_dict['mail'] = user['mail'] - if args['add_mailalias']: - if not isinstance(args['add_mailalias'], list): - args['add_mailalias'] = [ args['add_mailalias'] ] - for mail in args['add_mailalias']: - validate({ mail : r'^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,6}$' }) - yldap.validate_uniqueness({ - 'mail' : mail, - 'mailalias' : mail - }) - if 'mailalias' in user: - user['mailalias'].append(mail) - else: - user['mailalias'] = [ mail ] - new_attr_dict['mailalias'] = user['mailalias'] + if args['remove_mailforward']: + if not isinstance(args['remove_mailforward'], list): + args['remove_mailforward'] = [ args['remove_mailforward'] ] + for mail in args['remove_mailforward']: + if len(user['mail']) > 1 and mail in user['mail'][1:]: + user['mail'].remove(mail) + else: + raise YunoHostError(22, _("Invalid mail forward : ") + mail) + new_attr_dict['mail'] = user['mail'] - if args['remove_mailalias']: - if not isinstance(args['remove_mailalias'], list): - args['remove_mailalias'] = [ args['remove_mailalias'] ] - for mail in args['remove_mailalias']: - if 'mailalias' in user and mail in user['mailalias']: - user['mailalias'].remove(mail) - else: - raise YunoHostError(22, _("Invalid mail alias : ") + mail) - new_attr_dict['mailalias'] = user['mailalias'] + if args['add_mailalias']: + if not isinstance(args['add_mailalias'], list): + args['add_mailalias'] = [ args['add_mailalias'] ] + for mail in args['add_mailalias']: + validate({ mail : r'^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,6}$' }) + yldap.validate_uniqueness({ + 'mail' : mail, + 'mailalias' : mail + }) + if 'mailalias' in user: + user['mailalias'].append(mail) + else: + user['mailalias'] = [ mail ] + new_attr_dict['mailalias'] = user['mailalias'] - if yldap.update('uid=' + args['user'] + ',ou=users', new_attr_dict): - win_msg(_("User successfully updated")) - return user_info({ 'user' : args['user'], 'mail' : None }, connections) - else: - raise YunoHostError(169, _("An error occured during user update")) + if args['remove_mailalias']: + if not isinstance(args['remove_mailalias'], list): + args['remove_mailalias'] = [ args['remove_mailalias'] ] + for mail in args['remove_mailalias']: + if 'mailalias' in user and mail in user['mailalias']: + user['mailalias'].remove(mail) + else: + raise YunoHostError(22, _("Invalid mail alias : ") + mail) + new_attr_dict['mailalias'] = user['mailalias'] + + if yldap.update('uid=' + args['user'] + ',ou=users', new_attr_dict): + win_msg(_("User successfully updated")) + return user_info({ 'user' : args['user'], 'mail' : None }, connections) + else: + raise YunoHostError(169, _("An error occured during user update")) -def user_info(args, connections): +def user_info(args): """ Fetch user informations from LDAP Keyword argument: args -- Dictionnary of values (can be empty) - connections -- LDAP connection Returns: Dict """ - yldap = connections['ldap'] - user_attrs = ['cn', 'mail', 'uid', 'mailAlias'] + with YunoHostLDAP() as yldap: + user_attrs = ['cn', 'mail', 'uid', 'mailAlias'] - if args['mail']: - validate({ args['mail'] : r'^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,6}$' }) - filter = 'mail=' + args['mail'] - else: - args = get_required_args(args, { 'user' : _("Username") }) - validate({ args['user'] : r'^[a-z0-9_]+$' }) - filter = 'uid=' + args['user'] + if args['mail']: + validate({ args['mail'] : r'^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,6}$' }) + filter = 'mail=' + args['mail'] + else: + args = get_required_args(args, { 'user' : _("Username") }) + validate({ args['user'] : r'^[a-z0-9_]+$' }) + filter = 'uid=' + args['user'] - result = yldap.search('ou=users,dc=yunohost,dc=org', filter, user_attrs) - user = result[0] - result_dict = { - 'Username': user['uid'], - 'Fullname': user['cn'], - 'Mail': user['mail'][0] - } + result = yldap.search('ou=users,dc=yunohost,dc=org', filter, user_attrs) + user = result[0] + result_dict = { + 'Username': user['uid'], + 'Fullname': user['cn'], + 'Mail': user['mail'][0] + } - if len(user['mail']) > 1: - result_dict['Mail Forward'] = user['mail'][1:] + if len(user['mail']) > 1: + result_dict['Mail Forward'] = user['mail'][1:] - if 'mailalias' in user: - result_dict['Mail Aliases'] = user['mailalias'] + if 'mailalias' in user: + result_dict['Mail Aliases'] = user['mailalias'] - if result: - return result_dict - else: - raise YunoHostError(167, _("No user found")) + if result: + return result_dict + else: + raise YunoHostError(167, _("No user found"))