about summary refs log tree commit diff
path: root/gn_auth/auth/system/admin/users.py
diff options
context:
space:
mode:
authorClaude Sonnet 4.62026-08-31 10:00:00 +0000
committerFrederick Muriuki Muriithi2026-08-31 10:24:53 -0500
commit5b4380e61e003a9b4450221d0f499db069098c19 (patch)
treef15007e45f68995dc1eb95fbf8e927f8751baef1 /gn_auth/auth/system/admin/users.py
parent58c6f7a9eedc77c7268dc350387f78f77d619eac (diff)
downloadgn-auth-5b4380e61e003a9b4450221d0f499db069098c19.tar.gz
Move create_new_user to gn_auth/auth/system/admin/users.py
Move the user-creation endpoint from gn_auth/auth/authorisation/users/views.py
into the new sysadmin package at gn_auth/auth/system/admin/users.py.

New URL: POST /auth/system/administration/users/create
Old URL: POST /auth/user/create now issues a 308 Permanent Redirect.

The admin blueprint is updated to register the new users blueprint at /users.

Reviewed-By: Frederick M. Muriithi <fredmanglis@gmail.com>
Diffstat (limited to 'gn_auth/auth/system/admin/users.py')
-rw-r--r--gn_auth/auth/system/admin/users.py67
1 files changed, 67 insertions, 0 deletions
diff --git a/gn_auth/auth/system/admin/users.py b/gn_auth/auth/system/admin/users.py
new file mode 100644
index 0000000..f26518b
--- /dev/null
+++ b/gn_auth/auth/system/admin/users.py
@@ -0,0 +1,67 @@
+"""Administrative endpoints for user management."""
+from flask import jsonify, Response, Blueprint, make_response, current_app as app
+
+from gn_libs import sqlite3 as db
+
+from email_validator import validate_email, EmailNotValidError
+
+from gn_libs.privileges.system import can_create_or_delete_user
+
+from gn_auth.auth.errors import (
+    PasswordError,
+    UsernameError,
+    ForbiddenAccess,
+    UserRegistrationError)
+from gn_auth.auth.requests import request_json
+from gn_auth.auth.authentication.oauth2.resource_server import require_oauth
+from gn_auth.auth.authorisation.resources.system.models import user_roles_on_system
+from gn_auth.auth.authorisation.users.admin.models import create_verified_user
+from gn_auth.auth.authorisation.users.views import (
+    validate_password,
+    validate_username)
+
+users = Blueprint("users", __name__)
+
+
+@users.route("/create", methods=["POST"])
+def create_user() -> Response:
+    """Create a new user. Requires system:user:create-user privilege."""
+    with (require_oauth.acquire("profile") as token,
+          db.connection(app.config["AUTH_DB"]) as conn):
+        u_roles = user_roles_on_system(conn, token.user)
+        if not can_create_or_delete_user(tuple(
+                priv.privilege_id for role in u_roles
+                for priv in role.privileges)):
+            raise ForbiddenAccess(
+                "You need the `system:user:create-user` privilege.")
+        form = request_json()
+        errors = {}
+        try:
+            email = validate_email(
+                form.get("email", "").strip(), check_deliverability=False)
+        except EmailNotValidError as enve:
+            errors["email"] = (
+                f"E-Mail error: {'==>'.join(str(arg) for arg in enve.args)}")
+
+        try:
+            username = validate_username(form.get("name", "").strip())
+        except UsernameError as uerr:
+            errors["name"] = str(uerr.args[0])
+
+        try:
+            passwd = validate_password(
+                form.get("password", "").strip(),
+                form.get("password", "").strip())
+        except PasswordError as perr:
+            errors["password"] = str(perr.args[0])
+
+        if len(tuple(errors.keys())) > 0:
+            raise UserRegistrationError(tuple(errors.values()))
+
+        user = create_verified_user(conn, email.normalized, username, passwd)
+
+    return make_response(jsonify({
+        "user_id": str(user.user_id),
+        "email": user.email,
+        "name": user.name
+    }), 201)