Browse Source

cloned course logic added in the backend for admin panel

master
Mohsen Taba 1 month ago
parent
commit
1c145fbfb7
  1. 7
      apps/course/serializers/admin.py
  2. 154
      apps/course/views/admin.py

7
apps/course/serializers/admin.py

@ -270,6 +270,12 @@ class AdminCourseDetailSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
ret = super().to_representation(instance)
lang = get_request_lang(self)
ret['title'] = get_localized_field(lang, instance.title)
ret['slug'] = get_localized_field(lang, instance.slug)
ret['level'] = get_localized_field(lang, instance.level)
ret['status'] = get_localized_field(lang, instance.status)
ret['description'] = get_localized_field(lang, instance.description)
ret['short_description'] = get_localized_field(lang, instance.short_description)
# Inject legacy fields
first_prof = instance.professors.first()
ret['professor'] = first_prof.id if first_prof else None
@ -673,4 +679,3 @@ class AdminLiveSessionDetailSerializer(serializers.ModelSerializer):
})
return data

154
apps/course/views/admin.py

@ -1,4 +1,6 @@
import logging
import re
from copy import deepcopy
from django.db import transaction
from django.db.models import Count, Q
@ -27,6 +29,8 @@ from apps.course.models import (
LiveSessionUser,
LiveSessionRecording
)
from apps.course.models.course import extract_text_from_json
from apps.quiz.models import Quiz, Question
from apps.course.serializers.admin import (
AdminCourseCategorySerializer,
AdminCourseListSerializer,
@ -134,6 +138,156 @@ class AdminCourseViewSet(viewsets.ModelViewSet):
else:
serializer.save()
def _build_cloned_title(self, source_course, requested_title=None):
custom_title = str(requested_title or "").strip()
if custom_title:
return [{"language_code": "en", "title": custom_title}]
source_titles = deepcopy(source_course.title or [])
source_title_text = extract_text_from_json(source_titles).strip() or f"Course {source_course.pk}"
base_title = re.sub(r"\s*\(copied(?:#\d+)?\)$", "", source_title_text).strip() or source_title_text
suffix = "(copied)"
if isinstance(source_titles, list) and source_titles:
localized_titles = []
for item in source_titles:
if isinstance(item, dict):
localized_item = deepcopy(item)
for key in ("title", "text", "value", "name"):
if key in localized_item and localized_item.get(key):
cleaned_value = re.sub(r"\s*\(copied(?:#\d+)?\)$", "", str(localized_item[key])).strip()
localized_item[key] = f"{cleaned_value}{suffix}"
break
else:
localized_item["title"] = f"{base_title}{suffix}"
localized_titles.append(localized_item)
elif item:
cleaned_item = re.sub(r"\s*\(copied(?:#\d+)?\)$", "", str(item)).strip()
localized_titles.append(f"{cleaned_item}{suffix}")
if localized_titles:
return localized_titles
return [{"language_code": "en", "title": f"{base_title}{suffix}"}]
@action(detail=True, methods=['post'])
def clone(self, request, pk=None):
source_course = self.get_object()
requested_title = request.data.get('title')
with transaction.atomic():
cloned_course = Course.objects.create(
title=self._build_cloned_title(source_course, requested_title),
category=source_course.category,
thumbnail=source_course.thumbnail.name if source_course.thumbnail else None,
video_type=source_course.video_type,
video_file=source_course.video_file.name if source_course.video_file else None,
video_link=source_course.video_link,
is_online=source_course.is_online,
online_link=source_course.online_link,
level=deepcopy(source_course.level),
duration=source_course.duration,
lessons_count=source_course.lessons_count,
description=deepcopy(source_course.description),
short_description=deepcopy(source_course.short_description),
status=deepcopy(source_course.status),
is_free=source_course.is_free,
price=source_course.price,
price_rub=source_course.price_rub,
discount_percentage=source_course.discount_percentage,
is_group_chat_locked=source_course.is_group_chat_locked,
is_professor_chat_locked=source_course.is_professor_chat_locked,
timing=deepcopy(source_course.timing),
features=deepcopy(source_course.features),
)
cloned_course.professors.set(source_course.professors.all())
chapter_map = {}
source_chapters = source_course.chapters.all().order_by('priority', 'id')
for chapter in source_chapters:
cloned_chapter = CourseChapter.objects.create(
course=cloned_course,
title=deepcopy(chapter.title),
priority=chapter.priority,
is_active=chapter.is_active,
)
chapter_map[chapter.id] = cloned_chapter
lesson_map = {}
source_lessons = source_course.lessons.select_related('lesson', 'chapter').all().order_by('priority', 'id')
for course_lesson in source_lessons:
base_lesson = course_lesson.lesson
cloned_lesson = Lesson.objects.create(
title=deepcopy(base_lesson.title),
content_type=deepcopy(base_lesson.content_type),
content_file=base_lesson.content_file.name if base_lesson and base_lesson.content_file else None,
video_link=base_lesson.video_link if base_lesson else None,
duration=base_lesson.duration if base_lesson else 0,
)
cloned_course_lesson = CourseLesson.objects.create(
course=cloned_course,
chapter=chapter_map.get(course_lesson.chapter_id),
lesson=cloned_lesson,
title=deepcopy(course_lesson.title),
priority=course_lesson.priority,
is_active=course_lesson.is_active,
)
lesson_map[course_lesson.id] = cloned_course_lesson
source_attachments = source_course.attachments.select_related('attachment').all()
for course_attachment in source_attachments:
base_attachment = course_attachment.attachment
cloned_attachment = Attachment.objects.create(
title=deepcopy(base_attachment.title),
file=base_attachment.file.name if base_attachment and base_attachment.file else None,
file_size=base_attachment.file_size if base_attachment else None,
)
CourseAttachment.objects.create(
course=cloned_course,
attachment=cloned_attachment,
)
source_glossaries = source_course.glossaries.select_related('glossary').all()
for course_glossary in source_glossaries:
base_glossary = course_glossary.glossary
cloned_glossary = Glossary.objects.create(
title=base_glossary.title,
description=deepcopy(base_glossary.description),
)
CourseGlossary.objects.create(
course=cloned_course,
glossary=cloned_glossary,
)
source_quizzes = source_course.quizzes.prefetch_related('questions').all()
for quiz in source_quizzes:
cloned_quiz = Quiz.objects.create(
lesson=lesson_map.get(quiz.lesson_id),
course=cloned_course,
lesson_number=quiz.lesson_number,
title=deepcopy(quiz.title),
description=deepcopy(quiz.description),
each_question_timing=quiz.each_question_timing,
status=quiz.status,
)
for question in quiz.questions.all():
Question.objects.create(
quiz=cloned_quiz,
question=deepcopy(question.question),
option1=deepcopy(question.option1),
option2=deepcopy(question.option2),
option3=deepcopy(question.option3),
option4=deepcopy(question.option4),
correct_answer=question.correct_answer,
priority=question.priority,
)
cloned_course.recalculate_lessons_count()
cloned_course.refresh_from_db()
serializer = self.get_serializer(cloned_course)
return Response(serializer.data, status=201)
class AdminChapterViewSet(viewsets.ModelViewSet):
"""

Loading…
Cancel
Save