about summary refs log tree commit diff
path: root/gn_auth/auth
diff options
context:
space:
mode:
Diffstat (limited to 'gn_auth/auth')
-rw-r--r--gn_auth/auth/authorisation/resources/checks.py1
-rw-r--r--gn_auth/auth/authorisation/resources/models.py32
-rw-r--r--gn_auth/auth/authorisation/resources/system/views.py27
-rw-r--r--gn_auth/auth/authorisation/resources/views.py59
-rw-r--r--gn_auth/auth/errors.py2
5 files changed, 96 insertions, 25 deletions
diff --git a/gn_auth/auth/authorisation/resources/checks.py b/gn_auth/auth/authorisation/resources/checks.py
index bc9e4da..004c780 100644
--- a/gn_auth/auth/authorisation/resources/checks.py
+++ b/gn_auth/auth/authorisation/resources/checks.py
@@ -199,4 +199,3 @@ def can_edit(
             user_id,
             system_resource(conn).resource_id,
             "(OR system:system-wide:data:edit system:resource:edit)"))
-
diff --git a/gn_auth/auth/authorisation/resources/models.py b/gn_auth/auth/authorisation/resources/models.py
index 8c9abc7..27ef183 100644
--- a/gn_auth/auth/authorisation/resources/models.py
+++ b/gn_auth/auth/authorisation/resources/models.py
@@ -16,10 +16,9 @@ from gn_auth.auth.authorisation.privileges import Privilege
 from gn_auth.auth.authorisation.checks import authorised_p
 from gn_auth.auth.errors import NotFoundError, AuthorisationError
 
-from .system.models import system_resource
+from .common import assign_resource_owner_role
 from .checks import can_edit, authorised_for_spec
 from .base import Resource, ResourceCategory, resource_from_dbrow
-from .common import assign_resource_owner_role, grant_access_to_sysadmins
 from .groups.models import Group, is_group_leader
 from .inbredset.models import resource_data as inbredset_resource_data
 from .mrna import (
@@ -79,8 +78,6 @@ def create_resource(# pylint: disable=[too-many-arguments, too-many-positional-a
                        "VALUES (?, ?)",
                        (str(group.group_id), str(resource.resource_id)))
         assign_resource_owner_role(cursor, resource.resource_id, user.user_id)
-        grant_access_to_sysadmins(
-            cursor, resource.resource_id, system_resource(conn).resource_id)
 
         return resource
 
@@ -106,6 +103,27 @@ def delete_resource(conn: db.DbConnection, resource_id: UUID):
                        (str(resource_id),))
 
 
+def edit_resource(conn: db.DbConnection, resource_id: UUID, name: str) -> Resource:
+    """Edit basic resource details."""
+    with db.cursor(conn) as cursor:
+        cursor.execute("UPDATE resources SET resource_name=? "
+                       "WHERE resource_id=?",
+                       (name, str(resource_id)))
+        cursor.execute(
+            "SELECT r.*, rc.* FROM resources AS r "
+            "INNER JOIN resource_categories AS rc "
+            "ON r.resource_category_id=rc.resource_category_id "
+            "WHERE r.resource_id=?",
+            (str(resource_id),))
+        _resource = resource_from_dbrow(cursor.fetchone())
+        cursor.execute(
+            "SELECT u.* FROM resources AS r INNER JOIN users AS u "
+            "ON r.created_by=u.user_id WHERE r.resource_id=?",
+            (str(resource_id),))
+        return Resource.from_resource(
+            _resource, created_by=User.from_sqlite3_row(cursor.fetchone()))
+
+
 def resource_category_by_id(
         conn: db.DbConnection, category_id: UUID) -> ResourceCategory:
     """Retrieve a resource category by its ID."""
@@ -315,8 +333,7 @@ def link_data_to_resource(
     """Link data to resource."""
     if not can_edit(conn, user.user_id, resource_id):
         raise AuthorisationError(
-            "You are not authorised to link data to resource with id "
-            f"{resource_id}")
+            "You are not authorised to link/unlink data to this resource.")
 
     resource = with_db_connection(partial(
         resource_by_id, user=user, resource_id=resource_id))
