docs: Add Forgejo and development setup guides, and refactor API documentation structure.
This commit is contained in:
parent
7b1ed6f6cc
commit
a6427b2083
9 changed files with 2446 additions and 7 deletions
438
docs/api-docs/api_prerequisites_examples.md
Normal file
438
docs/api-docs/api_prerequisites_examples.md
Normal file
|
|
@ -0,0 +1,438 @@
|
|||
# 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:
|
||||
```http
|
||||
GET /api/students/courses/1/lessons/3/access-check
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
#### Response 200 (Can Access):
|
||||
```json
|
||||
{
|
||||
"can_access": true,
|
||||
"lesson": {
|
||||
"id": 3,
|
||||
"title": "แบบทดสอบท้ายบท",
|
||||
"type": "quiz",
|
||||
"sort_order": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Response 200 (Locked - Incomplete Prerequisites):
|
||||
```json
|
||||
{
|
||||
"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):
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
```http
|
||||
GET /api/students/courses/1/learn
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
#### Response 200:
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
```http
|
||||
GET /api/students/courses/1/lessons/3
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
#### Response 403 (Locked):
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
```http
|
||||
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:
|
||||
```json
|
||||
{
|
||||
"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):
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
```http
|
||||
GET /api/instructor/courses/1/lessons/4/prerequisites
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
#### Response 200:
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
```http
|
||||
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:
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```javascript
|
||||
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
|
||||
|
||||
```javascript
|
||||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue