elearning/docs/api-docs/api_attachments_examples.md

520 lines
13 KiB
Markdown

# API Usage Examples - Lesson Attachments
## 📎 Lesson Attachments Endpoints
---
## 1. Upload Attachment (Instructor)
### POST `/instructor/courses/:courseId/lessons/:lessonId/attachments`
#### Request:
```http
POST /api/instructor/courses/1/lessons/5/attachments
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: multipart/form-data
file: <slides.pdf>
description_th: "สไลด์ประกอบการสอน"
description_en: "Lecture slides"
sort_order: 1
```
#### Response 201:
```json
{
"id": 10,
"lesson_id": 5,
"file_name": "slides.pdf",
"file_path": "lessons/5/slides.pdf",
"file_size": 2048576,
"mime_type": "application/pdf",
"description": {
"th": "สไลด์ประกอบการสอน",
"en": "Lecture slides"
},
"sort_order": 1,
"download_url": "/api/lessons/5/attachments/10/download",
"created_at": "2024-12-23T15:00:00Z"
}
```
#### Response 422 (File Too Large):
```json
{
"error": {
"code": "FILE_TOO_LARGE",
"message": "File size exceeds maximum limit of 100 MB",
"file_size": 104857600,
"max_size": 104857600
}
}
```
#### Response 422 (Too Many Attachments):
```json
{
"error": {
"code": "MAX_ATTACHMENTS_EXCEEDED",
"message": "Maximum 10 attachments per lesson",
"current_count": 10,
"max_count": 10
}
}
```
#### Response 422 (Invalid File Type):
```json
{
"error": {
"code": "INVALID_FILE_TYPE",
"message": "File type not allowed",
"mime_type": "application/x-executable",
"allowed_types": ["application/pdf", "application/zip", "image/jpeg", "..."]
}
}
```
---
## 2. List Attachments (Instructor)
### GET `/instructor/courses/:courseId/lessons/:lessonId/attachments`
#### Request:
```http
GET /api/instructor/courses/1/lessons/5/attachments
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
#### Response 200:
```json
{
"lesson_id": 5,
"attachments": [
{
"id": 10,
"file_name": "slides.pdf",
"file_size": 2048576,
"mime_type": "application/pdf",
"description": {
"th": "สไลด์ประกอบการสอน",
"en": "Lecture slides"
},
"sort_order": 1,
"download_url": "/api/lessons/5/attachments/10/download",
"created_at": "2024-12-23T15:00:00Z"
},
{
"id": 11,
"file_name": "code.zip",
"file_size": 512000,
"mime_type": "application/zip",
"description": {
"th": "โค้ดตัวอย่าง",
"en": "Sample code"
},
"sort_order": 2,
"download_url": "/api/lessons/5/attachments/11/download",
"created_at": "2024-12-23T15:05:00Z"
},
{
"id": 12,
"file_name": "exercises.docx",
"file_size": 256000,
"mime_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"description": {
"th": "แบบฝึกหัด",
"en": "Exercises"
},
"sort_order": 3,
"download_url": "/api/lessons/5/attachments/12/download",
"created_at": "2024-12-23T15:10:00Z"
}
],
"total": 3
}
```
---
## 3. Update Attachment Info (Instructor)
### PUT `/instructor/courses/:courseId/lessons/:lessonId/attachments/:attachmentId`
#### Request:
```http
PUT /api/instructor/courses/1/lessons/5/attachments/10
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"description": {
"th": "สไลด์ประกอบการสอน (ฉบับแก้ไข)",
"en": "Lecture slides (revised)"
},
"sort_order": 2
}
```
#### Response 200:
```json
{
"id": 10,
"lesson_id": 5,
"file_name": "slides.pdf",
"file_size": 2048576,
"mime_type": "application/pdf",
"description": {
"th": "สไลด์ประกอบการสอน (ฉบับแก้ไข)",
"en": "Lecture slides (revised)"
},
"sort_order": 2,
"updated_at": "2024-12-23T15:20:00Z"
}
```
---
## 4. Delete Attachment (Instructor)
### DELETE `/instructor/courses/:courseId/lessons/:lessonId/attachments/:attachmentId`
#### Request:
```http
DELETE /api/instructor/courses/1/lessons/5/attachments/10
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
#### Response 204:
```
No Content
```
---
## 5. Reorder Attachments (Instructor)
### PUT `/instructor/courses/:courseId/lessons/:lessonId/attachments/reorder`
#### Request:
```http
PUT /api/instructor/courses/1/lessons/5/attachments/reorder
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"attachments": [
{ "id": 11, "sort_order": 1 },
{ "id": 12, "sort_order": 2 },
{ "id": 10, "sort_order": 3 }
]
}
```
#### Response 200:
```json
{
"message": "Attachments reordered successfully",
"attachments": [
{
"id": 11,
"file_name": "code.zip",
"sort_order": 1
},
{
"id": 12,
"file_name": "exercises.docx",
"sort_order": 2
},
{
"id": 10,
"file_name": "slides.pdf",
"sort_order": 3
}
]
}
```
---
## 6. Get Lesson with Attachments (Student)
### GET `/students/courses/:courseId/lessons/:lessonId`
**Changes**: เพิ่ม `attachments` array
#### Request:
```http
GET /api/students/courses/1/lessons/5
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
#### Response 200:
```json
{
"id": 5,
"title": "บทที่ 3: ทฤษฎี",
"content": "<p>เนื้อหาบทเรียน...</p>",
"type": "video",
"video_url": "https://cdn.example.com/videos/lesson-5.m3u8",
"duration": "00:25:00",
"is_completed": false,
"can_access": true,
"attachments": [
{
"id": 11,
"file_name": "code.zip",
"file_size": 512000,
"mime_type": "application/zip",
"description": "โค้ดตัวอย่าง",
"download_url": "/api/lessons/5/attachments/11/download"
},
{
"id": 12,
"file_name": "exercises.docx",
"file_size": 256000,
"mime_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"description": "แบบฝึกหัด",
"download_url": "/api/lessons/5/attachments/12/download"
},
{
"id": 10,
"file_name": "slides.pdf",
"file_size": 2048576,
"mime_type": "application/pdf",
"description": "สไลด์ประกอบการสอน",
"download_url": "/api/lessons/5/attachments/10/download"
}
]
}
```
---
## 7. Download Attachment
### GET `/lessons/:lessonId/attachments/:attachmentId/download`
#### Request:
```http
GET /api/lessons/5/attachments/10/download
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
#### Response 200:
```http
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="slides.pdf"
Content-Length: 2048576
<binary file data>
```
#### Response 403 (Not Enrolled):
```json
{
"error": {
"code": "NOT_ENROLLED",
"message": "You must enroll in this course to download attachments",
"course_id": 1
}
}
```
---
## Frontend Integration Examples
### 1. Upload Attachment Component
```javascript
async function uploadAttachment(courseId, lessonId, file, description) {
const formData = new FormData();
formData.append('file', file);
formData.append('description_th', description.th);
formData.append('description_en', description.en);
formData.append('sort_order', 1);
try {
const response = await fetch(
`/api/instructor/courses/${courseId}/lessons/${lessonId}/attachments`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
},
body: formData
}
);
if (!response.ok) {
const error = await response.json();
if (error.error.code === 'FILE_TOO_LARGE') {
showAlert('ไฟล์ใหญ่เกินไป (สูงสุด 100 MB)');
} else if (error.error.code === 'MAX_ATTACHMENTS_EXCEEDED') {
showAlert('แนบไฟล์ได้สูงสุด 10 ไฟล์');
} else if (error.error.code === 'INVALID_FILE_TYPE') {
showAlert('ประเภทไฟล์ไม่รองรับ');
}
return;
}
const data = await response.json();
showSuccess('อัปโหลดไฟล์สำเร็จ');
return data;
} catch (error) {
console.error('Upload error:', error);
showAlert('เกิดข้อผิดพลาดในการอัปโหลด');
}
}
```
### 2. Display Attachments List
```javascript
function AttachmentsList({ attachments }) {
return (
<div className="attachments-list">
<h3>📎 ไฟลแนบ ({attachments.length})</h3>
{attachments.map(attachment => (
<div key={attachment.id} className="attachment-item">
<div className="file-icon">
{getFileIcon(attachment.mime_type)}
</div>
<div className="file-info">
<div className="file-name">{attachment.file_name}</div>
<div className="file-description">{attachment.description}</div>
<div className="file-size">{formatFileSize(attachment.file_size)}</div>
</div>
<a
href={attachment.download_url}
download
className="download-button"
>
ดาวนโหลด
</a>
</div>
))}
</div>
);
}
function getFileIcon(mimeType) {
if (mimeType.includes('pdf')) return '📄';
if (mimeType.includes('zip')) return '📦';
if (mimeType.includes('word')) return '📝';
if (mimeType.includes('excel')) return '📊';
if (mimeType.includes('powerpoint')) return '📊';
if (mimeType.includes('image')) return '🖼️';
return '📎';
}
function formatFileSize(bytes) {
if (bytes < 1024) return bytes + ' B';
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
}
```
### 3. Drag & Drop Reorder
```javascript
function ReorderAttachments({ attachments, onReorder }) {
const [items, setItems] = useState(attachments);
const handleDragEnd = (result) => {
if (!result.destination) return;
const reordered = Array.from(items);
const [removed] = reordered.splice(result.source.index, 1);
reordered.splice(result.destination.index, 0, removed);
// Update sort_order
const updated = reordered.map((item, index) => ({
id: item.id,
sort_order: index + 1
}));
setItems(reordered);
onReorder(updated);
};
return (
<DragDropContext onDragEnd={handleDragEnd}>
<Droppable droppableId="attachments">
{(provided) => (
<div {...provided.droppableProps} ref={provided.innerRef}>
{items.map((item, index) => (
<Draggable key={item.id} draggableId={String(item.id)} index={index}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
{item.file_name}
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
}
```
---
## Allowed File Types
| Category | MIME Type | Extension |
|----------|-----------|-----------|
| **Documents** | `application/pdf` | .pdf |
| | `application/msword` | .doc |
| | `application/vnd.openxmlformats-officedocument.wordprocessingml.document` | .docx |
| | `application/vnd.ms-excel` | .xls |
| | `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` | .xlsx |
| | `application/vnd.ms-powerpoint` | .ppt |
| | `application/vnd.openxmlformats-officedocument.presentationml.presentation` | .pptx |
| **Archives** | `application/zip` | .zip |
| | `application/x-rar-compressed` | .rar |
| | `application/x-7z-compressed` | .7z |
| **Images** | `image/jpeg` | .jpg |
| | `image/png` | .png |
| | `image/gif` | .gif |
| **Text** | `text/plain` | .txt |
| | `text/csv` | .csv |
---
## File Limits
- **Max file size**: 100 MB per file
- **Max attachments**: 10 files per lesson
- **Total size**: 500 MB per lesson
---
## Summary
**New Endpoints**: 6
- `POST /instructor/courses/:courseId/lessons/:lessonId/attachments`
- `GET /instructor/courses/:courseId/lessons/:lessonId/attachments`
- `PUT /instructor/courses/:courseId/lessons/:lessonId/attachments/:attachmentId`
- `DELETE /instructor/courses/:courseId/lessons/:lessonId/attachments/:attachmentId`
- `PUT /instructor/courses/:courseId/lessons/:lessonId/attachments/reorder`
- `GET /lessons/:lessonId/attachments/:attachmentId/download`
**Modified Endpoints**: 2
- `GET /students/courses/:courseId/lessons/:lessonId` - เพิ่ม attachments array
- `GET /students/courses/:courseId/learn` - เพิ่ม attachments_count