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,3 +1,4 @@
|
||||
from dataclasses import field
|
||||
from typing import Final
|
||||
|
||||
import requests
|
||||
@@ -20,6 +21,13 @@ class UsersCurrentResponseLaboratory:
|
||||
role: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UsersCurrentResponseProject:
|
||||
id: int
|
||||
name: str | None
|
||||
bit_position: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UsersApiCurrentResponse:
|
||||
id: int
|
||||
@@ -35,6 +43,7 @@ class UsersApiCurrentResponse:
|
||||
is_reviewer: bool
|
||||
last_login: str # ISO8601
|
||||
date_joined: str # ISO8601
|
||||
projects: list[UsersCurrentResponseProject] = field(default_factory=list)
|
||||
|
||||
|
||||
class UsersApi(BaseApi):
|
||||
@@ -50,6 +59,20 @@ class UsersApi(BaseApi):
|
||||
user = User(id=obj.id, username=obj.username, laboratory_ids=laboratory_ids, is_reviewer=obj.is_reviewer)
|
||||
return user
|
||||
|
||||
def project_names(self) -> dict[int, str]:
|
||||
"""Names of the user's projects by bit_position, the bit their access level sets."""
|
||||
url = self.ENTRYPOINT + "current/"
|
||||
response = self.connection.get(url)
|
||||
self._raise_response_error(response)
|
||||
obj = TypeAdapter(UsersApiCurrentResponse).validate_python(response.json())
|
||||
names: dict[int, list[str]] = {}
|
||||
for project in obj.projects:
|
||||
if project.name:
|
||||
# bit_position is not unique on the server, and a folder at a shared bit
|
||||
# belongs to every project holding it, so all of them are named.
|
||||
names.setdefault(project.bit_position, []).append(project.name)
|
||||
return {bit: ", ".join(sorted(x)) for bit, x in names.items()}
|
||||
|
||||
def token(self, username: str, password: str) -> Token:
|
||||
# print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name)
|
||||
url = self.ENTRYPOINT + "token/"
|
||||
|
||||
Reference in New Issue
Block a user