about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.guix-channel51
-rw-r--r--.guix/modules/gn-auth.scm2
-rw-r--r--gn_auth/auth/authorisation/resources/groups/models.py4
-rw-r--r--gn_auth/auth/authorisation/resources/models.py15
-rw-r--r--gn_auth/auth/authorisation/resources/system/models.py17
-rw-r--r--gn_auth/auth/authorisation/users/collections/models.py4
-rw-r--r--gn_auth/auth/authorisation/users/views.py21
-rwxr-xr-xsetup.py2
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]
       })