351 lines
9.1 KiB
JavaScript
351 lines
9.1 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const vocabController = require('../controllers/vocabController');
|
|
const { authenticateToken } = require('../middleware/auth');
|
|
|
|
/**
|
|
* ============================================
|
|
* POST /api/vocabs
|
|
* ============================================
|
|
* Tạo một vocab entry mới
|
|
*
|
|
* INPUT:
|
|
* {
|
|
* text: String (required) - từ thực tế (wash, washes, washing, ate, eaten...)
|
|
* ipa: String - phiên âm IPA (ví dụ: /wɒʃ/)
|
|
* base_word: String (required) - từ gốc để nhóm lại (wash, eat...)
|
|
* form_key: JSON - loại biến thể (V1, V2, V3, V_ing, Noun_Form...), mặc định 'base'
|
|
* vi: String - nghĩa tiếng Việt
|
|
* category: String - category của từ (Action Verbs, Nouns, etc.)
|
|
* topic: String - chủ đề (Food, Travel, Education, etc.)
|
|
* image_small: JSON Array - mảng URLs của hình ảnh nhỏ
|
|
* image_square: JSON Array - mảng URLs của hình ảnh vuông
|
|
* image_normal: JSON Array - mảng URLs của hình ảnh bình thường
|
|
* audio: JSON Array - mảng URLs của audio files
|
|
* example_sentences: JSON - các câu ví dụ
|
|
* tags: JSON Array - các tags để phân loại
|
|
* syntax: JSON - vai trò cú pháp
|
|
* semantics: JSON - ràng buộc ngữ nghĩa
|
|
* constraints: JSON - ràng buộc ngữ pháp
|
|
* }
|
|
*
|
|
* OUTPUT:
|
|
* {
|
|
* success: Boolean,
|
|
* message: String,
|
|
* data: Vocab object đã tạo (bao gồm vocab_id, created_at, updated_at)
|
|
* }
|
|
**/
|
|
|
|
router.post('/', vocabController.createVocab);
|
|
|
|
/**
|
|
* ============================================
|
|
* POST /api/vocabs/bulk
|
|
* ============================================
|
|
* Tạo nhiều vocab entries cùng lúc
|
|
*
|
|
* INPUT:
|
|
* {
|
|
* vocabs: Array of Vocab objects - mỗi object phải có text và base_word
|
|
* [
|
|
* {
|
|
* text: String (required),
|
|
* base_word: String (required),
|
|
* ipa: String,
|
|
* vi: String,
|
|
* ...
|
|
* },
|
|
* ...
|
|
* ]
|
|
* }
|
|
*
|
|
* OUTPUT:
|
|
* {
|
|
* success: Boolean,
|
|
* message: String,
|
|
* data: Array of created Vocab objects,
|
|
* count: Number - số lượng vocab đã tạo
|
|
* }
|
|
**/
|
|
router.post('/bulk', vocabController.bulkCreateVocabs);
|
|
|
|
/**
|
|
* ============================================
|
|
* POST /api/vocabs/search
|
|
* ============================================
|
|
* Tìm kiếm vocab nâng cao với nhiều filter
|
|
*
|
|
* INPUT:
|
|
* {
|
|
* topic: String (optional) - chủ đề (exact match)
|
|
* category: String (optional) - loại từ (exact match)
|
|
* base_word: String (optional) - từ gốc (partial match với LIKE)
|
|
* form_key: JSON (optional) - loại biến thể (V1, V2, V3, V_ing, Noun_Form, etc.)
|
|
* text: String (optional) - từ thực tế (partial match với LIKE)
|
|
* vi: String (optional) - nghĩa tiếng Việt (partial match với LIKE)
|
|
*
|
|
* v_type: Boolean (optional) - tìm các biến thể khác của cùng một base_word
|
|
* base_word_filter: String (optional) - base_word cụ thể (dùng khi v_type=true)
|
|
*
|
|
* shuffle_pos: Object (optional) - tìm từ thay thế dựa trên syntax
|
|
* {
|
|
* is_subject: Boolean,
|
|
* is_verb: Boolean,
|
|
* is_object: Boolean,
|
|
* is_be: Boolean,
|
|
* is_adj: Boolean,
|
|
* is_adv: Boolean,
|
|
* is_article: Boolean
|
|
* }
|
|
*
|
|
* page: Number - trang hiện tại (mặc định: 1)
|
|
* limit: Number - số items mỗi trang (mặc định: 100)
|
|
* }
|
|
*
|
|
* OUTPUT:
|
|
* {
|
|
* success: Boolean,
|
|
* message: String,
|
|
* data: Array of Vocab objects,
|
|
* pagination: {
|
|
* total: Number,
|
|
* page: Number,
|
|
* limit: Number,
|
|
* totalPages: Number
|
|
* }
|
|
* }
|
|
**/
|
|
router.post('/search', vocabController.searchVocabs);
|
|
|
|
/**
|
|
* ============================================
|
|
* GET /api/vocabs
|
|
* ============================================
|
|
* Lấy danh sách tất cả vocab với phân trang và filter
|
|
*
|
|
* INPUT (Query Parameters):
|
|
* {
|
|
* page: Number - trang hiện tại (mặc định: 1)
|
|
* limit: Number - số items mỗi trang (mặc định: 20)
|
|
* category: String - lọc theo category
|
|
* topic: String - lọc theo topic
|
|
* base_word: String - lọc theo base_word chính xác
|
|
* text: String - lọc theo text chính xác
|
|
* search: String - tìm kiếm trong text, base_word và vi
|
|
* is_active: Boolean - lọc theo trạng thái active (mặc định: true)
|
|
* }
|
|
*
|
|
* OUTPUT:
|
|
* {
|
|
* success: Boolean,
|
|
* message: String,
|
|
* data: Array of Vocab objects,
|
|
* pagination: {
|
|
* total: Number,
|
|
* page: Number,
|
|
* limit: Number,
|
|
* totalPages: Number
|
|
* }
|
|
* }
|
|
*
|
|
**/
|
|
router.get('/', vocabController.getAllVocabs);
|
|
|
|
/**
|
|
* ============================================
|
|
* GET /api/vocabs/stats/overview
|
|
* ============================================
|
|
* Lấy thống kê tổng quan về vocab
|
|
*
|
|
* INPUT: Không có
|
|
*
|
|
* OUTPUT:
|
|
* {
|
|
* success: Boolean,
|
|
* message: String,
|
|
* data: {
|
|
* total: {
|
|
* active: Number,
|
|
* inactive: Number,
|
|
* all: Number
|
|
* },
|
|
* unique_base_words: Number,
|
|
* by_category: Array [{category: String, count: Number}],
|
|
* by_topic: Array [{topic: String, count: Number}]
|
|
* }
|
|
* }
|
|
**/
|
|
router.get('/stats/overview', vocabController.getVocabStats);
|
|
|
|
/**
|
|
* ============================================
|
|
* GET /api/vocabs/meta/categories
|
|
* ============================================
|
|
* Lấy danh sách tất cả categories
|
|
*
|
|
* INPUT: Không có
|
|
*
|
|
* OUTPUT:
|
|
* {
|
|
* success: Boolean,
|
|
* message: String,
|
|
* data: Array of String - danh sách categories,
|
|
* count: Number - số lượng categories
|
|
* }
|
|
**/
|
|
router.get('/meta/categories', vocabController.getAllCategories);
|
|
|
|
/**
|
|
* ============================================
|
|
* GET /api/vocabs/meta/topics
|
|
* ============================================
|
|
* Lấy danh sách tất cả topics
|
|
*
|
|
* INPUT: Không có
|
|
*
|
|
* OUTPUT:
|
|
* {
|
|
* success: Boolean,
|
|
* message: String,
|
|
* data: Array of String - danh sách topics,
|
|
* count: Number - số lượng topics
|
|
* }
|
|
**/
|
|
router.get('/meta/topics', vocabController.getAllTopics);
|
|
|
|
/**
|
|
* ============================================
|
|
* GET /api/vocabs/missing/ipa
|
|
* ============================================
|
|
* Lấy tất cả các vocab chưa có IPA
|
|
*
|
|
* INPUT (Query Parameters):
|
|
* {
|
|
* page: Number - trang hiện tại (mặc định: 1),
|
|
* limit: Number - số items mỗi trang (mặc định: 50)
|
|
* }
|
|
*
|
|
* OUTPUT:
|
|
* {
|
|
* success: Boolean,
|
|
* message: String,
|
|
* data: Array of Vocab objects - các vocab chưa có IPA,
|
|
* pagination: {
|
|
* total: Number,
|
|
* page: Number,
|
|
* limit: Number,
|
|
* totalPages: Number
|
|
* }
|
|
* }
|
|
**/
|
|
router.get('/missing/ipa', vocabController.getVocabsWithoutIpa);
|
|
|
|
/**
|
|
* ============================================
|
|
* GET /api/vocabs/missing/images
|
|
* ============================================
|
|
* Lấy tất cả các vocab chưa đủ hình ảnh
|
|
*
|
|
* INPUT (Query Parameters):
|
|
* {
|
|
* page: Number - trang hiện tại (mặc định: 1),
|
|
* limit: Number - số items mỗi trang (mặc định: 50)
|
|
* }
|
|
*
|
|
* OUTPUT:
|
|
* {
|
|
* success: Boolean,
|
|
* message: String,
|
|
* data: Array of Vocab objects - các vocab chưa đủ hình ảnh,
|
|
* pagination: {
|
|
* total: Number,
|
|
* page: Number,
|
|
* limit: Number,
|
|
* totalPages: Number
|
|
* }
|
|
* }
|
|
**/
|
|
router.get('/missing/images', vocabController.getVocabsWithoutImages);
|
|
|
|
/**
|
|
* ============================================
|
|
* GET /api/vocabs/:id
|
|
* ============================================
|
|
* Lấy chi tiết một vocab theo ID
|
|
*
|
|
* INPUT (URL Parameter):
|
|
* {
|
|
* id: UUID - vocab_id của vocab cần lấy
|
|
* }
|
|
*
|
|
* OUTPUT:
|
|
* {
|
|
* success: Boolean,
|
|
* message: String,
|
|
* data: Vocab object với đầy đủ thông tin
|
|
* }
|
|
**/
|
|
router.get('/:id', vocabController.getVocabById);
|
|
|
|
/**
|
|
* ============================================
|
|
* PUT /api/vocabs/:id
|
|
* ============================================
|
|
* Cập nhật thông tin vocab
|
|
*
|
|
* INPUT (URL Parameter + Body):
|
|
* {
|
|
* id: UUID - vocab_id cần update
|
|
* Body: Object - các trường cần update (có thể update một hoặc nhiều trường)
|
|
* {
|
|
* text: String,
|
|
* ipa: String,
|
|
* base_word: String,
|
|
* form_key: JSON,
|
|
* vi: String,
|
|
* category: String,
|
|
* topic: String,
|
|
* image_small: JSON Array,
|
|
* image_square: JSON Array,
|
|
* image_normal: JSON Array,
|
|
* audio: JSON Array,
|
|
* example_sentences: JSON,
|
|
* tags: JSON Array,
|
|
* syntax: JSON,
|
|
* semantics: JSON,
|
|
* constraints: JSON,
|
|
* is_active: Boolean
|
|
* }
|
|
* }
|
|
*
|
|
* OUTPUT:
|
|
* {
|
|
* success: Boolean,
|
|
* message: String,
|
|
* data: Updated Vocab object
|
|
* }
|
|
* **/
|
|
router.put('/:id', vocabController.updateVocab);
|
|
|
|
/**
|
|
* ============================================
|
|
* DELETE /api/vocabs/:id
|
|
* ============================================
|
|
* Xóa mềm vocab (set is_active = false)
|
|
*
|
|
* INPUT (URL Parameter):
|
|
* {
|
|
* id: UUID - vocab_id cần xóa
|
|
* }
|
|
*
|
|
* OUTPUT:
|
|
* {
|
|
* success: Boolean,
|
|
* message: String
|
|
* }
|
|
**/
|
|
router.delete('/:id', vocabController.deleteVocab);
|
|
|
|
module.exports = router;
|