about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2024-06-17 13:53:50 -0500
committerFrederick Muriuki Muriithi2024-06-17 13:53:50 -0500
commit1776582ab9d44758793cab70978b353c00be51bc (patch)
tree7bb8e61897ee34e134724ab206ba326b8e6aa672
parent5612df9436cad6d9b88242cb26c8d2de7fd174e7 (diff)
downloadgn-auth-1776582ab9d44758793cab70978b353c00be51bc.tar.gz
Create a resource role.
-rw-r--r--gn_auth/auth/authorisation/resources/views.py39
-rw-r--r--gn_auth/auth/authorisation/roles/models.py11
2 files changed, 45 insertions, 5 deletions
diff --git a/gn_auth/auth/authorisation/resources/views.py b/gn_auth/auth/authorisation/resources/views.py
index 4583346..736b315 100644
--- a/gn_auth/auth/authorisation/resources/views.py
+++ b/gn_auth/auth/authorisation/resources/views.py
@@ -8,8 +8,9 @@ import time
 from dataclasses import asdict
 from functools import reduce
 
-from authlib.integrations.flask_oauth2.errors import _HTTPException
+from werkzeug.exceptions import BadRequest
 from authlib.jose import jwt
+from authlib.integrations.flask_oauth2.errors import _HTTPException
 from flask import (make_response, request, jsonify, Response,
                    Blueprint, current_app as app)
 
@@ -17,7 +18,9 @@ from gn_auth.auth.db import sqlite3 as db
 from gn_auth.auth.db.sqlite3 import with_db_connection
 
 from gn_auth.auth.authorisation.roles import Role
+from gn_auth.auth.authorisation.roles.models import create_role
 from gn_auth.auth.authorisation.privileges import Privilege
+from gn_auth.auth.authorisation.privileges.models import privileges_by_ids
 from gn_auth.auth.errors import InvalidData, InconsistencyError, AuthorisationError
 from gn_auth.auth.authorisation.roles.models import (
     role_by_id,
@@ -570,3 +573,37 @@ def resource_role_users(resource_id: UUID, role_id: UUID):
         results = cursor.fetchall() or []
 
     return jsonify(tuple(User.from_sqlite3_row(row) for row in results)), 200
+
+
+@resources.route("/<uuid:resource_id>/roles/create", methods=["POST"])
+@require_oauth("profile group resource")
+def create_resource_role(resource_id: UUID):
+    """Create a role to act upon a specific resource."""
+    role_name = request.json.get("role_name", "").strip()
+    if not bool(role_name):
+        raise BadRequest("You must provide the name for the new role.")
+
+    with (require_oauth.acquire("profile group resource") as _token,
+          db.connection(app.config["AUTH_DB"]) as conn,
+          db.cursor(conn) as cursor):
+        resource = resource_by_id(conn, _token.user, resource_id)
+        if not bool(resource):
+            raise BadRequest("No resource with that ID exists.")
+
+        privileges = privileges_by_ids(conn, request.json.get("privileges", []))
+        if len(privileges) == 0:
+            raise BadRequest(
+                "You must provide at least one privilege for the new role.")
+        role = create_role(cursor,
+                           f"{resource.resource_name}::{role_name}",
+                           privileges)
+        cursor.execute(
+            "INSERT INTO resource_roles(resource_id, role_created_by, role_id) "
+            "VALUES (:resource_id, :user_id, :role_id)",
+            {
+                "resource_id": str(resource_id),
+                "user_id": str(_token.user.user_id),
+                "role_id": str(role.role_id)
+            })
+
+    return jsonify(asdict(role))
diff --git a/gn_auth/auth/authorisation/roles/models.py b/gn_auth/auth/authorisation/roles/models.py
index e740bfd..d58c4a1 100644
--- a/gn_auth/auth/authorisation/roles/models.py
+++ b/gn_auth/auth/authorisation/roles/models.py
@@ -54,11 +54,14 @@ def db_rows_to_roles(rows) -> tuple[Role, ...]:
                  if bool(rows) else [])
 
 @authorised_p(
-    privileges = ("group:role:create-role",),
+    privileges = ("resource:role:create-role",),
     error_description="Could not create role")
 def create_role(
-        cursor: db.DbCursor, role_name: str,
-        privileges: Iterable[Privilege]) -> Role:
+        cursor: db.DbCursor,
+        role_name: str,
+        privileges: Iterable[Privilege],
+        user_editable: bool=True
+) -> Role:
     """
     Create a new generic role.
 
@@ -71,7 +74,7 @@ def create_role(
 
     RETURNS: An immutable `gn3.auth.authorisation.roles.Role` object
     """
-    role = Role(uuid4(), role_name, True, tuple(privileges))
+    role = Role(uuid4(), role_name, user_editable, tuple(privileges))
 
     cursor.execute(
         "INSERT INTO roles(role_id, role_name, user_editable) VALUES (?, ?, ?)",