feat: user init & refactors

This commit is contained in:
swve 2023-11-12 23:16:34 +01:00
parent b4dcc14749
commit a50fc67104
25 changed files with 356 additions and 358 deletions

View file

@ -1,7 +1,7 @@
from fastapi import FastAPI, Request from fastapi import FastAPI, Request
from config.config import LearnHouseConfig, get_learnhouse_config from config.config import LearnHouseConfig, get_learnhouse_config
from src.core.events.events import shutdown_app, startup_app from src.core.events.events import shutdown_app, startup_app
from src.router import v1_router, rewrite from src.router import v1_router
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
@ -60,7 +60,6 @@ app.mount("/content", StaticFiles(directory="content"), name="content")
# Global Routes # Global Routes
app.include_router(v1_router) app.include_router(v1_router)
app.include_router(rewrite)
# General Routes # General Routes
@app.get("/") @app.get("/")

View file

@ -3,7 +3,7 @@ from fastapi import FastAPI
import motor.motor_asyncio import motor.motor_asyncio
from sqlmodel import Field, SQLModel, Session, create_engine from sqlmodel import Field, SQLModel, Session, create_engine
from src.rewrite.services.db import ( from src.db import (
user_organizations, user_organizations,
users, users,
roles, roles,

View file

@ -7,7 +7,7 @@ from sqlmodel import Field, SQLModel
class RoleTypeEnum(str, Enum): class RoleTypeEnum(str, Enum):
ORGANIZATION = "ORGANIZATION" ORGANIZATION = "ORGANIZATION"
ORGANIZATION_API_TOKEN = "ORGANIZATION_API_TOKEN" ORGANIZATION_API_TOKEN = "ORGANIZATION_API_TOKEN"
DEFAULT = "DEFAULT" GLOBAL = "GLOBAL"
class RoleBase(SQLModel): class RoleBase(SQLModel):
@ -19,7 +19,7 @@ class RoleBase(SQLModel):
class Role(RoleBase, table=True): class Role(RoleBase, table=True):
id: Optional[int] = Field(default=None, primary_key=True) id: Optional[int] = Field(default=None, primary_key=True)
org_id: int = Field(default=None, foreign_key="organization.id") org_id: int = Field(default=None, foreign_key="organization.id")
role_type: RoleTypeEnum = RoleTypeEnum.DEFAULT role_type: RoleTypeEnum = RoleTypeEnum.GLOBAL
role_uuid: str role_uuid: str
creation_date: str creation_date: str
update_date: str update_date: str

View file

@ -16,7 +16,18 @@ class UserCreate(UserBase):
class UserUpdate(UserBase): class UserUpdate(UserBase):
password: Optional[str] = None username: str
first_name: Optional[str]
last_name: Optional[str]
email: str
avatar_image: Optional[str] = ""
bio: Optional[str] = ""
class UserUpdatePassword(SQLModel):
user_id: int
old_password: str
new_password: str
class UserRead(UserBase): class UserRead(UserBase):

View file

@ -1,23 +0,0 @@
from fastapi import APIRouter, Depends, Request
from sqlmodel import Session
from src.core.events.database import get_db_session
from src.rewrite.services.db.users import UserCreate, UserRead
from src.rewrite.services.users.users import create_user
router = APIRouter()
@router.post("/", response_model=UserRead, tags=["users"])
async def api_create_user(
*,
request: Request,
db_session: Session = Depends(get_db_session),
user_object: UserCreate,
org_slug: str
):
"""
Create new user
"""
return await create_user(request, db_session, None, user_object, org_slug)

View file

@ -1,43 +0,0 @@
from datetime import datetime
from uuid import uuid4
from fastapi import Request
from sqlmodel import Session
from src.rewrite.services.db.users import User, UserCreate
from src.security.security import security_hash_password
from src.services.users.schemas.users import PublicUser
async def create_user(
request: Request,
db_session: Session,
current_user: PublicUser | None,
user_object: UserCreate,
org_slug: str,
):
user = User.from_orm(user_object)
# Complete the user object
user.user_uuid = f"user_{uuid4()}"
user.password = await security_hash_password(user_object.password)
user.email_verified = False
user.creation_date = str(datetime.now())
user.update_date = str(datetime.now())
# Verifications
#todo: add username uniqueness verification
#todo: add email uniqueness verification
#todo: add user to org as member if org is not None
# Exclude unset values
user_data = user.dict(exclude_unset=True)
for key, value in user_data.items():
setattr(user, key, value)
# Add user to database
db_session.add(user)
db_session.commit()
db_session.refresh(user)
return user

View file

@ -1,7 +1,5 @@
from fastapi import APIRouter, Depends from fastapi import APIRouter, Depends
from src import rewrite
from src.routers import blocks, dev, trail, users, auth, orgs, roles from src.routers import blocks, dev, trail, users, auth, orgs, roles
from src.rewrite.routers import users as rw_users
from src.routers.courses import chapters, collections, courses, activities from src.routers.courses import chapters, collections, courses, activities
from src.routers.install import install from src.routers.install import install
from src.services.dev.dev import isDevModeEnabledOrRaise from src.services.dev.dev import isDevModeEnabledOrRaise
@ -9,7 +7,6 @@ from src.services.install.install import isInstallModeEnabled
v1_router = APIRouter(prefix="/api/v1") v1_router = APIRouter(prefix="/api/v1")
rewrite = APIRouter(prefix="/api/rewrite")
# API Routes # API Routes
@ -39,5 +36,3 @@ v1_router.include_router(
dependencies=[Depends(isInstallModeEnabled)], dependencies=[Depends(isInstallModeEnabled)],
) )
# Rewrite Routes
rewrite.include_router(rw_users.router, prefix="/users", tags=["users"])

View file

@ -1,5 +1,8 @@
from fastapi import Depends, APIRouter, HTTPException, Response, status, Request from fastapi import Depends, APIRouter, HTTPException, Response, status, Request
from fastapi.security import OAuth2PasswordRequestForm from fastapi.security import OAuth2PasswordRequestForm
from sqlmodel import Session
from src.db.users import UserRead
from src.core.events.database import get_db_session
from config.config import get_learnhouse_config from config.config import get_learnhouse_config
from src.security.auth import AuthJWT, authenticate_user from src.security.auth import AuthJWT, authenticate_user
from src.services.users.users import PublicUser from src.services.users.users import PublicUser
@ -9,7 +12,7 @@ router = APIRouter()
@router.post("/refresh") @router.post("/refresh")
def refresh(response: Response,Authorize: AuthJWT = Depends()): def refresh(response: Response, Authorize: AuthJWT = Depends()):
""" """
The jwt_refresh_token_required() function insures a valid refresh The jwt_refresh_token_required() function insures a valid refresh
token is present in the request before running any code below that function. token is present in the request before running any code below that function.
@ -21,7 +24,12 @@ def refresh(response: Response,Authorize: AuthJWT = Depends()):
current_user = Authorize.get_jwt_subject() current_user = Authorize.get_jwt_subject()
new_access_token = Authorize.create_access_token(subject=current_user) # type: ignore new_access_token = Authorize.create_access_token(subject=current_user) # type: ignore
response.set_cookie(key="access_token_cookie", value=new_access_token, httponly=False, domain=get_learnhouse_config().hosting_config.cookie_config.domain) response.set_cookie(
key="access_token_cookie",
value=new_access_token,
httponly=False,
domain=get_learnhouse_config().hosting_config.cookie_config.domain,
)
return {"access_token": new_access_token} return {"access_token": new_access_token}
@ -31,8 +39,11 @@ async def login(
response: Response, response: Response,
Authorize: AuthJWT = Depends(), Authorize: AuthJWT = Depends(),
form_data: OAuth2PasswordRequestForm = Depends(), form_data: OAuth2PasswordRequestForm = Depends(),
db_session: Session = Depends(get_db_session),
): ):
user = await authenticate_user(request, form_data.username, form_data.password) user = await authenticate_user(
request, form_data.username, form_data.password, db_session
)
if not user: if not user:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,
@ -44,8 +55,14 @@ async def login(
refresh_token = Authorize.create_refresh_token(subject=form_data.username) refresh_token = Authorize.create_refresh_token(subject=form_data.username)
Authorize.set_refresh_cookies(refresh_token) Authorize.set_refresh_cookies(refresh_token)
# set cookies using fastapi # set cookies using fastapi
response.set_cookie(key="access_token_cookie", value=access_token, httponly=False, domain=get_learnhouse_config().hosting_config.cookie_config.domain) response.set_cookie(
user = PublicUser(**user.dict()) key="access_token_cookie",
value=access_token,
httponly=False,
domain=get_learnhouse_config().hosting_config.cookie_config.domain,
)
user = UserRead.from_orm(user)
result = { result = {
"user": user, "user": user,

View file

@ -1,10 +1,24 @@
from fastapi import Depends, APIRouter, Request from fastapi import APIRouter, Depends, Request
from sqlmodel import Session
from src.security.auth import get_current_user from src.security.auth import get_current_user
from src.services.users.schemas.users import PasswordChangeForm, PublicUser, User, UserWithPassword from src.core.events.database import get_db_session
from src.services.users.users import create_user, delete_user, get_profile_metadata, get_user_by_userid, update_user, update_user_password
from src.db.users import (
User,
UserCreate,
UserRead,
UserUpdate,
UserUpdatePassword,
)
from src.services.users.users import (
create_user,
create_user_without_org,
delete_user_by_id,
read_user_by_id,
read_user_by_uuid,
update_user,
update_user_password,
)
router = APIRouter() router = APIRouter()
@ -17,50 +31,95 @@ async def api_get_current_user(current_user: User = Depends(get_current_user)):
""" """
return current_user.dict() return current_user.dict()
@router.get("/profile_metadata")
async def api_get_current_user_metadata(request: Request,current_user: User = Depends(get_current_user)): @router.post("/org_id/{org_id}", response_model=UserRead, tags=["users"])
async def api_create_user_with_orgid(
*,
request: Request,
db_session: Session = Depends(get_db_session),
user_object: UserCreate,
org_id: int,
) -> UserRead:
""" """
Get current user Create User with Org ID
""" """
return await get_profile_metadata(request , current_user.dict()) return await create_user(request, db_session, None, user_object, org_id)
@router.post("/", response_model=UserRead, tags=["users"])
@router.get("/user_id/{user_id}") async def api_create_user_without_org(
async def api_get_user_by_userid(request: Request,user_id: str): *,
request: Request,
db_session: Session = Depends(get_db_session),
user_object: UserCreate,
org_id: int,
) -> UserRead:
""" """
Get single user by user_id Create User
""" """
return await get_user_by_userid(request, user_id) return await create_user_without_org(request, db_session, None, user_object)
@router.post("/") @router.get("/user_id/{user_id}", response_model=UserRead, tags=["users"])
async def api_create_user(request: Request,user_object: UserWithPassword, org_slug: str ): async def api_get_user_by_id(
*,
request: Request,
db_session: Session = Depends(get_db_session),
user_id: int,
) -> UserRead:
""" """
Create new user Get User by ID
""" """
return await create_user(request, None, user_object, org_slug) return await read_user_by_id(request, db_session, None, user_id)
@router.delete("/user_id/{user_id}") @router.get("/user_uuid/{user_uuid}", response_model=UserRead, tags=["users"])
async def api_delete_user(request: Request, user_id: str, current_user: PublicUser = Depends(get_current_user)): async def api_get_user_by_uuid(
*,
request: Request,
db_session: Session = Depends(get_db_session),
user_uuid: str,
) -> UserRead:
""" """
Delete user by ID Get User by UUID
""" """
return await read_user_by_uuid(request, db_session, None, user_uuid)
return await delete_user(request, current_user, user_id)
@router.put("/user_id/{user_id}") @router.put("/", response_model=UserRead, tags=["users"])
async def api_update_user(request: Request, user_object: User, user_id: str, current_user: PublicUser = Depends(get_current_user)): async def api_update_user(
*,
request: Request,
db_session: Session = Depends(get_db_session),
user_object: UserUpdate,
) -> UserRead:
""" """
Update user by ID Update User
""" """
return await update_user(request, user_id, user_object, current_user) return await update_user(request, db_session, None, user_object)
@router.put("/password/user_id/{user_id}")
async def api_update_user_password(request: Request, user_id: str , passwordChangeForm : PasswordChangeForm, current_user: PublicUser = Depends(get_current_user)): @router.put("/change_password/", response_model=UserRead, tags=["users"])
async def api_update_user_password(
*,
request: Request,
db_session: Session = Depends(get_db_session),
form: UserUpdatePassword,
) -> UserRead:
""" """
Update user password by ID Update User Password
""" """
return await update_user_password(request,current_user, user_id, passwordChangeForm) return await update_user_password(request, db_session, None, form)
@router.delete("/user_id/{user_id}", tags=["users"])
async def api_delete_user(
*,
request: Request,
db_session: Session = Depends(get_db_session),
user_id: int,
):
"""
Delete User
"""
return await delete_user_by_id(request, db_session, None, user_id)

View file

@ -1,3 +1,7 @@
from sqlmodel import Session
from src.core.events.database import get_db_session
from src.db.users import User, UserRead
from src.services.users.users import security_get_user
from config.config import get_learnhouse_config from config.config import get_learnhouse_config
from pydantic import BaseModel from pydantic import BaseModel
from fastapi import Depends, HTTPException, Request, status from fastapi import Depends, HTTPException, Request, status
@ -6,7 +10,7 @@ from jose import JWTError, jwt
from datetime import datetime, timedelta from datetime import datetime, timedelta
from src.services.dev.dev import isDevModeEnabled from src.services.dev.dev import isDevModeEnabled
from src.services.users.schemas.users import AnonymousUser, PublicUser from src.services.users.schemas.users import AnonymousUser, PublicUser
from src.services.users.users import security_get_user, security_verify_password from src.services.users.users import security_verify_password
from src.security.security import ALGORITHM, SECRET_KEY from src.security.security import ALGORITHM, SECRET_KEY
from fastapi_jwt_auth import AuthJWT from fastapi_jwt_auth import AuthJWT
@ -45,10 +49,13 @@ class TokenData(BaseModel):
#### Classes #################################################### #### Classes ####################################################
async def authenticate_user(
request: Request,
async def authenticate_user(request: Request, email: str, password: str): email: str,
user = await security_get_user(request, email) password: str,
db_session: Session,
) -> User | bool:
user = await security_get_user(request, db_session, email)
if not user: if not user:
return False return False
if not await security_verify_password(password, user.password): if not await security_verify_password(password, user.password):
@ -67,7 +74,11 @@ def create_access_token(data: dict, expires_delta: timedelta | None = None):
return encoded_jwt return encoded_jwt
async def get_current_user(request: Request, Authorize: AuthJWT = Depends()): async def get_current_user(
request: Request,
Authorize: AuthJWT = Depends(),
db_session: Session = Depends(get_db_session),
):
credentials_exception = HTTPException( credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials", detail="Could not validate credentials",
@ -81,10 +92,10 @@ async def get_current_user(request: Request, Authorize: AuthJWT = Depends()):
except JWTError: except JWTError:
raise credentials_exception raise credentials_exception
if username: if username:
user = await security_get_user(request, email=token_data.username) # type: ignore # treated as an email user = await security_get_user(request, db_session, email=token_data.username) # type: ignore # treated as an email
if user is None: if user is None:
raise credentials_exception raise credentials_exception
return PublicUser(**user.dict()) return UserRead(**user.dict())
else: else:
return AnonymousUser() return AnonymousUser()

View file

@ -3,10 +3,11 @@ import requests
from datetime import datetime from datetime import datetime
from uuid import uuid4 from uuid import uuid4
from fastapi import Request from fastapi import Request
from src.services.users.schemas.users import UserInDB
from src.security.security import security_hash_password from src.security.security import security_hash_password
from src.services.courses.chapters import CourseChapter, create_coursechapter from src.services.courses.chapters import CourseChapter, create_coursechapter
from src.services.courses.activities.activities import Activity, create_activity from src.services.courses.activities.activities import Activity, create_activity
from src.services.users.users import PublicUser, UserInDB from src.services.users.users import PublicUser
from src.services.orgs.orgs import Organization, create_org from src.services.orgs.orgs import Organization, create_org
from src.services.roles.schemas.roles import Permission, Elements, RoleInDB from src.services.roles.schemas.roles import Permission, Elements, RoleInDB

View file

@ -1,215 +1,285 @@
from datetime import datetime from datetime import datetime
from typing import Literal
from uuid import uuid4 from uuid import uuid4
from fastapi import HTTPException, Request, status from fastapi import HTTPException, Request, status
from src.security.rbac.rbac import ( from sqlmodel import Session, select
authorization_verify_based_on_roles, from src.db.organizations import Organization
authorization_verify_if_user_is_anon, from src.db.users import (
)
from src.security.security import security_hash_password, security_verify_password
from src.services.users.schemas.users import (
PasswordChangeForm,
PublicUser,
User, User,
UserOrganization, UserCreate,
UserRolesInOrganization, UserRead,
UserWithPassword, UserUpdate,
UserInDB, UserUpdatePassword,
) )
from src.db.user_organizations import UserOrganization
from src.security.security import security_hash_password, security_verify_password
from src.services.users.schemas.users import PublicUser
async def create_user( async def create_user(
request: Request, request: Request,
db_session: Session,
current_user: PublicUser | None, current_user: PublicUser | None,
user_object: UserWithPassword, user_object: UserCreate,
org_slug: str, org_id: int,
): ):
users = request.app.db["users"] user = User.from_orm(user_object)
isUsernameAvailable = await users.find_one({"username": user_object.username}) # Complete the user object
isEmailAvailable = await users.find_one({"email": user_object.email}) user.user_uuid = f"user_{uuid4()}"
user.password = await security_hash_password(user_object.password)
user.email_verified = False
user.creation_date = str(datetime.now())
user.update_date = str(datetime.now())
if isUsernameAvailable: # Verifications
# Check if Organization exists
statement = select(Organization).where(Organization.id == org_id)
result = db_session.exec(statement)
if not result.first():
raise HTTPException( raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Username already exists" status_code=400,
detail="Organization does not exist",
) )
if isEmailAvailable: # Username
statement = select(User).where(User.username == user.username)
result = db_session.exec(statement)
if result.first():
raise HTTPException( raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Email already exists" status_code=400,
detail="Username already exists",
) )
# Generate user_id with uuid4 # Email
user_id = str(f"user_{uuid4()}") statement = select(User).where(User.email == user.email)
result = db_session.exec(statement)
# Check if the requesting user is authenticated if result.first():
if current_user is not None:
# Verify rights
await verify_user_rights_on_user(request, current_user, "create", user_id)
# Set the username & hash the password
user_object.username = user_object.username.lower()
user_object.password = await security_hash_password(user_object.password)
# Get org_id from org_slug
orgs = request.app.db["organizations"]
# Check if the org exists
isOrgExists = await orgs.find_one({"slug": org_slug})
# If the org does not exist, raise an error
if not isOrgExists and (org_slug != "None"):
raise HTTPException( raise HTTPException(
status_code=status.HTTP_409_CONFLICT, status_code=400,
detail="You are trying to create a user in an organization that does not exist", detail="Email already exists",
) )
org_id = isOrgExists["org_id"] if org_slug != "None" else '' # Exclude unset values
user_data = user.dict(exclude_unset=True)
for key, value in user_data.items():
setattr(user, key, value)
# Create initial orgs list with the org_id passed in # Add user to database
orgs = ( db_session.add(user)
[UserOrganization(org_id=org_id, org_role="member")] db_session.commit()
if org_slug != "None" db_session.refresh(user)
else []
)
# Give role # Link user and organization
roles = ( user_organization = UserOrganization(
[UserRolesInOrganization(role_id="role_member", org_id=org_id)] user_id=user.id is not None,
if org_slug != "None" org_id=int(org_id),
else [] role_id=1,
)
# Create the user
user = UserInDB(
user_id=user_id,
creation_date=str(datetime.now()), creation_date=str(datetime.now()),
update_date=str(datetime.now()), update_date=str(datetime.now()),
orgs=orgs,
roles=roles,
**user_object.dict(),
) )
# Insert the user into the database db_session.add(user_organization)
await users.insert_one(user.dict()) db_session.commit()
db_session.refresh(user_organization)
return User(**user.dict()) user = UserRead.from_orm(user)
return user
async def read_user(request: Request, current_user: PublicUser, user_id: str): async def create_user_without_org(
users = request.app.db["users"] request: Request,
db_session: Session,
current_user: PublicUser | None,
user_object: UserCreate,
):
user = User.from_orm(user_object)
# Check if the user exists # Complete the user object
isUserExists = await users.find_one({"user_id": user_id}) user.user_uuid = f"user_{uuid4()}"
user.password = await security_hash_password(user_object.password)
user.email_verified = False
user.creation_date = str(datetime.now())
user.update_date = str(datetime.now())
# Verify rights # Verifications
await verify_user_rights_on_user(request, current_user, "read", user_id)
# If the user does not exist, raise an error # Username
if not isUserExists: statement = select(User).where(User.username == user.username)
result = db_session.exec(statement)
if result.first():
raise HTTPException( raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="User does not exist" status_code=400,
detail="Username already exists",
) )
return User(**isUserExists) # Email
statement = select(User).where(User.email == user.email)
result = db_session.exec(statement)
if result.first():
raise HTTPException(
status_code=400,
detail="Email already exists",
)
# Exclude unset values
user_data = user.dict(exclude_unset=True)
for key, value in user_data.items():
setattr(user, key, value)
# Add user to database
db_session.add(user)
db_session.commit()
db_session.refresh(user)
user = UserRead.from_orm(user)
return user
async def update_user( async def update_user(
request: Request, user_id: str, user_object: User, current_user: PublicUser request: Request,
db_session: Session,
current_user: PublicUser | None,
user_object: UserUpdate,
): ):
users = request.app.db["users"] # Get user
statement = select(User).where(User.username == user_object.username)
user = db_session.exec(statement).first()
# Verify rights if not user:
await verify_user_rights_on_user(request, current_user, "update", user_id)
isUserExists = await users.find_one({"user_id": user_id})
isUsernameAvailable = await users.find_one({"username": user_object.username})
isEmailAvailable = await users.find_one({"email": user_object.email})
if not isUserExists:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="User does not exist" status_code=400,
detail="User does not exist",
) )
# okay if username is not changed # Update user
if isUserExists["username"] == user_object.username: user_data = user_object.dict(exclude_unset=True)
user_object.username = user_object.username.lower() for key, value in user_data.items():
setattr(user, key, value)
else: # Update user in database
if isUsernameAvailable: db_session.add(user)
raise HTTPException( db_session.commit()
status_code=status.HTTP_409_CONFLICT, detail="Username already used" db_session.refresh(user)
)
if isEmailAvailable: user = UserRead.from_orm(user)
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Email already used"
)
updated_user = {"$set": user_object.dict()} return user
users.update_one({"user_id": user_id}, updated_user)
return User(**user_object.dict())
async def update_user_password( async def update_user_password(
request: Request, request: Request,
current_user: PublicUser, db_session: Session,
user_id: str, current_user: PublicUser | None,
password_change_form: PasswordChangeForm, form: UserUpdatePassword,
): ):
users = request.app.db["users"] # Get user
statement = select(User).where(User.username == form.user_id)
user = db_session.exec(statement).first()
isUserExists = await users.find_one({"user_id": user_id}) if not user:
# Verify rights
await verify_user_rights_on_user(request, current_user, "update", user_id)
if not isUserExists:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="User does not exist" status_code=400,
detail="User does not exist",
) )
if not await security_verify_password( if not await security_verify_password(form.old_password, user.password):
password_change_form.old_password, isUserExists["password"]
):
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="Wrong password" status_code=status.HTTP_401_UNAUTHORIZED, detail="Wrong password"
) )
new_password = await security_hash_password(password_change_form.new_password) # Update user
user.password = await security_hash_password(form.new_password)
updated_user = {"$set": {"password": new_password}} # Update user in database
await users.update_one({"user_id": user_id}, updated_user) db_session.add(user)
db_session.commit()
db_session.refresh(user)
return {"detail": "Password updated"} user = UserRead.from_orm(user)
return user
async def delete_user(request: Request, current_user: PublicUser, user_id: str): async def read_user_by_id(
users = request.app.db["users"] request: Request,
db_session: Session,
current_user: PublicUser | None,
user_id: int,
):
# Get user
statement = select(User).where(User.id == user_id)
user = db_session.exec(statement).first()
isUserExists = await users.find_one({"user_id": user_id}) if not user:
# Verify is user has permission to delete the user
await verify_user_rights_on_user(request, current_user, "delete", user_id)
if not isUserExists:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="User does not exist" status_code=400,
detail="User does not exist",
) )
await users.delete_one({"user_id": user_id}) user = UserRead.from_orm(user)
return {"detail": "User deleted"} return user
async def read_user_by_uuid(
request: Request,
db_session: Session,
current_user: PublicUser | None,
uuid: str,
):
# Get user
statement = select(User).where(User.user_uuid == uuid)
user = db_session.exec(statement).first()
if not user:
raise HTTPException(
status_code=400,
detail="User does not exist",
)
user = UserRead.from_orm(user)
return user
async def delete_user_by_id(
request: Request,
db_session: Session,
current_user: PublicUser | None,
user_id: int,
):
# Get user
statement = select(User).where(User.id == user_id)
user = db_session.exec(statement).first()
if not user:
raise HTTPException(
status_code=400,
detail="User does not exist",
)
# Delete user
db_session.delete(user)
db_session.commit()
return "User deleted"
# Utils & Security functions # Utils & Security functions
async def security_get_user(request: Request, email: str): async def security_get_user(request: Request, db_session: Session, email: str) -> User:
users = request.app.db["users"] # Check if user exists
statement = select(User).where(User.email == email)
user = await users.find_one({"email": email}) user = db_session.exec(statement).first()
if not user: if not user:
raise HTTPException( raise HTTPException(
@ -217,105 +287,6 @@ async def security_get_user(request: Request, email: str):
detail="User with Email does not exist", detail="User with Email does not exist",
) )
return UserInDB(**user) user = User(**user.dict())
async def get_userid_by_username(request: Request, username: str):
users = request.app.db["users"]
user = await users.find_one({"username": username})
if not user:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="User does not exist"
)
return user["user_id"]
async def get_user_by_userid(request: Request, user_id: str):
users = request.app.db["users"]
user = await users.find_one({"user_id": user_id})
if not user:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="User does not exist"
)
user = User(**user)
return user return user
async def get_profile_metadata(request: Request, user):
users = request.app.db["users"]
request.app.db["roles"]
user = await users.find_one({"user_id": user["user_id"]})
if not user:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="User does not exist"
)
return {"user_object": PublicUser(**user), "roles": "random"}
# Verification of the user's permissions on the roles
async def verify_user_rights_on_user(
request: Request,
current_user: PublicUser,
action: Literal["create", "read", "update", "delete"],
user_id: str,
):
users = request.app.db["users"]
user = UserInDB(**await users.find_one({"user_id": user_id}))
if action == "create":
return True
if action == "read":
await authorization_verify_if_user_is_anon(current_user.user_id)
if current_user.user_id == user_id:
return True
for org in current_user.orgs:
if org.org_id in [org.org_id for org in user.orgs]:
return True
return False
if action == "update":
await authorization_verify_if_user_is_anon(current_user.user_id)
if current_user.user_id == user_id:
return True
for org in current_user.orgs:
if org.org_id in [org.org_id for org in user.orgs]:
if org.org_role == "owner":
return True
await authorization_verify_based_on_roles(
request, current_user.user_id, "update", user["roles"], user_id
)
return False
if action == "delete":
await authorization_verify_if_user_is_anon(current_user.user_id)
if current_user.user_id == user_id:
return True
for org in current_user.orgs:
if org.org_id in [org.org_id for org in user.orgs]:
if org.org_role == "owner":
return True
await authorization_verify_based_on_roles(
request, current_user.user_id, "update", user["roles"], user_id
)