11 changed files with 430 additions and 13 deletions
-
8apps/lms/admin.py
-
1apps/lms/management/__init__.py
-
1apps/lms/management/commands/__init__.py
-
271apps/lms/management/commands/seed_online_courses.py
-
28apps/lms/migrations/0002_course_adobe_connect_url_course_course_type_and_more.py
-
3apps/lms/models/__init__.py
-
24apps/lms/models/course.py
-
32apps/lms/serializers/course_serializers.py
-
59apps/lms/tests/test_phase8_lms.py
-
8apps/lms/views/course_views.py
-
8apps/profiles/management/commands/seed_almadinah_rich_data.py
@ -0,0 +1 @@ |
|||||
|
# LMS management package |
||||
@ -0,0 +1 @@ |
|||||
|
# LMS management commands |
||||
@ -0,0 +1,271 @@ |
|||||
|
from django.core.management.base import BaseCommand |
||||
|
from django.contrib.auth import get_user_model |
||||
|
from apps.profiles.models import Institution |
||||
|
from apps.lms.models import ( |
||||
|
Course, |
||||
|
CourseType, |
||||
|
CourseCategory, |
||||
|
CourseLevel, |
||||
|
CourseLanguage, |
||||
|
CourseModule, |
||||
|
Lesson, |
||||
|
QuizQuestion, |
||||
|
) |
||||
|
|
||||
|
User = get_user_model() |
||||
|
|
||||
|
|
||||
|
class Command(BaseCommand): |
||||
|
help = "Seeds initial sample online and hybrid courses with Adobe Connect links and live schedules." |
||||
|
|
||||
|
def handle(self, *args, **options): |
||||
|
self.stdout.write(self.style.NOTICE("Seeding sample online courses...")) |
||||
|
|
||||
|
admin_user = User.objects.filter(is_staff=True).first() or User.objects.first() |
||||
|
institution = Institution.objects.first() |
||||
|
|
||||
|
sample_courses = [ |
||||
|
{ |
||||
|
"title": "Interactive Workshop: International Cultural Diplomacy & Interfaith Dialogue", |
||||
|
"slug": "online-cultural-diplomacy-interfaith", |
||||
|
"course_type": CourseType.ONLINE, |
||||
|
"adobe_connect_url": "https://live.astan.ir/cultural-diplomacy", |
||||
|
"live_schedule": "Sundays & Tuesdays at 17:00 UTC", |
||||
|
"category": CourseCategory.CULTURAL_DIPLOMACY, |
||||
|
"language": CourseLanguage.EN, |
||||
|
"level": CourseLevel.INTERMEDIATE, |
||||
|
"instructor_name": "Dr. Mohammad Javad Karimi", |
||||
|
"instructor_title": "Senior Fellow at Razavi Islamic Studies Institute", |
||||
|
"organization_name": "Razavi International Academy", |
||||
|
"description": ( |
||||
|
"A high-impact live online workshop series exploring strategic communication, " |
||||
|
"interfaith dialogue methodologies, and cultural diplomacy across global institutions. " |
||||
|
"All sessions are hosted in real-time via Adobe Connect virtual classroom with interactive Q&A." |
||||
|
), |
||||
|
"duration_hours": 16.0, |
||||
|
"rating": 4.95, |
||||
|
"reviews_count": 38, |
||||
|
"is_published": True, |
||||
|
"is_featured": True, |
||||
|
"modules": [ |
||||
|
{ |
||||
|
"title": "Module 1: Foundations of Cultural Diplomacy", |
||||
|
"order": 1, |
||||
|
"lessons": [ |
||||
|
{ |
||||
|
"title": "Live Orientation & Syllabus Walkthrough", |
||||
|
"lesson_type": Lesson.LessonType.READING, |
||||
|
"duration_minutes": 30, |
||||
|
"content": ( |
||||
|
"# Live Course Welcome & Guidelines\n\n" |
||||
|
"Welcome to the **International Cultural Diplomacy** live series.\n\n" |
||||
|
"### How to Join the Live Classroom\n" |
||||
|
"- The live sessions take place every **Sunday and Tuesday at 17:00 UTC**.\n" |
||||
|
"- Please ensure your Adobe Connect client is updated.\n" |
||||
|
"- Interactive microphones and webcam access will be enabled during designated Q&A segments." |
||||
|
), |
||||
|
"is_preview": True, |
||||
|
"order": 1, |
||||
|
}, |
||||
|
{ |
||||
|
"title": "Session 1 Live Stream Recording & Summary", |
||||
|
"lesson_type": Lesson.LessonType.VIDEO, |
||||
|
"video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", |
||||
|
"duration_minutes": 60, |
||||
|
"content": "Archived lecture notes and summary discussion points from the first live lecture.", |
||||
|
"is_preview": False, |
||||
|
"order": 2, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
"title": "Module 2: Practical Interfaith Case Studies", |
||||
|
"order": 2, |
||||
|
"lessons": [ |
||||
|
{ |
||||
|
"title": "Live Workshop: Interfaith Crisis Management", |
||||
|
"lesson_type": Lesson.LessonType.ASSIGNMENT, |
||||
|
"duration_minutes": 90, |
||||
|
"content": "Collaborative case study solving during the live Adobe Connect breakout rooms.", |
||||
|
"is_preview": False, |
||||
|
"order": 1, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
"title": "سیره و سبک زندگی رضوی در جامعه معاصر (دوره برخط زنده)", |
||||
|
"slug": "online-razavi-lifestyle-modern-society", |
||||
|
"course_type": CourseType.ONLINE, |
||||
|
"adobe_connect_url": "https://live.astan.ir/razavi-ethics", |
||||
|
"live_schedule": "پنجشنبهها ساعت ۱۸:۳۰ به وقت تهران", |
||||
|
"category": CourseCategory.RAZAVI_TEACHINGS, |
||||
|
"language": CourseLanguage.FA, |
||||
|
"level": CourseLevel.INTRODUCTORY, |
||||
|
"instructor_name": "استاد سید علیرضا حسینی", |
||||
|
"instructor_title": "مدرس حوزه و پژوهشگر سیره و معارف اهلبیت (ع)", |
||||
|
"organization_name": "مرکز ارتباطات بینالملل آستان قدس رضوی", |
||||
|
"description": ( |
||||
|
"دوره تعاملی و برخط پیرامون آموزههای کاربردی امام رضا (ع) در مدیریت خانواده، اخلاق حرفهای، " |
||||
|
"و مسئولیت اجتماعی در بستر کلاس مجازی ادوبی کانکت با پاسخگویی زنده به پرسشهای دانشجویان." |
||||
|
), |
||||
|
"duration_hours": 10.0, |
||||
|
"rating": 5.0, |
||||
|
"reviews_count": 64, |
||||
|
"is_published": True, |
||||
|
"is_featured": True, |
||||
|
"modules": [ |
||||
|
{ |
||||
|
"title": "فصل اول: مبانی اخلاق گفتوگو و مدارا در سیره امام رضا (ع)", |
||||
|
"order": 1, |
||||
|
"lessons": [ |
||||
|
{ |
||||
|
"title": "راهنمای ورود به کلاس مجازی ادوبی کانکت و تقویم جلسات", |
||||
|
"lesson_type": Lesson.LessonType.READING, |
||||
|
"duration_minutes": 20, |
||||
|
"content": ( |
||||
|
"# راهنمای شرکت در جلسات برخط\n\n" |
||||
|
"دانشپژوهان گرامی، کلاسهای زنده هفتگی از طریق لینک ادوبی کانکت اختصاصی دوره برگزار میگردد.\n" |
||||
|
"جهت شرکت در مباحث، پس از ورود به سامانه ادوبی، با نام کامل خود وارد اتاق جلسه شوید." |
||||
|
), |
||||
|
"is_preview": True, |
||||
|
"order": 1, |
||||
|
}, |
||||
|
{ |
||||
|
"title": "جلسه زنده اول: مناظرات رضوی و درسهای آن برای دنیای امروز", |
||||
|
"lesson_type": Lesson.LessonType.READING, |
||||
|
"duration_minutes": 75, |
||||
|
"content": "متن و نکات کلیدی جلسه برخط اول همراه با فایل اسلایدها و منابع تکمیلی.", |
||||
|
"is_preview": False, |
||||
|
"order": 2, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
"title": "Advanced Islamic Center & Community Leadership (Live Cohort)", |
||||
|
"slug": "online-center-community-leadership", |
||||
|
"course_type": CourseType.ONLINE, |
||||
|
"adobe_connect_url": "https://live.astan.ir/center-leadership", |
||||
|
"live_schedule": "Every Saturday at 14:00 GMT", |
||||
|
"category": CourseCategory.CENTER_MANAGEMENT, |
||||
|
"language": CourseLanguage.EN, |
||||
|
"level": CourseLevel.ADVANCED, |
||||
|
"instructor_name": "Sheikh Bilal Al-Kazemi", |
||||
|
"instructor_title": "Director of International Community Engagement", |
||||
|
"organization_name": "Federation of Global Islamic Centers", |
||||
|
"description": ( |
||||
|
"A specialized leadership masterclass for center directors, mosque trustees, and community organizers. " |
||||
|
"Features live panel discussions, strategic planning exercises, and real-time governance case studies." |
||||
|
), |
||||
|
"duration_hours": 18.0, |
||||
|
"rating": 4.88, |
||||
|
"reviews_count": 29, |
||||
|
"is_published": True, |
||||
|
"is_featured": False, |
||||
|
"modules": [ |
||||
|
{ |
||||
|
"title": "Module 1: Strategic Governance and Crisis Leadership", |
||||
|
"order": 1, |
||||
|
"lessons": [ |
||||
|
{ |
||||
|
"title": "Cohort Onboarding & Live Room Setup", |
||||
|
"lesson_type": Lesson.LessonType.READING, |
||||
|
"duration_minutes": 25, |
||||
|
"content": ( |
||||
|
"# Live Cohort Setup\n\n" |
||||
|
"Sessions convene every Saturday at 14:00 GMT via Adobe Connect.\n" |
||||
|
"Please review the community governance code before attending Session 1." |
||||
|
), |
||||
|
"is_preview": True, |
||||
|
"order": 1, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
"title": "Comprehensive Quranic Arabic for Researchers (Hybrid Course)", |
||||
|
"slug": "hybrid-quranic-arabic-researchers", |
||||
|
"course_type": CourseType.HYBRID, |
||||
|
"adobe_connect_url": "https://live.astan.ir/quranic-arabic", |
||||
|
"live_schedule": "Mondays & Wednesdays at 19:00 Mecca Time", |
||||
|
"category": CourseCategory.SPECIALIZED_LANGUAGES, |
||||
|
"language": CourseLanguage.AR, |
||||
|
"level": CourseLevel.INTERMEDIATE, |
||||
|
"instructor_name": "د. طارق الهاشمي", |
||||
|
"instructor_title": "أستاذ اللغويات والترجمة التخصصية", |
||||
|
"organization_name": "معهد الدراسات اللغوية التخصصية", |
||||
|
"description": ( |
||||
|
"دورة هجينة تجمع بين الدروس المسجلة الذاتية وورش العمل الحية الأسبوعية عبر أدوبي كونكت " |
||||
|
"لتحليل النصوص الدينية والمصطلحات القرآنية التخصصية." |
||||
|
), |
||||
|
"duration_hours": 24.0, |
||||
|
"rating": 4.92, |
||||
|
"reviews_count": 45, |
||||
|
"is_published": True, |
||||
|
"is_featured": True, |
||||
|
"modules": [ |
||||
|
{ |
||||
|
"title": "الوحدة الأولى: البنية الصرفية والنحوية المتقدمة", |
||||
|
"order": 1, |
||||
|
"lessons": [ |
||||
|
{ |
||||
|
"title": "مقدمة البرنامج وجدول البث المباشر", |
||||
|
"lesson_type": Lesson.LessonType.READING, |
||||
|
"duration_minutes": 20, |
||||
|
"content": ( |
||||
|
"# جدول الجلسات التفاعلية المباشرة\n\n" |
||||
|
"تنعقد الورش الحية يومي الإثنين والأربعاء الساعة 19:00 بتوقيت مكة المكرمة عبر قاعة أدوبي كونكت." |
||||
|
), |
||||
|
"is_preview": True, |
||||
|
"order": 1, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
] |
||||
|
|
||||
|
created_count = 0 |
||||
|
for data in sample_courses: |
||||
|
modules_data = data.pop("modules", []) |
||||
|
slug = data["slug"] |
||||
|
|
||||
|
course, created = Course.objects.update_or_create( |
||||
|
slug=slug, |
||||
|
defaults={ |
||||
|
**data, |
||||
|
"institution": institution, |
||||
|
"created_by": admin_user, |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
if created: |
||||
|
created_count += 1 |
||||
|
self.stdout.write(self.style.SUCCESS(f"Created course: {course.title} ({course.course_type})")) |
||||
|
else: |
||||
|
self.stdout.write(self.style.WARNING(f"Updated course: {course.title} ({course.course_type})")) |
||||
|
|
||||
|
# Create modules and lessons |
||||
|
for m_data in modules_data: |
||||
|
lessons_data = m_data.pop("lessons", []) |
||||
|
module, _ = CourseModule.objects.update_or_create( |
||||
|
course=course, |
||||
|
order=m_data["order"], |
||||
|
defaults={"title": m_data["title"]}, |
||||
|
) |
||||
|
for l_data in lessons_data: |
||||
|
Lesson.objects.update_or_create( |
||||
|
module=module, |
||||
|
order=l_data["order"], |
||||
|
defaults=l_data, |
||||
|
) |
||||
|
|
||||
|
self.stdout.write( |
||||
|
self.style.SUCCESS( |
||||
|
f"Successfully seeded {len(sample_courses)} online/hybrid courses (New: {created_count})!" |
||||
|
) |
||||
|
) |
||||
@ -0,0 +1,28 @@ |
|||||
|
# Generated by Django 4.2.30 on 2026-10-22 06:59 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('lms', '0001_initial'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='course', |
||||
|
name='adobe_connect_url', |
||||
|
field=models.URLField(blank=True, max_length=500, null=True, verbose_name='Adobe Connect / Online Meeting Link'), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='course', |
||||
|
name='course_type', |
||||
|
field=models.CharField(choices=[('recorded', 'Recorded / Self-Paced'), ('online', 'Live Online (Adobe Connect)'), ('hybrid', 'Hybrid (Recorded & Live Online)')], default='recorded', max_length=20, verbose_name='Course Delivery Type'), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='course', |
||||
|
name='live_schedule', |
||||
|
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='Live Schedule (e.g. Saturdays at 18:00 UTC)'), |
||||
|
), |
||||
|
] |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue