diff --git a/src/allmende_payment_system/api/admin.py b/src/allmende_payment_system/api/admin.py new file mode 100644 index 0000000..ec73c0c --- /dev/null +++ b/src/allmende_payment_system/api/admin.py @@ -0,0 +1,26 @@ +from decimal import Decimal + +from fastapi import APIRouter, HTTPException, Request +from sqlalchemy import select +from starlette import status +from starlette.responses import RedirectResponse + +from allmende_payment_system.api.dependencies import SessionDep, UserDep +from allmende_payment_system.models import Area, Order, OrderItem, Product, User +from allmende_payment_system.tools import get_jinja_renderer + +admin_router = APIRouter(prefix="/admin") + + +@admin_router.get("/users") +async def user_list(request: Request, session: SessionDep, user: UserDep): + if not user.has_permission("user", "edit"): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + query = select(User) + users = session.scalars(query).all() + templates = get_jinja_renderer() + return templates.TemplateResponse( + "users.html.jinja", + context={"request": request, "users": users}, + ) diff --git a/src/allmende_payment_system/app.py b/src/allmende_payment_system/app.py index adcbbff..0b4a156 100644 --- a/src/allmende_payment_system/app.py +++ b/src/allmende_payment_system/app.py @@ -4,6 +4,7 @@ from fastapi import Depends, FastAPI from fastapi.staticfiles import StaticFiles from allmende_payment_system.api import root_router +from allmende_payment_system.api.admin import admin_router from allmende_payment_system.api.dependencies import get_user_object from allmende_payment_system.api.shop import shop_router @@ -20,3 +21,4 @@ app.mount( app.include_router(root_router) app.include_router(shop_router) +app.include_router(admin_router) diff --git a/src/allmende_payment_system/models.py b/src/allmende_payment_system/models.py index a856baa..cf56d9c 100644 --- a/src/allmende_payment_system/models.py +++ b/src/allmende_payment_system/models.py @@ -55,6 +55,12 @@ class User(Base): ) orders: Mapped[list["Order"]] = relationship("Order", back_populates="user") + user_groups: Mapped[list["UserGroup"]] = relationship( + "UserGroup", + secondary=TABLE_PREFIX + "user_user_group_association", + back_populates="users", + ) + @property def shopping_cart(self): for order in self.orders: @@ -68,6 +74,52 @@ class User(Base): return cart + def has_permission(self, scope: str, action: str) -> bool: + for group in self.user_groups: + for permission in group.permissions: + if permission.scope == scope and permission.action == action: + return True + return False + + +class UserGroup(Base): + __tablename__ = TABLE_PREFIX + "user_group" + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) + name: Mapped[str] = mapped_column(nullable=False, unique=True) + description: Mapped[str] = mapped_column(nullable=True) + + permissions = relationship("Permission", back_populates="user_group") + + users: Mapped[list["User"]] = relationship( + "User", + secondary=TABLE_PREFIX + "user_user_group_association", + back_populates="user_groups", + ) + + +user_group_association = Table( + TABLE_PREFIX + "user_user_group_association", + Base.metadata, + Column("user_id", ForeignKey(TABLE_PREFIX + "user.id"), primary_key=True), + Column( + "user_group_id", ForeignKey(TABLE_PREFIX + "user_group.id"), primary_key=True + ), +) + + +class Permission(Base): + __tablename__ = TABLE_PREFIX + "permission" + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) + scope: Mapped[str] = mapped_column(nullable=False) + action: Mapped[str] = mapped_column(nullable=False) + + user_group_id: Mapped[int] = mapped_column( + ForeignKey(TABLE_PREFIX + "user_group.id") + ) + user_group: Mapped["UserGroup"] = relationship( + "UserGroup", back_populates="permissions" + ) + class Area(Base): __tablename__ = TABLE_PREFIX + "area" diff --git a/src/allmende_payment_system/templates/base.html.jinja b/src/allmende_payment_system/templates/base.html.jinja index ead407e..b56a066 100644 --- a/src/allmende_payment_system/templates/base.html.jinja +++ b/src/allmende_payment_system/templates/base.html.jinja @@ -29,16 +29,13 @@ Einkaufen -{#
| ID | +Username | +Azeigename | +Gruppen | ++ |
|---|---|---|---|---|
| {{ user.id }} | +{{ user.username }} | +{{ user.display_name }} | +{{ user.user_groups | map(attribute='name') | join(', ') }} | ++ Bearbeiten + Löschen + | +