Skip to content
This repository has been archived by the owner on Sep 27, 2024. It is now read-only.

Commit

Permalink
since no more dependency injection, request must be passed down #122
Browse files Browse the repository at this point in the history
  • Loading branch information
lbarraga committed Apr 3, 2024
1 parent cdfd92e commit 209e3f1
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 57 deletions.
63 changes: 33 additions & 30 deletions backend/routes/dependencies/role_dependencies.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from fastapi import Depends
from fastapi.security import APIKeyHeader
from starlette.requests import Request

from controllers.auth.token_controller import verify_token
from db.sessions import get_session
Expand All @@ -18,106 +17,110 @@
InvalidStudentCredentialsError,
InvalidTeacherCredentialsError,
NoAccessToDataError,
NoCasHeaderError,
)

auth_scheme = APIKeyHeader(name="cas")

def get_authenticated_user(request: Request) -> int:
token: str | None = request.headers.get("cas")

if token is None:
raise NoCasHeaderError

def get_authenticated_user(token: str = Depends(auth_scheme)) -> int:
uid = verify_token(token)
if uid is None:
raise InvalidAuthenticationError
return uid


def get_authenticated_admin() -> AdminDataclass:
def get_authenticated_admin(request: Request) -> AdminDataclass:
session = next(get_session())
uid = get_authenticated_user()
uid = get_authenticated_user(request)

if not is_user_admin(session, uid):
raise InvalidAdminCredentialsError
return get_admin(session, uid)


def get_authenticated_teacher() -> TeacherDataclass:
def get_authenticated_teacher(request: Request) -> TeacherDataclass:
session = next(get_session())
uid = get_authenticated_user()
uid = get_authenticated_user(request)

if not is_user_teacher(session, uid):
raise InvalidTeacherCredentialsError
return get_teacher(session, uid)


def get_authenticated_student() -> StudentDataclass:
def get_authenticated_student(request: Request) -> StudentDataclass:
session = next(get_session())
uid = get_authenticated_user()
uid = get_authenticated_user(request)

if not is_user_student(session, uid):
raise InvalidStudentCredentialsError

return get_student(session, uid)


def ensure_user_authorized_for_subject(subject_id: int) -> None:
def ensure_user_authorized_for_subject(request: Request, subject_id: int) -> None:
session = next(get_session())
uid = get_authenticated_user()
uid = get_authenticated_user(request)

if not is_user_authorized_for_subject(subject_id, session, uid):
raise NoAccessToDataError


def ensure_user_authorized_for_project(project_id: int) -> None:
def ensure_user_authorized_for_project(request: Request, project_id: int) -> None:
session = next(get_session())
uid = get_authenticated_user()
uid = get_authenticated_user(request)

project = get_project(session, project_id)
if not is_user_authorized_for_subject(project.subject_id, session, uid):
raise NoAccessToDataError


def ensure_student_authorized_for_subject(subject_id: int) -> StudentDataclass:
def ensure_student_authorized_for_subject(request: Request, subject_id: int) -> StudentDataclass:
session = next(get_session())
student = get_authenticated_student()
student = get_authenticated_student(request)

subjects_of_student = get_subjects_of_student(session, student.id)
if subject_id not in [subject.id for subject in subjects_of_student]:
raise NoAccessToDataError
return student


def ensure_teacher_authorized_for_subject(subject_id: int) -> TeacherDataclass:
def ensure_teacher_authorized_for_subject(request: Request, subject_id: int) -> TeacherDataclass:
session = next(get_session())
teacher = get_authenticated_teacher()
teacher = get_authenticated_teacher(request)

subjects_of_teacher = get_subjects_of_teacher(session, teacher.id)
if subject_id not in [subject.id for subject in subjects_of_teacher]:
raise NoAccessToDataError
return teacher


def ensure_student_authorized_for_project(project_id: int) -> StudentDataclass:
def ensure_student_authorized_for_project(request: Request, project_id: int) -> StudentDataclass:
session = next(get_session())
student = get_authenticated_student()
student = get_authenticated_student(request)

projects_of_student = get_projects_of_student(session, student.id)
if project_id not in [project.id for project in projects_of_student]:
raise NoAccessToDataError
return student


def ensure_teacher_authorized_for_project(project_id: int) -> TeacherDataclass:
def ensure_teacher_authorized_for_project(request: Request, project_id: int) -> TeacherDataclass:
session = next(get_session())
teacher = get_authenticated_teacher()
teacher = get_authenticated_teacher(request)

projects_of_teacher = get_projects_of_teacher(session, teacher.id)
if project_id not in [project.id for project in projects_of_teacher]:
raise NoAccessToDataError
return teacher


def ensure_student_authorized_for_group(group_id: int) -> StudentDataclass:
def ensure_student_authorized_for_group(request: Request, group_id: int) -> StudentDataclass:
session = next(get_session())
student = get_authenticated_student()
student = get_authenticated_student(request)

group = get_group(session, group_id)
projects_of_student = get_projects_of_student(session, student.id)
Expand All @@ -126,28 +129,28 @@ def ensure_student_authorized_for_group(group_id: int) -> StudentDataclass:
return student


def ensure_user_authorized_for_group(group_id: int) -> None:
def ensure_user_authorized_for_group(request: Request, group_id: int) -> None:
session = next(get_session())
uid = get_authenticated_user()
uid = get_authenticated_user(request)

group = get_group(session, group_id)
project = get_project(session, group.project_id)
if not is_user_authorized_for_subject(project.subject_id, session, uid):
raise NoAccessToDataError


def ensure_student_in_group(group_id: int) -> StudentDataclass:
def ensure_student_in_group(request: Request, group_id: int) -> StudentDataclass:
session = next(get_session())
student = get_authenticated_student()
student = get_authenticated_student(request)

if student not in get_students_of_group(session, group_id):
raise NoAccessToDataError
return student


def ensure_user_authorized_for_submission(group_id: int) -> None:
def ensure_user_authorized_for_submission(request: Request, group_id: int) -> None:
session = next(get_session())
uid = get_authenticated_user()
uid = get_authenticated_user(request)

group = get_group(session, group_id)
if is_user_student(session, uid):
Expand Down
4 changes: 4 additions & 0 deletions backend/routes/errors/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ class NoAccessToDataError(Exception):

class InvalidAuthenticationError(Exception):
ERROR_MESSAGE = "User is not authenticated"


class NoCasHeaderError(Exception):
ERROR_MESSAGE = "No CAS header is present in the request."
8 changes: 4 additions & 4 deletions backend/routes/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@
@group_router.post("/groups/{group_id}/join", tags=[Tags.GROUP], summary="Join a certain group.")
def group_join(request: Request, group_id: int) -> None:
session = request.state.session
student = ensure_student_authorized_for_group(group_id)
student = ensure_student_authorized_for_group(request, group_id)
add_student_to_group(session, student.id, group_id)


@group_router.post("/groups/{group_id}/leave", tags=[Tags.GROUP], summary="Leave a certain group.")
def group_leave(request: Request, group_id: int) -> None:
session = request.state.session
student = ensure_student_authorized_for_group(group_id)
student = ensure_student_authorized_for_group(request, group_id)
remove_student_from_group(session, student.id, group_id)


@group_router.get("/groups/{group_id}/members", tags=[Tags.GROUP], summary="List group members.")
def list_group_members(request: Request, group_id: int) -> list[StudentDataclass]:
ensure_user_authorized_for_group(group_id)
ensure_user_authorized_for_group(request, group_id)
session = request.state.session
return get_students_of_group(session, group_id)


@group_router.get("/projects/{project_id}/group", tags=[Tags.GROUP], summary="Get your group for a project.")
def project_get_group(request: Request, project_id: int) -> GroupDataclass | None:
session = request.state.session
student = ensure_student_authorized_for_project(project_id)
student = ensure_student_authorized_for_project(request, project_id)
return get_group_for_student_and_project(session, student.id, project_id)
8 changes: 4 additions & 4 deletions backend/routes/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,27 @@
@project_router.get("/projects/{project_id}", tags=[Tags.PROJECT], summary="Get a certain project.")
def project_get(request: Request, project_id: int) -> ProjectDataclass:
session = request.state.session
ensure_user_authorized_for_project(project_id)
ensure_user_authorized_for_project(request, project_id)
project: ProjectDataclass = get_project(session, project_id)
return project


@project_router.get("/projects/{project_id}/groups", tags=[Tags.PROJECT], summary="Get all groups of a project.")
def project_get_groups(request: Request, project_id: int) -> list[GroupDataclass]:
session = request.state.session
ensure_user_authorized_for_project(project_id)
ensure_user_authorized_for_project(request, project_id)
return get_groups_of_project(session, project_id)


@project_router.post("/projects/{project_id}/groups", tags=[Tags.PROJECT], summary="Create a group for a project.")
def project_create_group(request: Request, project_id: int) -> GroupDataclass:
session = request.state.session
ensure_teacher_authorized_for_project(project_id)
ensure_teacher_authorized_for_project(request, project_id)
return create_group(session, project_id)


@project_router.patch("/projects/{project_id}", tags=[Tags.PROJECT], summary="Update a project.")
def patch_update_project(request: Request, project_id: int, project: ProjectInput) -> None:
session = request.state.session
ensure_teacher_authorized_for_project(project_id)
ensure_teacher_authorized_for_project(request, project_id)
update_project(session, project_id, project)
6 changes: 3 additions & 3 deletions backend/routes/student.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@

@student_router.get("/student/subjects", tags=[Tags.STUDENT], summary="Get all subjects of the student.")
def subjects_of_student_get(request: Request) -> list[SubjectDataclass]:
student = get_authenticated_student()
student = get_authenticated_student(request)
return get_subjects_of_student(request.state.session, student.id)


@student_router.get("/student/projects", tags=[Tags.STUDENT], summary="Get all projects of the student.")
def projects_of_student_get(request: Request) -> list[ProjectDataclass]:
student = get_authenticated_student()
student = get_authenticated_student(request)
return get_projects_of_student(request.state.session, student.id)


