feat: add Assignments, Tasks, Submissions CRUD

This commit is contained in:
swve 2024-07-10 23:35:32 +02:00
parent cd2397f4f7
commit 47782b57bc
32 changed files with 1719 additions and 218 deletions

View file

@ -1,133 +0,0 @@
from typing import Optional
from openai import BaseModel
from sqlalchemy import JSON, Column, ForeignKey
from sqlmodel import Field, SQLModel
from enum import Enum
class AssignmentTypeEnum(str, Enum):
FILE_SUBMISSION = "FILE_SUBMISSION"
QUIZ = "QUIZ"
OTHER = "OTHER"
class Assignment(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
assignment_uuid: str
title: str
description: str
due_date: str
org_id: int = Field(
sa_column=Column("org_id", ForeignKey("organization.id", ondelete="CASCADE"))
)
course_id: int = Field(
sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE"))
)
chapter_id: int = Field(
sa_column=Column("chapter_id", ForeignKey("chapter.id", ondelete="CASCADE"))
)
activity_id: int = Field(
sa_column=Column("activity_id", ForeignKey("activity.id", ondelete="CASCADE"))
)
creation_date: str
update_date: str
class AssignmentTask(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
assignment_task_uuid: str = ""
title: str = ""
description: str = ""
hint: str = ""
assignment_type: AssignmentTypeEnum
contents: dict = Field(default={}, sa_column=Column(JSON))
max_grade_value: int = (
0 # Value is always between 0-100 and is used as the maximum grade for the task
)
# Foreign keys
assignment_id: int = Field(
sa_column=Column(
"assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
)
)
org_id: int = Field(
sa_column=Column("org_id", ForeignKey("organization.id", ondelete="CASCADE"))
)
course_id: int = Field(
sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE"))
)
chapter_id: int = Field(
sa_column=Column("chapter_id", ForeignKey("chapter.id", ondelete="CASCADE"))
)
activity_id: int = Field(
sa_column=Column("activity_id", ForeignKey("activity.id", ondelete="CASCADE"))
)
creation_date: str
update_date: str
class AssignmentTaskSubmission(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
assignment_task_submission_uuid: str = ""
task_submission: dict = Field(default={}, sa_column=Column(JSON))
grade: int = (
0 # Value is always between 0-100 depending on the questions, this is used to calculate the final grade on the AssignmentUser model
)
task_submission_grade_feedback: str = "" # Feedback given by the teacher
# Foreign keys
user_id: int = Field(
sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
)
activity_id: int = Field(
sa_column=Column("activity_id", ForeignKey("activity.id", ondelete="CASCADE"))
)
course_id: int = Field(
sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE"))
)
chapter_id: int = Field(
sa_column=Column("chapter_id", ForeignKey("chapter.id", ondelete="CASCADE"))
)
assignment_task_id: int = Field(
sa_column=Column(
"assignment_task_id", ForeignKey("assignment_task.id", ondelete="CASCADE")
)
)
creation_date: str = ""
update_date: str = ""
# Note on grading :
# To calculate the final grade :
class AssignmentUserSubmissionStatus(str, Enum):
PENDING = "PENDING"
SUBMITTED = "SUBMITTED"
GRADED = "GRADED"
LATE = "LATE"
NOT_SUBMITTED = "NOT_SUBMITTED"
class AssignmentUserSubmission(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
assignment_user_uuid: str = ""
submission_status: AssignmentUserSubmissionStatus = (
AssignmentUserSubmissionStatus.PENDING
)
grading: str = ""
user_id: int = Field(
sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
)
assignment_id: int = Field(
sa_column=Column(
"assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
)
)
creation_date: str = ""
update_date: str = ""

View file

@ -0,0 +1,317 @@
from typing import Optional, Dict
from sqlalchemy import JSON, Column, ForeignKey
from sqlmodel import Field, SQLModel
from enum import Enum
## Assignment ##
class GradingTypeEnum(str, Enum):
ALPHABET = "ALPHABET"
NUMERIC = "NUMERIC"
PERCENTAGE = "PERCENTAGE"
class AssignmentBase(SQLModel):
"""Represents the common fields for an assignment."""
title: str
description: str
due_date: str
published: Optional[bool] = False
grading_type: GradingTypeEnum
org_id: int
course_id: int
chapter_id: int
activity_id: int
class AssignmentCreate(AssignmentBase):
"""Model for creating a new assignment."""
pass # Inherits all fields from AssignmentBase
class AssignmentRead(AssignmentBase):
"""Model for reading an assignment."""
id: int
assignment_uuid: str
creation_date: Optional[str]
update_date: Optional[str]
class AssignmentUpdate(SQLModel):
"""Model for updating an assignment."""
title: Optional[str]
description: Optional[str]
due_date: Optional[str]
published: Optional[bool]
grading_type: Optional[GradingTypeEnum]
org_id: Optional[int]
course_id: Optional[int]
chapter_id: Optional[int]
activity_id: Optional[int]
update_date: Optional[str]
class Assignment(AssignmentBase, table=True):
"""Represents an assignment with relevant details and foreign keys."""
id: Optional[int] = Field(default=None, primary_key=True)
creation_date: Optional[str]
update_date: Optional[str]
assignment_uuid: str
org_id: int = Field(
sa_column=Column("org_id", ForeignKey("organization.id", ondelete="CASCADE"))
)
course_id: int = Field(
sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE"))
)
chapter_id: int = Field(
sa_column=Column("chapter_id", ForeignKey("chapter.id", ondelete="CASCADE"))
)
activity_id: int = Field(
sa_column=Column("activity_id", ForeignKey("activity.id", ondelete="CASCADE"))
)
## Assignment ##
## AssignmentTask ##
class AssignmentTaskTypeEnum(str, Enum):
FILE_SUBMISSION = "FILE_SUBMISSION"
QUIZ = "QUIZ"
FORM = "FORM" # soon to be implemented
OTHER = "OTHER"
class AssignmentTaskBase(SQLModel):
"""Represents the common fields for an assignment task."""
title: str
description: str
hint: str
assignment_type: AssignmentTaskTypeEnum
contents: Dict = Field(default={}, sa_column=Column(JSON))
max_grade_value: int = 0 # Value is always between 0-100
assignment_id: int
org_id: int
course_id: int
chapter_id: int
activity_id: int
class AssignmentTaskCreate(AssignmentTaskBase ):
"""Model for creating a new assignment task."""
pass # Inherits all fields from AssignmentTaskBase
class AssignmentTaskRead(AssignmentTaskBase):
"""Model for reading an assignment task."""
id: int
assignment_task_uuid: str
class AssignmentTaskUpdate(SQLModel):
"""Model for updating an assignment task."""
title: Optional[str]
description: Optional[str]
hint: Optional[str]
assignment_type: Optional[AssignmentTaskTypeEnum]
contents: Optional[Dict] = Field(default={}, sa_column=Column(JSON))
max_grade_value: Optional[int]
assignment_id: Optional[int]
org_id: Optional[int]
course_id: Optional[int]
chapter_id: Optional[int]
activity_id: Optional[int]
class AssignmentTask(AssignmentTaskBase, table=True):
"""Represents a task within an assignment with various attributes and foreign keys."""
id: Optional[int] = Field(default=None, primary_key=True)
assignment_task_uuid: str
creation_date: str
update_date: str
assignment_id: int = Field(
sa_column=Column(
"assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
)
)
org_id: int = Field(
sa_column=Column("org_id", ForeignKey("organization.id", ondelete="CASCADE"))
)
course_id: int = Field(
sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE"))
)
chapter_id: int = Field(
sa_column=Column("chapter_id", ForeignKey("chapter.id", ondelete="CASCADE"))
)
activity_id: int = Field(
sa_column=Column("activity_id", ForeignKey("activity.id", ondelete="CASCADE"))
)
## AssignmentTask ##
## AssignmentTaskSubmission ##
class AssignmentTaskSubmissionBase(SQLModel):
"""Represents the common fields for an assignment task submission."""
task_submission: Dict = Field(default={}, sa_column=Column(JSON))
grade: int = 0 # Value is always between 0-100
task_submission_grade_feedback: str
assignment_type: AssignmentTaskTypeEnum
user_id: int
activity_id: int
course_id: int
chapter_id: int
assignment_task_id: int
class AssignmentTaskSubmissionCreate(AssignmentTaskSubmissionBase):
"""Model for creating a new assignment task submission."""
pass # Inherits all fields from AssignmentTaskSubmissionBase
class AssignmentTaskSubmissionRead(AssignmentTaskSubmissionBase):
"""Model for reading an assignment task submission."""
id: int
creation_date: str
update_date: str
class AssignmentTaskSubmissionUpdate(SQLModel):
"""Model for updating an assignment task submission."""
assignment_task_submission_uuid: Optional[str]
task_submission: Optional[Dict] = Field(default={}, sa_column=Column(JSON))
grade: Optional[int]
task_submission_grade_feedback: Optional[str]
assignment_type: Optional[AssignmentTaskTypeEnum]
user_id: Optional[int]
activity_id: Optional[int]
course_id: Optional[int]
chapter_id: Optional[int]
assignment_task_id: Optional[int]
class AssignmentTaskSubmission(AssignmentTaskSubmissionBase, table=True):
"""Represents a submission for a specific assignment task with grade and feedback."""
id: Optional[int] = Field(default=None, primary_key=True)
assignment_task_submission_uuid: str
task_submission: Dict = Field(default={}, sa_column=Column(JSON))
grade: int = 0 # Value is always between 0-100
task_submission_grade_feedback: str
assignment_type: AssignmentTaskTypeEnum
user_id: int = Field(
sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
)
activity_id: int = Field(
sa_column=Column("activity_id", ForeignKey("activity.id", ondelete="CASCADE"))
)
course_id: int = Field(
sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE"))
)
chapter_id: int = Field(
sa_column=Column("chapter_id", ForeignKey("chapter.id", ondelete="CASCADE"))
)
assignment_task_id: int = Field(
sa_column=Column(
"assignment_task_id", ForeignKey("assignmenttask.id", ondelete="CASCADE")
)
)
creation_date: str
update_date: str
## AssignmentTaskSubmission ##
## AssignmentUserSubmission ##
class AssignmentUserSubmissionStatus(str, Enum):
PENDING = "PENDING"
SUBMITTED = "SUBMITTED"
GRADED = "GRADED"
LATE = "LATE"
NOT_SUBMITTED = "NOT_SUBMITTED"
class AssignmentUserSubmissionBase(SQLModel):
"""Represents the submission status of an assignment for a user."""
submission_status: AssignmentUserSubmissionStatus = (
AssignmentUserSubmissionStatus.PENDING
)
grade: str
user_id: int = Field(
sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
)
assignment_id: int = Field(
sa_column=Column(
"assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
)
)
class AssignmentUserSubmissionCreate(AssignmentUserSubmissionBase):
"""Model for creating a new assignment user submission."""
pass # Inherits all fields from AssignmentUserSubmissionBase
class AssignmentUserSubmissionRead(AssignmentUserSubmissionBase):
"""Model for reading an assignment user submission."""
id: int
creation_date: str
update_date: str
class AssignmentUserSubmissionUpdate(SQLModel):
"""Model for updating an assignment user submission."""
submission_status: Optional[AssignmentUserSubmissionStatus]
grade: Optional[str]
user_id: Optional[int]
assignment_id: Optional[int]
class AssignmentUserSubmission(AssignmentUserSubmissionBase, table=True):
"""Represents the submission status of an assignment for a user."""
id: Optional[int] = Field(default=None, primary_key=True)
creation_date: str
update_date: str
submission_status: AssignmentUserSubmissionStatus = (
AssignmentUserSubmissionStatus.PENDING
)
grade: str
user_id: int = Field(
sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
)
assignment_id: int = Field(
sa_column=Column(
"assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
)
)

View file

@ -35,7 +35,7 @@ class BlockCreate(BlockBase):
class BlockRead(BlockBase):
id: int
id: int = Field(default=None, primary_key=True)
org_id: int = Field(default=None, foreign_key="organization.id")
course_id: int = Field(default=None, foreign_key="course.id")
chapter_id: int = Field(default=None, foreign_key="chapter.id")

View file

@ -2,7 +2,7 @@ from typing import Any, List, Optional
from pydantic import BaseModel
from sqlalchemy import Column, ForeignKey
from sqlmodel import Field, SQLModel
from src.db.activities import ActivityRead
from src.db.courses.activities import ActivityRead
class ChapterBase(SQLModel):
@ -33,10 +33,10 @@ class ChapterCreate(ChapterBase):
class ChapterUpdate(ChapterBase):
name: Optional[str]
description: Optional[str]
thumbnail_image: Optional[str]
description: Optional[str] = ""
thumbnail_image: Optional[str] = ""
course_id: Optional[int]
org_id: Optional[int]
org_id: Optional[int] # type: ignore
class ChapterRead(ChapterBase):

View file

@ -3,7 +3,7 @@ from sqlalchemy import Column, ForeignKey, Integer
from sqlmodel import Field, SQLModel
from src.db.users import UserRead
from src.db.trails import TrailRead
from src.db.chapters import ChapterRead
from src.db.courses.chapters import ChapterRead
class CourseBase(SQLModel):
@ -21,7 +21,7 @@ class Course(CourseBase, table=True):
org_id: int = Field(
sa_column=Column(Integer, ForeignKey("organization.id", ondelete="CASCADE"))
)
course_uuid: str = ""
course_uuid: str = ""
creation_date: str = ""
update_date: str = ""

View file

@ -6,8 +6,12 @@ from src.db.trail_runs import TrailRunRead
class TrailBase(SQLModel):
org_id: int = Field(default=None, foreign_key="organization.id")
user_id: int = Field(default=None, foreign_key="user.id")
org_id: int = Field(
sa_column=Column(Integer, ForeignKey("organization.id", ondelete="CASCADE"))
)
user_id: int = Field(
sa_column=Column(Integer, ForeignKey("user.id", ondelete="CASCADE"))
)
class Trail(TrailBase, table=True):
@ -20,6 +24,7 @@ class Trail(TrailBase, table=True):
class TrailCreate(TrailBase):
pass
# TODO: This is a hacky way to get around the list[TrailRun] issue, find a better way to do this
class TrailRead(BaseModel):
id: Optional[int] = Field(default=None, primary_key=True)

View file

@ -1,8 +1,9 @@
from fastapi import APIRouter, Depends
from src.routers import usergroups
from src.routers import blocks, dev, trail, users, auth, orgs, roles
from src.routers import dev, trail, users, auth, orgs, roles
from src.routers.ai import ai
from src.routers.courses import chapters, collections, courses, activities
from src.routers.courses import chapters, collections, courses, assignments
from src.routers.courses.activities import activities, blocks
from src.routers.install import install
from src.services.dev.dev import isDevModeEnabledOrRaise
from src.services.install.install import isInstallModeEnabled
@ -19,6 +20,7 @@ v1_router.include_router(orgs.router, prefix="/orgs", tags=["orgs"])
v1_router.include_router(roles.router, prefix="/roles", tags=["roles"])
v1_router.include_router(blocks.router, prefix="/blocks", tags=["blocks"])
v1_router.include_router(courses.router, prefix="/courses", tags=["courses"])
v1_router.include_router(assignments.router, prefix="/assignments", tags=["assignments"])
v1_router.include_router(chapters.router, prefix="/chapters", tags=["chapters"])
v1_router.include_router(activities.router, prefix="/activities", tags=["activities"])
v1_router.include_router(collections.router, prefix="/collections", tags=["collections"])

View file

@ -1,6 +1,6 @@
from typing import List
from fastapi import APIRouter, Depends, UploadFile, Form, Request
from src.db.activities import ActivityCreate, ActivityRead, ActivityUpdate
from src.db.courses.activities import ActivityCreate, ActivityRead, ActivityUpdate
from src.db.users import PublicUser
from src.core.events.database import get_db_session
from src.services.courses.activities.activities import (

View file

@ -1,5 +1,5 @@
from fastapi import APIRouter, Depends, UploadFile, Form, Request
from src.db.blocks import BlockRead
from src.db.courses.blocks import BlockRead
from src.core.events.database import get_db_session
from src.security.auth import get_current_user
from src.services.blocks.block_types.imageBlock.imageBlock import (

View file

@ -0,0 +1,310 @@
from fastapi import APIRouter, Depends, Request
from src.db.courses.assignments import (
AssignmentCreate,
AssignmentRead,
AssignmentTaskCreate,
AssignmentTaskSubmissionCreate,
AssignmentTaskUpdate,
AssignmentUpdate,
AssignmentUserSubmissionCreate,
)
from src.db.users import PublicUser
from src.core.events.database import get_db_session
from src.security.auth import get_current_user
from src.services.courses.activities.assignments import (
create_assignment,
create_assignment_submission,
create_assignment_task,
create_assignment_task_submission,
delete_assignment,
delete_assignment_submission,
delete_assignment_task,
delete_assignment_task_submission,
read_assignment,
read_assignment_submissions,
read_assignment_task_submissions,
read_assignment_tasks,
read_user_assignment_submissions,
read_user_assignment_task_submissions,
update_assignment,
update_assignment_submission,
update_assignment_task,
)
router = APIRouter()
## ASSIGNMENTS ##
@router.post("/")
async def api_create_assignments(
request: Request,
assignment_object: AssignmentCreate,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
) -> AssignmentRead:
"""
Create new activity
"""
return await create_assignment(request, assignment_object, current_user, db_session)
@router.get("/{assignment_uuid}")
async def api_read_assignment(
request: Request,
assignment_uuid: str,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
) -> AssignmentRead:
"""
Read an assignment
"""
return await read_assignment(request, assignment_uuid, current_user, db_session)
@router.put("/{assignment_uuid}")
async def api_update_assignment(
request: Request,
assignment_uuid: str,
assignment_object: AssignmentUpdate,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
) -> AssignmentRead:
"""
Update an assignment
"""
return await update_assignment(
request, assignment_uuid, assignment_object, current_user, db_session
)
@router.delete("/{assignment_uuid}")
async def api_delete_assignment(
request: Request,
assignment_uuid: str,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
"""
Delete an assignment
"""
return await delete_assignment(request, assignment_uuid, current_user, db_session)
## ASSIGNMENTS Tasks ##
@router.post("/{assignment_uuid}/tasks")
async def api_create_assignment_tasks(
request: Request,
assignment_uuid: str,
assignment_task_object: AssignmentTaskCreate,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
"""
Create new tasks for an assignment
"""
return await create_assignment_task(
request, assignment_uuid, assignment_task_object, current_user, db_session
)
@router.get("/{assignment_uuid}/tasks")
async def api_read_assignment_tasks(
request: Request,
assignment_uuid: str,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
"""
Read tasks for an assignment
"""
return await read_assignment_tasks(
request, assignment_uuid, current_user, db_session
)
@router.put("/{assignment_uuid}/tasks/{task_uuid}")
async def api_update_assignment_tasks(
request: Request,
assignment_task_uuid: str,
assignment_task_object: AssignmentTaskUpdate,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
"""
Update tasks for an assignment
"""
return await update_assignment_task(
request, assignment_task_uuid, assignment_task_object, current_user, db_session
)
@router.delete("/{assignment_uuid}/tasks/{task_uuid}")
async def api_delete_assignment_tasks(
request: Request,
assignment_task_uuid: str,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
"""
Delete tasks for an assignment
"""
return await delete_assignment_task(
request, assignment_task_uuid, current_user, db_session
)
## ASSIGNMENTS Tasks Submissions ##
@router.post("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions")
async def api_create_assignment_task_submissions(
request: Request,
assignment_task_submission_object: AssignmentTaskSubmissionCreate,
assignment_task_uuid: str,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
"""
Create new task submissions for an assignment
"""
return await create_assignment_task_submission(
request,
assignment_task_uuid,
assignment_task_submission_object,
current_user,
db_session,
)
@router.get("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions/{user_id}")
async def api_read_user_assignment_task_submissions(
request: Request,
assignment_task_uuid: str,
user_id: int,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
"""
Read task submissions for an assignment from a user
"""
return await read_user_assignment_task_submissions(
request, assignment_task_uuid, user_id, current_user, db_session
)
@router.get("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions")
async def api_read_assignment_task_submissions(
request: Request,
assignment_task_uuid: str,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
"""
Read task submissions for an assignment from a user
"""
return await read_assignment_task_submissions(
request, assignment_task_uuid, current_user, db_session
)
@router.delete(
"/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions/{assignment_task_submission_uuid}"
)
async def api_delete_assignment_task_submissions(
request: Request,
assignment_task_submission_uuid: str,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
"""
Delete task submissions for an assignment from a user
"""
return await delete_assignment_task_submission(
request, assignment_task_submission_uuid, current_user, db_session
)
## ASSIGNMENTS Submissions ##
@router.post("/{assignment_uuid}/submissions")
async def api_create_assignment_submissions(
request: Request,
assignment_uuid: str,
assignment_submission: AssignmentUserSubmissionCreate,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
"""
Create new submissions for an assignment
"""
return await create_assignment_submission(
request, assignment_uuid, assignment_submission, current_user, db_session
)
@router.get("/{assignment_uuid}/submissions")
async def api_read_assignment_submissions(
request: Request,
assignment_uuid: str,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
"""
Read submissions for an assignment
"""
return await read_assignment_submissions(
request, assignment_uuid, current_user, db_session
)
@router.get("/{assignment_uuid}/submissions/{user_id}")
async def api_read_user_assignment_submissions(
request: Request,
assignment_uuid: str,
user_id: int,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
"""
Read submissions for an assignment from a user
"""
return await read_user_assignment_submissions(
request, assignment_uuid, user_id, current_user, db_session
)
@router.put("/{assignment_uuid}/submissions/{user_id}")
async def api_update_user_assignment_submissions(
request: Request,
assignment_uuid: str,
user_id: str,
assignment_submission: AssignmentUserSubmissionCreate,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
"""
Update submissions for an assignment from a user
"""
return await update_assignment_submission(
request, user_id, assignment_submission, current_user, db_session
)
@router.delete("/{assignment_uuid}/submissions/{user_id}")
async def api_delete_user_assignment_submissions(
request: Request,
assignment_id: str,
user_id: str,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
"""
Delete submissions for an assignment from a user
"""
return await delete_assignment_submission(
request, assignment_id, user_id, current_user, db_session
)

View file

@ -1,7 +1,7 @@
from typing import List
from fastapi import APIRouter, Depends, Request
from src.core.events.database import get_db_session
from src.db.chapters import (
from src.db.courses.chapters import (
ChapterCreate,
ChapterRead,
ChapterUpdate,

View file

@ -2,13 +2,13 @@ from typing import List
from fastapi import APIRouter, Depends, UploadFile, Form, Request
from sqlmodel import Session
from src.core.events.database import get_db_session
from src.db.course_updates import (
from src.db.courses.course_updates import (
CourseUpdateCreate,
CourseUpdateRead,
CourseUpdateUpdate,
)
from src.db.users import PublicUser
from src.db.courses import (
from src.db.courses.courses import (
CourseCreate,
CourseRead,
CourseUpdate,

View file

@ -3,7 +3,7 @@ from fastapi import HTTPException, status, Request
from sqlalchemy import null
from sqlmodel import Session, select
from src.db.collections import Collection
from src.db.courses import Course
from src.db.courses.courses import Course
from src.db.resource_authors import ResourceAuthor, ResourceAuthorshipEnum
from src.db.roles import Role
from src.db.user_organizations import UserOrganization

View file

@ -3,10 +3,10 @@ from sqlmodel import Session, select
from src.db.organization_config import OrganizationConfig
from src.db.organizations import Organization
from src.services.ai.utils import check_limits_and_config, count_ai_ask
from src.db.courses import Course, CourseRead
from src.db.courses.courses import Course, CourseRead
from src.core.events.database import get_db_session
from src.db.users import PublicUser
from src.db.activities import Activity, ActivityRead
from src.db.courses.activities import Activity, ActivityRead
from src.security.auth import get_current_user
from src.services.ai.base import ask_ai, get_chat_session_history

View file

@ -3,9 +3,9 @@ from uuid import uuid4
from src.db.organizations import Organization
from fastapi import HTTPException, status, UploadFile, Request
from sqlmodel import Session, select
from src.db.activities import Activity
from src.db.blocks import Block, BlockRead, BlockTypeEnum
from src.db.courses import Course
from src.db.courses.activities import Activity
from src.db.courses.blocks import Block, BlockRead, BlockTypeEnum
from src.db.courses.courses import Course
from src.services.blocks.utils.upload_files import upload_file_and_return_file_object
from src.services.users.users import PublicUser

View file

@ -3,9 +3,9 @@ from uuid import uuid4
from src.db.organizations import Organization
from fastapi import HTTPException, status, UploadFile, Request
from sqlmodel import Session, select
from src.db.activities import Activity
from src.db.blocks import Block, BlockRead, BlockTypeEnum
from src.db.courses import Course
from src.db.courses.activities import Activity
from src.db.courses.blocks import Block, BlockRead, BlockTypeEnum
from src.db.courses.courses import Course
from src.services.blocks.utils.upload_files import upload_file_and_return_file_object
from src.services.users.users import PublicUser

View file

@ -3,9 +3,9 @@ from uuid import uuid4
from src.db.organizations import Organization
from fastapi import HTTPException, status, UploadFile, Request
from sqlmodel import Session, select
from src.db.activities import Activity
from src.db.blocks import Block, BlockRead, BlockTypeEnum
from src.db.courses import Course
from src.db.courses.activities import Activity
from src.db.courses.blocks import Block, BlockRead, BlockTypeEnum
from src.db.courses.courses import Course
from src.services.blocks.utils.upload_files import upload_file_and_return_file_object
from src.services.users.users import PublicUser

View file

@ -1,14 +1,14 @@
from typing import Literal
from sqlmodel import Session, select
from src.db.courses import Course
from src.db.chapters import Chapter
from src.db.courses.courses import Course
from src.db.courses.chapters import Chapter
from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship_and_usergroups,
authorization_verify_if_element_is_public,
authorization_verify_if_user_is_anon,
)
from src.db.activities import ActivityCreate, Activity, ActivityRead, ActivityUpdate
from src.db.chapter_activities import ChapterActivity
from src.db.courses.activities import ActivityCreate, Activity, ActivityRead, ActivityUpdate
from src.db.courses.chapter_activities import ChapterActivity
from src.db.users import AnonymousUser, PublicUser
from fastapi import HTTPException, Request
from uuid import uuid4
@ -58,7 +58,7 @@ async def create_activity(
statement = (
select(ChapterActivity)
.where(ChapterActivity.chapter_id == activity_object.chapter_id)
.order_by(ChapterActivity.order)
.order_by(ChapterActivity.order) # type: ignore
)
chapter_activities = db_session.exec(statement).all()

View file

@ -0,0 +1,997 @@
####################################################
# CRUD
####################################################
from datetime import datetime
from typing import Literal
from uuid import uuid4
from fastapi import HTTPException, Request
from sqlmodel import Session, select
from src.db.courses.assignments import (
Assignment,
AssignmentCreate,
AssignmentRead,
AssignmentTask,
AssignmentTaskCreate,
AssignmentTaskRead,
AssignmentTaskSubmission,
AssignmentTaskSubmissionCreate,
AssignmentTaskSubmissionRead,
AssignmentTaskUpdate,
AssignmentUpdate,
AssignmentUserSubmission,
AssignmentUserSubmissionCreate,
AssignmentUserSubmissionRead,
)
from src.db.courses.courses import Course
from src.db.users import AnonymousUser, PublicUser
from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship_and_usergroups,
authorization_verify_if_element_is_public,
authorization_verify_if_user_is_anon,
)
## > Assignments CRUD
async def create_assignment(
request: Request,
assignment_object: AssignmentCreate,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Check if org exists
statement = select(Course).where(Course.id == assignment_object.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "create", db_session)
# Create Assignment
assignment = Assignment(**assignment_object.model_dump())
assignment.assignment_uuid = str(f"assignment_{uuid4()}")
assignment.creation_date = str(datetime.now())
assignment.update_date = str(datetime.now())
assignment.org_id = course.org_id
# Insert Assignment in DB
db_session.add(assignment)
db_session.commit()
db_session.refresh(assignment)
# return assignment read
return AssignmentRead.model_validate(assignment)
async def read_assignment(
request: Request,
assignment_uuid: str,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Check if assignment exists
statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "read", db_session)
# return assignment read
return AssignmentRead.model_validate(assignment)
async def update_assignment(
request: Request,
assignment_uuid: str,
assignment_object: AssignmentUpdate,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Check if assignment exists
statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "update", db_session)
# Update only the fields that were passed in
for var, value in vars(assignment_object).items():
if value is not None:
setattr(assignment, var, value)
assignment.update_date = str(datetime.now())
# Insert Assignment in DB
db_session.add(assignment)
db_session.commit()
db_session.refresh(assignment)
# return assignment read
return AssignmentRead.model_validate(assignment)
async def delete_assignment(
request: Request,
assignment_uuid: str,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Check if assignment exists
statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "delete", db_session)
# Delete Assignment
db_session.delete(assignment)
db_session.commit()
return {"message": "Assignment deleted"}
## > Assignments Tasks CRUD
async def create_assignment_task(
request: Request,
assignment_uuid: str,
assignment_task_object: AssignmentTaskCreate,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Check if assignment exists
statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "create", db_session)
# Create Assignment Task
assignment_task = AssignmentTask(**assignment_task_object.model_dump())
assignment_task.assignment_task_uuid = str(f"assignmenttask_{uuid4()}")
assignment_task.creation_date = str(datetime.now())
assignment_task.update_date = str(datetime.now())
assignment_task.org_id = course.org_id
# Insert Assignment Task in DB
db_session.add(assignment_task)
db_session.commit()
db_session.refresh(assignment_task)
# return assignment task read
return AssignmentTaskRead.model_validate(assignment_task)
async def read_assignment_tasks(
request: Request,
assignment_uuid: str,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Find assignment
statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# Find assignments tasks for an assignment
statement = select(AssignmentTask).where(
assignment.assignment_uuid == assignment_uuid
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "read", db_session)
# return assignment tasks read
return [
AssignmentTaskRead.model_validate(assignment_task)
for assignment_task in db_session.exec(statement).all()
]
async def update_assignment_task(
request: Request,
assignment_task_uuid: str,
assignment_task_object: AssignmentTaskUpdate,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Check if assignment task exists
statement = select(AssignmentTask).where(
AssignmentTask.assignment_task_uuid == assignment_task_uuid
)
assignment_task = db_session.exec(statement).first()
if not assignment_task:
raise HTTPException(
status_code=404,
detail="Assignment Task not found",
)
# Check if assignment exists
statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "update", db_session)
# Update only the fields that were passed in
for var, value in vars(assignment_task_object).items():
if value is not None:
setattr(assignment_task, var, value)
assignment_task.update_date = str(datetime.now())
# Insert Assignment Task in DB
db_session.add(assignment_task)
db_session.commit()
db_session.refresh(assignment_task)
# return assignment task read
return AssignmentTaskRead.model_validate(assignment_task)
async def delete_assignment_task(
request: Request,
assignment_task_uuid: str,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Check if assignment task exists
statement = select(AssignmentTask).where(
AssignmentTask.assignment_task_uuid == assignment_task_uuid
)
assignment_task = db_session.exec(statement).first()
if not assignment_task:
raise HTTPException(
status_code=404,
detail="Assignment Task not found",
)
# Check if assignment exists
statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "delete", db_session)
# Delete Assignment Task
db_session.delete(assignment_task)
db_session.commit()
return {"message": "Assignment Task deleted"}
## > Assignments Tasks Submissions CRUD
async def create_assignment_task_submission(
request: Request,
assignment_task_uuid: str,
assignment_task_submission_object: AssignmentTaskSubmissionCreate,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Check if assignment task exists
statement = select(AssignmentTask).where(
AssignmentTask.assignment_task_uuid == assignment_task_uuid
)
assignment_task = db_session.exec(statement).first()
if not assignment_task:
raise HTTPException(
status_code=404,
detail="Assignment Task not found",
)
# Check if assignment exists
statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "create", db_session)
# Create Assignment Task Submission
assignment_task_submission = AssignmentTaskSubmission(
**assignment_task_submission_object.model_dump()
)
assignment_task_submission.assignment_task_submission_uuid = str(
f"assignmenttasksubmission_{uuid4()}"
)
assignment_task_submission.creation_date = str(datetime.now())
assignment_task_submission.update_date = str(datetime.now())
assignment_task_submission.org_id = course.org_id
# Insert Assignment Task Submission in DB
db_session.add(assignment_task_submission)
db_session.commit()
db_session.refresh(assignment_task_submission)
# return assignment task submission read
return AssignmentTaskSubmissionRead.model_validate(assignment_task_submission)
async def read_user_assignment_task_submissions(
request: Request,
assignment_task_submission_uuid: str,
user_id: int,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Check if assignment task submission exists
statement = select(AssignmentTaskSubmission).where(
AssignmentTaskSubmission.assignment_task_submission_uuid
== assignment_task_submission_uuid,
AssignmentTaskSubmission.user_id == user_id,
)
assignment_task_submission = db_session.exec(statement).first()
if not assignment_task_submission:
raise HTTPException(
status_code=404,
detail="Assignment Task Submission not found",
)
# Check if assignment task exists
statement = select(AssignmentTask).where(
AssignmentTask.id == assignment_task_submission.assignment_task_id
)
assignment_task = db_session.exec(statement).first()
if not assignment_task:
raise HTTPException(
status_code=404,
detail="Assignment Task not found",
)
# Check if assignment exists
statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "read", db_session)
# return assignment task submission read
return AssignmentTaskSubmissionRead.model_validate(assignment_task_submission)
async def read_assignment_task_submissions(
request: Request,
assignment_task_submission_uuid: str,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Check if assignment task submission exists
statement = select(AssignmentTaskSubmission).where(
AssignmentTaskSubmission.assignment_task_submission_uuid
== assignment_task_submission_uuid,
)
assignment_task_submission = db_session.exec(statement).first()
if not assignment_task_submission:
raise HTTPException(
status_code=404,
detail="Assignment Task Submission not found",
)
# Check if assignment task exists
statement = select(AssignmentTask).where(
AssignmentTask.id == assignment_task_submission.assignment_task_id
)
assignment_task = db_session.exec(statement).first()
if not assignment_task:
raise HTTPException(
status_code=404,
detail="Assignment Task not found",
)
# Check if assignment exists
statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "read", db_session)
# return assignment task submission read
return AssignmentTaskSubmissionRead.model_validate(assignment_task_submission)
async def update_assignment_task_submission(
request: Request,
assignment_task_submission_uuid: str,
assignment_task_submission_object: AssignmentTaskSubmissionCreate,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Check if assignment task submission exists
statement = select(AssignmentTaskSubmission).where(
AssignmentTaskSubmission.assignment_task_submission_uuid
== assignment_task_submission_uuid
)
assignment_task_submission = db_session.exec(statement).first()
if not assignment_task_submission:
raise HTTPException(
status_code=404,
detail="Assignment Task Submission not found",
)
# Check if assignment task exists
statement = select(AssignmentTask).where(
AssignmentTask.id == assignment_task_submission.assignment_task_id
)
assignment_task = db_session.exec(statement).first()
if not assignment_task:
raise HTTPException(
status_code=404,
detail="Assignment Task not found",
)
# Check if assignment exists
statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "update", db_session)
# Update only the fields that were passed in
for var, value in vars(assignment_task_submission_object).items():
if value is not None:
setattr(assignment_task_submission, var, value)
assignment_task_submission.update_date = str(datetime.now())
# Insert Assignment Task Submission in DB
db_session.add(assignment_task_submission)
db_session.commit()
db_session.refresh(assignment_task_submission)
# return assignment task submission read
return AssignmentTaskSubmissionRead.model_validate(assignment_task_submission)
async def delete_assignment_task_submission(
request: Request,
assignment_task_submission_uuid: str,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Check if assignment task submission exists
statement = select(AssignmentTaskSubmission).where(
AssignmentTaskSubmission.assignment_task_submission_uuid
== assignment_task_submission_uuid
)
assignment_task_submission = db_session.exec(statement).first()
if not assignment_task_submission:
raise HTTPException(
status_code=404,
detail="Assignment Task Submission not found",
)
# Check if assignment task exists
statement = select(AssignmentTask).where(
AssignmentTask.id == assignment_task_submission.assignment_task_id
)
assignment_task = db_session.exec(statement).first()
if not assignment_task:
raise HTTPException(
status_code=404,
detail="Assignment Task not found",
)
# Check if assignment exists
statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "delete", db_session)
# Delete Assignment Task Submission
db_session.delete(assignment_task_submission)
db_session.commit()
return {"message": "Assignment Task Submission deleted"}
## > Assignments Submissions CRUD
async def create_assignment_submission(
request: Request,
assignment_uuid: str,
assignment_user_submission_object: AssignmentUserSubmissionCreate,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Check if assignment exists
statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if the submission has already been made
statement = select(AssignmentUserSubmission).where(
AssignmentUserSubmission.assignment_id == assignment.id,
AssignmentUserSubmission.user_id == assignment_user_submission_object.user_id,
)
assignment_user_submission = db_session.exec(statement).first()
if assignment_user_submission:
raise HTTPException(
status_code=400,
detail="Assignment User Submission already exists",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "create", db_session)
# Create Assignment User Submission
assignment_user_submission = AssignmentUserSubmission(
**assignment_user_submission_object.model_dump()
)
assignment_user_submission.assignment_user_submission_uuid = str(
f"assignmentusersubmission_{uuid4()}"
)
assignment_user_submission.creation_date = str(datetime.now())
assignment_user_submission.update_date = str(datetime.now())
assignment_user_submission.org_id = course.org_id
# Insert Assignment User Submission in DB
db_session.add(assignment_user_submission)
db_session.commit()
# return assignment user submission read
return AssignmentUserSubmissionRead.model_validate(assignment_user_submission)
async def read_assignment_submissions(
request: Request,
assignment_uuid: str,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Find assignment
statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# Find assignments tasks for an assignment
statement = select(AssignmentUserSubmission).where(
assignment.assignment_uuid == assignment_uuid
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "read", db_session)
# return assignment tasks read
return [
AssignmentUserSubmissionRead.model_validate(assignment_user_submission)
for assignment_user_submission in db_session.exec(statement).all()
]
async def read_user_assignment_submissions(
request: Request,
assignment_uuid: str,
user_id: int,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Find assignment
statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# Find assignments tasks for an assignment
statement = select(AssignmentUserSubmission).where(
assignment.assignment_uuid == assignment_uuid,
AssignmentUserSubmission.user_id == user_id,
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "read", db_session)
# return assignment tasks read
return [
AssignmentUserSubmissionRead.model_validate(assignment_user_submission)
for assignment_user_submission in db_session.exec(statement).all()
]
async def update_assignment_submission(
request: Request,
user_id: str,
assignment_user_submission_object: AssignmentUserSubmissionCreate,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Check if assignment user submission exists
statement = select(AssignmentUserSubmission).where(
AssignmentUserSubmission.user_id == user_id
)
assignment_user_submission = db_session.exec(statement).first()
if not assignment_user_submission:
raise HTTPException(
status_code=404,
detail="Assignment User Submission not found",
)
# Check if assignment exists
statement = select(Assignment).where(
Assignment.id == assignment_user_submission.assignment_id
)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "update", db_session)
# Update only the fields that were passed in
for var, value in vars(assignment_user_submission_object).items():
if value is not None:
setattr(assignment_user_submission, var, value)
assignment_user_submission.update_date = str(datetime.now())
# Insert Assignment User Submission in DB
db_session.add(assignment_user_submission)
db_session.commit()
db_session.refresh(assignment_user_submission)
# return assignment user submission read
return AssignmentUserSubmissionRead.model_validate(assignment_user_submission)
async def delete_assignment_submission(
request: Request,
user_id: str,
assignment_id: str,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
# Check if assignment user submission exists
statement = select(AssignmentUserSubmission).where(
AssignmentUserSubmission.user_id == user_id,
AssignmentUserSubmission.assignment_id == assignment_id,
)
assignment_user_submission = db_session.exec(statement).first()
if not assignment_user_submission:
raise HTTPException(
status_code=404,
detail="Assignment User Submission not found",
)
# Check if assignment exists
statement = select(Assignment).where(
Assignment.id == assignment_user_submission.assignment_id
)
assignment = db_session.exec(statement).first()
if not assignment:
raise HTTPException(
status_code=404,
detail="Assignment not found",
)
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
if not course:
raise HTTPException(
status_code=404,
detail="Course not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "delete", db_session)
# Delete Assignment User Submission
db_session.delete(assignment_user_submission)
db_session.commit()
return {"message": "Assignment User Submission deleted"}
## 🔒 RBAC Utils ##
async def rbac_check(
request: Request,
course_uuid: str,
current_user: PublicUser | AnonymousUser,
action: Literal["create", "read", "update", "delete"],
db_session: Session,
):
if action == "read":
if current_user.id == 0: # Anonymous user
res = await authorization_verify_if_element_is_public(
request, course_uuid, action, db_session
)
return res
else:
res = (
await authorization_verify_based_on_roles_and_authorship_and_usergroups(
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_and_usergroups(
request,
current_user.id,
action,
course_uuid,
db_session,
)
## 🔒 RBAC Utils ##

View file

@ -1,20 +1,20 @@
from typing import Literal
from src.db.courses import Course
from src.db.courses.courses import Course
from src.db.organizations import Organization
from sqlmodel import Session, select
from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship_and_usergroups,
authorization_verify_if_user_is_anon,
)
from src.db.chapters import Chapter
from src.db.activities import (
from src.db.courses.chapters import Chapter
from src.db.courses.activities import (
Activity,
ActivityRead,
ActivitySubTypeEnum,
ActivityTypeEnum,
)
from src.db.chapter_activities import ChapterActivity
from src.db.course_chapters import CourseChapter
from src.db.courses.chapter_activities import ChapterActivity
from src.db.courses.course_chapters import CourseChapter
from src.db.users import AnonymousUser, PublicUser
from src.services.courses.activities.uploads.pdfs import upload_pdf
from fastapi import HTTPException, status, UploadFile, Request

View file

@ -1,5 +1,5 @@
from src.db.activities import ActivityRead
from src.db.courses import CourseRead
from src.db.courses.activities import ActivityRead
from src.db.courses.courses import CourseRead
def structure_activity_content_by_type(activity):

View file

@ -1,5 +1,5 @@
from typing import Literal
from src.db.courses import Course
from src.db.courses.courses import Course
from src.db.organizations import Organization
from pydantic import BaseModel
@ -8,15 +8,15 @@ from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship_and_usergroups,
authorization_verify_if_user_is_anon,
)
from src.db.chapters import Chapter
from src.db.activities import (
from src.db.courses.chapters import Chapter
from src.db.courses.activities import (
Activity,
ActivityRead,
ActivitySubTypeEnum,
ActivityTypeEnum,
)
from src.db.chapter_activities import ChapterActivity
from src.db.course_chapters import CourseChapter
from src.db.courses.chapter_activities import ChapterActivity
from src.db.courses.course_chapters import CourseChapter
from src.db.users import AnonymousUser, PublicUser
from src.services.courses.activities.uploads.videos import upload_video
from fastapi import HTTPException, status, UploadFile, Request

View file

@ -8,10 +8,10 @@ from src.security.rbac.rbac import (
authorization_verify_if_element_is_public,
authorization_verify_if_user_is_anon,
)
from src.db.course_chapters import CourseChapter
from src.db.activities import Activity, ActivityRead
from src.db.chapter_activities import ChapterActivity
from src.db.chapters import (
from src.db.courses.course_chapters import CourseChapter
from src.db.courses.activities import Activity, ActivityRead
from src.db.courses.chapter_activities import ChapterActivity
from src.db.courses.chapters import (
Chapter,
ChapterCreate,
ChapterRead,

View file

@ -15,7 +15,7 @@ from src.db.collections import (
CollectionUpdate,
)
from src.db.collections_courses import CollectionCourse
from src.db.courses import Course
from src.db.courses.courses import Course
from src.services.users.users import PublicUser
from fastapi import HTTPException, status, Request

View file

@ -8,7 +8,7 @@ from src.db.organizations import Organization
from src.services.trail.trail import get_user_trail_with_orgid
from src.db.resource_authors import ResourceAuthor, ResourceAuthorshipEnum
from src.db.users import PublicUser, AnonymousUser, User, UserRead
from src.db.courses import (
from src.db.courses.courses import (
Course,
CourseCreate,
CourseRead,

View file

@ -3,13 +3,13 @@ from typing import List
from uuid import uuid4
from fastapi import HTTPException, Request, status
from sqlmodel import Session, col, select
from src.db.course_updates import (
from src.db.courses.course_updates import (
CourseUpdate,
CourseUpdateCreate,
CourseUpdateRead,
CourseUpdateUpdate,
)
from src.db.courses import Course
from src.db.courses.courses import Course
from src.db.organizations import Organization
from src.db.users import AnonymousUser, PublicUser
from src.services.courses.courses import rbac_check

View file

@ -1,10 +1,10 @@
from datetime import datetime
from uuid import uuid4
from src.db.chapter_activities import ChapterActivity
from src.db.courses.chapter_activities import ChapterActivity
from fastapi import HTTPException, Request, status
from sqlmodel import Session, select
from src.db.activities import Activity
from src.db.courses import Course
from src.db.courses.activities import Activity
from src.db.courses.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