mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
quality: add type hints to user.py
This commit is contained in:
parent
4ee8d4e8ca
commit
1ba75df0e2
3 changed files with 110 additions and 100 deletions
|
@ -218,10 +218,6 @@ user:
|
||||||
action_help: List existing groups
|
action_help: List existing groups
|
||||||
api: GET /users/groups
|
api: GET /users/groups
|
||||||
arguments:
|
arguments:
|
||||||
-s:
|
|
||||||
full: --short
|
|
||||||
help: List only the names of groups
|
|
||||||
action: store_true
|
|
||||||
-f:
|
-f:
|
||||||
full: --full
|
full: --full
|
||||||
help: Display all informations known about each groups
|
help: Display all informations known about each groups
|
||||||
|
|
204
src/user.py
204
src/user.py
|
@ -24,6 +24,7 @@ import random
|
||||||
import subprocess
|
import subprocess
|
||||||
import copy
|
import copy
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
from typing import TYPE_CHECKING, Literal, Any, TextIO, Optional, Callable, cast
|
||||||
|
|
||||||
from moulinette import Moulinette, m18n
|
from moulinette import Moulinette, m18n
|
||||||
from moulinette.utils.process import check_output
|
from moulinette.utils.process import check_output
|
||||||
|
@ -33,7 +34,14 @@ from yunohost.service import service_status
|
||||||
from yunohost.log import is_unit_operation
|
from yunohost.log import is_unit_operation
|
||||||
from yunohost.utils.system import binary_to_human
|
from yunohost.utils.system import binary_to_human
|
||||||
|
|
||||||
logger = getLogger("yunohost.user")
|
if TYPE_CHECKING:
|
||||||
|
from yunohost.log import OperationLogger
|
||||||
|
from moulinette.utils.log import MoulinetteLogger
|
||||||
|
from bottle import HTTPResponse as HTTPResponseType
|
||||||
|
logger = cast(MoulinetteLogger, getLogger("yunohost.user"))
|
||||||
|
else:
|
||||||
|
logger = getLogger("yunohost.user")
|
||||||
|
|
||||||
|
|
||||||
FIELDS_FOR_IMPORT = {
|
FIELDS_FOR_IMPORT = {
|
||||||
"username": r"^[a-z0-9_.]+$",
|
"username": r"^[a-z0-9_.]+$",
|
||||||
|
@ -49,8 +57,7 @@ FIELDS_FOR_IMPORT = {
|
||||||
|
|
||||||
ADMIN_ALIASES = ["root", "admin", "admins", "webmaster", "postmaster", "abuse"]
|
ADMIN_ALIASES = ["root", "admin", "admins", "webmaster", "postmaster", "abuse"]
|
||||||
|
|
||||||
|
def user_list(fields: Optional[list[str]] = None) -> dict[str, dict[str, Any]] :
|
||||||
def user_list(fields=None):
|
|
||||||
from yunohost.utils.ldap import _get_ldap_interface
|
from yunohost.utils.ldap import _get_ldap_interface
|
||||||
|
|
||||||
ldap_attrs = {
|
ldap_attrs = {
|
||||||
|
@ -71,7 +78,7 @@ def user_list(fields=None):
|
||||||
def display_default(values, _):
|
def display_default(values, _):
|
||||||
return values[0] if len(values) == 1 else values
|
return values[0] if len(values) == 1 else values
|
||||||
|
|
||||||
display = {
|
display: dict[str, Callable[[list[str], dict], Any]] = {
|
||||||
"password": lambda values, user: "",
|
"password": lambda values, user: "",
|
||||||
"mail": lambda values, user: display_default(values[:1], user),
|
"mail": lambda values, user: display_default(values[:1], user),
|
||||||
"mail-alias": lambda values, _: values[1:],
|
"mail-alias": lambda values, _: values[1:],
|
||||||
|
@ -108,15 +115,18 @@ def user_list(fields=None):
|
||||||
)
|
)
|
||||||
|
|
||||||
for user in result:
|
for user in result:
|
||||||
entry = {}
|
entry: dict[str, str] = {}
|
||||||
for field in fields:
|
for field in fields:
|
||||||
values = []
|
values = []
|
||||||
if ldap_attrs[field] in user:
|
if ldap_attrs[field] in user:
|
||||||
values = user[ldap_attrs[field]]
|
values = user[ldap_attrs[field]]
|
||||||
entry[field] = display.get(field, display_default)(values, user)
|
entry[field] = display.get(field, display_default)(values, user)
|
||||||
|
|
||||||
users[user["uid"][0]] = entry
|
username: str = user["uid"][0]
|
||||||
|
users[username] = entry
|
||||||
|
|
||||||
|
# Dict entry 0 has incompatible type "str": "dict[Any, dict[str, Any]]";
|
||||||
|
# expected "str": "dict[str, str]" [dict-item]
|
||||||
return {"users": users}
|
return {"users": users}
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,17 +144,17 @@ def shellexists(shell):
|
||||||
|
|
||||||
@is_unit_operation([("username", "user")])
|
@is_unit_operation([("username", "user")])
|
||||||
def user_create(
|
def user_create(
|
||||||
operation_logger,
|
operation_logger: OperationLogger,
|
||||||
username,
|
username: str,
|
||||||
domain,
|
domain: str,
|
||||||
password,
|
password: str,
|
||||||
fullname=None,
|
fullname: str,
|
||||||
mailbox_quota="0",
|
mailbox_quota="0",
|
||||||
admin=False,
|
admin: bool = False,
|
||||||
from_import=False,
|
from_import: bool = False,
|
||||||
loginShell=None,
|
loginShell=None,
|
||||||
):
|
) -> dict[str, str]:
|
||||||
if not fullname or not fullname.strip():
|
if not fullname.strip():
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
"You should specify the fullname of the user using option -F"
|
"You should specify the fullname of the user using option -F"
|
||||||
)
|
)
|
||||||
|
@ -270,12 +280,12 @@ def user_create(
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
home = f"/home/{username}"
|
home = f"/home/{username}"
|
||||||
if not os.path.isdir(home):
|
if not os.path.isdir(home):
|
||||||
logger.warning(m18n.n("user_home_creation_failed", home=home), exc_info=1)
|
logger.warning(m18n.n("user_home_creation_failed", home=home), exc_info=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
subprocess.check_call(["setfacl", "-m", "g:all_users:---", f"/home/{username}"])
|
subprocess.check_call(["setfacl", "-m", "g:all_users:---", f"/home/{username}"])
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
logger.warning(f"Failed to protect /home/{username}", exc_info=1)
|
logger.warning(f"Failed to protect /home/{username}", exc_info=True)
|
||||||
|
|
||||||
# Create group for user and add to group 'all_users'
|
# Create group for user and add to group 'all_users'
|
||||||
user_group_create(groupname=username, gid=uid, primary_group=True, sync_perm=False)
|
user_group_create(groupname=username, gid=uid, primary_group=True, sync_perm=False)
|
||||||
|
@ -302,7 +312,7 @@ def user_create(
|
||||||
|
|
||||||
|
|
||||||
@is_unit_operation([("username", "user")])
|
@is_unit_operation([("username", "user")])
|
||||||
def user_delete(operation_logger, username, purge=False, from_import=False):
|
def user_delete(operation_logger: OperationLogger, username: str, purge: bool = False, from_import: bool =False):
|
||||||
from yunohost.hook import hook_callback
|
from yunohost.hook import hook_callback
|
||||||
from yunohost.utils.ldap import _get_ldap_interface
|
from yunohost.utils.ldap import _get_ldap_interface
|
||||||
from yunohost.authenticators.ldap_ynhuser import Authenticator as PortalAuth
|
from yunohost.authenticators.ldap_ynhuser import Authenticator as PortalAuth
|
||||||
|
@ -353,18 +363,18 @@ def user_delete(operation_logger, username, purge=False, from_import=False):
|
||||||
|
|
||||||
@is_unit_operation([("username", "user")], exclude=["change_password"])
|
@is_unit_operation([("username", "user")], exclude=["change_password"])
|
||||||
def user_update(
|
def user_update(
|
||||||
operation_logger,
|
operation_logger: OperationLogger,
|
||||||
username,
|
username: str,
|
||||||
mail=None,
|
mail: Optional[str] = None,
|
||||||
change_password=None,
|
change_password: Optional[str] = None,
|
||||||
add_mailforward=None,
|
add_mailforward: None | str | list[str] = None,
|
||||||
remove_mailforward=None,
|
remove_mailforward: None | str | list[str] = None,
|
||||||
add_mailalias=None,
|
add_mailalias: None | str | list[str] = None,
|
||||||
remove_mailalias=None,
|
remove_mailalias: None | str | list[str] = None,
|
||||||
mailbox_quota=None,
|
mailbox_quota: Optional[str] = None,
|
||||||
from_import=False,
|
from_import: bool = False,
|
||||||
fullname=None,
|
fullname: Optional[str] = None,
|
||||||
loginShell=None,
|
loginShell: Optional[str] = None,
|
||||||
):
|
):
|
||||||
if fullname and fullname.strip():
|
if fullname and fullname.strip():
|
||||||
fullname = fullname.strip()
|
fullname = fullname.strip()
|
||||||
|
@ -399,7 +409,7 @@ def user_update(
|
||||||
if not result:
|
if not result:
|
||||||
raise YunohostValidationError("user_unknown", user=username)
|
raise YunohostValidationError("user_unknown", user=username)
|
||||||
user = result[0]
|
user = result[0]
|
||||||
env_dict = {"YNH_USER_USERNAME": username}
|
env_dict: dict[str, str] = {"YNH_USER_USERNAME": username}
|
||||||
|
|
||||||
# Get modifications from arguments
|
# Get modifications from arguments
|
||||||
new_attr_dict = {}
|
new_attr_dict = {}
|
||||||
|
@ -428,9 +438,9 @@ def user_update(
|
||||||
# without a specified value, change_password will be set to the const 0.
|
# without a specified value, change_password will be set to the const 0.
|
||||||
# In this case we prompt for the new password.
|
# In this case we prompt for the new password.
|
||||||
if Moulinette.interface.type == "cli" and not change_password:
|
if Moulinette.interface.type == "cli" and not change_password:
|
||||||
change_password = Moulinette.prompt(
|
change_password = cast(str, Moulinette.prompt(
|
||||||
m18n.n("ask_password"), is_password=True, confirm=True
|
m18n.n("ask_password"), is_password=True, confirm=True
|
||||||
)
|
))
|
||||||
|
|
||||||
# Ensure compatibility and sufficiently complex password
|
# Ensure compatibility and sufficiently complex password
|
||||||
assert_password_is_compatible(change_password)
|
assert_password_is_compatible(change_password)
|
||||||
|
@ -462,7 +472,7 @@ def user_update(
|
||||||
|
|
||||||
new_attr_dict["mail"] = [mail] + user["mail"][1:]
|
new_attr_dict["mail"] = [mail] + user["mail"][1:]
|
||||||
|
|
||||||
if add_mailalias:
|
if add_mailalias is not None:
|
||||||
if not isinstance(add_mailalias, list):
|
if not isinstance(add_mailalias, list):
|
||||||
add_mailalias = [add_mailalias]
|
add_mailalias = [add_mailalias]
|
||||||
for mail in add_mailalias:
|
for mail in add_mailalias:
|
||||||
|
@ -555,7 +565,7 @@ def user_update(
|
||||||
return user_info(username)
|
return user_info(username)
|
||||||
|
|
||||||
|
|
||||||
def user_info(username):
|
def user_info(username: str) -> dict[str, str]:
|
||||||
"""
|
"""
|
||||||
Get user informations
|
Get user informations
|
||||||
|
|
||||||
|
@ -624,8 +634,8 @@ def user_info(username):
|
||||||
has_value = re.search(r"Value=(\d+)", cmd_result)
|
has_value = re.search(r"Value=(\d+)", cmd_result)
|
||||||
|
|
||||||
if has_value:
|
if has_value:
|
||||||
storage_use = int(has_value.group(1)) * 1000
|
storage_use_int = int(has_value.group(1)) * 1000
|
||||||
storage_use = binary_to_human(storage_use)
|
storage_use = binary_to_human(storage_use_int)
|
||||||
|
|
||||||
if is_limited:
|
if is_limited:
|
||||||
has_percent = re.search(r"%=(\d+)", cmd_result)
|
has_percent = re.search(r"%=(\d+)", cmd_result)
|
||||||
|
@ -642,7 +652,7 @@ def user_info(username):
|
||||||
return result_dict
|
return result_dict
|
||||||
|
|
||||||
|
|
||||||
def user_export():
|
def user_export() -> str | HTTPResponseType:
|
||||||
"""
|
"""
|
||||||
Export users into CSV
|
Export users into CSV
|
||||||
|
|
||||||
|
@ -684,7 +694,7 @@ def user_export():
|
||||||
|
|
||||||
|
|
||||||
@is_unit_operation()
|
@is_unit_operation()
|
||||||
def user_import(operation_logger, csvfile, update=False, delete=False):
|
def user_import(operation_logger: OperationLogger, csvfile: TextIO, update: bool = False, delete: bool = False) -> dict[str, int]:
|
||||||
"""
|
"""
|
||||||
Import users from CSV
|
Import users from CSV
|
||||||
|
|
||||||
|
@ -700,7 +710,7 @@ def user_import(operation_logger, csvfile, update=False, delete=False):
|
||||||
from yunohost.domain import domain_list
|
from yunohost.domain import domain_list
|
||||||
|
|
||||||
# Pre-validate data and prepare what should be done
|
# Pre-validate data and prepare what should be done
|
||||||
actions = {"created": [], "updated": [], "deleted": []}
|
actions: dict[str, list[dict[str, Any]]] = {"created": [], "updated": [], "deleted": []}
|
||||||
is_well_formatted = True
|
is_well_formatted = True
|
||||||
|
|
||||||
def to_list(str_list):
|
def to_list(str_list):
|
||||||
|
@ -713,10 +723,11 @@ def user_import(operation_logger, csvfile, update=False, delete=False):
|
||||||
existing_domains = domain_list()["domains"]
|
existing_domains = domain_list()["domains"]
|
||||||
|
|
||||||
reader = csv.DictReader(csvfile, delimiter=";", quotechar='"')
|
reader = csv.DictReader(csvfile, delimiter=";", quotechar='"')
|
||||||
|
reader_fields = cast(list[str], reader.fieldnames)
|
||||||
users_in_csv = []
|
users_in_csv = []
|
||||||
|
|
||||||
missing_columns = [
|
missing_columns: list[str] = [
|
||||||
key for key in FIELDS_FOR_IMPORT.keys() if key not in reader.fieldnames
|
key for key in FIELDS_FOR_IMPORT.keys() if key not in reader_fields
|
||||||
]
|
]
|
||||||
if missing_columns:
|
if missing_columns:
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
|
@ -758,7 +769,7 @@ def user_import(operation_logger, csvfile, update=False, delete=False):
|
||||||
for mail in user["mail-alias"]
|
for mail in user["mail-alias"]
|
||||||
if mail.split("@", 1)[1] not in existing_domains
|
if mail.split("@", 1)[1] not in existing_domains
|
||||||
]
|
]
|
||||||
unknown_domains = set(unknown_domains)
|
unknown_domains = list(set(unknown_domains))
|
||||||
|
|
||||||
if unknown_domains:
|
if unknown_domains:
|
||||||
format_errors.append(
|
format_errors.append(
|
||||||
|
@ -792,7 +803,7 @@ def user_import(operation_logger, csvfile, update=False, delete=False):
|
||||||
|
|
||||||
if delete:
|
if delete:
|
||||||
actions["deleted"] = [
|
actions["deleted"] = [
|
||||||
user for user in existing_users if user not in users_in_csv
|
{"username": user} for user in existing_users if user not in users_in_csv
|
||||||
]
|
]
|
||||||
|
|
||||||
if delete and not users_in_csv:
|
if delete and not users_in_csv:
|
||||||
|
@ -808,7 +819,7 @@ def user_import(operation_logger, csvfile, update=False, delete=False):
|
||||||
|
|
||||||
if total == 0:
|
if total == 0:
|
||||||
logger.info(m18n.n("user_import_nothing_to_do"))
|
logger.info(m18n.n("user_import_nothing_to_do"))
|
||||||
return
|
return {}
|
||||||
|
|
||||||
# Apply creation, update and deletion operation
|
# Apply creation, update and deletion operation
|
||||||
result = {"created": 0, "updated": 0, "deleted": 0, "errors": 0}
|
result = {"created": 0, "updated": 0, "deleted": 0, "errors": 0}
|
||||||
|
@ -825,14 +836,14 @@ def user_import(operation_logger, csvfile, update=False, delete=False):
|
||||||
progress.old = bar
|
progress.old = bar
|
||||||
logger.info(bar)
|
logger.info(bar)
|
||||||
|
|
||||||
progress.nb = 0
|
progress.nb = 0 # type: ignore[attr-defined]
|
||||||
progress.old = ""
|
progress.old = "" # type: ignore[attr-defined]
|
||||||
|
|
||||||
def on_failure(user, exception):
|
def _on_failure(user, exception):
|
||||||
result["errors"] += 1
|
result["errors"] += 1
|
||||||
logger.error(user + ": " + str(exception))
|
logger.error(user + ": " + str(exception))
|
||||||
|
|
||||||
def update(new_infos, old_infos=False):
|
def _import_update(new_infos, old_infos=False):
|
||||||
remove_alias = None
|
remove_alias = None
|
||||||
remove_forward = None
|
remove_forward = None
|
||||||
remove_groups = []
|
remove_groups = []
|
||||||
|
@ -900,18 +911,18 @@ def user_import(operation_logger, csvfile, update=False, delete=False):
|
||||||
# We do delete and update before to avoid mail uniqueness issues
|
# We do delete and update before to avoid mail uniqueness issues
|
||||||
for user in actions["deleted"]:
|
for user in actions["deleted"]:
|
||||||
try:
|
try:
|
||||||
user_delete(user, purge=True, from_import=True)
|
user_delete(user["username"], purge=True, from_import=True)
|
||||||
result["deleted"] += 1
|
result["deleted"] += 1
|
||||||
except YunohostError as e:
|
except YunohostError as e:
|
||||||
on_failure(user, e)
|
_on_failure(user, e)
|
||||||
progress(f"Deleting {user}")
|
progress(f"Deleting {user}")
|
||||||
|
|
||||||
for user in actions["updated"]:
|
for user in actions["updated"]:
|
||||||
try:
|
try:
|
||||||
update(user, users[user["username"]])
|
_import_update(user, users[user["username"]])
|
||||||
result["updated"] += 1
|
result["updated"] += 1
|
||||||
except YunohostError as e:
|
except YunohostError as e:
|
||||||
on_failure(user["username"], e)
|
_on_failure(user["username"], e)
|
||||||
progress(f"Updating {user['username']}")
|
progress(f"Updating {user['username']}")
|
||||||
|
|
||||||
for user in actions["created"]:
|
for user in actions["created"]:
|
||||||
|
@ -924,10 +935,10 @@ def user_import(operation_logger, csvfile, update=False, delete=False):
|
||||||
from_import=True,
|
from_import=True,
|
||||||
fullname=(user["firstname"] + " " + user["lastname"]).strip(),
|
fullname=(user["firstname"] + " " + user["lastname"]).strip(),
|
||||||
)
|
)
|
||||||
update(user)
|
_import_update(user)
|
||||||
result["created"] += 1
|
result["created"] += 1
|
||||||
except YunohostError as e:
|
except YunohostError as e:
|
||||||
on_failure(user["username"], e)
|
_on_failure(user["username"], e)
|
||||||
progress(f"Creating {user['username']}")
|
progress(f"Creating {user['username']}")
|
||||||
|
|
||||||
permission_sync_to_user()
|
permission_sync_to_user()
|
||||||
|
@ -948,12 +959,11 @@ def user_import(operation_logger, csvfile, update=False, delete=False):
|
||||||
#
|
#
|
||||||
# Group subcategory
|
# Group subcategory
|
||||||
#
|
#
|
||||||
def user_group_list(short=False, full=False, include_primary_groups=True):
|
def user_group_list(full: bool = False, include_primary_groups: bool = True) -> dict[str, dict[str, dict]]:
|
||||||
"""
|
"""
|
||||||
List users
|
List users
|
||||||
|
|
||||||
Keyword argument:
|
Keyword argument:
|
||||||
short -- Only list the name of the groups without any additional info
|
|
||||||
full -- List all the info available for each groups
|
full -- List all the info available for each groups
|
||||||
include_primary_groups -- Include groups corresponding to users (which should always only contains this user)
|
include_primary_groups -- Include groups corresponding to users (which should always only contains this user)
|
||||||
This option is set to false by default in the action map because we don't want to have
|
This option is set to false by default in the action map because we don't want to have
|
||||||
|
@ -975,7 +985,7 @@ def user_group_list(short=False, full=False, include_primary_groups=True):
|
||||||
# Parse / organize information to be outputed
|
# Parse / organize information to be outputed
|
||||||
|
|
||||||
users = user_list()["users"]
|
users = user_list()["users"]
|
||||||
groups = {}
|
groups: dict[str, dict[str, Any]] = {}
|
||||||
for infos in groups_infos:
|
for infos in groups_infos:
|
||||||
name = infos["cn"][0]
|
name = infos["cn"][0]
|
||||||
|
|
||||||
|
@ -993,16 +1003,13 @@ def user_group_list(short=False, full=False, include_primary_groups=True):
|
||||||
_ldap_path_extract(p, "cn") for p in infos.get("permission", [])
|
_ldap_path_extract(p, "cn") for p in infos.get("permission", [])
|
||||||
]
|
]
|
||||||
|
|
||||||
if short:
|
|
||||||
groups = list(groups.keys())
|
|
||||||
|
|
||||||
return {"groups": groups}
|
return {"groups": groups}
|
||||||
|
|
||||||
|
|
||||||
@is_unit_operation([("groupname", "group")])
|
@is_unit_operation([("groupname", "group")])
|
||||||
def user_group_create(
|
def user_group_create(
|
||||||
operation_logger, groupname, gid=None, primary_group=False, sync_perm=True
|
operation_logger: OperationLogger, groupname: str, gid: Optional[int] = None, primary_group: bool = False, sync_perm: bool = True
|
||||||
):
|
) -> dict[str, str]:
|
||||||
"""
|
"""
|
||||||
Create group
|
Create group
|
||||||
|
|
||||||
|
@ -1041,7 +1048,7 @@ def user_group_create(
|
||||||
|
|
||||||
uid_guid_found = False
|
uid_guid_found = False
|
||||||
while not uid_guid_found:
|
while not uid_guid_found:
|
||||||
gid = str(random.randint(200, 99999))
|
gid = random.randint(200, 99999)
|
||||||
uid_guid_found = gid not in all_gid
|
uid_guid_found = gid not in all_gid
|
||||||
|
|
||||||
attr_dict = {
|
attr_dict = {
|
||||||
|
@ -1074,7 +1081,7 @@ def user_group_create(
|
||||||
|
|
||||||
|
|
||||||
@is_unit_operation([("groupname", "group")])
|
@is_unit_operation([("groupname", "group")])
|
||||||
def user_group_delete(operation_logger, groupname, force=False, sync_perm=True):
|
def user_group_delete(operation_logger: OperationLogger, groupname: str, force: bool = False, sync_perm: bool = True) -> None:
|
||||||
"""
|
"""
|
||||||
Delete user
|
Delete user
|
||||||
|
|
||||||
|
@ -1116,16 +1123,16 @@ def user_group_delete(operation_logger, groupname, force=False, sync_perm=True):
|
||||||
|
|
||||||
@is_unit_operation([("groupname", "group")])
|
@is_unit_operation([("groupname", "group")])
|
||||||
def user_group_update(
|
def user_group_update(
|
||||||
operation_logger,
|
operation_logger: OperationLogger,
|
||||||
groupname,
|
groupname: str,
|
||||||
add=None,
|
add: None | str | list[str] = None,
|
||||||
remove=None,
|
remove: None | str | list[str] = None,
|
||||||
add_mailalias=None,
|
add_mailalias: None | str | list[str] = None,
|
||||||
remove_mailalias=None,
|
remove_mailalias: None | str | list[str] = None,
|
||||||
force=False,
|
force: bool = False,
|
||||||
sync_perm=True,
|
sync_perm: bool = True,
|
||||||
from_import=False,
|
from_import: bool = False,
|
||||||
):
|
) -> None | dict[str, Any]:
|
||||||
from yunohost.permission import permission_sync_to_user
|
from yunohost.permission import permission_sync_to_user
|
||||||
from yunohost.utils.ldap import _get_ldap_interface, _ldap_path_extract
|
from yunohost.utils.ldap import _get_ldap_interface, _ldap_path_extract
|
||||||
|
|
||||||
|
@ -1165,7 +1172,7 @@ def user_group_update(
|
||||||
_ldap_path_extract(p, "uid") for p in group.get("member", [])
|
_ldap_path_extract(p, "uid") for p in group.get("member", [])
|
||||||
]
|
]
|
||||||
new_group_members = copy.copy(current_group_members)
|
new_group_members = copy.copy(current_group_members)
|
||||||
new_attr_dict = {}
|
new_attr_dict: dict[str, list] = {}
|
||||||
|
|
||||||
if add:
|
if add:
|
||||||
users_to_add = [add] if not isinstance(add, list) else add
|
users_to_add = [add] if not isinstance(add, list) else add
|
||||||
|
@ -1205,8 +1212,8 @@ def user_group_update(
|
||||||
new_group_members_dns = [
|
new_group_members_dns = [
|
||||||
"uid=" + user + ",ou=users,dc=yunohost,dc=org" for user in new_group_members
|
"uid=" + user + ",ou=users,dc=yunohost,dc=org" for user in new_group_members
|
||||||
]
|
]
|
||||||
new_attr_dict["member"] = set(new_group_members_dns)
|
new_attr_dict["member"] = list(set(new_group_members_dns))
|
||||||
new_attr_dict["memberUid"] = set(new_group_members)
|
new_attr_dict["memberUid"] = list(set(new_group_members))
|
||||||
|
|
||||||
# Check the whole alias situation
|
# Check the whole alias situation
|
||||||
if add_mailalias:
|
if add_mailalias:
|
||||||
|
@ -1258,7 +1265,7 @@ def user_group_update(
|
||||||
|
|
||||||
if set(new_group_mail) != set(current_group_mail):
|
if set(new_group_mail) != set(current_group_mail):
|
||||||
logger.info(m18n.n("group_update_aliases", group=groupname))
|
logger.info(m18n.n("group_update_aliases", group=groupname))
|
||||||
new_attr_dict["mail"] = set(new_group_mail)
|
new_attr_dict["mail"] = list(set(new_group_mail))
|
||||||
|
|
||||||
if new_attr_dict["mail"] and "mailGroup" not in group["objectClass"]:
|
if new_attr_dict["mail"] and "mailGroup" not in group["objectClass"]:
|
||||||
new_attr_dict["objectClass"] = group["objectClass"] + ["mailGroup"]
|
new_attr_dict["objectClass"] = group["objectClass"] + ["mailGroup"]
|
||||||
|
@ -1296,8 +1303,10 @@ def user_group_update(
|
||||||
|
|
||||||
return user_group_info(groupname)
|
return user_group_info(groupname)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def user_group_info(groupname):
|
|
||||||
|
def user_group_info(groupname: str) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Get user informations
|
Get user informations
|
||||||
|
|
||||||
|
@ -1333,7 +1342,7 @@ def user_group_info(groupname):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def user_group_add(groupname, usernames, force=False, sync_perm=True):
|
def user_group_add(groupname: str, usernames: list[str], force: bool = False, sync_perm: bool = True) -> Optional[dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
Add user(s) to a group
|
Add user(s) to a group
|
||||||
|
|
||||||
|
@ -1345,7 +1354,7 @@ def user_group_add(groupname, usernames, force=False, sync_perm=True):
|
||||||
return user_group_update(groupname, add=usernames, force=force, sync_perm=sync_perm)
|
return user_group_update(groupname, add=usernames, force=force, sync_perm=sync_perm)
|
||||||
|
|
||||||
|
|
||||||
def user_group_remove(groupname, usernames, force=False, sync_perm=True):
|
def user_group_remove(groupname: str, usernames: list[str], force: bool = False, sync_perm: bool = True) -> Optional[dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
Remove user(s) from a group
|
Remove user(s) from a group
|
||||||
|
|
||||||
|
@ -1359,11 +1368,11 @@ def user_group_remove(groupname, usernames, force=False, sync_perm=True):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def user_group_add_mailalias(groupname, aliases):
|
def user_group_add_mailalias(groupname: str, aliases: list[str]) -> Optional[dict[str, Any]]:
|
||||||
return user_group_update(groupname, add_mailalias=aliases, sync_perm=False)
|
return user_group_update(groupname, add_mailalias=aliases, sync_perm=False)
|
||||||
|
|
||||||
|
|
||||||
def user_group_remove_mailalias(groupname, aliases):
|
def user_group_remove_mailalias(groupname: str, aliases: list[str]) -> Optional[dict[str, Any]]:
|
||||||
return user_group_update(groupname, remove_mailalias=aliases, sync_perm=False)
|
return user_group_update(groupname, remove_mailalias=aliases, sync_perm=False)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1371,14 +1380,15 @@ def user_group_remove_mailalias(groupname, aliases):
|
||||||
# Permission subcategory
|
# Permission subcategory
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# FIXME: missing return type
|
||||||
def user_permission_list(short=False, full=False, apps=[]):
|
def user_permission_list(short: bool = False, full: bool = False, apps: list[str] = []):
|
||||||
from yunohost.permission import user_permission_list
|
from yunohost.permission import user_permission_list
|
||||||
|
|
||||||
return user_permission_list(short, full, absolute_urls=True, apps=apps)
|
return user_permission_list(short, full, absolute_urls=True, apps=apps)
|
||||||
|
|
||||||
|
|
||||||
def user_permission_update(permission, label=None, show_tile=None, sync_perm=True):
|
# FIXME: missing return type
|
||||||
|
def user_permission_update(permission: str, label: Optional[str] = None, show_tile: Optional[bool] = None, sync_perm: bool = True):
|
||||||
from yunohost.permission import user_permission_update
|
from yunohost.permission import user_permission_update
|
||||||
|
|
||||||
return user_permission_update(
|
return user_permission_update(
|
||||||
|
@ -1386,7 +1396,8 @@ def user_permission_update(permission, label=None, show_tile=None, sync_perm=Tru
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def user_permission_add(permission, names, protected=None, force=False, sync_perm=True):
|
# FIXME: missing return type
|
||||||
|
def user_permission_add(permission: str, names: list[str], protected: Optional[bool] = None, force: bool = False, sync_perm: bool = True):
|
||||||
from yunohost.permission import user_permission_update
|
from yunohost.permission import user_permission_update
|
||||||
|
|
||||||
return user_permission_update(
|
return user_permission_update(
|
||||||
|
@ -1394,8 +1405,9 @@ def user_permission_add(permission, names, protected=None, force=False, sync_per
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# FIXME: missing return type
|
||||||
def user_permission_remove(
|
def user_permission_remove(
|
||||||
permission, names, protected=None, force=False, sync_perm=True
|
permission: str, names: list[str], protected: Optional[bool] = None, force: bool = False, sync_perm: bool = True
|
||||||
):
|
):
|
||||||
from yunohost.permission import user_permission_update
|
from yunohost.permission import user_permission_update
|
||||||
|
|
||||||
|
@ -1404,13 +1416,15 @@ def user_permission_remove(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def user_permission_reset(permission, sync_perm=True):
|
# FIXME: missing return type
|
||||||
|
def user_permission_reset(permission: str, sync_perm: bool = True):
|
||||||
from yunohost.permission import user_permission_reset
|
from yunohost.permission import user_permission_reset
|
||||||
|
|
||||||
return user_permission_reset(permission, sync_perm=sync_perm)
|
return user_permission_reset(permission, sync_perm=sync_perm)
|
||||||
|
|
||||||
|
|
||||||
def user_permission_info(permission):
|
# FIXME: missing return type
|
||||||
|
def user_permission_info(permission: str):
|
||||||
from yunohost.permission import user_permission_info
|
from yunohost.permission import user_permission_info
|
||||||
|
|
||||||
return user_permission_info(permission)
|
return user_permission_info(permission)
|
||||||
|
@ -1422,15 +1436,15 @@ def user_permission_info(permission):
|
||||||
import yunohost.ssh
|
import yunohost.ssh
|
||||||
|
|
||||||
|
|
||||||
def user_ssh_list_keys(username):
|
def user_ssh_list_keys(username: str) -> dict[str, dict[str, str]]:
|
||||||
return yunohost.ssh.user_ssh_list_keys(username)
|
return yunohost.ssh.user_ssh_list_keys(username)
|
||||||
|
|
||||||
|
|
||||||
def user_ssh_add_key(username, key, comment):
|
def user_ssh_add_key(username: str, key: str, comment: Optional[str] = None) -> None:
|
||||||
return yunohost.ssh.user_ssh_add_key(username, key, comment)
|
return yunohost.ssh.user_ssh_add_key(username, key, comment)
|
||||||
|
|
||||||
|
|
||||||
def user_ssh_remove_key(username, key):
|
def user_ssh_remove_key(username: str, key: str) -> None:
|
||||||
return yunohost.ssh.user_ssh_remove_key(username, key)
|
return yunohost.ssh.user_ssh_remove_key(username, key)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1438,7 +1452,7 @@ def user_ssh_remove_key(username, key):
|
||||||
# End SSH subcategory
|
# End SSH subcategory
|
||||||
#
|
#
|
||||||
|
|
||||||
def _update_admins_group_aliases(old_main_domain, new_main_domain):
|
def _update_admins_group_aliases(old_main_domain: str, new_main_domain: str) -> None:
|
||||||
current_admin_aliases = user_group_info("admins")["mail-aliases"]
|
current_admin_aliases = user_group_info("admins")["mail-aliases"]
|
||||||
|
|
||||||
aliases_to_remove = [
|
aliases_to_remove = [
|
||||||
|
|
|
@ -1783,7 +1783,7 @@ class GroupOption(BaseChoicesOption):
|
||||||
# TODO remove calls to resources in validators (pydantic V2 should adress this)
|
# TODO remove calls to resources in validators (pydantic V2 should adress this)
|
||||||
from yunohost.user import user_group_list
|
from yunohost.user import user_group_list
|
||||||
|
|
||||||
groups = user_group_list(short=True, include_primary_groups=False)["groups"]
|
groups = list(user_group_list(include_primary_groups=False)["groups"].keys())
|
||||||
|
|
||||||
def _human_readable_group(groupname):
|
def _human_readable_group(groupname):
|
||||||
# i18n: visitors
|
# i18n: visitors
|
||||||
|
|
Loading…
Add table
Reference in a new issue