feat: build access level labels from their bits and project names
Labels came from a fixed table matched by subset, so Storage (no bits) matched any level the table lacked, and a level was named after the first entry it contained: the server's Brain/MINDS 2.0 folders (0x10000) showed as Storage and 0x10104 as CBS or PW Open. Labels are now composed from the bits. Projects (bit 16 and up) take the names the server reports to their members through users/current/, and otherwise Project<n>; restrict slot 1 is CBS and any other Restrict<n>. A level with no meaning is shown as Unknown (0x...). chacl reads keys built the same way, refuses public and storage before any request, and lists the user's projects with their keys when given an invalid level.
This commit is contained in:
@@ -1,18 +1,28 @@
|
||||
from argparse import Namespace
|
||||
from typing import Any
|
||||
from typing import Any, Final
|
||||
|
||||
import requests
|
||||
|
||||
from mdrsclient.commands.base import BaseCommand
|
||||
from mdrsclient.exceptions import IllegalArgumentException
|
||||
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<n>_open, "
|
||||
"or several open levels joined by `_or_` (e.g. cbs_or_pw_open). "
|
||||
"<n> 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="access level (private, cbs_open, pw_open)")
|
||||
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 access level is `pw_open`")
|
||||
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)
|
||||
|
||||
@@ -21,9 +31,10 @@ class ChaclCommand(BaseCommand):
|
||||
remote_path = str(args.remote_path)
|
||||
access_level = FolderAccessLevel.key2id(str(args.access_level))
|
||||
if access_level is None:
|
||||
raise IllegalArgumentException(
|
||||
"Invalid `access_level` parameter. must be `private`, `cbs_open` or `pw_open`."
|
||||
)
|
||||
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)
|
||||
@@ -35,3 +46,24 @@ class ChaclCommand(BaseCommand):
|
||||
|
||||
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<n>_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])
|
||||
|
||||
Reference in New Issue
Block a user