Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
B
BACKEND CHALLENGES
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Phạm Quang Bảo
BACKEND CHALLENGES
Commits
66487b83
Commit
66487b83
authored
May 20, 2026
by
Phạm Quang Bảo
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(challenge_8): authorization and add api get/set role
parent
11e8bbc6
Changes
17
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
666 additions
and
72 deletions
+666
-72
index.ts
code/src/controllers/api/v1.0/classes/index.ts
+8
-2
{id}.ts
code/src/controllers/api/v1.0/classes/{id}.ts
+13
-0
index.ts
code/src/controllers/api/v1.0/courses/index.ts
+12
-1
{id}.ts
code/src/controllers/api/v1.0/courses/{id}.ts
+15
-0
index.ts
...ollers/api/v1.0/enrollments/all-student-in-class/index.ts
+4
-1
index.ts
code/src/controllers/api/v1.0/enrollments/enroll/index.ts
+4
-5
index.ts
code/src/controllers/api/v1.0/enrollments/unenroll/index.ts
+4
-4
index.ts
code/src/controllers/api/v1.0/roles/index.ts
+53
-0
index.ts
code/src/controllers/api/v1.0/roles/set-role/index.ts
+56
-0
swagger-output.json
code/src/docs/swagger/swagger-output.json
+268
-28
request.ts
code/src/middlewares/request.ts
+14
-7
CoursesProvider.ts
code/src/providers/CoursesProvider.ts
+2
-1
RolesProvider.ts
code/src/providers/RolesProvider.ts
+34
-0
config.ts
code/src/templates/swagger/config.ts
+2
-0
schemas.ts
code/src/templates/swagger/courses/schemas.ts
+26
-23
schema.ts
code/src/templates/swagger/enrollment/schema.ts
+28
-0
schema.ts
code/src/templates/swagger/roles/schema.ts
+123
-0
No files found.
code/src/controllers/api/v1.0/classes/index.ts
View file @
66487b83
...
@@ -3,6 +3,8 @@ import type { Resource } from "express-automatic-routes";
...
@@ -3,6 +3,8 @@ import type { Resource } from "express-automatic-routes";
import
{
ClassesProvider
}
from
"#providers/ClassesProvider"
;
import
{
ClassesProvider
}
from
"#providers/ClassesProvider"
;
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
queryModifier
from
"#middlewares/request"
;
import
queryModifier
from
"#middlewares/request"
;
import
{
authorize
}
from
"#middlewares/authorization"
;
import
{
authMiddleware
}
from
"#middlewares/authentication"
;
export
default
(
_express
:
Application
)
=>
{
export
default
(
_express
:
Application
)
=>
{
const
classesProvider
=
new
ClassesProvider
();
const
classesProvider
=
new
ClassesProvider
();
...
@@ -13,6 +15,8 @@ export default (_express: Application) => {
...
@@ -13,6 +15,8 @@ export default (_express: Application) => {
* /api/v1.0/classes:
* /api/v1.0/classes:
* get:
* get:
* tags: [Classes]
* tags: [Classes]
* security:
* - bearerAuth: []
* parameters:
* parameters:
* - $ref: '#/components/parameters/filters'
* - $ref: '#/components/parameters/filters'
* - $ref: '#/components/parameters/sort'
* - $ref: '#/components/parameters/sort'
...
@@ -27,7 +31,7 @@ export default (_express: Application) => {
...
@@ -27,7 +31,7 @@ export default (_express: Application) => {
* $ref: "#/components/schemas/ClassListResponse"
* $ref: "#/components/schemas/ClassListResponse"
*/
*/
get
:
{
get
:
{
middleware
:
[
queryModifier
],
middleware
:
[
queryModifier
,
authMiddleware
,
authorize
(
'admin'
,
'instructor'
)
],
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
try
{
try
{
...
@@ -63,13 +67,15 @@ export default (_express: Application) => {
...
@@ -63,13 +67,15 @@ export default (_express: Application) => {
* content:
* content:
* application/json:
* application/json:
* schema:
* schema:
* $ref: "#/components/schemas/ClassResponse"
* $ref: "#/components/schemas/ClassResponse"
* 400:
* 400:
* description: Dữ liệu đầu vào không hợp lệ (Thiếu trường, sai định dạng)
* description: Dữ liệu đầu vào không hợp lệ (Thiếu trường, sai định dạng)
* 500:
* 500:
* description: Lỗi hệ thống phía Server
* description: Lỗi hệ thống phía Server
*/
*/
post
:
{
post
:
{
middleware
:
[
queryModifier
,
authMiddleware
,
authorize
(
'admin'
,
'instructor'
)],
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
try
{
try
{
const
newClass
=
await
classesProvider
.
createClass
(
req
.
body
);
const
newClass
=
await
classesProvider
.
createClass
(
req
.
body
);
...
...
code/src/controllers/api/v1.0/classes/{id}.ts
View file @
66487b83
...
@@ -2,6 +2,9 @@ import type { Application } from "express";
...
@@ -2,6 +2,9 @@ import type { Application } from "express";
import
type
{
Resource
}
from
"express-automatic-routes"
;
import
type
{
Resource
}
from
"express-automatic-routes"
;
import
{
ClassesProvider
}
from
"#providers/ClassesProvider.js"
;
import
{
ClassesProvider
}
from
"#providers/ClassesProvider.js"
;
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
{
authorize
}
from
"#middlewares/authorization"
;
import
queryModifier
from
"#middlewares/request"
;
import
{
authMiddleware
}
from
"#middlewares/authentication"
;
export
default
(
_express
:
Application
)
=>
{
export
default
(
_express
:
Application
)
=>
{
const
classesProvider
=
new
ClassesProvider
();
const
classesProvider
=
new
ClassesProvider
();
...
@@ -12,6 +15,8 @@ export default (_express: Application) => {
...
@@ -12,6 +15,8 @@ export default (_express: Application) => {
* /api/v1.0/classes/{id}:
* /api/v1.0/classes/{id}:
* get:
* get:
* tags: [Classes]
* tags: [Classes]
* security:
* - bearerAuth: []
* parameters:
* parameters:
* - name: id
* - name: id
* in: path
* in: path
...
@@ -28,6 +33,8 @@ export default (_express: Application) => {
...
@@ -28,6 +33,8 @@ export default (_express: Application) => {
* $ref: "#/components/schemas/ClassResponse"
* $ref: "#/components/schemas/ClassResponse"
*/
*/
get
:
{
get
:
{
middleware
:
[
queryModifier
,
authMiddleware
,
authorize
(
'admin'
,
'instructor'
)],
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
const
{
id
}
=
req
.
params
;
const
{
id
}
=
req
.
params
;
...
@@ -57,6 +64,8 @@ export default (_express: Application) => {
...
@@ -57,6 +64,8 @@ export default (_express: Application) => {
* /api/v1.0/classes/{id}:
* /api/v1.0/classes/{id}:
* put:
* put:
* tags: [Classes]
* tags: [Classes]
* security:
* - bearerAuth: []
* parameters:
* parameters:
* - name: id
* - name: id
* in: path
* in: path
...
@@ -80,6 +89,8 @@ export default (_express: Application) => {
...
@@ -80,6 +89,8 @@ export default (_express: Application) => {
* $ref: "#/components/schemas/ClassResponse"
* $ref: "#/components/schemas/ClassResponse"
*/
*/
put
:
{
put
:
{
middleware
:
[
queryModifier
,
authMiddleware
,
authorize
(
'admin'
,
'instructor'
)],
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
const
{
id
}
=
req
.
params
;
const
{
id
}
=
req
.
params
;
...
@@ -123,6 +134,8 @@ export default (_express: Application) => {
...
@@ -123,6 +134,8 @@ export default (_express: Application) => {
* description: Xóa lớp học thành công
* description: Xóa lớp học thành công
*/
*/
delete
:
{
delete
:
{
middleware
:
[
queryModifier
,
authMiddleware
,
authorize
(
'admin'
,
'instructor'
)],
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
const
{
id
}
=
req
.
params
;
const
{
id
}
=
req
.
params
;
...
...
code/src/controllers/api/v1.0/courses/index.ts
View file @
66487b83
...
@@ -2,6 +2,9 @@ import type { Application } from "express";
...
@@ -2,6 +2,9 @@ import type { Application } from "express";
import
type
{
Resource
}
from
"express-automatic-routes"
;
import
type
{
Resource
}
from
"express-automatic-routes"
;
import
{
CoursesProvider
}
from
"#providers/CoursesProvider.js"
;
import
{
CoursesProvider
}
from
"#providers/CoursesProvider.js"
;
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
queryModifier
from
"#middlewares/request"
;
import
{
authorize
}
from
"#middlewares/authorization"
;
import
{
authMiddleware
}
from
"#middlewares/authentication"
;
export
default
(
_express
:
Application
)
=>
{
export
default
(
_express
:
Application
)
=>
{
const
coursesProvider
=
new
CoursesProvider
();
const
coursesProvider
=
new
CoursesProvider
();
...
@@ -12,6 +15,8 @@ export default (_express: Application) => {
...
@@ -12,6 +15,8 @@ export default (_express: Application) => {
* /api/v1.0/courses:
* /api/v1.0/courses:
* get:
* get:
* tags: [Courses]
* tags: [Courses]
* security:
* - bearerAuth: []
* parameters:
* parameters:
* - $ref: '#/components/parameters/filters'
* - $ref: '#/components/parameters/filters'
* - $ref: '#/components/parameters/sort'
* - $ref: '#/components/parameters/sort'
...
@@ -23,9 +28,11 @@ export default (_express: Application) => {
...
@@ -23,9 +28,11 @@ export default (_express: Application) => {
* content:
* content:
* application/json:
* application/json:
* schema:
* schema:
* $ref: "#/components/schemas/CourseListResponse"
* $ref: "#/components/schemas/CourseListResponse"
*/
*/
get
:
{
get
:
{
middleware
:
[
queryModifier
,
authMiddleware
,
authorize
(
'admin'
,
'instructor'
)],
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
try
{
try
{
const
courses
=
await
coursesProvider
.
getAllCourses
(
req
.
payload
);
const
courses
=
await
coursesProvider
.
getAllCourses
(
req
.
payload
);
...
@@ -48,6 +55,8 @@ export default (_express: Application) => {
...
@@ -48,6 +55,8 @@ export default (_express: Application) => {
* post:
* post:
* tags: [Courses]
* tags: [Courses]
* description: Thêm một khóa học mới vào hệ thống
* description: Thêm một khóa học mới vào hệ thống
* security:
* - bearerAuth: []
* requestBody:
* requestBody:
* required: true
* required: true
* content:
* content:
...
@@ -63,6 +72,8 @@ export default (_express: Application) => {
...
@@ -63,6 +72,8 @@ export default (_express: Application) => {
* $ref: "#/components/schemas/CourseResponse"
* $ref: "#/components/schemas/CourseResponse"
*/
*/
post
:
{
post
:
{
middleware
:
[
queryModifier
,
authMiddleware
,
authorize
(
'admin'
,
'instructor'
)],
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
try
{
try
{
const
newCourse
=
await
coursesProvider
.
createCourse
(
req
.
body
);
const
newCourse
=
await
coursesProvider
.
createCourse
(
req
.
body
);
...
...
code/src/controllers/api/v1.0/courses/{id}.ts
View file @
66487b83
...
@@ -2,6 +2,9 @@ import type { Application } from "express";
...
@@ -2,6 +2,9 @@ import type { Application } from "express";
import
type
{
Resource
}
from
"express-automatic-routes"
;
import
type
{
Resource
}
from
"express-automatic-routes"
;
import
{
CoursesProvider
}
from
"#providers/CoursesProvider.js"
;
import
{
CoursesProvider
}
from
"#providers/CoursesProvider.js"
;
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
queryModifier
from
"#middlewares/request"
;
import
{
authorize
}
from
"#middlewares/authorization"
;
import
{
authMiddleware
}
from
"#middlewares/authentication"
;
export
default
(
_express
:
Application
)
=>
{
export
default
(
_express
:
Application
)
=>
{
const
coursesProvider
=
new
CoursesProvider
();
const
coursesProvider
=
new
CoursesProvider
();
...
@@ -12,6 +15,8 @@ export default (_express: Application) => {
...
@@ -12,6 +15,8 @@ export default (_express: Application) => {
* /api/v1.0/courses/{id}:
* /api/v1.0/courses/{id}:
* get:
* get:
* tags: [Courses]
* tags: [Courses]
* security:
* - bearerAuth: []
* parameters:
* parameters:
* - name: id
* - name: id
* in: path
* in: path
...
@@ -28,6 +33,8 @@ export default (_express: Application) => {
...
@@ -28,6 +33,8 @@ export default (_express: Application) => {
* $ref: "#/components/schemas/CourseResponse"
* $ref: "#/components/schemas/CourseResponse"
*/
*/
get
:
{
get
:
{
middleware
:
[
queryModifier
,
authMiddleware
,
authorize
(
'admin'
,
'instructor'
)],
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
const
id
=
req
.
params
.
id
;
const
id
=
req
.
params
.
id
;
...
@@ -49,6 +56,8 @@ export default (_express: Application) => {
...
@@ -49,6 +56,8 @@ export default (_express: Application) => {
* /api/v1.0/courses/{id}:
* /api/v1.0/courses/{id}:
* put:
* put:
* tags: [Courses]
* tags: [Courses]
* security:
* - bearerAuth: []
* parameters:
* parameters:
* - name: id
* - name: id
* in: path
* in: path
...
@@ -72,6 +81,8 @@ export default (_express: Application) => {
...
@@ -72,6 +81,8 @@ export default (_express: Application) => {
* $ref: "#/components/schemas/CourseResponse"
* $ref: "#/components/schemas/CourseResponse"
*/
*/
put
:
{
put
:
{
middleware
:
[
queryModifier
,
authMiddleware
,
authorize
(
'admin'
,
'instructor'
)],
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
const
{
id
}
=
req
.
params
;
const
{
id
}
=
req
.
params
;
...
@@ -101,6 +112,8 @@ export default (_express: Application) => {
...
@@ -101,6 +112,8 @@ export default (_express: Application) => {
* /api/v1.0/courses/{id}:
* /api/v1.0/courses/{id}:
* delete:
* delete:
* tags: [Courses]
* tags: [Courses]
* security:
* - bearerAuth: []
* parameters:
* parameters:
* - name: id
* - name: id
* in: path
* in: path
...
@@ -117,6 +130,8 @@ export default (_express: Application) => {
...
@@ -117,6 +130,8 @@ export default (_express: Application) => {
* $ref: "#/components/schemas/CourseResponse"
* $ref: "#/components/schemas/CourseResponse"
*/
*/
delete
:
{
delete
:
{
middleware
:
[
queryModifier
,
authMiddleware
,
authorize
(
'admin'
,
'instructor'
)],
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
const
{
id
}
=
req
.
params
;
const
{
id
}
=
req
.
params
;
...
...
code/src/controllers/api/v1.0/enrollments/all-student-in-class/index.ts
View file @
66487b83
...
@@ -2,6 +2,7 @@ import type { Application } from "express";
...
@@ -2,6 +2,7 @@ import type { Application } from "express";
import
type
{
Resource
}
from
"express-automatic-routes"
;
import
type
{
Resource
}
from
"express-automatic-routes"
;
import
{
EnrollProvider
}
from
"#providers/EnrollProvider.js"
;
import
{
EnrollProvider
}
from
"#providers/EnrollProvider.js"
;
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
queryModifier
from
"#middlewares/request"
;
export
default
(
_express
:
Application
)
=>
{
export
default
(
_express
:
Application
)
=>
{
const
enrollProvider
=
new
EnrollProvider
();
const
enrollProvider
=
new
EnrollProvider
();
...
@@ -11,7 +12,7 @@ export default (_express: Application) => {
...
@@ -11,7 +12,7 @@ export default (_express: Application) => {
* @openapi
* @openapi
* /api/v1.0/enrollments/all-student-in-class:
* /api/v1.0/enrollments/all-student-in-class:
* post:
* post:
* tags: [
e
nrollments]
* tags: [
E
nrollments]
* description: Xem tất cả học sinh có trong lớp học
* description: Xem tất cả học sinh có trong lớp học
* requestBody:
* requestBody:
* required: true
* required: true
...
@@ -30,6 +31,8 @@ export default (_express: Application) => {
...
@@ -30,6 +31,8 @@ export default (_express: Application) => {
* $ref: "#/components/schemas/AllStudentInClassOutput"
* $ref: "#/components/schemas/AllStudentInClassOutput"
*/
*/
post
:
{
post
:
{
middleware
:
[
queryModifier
],
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
try
{
try
{
const
students
=
await
enrollProvider
.
getAllStudentInClass
(
req
.
body
.
class_id
);
const
students
=
await
enrollProvider
.
getAllStudentInClass
(
req
.
body
.
class_id
);
...
...
code/src/controllers/api/v1.0/enrollments/enroll/index.ts
View file @
66487b83
...
@@ -4,6 +4,7 @@ import { EnrollProvider } from "#providers/EnrollProvider.js";
...
@@ -4,6 +4,7 @@ import { EnrollProvider } from "#providers/EnrollProvider.js";
import
{
authorize
}
from
"#middlewares/authorization"
;
import
{
authorize
}
from
"#middlewares/authorization"
;
import
{
authMiddleware
}
from
"#middlewares/authentication"
;
import
{
authMiddleware
}
from
"#middlewares/authentication"
;
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
queryModifier
from
"#middlewares/request"
;
export
default
(
_express
:
Application
)
=>
{
export
default
(
_express
:
Application
)
=>
{
const
enrollProvider
=
new
EnrollProvider
();
const
enrollProvider
=
new
EnrollProvider
();
...
@@ -13,7 +14,7 @@ export default (_express: Application) => {
...
@@ -13,7 +14,7 @@ export default (_express: Application) => {
* @openapi
* @openapi
* /api/v1.0/enrollments/enroll:
* /api/v1.0/enrollments/enroll:
* post:
* post:
* tags: [
e
nrollments]
* tags: [
E
nrollments]
* security:
* security:
* - bearerAuth: []
* - bearerAuth: []
* description: Tham gia khoá học
* description: Tham gia khoá học
...
@@ -29,12 +30,10 @@ export default (_express: Application) => {
...
@@ -29,12 +30,10 @@ export default (_express: Application) => {
* content:
* content:
* application/json:
* application/json:
* schema:
* schema:
* type: array
* $ref: "#/components/schemas/Enrollment"
* items:
* $ref: "#/components/schemas/Enrollment"
*/
*/
post
:
{
post
:
{
middleware
:
[
authMiddleware
,
authorize
(
"student"
)],
middleware
:
[
queryModifier
,
authMiddleware
,
authorize
(
"student"
)],
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
try
{
try
{
...
...
code/src/controllers/api/v1.0/enrollments/unenroll/index.ts
View file @
66487b83
...
@@ -3,6 +3,7 @@ import type { Resource } from "express-automatic-routes";
...
@@ -3,6 +3,7 @@ import type { Resource } from "express-automatic-routes";
import
{
EnrollProvider
}
from
"#providers/EnrollProvider.js"
;
import
{
EnrollProvider
}
from
"#providers/EnrollProvider.js"
;
import
{
authorize
}
from
"#middlewares/authorization"
;
import
{
authorize
}
from
"#middlewares/authorization"
;
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
queryModifier
from
"#middlewares/request"
;
export
default
(
_express
:
Application
)
=>
{
export
default
(
_express
:
Application
)
=>
{
const
enrollProvider
=
new
EnrollProvider
();
const
enrollProvider
=
new
EnrollProvider
();
...
@@ -12,7 +13,7 @@ export default (_express: Application) => {
...
@@ -12,7 +13,7 @@ export default (_express: Application) => {
* @openapi
* @openapi
* /api/v1.0/enrollments/unenroll:
* /api/v1.0/enrollments/unenroll:
* post:
* post:
* tags: [
e
nrollments]
* tags: [
E
nrollments]
* description: Hủy đăng ký khóa học
* description: Hủy đăng ký khóa học
* requestBody:
* requestBody:
* required: true
* required: true
...
@@ -26,11 +27,10 @@ export default (_express: Application) => {
...
@@ -26,11 +27,10 @@ export default (_express: Application) => {
* content:
* content:
* application/json:
* application/json:
* schema:
* schema:
* type: array
* $ref: "#/components/schemas/Unenrollment"
* items:
* $ref: "#/components/schemas/Unenrollment"
*/
*/
post
:
{
post
:
{
middleware
:
[
queryModifier
],
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
try
{
try
{
const
enroll
=
await
enrollProvider
.
unEnroll
(
req
.
body
.
userId
,
req
.
body
.
classId
);
const
enroll
=
await
enrollProvider
.
unEnroll
(
req
.
body
.
userId
,
req
.
body
.
classId
);
...
...
code/src/controllers/api/v1.0/roles/index.ts
0 → 100644
View file @
66487b83
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
{
RolesProvider
}
from
"#providers/RolesProvider.js"
;
import
{
Application
}
from
"express"
;
import
{
Resource
}
from
"express-automatic-routes"
;
import
queryModifier
from
"#middlewares/request"
;
export
default
(
_express
:
Application
)
=>
{
const
rolesProvider
=
new
RolesProvider
();
return
<
Resource
>
{
/**
* @openapi
* /api/v1.0/roles:
* get:
* tags: [Roles]
* parameters:
* - $ref: '#/components/parameters/filters'
* - $ref: '#/components/parameters/sort'
* - $ref: '#/components/parameters/page'
* - $ref: '#/components/parameters/pageSize'
* responses:
* 200:
* description: Trả về danh sách vai trò thành công
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/RoleListResponse"
*/
get
:
{
middleware
:
[
queryModifier
],
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
try
{
const
roles
=
await
rolesProvider
.
getRoles
(
req
.
payload
);
res
.
sendOk
({
data
:
roles
,
message
:
"Lấy danh sách vai trò thành công"
,
message_en
:
"Roles fetched successfully"
,
status
:
200
});
}
catch
(
error
)
{
console
.
error
(
"Error fetching roles:"
,
error
);
res
.
sendError
({
message
:
"Lấy danh sách vai trò thất bại"
,
message_en
:
"Failed to fetch roles"
,
status
:
500
});
}
}
}
};
};
\ No newline at end of file
code/src/controllers/api/v1.0/roles/set-role/index.ts
0 → 100644
View file @
66487b83
import
{
Req
,
Res
}
from
"#interface/IApi"
;
import
{
RolesProvider
}
from
"#providers/RolesProvider.js"
;
import
{
Application
}
from
"express"
;
import
{
Resource
}
from
"express-automatic-routes"
;
import
{
authorize
}
from
"#middlewares/authorization"
;
import
{
authMiddleware
}
from
"#middlewares/authentication"
;
export
default
(
_express
:
Application
)
=>
{
const
rolesProvider
=
new
RolesProvider
();
return
<
Resource
>
{
/**
* @openapi
* /api/v1.0/roles/set-role:
* post:
* tags: [Roles]
* security:
* - bearerAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/setRoleRequest"
* responses:
* 201:
* description: Cập nhật vai trò thành công
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/SetRoleResponse"
*/
post
:
{
middleware
:
[
authMiddleware
,
authorize
(
"admin"
)],
handler
:
async
(
req
:
Req
,
res
:
Res
)
=>
{
try
{
const
setRole
=
await
rolesProvider
.
setRole
(
req
.
body
);
res
.
sendOk
({
data
:
setRole
,
message
:
"Cập nhật vai trò thành công"
,
message_en
:
"Role updated successfully"
,
status
:
201
});
}
catch
(
error
)
{
console
.
error
(
"Error updating role:"
,
error
);
res
.
sendError
({
message
:
"Cập nhật vai trò thất bại"
,
message_en
:
"Failed to update role"
,
status
:
500
});
}
}
}
};
};
\ No newline at end of file
code/src/docs/swagger/swagger-output.json
View file @
66487b83
This diff is collapsed.
Click to expand it.
code/src/middlewares/request.ts
View file @
66487b83
...
@@ -17,21 +17,28 @@ export default function queryModifier(req: Req, _res: Res, next: NextFunction) {
...
@@ -17,21 +17,28 @@ export default function queryModifier(req: Req, _res: Res, next: NextFunction) {
const
arrFilters
=
filters
.
split
(
","
);
const
arrFilters
=
filters
.
split
(
","
);
arrFilters
.
forEach
((
element
)
=>
{
arrFilters
.
forEach
((
element
)
=>
{
// Mỗi phần tử sẽ có dạng: "status|=|published" hoặc "title|like|NodeJS"
// Mỗi phần tử sẽ có dạng: "status == published" hoặc "title @= NodeJS"
const
parts
=
element
.
split
(
"|"
);
const
trimmedElement
=
element
.
trim
();
const
parts
=
trimmedElement
.
match
(
/^
(\S
+
)\s
*
(
==|@=|>=|<=|>|<
)\s
*
(
.+
)
$/i
);
// Phải đủ 3 thành phần: [Tên cột, Toán tử, Giá trị]
// Phải đủ 3 thành phần: [Tên cột, Toán tử, Giá trị]
if
(
parts
.
length
===
3
)
{
if
(
parts
)
{
const
[
field
,
operator
,
value
]
=
parts
as
[
string
,
string
,
string
];
const
field
=
parts
[
1
]?.
trim
();
const
operator
=
parts
[
2
]?.
trim
().
toLowerCase
();
const
value
=
parts
[
3
]?.
trim
();
if
(
!
field
||
!
operator
||
value
===
undefined
)
{
return
;
}
let
condition
:
any
=
{};
let
condition
:
any
=
{};
// Dịch toán tử từ URL sang toán tử Sequelize tương ứng
// Dịch toán tử từ URL sang toán tử Sequelize tương ứng
switch
(
operator
.
toLowerCase
()
)
{
switch
(
operator
)
{
case
"="
:
case
"=
=
"
:
condition
[
field
]
=
{
[
Op
.
eq
]:
value
};
condition
[
field
]
=
{
[
Op
.
eq
]:
value
};
break
;
break
;
case
"
like
"
:
case
"
@=
"
:
condition
[
field
]
=
{
[
Op
.
iLike
]:
`%
${
value
}
%`
};
condition
[
field
]
=
{
[
Op
.
iLike
]:
`%
${
value
}
%`
};
break
;
break
;
case
">"
:
case
">"
:
...
...
code/src/providers/CoursesProvider.ts
View file @
66487b83
...
@@ -13,7 +13,8 @@ export class CoursesProvider {
...
@@ -13,7 +13,8 @@ export class CoursesProvider {
where
:
params
.
filters
,
where
:
params
.
filters
,
order
:
params
.
sortBy
?
[[
params
.
sortBy
,
params
.
sortOrder
]]
:
[[
'created_at'
,
'DESC'
]],
order
:
params
.
sortBy
?
[[
params
.
sortBy
,
params
.
sortOrder
]]
:
[[
'created_at'
,
'DESC'
]],
limit
:
params
.
pageSize
,
limit
:
params
.
pageSize
,
offset
:
(
params
.
page
-
1
)
*
params
.
pageSize
offset
:
(
params
.
page
-
1
)
*
params
.
pageSize
,
raw
:
true
,
});
});
return
{
return
{
count
,
count
,
...
...
code/src/providers/RolesProvider.ts
0 → 100644
View file @
66487b83
import
{
payload
}
from
"#interface/IApi"
;
import
{
models
}
from
"#models/sequelize-config.js"
;
export
class
RolesProvider
{
async
getRoles
(
params
:
payload
)
{
const
{
count
,
rows
}
=
await
models
.
roles
.
findAndCountAll
({
where
:
params
.
filters
,
order
:
params
.
sortBy
?
[[
params
.
sortBy
,
params
.
sortOrder
]]
:
[[
'created_at'
,
'DESC'
]],
limit
:
params
.
pageSize
,
offset
:
(
params
.
page
-
1
)
*
params
.
pageSize
,
raw
:
true
});
return
{
count
,
page
:
params
.
page
,
pageSize
:
params
.
pageSize
,
rows
};
}
async
setRole
(
body
:
{
user_id
:
string
;
role_id
:
string
})
{
const
[
affectedRows
,
updatedUsers
]
=
await
models
.
users
.
update
(
{
role_id
:
body
.
role_id
},
{
where
:
{
id
:
body
.
user_id
},
returning
:
true
,
},
);
return
updatedUsers
[
0
];
}
}
code/src/templates/swagger/config.ts
View file @
66487b83
...
@@ -10,6 +10,7 @@ import sendOTPSchemas from './sendOTP/schema.js';
...
@@ -10,6 +10,7 @@ import sendOTPSchemas from './sendOTP/schema.js';
import
verifyOTPSchemas
from
'./verifyOTP/schema.js'
;
import
verifyOTPSchemas
from
'./verifyOTP/schema.js'
;
import
logoutSchemas
from
'./logout/schema.js'
;
import
logoutSchemas
from
'./logout/schema.js'
;
import
enrollmentSchemas
from
'./enrollment/schema.js'
;
import
enrollmentSchemas
from
'./enrollment/schema.js'
;
import
rolesSchemas
from
'./roles/schema.js'
;
const
swaggerOptions
:
Options
=
{
const
swaggerOptions
:
Options
=
{
definition
:
{
definition
:
{
...
@@ -36,6 +37,7 @@ const swaggerOptions: Options = {
...
@@ -36,6 +37,7 @@ const swaggerOptions: Options = {
...
verifyOTPSchemas
,
...
verifyOTPSchemas
,
...
logoutSchemas
,
...
logoutSchemas
,
...
enrollmentSchemas
,
...
enrollmentSchemas
,
...
rolesSchemas
,
},
},
parameters
:
{
parameters
:
{
filters
:
{
filters
:
{
...
...
code/src/templates/swagger/courses/schemas.ts
View file @
66487b83
...
@@ -10,12 +10,31 @@ const courseSchemas = {
...
@@ -10,12 +10,31 @@ const courseSchemas = {
created_by
:
'2b4f6f8e-19f6-4c5d-93c2-4d7a7c3d1e11'
,
created_by
:
'2b4f6f8e-19f6-4c5d-93c2-4d7a7c3d1e11'
,
},
},
properties
:
{
properties
:
{
id
:
{
type
:
'string'
,
format
:
'uuid'
},
id
:
{
name
:
{
type
:
'string'
},
type
:
'string'
,
description
:
{
type
:
'string'
,
nullable
:
true
},
format
:
'uuid'
status
:
{
type
:
'string'
,
nullable
:
true
},
},
created_at
:
{
type
:
'string'
,
format
:
'date-time'
,
nullable
:
true
},
name
:
{
created_by
:
{
type
:
'string'
,
format
:
'uuid'
,
nullable
:
true
},
type
:
'string'
},
description
:
{
type
:
'string'
,
nullable
:
true
},
status
:
{
type
:
'string'
,
nullable
:
true
},
created_at
:
{
type
:
'string'
,
format
:
'date-time'
,
nullable
:
true
},
created_by
:
{
type
:
'string'
,
format
:
'uuid'
,
nullable
:
true
},
},
},
},
},
CourseResponse
:
{
CourseResponse
:
{
...
@@ -40,23 +59,7 @@ const courseSchemas = {
...
@@ -40,23 +59,7 @@ const courseSchemas = {
type
:
'string'
,
type
:
'string'
,
example
:
'2024-02-26 03:12:45'
,
example
:
'2024-02-26 03:12:45'
,
},
},
violations
:
{
violations
:
{},
type
:
'array'
,
items
:
{
type
:
'object'
,
properties
:
{
code
:
{
type
:
'number'
,
},
message
:
{
type
:
'string'
,
},
action
:
{
nullable
:
true
,
},
},
},
},
},
},
},
},
...
...
code/src/templates/swagger/enrollment/schema.ts
View file @
66487b83
const
enrollmentSchemas
=
{
const
enrollmentSchemas
=
{
EnrollmentInput
:
{
EnrollmentInput
:
{
type
:
'object'
,
type
:
'object'
,
required
:
[
'class_id'
],
example
:
{
example
:
{
class_id
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
class_id
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
},
},
properties
:
{
properties
:
{
class_id
:
{
class_id
:
{
type
:
'string'
,
type
:
'string'
,
format
:
'uuid'
,
example
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
example
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
},
},
},
},
...
@@ -14,6 +16,7 @@ const enrollmentSchemas = {
...
@@ -14,6 +16,7 @@ const enrollmentSchemas = {
UnenrollmentInput
:
{
UnenrollmentInput
:
{
type
:
'object'
,
type
:
'object'
,
required
:
[
'userId'
,
'classId'
],
example
:
{
example
:
{
userId
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
userId
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
classId
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
classId
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
...
@@ -21,10 +24,12 @@ const enrollmentSchemas = {
...
@@ -21,10 +24,12 @@ const enrollmentSchemas = {
properties
:
{
properties
:
{
userId
:
{
userId
:
{
type
:
'string'
,
type
:
'string'
,
format
:
'uuid'
,
example
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
example
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
},
},
classId
:
{
classId
:
{
type
:
'string'
,
type
:
'string'
,
format
:
'uuid'
,
example
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
example
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
},
},
},
},
...
@@ -35,24 +40,45 @@ const enrollmentSchemas = {
...
@@ -35,24 +40,45 @@ const enrollmentSchemas = {
example
:
{
example
:
{
message
:
'Hủy đăng ký khóa học thành công'
,
message
:
'Hủy đăng ký khóa học thành công'
,
},
},
properties
:
{
message
:
{
type
:
'string'
,
example
:
'Hủy đăng ký khóa học thành công'
,
},
},
},
},
Enrollment
:
{
Enrollment
:
{
type
:
'object'
,
type
:
'object'
,
example
:
{
example
:
{
id
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
user_id
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
user_id
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
class_id
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
class_id
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
created_at
:
'2026-05-20T00:00:00.000Z'
,
status
:
'active'
,
status
:
'active'
,
},
},
properties
:
{
properties
:
{
id
:
{
type
:
'string'
,
format
:
'uuid'
,
example
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
},
user_id
:
{
user_id
:
{
type
:
'string'
,
type
:
'string'
,
format
:
'uuid'
,
example
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
example
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
},
},
class_id
:
{
class_id
:
{
type
:
'string'
,
type
:
'string'
,
format
:
'uuid'
,
example
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
example
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
},
},
created_at
:
{
type
:
'string'
,
format
:
'date-time'
,
nullable
:
true
,
example
:
'2026-05-20T00:00:00.000Z'
,
},
status
:
{
status
:
{
type
:
'string'
,
type
:
'string'
,
example
:
'active'
,
example
:
'active'
,
...
@@ -62,12 +88,14 @@ const enrollmentSchemas = {
...
@@ -62,12 +88,14 @@ const enrollmentSchemas = {
AllStudentInClassInput
:
{
AllStudentInClassInput
:
{
type
:
'object'
,
type
:
'object'
,
required
:
[
'class_id'
],
example
:
{
example
:
{
class_id
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
class_id
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
},
},
properties
:
{
properties
:
{
class_id
:
{
class_id
:
{
type
:
'string'
,
type
:
'string'
,
format
:
'uuid'
,
example
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
example
:
'3fa85f64-5717-4562-b3fc-2c963f66afa6'
,
},
},
},
},
...
...
code/src/templates/swagger/roles/schema.ts
0 → 100644
View file @
66487b83
const
rolesSchemas
=
{
RoleListResponse
:
{
type
:
"object"
,
properties
:
{
count
:
{
type
:
"integer"
},
page
:
{
type
:
"integer"
},
pageSize
:
{
type
:
"integer"
},
rows
:
{
type
:
"array"
,
items
:
{
$ref
:
"#/components/schemas/Role"
}
}
}
},
Role
:
{
type
:
"object"
,
properties
:
{
id
:
{
type
:
"string"
},
name
:
{
type
:
"string"
},
description
:
{
type
:
"string"
},
created_at
:
{
type
:
"string"
,
format
:
"date-time"
},
created_by
:
{
type
:
"string"
}
}
},
setRoleRequest
:
{
type
:
"object"
,
properties
:
{
user_id
:
{
type
:
"string"
},
role_id
:
{
type
:
"string"
}
},
required
:
[
"user_id"
,
"role_id"
]
},
SetRoleResponse
:
{
type
:
"object"
,
properties
:
{
message
:
{
type
:
"string"
,
example
:
"Cập nhật vai trò thành công"
},
message_en
:
{
type
:
"string"
,
example
:
"Role updated successfully"
},
responseData
:
{
type
:
"object"
,
properties
:
{
id
:
{
type
:
"string"
,
example
:
"123e4567-e89b-12d3-a456-426614174000"
},
name
:
{
type
:
"string"
,
example
:
"John Doe"
},
date_of_birth
:
{
type
:
"string"
,
format
:
"date-time"
,
example
:
"1990-09-30T17:00:00.000Z"
},
phone
:
{
type
:
"string"
,
example
:
"0901234567"
},
email
:
{
type
:
"string"
,
format
:
"email"
,
example
:
"john.doe@example.com"
},
address
:
{
type
:
"string"
,
example
:
"123 Main St, City, Country"
},
created_at
:
{
type
:
"string"
,
format
:
"date-time"
,
example
:
"2023-01-01T00:00:00.000Z"
},
role_id
:
{
type
:
"string"
,
example
:
"41d5ac41-3ee4-45cb-a381-a83b07694b99"
}
}
},
status
:
{
type
:
"string"
,
example
:
"true"
},
timeStamp
:
{
type
:
"string"
,
example
:
"2026-05-20 13:37:24"
},
violations
:
{
type
:
"array"
,
}
}
}
}
export
default
rolesSchemas
;
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment