From 10479a625abda1b8c8f0ffa74a91d5d66aa597cb Mon Sep 17 00:00:00 2001 From: Luka Radenovic Date: Thu, 14 Apr 2022 13:32:35 +0200 Subject: [PATCH] Added new endpoint for roles and updated users endpoints to work with roles --- app.py | 1 + areas/apps/models.py | 5 ++- areas/roles/__init__.py | 2 ++ areas/{users => roles}/models.py | 0 areas/roles/role_service.py | 8 +++++ areas/roles/roles.py | 15 ++++++++ areas/users/__init__.py | 2 +- areas/users/user_service.py | 61 ++++++++++++++++++++++++++++++++ areas/users/users.py | 20 +++++------ areas/users/validation.py | 7 +++- 10 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 areas/roles/__init__.py rename areas/{users => roles}/models.py (100%) create mode 100644 areas/roles/role_service.py create mode 100644 areas/roles/roles.py create mode 100644 areas/users/user_service.py diff --git a/app.py b/app.py index 79a4ad2..6e74b2f 100644 --- a/app.py +++ b/app.py @@ -13,6 +13,7 @@ from web import web from areas import users from areas import apps from areas import auth +from areas import roles from cliapp import cliapp from web import login diff --git a/areas/apps/models.py b/areas/apps/models.py index 85dc4ae..a9afdaf 100644 --- a/areas/apps/models.py +++ b/areas/apps/models.py @@ -1,4 +1,5 @@ from sqlalchemy import ForeignKey, Integer, String +from sqlalchemy.orm import relationship from database import db @@ -25,5 +26,7 @@ class AppRole(db.Model): app_id = db.Column(Integer, ForeignKey("app.id"), primary_key=True) role_id = db.Column(Integer, ForeignKey("role.id")) + role = relationship("Role") + def __repr__(self): - return f"{self.role} for {self.user_id} on {self.app_id}" + return f"role_id: {self.role_id}, user_id: {self.user_id}, app_id: {self.app_id}, role: {self.role}" diff --git a/areas/roles/__init__.py b/areas/roles/__init__.py new file mode 100644 index 0000000..57b8206 --- /dev/null +++ b/areas/roles/__init__.py @@ -0,0 +1,2 @@ +from .roles import * +from .models import * diff --git a/areas/users/models.py b/areas/roles/models.py similarity index 100% rename from areas/users/models.py rename to areas/roles/models.py diff --git a/areas/roles/role_service.py b/areas/roles/role_service.py new file mode 100644 index 0000000..3eb3207 --- /dev/null +++ b/areas/roles/role_service.py @@ -0,0 +1,8 @@ +from .models import Role + + +class RoleService: + @staticmethod + def get_roles(): + roles = Role.query.all() + return [{"id": r.id, "name": r.name} for r in roles] diff --git a/areas/roles/roles.py b/areas/roles/roles.py new file mode 100644 index 0000000..8f2cdd2 --- /dev/null +++ b/areas/roles/roles.py @@ -0,0 +1,15 @@ +from flask import jsonify, request +from flask_jwt_extended import jwt_required +from flask_cors import cross_origin + +from areas import api_v1 + +from .role_service import RoleService + + +@api_v1.route("/roles", methods=["GET"]) +@jwt_required() +@cross_origin() +def get_roles(): + roles = RoleService.get_roles() + return jsonify(roles) diff --git a/areas/users/__init__.py b/areas/users/__init__.py index a19fa8f..3686613 100644 --- a/areas/users/__init__.py +++ b/areas/users/__init__.py @@ -1,2 +1,2 @@ from .users import * -from .models import * +from .user_service import * diff --git a/areas/users/user_service.py b/areas/users/user_service.py new file mode 100644 index 0000000..a972d86 --- /dev/null +++ b/areas/users/user_service.py @@ -0,0 +1,61 @@ +import copy + +from database import db +from areas.apps import AppRole +from helpers import KratosApi + + +class UserService: + @staticmethod + def get_users(): + res = KratosApi.get("/identities").json() + userList = [] + for r in res: + userList.append(UserService.__insertAppRoleToUser(r["id"], r)) + + return userList + + @staticmethod + def get_user(id): + res = KratosApi.get("/identities/{}".format(id)).json() + return UserService.__insertAppRoleToUser(id, res) + + @staticmethod + def post_user(data): + kratos_data = { + "schema_id": "default", + "traits": {"email": data["email"], "name": data["name"]}, + } + res = KratosApi.post("/identities", kratos_data).json() + + appRole = AppRole( + user_id=res["id"], + role_id=data["role_id"] if "role_id" in data else None, + app_id=1, + ) + + db.session.add(appRole) + db.session.commit() + + return UserService.get_user(res["id"]) + + @staticmethod + def put_user(id, data): + kratos_data = { + "schema_id": "default", + "traits": {"email": data["email"], "name": data["name"]}, + } + KratosApi.put("/identities/{}".format(id), kratos_data) + + app_role = AppRole.query.filter_by(user_id=id).first() + app_role.role_id = data["role_id"] if "role_id" in data else None + db.session.commit() + + return UserService.get_user(id) + + @staticmethod + def __insertAppRoleToUser(userId, userRes): + app_role = AppRole.query.filter_by(user_id=userId).first() + userRes["traits"]["app_role_id"] = app_role.role_id if app_role else None + + return userRes diff --git a/areas/users/users.py b/areas/users/users.py index 73d7a5d..a2127c0 100644 --- a/areas/users/users.py +++ b/areas/users/users.py @@ -5,23 +5,25 @@ from flask_expects_json import expects_json from areas import api_v1 from helpers import KratosApi + from .validation import schema +from .user_service import UserService @api_v1.route("/users", methods=["GET"]) @jwt_required() @cross_origin() def get_users(): - res = KratosApi.get("/identities") - return jsonify(res.json()) + res = UserService.get_users() + return jsonify(res) @api_v1.route("/users/", methods=["GET"]) @jwt_required() @cross_origin() def get_user(id): - res = KratosApi.get("/identities/{}".format(id)) - return jsonify(res.json()) + res = UserService.get_user(id) + return jsonify(res) @api_v1.route("/users", methods=["POST"]) @@ -30,9 +32,8 @@ def get_user(id): @expects_json(schema) def post_user(): data = request.get_json() - kratos_data = {"schema_id": "default", "traits": data} - res = KratosApi.post("/identities", kratos_data) - return jsonify(res.json()), res.status_code + res = UserService.post_user(data) + return jsonify(res) @api_v1.route("/users/", methods=["PUT"]) @@ -41,9 +42,8 @@ def post_user(): @expects_json(schema) def put_user(id): data = request.get_json() - kratos_data = {"schema_id": "default", "traits": data} - res = KratosApi.put("/identities/{}".format(id), kratos_data) - return jsonify(res.json()), res.status_code + res = UserService.put_user(id, data) + return jsonify(res) @api_v1.route("/users/", methods=["DELETE"]) diff --git a/areas/users/validation.py b/areas/users/validation.py index 84c3dea..85d6031 100644 --- a/areas/users/validation.py +++ b/areas/users/validation.py @@ -8,7 +8,12 @@ schema = { "description": "Email of the user", "pattern": r"(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])", "minLength": 1, - } + }, + "role_id": { + "type": "integer", + "description": "Role of the user", + "minimum": 1, + }, }, "required": ["email"], }