diff options
| -rw-r--r-- | .guix-channel | 51 | ||||
| -rw-r--r-- | .guix/modules/gn-auth.scm | 2 | ||||
| -rw-r--r-- | gn_auth/auth/authorisation/resources/groups/models.py | 4 | ||||
| -rw-r--r-- | gn_auth/auth/authorisation/resources/models.py | 15 | ||||
| -rw-r--r-- | gn_auth/auth/authorisation/resources/system/models.py | 17 | ||||
| -rw-r--r-- | gn_auth/auth/authorisation/users/collections/models.py | 4 | ||||
| -rw-r--r-- | gn_auth/auth/authorisation/users/views.py | 21 | ||||
| -rwxr-xr-x | setup.py | 2 |
8 files changed, 92 insertions, 24 deletions
diff --git a/.guix-channel b/.guix-channel index 9476e74..2c37401 100644 --- a/.guix-channel +++ b/.guix-channel @@ -3,18 +3,55 @@ (directory ".guix/modules") (dependencies (channel + (name gn-machines) + (url "https://git.genenetwork.org/gn-machines") + (branch "main")) + ;; Until https://issues.guix.gnu.org/68797 is resolved, we need to + ;; explicitly list guix-bioinformatics, guix-forge, guix-past and + ;; guix-rust-past-crates—the dependencies of the gn-machines channel—here. + (channel + (name guix) + (url "https://codeberg.org/guix/guix") + (branch "master") + (commit "0a4740705090acc4c8a10d4f53afc58c9f62e980") + (introduction + (channel-introduction + (version 0) + (commit "9edb3f66fd807b096b48283debdcddccfea34bad") + (signer + "BBB0 2DDF 2CEA F6A8 0D1D E643 A2A0 6DF2 A33A 54FA")))) + (channel + (name guix-forge) + (url "https://git.systemreboot.net/guix-forge/") + (branch "main") + (commit "e43fd9a4d73654d3876e2c698af7da89f3408f89") + (introduction + (channel-introduction + (version 0) + (commit "0432e37b20dd678a02efee21adf0b9525a670310") + (signer + "7F73 0343 F2F0 9F3C 77BF 79D3 2E25 EE8B 6180 2BB3")))) + (channel (name guix-bioinformatics) (url "https://git.genenetwork.org/guix-bioinformatics") - (branch "master")) - ;; FIXME: guix-bioinformatics depends on guix-past. So, there - ;; should be no reason to explicitly depend on guix-past. But, the - ;; channel does not build otherwise. This is probably a guix bug. + (commit "903465c85c9b2ae28480b236c3364da873ca8f51")) (channel (name guix-past) - (url "https://gitlab.inria.fr/guix-hpc/guix-past") + (url "https://codeberg.org/guix-science/guix-past") + (branch "master") + (introduction + (channel-introduction + (version 0) + (commit "c3bc94ee752ec545e39c1b8a29f739405767b51c") + (signer + "3CE4 6455 8A84 FDC6 9DB4 0CFB 090B 1199 3D9A EBB5")))) + (channel + (name guix-rust-past-crates) + (url "https://codeberg.org/guix/guix-rust-past-crates.git") + (branch "trunk") (introduction (channel-introduction (version 0) - (commit "0c119db2ea86a389769f4d2b9c6f5c41c027e336") + (commit "1db24ca92c28255b28076792b93d533eabb3dc6a") (signer - "3CE4 6455 8A84 FDC6 9DB4 0CFB 090B 1199 3D9A EBB5")))))) + "F4C2 D1DF 3FDE EA63 D1D3 0776 ACC6 6D09 CA52 8292")))))) diff --git a/.guix/modules/gn-auth.scm b/.guix/modules/gn-auth.scm index 0dab8d9..0d9cbc9 100644 --- a/.guix/modules/gn-auth.scm +++ b/.guix/modules/gn-auth.scm @@ -1,5 +1,5 @@ (define-module (gn-auth) - #:use-module ((gn packages genenetwork) + #:use-module ((gn-machines genenetwork) #:select (gn-auth) #:prefix gn:) #:use-module ((gnu packages check) #:select (python-pylint)) #:use-module ((gnu packages python-check) #:select (python-mypy)) diff --git a/gn_auth/auth/authorisation/resources/groups/models.py b/gn_auth/auth/authorisation/resources/groups/models.py index a1937ce..6a7af4c 100644 --- a/gn_auth/auth/authorisation/resources/groups/models.py +++ b/gn_auth/auth/authorisation/resources/groups/models.py @@ -428,8 +428,8 @@ gjr.status='PENDING'", return tuple(dict(row)for row in cursor.fetchall()) raise AuthorisationError( - "You do not have the appropriate authorisation to access the " - "group's join requests.") + "You need to be the group's leader in order to access the group's join " + "requests.") @authorised_p(("system:group:view-group", "system:group:edit-group"), diff --git a/gn_auth/auth/authorisation/resources/models.py b/gn_auth/auth/authorisation/resources/models.py index 31371fd..a4df363 100644 --- a/gn_auth/auth/authorisation/resources/models.py +++ b/gn_auth/auth/authorisation/resources/models.py @@ -2,9 +2,10 @@ from dataclasses import asdict from uuid import UUID, uuid4 from functools import reduce, partial -from typing import Dict, Sequence, Optional +from typing import Dict, Union, Sequence, Optional + +from gn_libs import sqlite3 as db -from gn_auth.auth.db import sqlite3 as db from gn_auth.auth.authentication.users import User from gn_auth.auth.db.sqlite3 import with_db_connection @@ -40,7 +41,7 @@ from .phenotypes.models import ( error_description="Insufficient privileges to create a resource", oauth2_scope="profile resource") def create_resource(# pylint: disable=[too-many-arguments, too-many-positional-arguments] - conn: db.DbConnection, + conn: Union[db.DbConnection, db.DbCursor], resource_name: str, resource_category: ResourceCategory, user: User, @@ -48,7 +49,7 @@ def create_resource(# pylint: disable=[too-many-arguments, too-many-positional-a public: bool ) -> Resource: """Create a resource item.""" - with db.cursor(conn) as cursor: + def __create_resource__(cursor: db.DbCursor) -> Resource: resource = Resource(uuid4(), resource_name, resource_category, public) cursor.execute( "INSERT INTO resources VALUES (?, ?, ?, ?)", @@ -75,6 +76,12 @@ def create_resource(# pylint: disable=[too-many-arguments, too-many-positional-a return resource + if hasattr(conn, "cursor"): # This is a connection: get its cursor. + with db.cursor(conn) as cursor: + return __create_resource__(cursor) + else: + return __create_resource__(conn) + def delete_resource(conn: db.DbConnection, resource_id: UUID): """Delete a resource.""" diff --git a/gn_auth/auth/authorisation/resources/system/models.py b/gn_auth/auth/authorisation/resources/system/models.py index 303b0ac..25089fa 100644 --- a/gn_auth/auth/authorisation/resources/system/models.py +++ b/gn_auth/auth/authorisation/resources/system/models.py @@ -1,9 +1,10 @@ """Base functions and utilities for system resources.""" from uuid import UUID from functools import reduce -from typing import Sequence +from typing import Union, Sequence + +from gn_libs import sqlite3 as db -from gn_auth.auth.db import sqlite3 as db from gn_auth.auth.errors import NotFoundError from gn_auth.auth.authentication.users import User @@ -52,9 +53,9 @@ def user_roles_on_system(conn: db.DbConnection, user: User) -> Sequence[Role]: return tuple() -def system_resource(conn: db.DbConnection) -> Resource: +def system_resource(conn: Union[db.DbConnection, db.DbCursor]) -> Resource: """Retrieve the system resource.""" - with db.cursor(conn) as cursor: + def __fetch_sys_resource__(cursor: db.DbCursor) -> Resource: cursor.execute( "SELECT resource_categories.*, resources.resource_id, " "resources.resource_name, resources.public " @@ -65,4 +66,10 @@ def system_resource(conn: db.DbConnection) -> Resource: if row: return resource_from_dbrow(row) - raise NotFoundError("Could not find a system resource!") + raise NotFoundError("Could not find a system resource!") + + if hasattr(conn, "cursor"): # is connection + with db.cursor(conn) as cursor: + return __fetch_sys_resource__(cursor) + else: + return __fetch_sys_resource__(conn) diff --git a/gn_auth/auth/authorisation/users/collections/models.py b/gn_auth/auth/authorisation/users/collections/models.py index 63443ef..30242c2 100644 --- a/gn_auth/auth/authorisation/users/collections/models.py +++ b/gn_auth/auth/authorisation/users/collections/models.py @@ -72,8 +72,8 @@ def __retrieve_old_accounts__(rconn: Redis) -> dict: def parse_collection(coll: dict) -> dict: """Parse the collection as persisted in redis to a usable python object.""" - created = coll.get("created", coll.get("created_timestamp")) - changed = coll.get("changed", coll.get("changed_timestamp")) + created = coll.get("created", coll.get("created_timestamp", "")) + changed = coll.get("changed", coll.get("changed_timestamp", "")) return { "id": UUID(coll["id"]), "name": coll["name"], diff --git a/gn_auth/auth/authorisation/users/views.py b/gn_auth/auth/authorisation/users/views.py index 4061e07..c248ac3 100644 --- a/gn_auth/auth/authorisation/users/views.py +++ b/gn_auth/auth/authorisation/users/views.py @@ -4,9 +4,9 @@ import sqlite3 import secrets import traceback from dataclasses import asdict -from typing import Any, Sequence from urllib.parse import urljoin from functools import reduce, partial +from typing import Any, Union, Sequence from datetime import datetime, timedelta from email.headerregistry import Address from email_validator import validate_email, EmailNotValidError @@ -46,7 +46,8 @@ from gn_auth.auth.errors import ( UserRegistrationError) -from gn_auth.auth.authentication.users import valid_login, user_by_email +from gn_auth.auth.authentication.users import ( + valid_login, user_by_email, user_by_id) from gn_auth.auth.authentication.oauth2.resource_server import require_oauth from gn_auth.auth.authentication.users import User, save_user, set_user_password from gn_auth.auth.authentication.oauth2.models.oauth2token import ( @@ -78,6 +79,22 @@ def user_details() -> Response: **({"group": asdict(the_group)} if the_group else {}) }) +@users.route("/<user_id>", methods=["GET"]) +def get_user(user_id: str) -> Union[Response, tuple[Response, int]]: + """Fetch user details by user_id.""" + try: + with db.connection(current_app.config["AUTH_DB"]) as conn: + user = user_by_id(conn, uuid.UUID(user_id)) + return jsonify({ + "user_id": str(user.user_id), + "email": user.email, + "name": user.name + }) + except ValueError: + return jsonify({"error": "Invalid user ID format"}), 400 + except NotFoundError: + return jsonify({"error": "User not found"}), 404 + @users.route("/roles", methods=["GET"]) @require_oauth("role") def user_roles() -> Response: diff --git a/setup.py b/setup.py index 59cd86f..c7339e2 100755 --- a/setup.py +++ b/setup.py @@ -44,5 +44,5 @@ setup(author="Frederick M. Muriithi", version="0.0.1", tests_require=["pytest", "hypothesis"], cmdclass={ - "run_tests": RunTests # testing + "run_tests": RunTests # type: ignore[dict-item] }) |
