from argparse import Namespace from typing import Any, Final import requests from mdrsclient.commands.base import BaseCommand from mdrsclient.exceptions import IllegalArgumentException, MDRSException from mdrsclient.models import FolderAccessLevel class ChaclCommand(BaseCommand): ACCESS_LEVEL_HELP: Final[str] = ( "access level: private, pw_open, cbs_open, project_open, " "or several open levels joined by `_or_` (e.g. cbs_or_pw_open). " " is the project's bit position; an invalid level lists the projects you belong to" ) @classmethod def register(cls, parsers: Any) -> None: chacl_parser = parsers.add_parser("chacl", help="change the folder access level") chacl_parser.add_argument("access_level", help=cls.ACCESS_LEVEL_HELP) chacl_parser.add_argument("-r", "--recursive", help="change access levels recursively", action="store_true") chacl_parser.add_argument( "-p", "--password", help="password to set when the access level includes `pw` (e.g. pw_open)" ) chacl_parser.add_argument("remote_path", help="remote folder path (remote:/lab/path/)") chacl_parser.set_defaults(func=cls.func) @classmethod def func(cls, args: Namespace) -> None: remote_path = str(args.remote_path) access_level = FolderAccessLevel.key2id(str(args.access_level)) if access_level is None: raise IllegalArgumentException(cls._invalid_level_message(remote_path)) if access_level in (FolderAccessLevel.STORAGE, FolderAccessLevel.PUBLIC): # The server refuses both; saying so here spares a round trip and a bare 400. raise IllegalArgumentException(f"`{args.access_level}` cannot be set as an access level.") password = str(args.password) if args.password else None is_recursive = bool(args.recursive) cls.chacl(remote_path, access_level, is_recursive, password) @classmethod def chacl(cls, remote_path: str, access_level: int, is_recursive: bool, password: str | None) -> None: remote = remote_path.split(":", 1)[0] if ":" in remote_path else "" from mdrsclient.client import MdrsClient client = MdrsClient.from_remote(remote) client.chacl(remote_path, access_level, is_recursive, password) @classmethod def _invalid_level_message(cls, remote_path: str) -> str: message = ( "Invalid `access_level` parameter. must be `private`, `pw_open`, `cbs_open`, `project_open` " "or open levels joined by `_or_` (e.g. `cbs_or_pw_open`)." ) remote = remote_path.split(":", 1)[0] if ":" in remote_path else "" from mdrsclient.client import MdrsClient # The project numbers are known only to the server, and only for the user's own # projects. Not reaching it leaves the message as it is: the error being reported # is the level, not the connection. try: projects = MdrsClient.from_remote(remote).project_names() except (MDRSException, requests.RequestException): return message if not projects: return message lines = [f" project{bit}_open: {name}" for bit, name in sorted(projects.items())] return "\n".join([message, "Projects you belong to:", *lines])