Skip to content

Commit 620c970

Browse files
authored
Merge pull request #76 from AvaCodeSolutions/feat/21/delete-course-content-api
feat: #21 delete course content API
2 parents 00eaedf + a4be104 commit 620c970

File tree

3 files changed

+103
-0
lines changed

3 files changed

+103
-0
lines changed

django_email_learning/api/urls.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
OrganizationsView,
77
SingleCourseView,
88
CourseContentView,
9+
SingleCourseContentView,
910
UpdateSessionView,
1011
)
1112

@@ -32,6 +33,11 @@
3233
CourseContentView.as_view(),
3334
name="course_content_view",
3435
),
36+
path(
37+
"organizations/<int:organization_id>/courses/<int:course_id>/contents/<int:course_content_id>/",
38+
SingleCourseContentView.as_view(),
39+
name="single_course_content_view",
40+
),
3541
path("organizations/", OrganizationsView.as_view(), name="organizations_view"),
3642
path("session", UpdateSessionView.as_view(), name="update_session_view"),
3743
path("", page_not_found, name="root"),

django_email_learning/api/views.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from django_email_learning.api import serializers
1010
from django_email_learning.models import (
1111
Course,
12+
CourseContent,
1213
ImapConnection,
1314
OrganizationUser,
1415
Organization,
@@ -98,6 +99,23 @@ def get(self, request, *args, **kwargs) -> JsonResponse: # type: ignore[no-unty
9899
return JsonResponse({"error": "Course not found"}, status=404)
99100

100101

102+
@method_decorator(accessible_for(roles={"admin", "editor"}), name="delete")
103+
class SingleCourseContentView(View):
104+
def delete(self, request, *args, **kwargs): # type: ignore[no-untyped-def]
105+
try:
106+
course_content = CourseContent.objects.get(id=kwargs["course_content_id"])
107+
course_content.delete()
108+
return JsonResponse(
109+
{"message": "Course content deleted successfully"}, status=200
110+
)
111+
except CourseContent.DoesNotExist:
112+
return JsonResponse({"error": "Course content not found"}, status=404)
113+
except ValidationError as e:
114+
return JsonResponse({"error": e.errors()}, status=400)
115+
except (IntegrityError, ValueError) as e:
116+
return JsonResponse({"error": str(e)}, status=409)
117+
118+
101119
@method_decorator(accessible_for(roles={"admin", "editor"}), name="post")
102120
@method_decorator(accessible_for(roles={"admin", "editor"}), name="delete")
103121
@method_decorator(accessible_for(roles={"admin", "editor", "viewer"}), name="get")

tests/api/test_views/test_course_content_view.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,3 +344,82 @@ def test_list_course_content_with_existing_contents(superadmin_client, create_co
344344
}
345345
assert "lesson" not in data["course_contents"][0]
346346
assert "quiz" not in data["course_contents"][1]
347+
348+
349+
def test_delete_course_content(superadmin_client, create_course):
350+
url = get_url()
351+
# Create a lesson content
352+
lesson_payload = {
353+
"content": {
354+
"title": LESSON_TITLE,
355+
"content": LESSON_CONTENT,
356+
"type": "lesson",
357+
},
358+
"priority": 1,
359+
"waiting_period": {"period": 2, "type": "days"},
360+
}
361+
response = superadmin_client.post(
362+
url, json.dumps(lesson_payload), content_type="application/json"
363+
)
364+
assert response.status_code == 201
365+
data = response.json()
366+
course_content_id = data["id"]
367+
368+
# Delete the created course content
369+
delete_url = reverse(
370+
"django_email_learning:api:single_course_content_view",
371+
kwargs={
372+
"organization_id": 1,
373+
"course_id": 1,
374+
"course_content_id": course_content_id,
375+
},
376+
)
377+
contents_response = superadmin_client.get(url)
378+
assert contents_response.status_code == 200
379+
assert len(contents_response.json()["course_contents"]) == 1
380+
381+
delete_response = superadmin_client.delete(delete_url)
382+
assert delete_response.status_code == 200
383+
384+
# Verify that the course content is deleted
385+
contents_response_after_delete = superadmin_client.get(url)
386+
assert contents_response_after_delete.status_code == 200
387+
assert len(contents_response_after_delete.json()["course_contents"]) == 0
388+
get_response = superadmin_client.delete(delete_url)
389+
assert get_response.status_code == 404
390+
391+
392+
def test_viewer_cannot_delete_course_content(viewer_client, create_course):
393+
url = get_url()
394+
# Create a lesson content
395+
lesson_payload = {
396+
"content": {
397+
"title": LESSON_TITLE,
398+
"content": LESSON_CONTENT,
399+
"type": "lesson",
400+
},
401+
"priority": 1,
402+
"waiting_period": {"period": 2, "type": "days"},
403+
}
404+
response = viewer_client.post(
405+
url, json.dumps(lesson_payload), content_type="application/json"
406+
)
407+
assert response.status_code == 403
408+
409+
410+
def test_anonymous_user_cannot_delete_course_content(anonymous_client, create_course):
411+
url = get_url()
412+
# Create a lesson content
413+
lesson_payload = {
414+
"content": {
415+
"title": LESSON_TITLE,
416+
"content": LESSON_CONTENT,
417+
"type": "lesson",
418+
},
419+
"priority": 1,
420+
"waiting_period": {"period": 2, "type": "days"},
421+
}
422+
response = anonymous_client.post(
423+
url, json.dumps(lesson_payload), content_type="application/json"
424+
)
425+
assert response.status_code == 401

0 commit comments

Comments
 (0)