Skip to content

Commit ae912ad

Browse files
committed
feat: implement soft delete functionality for courses and associated archives, ensuring only active courses are queried
1 parent 9634de8 commit ae912ad

3 files changed

Lines changed: 37 additions & 11 deletions

File tree

backend/app/api/services/archives.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ async def upload_archive(
4747

4848
query = select(Course).where(
4949
Course.name == subject,
50-
Course.category == category
50+
Course.category == category,
51+
Course.deleted_at.is_(None)
5152
)
5253
result = await db.execute(query)
5354
course = result.scalar_one_or_none()

backend/app/api/services/courses.py

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ async def get_categorized_courses(
2222
Get all courses grouped by category.
2323
Returns courses with their IDs grouped by category.
2424
"""
25-
query = select(Course)
25+
query = select(Course).where(Course.deleted_at.is_(None))
2626
result = await db.execute(query)
2727
courses = result.scalars().all()
2828

@@ -42,7 +42,10 @@ async def get_course_archives(
4242
"""
4343
Get all archives for a specific course.
4444
"""
45-
course_query = select(Course).where(Course.id == course_id)
45+
course_query = select(Course).where(
46+
Course.id == course_id,
47+
Course.deleted_at.is_(None)
48+
)
4649
result = await db.execute(course_query)
4750
course = result.scalar_one_or_none()
4851

@@ -194,7 +197,10 @@ async def update_archive_course(
194197
)
195198

196199
# Transfer to existing course by ID
197-
new_course_query = select(Course).where(Course.id == course_update.course_id)
200+
new_course_query = select(Course).where(
201+
Course.id == course_update.course_id,
202+
Course.deleted_at.is_(None)
203+
)
198204
new_course_result = await db.execute(new_course_query)
199205
new_course = new_course_result.scalar_one_or_none()
200206

@@ -207,7 +213,8 @@ async def update_archive_course(
207213
# Transfer to course by name and category, create if not exists
208214
new_course_query = select(Course).where(
209215
Course.name == course_update.course_name,
210-
Course.category == course_update.course_category
216+
Course.category == course_update.course_category,
217+
Course.deleted_at.is_(None)
211218
)
212219
new_course_result = await db.execute(new_course_query)
213220
new_course = new_course_result.scalar_one_or_none()
@@ -302,7 +309,8 @@ async def create_course(
302309

303310
query = select(Course).where(
304311
Course.name == course_data.name,
305-
Course.category == course_data.category
312+
Course.category == course_data.category,
313+
Course.deleted_at.is_(None)
306314
)
307315
result = await db.execute(query)
308316
existing_course = result.scalar_one_or_none()
@@ -340,7 +348,10 @@ async def update_course(
340348
detail="Only admins can update courses"
341349
)
342350

343-
query = select(Course).where(Course.id == course_id)
351+
query = select(Course).where(
352+
Course.id == course_id,
353+
Course.deleted_at.is_(None)
354+
)
344355
result = await db.execute(query)
345356
course = result.scalar_one_or_none()
346357

@@ -358,7 +369,8 @@ async def update_course(
358369
check_query = select(Course).where(
359370
Course.name == new_name,
360371
Course.category == new_category,
361-
Course.id != course_id
372+
Course.id != course_id,
373+
Course.deleted_at.is_(None)
362374
)
363375
check_result = await db.execute(check_query)
364376
existing_course = check_result.scalar_one_or_none()
@@ -394,7 +406,10 @@ async def delete_course(
394406
detail="Only admins can delete courses"
395407
)
396408

397-
query = select(Course).where(Course.id == course_id)
409+
query = select(Course).where(
410+
Course.id == course_id,
411+
Course.deleted_at.is_(None)
412+
)
398413
result = await db.execute(query)
399414
course = result.scalar_one_or_none()
400415

@@ -411,10 +426,14 @@ async def delete_course(
411426
archives_result = await db.execute(archives_query)
412427
archives = archives_result.scalars().all()
413428

429+
# Soft delete all associated archives and the course
414430
current_time = datetime.now(timezone.utc)
415431
for archive in archives:
416432
archive.deleted_at = current_time
417-
await db.delete(course)
433+
434+
# Soft delete the course
435+
course.deleted_at = current_time
436+
418437
await db.commit()
419438

420439
return {"message": f"Course '{course.name}' and {len(archives)} associated archives deleted successfully"}
@@ -433,7 +452,7 @@ async def list_all_courses(
433452
detail="Only admins can access all courses"
434453
)
435454

436-
query = select(Course).order_by(Course.category, Course.name)
455+
query = select(Course).where(Course.deleted_at.is_(None)).order_by(Course.category, Course.name)
437456
result = await db.execute(query)
438457
courses = result.scalars().all()
439458

backend/app/models/models.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ class Course(SQLModel, table=True):
5353
id: Optional[int] = Field(default=None, primary_key=True)
5454
name: str = Field(index=True)
5555
category: CourseCategory
56+
deleted_at: Optional[datetime] = Field(
57+
sa_column=Column(
58+
DateTime(timezone=True),
59+
nullable=True
60+
)
61+
)
5662

5763
archives: List["Archive"] = Relationship(back_populates="course")
5864

0 commit comments

Comments
 (0)