mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: users management
This commit is contained in:
parent
a552300e15
commit
689625b0d5
22 changed files with 621 additions and 36 deletions
|
|
@ -225,7 +225,7 @@ async def get_course_chapters(
|
|||
chapters = [ChapterRead(**chapter.dict(), activities=[]) for chapter in chapters]
|
||||
|
||||
# RBAC check
|
||||
await rbac_check(request, course.course_uuid, current_user, "read", db_session)
|
||||
await rbac_check(request, course.course_uuid, current_user, "read", db_session) # type: ignore
|
||||
|
||||
# Get activities for each chapter
|
||||
for chapter in chapters:
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ async def update_course_thumbnail(
|
|||
if thumbnail_file and thumbnail_file.filename:
|
||||
name_in_disk = f"{course_uuid}_thumbnail_{uuid4()}.{thumbnail_file.filename.split('.')[-1]}"
|
||||
await upload_thumbnail(
|
||||
thumbnail_file, name_in_disk, 'users', course.course_uuid
|
||||
thumbnail_file, name_in_disk, org.org_uuid, course.course_uuid
|
||||
)
|
||||
|
||||
# Update course
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from datetime import datetime
|
|||
from typing import Literal
|
||||
from uuid import uuid4
|
||||
from sqlmodel import Session, select
|
||||
from src.db.roles import Role, RoleRead
|
||||
from src.db.organization_config import (
|
||||
AIConfig,
|
||||
AIEnabledFeatures,
|
||||
|
|
@ -15,16 +16,18 @@ from src.db.organization_config import (
|
|||
OrganizationConfigBase,
|
||||
)
|
||||
from src.security.rbac.rbac import (
|
||||
authorization_verify_based_on_roles_and_authorship,
|
||||
authorization_verify_based_on_org_admin_status,
|
||||
authorization_verify_based_on_roles,
|
||||
authorization_verify_if_user_is_anon,
|
||||
)
|
||||
from src.db.users import AnonymousUser, PublicUser
|
||||
from src.db.users import AnonymousUser, PublicUser, User, UserRead
|
||||
from src.db.user_organizations import UserOrganization
|
||||
from src.db.organizations import (
|
||||
Organization,
|
||||
OrganizationCreate,
|
||||
OrganizationRead,
|
||||
OrganizationUpdate,
|
||||
OrganizationUser,
|
||||
)
|
||||
from src.services.orgs.logos import upload_org_logo
|
||||
from fastapi import HTTPException, UploadFile, status, Request
|
||||
|
|
@ -66,6 +69,199 @@ async def get_organization(
|
|||
return org
|
||||
|
||||
|
||||
async def get_organization_users(
|
||||
request: Request,
|
||||
org_id: str,
|
||||
db_session: Session,
|
||||
current_user: PublicUser | AnonymousUser,
|
||||
) -> list[OrganizationUser]:
|
||||
statement = select(Organization).where(Organization.id == org_id)
|
||||
result = db_session.exec(statement)
|
||||
|
||||
org = result.first()
|
||||
|
||||
if not org:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="Organization not found",
|
||||
)
|
||||
|
||||
# RBAC check
|
||||
await rbac_check(request, org.org_uuid, current_user, "read", db_session)
|
||||
|
||||
statement = (
|
||||
select(User)
|
||||
.join(UserOrganization)
|
||||
.join(Organization)
|
||||
.where(Organization.id == org_id)
|
||||
)
|
||||
users = db_session.exec(statement)
|
||||
users = users.all()
|
||||
|
||||
org_users_list = []
|
||||
|
||||
for user in users:
|
||||
statement = select(UserOrganization).where(
|
||||
UserOrganization.user_id == user.id, UserOrganization.org_id == org_id
|
||||
)
|
||||
result = db_session.exec(statement)
|
||||
user_org = result.first()
|
||||
|
||||
if not user_org:
|
||||
logging.error(f"User {user.id} not found")
|
||||
|
||||
# skip this user
|
||||
continue
|
||||
|
||||
|
||||
statement = select(Role).where(Role.id == user_org.role_id)
|
||||
result = db_session.exec(statement)
|
||||
|
||||
role = result.first()
|
||||
|
||||
if not role:
|
||||
logging.error(f"Role {user_org.role_id} not found")
|
||||
|
||||
# skip this user
|
||||
continue
|
||||
|
||||
statement = select(User).where(User.id == user_org.user_id)
|
||||
result = db_session.exec(statement)
|
||||
|
||||
user = result.first()
|
||||
|
||||
if not user:
|
||||
logging.error(f"User {user_org.user_id} not found")
|
||||
|
||||
# skip this user
|
||||
continue
|
||||
|
||||
user = UserRead.from_orm(user)
|
||||
role = RoleRead.from_orm(role)
|
||||
|
||||
org_user = OrganizationUser(
|
||||
user=user,
|
||||
role=role,
|
||||
)
|
||||
|
||||
org_users_list.append(org_user)
|
||||
|
||||
return org_users_list
|
||||
|
||||
|
||||
async def remove_user_from_org(
|
||||
request: Request,
|
||||
org_id: int,
|
||||
user_id: int,
|
||||
db_session: Session,
|
||||
current_user: PublicUser | AnonymousUser,
|
||||
):
|
||||
statement = select(Organization).where(Organization.id == org_id)
|
||||
result = db_session.exec(statement)
|
||||
|
||||
org = result.first()
|
||||
|
||||
if not org:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="Organization not found",
|
||||
)
|
||||
|
||||
# RBAC check
|
||||
await rbac_check(request, org.org_uuid, current_user, "read", db_session)
|
||||
|
||||
statement = select(UserOrganization).where(
|
||||
UserOrganization.user_id == user_id, UserOrganization.org_id == org.id
|
||||
)
|
||||
result = db_session.exec(statement)
|
||||
|
||||
user_org = result.first()
|
||||
|
||||
if not user_org:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="User not found",
|
||||
)
|
||||
|
||||
# Check if user is the last admin
|
||||
statement = select(UserOrganization).where(
|
||||
UserOrganization.org_id == org.id, UserOrganization.role_id == 1
|
||||
)
|
||||
result = db_session.exec(statement)
|
||||
admins = result.all()
|
||||
|
||||
if len(admins) == 1 and admins[0].user_id == user_id:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="You can't remove the last admin of the organization",
|
||||
)
|
||||
|
||||
|
||||
db_session.delete(user_org)
|
||||
db_session.commit()
|
||||
|
||||
return {"detail": "User removed from org"}
|
||||
|
||||
|
||||
async def update_user_role(
|
||||
request: Request,
|
||||
org_id: str,
|
||||
user_id: str,
|
||||
role_uuid: str,
|
||||
db_session: Session,
|
||||
current_user: PublicUser | AnonymousUser,
|
||||
):
|
||||
# find role
|
||||
statement = select(Role).where(Role.role_uuid == role_uuid)
|
||||
result = db_session.exec(statement)
|
||||
|
||||
role = result.first()
|
||||
|
||||
if not role:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="Role not found",
|
||||
)
|
||||
|
||||
role_id = role.id
|
||||
|
||||
statement = select(Organization).where(Organization.id == org_id)
|
||||
result = db_session.exec(statement)
|
||||
|
||||
org = result.first()
|
||||
|
||||
if not org:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="Organization not found",
|
||||
)
|
||||
|
||||
# RBAC check
|
||||
await rbac_check(request, org.org_uuid, current_user, "read", db_session)
|
||||
|
||||
statement = select(UserOrganization).where(
|
||||
UserOrganization.user_id == user_id, UserOrganization.org_id == org.id
|
||||
)
|
||||
result = db_session.exec(statement)
|
||||
|
||||
user_org = result.first()
|
||||
|
||||
if not user_org:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="User not found",
|
||||
)
|
||||
|
||||
if role_id is not None:
|
||||
user_org.role_id = role_id
|
||||
|
||||
db_session.add(user_org)
|
||||
db_session.commit()
|
||||
db_session.refresh(user_org)
|
||||
|
||||
return {"detail": "User role updated"}
|
||||
|
||||
|
||||
async def get_organization_by_slug(
|
||||
request: Request,
|
||||
org_slug: str,
|
||||
|
|
@ -443,7 +639,7 @@ async def get_orgs_by_user(
|
|||
|
||||
async def rbac_check(
|
||||
request: Request,
|
||||
org_id: str,
|
||||
org_uuid: str,
|
||||
current_user: PublicUser | AnonymousUser,
|
||||
action: Literal["create", "read", "update", "delete"],
|
||||
db_session: Session,
|
||||
|
|
@ -455,8 +651,12 @@ async def rbac_check(
|
|||
else:
|
||||
await authorization_verify_if_user_is_anon(current_user.id)
|
||||
|
||||
await authorization_verify_based_on_roles_and_authorship(
|
||||
request, current_user.id, action, org_id, db_session
|
||||
await authorization_verify_based_on_roles(
|
||||
request, current_user.id, action, org_uuid, db_session
|
||||
)
|
||||
|
||||
await authorization_verify_based_on_org_admin_status(
|
||||
request, current_user.id, action, org_uuid, db_session
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ async def upload_avatar(avatar_file, name_in_disk, user_uuid):
|
|||
contents = avatar_file.file.read()
|
||||
try:
|
||||
await upload_content(
|
||||
f"avatars",
|
||||
"avatars",
|
||||
"users",
|
||||
user_uuid,
|
||||
contents,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue