elearning/docs/api-docs/api_prerequisites_examples.md

10 KiB

API Usage Examples - Lesson Prerequisites

New Endpoints Usage Examples


1. Check Lesson Access (Student)

GET /students/courses/:courseId/lessons/:lessonId/access-check

Purpose: ตรวจสอบว่าสามารถเข้าถึง lesson ได้หรือไม่ โดยไม่ต้อง load content

Request:

GET /api/students/courses/1/lessons/3/access-check
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Response 200 (Can Access):

{
  "can_access": true,
  "lesson": {
    "id": 3,
    "title": "แบบทดสอบท้ายบท",
    "type": "quiz",
    "sort_order": 3
  }
}

Response 200 (Locked - Incomplete Prerequisites):

{
  "can_access": false,
  "reason": "incomplete_prerequisites",
  "message": "กรุณาเรียนบทเรียนก่อนหน้าให้เสร็จก่อน",
  "required_lessons": [
    {
      "id": 1,
      "title": "บทที่ 1: แนะนำ",
      "type": "video",
      "is_completed": true
    },
    {
      "id": 2,
      "title": "บทที่ 2: ตัวแปร",
      "type": "video",
      "is_completed": false
    }
  ],
  "missing_lessons": [2],
  "next_available_lesson": {
    "id": 2,
    "title": "บทที่ 2: ตัวแปร"
  }
}

Response 200 (Locked - Quiz Not Passed):

{
  "can_access": false,
  "reason": "quiz_not_passed",
  "message": "กรุณาทำแบบทดสอบให้ผ่านก่อน",
  "required_quiz": {
    "lesson_id": 3,
    "title": "แบบทดสอบท้ายบท",
    "passing_score": 70,
    "your_best_score": 55,
    "attempts_used": 2,
    "max_attempts": 3
  }
}

2. Get Learning Page with Lock Status (Student)

GET /students/courses/:courseId/learn

Changes: เพิ่ม is_locked และ lock_reason ในแต่ละ lesson

Request:

GET /api/students/courses/1/learn
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Response 200:

{
  "course": {
    "id": 1,
    "title": "Python สำหรับผู้เริ่มต้น"
  },
  "enrollment": {
    "status": "enrolled",
    "progress_percentage": 35
  },
  "chapters": [
    {
      "id": 1,
      "title": "บทที่ 1: พื้นฐาน",
      "sort_order": 1,
      "lessons": [
        {
          "id": 1,
          "title": "1.1 แนะนำ Python",
          "type": "video",
          "duration": "00:15:30",
          "is_completed": true,
          "is_locked": false,
          "completed_at": "2024-12-23T10:00:00Z"
        },
        {
          "id": 2,
          "title": "1.2 ตัวแปร",
          "type": "video",
          "duration": "00:20:00",
          "is_completed": false,
          "is_locked": false
        },
        {
          "id": 3,
          "title": "1.3 แบบทดสอบ",
          "type": "quiz",
          "is_completed": false,
          "is_locked": true,
          "lock_reason": "incomplete_prerequisites",
          "required_lessons": [1, 2]
        },
        {
          "id": 4,
          "title": "1.4 ขั้นสูง",
          "type": "video",
          "duration": "00:25:00",
          "is_completed": false,
          "is_locked": true,
          "lock_reason": "quiz_not_passed",
          "required_quiz": 3
        }
      ]
    }
  ]
}

3. Get Lesson Content with Prerequisites Check (Student)

GET /students/courses/:courseId/lessons/:lessonId

Changes: ตรวจสอบ prerequisites ก่อน return content

Request:

GET /api/students/courses/1/lessons/3
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Response 403 (Locked):

{
  "error": {
    "code": "LESSON_LOCKED",
    "message": "Cannot access this lesson",
    "reason": "incomplete_prerequisites",
    "required_lessons": [1, 2],
    "completed_lessons": [1],
    "missing_lessons": [2],
    "next_available_lesson": {
      "id": 2,
      "title": "บทที่ 2: ตัวแปร",
      "type": "video"
    }
  }
}

4. Create Lesson with Prerequisites (Instructor)

POST /instructor/courses/:courseId/chapters/:chapterId/lessons

Changes: เพิ่ม fields สำหรับ prerequisites

Request:

POST /api/instructor/courses/1/chapters/1/lessons
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

{
  "title": {
    "th": "แบบทดสอบท้ายบท",
    "en": "Chapter Quiz"
  },
  "content": {
    "th": "<p>ทดสอบความเข้าใจ</p>",
    "en": "<p>Test your understanding</p>"
  },
  "type": "quiz",
  "sort_order": 3,
  "is_sequential": true,
  "prerequisite_lesson_ids": [1, 2],
  "require_pass_quiz": true
}

Response 201:

{
  "id": 3,
  "chapter_id": 1,
  "title": {
    "th": "แบบทดสอบท้ายบท",
    "en": "Chapter Quiz"
  },
  "type": "quiz",
  "sort_order": 3,
  "is_sequential": true,
  "prerequisite_lesson_ids": [1, 2],
  "require_pass_quiz": true,
  "created_at": "2024-12-23T14:00:00Z"
}

