diff --git a/apps/api/src/db/courses/assignments.py b/apps/api/src/db/courses/assignments.py
index dc7722a5..a2884114 100644
--- a/apps/api/src/db/courses/assignments.py
+++ b/apps/api/src/db/courses/assignments.py
@@ -4,7 +4,6 @@ from sqlmodel import Field, SQLModel
from enum import Enum
-
## Assignment ##
class GradingTypeEnum(str, Enum):
ALPHABET = "ALPHABET"
@@ -87,7 +86,7 @@ class Assignment(AssignmentBase, table=True):
class AssignmentTaskTypeEnum(str, Enum):
FILE_SUBMISSION = "FILE_SUBMISSION"
QUIZ = "QUIZ"
- FORM = "FORM" # soon to be implemented
+ FORM = "FORM" # soon to be implemented
OTHER = "OTHER"
@@ -102,8 +101,6 @@ class AssignmentTaskBase(SQLModel):
contents: Dict = Field(default={}, sa_column=Column(JSON))
max_grade_value: int = 0 # Value is always between 0-100
-
-
class AssignmentTaskCreate(AssignmentTaskBase):
"""Model for creating a new assignment task."""
@@ -194,6 +191,7 @@ class AssignmentTaskSubmissionRead(AssignmentTaskSubmissionBase):
class AssignmentTaskSubmissionUpdate(SQLModel):
"""Model for updating an assignment task submission."""
+
assignment_task_id: Optional[int]
assignment_task_submission_uuid: Optional[str]
task_submission: Optional[Dict] = Field(default=None, sa_column=Column(JSON))
@@ -233,10 +231,12 @@ class AssignmentTaskSubmission(AssignmentTaskSubmissionBase, table=True):
creation_date: str
update_date: str
+
## AssignmentTaskSubmission ##
## AssignmentUserSubmission ##
+
class AssignmentUserSubmissionStatus(str, Enum):
PENDING = "PENDING"
SUBMITTED = "SUBMITTED"
@@ -248,11 +248,10 @@ class AssignmentUserSubmissionStatus(str, Enum):
class AssignmentUserSubmissionBase(SQLModel):
"""Represents the submission status of an assignment for a user."""
-
submission_status: AssignmentUserSubmissionStatus = (
AssignmentUserSubmissionStatus.PENDING
)
- grade: str
+ grade: int
user_id: int = Field(
sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
)
@@ -262,11 +261,14 @@ class AssignmentUserSubmissionBase(SQLModel):
)
)
-class AssignmentUserSubmissionCreate(AssignmentUserSubmissionBase):
+
+class AssignmentUserSubmissionCreate(SQLModel):
"""Model for creating a new assignment user submission."""
+ assignment_id: int
pass # Inherits all fields from AssignmentUserSubmissionBase
+
class AssignmentUserSubmissionRead(AssignmentUserSubmissionBase):
"""Model for reading an assignment user submission."""
@@ -274,6 +276,7 @@ class AssignmentUserSubmissionRead(AssignmentUserSubmissionBase):
creation_date: str
update_date: str
+
class AssignmentUserSubmissionUpdate(SQLModel):
"""Model for updating an assignment user submission."""
@@ -282,17 +285,19 @@ class AssignmentUserSubmissionUpdate(SQLModel):
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
+ assignmentusersubmission_uuid: str
submission_status: AssignmentUserSubmissionStatus = (
AssignmentUserSubmissionStatus.PENDING
)
- grade: str
+ grade: int
user_id: int = Field(
sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
)
@@ -301,4 +306,3 @@ class AssignmentUserSubmission(AssignmentUserSubmissionBase, table=True):
"assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
)
)
-
diff --git a/apps/api/src/routers/courses/assignments.py b/apps/api/src/routers/courses/assignments.py
index 3365ca94..8211b776 100644
--- a/apps/api/src/routers/courses/assignments.py
+++ b/apps/api/src/routers/courses/assignments.py
@@ -31,6 +31,7 @@ from src.services.courses.activities.assignments import (
read_assignment_task_submissions,
read_assignment_tasks,
read_user_assignment_submissions,
+ read_user_assignment_submissions_me,
read_user_assignment_task_submissions,
read_user_assignment_task_submissions_me,
update_assignment,
@@ -208,6 +209,7 @@ async def api_put_assignment_task_ref_file(
request, db_session, assignment_task_uuid, current_user, reference_file
)
+
@router.post("/{assignment_uuid}/tasks/{assignment_task_uuid}/sub_file")
async def api_put_assignment_task_sub_file(
request: Request,
@@ -277,6 +279,7 @@ async def api_read_user_assignment_task_submissions(
request, assignment_task_uuid, user_id, current_user, db_session
)
+
@router.get("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions/user/me")
async def api_read_user_assignment_task_submissions_me(
request: Request,
@@ -331,7 +334,6 @@ async def api_delete_assignment_task_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),
):
@@ -339,7 +341,7 @@ async def api_create_assignment_submissions(
Create new submissions for an assignment
"""
return await create_assignment_submission(
- request, assignment_uuid, assignment_submission, current_user, db_session
+ request, assignment_uuid, current_user, db_session
)
@@ -358,6 +360,21 @@ async def api_read_assignment_submissions(
)
+@router.get("/{assignment_uuid}/submissions/me")
+async def api_read_user_assignment_submission_me(
+ request: Request,
+ assignment_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Read submissions for an assignment from the current user
+ """
+ return await read_user_assignment_submissions_me(
+ request, assignment_uuid, current_user, db_session
+ )
+
+
@router.get("/{assignment_uuid}/submissions/{user_id}")
async def api_read_user_assignment_submissions(
request: Request,
diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py
index c29e84f3..447ec12b 100644
--- a/apps/api/src/services/courses/activities/assignments.py
+++ b/apps/api/src/services/courses/activities/assignments.py
@@ -7,6 +7,7 @@ from typing import Literal
from uuid import uuid4
from fastapi import HTTPException, Request, UploadFile
from sqlmodel import Session, select
+from sympy import Sum
from src.db.courses.activities import Activity
from src.db.courses.assignments import (
@@ -25,6 +26,7 @@ from src.db.courses.assignments import (
AssignmentUserSubmission,
AssignmentUserSubmissionCreate,
AssignmentUserSubmissionRead,
+ AssignmentUserSubmissionStatus,
)
from src.db.courses.courses import Course
from src.db.organizations import Organization
@@ -1028,7 +1030,6 @@ async def delete_assignment_task_submission(
async def create_assignment_submission(
request: Request,
assignment_uuid: str,
- assignment_user_submission_object: AssignmentUserSubmissionCreate,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
@@ -1045,7 +1046,7 @@ async def create_assignment_submission(
# 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,
+ AssignmentUserSubmission.user_id == current_user.id,
)
assignment_user_submission = db_session.exec(statement).first()
@@ -1066,21 +1067,33 @@ async def create_assignment_submission(
detail="Course not found",
)
+ # Check if User already submitted the assignment
+ statement = select(AssignmentUserSubmission).where(
+ AssignmentUserSubmission.assignment_id == assignment.id,
+ AssignmentUserSubmission.user_id == current_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",
+ )
+
# 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()
+ user_id=current_user.id,
+ assignment_id=assignment.id, # type: ignore
+ grade=0,
+ assignmentusersubmission_uuid=str(f"assignmentusersubmission_{uuid4()}"),
+ submission_status=AssignmentUserSubmissionStatus.PENDING,
+ creation_date=str(datetime.now()),
+ update_date=str(datetime.now()),
)
- 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()
@@ -1173,6 +1186,21 @@ async def read_user_assignment_submissions(
]
+async def read_user_assignment_submissions_me(
+ request: Request,
+ assignment_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ return await read_user_assignment_submissions(
+ request,
+ assignment_uuid,
+ current_user.id,
+ current_user,
+ db_session,
+ )
+
+
async def update_assignment_submission(
request: Request,
user_id: str,
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
index d579d760..fe12ea9d 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
@@ -1,9 +1,9 @@
'use client'
import Link from 'next/link'
-import { getUriWithOrg } from '@services/config/config'
+import { getAPIUrl, getUriWithOrg } from '@services/config/config'
import Canva from '@components/Objects/Activities/DynamicCanva/DynamicCanva'
import VideoActivity from '@components/Objects/Activities/Video/Video'
-import { Check, MoreVertical } from 'lucide-react'
+import { BookOpenCheck, Check, MoreVertical, UserRoundPen } from 'lucide-react'
import { markActivityAsComplete } from '@services/courses/activity'
import DocumentPdfActivity from '@components/Objects/Activities/DocumentPdf/DocumentPdf'
import ActivityIndicators from '@components/Pages/Courses/ActivityIndicators'
@@ -17,10 +17,14 @@ import AIActivityAsk from '@components/Objects/Activities/AI/AIActivityAsk'
import AIChatBotProvider from '@components/Contexts/AI/AIChatBotContext'
import { useLHSession } from '@components/Contexts/LHSessionContext'
import React, { useEffect } from 'react'
-import { getAssignmentFromActivityUUID } from '@services/courses/assignments'
+import { getAssignmentFromActivityUUID, submitAssignmentForGrading } from '@services/courses/assignments'
import AssignmentStudentActivity from '@components/Objects/Activities/Assignment/AssignmentStudentActivity'
import { AssignmentProvider } from '@components/Contexts/Assignments/AssignmentContext'
import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext'
+import AssignmentSubmissionProvider, { AssignmentSubmissionContext, useAssignmentSubmission } from '@components/Contexts/Assignments/AssignmentSubmissionContext'
+import toast from 'react-hot-toast'
+import { mutate } from 'swr'
+import ConfirmationModal from '@components/StyledElements/ConfirmationModal/ConfirmationModal'
interface ActivityClientProps {
activityid: string
@@ -135,6 +139,21 @@ function ActivityClient(props: ActivityClientProps) {
/>
>
}
+ {activity.activity_type == 'TYPE_ASSIGNMENT' &&
+ <>
+
+
Don't forget to save your progress