feat: edit tasks and general improvements

This commit is contained in:
swve 2024-07-14 14:06:25 +02:00
parent acfcea026b
commit 3c41e0ee73
13 changed files with 570 additions and 93 deletions

View file

@ -127,11 +127,6 @@ class AssignmentTaskUpdate(SQLModel):
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):

View file

@ -1,4 +1,4 @@
from fastapi import APIRouter, Depends, Request
from fastapi import APIRouter, Depends, Request, UploadFile
from src.db.courses.assignments import (
AssignmentCreate,
AssignmentRead,
@ -21,6 +21,7 @@ from src.services.courses.activities.assignments import (
delete_assignment_submission,
delete_assignment_task,
delete_assignment_task_submission,
put_assignment_task_reference_file,
read_assignment,
read_assignment_from_activity_uuid,
read_assignment_submissions,
@ -64,6 +65,7 @@ async def api_read_assignment(
"""
return await read_assignment(request, assignment_uuid, current_user, db_session)
@router.get("/activity/{activity_uuid}")
async def api_read_assignment_from_activity(
request: Request,
@ -74,7 +76,9 @@ async def api_read_assignment_from_activity(
"""
Read an assignment
"""
return await read_assignment_from_activity_uuid(request, activity_uuid, current_user, db_session)
return await read_assignment_from_activity_uuid(
request, activity_uuid, current_user, db_session
)
@router.put("/{assignment_uuid}")
@ -105,6 +109,7 @@ async def api_delete_assignment(
"""
return await delete_assignment(request, assignment_uuid, current_user, db_session)
@router.delete("/activity/{activity_uuid}")
async def api_delete_assignment_from_activity(
request: Request,
@ -115,7 +120,9 @@ async def api_delete_assignment_from_activity(
"""
Delete an assignment
"""
return await delete_assignment_from_activity_uuid(request, activity_uuid, current_user, db_session)
return await delete_assignment_from_activity_uuid(
request, activity_uuid, current_user, db_session
)
## ASSIGNMENTS Tasks ##
@ -166,7 +173,8 @@ async def api_read_assignment_task(
request, assignment_task_uuid, current_user, db_session
)
@router.put("/{assignment_uuid}/tasks/{task_uuid}")
@router.put("/{assignment_uuid}/tasks/{assignment_task_uuid}")
async def api_update_assignment_tasks(
request: Request,
assignment_task_uuid: str,
@ -182,6 +190,22 @@ async def api_update_assignment_tasks(
)
@router.post("/{assignment_uuid}/tasks/{assignment_task_uuid}/ref_file")
async def api_put_assignment_task_ref_file(
request: Request,
assignment_task_uuid: str,
reference_file: UploadFile | None = None,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
"""
Update tasks for an assignment
"""
return await put_assignment_task_reference_file(
request, db_session, assignment_task_uuid, current_user, reference_file
)
@router.delete("/{assignment_uuid}/tasks/{task_uuid}")
async def api_delete_assignment_tasks(
request: Request,

View file

@ -5,7 +5,7 @@
from datetime import datetime
from typing import Literal
from uuid import uuid4
from fastapi import HTTPException, Request
from fastapi import HTTPException, Request, UploadFile
from sqlmodel import Session, select
from src.db.courses.activities import Activity
@ -26,12 +26,16 @@ from src.db.courses.assignments import (
AssignmentUserSubmissionRead,
)
from src.db.courses.courses import Course
from src.db.organizations import Organization
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,
)
from src.services.courses.activities.uploads.tasks_ref_files import (
upload_reference_file,
)
## > Assignments CRUD
@ -104,6 +108,7 @@ async def read_assignment(
# return assignment read
return AssignmentRead.model_validate(assignment)
async def read_assignment_from_activity_uuid(
request: Request,
activity_uuid: str,
@ -119,7 +124,7 @@ async def read_assignment_from_activity_uuid(
status_code=404,
detail="Activity not found",
)
# Check if course exists
statement = select(Course).where(Course.id == activity.course_id)
course = db_session.exec(statement).first()
@ -129,7 +134,7 @@ async def read_assignment_from_activity_uuid(
status_code=404,
detail="Course not found",
)
# Check if assignment exists
statement = select(Assignment).where(Assignment.activity_id == activity.id)
assignment = db_session.exec(statement).first()
@ -227,6 +232,7 @@ async def delete_assignment(
return {"message": "Assignment deleted"}
async def delete_assignment_from_activity_uuid(
request: Request,
activity_uuid: str,
@ -243,7 +249,7 @@ async def delete_assignment_from_activity_uuid(
status_code=404,
detail="Activity not found",
)
# Check if course exists
statement = select(Course).where(Course.id == activity.course_id)
course = db_session.exec(statement).first()
@ -253,7 +259,7 @@ async def delete_assignment_from_activity_uuid(
status_code=404,
detail="Course not found",
)
# Check if assignment exists
statement = select(Assignment).where(Assignment.activity_id == activity.id)
assignment = db_session.exec(statement).first()
@ -263,7 +269,7 @@ async def delete_assignment_from_activity_uuid(
status_code=404,
detail="Assignment not found",
)
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "delete", db_session)
@ -317,7 +323,7 @@ async def create_assignment_task(
assignment_task.org_id = course.org_id
assignment_task.chapter_id = assignment.chapter_id
assignment_task.activity_id = assignment.activity_id
assignment_task.assignment_id = assignment.id # type: ignore
assignment_task.assignment_id = assignment.id # type: ignore
assignment_task.course_id = assignment.course_id
# Insert Assignment Task in DB
@ -369,6 +375,7 @@ async def read_assignment_tasks(
for assignment_task in db_session.exec(statement).all()
]
async def read_assignment_task(
request: Request,
assignment_task_uuid: str,
@ -376,7 +383,9 @@ async def read_assignment_task(
db_session: Session,
):
# Find assignment
statement = select(AssignmentTask).where(AssignmentTask.assignment_task_uuid == assignment_task_uuid)
statement = select(AssignmentTask).where(
AssignmentTask.assignment_task_uuid == assignment_task_uuid
)
assignmenttask = db_session.exec(statement).first()
if not assignmenttask:
@ -384,7 +393,7 @@ async def read_assignment_task(
status_code=404,
detail="Assignment Task not found",
)
# Check if assignment exists
statement = select(Assignment).where(Assignment.id == assignmenttask.assignment_id)
assignment = db_session.exec(statement).first()
@ -394,7 +403,57 @@ async def read_assignment_task(
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 read
return AssignmentTaskRead.model_validate(assignmenttask)
async def put_assignment_task_reference_file(
request: Request,
db_session: Session,
assignment_task_uuid: str,
current_user: PublicUser | AnonymousUser,
reference_file: UploadFile | None = None,
):
# 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 for activity
statement = select(Activity).where(Activity.id == assignment.activity_id)
activity = db_session.exec(statement).first()
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
@ -405,11 +464,34 @@ async def read_assignment_task(
detail="Course not found",
)
# Get org uuid
org_statement = select(Organization).where(Organization.id == course.org_id)
org = db_session.exec(org_statement).first()
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "read", db_session)
await rbac_check(request, course.course_uuid, current_user, "update", db_session)
# Upload reference file
if reference_file and reference_file.filename and activity and org:
name_in_disk = (
f"{assignment_task_uuid}{uuid4()}.{reference_file.filename.split('.')[-1]}"
)
await upload_reference_file(
reference_file, name_in_disk, activity.activity_uuid, org.org_uuid, course.course_uuid, assignment.assignment_uuid, assignment_task_uuid
)
course.thumbnail_image = name_in_disk
# Update reference file
assignment_task.reference_file = name_in_disk
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(assignmenttask)
return AssignmentTaskRead.model_validate(assignment_task)
async def update_assignment_task(

View file

@ -0,0 +1,24 @@
from uuid import uuid4
from src.services.utils.upload_content import upload_content
async def upload_reference_file(
file,
name_in_disk,
activity_uuid,
org_uuid,
course_uuid,
assignment_uuid,
assignment_task_uuid,
):
contents = file.file.read()
file_format = file.filename.split(".")[-1]
await upload_content(
f"courses/{course_uuid}/activities/{activity_uuid}/assignments/{assignment_uuid}/tasks/{assignment_task_uuid}",
"orgs",
org_uuid,
contents,
f"{name_in_disk}",
["pdf", "docx", "mp4", "jpg", "jpeg", "png", "pptx"],
)

View file

@ -1,24 +1,37 @@
from typing import Literal
from typing import Literal, Optional
import boto3
from botocore.exceptions import ClientError
import os
from fastapi import HTTPException
from config.config import get_learnhouse_config
async def upload_content(
directory: str,
type_of_dir: Literal["orgs", "users"],
uuid: str, # org_uuid or user_uuid
uuid: str, # org_uuid or user_uuid
file_binary: bytes,
file_and_format: str,
allowed_formats: Optional[list[str]] = None,
):
# Get Learnhouse Config
learnhouse_config = get_learnhouse_config()
file_format = file_and_format.split(".")[-1].strip().lower()
# Get content delivery method
content_delivery = learnhouse_config.hosting_config.content_delivery.type
# Check if format file is allowed
if allowed_formats:
if file_format not in allowed_formats:
raise HTTPException(
status_code=400,
detail=f"File format {file_format} not allowed",
)
if content_delivery == "filesystem":
# create folder for activity
if not os.path.exists(f"content/{type_of_dir}/{uuid}/{directory}"):