Commit f8b76737 authored by ThinhNC's avatar ThinhNC

fix(api,validation): standardize CrawlScheduleController envelope and enforce...

fix(api,validation): standardize CrawlScheduleController envelope and enforce validateParams on all route identifiers
parent 2a7f8a5f
...@@ -83,9 +83,7 @@ ...@@ -83,9 +83,7 @@
"description": "Email hoặc mật khẩu không chính xác" "description": "Email hoặc mật khẩu không chính xác"
} }
}, },
"tags": [ "tags": ["Auth"],
"Auth"
],
"summary": "Đăng nhập người dùng", "summary": "Đăng nhập người dùng",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -141,9 +139,7 @@ ...@@ -141,9 +139,7 @@
} }
} }
}, },
"tags": [ "tags": ["Auth"],
"Auth"
],
"summary": "Làm mới Access Token" "summary": "Làm mới Access Token"
} }
}, },
...@@ -182,9 +178,7 @@ ...@@ -182,9 +178,7 @@
} }
} }
}, },
"tags": [ "tags": ["Auth"],
"Auth"
],
"summary": "Đăng xuất" "summary": "Đăng xuất"
} }
}, },
...@@ -215,9 +209,7 @@ ...@@ -215,9 +209,7 @@
"description": "Chưa xác thực hoặc token không hợp lệ" "description": "Chưa xác thực hoặc token không hợp lệ"
} }
}, },
"tags": [ "tags": ["Auth"],
"Auth"
],
"summary": "Lấy thông tin người dùng hiện tại" "summary": "Lấy thông tin người dùng hiện tại"
}, },
"put": { "put": {
...@@ -249,9 +241,7 @@ ...@@ -249,9 +241,7 @@
"description": "Chưa xác thực" "description": "Chưa xác thực"
} }
}, },
"tags": [ "tags": ["Auth"],
"Auth"
],
"summary": "Cập nhật thông tin cá nhân", "summary": "Cập nhật thông tin cá nhân",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -348,9 +338,7 @@ ...@@ -348,9 +338,7 @@
"description": "Chưa xác thực" "description": "Chưa xác thực"
} }
}, },
"tags": [ "tags": ["Auth"],
"Auth"
],
"summary": "Xem hạn mức và mức độ sử dụng Quota hiện tại" "summary": "Xem hạn mức và mức độ sử dụng Quota hiện tại"
} }
}, },
...@@ -415,9 +403,7 @@ ...@@ -415,9 +403,7 @@
"description": "Chưa xác thực" "description": "Chưa xác thực"
} }
}, },
"tags": [ "tags": ["Auth"],
"Auth"
],
"summary": "Đổi mật khẩu tài khoản", "summary": "Đổi mật khẩu tài khoản",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -458,9 +444,7 @@ ...@@ -458,9 +444,7 @@
"description": "Email đã được sử dụng hoặc dữ liệu không hợp lệ" "description": "Email đã được sử dụng hoặc dữ liệu không hợp lệ"
} }
}, },
"tags": [ "tags": ["Auth"],
"Auth"
],
"summary": "Đăng ký tài khoản mới", "summary": "Đăng ký tài khoản mới",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -502,9 +486,7 @@ ...@@ -502,9 +486,7 @@
"description": "Email không hợp lệ" "description": "Email không hợp lệ"
} }
}, },
"tags": [ "tags": ["Auth"],
"Auth"
],
"summary": "Yêu cầu đặt lại mật khẩu", "summary": "Yêu cầu đặt lại mật khẩu",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -512,9 +494,7 @@ ...@@ -512,9 +494,7 @@
"application/json": { "application/json": {
"schema": { "schema": {
"type": "object", "type": "object",
"required": [ "required": ["email"],
"email"
],
"properties": { "properties": {
"email": { "email": {
"type": "string", "type": "string",
...@@ -556,9 +536,7 @@ ...@@ -556,9 +536,7 @@
"description": "Token không hợp lệ, đã hết hạn hoặc mật khẩu không đúng định dạng" "description": "Token không hợp lệ, đã hết hạn hoặc mật khẩu không đúng định dạng"
} }
}, },
"tags": [ "tags": ["Auth"],
"Auth"
],
"summary": "Đặt lại mật khẩu mới", "summary": "Đặt lại mật khẩu mới",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -566,10 +544,7 @@ ...@@ -566,10 +544,7 @@
"application/json": { "application/json": {
"schema": { "schema": {
"type": "object", "type": "object",
"required": [ "required": ["token", "password"],
"token",
"password"
],
"properties": { "properties": {
"token": { "token": {
"type": "string", "type": "string",
...@@ -614,9 +589,7 @@ ...@@ -614,9 +589,7 @@
"description": "Địa chỉ email không hợp lệ" "description": "Địa chỉ email không hợp lệ"
} }
}, },
"tags": [ "tags": ["Auth"],
"Auth"
],
"summary": "Gửi lại email xác thực", "summary": "Gửi lại email xác thực",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -658,9 +631,7 @@ ...@@ -658,9 +631,7 @@
"description": "Token không hợp lệ hoặc đã hết hạn" "description": "Token không hợp lệ hoặc đã hết hạn"
} }
}, },
"tags": [ "tags": ["Auth"],
"Auth"
],
"summary": "Xác thực địa chỉ email", "summary": "Xác thực địa chỉ email",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -668,9 +639,7 @@ ...@@ -668,9 +639,7 @@
"application/json": { "application/json": {
"schema": { "schema": {
"type": "object", "type": "object",
"required": [ "required": ["token"],
"token"
],
"properties": { "properties": {
"token": { "token": {
"type": "string", "type": "string",
...@@ -714,9 +683,7 @@ ...@@ -714,9 +683,7 @@
"description": "Chưa xác thực hoặc mật khẩu không chính xác" "description": "Chưa xác thực hoặc mật khẩu không chính xác"
} }
}, },
"tags": [ "tags": ["Auth"],
"Auth"
],
"summary": "Yêu cầu vô hiệu hóa tài khoản", "summary": "Yêu cầu vô hiệu hóa tài khoản",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -758,9 +725,7 @@ ...@@ -758,9 +725,7 @@
"description": "Mã xác nhận không hợp lệ, đã hết hạn hoặc tài khoản đã bị vô hiệu hóa" "description": "Mã xác nhận không hợp lệ, đã hết hạn hoặc tài khoản đã bị vô hiệu hóa"
} }
}, },
"tags": [ "tags": ["Auth"],
"Auth"
],
"summary": "Xác nhận vô hiệu hóa tài khoản", "summary": "Xác nhận vô hiệu hóa tài khoản",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -857,9 +822,7 @@ ...@@ -857,9 +822,7 @@
"description": "Không có quyền truy cập" "description": "Không có quyền truy cập"
} }
}, },
"tags": [ "tags": ["Users"],
"Users"
],
"summary": "Lấy danh sách người dùng" "summary": "Lấy danh sách người dùng"
}, },
"post": { "post": {
...@@ -904,9 +867,7 @@ ...@@ -904,9 +867,7 @@
} }
} }
}, },
"tags": [ "tags": ["Users"],
"Users"
],
"summary": "Tạo người dùng mới" "summary": "Tạo người dùng mới"
} }
}, },
...@@ -954,9 +915,7 @@ ...@@ -954,9 +915,7 @@
"description": "Không tìm thấy người dùng" "description": "Không tìm thấy người dùng"
} }
}, },
"tags": [ "tags": ["Users"],
"Users"
],
"summary": "Lấy thông tin người dùng theo ID" "summary": "Lấy thông tin người dùng theo ID"
}, },
"put": { "put": {
...@@ -1009,9 +968,7 @@ ...@@ -1009,9 +968,7 @@
} }
} }
}, },
"tags": [ "tags": ["Users"],
"Users"
],
"summary": "Cập nhật thông tin người dùng" "summary": "Cập nhật thông tin người dùng"
}, },
"delete": { "delete": {
...@@ -1052,9 +1009,7 @@ ...@@ -1052,9 +1009,7 @@
"description": "Không tìm thấy người dùng" "description": "Không tìm thấy người dùng"
} }
}, },
"tags": [ "tags": ["Users"],
"Users"
],
"summary": "Xóa người dùng" "summary": "Xóa người dùng"
} }
}, },
...@@ -1083,9 +1038,7 @@ ...@@ -1083,9 +1038,7 @@
"description": "Không có quyền users.roles.read" "description": "Không có quyền users.roles.read"
} }
}, },
"tags": [ "tags": ["Users"],
"Users"
],
"summary": "Xem Roles của User" "summary": "Xem Roles của User"
}, },
"put": { "put": {
...@@ -1118,9 +1071,7 @@ ...@@ -1118,9 +1071,7 @@
"description": "Không tìm thấy User hoặc Role" "description": "Không tìm thấy User hoặc Role"
} }
}, },
"tags": [ "tags": ["Users"],
"Users"
],
"summary": "Cập nhật toàn bộ Roles của User", "summary": "Cập nhật toàn bộ Roles của User",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -1171,9 +1122,7 @@ ...@@ -1171,9 +1122,7 @@
"description": "Không tìm thấy User hoặc Role" "description": "Không tìm thấy User hoặc Role"
} }
}, },
"tags": [ "tags": ["Users"],
"Users"
],
"summary": "Gán thêm một Role cho User" "summary": "Gán thêm một Role cho User"
}, },
"delete": { "delete": {
...@@ -1215,9 +1164,7 @@ ...@@ -1215,9 +1164,7 @@
"description": "Không tìm thấy User hoặc Role" "description": "Không tìm thấy User hoặc Role"
} }
}, },
"tags": [ "tags": ["Users"],
"Users"
],
"summary": "Gỡ một Role khỏi User" "summary": "Gỡ một Role khỏi User"
} }
}, },
...@@ -1274,9 +1221,7 @@ ...@@ -1274,9 +1221,7 @@
"description": "Không có quyền roles.read" "description": "Không có quyền roles.read"
} }
}, },
"tags": [ "tags": ["Roles"],
"Roles"
],
"summary": "Danh sách Roles" "summary": "Danh sách Roles"
}, },
"post": { "post": {
...@@ -1298,9 +1243,7 @@ ...@@ -1298,9 +1243,7 @@
"description": "Role slug đã tồn tại" "description": "Role slug đã tồn tại"
} }
}, },
"tags": [ "tags": ["Roles"],
"Roles"
],
"summary": "Tạo Role tùy chỉnh", "summary": "Tạo Role tùy chỉnh",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -1342,9 +1285,7 @@ ...@@ -1342,9 +1285,7 @@
"description": "Không tìm thấy Role" "description": "Không tìm thấy Role"
} }
}, },
"tags": [ "tags": ["Roles"],
"Roles"
],
"summary": "Chi tiết Role" "summary": "Chi tiết Role"
}, },
"patch": { "patch": {
...@@ -1377,9 +1318,7 @@ ...@@ -1377,9 +1318,7 @@
"description": "Không tìm thấy Role" "description": "Không tìm thấy Role"
} }
}, },
"tags": [ "tags": ["Roles"],
"Roles"
],
"summary": "Cập nhật Role", "summary": "Cập nhật Role",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -1422,9 +1361,7 @@ ...@@ -1422,9 +1361,7 @@
"description": "Không tìm thấy Role" "description": "Không tìm thấy Role"
} }
}, },
"tags": [ "tags": ["Roles"],
"Roles"
],
"summary": "Xóa Role" "summary": "Xóa Role"
} }
}, },
...@@ -1456,9 +1393,7 @@ ...@@ -1456,9 +1393,7 @@
"description": "Không tìm thấy Role" "description": "Không tìm thấy Role"
} }
}, },
"tags": [ "tags": ["Roles"],
"Roles"
],
"summary": "Xem danh sách Permissions của Role" "summary": "Xem danh sách Permissions của Role"
}, },
"put": { "put": {
...@@ -1488,9 +1423,7 @@ ...@@ -1488,9 +1423,7 @@
"description": "Không tìm thấy Role" "description": "Không tìm thấy Role"
} }
}, },
"tags": [ "tags": ["Roles"],
"Roles"
],
"summary": "Gán danh sách Permissions cho Role", "summary": "Gán danh sách Permissions cho Role",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -1529,9 +1462,7 @@ ...@@ -1529,9 +1462,7 @@
"description": "Không có quyền roles.read" "description": "Không có quyền roles.read"
} }
}, },
"tags": [ "tags": ["Roles"],
"Roles"
],
"summary": "Danh sách Users thuộc Role" "summary": "Danh sách Users thuộc Role"
} }
}, },
...@@ -1565,9 +1496,7 @@ ...@@ -1565,9 +1496,7 @@
"description": "Không có quyền permissions.read" "description": "Không có quyền permissions.read"
} }
}, },
"tags": [ "tags": ["Permissions"],
"Permissions"
],
"summary": "Danh mục Permissions hệ thống" "summary": "Danh mục Permissions hệ thống"
} }
}, },
...@@ -1599,9 +1528,7 @@ ...@@ -1599,9 +1528,7 @@
"description": "Không tìm thấy Permission" "description": "Không tìm thấy Permission"
} }
}, },
"tags": [ "tags": ["Permissions"],
"Permissions"
],
"summary": "Chi tiết Permission" "summary": "Chi tiết Permission"
} }
}, },
...@@ -1654,9 +1581,7 @@ ...@@ -1654,9 +1581,7 @@
"description": "Chưa xác thực" "description": "Chưa xác thực"
} }
}, },
"tags": [ "tags": ["Crawl Jobs"],
"Crawl Jobs"
],
"summary": "Tạo crawl job mới", "summary": "Tạo crawl job mới",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -1745,9 +1670,7 @@ ...@@ -1745,9 +1670,7 @@
} }
} }
}, },
"tags": [ "tags": ["Crawl Jobs"],
"Crawl Jobs"
],
"summary": "Lấy danh sách các crawl jobs" "summary": "Lấy danh sách các crawl jobs"
} }
}, },
...@@ -1789,9 +1712,7 @@ ...@@ -1789,9 +1712,7 @@
"description": "Không tìm thấy crawl job hoặc không có quyền truy cập" "description": "Không tìm thấy crawl job hoặc không có quyền truy cập"
} }
}, },
"tags": [ "tags": ["Crawl Jobs"],
"Crawl Jobs"
],
"summary": "Lấy thông tin chi tiết một crawl job" "summary": "Lấy thông tin chi tiết một crawl job"
}, },
"delete": { "delete": {
...@@ -1942,9 +1863,7 @@ ...@@ -1942,9 +1863,7 @@
"description": "Không tìm thấy crawl job" "description": "Không tìm thấy crawl job"
} }
}, },
"tags": [ "tags": ["Crawl Jobs"],
"Crawl Jobs"
],
"summary": "Hủy một crawl job đang chạy" "summary": "Hủy một crawl job đang chạy"
} }
}, },
...@@ -2148,10 +2067,7 @@ ...@@ -2148,10 +2067,7 @@
"in": "query", "in": "query",
"schema": { "schema": {
"type": "string", "type": "string",
"enum": [ "enum": ["asc", "desc"],
"asc",
"desc"
],
"default": "asc" "default": "asc"
}, },
"description": "Thứ tự sắp xếp" "description": "Thứ tự sắp xếp"
...@@ -2212,9 +2128,7 @@ ...@@ -2212,9 +2128,7 @@
} }
} }
}, },
"tags": [ "tags": ["Crawl Jobs"],
"Crawl Jobs"
],
"summary": "Lấy danh sách các trang đã crawl của job" "summary": "Lấy danh sách các trang đã crawl của job"
} }
}, },
...@@ -2418,10 +2332,7 @@ ...@@ -2418,10 +2332,7 @@
"in": "query", "in": "query",
"schema": { "schema": {
"type": "string", "type": "string",
"enum": [ "enum": ["asc", "desc"],
"asc",
"desc"
],
"default": "asc" "default": "asc"
}, },
"description": "Thứ tự sắp xếp" "description": "Thứ tự sắp xếp"
...@@ -2556,9 +2467,7 @@ ...@@ -2556,9 +2467,7 @@
"description": "Không tìm thấy crawl job hoặc không có quyền truy cập" "description": "Không tìm thấy crawl job hoặc không có quyền truy cập"
} }
}, },
"tags": [ "tags": ["Crawl Jobs"],
"Crawl Jobs"
],
"summary": "Xem preview dữ liệu clean/raw của các trang đã crawl" "summary": "Xem preview dữ liệu clean/raw của các trang đã crawl"
} }
}, },
...@@ -2600,9 +2509,7 @@ ...@@ -2600,9 +2509,7 @@
} }
} }
}, },
"tags": [ "tags": ["Crawl Jobs"],
"Crawl Jobs"
],
"summary": "Lấy danh sách các bản export của job" "summary": "Lấy danh sách các bản export của job"
}, },
"post": { "post": {
...@@ -2639,9 +2546,7 @@ ...@@ -2639,9 +2546,7 @@
} }
} }
}, },
"tags": [ "tags": ["Crawl Jobs"],
"Crawl Jobs"
],
"summary": "Yêu cầu xuất dữ liệu cho job", "summary": "Yêu cầu xuất dữ liệu cho job",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -2680,9 +2585,7 @@ ...@@ -2680,9 +2585,7 @@
} }
} }
}, },
"tags": [ "tags": ["Crawl Jobs"],
"Crawl Jobs"
],
"summary": "Tải xuống file export mới nhất" "summary": "Tải xuống file export mới nhất"
} }
}, },
...@@ -2723,14 +2626,7 @@ ...@@ -2723,14 +2626,7 @@
"required": false, "required": false,
"schema": { "schema": {
"type": "string", "type": "string",
"enum": [ "enum": ["IMAGE", "LINK", "PDF", "FILE", "VIDEO", "OTHER"]
"IMAGE",
"LINK",
"PDF",
"FILE",
"VIDEO",
"OTHER"
]
}, },
"description": "Lọc theo loại asset" "description": "Lọc theo loại asset"
} }
...@@ -2822,9 +2718,7 @@ ...@@ -2822,9 +2718,7 @@
"description": "Không tìm thấy crawl job hoặc không có quyền truy cập" "description": "Không tìm thấy crawl job hoặc không có quyền truy cập"
} }
}, },
"tags": [ "tags": ["Crawl Jobs"],
"Crawl Jobs"
],
"summary": "Lấy danh sách assets của job (có phân trang)" "summary": "Lấy danh sách assets của job (có phân trang)"
} }
}, },
...@@ -2877,9 +2771,7 @@ ...@@ -2877,9 +2771,7 @@
"description": "Không tìm thấy crawl job" "description": "Không tìm thấy crawl job"
} }
}, },
"tags": [ "tags": ["Crawl Jobs"],
"Crawl Jobs"
],
"summary": "Xem báo cáo thay đổi (Diff Report)" "summary": "Xem báo cáo thay đổi (Diff Report)"
} }
}, },
...@@ -2924,9 +2816,7 @@ ...@@ -2924,9 +2816,7 @@
"description": "Không tìm thấy crawl job hoặc diff report" "description": "Không tìm thấy crawl job hoặc diff report"
} }
}, },
"tags": [ "tags": ["Crawl Jobs"],
"Crawl Jobs"
],
"summary": "Tải file diff_report.json" "summary": "Tải file diff_report.json"
} }
}, },
...@@ -2968,9 +2858,7 @@ ...@@ -2968,9 +2858,7 @@
"description": "Chưa xác thực" "description": "Chưa xác thực"
} }
}, },
"tags": [ "tags": ["Crawl Schedules"],
"Crawl Schedules"
],
"summary": "Tạo lịch crawl định kỳ mới", "summary": "Tạo lịch crawl định kỳ mới",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -2999,12 +2887,7 @@ ...@@ -2999,12 +2887,7 @@
"in": "query", "in": "query",
"schema": { "schema": {
"type": "string", "type": "string",
"enum": [ "enum": ["DAILY", "WEEKLY", "MONTHLY", "CUSTOM"]
"DAILY",
"WEEKLY",
"MONTHLY",
"CUSTOM"
]
}, },
"description": "Lọc theo tần suất" "description": "Lọc theo tần suất"
}, },
...@@ -3073,9 +2956,7 @@ ...@@ -3073,9 +2956,7 @@
"description": "Chưa xác thực" "description": "Chưa xác thực"
} }
}, },
"tags": [ "tags": ["Crawl Schedules"],
"Crawl Schedules"
],
"summary": "Lấy danh sách lịch crawl định kỳ" "summary": "Lấy danh sách lịch crawl định kỳ"
} }
}, },
...@@ -3111,9 +2992,7 @@ ...@@ -3111,9 +2992,7 @@
"description": "Không tìm thấy lịch crawl" "description": "Không tìm thấy lịch crawl"
} }
}, },
"tags": [ "tags": ["Crawl Schedules"],
"Crawl Schedules"
],
"summary": "Xem chi tiết lịch crawl" "summary": "Xem chi tiết lịch crawl"
}, },
"patch": { "patch": {
...@@ -3158,9 +3037,7 @@ ...@@ -3158,9 +3037,7 @@
"description": "Không tìm thấy lịch crawl" "description": "Không tìm thấy lịch crawl"
} }
}, },
"tags": [ "tags": ["Crawl Schedules"],
"Crawl Schedules"
],
"summary": "Cập nhật lịch crawl", "summary": "Cập nhật lịch crawl",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -3210,9 +3087,7 @@ ...@@ -3210,9 +3087,7 @@
"description": "Không tìm thấy lịch crawl" "description": "Không tìm thấy lịch crawl"
} }
}, },
"tags": [ "tags": ["Crawl Schedules"],
"Crawl Schedules"
],
"summary": "Xóa lịch crawl" "summary": "Xóa lịch crawl"
} }
}, },
...@@ -3257,9 +3132,7 @@ ...@@ -3257,9 +3132,7 @@
"description": "Không tìm thấy lịch crawl" "description": "Không tìm thấy lịch crawl"
} }
}, },
"tags": [ "tags": ["Crawl Schedules"],
"Crawl Schedules"
],
"summary": "Kích hoạt chạy ngay lịch crawl" "summary": "Kích hoạt chạy ngay lịch crawl"
} }
}, },
...@@ -3336,9 +3209,7 @@ ...@@ -3336,9 +3209,7 @@
"description": "Không tìm thấy lịch crawl" "description": "Không tìm thấy lịch crawl"
} }
}, },
"tags": [ "tags": ["Crawl Schedules"],
"Crawl Schedules"
],
"summary": "Xem lịch sử các lần chạy của lịch crawl" "summary": "Xem lịch sử các lần chạy của lịch crawl"
} }
}, },
...@@ -3380,9 +3251,7 @@ ...@@ -3380,9 +3251,7 @@
"description": "Không tìm thấy file export" "description": "Không tìm thấy file export"
} }
}, },
"tags": [ "tags": ["Crawl Exports"],
"Crawl Exports"
],
"summary": "Tải xuống tệp export theo ID" "summary": "Tải xuống tệp export theo ID"
} }
}, },
...@@ -3520,9 +3389,7 @@ ...@@ -3520,9 +3389,7 @@
"description": "Không có quyền truy cập (không phải ADMIN)" "description": "Không có quyền truy cập (không phải ADMIN)"
} }
}, },
"tags": [ "tags": ["Audit Logs"],
"Audit Logs"
],
"summary": "Lấy danh sách nhật ký hệ thống" "summary": "Lấy danh sách nhật ký hệ thống"
} }
}, },
...@@ -3556,9 +3423,7 @@ ...@@ -3556,9 +3423,7 @@
"description": "Dữ liệu không hợp lệ hoặc thời điểm hết hạn không ở trong tương lai" "description": "Dữ liệu không hợp lệ hoặc thời điểm hết hạn không ở trong tương lai"
} }
}, },
"tags": [ "tags": ["API Keys"],
"API Keys"
],
"security": [ "security": [
{ {
"BearerAuth": [] "BearerAuth": []
...@@ -3605,9 +3470,7 @@ ...@@ -3605,9 +3470,7 @@
"description": "Chưa xác thực" "description": "Chưa xác thực"
} }
}, },
"tags": [ "tags": ["API Keys"],
"API Keys"
],
"security": [ "security": [
{ {
"BearerAuth": [] "BearerAuth": []
...@@ -3661,9 +3524,7 @@ ...@@ -3661,9 +3524,7 @@
"description": "Trạng thái không hợp lệ" "description": "Trạng thái không hợp lệ"
} }
}, },
"tags": [ "tags": ["API Keys"],
"API Keys"
],
"security": [ "security": [
{ {
"BearerAuth": [] "BearerAuth": []
...@@ -3722,9 +3583,7 @@ ...@@ -3722,9 +3583,7 @@
"description": "Không tìm thấy API Key" "description": "Không tìm thấy API Key"
} }
}, },
"tags": [ "tags": ["API Keys"],
"API Keys"
],
"security": [ "security": [
{ {
"BearerAuth": [] "BearerAuth": []
...@@ -3763,9 +3622,7 @@ ...@@ -3763,9 +3622,7 @@
"description": "Chưa xác thực" "description": "Chưa xác thực"
} }
}, },
"tags": [ "tags": ["Webhooks"],
"Webhooks"
],
"summary": "Tạo cấu hình Webhook", "summary": "Tạo cấu hình Webhook",
"requestBody": { "requestBody": {
"required": true, "required": true,
...@@ -3807,9 +3664,7 @@ ...@@ -3807,9 +3664,7 @@
"description": "Chưa xác thực" "description": "Chưa xác thực"
} }
}, },
"tags": [ "tags": ["Webhooks"],
"Webhooks"
],
"summary": "Xem danh sách Webhook configs" "summary": "Xem danh sách Webhook configs"
} }
}, },
...@@ -3872,9 +3727,7 @@ ...@@ -3872,9 +3727,7 @@
"description": "Không tìm thấy cấu hình Webhook" "description": "Không tìm thấy cấu hình Webhook"
} }
}, },
"tags": [ "tags": ["Webhooks"],
"Webhooks"
],
"summary": "Xóa cấu hình Webhook" "summary": "Xóa cấu hình Webhook"
} }
}, },
...@@ -3946,9 +3799,7 @@ ...@@ -3946,9 +3799,7 @@
"description": "Chưa xác thực" "description": "Chưa xác thực"
} }
}, },
"tags": [ "tags": ["Webhooks"],
"Webhooks"
],
"summary": "Xem lịch sử gửi Webhook" "summary": "Xem lịch sử gửi Webhook"
} }
}, },
...@@ -4079,11 +3930,7 @@ ...@@ -4079,11 +3930,7 @@
}, },
"role": { "role": {
"type": "string", "type": "string",
"enum": [ "enum": ["ADMIN", "CRAWLER_USER", "VIEWER"]
"ADMIN",
"CRAWLER_USER",
"VIEWER"
]
}, },
"isActive": { "isActive": {
"type": "boolean" "type": "boolean"
...@@ -4112,12 +3959,7 @@ ...@@ -4112,12 +3959,7 @@
}, },
"mode": { "mode": {
"type": "string", "type": "string",
"enum": [ "enum": ["SCRAPE", "CRAWL", "SITEMAP", "URL_LIST"]
"SCRAPE",
"CRAWL",
"SITEMAP",
"URL_LIST"
]
}, },
"status": { "status": {
"type": "string", "type": "string",
...@@ -4328,10 +4170,7 @@ ...@@ -4328,10 +4170,7 @@
}, },
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": ["internal", "external"]
"internal",
"external"
]
} }
} }
} }
...@@ -4417,21 +4256,11 @@ ...@@ -4417,21 +4256,11 @@
}, },
"exportType": { "exportType": {
"type": "string", "type": "string",
"enum": [ "enum": ["JSON", "CSV", "XLSX", "MARKDOWN", "ZIP"]
"JSON",
"CSV",
"XLSX",
"MARKDOWN",
"ZIP"
]
}, },
"status": { "status": {
"type": "string", "type": "string",
"enum": [ "enum": ["PENDING", "COMPLETED", "FAILED"]
"PENDING",
"COMPLETED",
"FAILED"
]
}, },
"fileName": { "fileName": {
"type": "string" "type": "string"
...@@ -4454,10 +4283,7 @@ ...@@ -4454,10 +4283,7 @@
}, },
"LoginRequest": { "LoginRequest": {
"type": "object", "type": "object",
"required": [ "required": ["email", "password"],
"email",
"password"
],
"properties": { "properties": {
"email": { "email": {
"type": "string", "type": "string",
...@@ -4472,10 +4298,7 @@ ...@@ -4472,10 +4298,7 @@
}, },
"RegisterRequest": { "RegisterRequest": {
"type": "object", "type": "object",
"required": [ "required": ["email", "password"],
"email",
"password"
],
"properties": { "properties": {
"email": { "email": {
"type": "string", "type": "string",
...@@ -4494,9 +4317,7 @@ ...@@ -4494,9 +4317,7 @@
}, },
"ResendVerificationRequest": { "ResendVerificationRequest": {
"type": "object", "type": "object",
"required": [ "required": ["email"],
"email"
],
"properties": { "properties": {
"email": { "email": {
"type": "string", "type": "string",
...@@ -4507,9 +4328,7 @@ ...@@ -4507,9 +4328,7 @@
}, },
"RequestDeactivationRequest": { "RequestDeactivationRequest": {
"type": "object", "type": "object",
"required": [ "required": ["password"],
"password"
],
"properties": { "properties": {
"password": { "password": {
"type": "string", "type": "string",
...@@ -4520,9 +4339,7 @@ ...@@ -4520,9 +4339,7 @@
}, },
"ConfirmDeactivationRequest": { "ConfirmDeactivationRequest": {
"type": "object", "type": "object",
"required": [ "required": ["token"],
"token"
],
"properties": { "properties": {
"token": { "token": {
"type": "string", "type": "string",
...@@ -4533,9 +4350,7 @@ ...@@ -4533,9 +4350,7 @@
}, },
"RefreshRequest": { "RefreshRequest": {
"type": "object", "type": "object",
"required": [ "required": ["refreshToken"],
"refreshToken"
],
"properties": { "properties": {
"refreshToken": { "refreshToken": {
"type": "string", "type": "string",
...@@ -4545,9 +4360,7 @@ ...@@ -4545,9 +4360,7 @@
}, },
"LogoutRequest": { "LogoutRequest": {
"type": "object", "type": "object",
"required": [ "required": ["refreshToken"],
"refreshToken"
],
"properties": { "properties": {
"refreshToken": { "refreshToken": {
"type": "string", "type": "string",
...@@ -4566,11 +4379,7 @@ ...@@ -4566,11 +4379,7 @@
}, },
"ChangePasswordRequest": { "ChangePasswordRequest": {
"type": "object", "type": "object",
"required": [ "required": ["currentPassword", "newPassword", "confirmPassword"],
"currentPassword",
"newPassword",
"confirmPassword"
],
"properties": { "properties": {
"currentPassword": { "currentPassword": {
"type": "string", "type": "string",
...@@ -4588,10 +4397,7 @@ ...@@ -4588,10 +4397,7 @@
}, },
"CreateUserRequest": { "CreateUserRequest": {
"type": "object", "type": "object",
"required": [ "required": ["email", "password"],
"email",
"password"
],
"properties": { "properties": {
"email": { "email": {
"type": "string", "type": "string",
...@@ -4608,11 +4414,7 @@ ...@@ -4608,11 +4414,7 @@
}, },
"role": { "role": {
"type": "string", "type": "string",
"enum": [ "enum": ["ADMIN", "CRAWLER_USER", "VIEWER"],
"ADMIN",
"CRAWLER_USER",
"VIEWER"
],
"example": "CRAWLER_USER" "example": "CRAWLER_USER"
}, },
"maxPagesLimit": { "maxPagesLimit": {
...@@ -4638,11 +4440,7 @@ ...@@ -4638,11 +4440,7 @@
}, },
"role": { "role": {
"type": "string", "type": "string",
"enum": [ "enum": ["ADMIN", "CRAWLER_USER", "VIEWER"],
"ADMIN",
"CRAWLER_USER",
"VIEWER"
],
"example": "VIEWER" "example": "VIEWER"
}, },
"isActive": { "isActive": {
...@@ -4673,12 +4471,7 @@ ...@@ -4673,12 +4471,7 @@
}, },
"mode": { "mode": {
"type": "string", "type": "string",
"enum": [ "enum": ["SCRAPE", "CRAWL", "SITEMAP", "URL_LIST"],
"SCRAPE",
"CRAWL",
"SITEMAP",
"URL_LIST"
],
"example": "CRAWL" "example": "CRAWL"
}, },
"maxPages": { "maxPages": {
...@@ -4699,38 +4492,25 @@ ...@@ -4699,38 +4492,25 @@
"type": "string", "type": "string",
"format": "uri" "format": "uri"
}, },
"example": [ "example": ["https://example.com/1", "https://example.com/2"],
"https://example.com/1",
"https://example.com/2"
],
"description": "Bắt buộc khi mode là URL_LIST" "description": "Bắt buộc khi mode là URL_LIST"
} }
} }
}, },
"CreateExportRequest": { "CreateExportRequest": {
"type": "object", "type": "object",
"required": [ "required": ["exportType"],
"exportType"
],
"properties": { "properties": {
"exportType": { "exportType": {
"type": "string", "type": "string",
"enum": [ "enum": ["JSON", "CSV", "XLSX", "MARKDOWN", "ZIP"],
"JSON",
"CSV",
"XLSX",
"MARKDOWN",
"ZIP"
],
"example": "JSON" "example": "JSON"
} }
} }
}, },
"CreateApiKeyRequest": { "CreateApiKeyRequest": {
"type": "object", "type": "object",
"required": [ "required": ["name"],
"name"
],
"properties": { "properties": {
"name": { "name": {
"type": "string", "type": "string",
...@@ -4749,9 +4529,7 @@ ...@@ -4749,9 +4529,7 @@
}, },
"UpdateApiKeyStatusRequest": { "UpdateApiKeyStatusRequest": {
"type": "object", "type": "object",
"required": [ "required": ["isActive"],
"isActive"
],
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"isActive": { "isActive": {
...@@ -4848,11 +4626,7 @@ ...@@ -4848,11 +4626,7 @@
}, },
"CreateWebhookConfigRequest": { "CreateWebhookConfigRequest": {
"type": "object", "type": "object",
"required": [ "required": ["url", "secret", "events"],
"url",
"secret",
"events"
],
"properties": { "properties": {
"url": { "url": {
"type": "string", "type": "string",
...@@ -4867,15 +4641,9 @@ ...@@ -4867,15 +4641,9 @@
"type": "array", "type": "array",
"items": { "items": {
"type": "string", "type": "string",
"enum": [ "enum": ["job.completed", "job.failed"]
"job.completed",
"job.failed"
]
}, },
"example": [ "example": ["job.completed", "job.failed"]
"job.completed",
"job.failed"
]
} }
} }
}, },
...@@ -4936,11 +4704,7 @@ ...@@ -4936,11 +4704,7 @@
}, },
"status": { "status": {
"type": "string", "type": "string",
"enum": [ "enum": ["PENDING", "SUCCESS", "FAILED"]
"PENDING",
"SUCCESS",
"FAILED"
]
}, },
"statusCode": { "statusCode": {
"type": "integer", "type": "integer",
...@@ -5004,21 +4768,11 @@ ...@@ -5004,21 +4768,11 @@
}, },
"mode": { "mode": {
"type": "string", "type": "string",
"enum": [ "enum": ["SCRAPE", "CRAWL", "SITEMAP", "URL_LIST"]
"SCRAPE",
"CRAWL",
"SITEMAP",
"URL_LIST"
]
}, },
"frequency": { "frequency": {
"type": "string", "type": "string",
"enum": [ "enum": ["DAILY", "WEEKLY", "MONTHLY", "CUSTOM"]
"DAILY",
"WEEKLY",
"MONTHLY",
"CUSTOM"
]
}, },
"cronExpression": { "cronExpression": {
"type": "string", "type": "string",
...@@ -5081,10 +4835,7 @@ ...@@ -5081,10 +4835,7 @@
}, },
"CreateCrawlScheduleRequest": { "CreateCrawlScheduleRequest": {
"type": "object", "type": "object",
"required": [ "required": ["name", "startUrl"],
"name",
"startUrl"
],
"properties": { "properties": {
"name": { "name": {
"type": "string", "type": "string",
...@@ -5097,22 +4848,12 @@ ...@@ -5097,22 +4848,12 @@
}, },
"mode": { "mode": {
"type": "string", "type": "string",
"enum": [ "enum": ["SCRAPE", "CRAWL", "SITEMAP", "URL_LIST"],
"SCRAPE",
"CRAWL",
"SITEMAP",
"URL_LIST"
],
"example": "CRAWL" "example": "CRAWL"
}, },
"frequency": { "frequency": {
"type": "string", "type": "string",
"enum": [ "enum": ["DAILY", "WEEKLY", "MONTHLY", "CUSTOM"],
"DAILY",
"WEEKLY",
"MONTHLY",
"CUSTOM"
],
"example": "DAILY" "example": "DAILY"
}, },
"cronExpression": { "cronExpression": {
...@@ -5175,21 +4916,11 @@ ...@@ -5175,21 +4916,11 @@
}, },
"mode": { "mode": {
"type": "string", "type": "string",
"enum": [ "enum": ["SCRAPE", "CRAWL", "SITEMAP", "URL_LIST"]
"SCRAPE",
"CRAWL",
"SITEMAP",
"URL_LIST"
]
}, },
"frequency": { "frequency": {
"type": "string", "type": "string",
"enum": [ "enum": ["DAILY", "WEEKLY", "MONTHLY", "CUSTOM"]
"DAILY",
"WEEKLY",
"MONTHLY",
"CUSTOM"
]
}, },
"cronExpression": { "cronExpression": {
"type": "string" "type": "string"
...@@ -5389,10 +5120,7 @@ ...@@ -5389,10 +5120,7 @@
}, },
"CreateRoleRequest": { "CreateRoleRequest": {
"type": "object", "type": "object",
"required": [ "required": ["name", "slug"],
"name",
"slug"
],
"properties": { "properties": {
"name": { "name": {
"type": "string", "type": "string",
...@@ -5431,9 +5159,7 @@ ...@@ -5431,9 +5159,7 @@
}, },
"AssignRolePermissionsRequest": { "AssignRolePermissionsRequest": {
"type": "object", "type": "object",
"required": [ "required": ["permissionIds"],
"permissionIds"
],
"properties": { "properties": {
"permissionIds": { "permissionIds": {
"type": "array", "type": "array",
...@@ -5446,9 +5172,7 @@ ...@@ -5446,9 +5172,7 @@
}, },
"AssignUserRolesRequest": { "AssignUserRolesRequest": {
"type": "object", "type": "object",
"required": [ "required": ["roleIds"],
"roleIds"
],
"properties": { "properties": {
"roleIds": { "roleIds": {
"type": "array", "type": "array",
......
...@@ -3,10 +3,14 @@ import { ApiKeyController } from "./api-key.controller"; ...@@ -3,10 +3,14 @@ import { ApiKeyController } from "./api-key.controller";
import { authMiddleware } from "../../middlewares/auth.middleware"; import { authMiddleware } from "../../middlewares/auth.middleware";
import { requirePermission } from "../../middlewares/permission.middleware"; import { requirePermission } from "../../middlewares/permission.middleware";
import { PERMISSIONS } from "../../common/constants/permission.constant"; import { PERMISSIONS } from "../../common/constants/permission.constant";
import { validate } from "../../middlewares/validate.middleware"; import {
validate,
validateParams,
} from "../../middlewares/validate.middleware";
import { import {
createApiKeySchema, createApiKeySchema,
updateApiKeyStatusSchema, updateApiKeyStatusSchema,
apiKeyParamsSchema,
} from "./api-key.validation"; } from "./api-key.validation";
const router = Router(); const router = Router();
...@@ -29,6 +33,7 @@ router.patch( ...@@ -29,6 +33,7 @@ router.patch(
"/:id", "/:id",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.API_KEYS_UPDATE), requirePermission(PERMISSIONS.API_KEYS_UPDATE),
validateParams(apiKeyParamsSchema),
validate(updateApiKeyStatusSchema), validate(updateApiKeyStatusSchema),
controller.setActive, controller.setActive,
); );
...@@ -36,6 +41,7 @@ router.delete( ...@@ -36,6 +41,7 @@ router.delete(
"/:id", "/:id",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.API_KEYS_DELETE), requirePermission(PERMISSIONS.API_KEYS_DELETE),
validateParams(apiKeyParamsSchema),
controller.revoke, controller.revoke,
); );
......
...@@ -24,3 +24,7 @@ export const updateApiKeyStatusSchema = z.object({ ...@@ -24,3 +24,7 @@ export const updateApiKeyStatusSchema = z.object({
invalid_type_error: "API Key status must be a boolean", invalid_type_error: "API Key status must be a boolean",
}), }),
}); });
export const apiKeyParamsSchema = z.object({
id: z.string().uuid("Invalid API key ID format"),
});
import { Router } from "express"; import { Router } from "express";
import { CrawlJobController } from "./crawl-job.controller"; import { CrawlJobController } from "./crawl-job.controller";
import { apiKeyOrAuthMiddleware } from "../../middlewares/api-key.middleware"; import { apiKeyOrAuthMiddleware } from "../../middlewares/api-key.middleware";
import { validate, validateQuery } from "../../middlewares/validate.middleware"; import {
validate,
validateQuery,
validateParams,
} from "../../middlewares/validate.middleware";
import { import {
createCrawlJobSchema, createCrawlJobSchema,
createExportSchema, createExportSchema,
...@@ -9,6 +13,7 @@ import { ...@@ -9,6 +13,7 @@ import {
getAssetsQuerySchema, getAssetsQuerySchema,
jobLogsQuerySchema, jobLogsQuerySchema,
diffQuerySchema, diffQuerySchema,
crawlJobParamsSchema,
} from "./crawl-job.validation"; } from "./crawl-job.validation";
import { crawlPageQuerySchema } from "../crawl-pages/crawl-page.validation"; import { crawlPageQuerySchema } from "../crawl-pages/crawl-page.validation";
import { requirePermission } from "../../middlewares/permission.middleware"; import { requirePermission } from "../../middlewares/permission.middleware";
...@@ -37,24 +42,28 @@ router.get( ...@@ -37,24 +42,28 @@ router.get(
"/:id", "/:id",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_JOBS_READ), requirePermission(PERMISSIONS.CRAWL_JOBS_READ),
validateParams(crawlJobParamsSchema),
controller.findById, controller.findById,
); );
router.delete( router.delete(
"/:id", "/:id",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_JOBS_DELETE), requirePermission(PERMISSIONS.CRAWL_JOBS_DELETE),
validateParams(crawlJobParamsSchema),
controller.delete, controller.delete,
); );
router.post( router.post(
"/:id/rerun", "/:id/rerun",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_JOBS_RETRY), requirePermission(PERMISSIONS.CRAWL_JOBS_RETRY),
validateParams(crawlJobParamsSchema),
controller.rerun, controller.rerun,
); );
router.get( router.get(
"/:id/logs", "/:id/logs",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_JOBS_READ), requirePermission(PERMISSIONS.CRAWL_JOBS_READ),
validateParams(crawlJobParamsSchema),
validateQuery(jobLogsQuerySchema), validateQuery(jobLogsQuerySchema),
controller.getLogs, controller.getLogs,
); );
...@@ -62,18 +71,21 @@ router.get( ...@@ -62,18 +71,21 @@ router.get(
"/:id/events", "/:id/events",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_JOBS_READ), requirePermission(PERMISSIONS.CRAWL_JOBS_READ),
validateParams(crawlJobParamsSchema),
controller.streamEvents, controller.streamEvents,
); );
router.post( router.post(
"/:id/cancel", "/:id/cancel",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_JOBS_CANCEL), requirePermission(PERMISSIONS.CRAWL_JOBS_CANCEL),
validateParams(crawlJobParamsSchema),
controller.cancel, controller.cancel,
); );
router.get( router.get(
"/:id/pages", "/:id/pages",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_JOBS_READ), requirePermission(PERMISSIONS.CRAWL_JOBS_READ),
validateParams(crawlJobParamsSchema),
validateQuery(crawlPageQuerySchema), validateQuery(crawlPageQuerySchema),
controller.getPages, controller.getPages,
); );
...@@ -81,6 +93,7 @@ router.get( ...@@ -81,6 +93,7 @@ router.get(
"/:id/pages/preview", "/:id/pages/preview",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_JOBS_READ), requirePermission(PERMISSIONS.CRAWL_JOBS_READ),
validateParams(crawlJobParamsSchema),
validateQuery(crawlPageQuerySchema), validateQuery(crawlPageQuerySchema),
controller.getPagesPreview, controller.getPagesPreview,
); );
...@@ -88,12 +101,14 @@ router.get( ...@@ -88,12 +101,14 @@ router.get(
"/:id/exports", "/:id/exports",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.EXPORTS_READ), requirePermission(PERMISSIONS.EXPORTS_READ),
validateParams(crawlJobParamsSchema),
controller.getExports, controller.getExports,
); );
router.post( router.post(
"/:id/exports", "/:id/exports",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.EXPORTS_CREATE), requirePermission(PERMISSIONS.EXPORTS_CREATE),
validateParams(crawlJobParamsSchema),
validate(createExportSchema), validate(createExportSchema),
(req, res, next) => { (req, res, next) => {
controller.createExport(req, res, next); controller.createExport(req, res, next);
...@@ -103,12 +118,14 @@ router.get( ...@@ -103,12 +118,14 @@ router.get(
"/:id/download", "/:id/download",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.EXPORTS_DOWNLOAD), requirePermission(PERMISSIONS.EXPORTS_DOWNLOAD),
validateParams(crawlJobParamsSchema),
controller.download, controller.download,
); );
router.get( router.get(
"/:id/assets", "/:id/assets",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_JOBS_READ), requirePermission(PERMISSIONS.CRAWL_JOBS_READ),
validateParams(crawlJobParamsSchema),
validateQuery(getAssetsQuerySchema), validateQuery(getAssetsQuerySchema),
controller.getAssets, controller.getAssets,
); );
...@@ -116,6 +133,7 @@ router.get( ...@@ -116,6 +133,7 @@ router.get(
"/:id/diff", "/:id/diff",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_JOBS_READ), requirePermission(PERMISSIONS.CRAWL_JOBS_READ),
validateParams(crawlJobParamsSchema),
validateQuery(diffQuerySchema), validateQuery(diffQuerySchema),
controller.getDiff, controller.getDiff,
); );
...@@ -123,6 +141,7 @@ router.get( ...@@ -123,6 +141,7 @@ router.get(
"/:id/diff/download", "/:id/diff/download",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_JOBS_READ), requirePermission(PERMISSIONS.CRAWL_JOBS_READ),
validateParams(crawlJobParamsSchema),
validateQuery(diffQuerySchema), validateQuery(diffQuerySchema),
controller.downloadDiff, controller.downloadDiff,
); );
......
...@@ -86,3 +86,7 @@ export const diffQuerySchema = z.object({ ...@@ -86,3 +86,7 @@ export const diffQuerySchema = z.object({
.uuid("Invalid compareWithJobId format") .uuid("Invalid compareWithJobId format")
.optional(), .optional(),
}); });
export const crawlJobParamsSchema = z.object({
id: z.string().uuid("Invalid job ID format"),
});
...@@ -13,6 +13,7 @@ export class CrawlScheduleController { ...@@ -13,6 +13,7 @@ export class CrawlScheduleController {
req.body, req.body,
); );
res.status(201).json({ res.status(201).json({
success: true,
message: "Crawl schedule created successfully", message: "Crawl schedule created successfully",
data: schedule, data: schedule,
}); });
...@@ -28,7 +29,10 @@ export class CrawlScheduleController { ...@@ -28,7 +29,10 @@ export class CrawlScheduleController {
req.user!.role, req.user!.role,
req.query as unknown as CrawlScheduleQueryDto, req.query as unknown as CrawlScheduleQueryDto,
); );
res.json(result); res.json({
success: true,
data: result,
});
} catch (error) { } catch (error) {
next(error); next(error);
} }
...@@ -41,7 +45,10 @@ export class CrawlScheduleController { ...@@ -41,7 +45,10 @@ export class CrawlScheduleController {
req.user!.role, req.user!.role,
req.params.id, req.params.id,
); );
res.json(schedule); res.json({
success: true,
data: schedule,
});
} catch (error) { } catch (error) {
next(error); next(error);
} }
...@@ -56,6 +63,7 @@ export class CrawlScheduleController { ...@@ -56,6 +63,7 @@ export class CrawlScheduleController {
req.body, req.body,
); );
res.json({ res.json({
success: true,
message: "Crawl schedule updated successfully", message: "Crawl schedule updated successfully",
data: updated, data: updated,
}); });
...@@ -68,6 +76,7 @@ export class CrawlScheduleController { ...@@ -68,6 +76,7 @@ export class CrawlScheduleController {
try { try {
await this.service.delete(req.user!.id, req.user!.role, req.params.id); await this.service.delete(req.user!.id, req.user!.role, req.params.id);
res.json({ res.json({
success: true,
message: "Crawl schedule deleted successfully", message: "Crawl schedule deleted successfully",
}); });
} catch (error) { } catch (error) {
...@@ -83,6 +92,7 @@ export class CrawlScheduleController { ...@@ -83,6 +92,7 @@ export class CrawlScheduleController {
req.params.id, req.params.id,
); );
res.status(201).json({ res.status(201).json({
success: true,
message: "Scheduled crawl triggered successfully", message: "Scheduled crawl triggered successfully",
data: job, data: job,
}); });
...@@ -104,7 +114,10 @@ export class CrawlScheduleController { ...@@ -104,7 +114,10 @@ export class CrawlScheduleController {
page, page,
limit, limit,
); );
res.json(history); res.json({
success: true,
data: history,
});
} catch (error) { } catch (error) {
next(error); next(error);
} }
......
import { Router } from "express"; import { Router } from "express";
import { CrawlScheduleController } from "./crawl-schedule.controller"; import { CrawlScheduleController } from "./crawl-schedule.controller";
import { apiKeyOrAuthMiddleware } from "../../middlewares/api-key.middleware"; import { apiKeyOrAuthMiddleware } from "../../middlewares/api-key.middleware";
import { validate, validateQuery } from "../../middlewares/validate.middleware"; import {
validate,
validateQuery,
validateParams,
} from "../../middlewares/validate.middleware";
import { import {
createCrawlScheduleSchema, createCrawlScheduleSchema,
updateCrawlScheduleSchema, updateCrawlScheduleSchema,
crawlScheduleQuerySchema, crawlScheduleQuerySchema,
crawlScheduleHistoryQuerySchema, crawlScheduleHistoryQuerySchema,
crawlScheduleParamsSchema,
} from "./crawl-schedule.validation"; } from "./crawl-schedule.validation";
import { requirePermission } from "../../middlewares/permission.middleware"; import { requirePermission } from "../../middlewares/permission.middleware";
import { PERMISSIONS } from "../../common/constants/permission.constant"; import { PERMISSIONS } from "../../common/constants/permission.constant";
...@@ -34,6 +39,7 @@ router.get( ...@@ -34,6 +39,7 @@ router.get(
"/:id", "/:id",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_SCHEDULES_READ), requirePermission(PERMISSIONS.CRAWL_SCHEDULES_READ),
validateParams(crawlScheduleParamsSchema),
controller.findById, controller.findById,
); );
...@@ -41,6 +47,7 @@ router.patch( ...@@ -41,6 +47,7 @@ router.patch(
"/:id", "/:id",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_SCHEDULES_UPDATE), requirePermission(PERMISSIONS.CRAWL_SCHEDULES_UPDATE),
validateParams(crawlScheduleParamsSchema),
validate(updateCrawlScheduleSchema), validate(updateCrawlScheduleSchema),
controller.update, controller.update,
); );
...@@ -49,6 +56,7 @@ router.delete( ...@@ -49,6 +56,7 @@ router.delete(
"/:id", "/:id",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_SCHEDULES_DELETE), requirePermission(PERMISSIONS.CRAWL_SCHEDULES_DELETE),
validateParams(crawlScheduleParamsSchema),
controller.delete, controller.delete,
); );
...@@ -56,6 +64,7 @@ router.post( ...@@ -56,6 +64,7 @@ router.post(
"/:id/run", "/:id/run",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_SCHEDULES_RUN), requirePermission(PERMISSIONS.CRAWL_SCHEDULES_RUN),
validateParams(crawlScheduleParamsSchema),
controller.triggerRun, controller.triggerRun,
); );
...@@ -63,6 +72,7 @@ router.get( ...@@ -63,6 +72,7 @@ router.get(
"/:id/history", "/:id/history",
apiKeyOrAuthMiddleware, apiKeyOrAuthMiddleware,
requirePermission(PERMISSIONS.CRAWL_SCHEDULES_READ), requirePermission(PERMISSIONS.CRAWL_SCHEDULES_READ),
validateParams(crawlScheduleParamsSchema),
validateQuery(crawlScheduleHistoryQuerySchema), validateQuery(crawlScheduleHistoryQuerySchema),
controller.getHistory, controller.getHistory,
); );
......
...@@ -111,3 +111,7 @@ export const crawlScheduleHistoryQuerySchema = z.object({ ...@@ -111,3 +111,7 @@ export const crawlScheduleHistoryQuerySchema = z.object({
page: z.coerce.number().int().min(1).default(1), page: z.coerce.number().int().min(1).default(1),
limit: z.coerce.number().int().min(1).max(100).default(20), limit: z.coerce.number().int().min(1).max(100).default(20),
}); });
export const crawlScheduleParamsSchema = z.object({
id: z.string().uuid("Invalid schedule ID format"),
});
...@@ -3,10 +3,14 @@ import { ExtractionTemplateController } from "./extraction-template.controller"; ...@@ -3,10 +3,14 @@ import { ExtractionTemplateController } from "./extraction-template.controller";
import { authMiddleware } from "../../middlewares/auth.middleware"; import { authMiddleware } from "../../middlewares/auth.middleware";
import { requirePermission } from "../../middlewares/permission.middleware"; import { requirePermission } from "../../middlewares/permission.middleware";
import { PERMISSIONS } from "../../common/constants/permission.constant"; import { PERMISSIONS } from "../../common/constants/permission.constant";
import { validate } from "../../middlewares/validate.middleware"; import {
validate,
validateParams,
} from "../../middlewares/validate.middleware";
import { import {
createExtractionTemplateSchema, createExtractionTemplateSchema,
updateExtractionTemplateSchema, updateExtractionTemplateSchema,
extractionTemplateParamsSchema,
} from "./extraction-template.validation"; } from "./extraction-template.validation";
const router = Router(); const router = Router();
...@@ -28,17 +32,20 @@ router.get( ...@@ -28,17 +32,20 @@ router.get(
router.get( router.get(
"/:id", "/:id",
requirePermission(PERMISSIONS.EXTRACTION_TEMPLATES_READ), requirePermission(PERMISSIONS.EXTRACTION_TEMPLATES_READ),
validateParams(extractionTemplateParamsSchema),
controller.findById, controller.findById,
); );
router.patch( router.patch(
"/:id", "/:id",
requirePermission(PERMISSIONS.EXTRACTION_TEMPLATES_UPDATE), requirePermission(PERMISSIONS.EXTRACTION_TEMPLATES_UPDATE),
validateParams(extractionTemplateParamsSchema),
validate(updateExtractionTemplateSchema), validate(updateExtractionTemplateSchema),
controller.update, controller.update,
); );
router.delete( router.delete(
"/:id", "/:id",
requirePermission(PERMISSIONS.EXTRACTION_TEMPLATES_DELETE), requirePermission(PERMISSIONS.EXTRACTION_TEMPLATES_DELETE),
validateParams(extractionTemplateParamsSchema),
controller.delete, controller.delete,
); );
......
...@@ -27,3 +27,7 @@ export const updateExtractionTemplateSchema = z.object({ ...@@ -27,3 +27,7 @@ export const updateExtractionTemplateSchema = z.object({
name: z.string().min(1).optional(), name: z.string().min(1).optional(),
fields: z.array(extractionFieldSchema).min(1).optional(), fields: z.array(extractionFieldSchema).min(1).optional(),
}); });
export const extractionTemplateParamsSchema = z.object({
id: z.string().uuid("Invalid template ID format"),
});
...@@ -3,6 +3,8 @@ import { PermissionController } from "./permission.controller"; ...@@ -3,6 +3,8 @@ import { PermissionController } from "./permission.controller";
import { authMiddleware } from "../../middlewares/auth.middleware"; import { authMiddleware } from "../../middlewares/auth.middleware";
import { requirePermission } from "../../middlewares/permission.middleware"; import { requirePermission } from "../../middlewares/permission.middleware";
import { PERMISSIONS } from "../../common/constants/permission.constant"; import { PERMISSIONS } from "../../common/constants/permission.constant";
import { validateParams } from "../../middlewares/validate.middleware";
import { permissionParamsSchema } from "./permission.validation";
const router = Router(); const router = Router();
const controller = new PermissionController(); const controller = new PermissionController();
...@@ -18,6 +20,7 @@ router.get( ...@@ -18,6 +20,7 @@ router.get(
"/:id", "/:id",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.PERMISSIONS_READ), requirePermission(PERMISSIONS.PERMISSIONS_READ),
validateParams(permissionParamsSchema),
controller.findById, controller.findById,
); );
......
import { z } from "zod";
export const permissionParamsSchema = z.object({
id: z.string().uuid("Invalid permission ID format"),
});
...@@ -2,12 +2,17 @@ import { Router } from "express"; ...@@ -2,12 +2,17 @@ import { Router } from "express";
import { RoleController } from "./role.controller"; import { RoleController } from "./role.controller";
import { authMiddleware } from "../../middlewares/auth.middleware"; import { authMiddleware } from "../../middlewares/auth.middleware";
import { requirePermission } from "../../middlewares/permission.middleware"; import { requirePermission } from "../../middlewares/permission.middleware";
import { validate, validateQuery } from "../../middlewares/validate.middleware"; import {
validate,
validateQuery,
validateParams,
} from "../../middlewares/validate.middleware";
import { import {
createRoleSchema, createRoleSchema,
updateRoleSchema, updateRoleSchema,
assignRolePermissionsSchema, assignRolePermissionsSchema,
listRolesQuerySchema, listRolesQuerySchema,
roleParamsSchema,
} from "./role.validation"; } from "./role.validation";
import { PERMISSIONS } from "../../common/constants/permission.constant"; import { PERMISSIONS } from "../../common/constants/permission.constant";
...@@ -26,6 +31,7 @@ router.get( ...@@ -26,6 +31,7 @@ router.get(
"/:id", "/:id",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.ROLES_READ), requirePermission(PERMISSIONS.ROLES_READ),
validateParams(roleParamsSchema),
controller.findById, controller.findById,
); );
...@@ -41,6 +47,7 @@ router.patch( ...@@ -41,6 +47,7 @@ router.patch(
"/:id", "/:id",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.ROLES_UPDATE), requirePermission(PERMISSIONS.ROLES_UPDATE),
validateParams(roleParamsSchema),
validate(updateRoleSchema), validate(updateRoleSchema),
controller.update, controller.update,
); );
...@@ -49,6 +56,7 @@ router.delete( ...@@ -49,6 +56,7 @@ router.delete(
"/:id", "/:id",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.ROLES_DELETE), requirePermission(PERMISSIONS.ROLES_DELETE),
validateParams(roleParamsSchema),
controller.delete, controller.delete,
); );
...@@ -56,6 +64,7 @@ router.get( ...@@ -56,6 +64,7 @@ router.get(
"/:id/permissions", "/:id/permissions",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.ROLES_PERMISSIONS_READ), requirePermission(PERMISSIONS.ROLES_PERMISSIONS_READ),
validateParams(roleParamsSchema),
controller.getRolePermissions, controller.getRolePermissions,
); );
...@@ -63,6 +72,7 @@ router.put( ...@@ -63,6 +72,7 @@ router.put(
"/:id/permissions", "/:id/permissions",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.ROLES_PERMISSIONS_ASSIGN), requirePermission(PERMISSIONS.ROLES_PERMISSIONS_ASSIGN),
validateParams(roleParamsSchema),
validate(assignRolePermissionsSchema), validate(assignRolePermissionsSchema),
controller.setRolePermissions, controller.setRolePermissions,
); );
...@@ -71,6 +81,7 @@ router.get( ...@@ -71,6 +81,7 @@ router.get(
"/:id/users", "/:id/users",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.ROLES_READ), requirePermission(PERMISSIONS.ROLES_READ),
validateParams(roleParamsSchema),
controller.getRoleUsers, controller.getRoleUsers,
); );
......
...@@ -67,3 +67,12 @@ export const listRolesQuerySchema = z.object({ ...@@ -67,3 +67,12 @@ export const listRolesQuerySchema = z.object({
) )
.optional(), .optional(),
}); });
export const roleParamsSchema = z.object({
id: z.string().uuid("Invalid role ID format"),
});
export const rolePermissionParamsSchema = z.object({
id: z.string().uuid("Invalid role ID format"),
permissionId: z.string().uuid("Invalid permission ID format"),
});
...@@ -2,12 +2,18 @@ import { Router } from "express"; ...@@ -2,12 +2,18 @@ import { Router } from "express";
import { UserController } from "./user.controller"; import { UserController } from "./user.controller";
import { authMiddleware } from "../../middlewares/auth.middleware"; import { authMiddleware } from "../../middlewares/auth.middleware";
import { requirePermission } from "../../middlewares/permission.middleware"; import { requirePermission } from "../../middlewares/permission.middleware";
import { validate, validateQuery } from "../../middlewares/validate.middleware"; import {
validate,
validateQuery,
validateParams,
} from "../../middlewares/validate.middleware";
import { import {
createUserSchema, createUserSchema,
updateUserSchema, updateUserSchema,
listUsersQuerySchema, listUsersQuerySchema,
assignUserRolesSchema, assignUserRolesSchema,
userParamsSchema,
userRoleAssignmentParamsSchema,
} from "./user.validation"; } from "./user.validation";
import { PERMISSIONS } from "../../common/constants/permission.constant"; import { PERMISSIONS } from "../../common/constants/permission.constant";
...@@ -26,6 +32,7 @@ router.get( ...@@ -26,6 +32,7 @@ router.get(
"/:id", "/:id",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.USERS_READ), requirePermission(PERMISSIONS.USERS_READ),
validateParams(userParamsSchema),
controller.findById, controller.findById,
); );
...@@ -44,6 +51,7 @@ router.put( ...@@ -44,6 +51,7 @@ router.put(
"/:id", "/:id",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.USERS_UPDATE), requirePermission(PERMISSIONS.USERS_UPDATE),
validateParams(userParamsSchema),
validate(updateUserSchema), validate(updateUserSchema),
(req, res, next) => { (req, res, next) => {
// #swagger.requestBody = { schema: { $ref: '#/components/schemas/UpdateUserRequest' } } // #swagger.requestBody = { schema: { $ref: '#/components/schemas/UpdateUserRequest' } }
...@@ -55,6 +63,7 @@ router.delete( ...@@ -55,6 +63,7 @@ router.delete(
"/:id", "/:id",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.USERS_DELETE), requirePermission(PERMISSIONS.USERS_DELETE),
validateParams(userParamsSchema),
controller.delete, controller.delete,
); );
...@@ -63,6 +72,7 @@ router.get( ...@@ -63,6 +72,7 @@ router.get(
"/:id/roles", "/:id/roles",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.USERS_ROLES_READ), requirePermission(PERMISSIONS.USERS_ROLES_READ),
validateParams(userParamsSchema),
controller.getUserRoles, controller.getUserRoles,
); );
...@@ -70,6 +80,7 @@ router.put( ...@@ -70,6 +80,7 @@ router.put(
"/:id/roles", "/:id/roles",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.USERS_ROLES_ASSIGN), requirePermission(PERMISSIONS.USERS_ROLES_ASSIGN),
validateParams(userParamsSchema),
validate(assignUserRolesSchema), validate(assignUserRolesSchema),
controller.assignRoles, controller.assignRoles,
); );
...@@ -78,6 +89,7 @@ router.post( ...@@ -78,6 +89,7 @@ router.post(
"/:id/roles/:roleId", "/:id/roles/:roleId",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.USERS_ROLES_ASSIGN), requirePermission(PERMISSIONS.USERS_ROLES_ASSIGN),
validateParams(userRoleAssignmentParamsSchema),
controller.assignRole, controller.assignRole,
); );
...@@ -85,6 +97,7 @@ router.delete( ...@@ -85,6 +97,7 @@ router.delete(
"/:id/roles/:roleId", "/:id/roles/:roleId",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.USERS_ROLES_ASSIGN), requirePermission(PERMISSIONS.USERS_ROLES_ASSIGN),
validateParams(userRoleAssignmentParamsSchema),
controller.revokeRole, controller.revokeRole,
); );
......
...@@ -47,3 +47,12 @@ export const assignUserRolesSchema = z.object({ ...@@ -47,3 +47,12 @@ export const assignUserRolesSchema = z.object({
required_error: "roleIds array is required", required_error: "roleIds array is required",
}), }),
}); });
export const userParamsSchema = z.object({
id: z.string().uuid("Invalid user ID format"),
});
export const userRoleAssignmentParamsSchema = z.object({
id: z.string().uuid("Invalid user ID format"),
roleId: z.string().uuid("Invalid role ID format"),
});
...@@ -3,11 +3,16 @@ import { WebhookController } from "./webhook.controller"; ...@@ -3,11 +3,16 @@ import { WebhookController } from "./webhook.controller";
import { authMiddleware } from "../../middlewares/auth.middleware"; import { authMiddleware } from "../../middlewares/auth.middleware";
import { requirePermission } from "../../middlewares/permission.middleware"; import { requirePermission } from "../../middlewares/permission.middleware";
import { PERMISSIONS } from "../../common/constants/permission.constant"; import { PERMISSIONS } from "../../common/constants/permission.constant";
import { validate, validateQuery } from "../../middlewares/validate.middleware"; import {
validate,
validateQuery,
validateParams,
} from "../../middlewares/validate.middleware";
import { import {
createWebhookConfigSchema, createWebhookConfigSchema,
updateWebhookConfigSchema, updateWebhookConfigSchema,
listWebhookDeliveriesQuerySchema, listWebhookDeliveriesQuerySchema,
webhookParamsSchema,
} from "./webhook.validation"; } from "./webhook.validation";
const router = Router(); const router = Router();
...@@ -30,6 +35,7 @@ router.patch( ...@@ -30,6 +35,7 @@ router.patch(
"/configs/:id", "/configs/:id",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.WEBHOOKS_UPDATE), requirePermission(PERMISSIONS.WEBHOOKS_UPDATE),
validateParams(webhookParamsSchema),
validate(updateWebhookConfigSchema), validate(updateWebhookConfigSchema),
controller.updateConfig, controller.updateConfig,
); );
...@@ -37,12 +43,14 @@ router.delete( ...@@ -37,12 +43,14 @@ router.delete(
"/configs/:id", "/configs/:id",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.WEBHOOKS_DELETE), requirePermission(PERMISSIONS.WEBHOOKS_DELETE),
validateParams(webhookParamsSchema),
controller.deleteConfig, controller.deleteConfig,
); );
router.post( router.post(
"/configs/:id/test", "/configs/:id/test",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.WEBHOOKS_TEST), requirePermission(PERMISSIONS.WEBHOOKS_TEST),
validateParams(webhookParamsSchema),
controller.testConfig, controller.testConfig,
); );
router.get( router.get(
...@@ -56,6 +64,7 @@ router.post( ...@@ -56,6 +64,7 @@ router.post(
"/deliveries/:id/redeliver", "/deliveries/:id/redeliver",
authMiddleware, authMiddleware,
requirePermission(PERMISSIONS.WEBHOOKS_UPDATE), requirePermission(PERMISSIONS.WEBHOOKS_UPDATE),
validateParams(webhookParamsSchema),
controller.redeliver, controller.redeliver,
); );
......
...@@ -41,3 +41,7 @@ export const listWebhookDeliveriesQuerySchema = z.object({ ...@@ -41,3 +41,7 @@ export const listWebhookDeliveriesQuerySchema = z.object({
page: z.coerce.number().int().min(1).default(1), page: z.coerce.number().int().min(1).default(1),
limit: z.coerce.number().int().min(1).max(100).default(20), limit: z.coerce.number().int().min(1).max(100).default(20),
}); });
export const webhookParamsSchema = z.object({
id: z.string().uuid("Invalid webhook ID format"),
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment