From 8ccf7409f6c89c3c5079a73c73dc2f6bfae086a7 Mon Sep 17 00:00:00 2001 From: Munyoki Kilyungi Date: Tue, 12 Mar 2024 00:29:30 +0300 Subject: Define Privilege/Role using frozen dataclass. * gn_auth/auth/authorisation/privileges.py: Import dataclass. Remove NamedTuple import. (Privilege): Use frozen dataclass. (Privelege.dictify): Delete. * gn_auth/auth/authorisation/resources/groups/views.py: Import dataclasses.asdict. (group_privileges): Replace dictify with asdict. (add_priv_to_role): Ditto. (delete_priv_from_role): Ditto. * gn_auth/auth/authorisation/resources/models.py: (assign_resource_user): Replace dictify with asdict. (unassign_resource_user): Ditto. * gn_auth/auth/authorisation/resources/system/views.py: Import dataclasses.asdict. Remove dictify import. (system_roles): Replace dictify with asdict. * gn_auth/auth/authorisation/resources/views.py: (resource_users): Replace dictify with asdict. (resources_authorisation): Ditto. * gn_auth/auth/authorisation/roles/models.py: Remove dictify and NameTuple import. (Role): Use frozen dataclass. (Role.dictify): Replace dictify(priv) with asdict(priv). * gn_auth/auth/authorisation/roles/views.py: Import dataclasses.asdict. Remove dictify import. (view_role): Replace dictify with asdict. * gn_auth/auth/authorisation/users/views.py: (user_roles): Replace dictify with asdict. Signed-off-by: Munyoki Kilyungi --- gn_auth/auth/authorisation/privileges.py | 13 +++++-------- gn_auth/auth/authorisation/resources/groups/views.py | 8 ++++---- gn_auth/auth/authorisation/resources/models.py | 4 ++-- gn_auth/auth/authorisation/resources/system/views.py | 5 ++--- gn_auth/auth/authorisation/resources/views.py | 4 ++-- gn_auth/auth/authorisation/roles/models.py | 14 +++++--------- gn_auth/auth/authorisation/roles/views.py | 5 +++-- gn_auth/auth/authorisation/users/views.py | 2 +- 8 files changed, 24 insertions(+), 31 deletions(-) diff --git a/gn_auth/auth/authorisation/privileges.py b/gn_auth/auth/authorisation/privileges.py index bba6258..99f41fc 100644 --- a/gn_auth/auth/authorisation/privileges.py +++ b/gn_auth/auth/authorisation/privileges.py @@ -1,20 +1,17 @@ """Handle privileges""" -from typing import Any, Iterable, NamedTuple +from dataclasses import dataclass +from typing import Any, Iterable from ..db import sqlite3 as db from ..authentication.users import User -class Privilege(NamedTuple): + +@dataclass(frozen=True) +class Privilege: """Class representing a privilege: creates immutable objects.""" privilege_id: str privilege_description: str - def dictify(self) -> dict[str, Any]: - """Return a dict representation of `Privilege` objects.""" - return { - "privilege_id": self.privilege_id, - "privilege_description": self.privilege_description - } def user_privileges(conn: db.DbConnection, user: User) -> Iterable[Privilege]: """Fetch the user's privileges from the database.""" diff --git a/gn_auth/auth/authorisation/resources/groups/views.py b/gn_auth/auth/authorisation/resources/groups/views.py index 8b471ff..303368c 100644 --- a/gn_auth/auth/authorisation/resources/groups/views.py +++ b/gn_auth/auth/authorisation/resources/groups/views.py @@ -5,8 +5,8 @@ import uuid import datetime from typing import Iterable from functools import partial - from dataclasses import asdict + from MySQLdb.cursors import DictCursor from flask import request, jsonify, Response, Blueprint, current_app @@ -331,7 +331,7 @@ def group_privileges(): privilege for arole in this_user_roles for privilege in arole.privileges) + group_level_roles #type: ignore[attr-defined] return jsonify(tuple( - dictify(priv) for priv in with_db_connection(__list_privileges__))) + asdict(priv) for priv in with_db_connection(__list_privileges__))) @@ -420,7 +420,7 @@ def add_priv_to_role(group_role_id: uuid.UUID) -> Response: """Add privilege to group role.""" with require_oauth.acquire("profile group role") as the_token: return jsonify({ - **dictify(with_db_connection(partial( + **asdict(with_db_connection(partial( __add_remove_priv_to_from_role__, group_role_id=group_role_id, direction="ADD", user=the_token.user))), "description": "Privilege added successfully" @@ -432,7 +432,7 @@ def delete_priv_from_role(group_role_id: uuid.UUID) -> Response: """Delete privilege from group role.""" with require_oauth.acquire("profile group role") as the_token: return jsonify({ - **dictify(with_db_connection(partial( + **asdict(with_db_connection(partial( __add_remove_priv_to_from_role__, group_role_id=group_role_id, direction="DELETE", user=the_token.user))), "description": "Privilege deleted successfully" diff --git a/gn_auth/auth/authorisation/resources/models.py b/gn_auth/auth/authorisation/resources/models.py index 7ebf5f7..97e6adf 100644 --- a/gn_auth/auth/authorisation/resources/models.py +++ b/gn_auth/auth/authorisation/resources/models.py @@ -343,7 +343,7 @@ def assign_resource_user( return { "resource": dictify(resource), "user": asdict(user), - "role": dictify(role), + "role": asdict(role), "description": ( f"The user '{user.name}'({user.email}) was assigned the " f"'{role.role.role_name}' role on resource with ID " @@ -367,7 +367,7 @@ def unassign_resource_user( return { "resource": dictify(resource), "user": asdict(user), - "role": dictify(role), + "role": asdict(role), "description": ( f"The user '{user.name}'({user.email}) had the " f"'{role.role.role_name}' role on resource with ID " diff --git a/gn_auth/auth/authorisation/resources/system/views.py b/gn_auth/auth/authorisation/resources/system/views.py index 70e28d6..b0d40c2 100644 --- a/gn_auth/auth/authorisation/resources/system/views.py +++ b/gn_auth/auth/authorisation/resources/system/views.py @@ -1,12 +1,11 @@ """Views relating to `System` resource(s).""" +from dataclasses import asdict from flask import jsonify, Blueprint from gn_auth.auth.db.sqlite3 import with_db_connection from gn_auth.auth.authentication.oauth2.resource_server import require_oauth -from gn_auth.auth.dictify import dictify - from .models import user_roles_on_system system = Blueprint("system", __name__) @@ -17,4 +16,4 @@ def system_roles(): with require_oauth.acquire("profile group") as the_token: roles = with_db_connection( lambda conn: user_roles_on_system(conn, the_token.user)) - return jsonify(tuple(dictify(role) for role in roles)) + return jsonify(tuple(asdict(role) for role in roles)) diff --git a/gn_auth/auth/authorisation/resources/views.py b/gn_auth/auth/authorisation/resources/views.py index 5d00f8c..43ee08b 100644 --- a/gn_auth/auth/authorisation/resources/views.py +++ b/gn_auth/auth/authorisation/resources/views.py @@ -193,9 +193,9 @@ def resource_users(resource_id: uuid.UUID): "users.") results = ( { - "roles": tuple(dictify(role) for role in row["roles"]) "user": asdict(row["user"]), "user_group": asdict(row["user_group"]), + "roles": tuple(asdict(role) for role in row["roles"]) } for row in ( user_row for user_id, user_row in with_db_connection(__the_users__).items())) @@ -347,7 +347,7 @@ def resources_authorisation(): str(resid): { "public-read": resid in pubres, "roles": tuple( - dictify(rol) for rol in + asdict(rol) for rol in the_resources.get(resid, {}).get("roles", tuple())) } for resid in resource_ids }) diff --git a/gn_auth/auth/authorisation/roles/models.py b/gn_auth/auth/authorisation/roles/models.py index a3a9d5b..74f9e64 100644 --- a/gn_auth/auth/authorisation/roles/models.py +++ b/gn_auth/auth/authorisation/roles/models.py @@ -3,30 +3,26 @@ from uuid import UUID, uuid4 from functools import reduce from typing import Any, Sequence, Iterable, NamedTuple +from typing import Any, Sequence, Iterable + from pymonad.either import Left, Right, Either from ...db import sqlite3 as db -from ...dictify import dictify from ...authentication.users import User from ..checks import authorised_p from ..privileges import Privilege from ..errors import NotFoundError, AuthorisationError -class Role(NamedTuple): + +@dataclass(frozen=True) +class Role: """Class representing a role: creates immutable objects.""" role_id: UUID role_name: str user_editable: bool privileges: tuple[Privilege, ...] - def dictify(self) -> dict[str, Any]: - """Return a dict representation of `Role` objects.""" - return { - "role_id": self.role_id, "role_name": self.role_name, - "user_editable": self.user_editable, - "privileges": tuple(dictify(priv) for priv in self.privileges) - } def check_user_editable(role: Role): """Raise an exception if `role` is not user editable.""" diff --git a/gn_auth/auth/authorisation/roles/views.py b/gn_auth/auth/authorisation/roles/views.py index a9b337f..00def89 100644 --- a/gn_auth/auth/authorisation/roles/views.py +++ b/gn_auth/auth/authorisation/roles/views.py @@ -1,9 +1,10 @@ """The views/routes for the `gn3.auth.authorisation.roles` package.""" import uuid +from dataclasses import asdict + from flask import jsonify, Response, Blueprint, current_app -from ...dictify import dictify from ...db import sqlite3 as db from .models import user_role @@ -23,4 +24,4 @@ def view_role(role_id: uuid.UUID) -> Response: with db.connection(db_uri) as conn: the_role = user_role(conn, the_token.user, role_id) return the_role.either( - __error__, lambda a_role: jsonify((dictify(a_role[0]), str(a_role[1])))) + __error__, lambda a_role: jsonify((asdict(a_role[0]), str(a_role[1])))) diff --git a/gn_auth/auth/authorisation/users/views.py b/gn_auth/auth/authorisation/users/views.py index ae3c45e..f9353eb 100644 --- a/gn_auth/auth/authorisation/users/views.py +++ b/gn_auth/auth/authorisation/users/views.py @@ -57,7 +57,7 @@ def user_roles() -> Response: with require_oauth.acquire("role") as token: with db.connection(current_app.config["AUTH_DB"]) as conn: return jsonify(tuple( - {**role, "roles": tuple(dictify(rol) for rol in role["roles"])} + {**role, "roles": tuple(asdict(rol) for rol in role["roles"])} for role in _user_roles(conn, token.user))) def validate_password(password, confirm_password) -> str: -- cgit v1.2.3