@student_router.post("/student/subjects/{subject_id}/join", tags=[Tags.STUDENT], summary="Join a subject.")
def student_subject_join(request: Request, subject_id: int) -> None:
student = get_authenticated_student()
student = get_authenticated_student(request)
add_student_to_subject(request.state.session, student.id, subject_id)
10 changes: 5 additions & 5 deletions backend/routes/subject.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,35 @@
@subject_router.get("/subjects/{subject_id}", tags=[Tags.SUBJECT], summary="Get a certain subject.")
def subject_get(request: Request, subject_id: int) -> SubjectDataclass:
session = request.state.session
get_authenticated_user()
get_authenticated_user(request)
return get_subject(session, subject_id)


@subject_router.get("/subjects/{subject_id}/projects", tags=[Tags.SUBJECT], summary="Get all projects of subject.")
def get_subject_projects(request: Request, subject_id: int) -> list[ProjectDataclass]:
session = request.state.session
ensure_user_authorized_for_subject(subject_id)
ensure_user_authorized_for_subject(request, subject_id)
return get_projects_of_subject(session, subject_id)


@subject_router.get("/subjects/{subject_id}/teachers", tags=[Tags.SUBJECT], summary="Get all teachers of subject.")
def get_subject_teachers(request: Request, subject_id: int) -> list[TeacherDataclass]:
session = request.state.session
ensure_user_authorized_for_subject(subject_id)
ensure_user_authorized_for_subject(request, subject_id)
return get_teachers_of_subject(session, subject_id)


@subject_router.get("/subjects/{subject_id}/students", tags=[Tags.SUBJECT], summary="Get all students of subject.")
def get_subject_students(request: Request, subject_id: int) -> list[StudentDataclass]:
session = request.state.session
ensure_user_authorized_for_subject(subject_id)
ensure_user_authorized_for_subject(request, subject_id)
return get_students_of_subject(session, subject_id)


@subject_router.post("/subjects/{subject_id}/projects", tags=[Tags.PROJECT], summary="Create project in a course.")
def new_project(request: Request, subject_id: int, project: ProjectInput) -> ProjectDataclass:
session = request.state.session
ensure_teacher_authorized_for_subject(subject_id)
ensure_teacher_authorized_for_subject(request, subject_id)
return create_project(
session,
subject_id=subject_id,
Expand Down
6 changes: 3 additions & 3 deletions backend/routes/submission.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
@submission_router.post("/groups/{group_id}/submission", tags=[Tags.SUBMISSION], summary="Make a submission.")
def make_submission(request: Request, group_id: int, file: Annotated[bytes, File()]) -> SubmissionDataclass:
session = request.state.session
student = ensure_student_in_group(group_id)
student = ensure_student_in_group(request, group_id)

filename = hashlib.sha256(file).hexdigest()
with open(f"submissions/{filename}", "wb") as f:
Expand All @@ -36,14 +36,14 @@ def make_submission(request: Request, group_id: int, file: Annotated[bytes, File
@submission_router.get("/groups/{group_id}/submission", tags=[Tags.SUBMISSION], summary="Get latest submission.")
def retrieve_submission(request: Request, group_id: int) -> SubmissionDataclass:
session = request.state.session
ensure_user_authorized_for_submission(group_id)
ensure_user_authorized_for_submission(request, group_id)
return get_last_submission(session, group_id)


@submission_router.get("/groups/{group_id}/submission/file", tags=[Tags.SUBMISSION], summary="Get last submission")
def retrieve_submission_file(request: Request, group_id: int) -> Response:
session = request.state.session
ensure_user_authorized_for_submission(group_id)
ensure_user_authorized_for_submission(request, group_id)

submission = get_last_submission(session, group_id)
with open(f"submissions/{submission.filename}", "rb") as file:
Expand Down
6 changes: 3 additions & 3 deletions backend/routes/teacher.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@
@teacher_router.get("/teacher/subjects", tags=[Tags.TEACHER], summary="Get all subjects the teacher manages.")
def subjects_of_teacher_get(request: Request) -> list[SubjectDataclass]:
session = request.state.session
teacher = get_authenticated_teacher()
teacher = get_authenticated_teacher(request)
return get_subjects_of_teacher(session, teacher.id)


@teacher_router.get("/teacher/projects", tags=[Tags.TEACHER], summary="Get all projects of the teacher.")
def projects_of_teacher_get(request: Request) -> list[ProjectDataclass]:
session = request.state.session
teacher = get_authenticated_teacher()
teacher = get_authenticated_teacher(request)
return get_projects_of_teacher(session, teacher.id)


@teacher_router.post("/teacher/subjects", tags=[Tags.SUBJECT], summary="Create a new subject.")
def create_subject_post(request: Request, subject: SubjectInput) -> SubjectDataclass:
session = request.state.session
teacher = get_authenticated_teacher()
teacher = get_authenticated_teacher(request)

new_subject = create_subject(session, name=subject.name)
add_teacher_to_subject(session, teacher_id=teacher.id, subject_id=new_subject.id)
Expand Down
Loading

0 comments on commit 209e3f1

Please sign in to comment.