@@ -331,8 +348,7 @@ def unlink_data_from_resource(
     """Unlink data from resource."""
     if not can_edit(conn, user.user_id, resource_id):
         raise AuthorisationError(
-            "You are not authorised to link data to resource with id "
-            f"{resource_id}")
+            "You are not authorised to link/unlink data this resource.")
 
     resource = with_db_connection(partial(
         resource_by_id, user=user, resource_id=resource_id))
diff --git a/gn_auth/auth/authorisation/resources/system/views.py b/gn_auth/auth/authorisation/resources/system/views.py
index b0d40c2..d7a57a9 100644
--- a/gn_auth/auth/authorisation/resources/system/views.py
+++ b/gn_auth/auth/authorisation/resources/system/views.py
@@ -1,19 +1,34 @@
 """Views relating to `System` resource(s)."""
+import logging
 from dataclasses import asdict
-from flask import jsonify, Blueprint
+from flask import request, jsonify, Blueprint, current_app as app
 
-from gn_auth.auth.db.sqlite3 import with_db_connection
+from gn_libs import sqlite3 as authdb
 
+from gn_auth.auth.authorisation.roles.models import db_rows_to_roles
 from gn_auth.auth.authentication.oauth2.resource_server import require_oauth
 
 from .models import user_roles_on_system
 
+logger = logging.getLogger(__name__)
 system = Blueprint("system", __name__)
 
+
 @system.route("/roles")
 def system_roles():
     """Get the roles that a user has that act on the system."""
-    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(asdict(role) for role in roles))
+    with (authdb.connection(app.config["AUTH_DB"]) as conn,
+          authdb.cursor(conn) as cursor):
+        if not bool(request.headers.get("Authorization", False)):
+            cursor.execute(
+                "SELECT r.*, p.* FROM roles AS r "
+                "INNER JOIN role_privileges AS rp ON r.role_id=rp.role_id "
+                "INNER JOIN privileges AS p ON rp.privilege_id=p.privilege_id "
+                "WHERE r.role_name='public-view'")
+            return jsonify(tuple(
+                asdict(role) for role in db_rows_to_roles(cursor.fetchall())))
+
+        with require_oauth.acquire("profile group") as the_token:
+            return jsonify(tuple(
+                asdict(role) for role in
+                user_roles_on_system(conn, the_token.user)))
diff --git a/gn_auth/auth/authorisation/resources/views.py b/gn_auth/auth/authorisation/resources/views.py
index 4b6c36c..ab44795 100644
--- a/gn_auth/auth/authorisation/resources/views.py
+++ b/gn_auth/auth/authorisation/resources/views.py
@@ -1,9 +1,10 @@
 """The views/routes for the resources package"""
-from uuid import UUID, uuid4
+import time
 import json
+import logging
 import operator
 import sqlite3
-import time
+from uuid import UUID, uuid4
 
 from dataclasses import asdict
 from functools import reduce
@@ -13,6 +14,7 @@ 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)
+import gn_libs.privileges.resources
 
 from gn_auth.auth.requests import request_json
 
@@ -43,6 +45,7 @@ from .inbredset.views import popbp
 from .genotypes.views import genobp
 from .phenotypes.views import phenobp
 from .errors import MissingGroupError
+from .system.models import system_resource
 from .groups.models import Group, user_group
 from .checks import can_delete, authorised_for
 from .models import (
@@ -50,7 +53,10 @@ from .models import (
     resource_categories, assign_resource_user, link_data_to_resource,
     unassign_resource_user, resource_category_by_id, user_roles_on_resources,
     unlink_data_from_resource, create_resource as _create_resource,
-    get_resource_id, delete_resource as _delete_resource)
+    get_resource_id, delete_resource as _delete_resource,
+    edit_resource as _edit_resource)
+
+logger = logging.getLogger(__name__)
 
 resources = Blueprint("resources", __name__)
 resources.register_blueprint(popbp, url_prefix="/")
@@ -95,8 +101,7 @@ def create_resource() -> Response:
                                       "resources.resource_name"):
                     raise InconsistencyError(
                         "You cannot have duplicate resource names.") from sql3ie
-                app.logger.debug(
-                    f"{type(sql3ie)=}: {sql3ie=}")
+                logger.debug("type(sql3ie)=%s: sql3ie=%s", type(sql3ie), sql3ie)
                 raise
 
 
@@ -114,6 +119,43 @@ def view_resource(resource_id: UUID) -> Response:
                 )
             )
 
+
+@resources.route("/<uuid:resource_id>/edit", methods=["POST"])
+@require_oauth("profile group resource")
+def edit_resource(resource_id: UUID) -> Response:
+    """Update/edit basic details regarding a resource."""
+    db_uri = app.config["AUTH_DB"]
+    with (require_oauth.acquire("profile group resource") as _token,
+          db.connection(db_uri) as conn):
+        _privileges = tuple(
+            privilege.privilege_id
+            for role in (
+                    role for resource in user_roles_on_resources(
+                        conn,
+                        _token.user,
+                        (resource_id, system_resource(conn).resource_id)
+                    ).values()
+                    for role in resource.get("roles", tuple()))
+            for privilege in role.privileges)
+        if not gn_libs.privileges.resources.can_edit(_privileges):
+            return make_response(jsonify({
+                "error": "AuthorisationError",
+                "error_description": "You are not allowed to edit this resource."
+            }), 401)
+
+        name = (request_json().get("resource_name") or "").strip()
+        if bool(name):
+            return jsonify({
+                "resource": asdict(_edit_resource(conn, resource_id, name)),
+                "message": "Resource updated successfully",
+                "status": "success"
+            })
+
+        return make_response(jsonify({
+            "error_description": "Expected `resource_name` to be provided.",
+            "error": "InvalidInput"
+        }), 400)
+
 def __safe_get_requests_page__(key: str = "page") -> int:
     """Get the results page if it exists or default to the first page."""
     try:
@@ -468,7 +510,7 @@ def resources_authorisation():
         })
         resp.status_code = 400
     except Exception as _exc:#pylint: disable=[broad-except]
-        app.logger.debug("Generic exception.", exc_info=True)
+        logger.debug("Generic exception.", exc_info=True)
         resp = jsonify({
             "status": "general-exception",
             "error_description": (
@@ -506,7 +548,6 @@ def get_user_roles_on_resource(name) -> Response:
         response = make_response({
             # Flatten this list
             "roles": roles,
-            "silly": "ausah",
         })
         iat = int(time.time())
         jose_header = {
@@ -705,13 +746,13 @@ def delete_resource():
                 "description": f"Successfully deleted resource with ID '{resource_id}'."
             })
         except ValueError as _verr:
-            app.logger.debug("Error!", exc_info=True)
+            logger.debug("Error!", exc_info=True)
             return jsonify({
                 "error": "ValueError",
                 "error-description": "An invalid identifier was provided"
             }), 400
         except TypeError as _terr:
-            app.logger.debug("Error!", exc_info=True)
+            logger.debug("Error!", exc_info=True)
             return jsonify({
                 "error": "TypeError",
                 "error-description": "An invalid identifier was provided"
diff --git a/gn_auth/auth/errors.py b/gn_auth/auth/errors.py
index 77b73aa..c499e86 100644
--- a/gn_auth/auth/errors.py
+++ b/gn_auth/auth/errors.py
@@ -6,7 +6,7 @@ class AuthorisationError(Exception):
 
     All exceptions in this package should inherit from this class.
     """
-    error_code: int = 400
+    error_code: int = 401
 
 class ForbiddenAccess(AuthorisationError):
     """Raised for forbidden access."""