Response 422 (Validation Error):

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid prerequisites",
    "details": [
      {
        "field": "prerequisite_lesson_ids",
        "message": "Lesson ID 99 does not exist"
      }
    ]
  }
}

5. View Lesson Prerequisites (Instructor)

GET /instructor/courses/:courseId/lessons/:lessonId/prerequisites

Request:

GET /api/instructor/courses/1/lessons/4/prerequisites
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Response 200:

{
  "lesson": {
    "id": 4,
    "title": "บทที่ 3: ขั้นสูง",
    "type": "video",
    "sort_order": 4
  },
  "is_sequential": true,
  "prerequisites": [
    {
      "id": 3,
      "title": "แบบทดสอบท้ายบท",
      "type": "quiz",
      "require_pass": true,
      "passing_score": 70
    }
  ],
  "affected_students": {
    "total_enrolled": 150,
    "can_access": 85,
    "locked": 65,
    "breakdown": {
      "incomplete_prerequisites": 45,
      "quiz_not_passed": 20
    }
  }
}

6. Update Lesson Prerequisites (Instructor)

POST /instructor/courses/:courseId/lessons/:lessonId/prerequisites

Request:

POST /api/instructor/courses/1/lessons/4/prerequisites
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

{
  "is_sequential": true,
  "prerequisite_lesson_ids": [3],
  "require_pass_quiz": false
}

Response 200:

{
  "lesson_id": 4,
  "is_sequential": true,
  "prerequisites": [
    {
      "id": 3,
      "title": "แบบทดสอบท้ายบท",
      "type": "quiz",
      "require_pass": false
    }
  ],
  "message": "Prerequisites updated successfully",
  "affected_students": {
    "newly_unlocked": 20,
    "still_locked": 45
  }
}

Error Codes

New Error Codes for Prerequisites

Code Description
LESSON_LOCKED Cannot access lesson due to prerequisites
INCOMPLETE_PREREQUISITES Required lessons not completed
QUIZ_NOT_PASSED Required quiz not passed
INVALID_PREREQUISITES Invalid prerequisite configuration
CIRCULAR_DEPENDENCY Circular dependency detected

Frontend Integration Examples

1. Display Locked Lesson

function LessonItem({ lesson }) {
  if (lesson.is_locked) {
    return (
      <div className="lesson-item locked">
        <LockIcon />
        <span className="lesson-title">{lesson.title}</span>
        
        {lesson.lock_reason === 'incomplete_prerequisites' && (
          <Tooltip>
            กรณาเรยนบทเรยนกอนหนาใหเสรจกอน
            <ul>
              {lesson.required_lessons.map(id => (
                <li key={id}>Lesson {id}</li>
              ))}
            </ul>
          </Tooltip>
        )}
        
        {lesson.lock_reason === 'quiz_not_passed' && (
          <Tooltip>
            กรณาทำแบบทดสอบใหานกอน (องได 70% ึ้นไป)
          </Tooltip>
        )}
      </div>
    );
  }
  
  return (
    <Link to={`/lessons/${lesson.id}`} className="lesson-item">
      {lesson.is_completed ? <CheckIcon /> : <PlayIcon />}
      <span>{lesson.title}</span>
    </Link>
  );
}

2. Check Access Before Navigation

async function navigateToLesson(courseId, lessonId) {
  try {
    const response = await fetch(
      `/api/students/courses/${courseId}/lessons/${lessonId}/access-check`,
      {
        headers: {
          'Authorization': `Bearer ${token}`
        }
      }
    );
    
    const data = await response.json();
    
    if (data.can_access) {
      // Navigate to lesson
      router.push(`/courses/${courseId}/lessons/${lessonId}`);
    } else {
      // Show lock message
      if (data.reason === 'incomplete_prerequisites') {
        showAlert(`กรุณาเรียนบทเรียนก่อนหน้าให้เสร็จก่อน`);
        // Highlight next available lesson
        highlightLesson(data.next_available_lesson.id);
      } else if (data.reason === 'quiz_not_passed') {
        showAlert(`กรุณาทำแบบทดสอบให้ผ่านก่อน`);
        // Navigate to quiz
        router.push(`/courses/${courseId}/lessons/${data.required_quiz.lesson_id}`);
      }
    }
  } catch (error) {
    console.error('Error checking lesson access:', error);
  }
}

Summary

New Endpoints: 3

  • GET /students/courses/:courseId/lessons/:lessonId/access-check
  • GET /instructor/courses/:courseId/lessons/:lessonId/prerequisites
  • POST /instructor/courses/:courseId/lessons/:lessonId/prerequisites

Modified Endpoints: 4

  • GET /students/courses/:courseId/learn - เพิ่ม lock status
  • GET /students/courses/:courseId/lessons/:lessonId - เช็ค prerequisites
  • POST /instructor/courses/:courseId/chapters/:chapterId/lessons - รองรับ prerequisites
  • PUT /instructor/courses/:courseId/lessons/:lessonId - รองรับ prerequisites