Merge pull request #135 from learnhouse/fix/post-migration-bugs

Post Migration Bug Fixes
This commit is contained in:
Badr B 2023-12-27 13:45:04 +01:00 committed by GitHub
commit a7e2bda41e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 580 additions and 336 deletions

View file

@ -3,6 +3,7 @@ from sqlmodel import Session, select
from src.db.chapters import Chapter
from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship,
authorization_verify_if_element_is_public,
authorization_verify_if_user_is_anon,
)
from src.db.activities import ActivityCreate, Activity, ActivityRead, ActivityUpdate
@ -212,20 +213,33 @@ async def get_activities(
async def rbac_check(
request: Request,
course_id: str,
course_uuid: str,
current_user: PublicUser | AnonymousUser,
action: Literal["create", "read", "update", "delete"],
db_session: Session,
):
await authorization_verify_if_user_is_anon(current_user.id)
if action == "read":
if current_user.id == 0: # Anonymous user
res = await authorization_verify_if_element_is_public(
request, course_uuid, action, db_session
)
print('res',res)
return res
else:
res = await authorization_verify_based_on_roles_and_authorship(
request, current_user.id, action, course_uuid, db_session
)
return res
else:
await authorization_verify_if_user_is_anon(current_user.id)
await authorization_verify_based_on_roles_and_authorship(
request,
current_user.id,
action,
course_id,
db_session,
)
await authorization_verify_based_on_roles_and_authorship(
request,
current_user.id,
action,
course_uuid,
db_session,
)
## 🔒 RBAC Utils ##

View file

@ -5,6 +5,7 @@ from sqlmodel import Session, select
from src.db.users import AnonymousUser
from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship,
authorization_verify_if_element_is_public,
authorization_verify_if_user_is_anon,
)
from src.db.course_chapters import CourseChapter
@ -207,6 +208,10 @@ async def get_course_chapters(
page: int = 1,
limit: int = 10,
) -> List[ChapterRead]:
statement = select(Course).where(Course.id == course_id)
course = db_session.exec(statement).first()
statement = (
select(Chapter)
.join(CourseChapter, Chapter.id == CourseChapter.chapter_id)
@ -220,7 +225,7 @@ async def get_course_chapters(
chapters = [ChapterRead(**chapter.dict(), activities=[]) for chapter in chapters]
# RBAC check
await rbac_check(request, "chapter_x", current_user, "read", db_session)
await rbac_check(request, course.course_uuid, current_user, "read", db_session)
# Get activities for each chapter
for chapter in chapters:
@ -532,20 +537,33 @@ async def reorder_chapters_and_activities(
async def rbac_check(
request: Request,
course_id: str,
course_uuid: str,
current_user: PublicUser | AnonymousUser,
action: Literal["create", "read", "update", "delete"],
db_session: Session,
):
await authorization_verify_if_user_is_anon(current_user.id)
if action == "read":
if current_user.id == 0: # Anonymous user
res = await authorization_verify_if_element_is_public(
request, course_uuid, action, db_session
)
print('res',res)
return res
else:
res = await authorization_verify_based_on_roles_and_authorship(
request, current_user.id, action, course_uuid, db_session
)
return res
else:
await authorization_verify_if_user_is_anon(current_user.id)
await authorization_verify_based_on_roles_and_authorship(
request,
current_user.id,
action,
course_id,
db_session,
)
await authorization_verify_based_on_roles_and_authorship(
request,
current_user.id,
action,
course_uuid,
db_session,
)
## 🔒 RBAC Utils ##

View file

@ -5,6 +5,7 @@ from sqlmodel import Session, select
from src.db.users import AnonymousUser
from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship,
authorization_verify_if_element_is_public,
authorization_verify_if_user_is_anon,
)
from src.db.collections import (
@ -245,20 +246,34 @@ async def get_collections(
async def rbac_check(
request: Request,
course_id: str,
collection_uuid: str,
current_user: PublicUser | AnonymousUser,
action: Literal["create", "read", "update", "delete"],
db_session: Session,
):
await authorization_verify_if_user_is_anon(current_user.id)
if action == "read":
if current_user.id == 0: # Anonymous user
res = await authorization_verify_if_element_is_public(
request, collection_uuid, action, db_session
)
print('res',res)
return res
else:
res = await authorization_verify_based_on_roles_and_authorship(
request, current_user.id, action, collection_uuid, db_session
)
return res
else:
await authorization_verify_if_user_is_anon(current_user.id)
await authorization_verify_based_on_roles_and_authorship(
request,
current_user.id,
action,
course_id,
db_session,
)
await authorization_verify_based_on_roles_and_authorship(
request,
current_user.id,
action,
collection_uuid,
db_session,
)
## 🔒 RBAC Utils ##

View file

@ -96,11 +96,16 @@ async def get_course_meta(
chapters = await get_course_chapters(request, course.id, db_session, current_user)
# Trail
trail = await get_user_trail_with_orgid(
request, current_user, course.org_id, db_session
)
trail = None
if isinstance(current_user, AnonymousUser):
trail = None
else:
trail = await get_user_trail_with_orgid(
request, current_user, course.org_id, db_session
)
trail = TrailRead.from_orm(trail)
trail = TrailRead.from_orm(trail)
return FullCourseReadWithTrail(
**course.dict(),
@ -359,7 +364,6 @@ async def get_courses_orgslug(
## 🔒 RBAC Utils ##
async def rbac_check(
request: Request,
course_uuid: str,
@ -369,13 +373,16 @@ async def rbac_check(
):
if action == "read":
if current_user.id == 0: # Anonymous user
await authorization_verify_if_element_is_public(
res = await authorization_verify_if_element_is_public(
request, course_uuid, action, db_session
)
print('res',res)
return res
else:
await authorization_verify_based_on_roles_and_authorship(
res = await authorization_verify_based_on_roles_and_authorship(
request, current_user.id, action, course_uuid, db_session
)
return res
else:
await authorization_verify_if_user_is_anon(current_user.id)

View file

@ -93,7 +93,7 @@ async def update_install_instance(
# Install Default roles
async def install_default_elements(request: Request, data: dict, db_session: Session):
async def install_default_elements( data: dict, db_session: Session):
# remove all default roles
statement = select(Role).where(Role.role_type == RoleTypeEnum.TYPE_GLOBAL)
roles = db_session.exec(statement).all()
@ -279,7 +279,7 @@ async def install_default_elements(request: Request, data: dict, db_session: Ses
# Organization creation
async def install_create_organization(
request: Request, org_object: OrganizationCreate, db_session: Session
org_object: OrganizationCreate, db_session: Session
):
org = Organization.from_orm(org_object)
@ -296,7 +296,7 @@ async def install_create_organization(
async def install_create_organization_user(
request: Request, user_object: UserCreate, org_slug: str, db_session: Session
user_object: UserCreate, org_slug: str, db_session: Session
):
user = User.from_orm(user_object)

View file

@ -8,7 +8,7 @@ from src.db.courses import Course
from src.db.trail_runs import TrailRun, TrailRunRead
from src.db.trail_steps import TrailStep
from src.db.trails import Trail, TrailCreate, TrailRead
from src.db.users import PublicUser
from src.db.users import AnonymousUser, PublicUser
async def create_user_trail(
@ -17,7 +17,7 @@ async def create_user_trail(
trail_object: TrailCreate,
db_session: Session,
) -> Trail:
statement = select(Trail).where(Trail.org_id == trail_object.org_id)
statement = select(Trail).where(Trail.org_id == trail_object.org_id, Trail.user_id == user.id)
trail = db_session.exec(statement).first()
if trail:
@ -103,7 +103,7 @@ async def check_trail_presence(
user: PublicUser,
db_session: Session,
):
statement = select(Trail).where(Trail.org_id == org_id, Trail.user_id == user.id)
statement = select(Trail).where(Trail.org_id == org_id, Trail.user_id == user_id)
trail = db_session.exec(statement).first()
if not trail:
@ -122,9 +122,15 @@ async def check_trail_presence(
async def get_user_trail_with_orgid(
request: Request, user: PublicUser, org_id: int, db_session: Session
request: Request, user: PublicUser | AnonymousUser, org_id: int, db_session: Session
) -> TrailRead:
if isinstance(user, AnonymousUser):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Anonymous users cannot access this endpoint",
)
trail = await check_trail_presence(
org_id=org_id,
user_id=user.id,

View file

@ -3,17 +3,20 @@ from typing import Literal
from uuid import uuid4
from fastapi import HTTPException, Request, status
from sqlmodel import Session, select
from src.db.roles import Role, RoleRead
from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship,
authorization_verify_if_user_is_anon,
)
from src.db.organizations import Organization
from src.db.organizations import Organization, OrganizationRead
from src.db.users import (
AnonymousUser,
PublicUser,
User,
UserCreate,
UserRead,
UserRoleWithOrg,
UserSession,
UserUpdate,
UserUpdatePassword,
)
@ -279,6 +282,57 @@ async def read_user_by_uuid(
return user
async def get_user_session(
request: Request,
db_session: Session,
current_user: PublicUser | AnonymousUser,
) -> UserSession:
# Get user
statement = select(User).where(User.user_uuid == current_user.user_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)
# Get roles and orgs
statement = (
select(UserOrganization)
.where(UserOrganization.user_id == user.id)
.join(Organization)
)
user_organizations = db_session.exec(statement).all()
roles = []
for user_organization in user_organizations:
role_statement = select(Role).where(Role.id == user_organization.role_id)
role = db_session.exec(role_statement).first()
org_statement = select(Organization).where(
Organization.id == user_organization.org_id
)
org = db_session.exec(org_statement).first()
roles.append(
UserRoleWithOrg(
role=RoleRead.from_orm(role),
org=OrganizationRead.from_orm(org),
)
)
user_session = UserSession(
user=user,
roles=roles,
)
return user_session
async def authorize_user_action(
request: Request,
db_session: Session,