refactor: System2/3, User Management SSO 인증 통합
- System2 신고: SSO JWT 인증 전환, API base 정리 - System3 부적합: SSO 인증 매니저 통합, 권한 체계 정비 - User Management: SSO 토큰 기반 사용자 관리 API 연동 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,25 +10,20 @@ const { getDb } = require('../config/database');
|
||||
/**
|
||||
* 모든 신고 카테고리 조회
|
||||
*/
|
||||
const getAllCategories = async (callback) => {
|
||||
try {
|
||||
const getAllCategories = async () => {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(
|
||||
`SELECT category_id, category_type, category_name, description, display_order, is_active, created_at
|
||||
FROM issue_report_categories
|
||||
ORDER BY category_type, display_order, category_id`
|
||||
);
|
||||
callback(null, rows);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return rows;
|
||||
};
|
||||
|
||||
/**
|
||||
* 타입별 활성 카테고리 조회 (nonconformity/safety)
|
||||
*/
|
||||
const getCategoriesByType = async (categoryType, callback) => {
|
||||
try {
|
||||
const getCategoriesByType = async (categoryType) => {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(
|
||||
`SELECT category_id, category_type, category_name, description, display_order
|
||||
@@ -37,17 +32,13 @@ const getCategoriesByType = async (categoryType, callback) => {
|
||||
ORDER BY display_order, category_id`,
|
||||
[categoryType]
|
||||
);
|
||||
callback(null, rows);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return rows;
|
||||
};
|
||||
|
||||
/**
|
||||
* 카테고리 생성
|
||||
*/
|
||||
const createCategory = async (categoryData, callback) => {
|
||||
try {
|
||||
const createCategory = async (categoryData) => {
|
||||
const db = await getDb();
|
||||
const { category_type, category_name, description = null, display_order = 0 } = categoryData;
|
||||
|
||||
@@ -57,17 +48,13 @@ const createCategory = async (categoryData, callback) => {
|
||||
[category_type, category_name, description, display_order]
|
||||
);
|
||||
|
||||
callback(null, result.insertId);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return result.insertId;
|
||||
};
|
||||
|
||||
/**
|
||||
* 카테고리 수정
|
||||
*/
|
||||
const updateCategory = async (categoryId, categoryData, callback) => {
|
||||
try {
|
||||
const updateCategory = async (categoryId, categoryData) => {
|
||||
const db = await getDb();
|
||||
const { category_name, description, display_order, is_active } = categoryData;
|
||||
|
||||
@@ -78,26 +65,19 @@ const updateCategory = async (categoryId, categoryData, callback) => {
|
||||
[category_name, description, display_order, is_active, categoryId]
|
||||
);
|
||||
|
||||
callback(null, result);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 카테고리 삭제
|
||||
*/
|
||||
const deleteCategory = async (categoryId, callback) => {
|
||||
try {
|
||||
const deleteCategory = async (categoryId) => {
|
||||
const db = await getDb();
|
||||
const [result] = await db.query(
|
||||
`DELETE FROM issue_report_categories WHERE category_id = ?`,
|
||||
[categoryId]
|
||||
);
|
||||
callback(null, result);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// ==================== 사전 정의 신고 항목 관리 ====================
|
||||
@@ -105,8 +85,7 @@ const deleteCategory = async (categoryId, callback) => {
|
||||
/**
|
||||
* 카테고리별 활성 항목 조회
|
||||
*/
|
||||
const getItemsByCategory = async (categoryId, callback) => {
|
||||
try {
|
||||
const getItemsByCategory = async (categoryId) => {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(
|
||||
`SELECT item_id, category_id, item_name, description, severity, display_order
|
||||
@@ -115,17 +94,13 @@ const getItemsByCategory = async (categoryId, callback) => {
|
||||
ORDER BY display_order, item_id`,
|
||||
[categoryId]
|
||||
);
|
||||
callback(null, rows);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return rows;
|
||||
};
|
||||
|
||||
/**
|
||||
* 모든 항목 조회 (관리용)
|
||||
*/
|
||||
const getAllItems = async (callback) => {
|
||||
try {
|
||||
const getAllItems = async () => {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(
|
||||
`SELECT iri.item_id, iri.category_id, iri.item_name, iri.description,
|
||||
@@ -135,17 +110,13 @@ const getAllItems = async (callback) => {
|
||||
INNER JOIN issue_report_categories irc ON iri.category_id = irc.category_id
|
||||
ORDER BY irc.category_type, irc.display_order, iri.display_order, iri.item_id`
|
||||
);
|
||||
callback(null, rows);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return rows;
|
||||
};
|
||||
|
||||
/**
|
||||
* 항목 생성
|
||||
*/
|
||||
const createItem = async (itemData, callback) => {
|
||||
try {
|
||||
const createItem = async (itemData) => {
|
||||
const db = await getDb();
|
||||
const { category_id, item_name, description = null, severity = 'medium', display_order = 0 } = itemData;
|
||||
|
||||
@@ -155,17 +126,13 @@ const createItem = async (itemData, callback) => {
|
||||
[category_id, item_name, description, severity, display_order]
|
||||
);
|
||||
|
||||
callback(null, result.insertId);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return result.insertId;
|
||||
};
|
||||
|
||||
/**
|
||||
* 항목 수정
|
||||
*/
|
||||
const updateItem = async (itemId, itemData, callback) => {
|
||||
try {
|
||||
const updateItem = async (itemId, itemData) => {
|
||||
const db = await getDb();
|
||||
const { item_name, description, severity, display_order, is_active } = itemData;
|
||||
|
||||
@@ -176,33 +143,25 @@ const updateItem = async (itemId, itemData, callback) => {
|
||||
[item_name, description, severity, display_order, is_active, itemId]
|
||||
);
|
||||
|
||||
callback(null, result);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 항목 삭제
|
||||
*/
|
||||
const deleteItem = async (itemId, callback) => {
|
||||
try {
|
||||
const deleteItem = async (itemId) => {
|
||||
const db = await getDb();
|
||||
const [result] = await db.query(
|
||||
`DELETE FROM issue_report_items WHERE item_id = ?`,
|
||||
[itemId]
|
||||
);
|
||||
callback(null, result);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 카테고리 ID로 단건 조회
|
||||
*/
|
||||
const getCategoryById = async (categoryId, callback) => {
|
||||
try {
|
||||
const getCategoryById = async (categoryId) => {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(
|
||||
`SELECT category_id, category_type, category_name, description
|
||||
@@ -210,10 +169,7 @@ const getCategoryById = async (categoryId, callback) => {
|
||||
WHERE category_id = ?`,
|
||||
[categoryId]
|
||||
);
|
||||
callback(null, rows[0] || null);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return rows[0] || null;
|
||||
};
|
||||
|
||||
// ==================== 문제 신고 관리 ====================
|
||||
@@ -224,8 +180,7 @@ const { getKoreaDatetime } = require('../utils/dateUtils');
|
||||
/**
|
||||
* 신고 생성
|
||||
*/
|
||||
const createReport = async (reportData, callback) => {
|
||||
try {
|
||||
const createReport = async (reportData) => {
|
||||
const db = await getDb();
|
||||
const {
|
||||
reporter_id,
|
||||
@@ -267,17 +222,13 @@ const createReport = async (reportData, callback) => {
|
||||
[result.insertId, reporter_id]
|
||||
);
|
||||
|
||||
callback(null, result.insertId);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return result.insertId;
|
||||
};
|
||||
|
||||
/**
|
||||
* 신고 목록 조회 (필터 옵션 포함)
|
||||
*/
|
||||
const getAllReports = async (filters = {}, callback) => {
|
||||
try {
|
||||
const getAllReports = async (filters = {}) => {
|
||||
const db = await getDb();
|
||||
let query = `
|
||||
SELECT
|
||||
@@ -368,17 +319,13 @@ const getAllReports = async (filters = {}, callback) => {
|
||||
}
|
||||
|
||||
const [rows] = await db.query(query, params);
|
||||
callback(null, rows);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return rows;
|
||||
};
|
||||
|
||||
/**
|
||||
* 신고 상세 조회
|
||||
*/
|
||||
const getReportById = async (reportId, callback) => {
|
||||
try {
|
||||
const getReportById = async (reportId) => {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(
|
||||
`SELECT
|
||||
@@ -413,17 +360,13 @@ const getReportById = async (reportId, callback) => {
|
||||
[reportId]
|
||||
);
|
||||
|
||||
callback(null, rows[0]);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return rows[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* 신고 수정
|
||||
*/
|
||||
const updateReport = async (reportId, reportData, userId, callback) => {
|
||||
try {
|
||||
const updateReport = async (reportId, reportData, userId) => {
|
||||
const db = await getDb();
|
||||
|
||||
// 기존 데이터 조회
|
||||
@@ -433,7 +376,7 @@ const updateReport = async (reportId, reportData, userId, callback) => {
|
||||
);
|
||||
|
||||
if (existing.length === 0) {
|
||||
return callback(new Error('신고를 찾을 수 없습니다.'));
|
||||
throw new Error('신고를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
const current = existing[0];
|
||||
@@ -494,17 +437,13 @@ const updateReport = async (reportId, reportData, userId, callback) => {
|
||||
JSON.stringify(newHistory), reportId]
|
||||
);
|
||||
|
||||
callback(null, result);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 신고 삭제
|
||||
*/
|
||||
const deleteReport = async (reportId, callback) => {
|
||||
try {
|
||||
const deleteReport = async (reportId) => {
|
||||
const db = await getDb();
|
||||
|
||||
// 먼저 사진 경로 조회 (삭제용)
|
||||
@@ -521,10 +460,7 @@ const deleteReport = async (reportId, callback) => {
|
||||
);
|
||||
|
||||
// 삭제할 사진 경로 반환
|
||||
callback(null, { result, photos: photos[0] });
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return { result, photos: photos[0] };
|
||||
};
|
||||
|
||||
// ==================== 상태 관리 ====================
|
||||
@@ -532,8 +468,7 @@ const deleteReport = async (reportId, callback) => {
|
||||
/**
|
||||
* 신고 접수 (reported → received)
|
||||
*/
|
||||
const receiveReport = async (reportId, userId, callback) => {
|
||||
try {
|
||||
const receiveReport = async (reportId, userId) => {
|
||||
const db = await getDb();
|
||||
|
||||
// 현재 상태 확인
|
||||
@@ -543,11 +478,11 @@ const receiveReport = async (reportId, userId, callback) => {
|
||||
);
|
||||
|
||||
if (current.length === 0) {
|
||||
return callback(new Error('신고를 찾을 수 없습니다.'));
|
||||
throw new Error('신고를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
if (current[0].status !== 'reported') {
|
||||
return callback(new Error('접수 대기 상태가 아닙니다.'));
|
||||
throw new Error('접수 대기 상태가 아닙니다.');
|
||||
}
|
||||
|
||||
const [result] = await db.query(
|
||||
@@ -564,17 +499,13 @@ const receiveReport = async (reportId, userId, callback) => {
|
||||
[reportId, userId]
|
||||
);
|
||||
|
||||
callback(null, result);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 담당자 배정
|
||||
*/
|
||||
const assignReport = async (reportId, assignData, callback) => {
|
||||
try {
|
||||
const assignReport = async (reportId, assignData) => {
|
||||
const db = await getDb();
|
||||
const { assigned_department, assigned_user_id, assigned_by } = assignData;
|
||||
|
||||
@@ -585,13 +516,13 @@ const assignReport = async (reportId, assignData, callback) => {
|
||||
);
|
||||
|
||||
if (current.length === 0) {
|
||||
return callback(new Error('신고를 찾을 수 없습니다.'));
|
||||
throw new Error('신고를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
// 접수 상태 이상이어야 배정 가능
|
||||
const validStatuses = ['received', 'in_progress'];
|
||||
if (!validStatuses.includes(current[0].status)) {
|
||||
return callback(new Error('접수된 상태에서만 담당자 배정이 가능합니다.'));
|
||||
throw new Error('접수된 상태에서만 담당자 배정이 가능합니다.');
|
||||
}
|
||||
|
||||
const [result] = await db.query(
|
||||
@@ -602,17 +533,13 @@ const assignReport = async (reportId, assignData, callback) => {
|
||||
[assigned_department, assigned_user_id, assigned_by, reportId]
|
||||
);
|
||||
|
||||
callback(null, result);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 처리 시작 (received → in_progress)
|
||||
*/
|
||||
const startProcessing = async (reportId, userId, callback) => {
|
||||
try {
|
||||
const startProcessing = async (reportId, userId) => {
|
||||
const db = await getDb();
|
||||
|
||||
// 현재 상태 확인
|
||||
@@ -622,11 +549,11 @@ const startProcessing = async (reportId, userId, callback) => {
|
||||
);
|
||||
|
||||
if (current.length === 0) {
|
||||
return callback(new Error('신고를 찾을 수 없습니다.'));
|
||||
throw new Error('신고를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
if (current[0].status !== 'received') {
|
||||
return callback(new Error('접수된 상태에서만 처리를 시작할 수 있습니다.'));
|
||||
throw new Error('접수된 상태에서만 처리를 시작할 수 있습니다.');
|
||||
}
|
||||
|
||||
const [result] = await db.query(
|
||||
@@ -643,17 +570,13 @@ const startProcessing = async (reportId, userId, callback) => {
|
||||
[reportId, userId]
|
||||
);
|
||||
|
||||
callback(null, result);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 처리 완료 (in_progress → completed)
|
||||
*/
|
||||
const completeReport = async (reportId, completionData, callback) => {
|
||||
try {
|
||||
const completeReport = async (reportId, completionData) => {
|
||||
const db = await getDb();
|
||||
const { resolution_notes, resolution_photo_path1, resolution_photo_path2, resolved_by } = completionData;
|
||||
|
||||
@@ -664,11 +587,11 @@ const completeReport = async (reportId, completionData, callback) => {
|
||||
);
|
||||
|
||||
if (current.length === 0) {
|
||||
return callback(new Error('신고를 찾을 수 없습니다.'));
|
||||
throw new Error('신고를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
if (current[0].status !== 'in_progress') {
|
||||
return callback(new Error('처리 중 상태에서만 완료할 수 있습니다.'));
|
||||
throw new Error('처리 중 상태에서만 완료할 수 있습니다.');
|
||||
}
|
||||
|
||||
const [result] = await db.query(
|
||||
@@ -687,17 +610,13 @@ const completeReport = async (reportId, completionData, callback) => {
|
||||
[reportId, resolved_by, resolution_notes]
|
||||
);
|
||||
|
||||
callback(null, result);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 신고 종료 (completed → closed)
|
||||
*/
|
||||
const closeReport = async (reportId, userId, callback) => {
|
||||
try {
|
||||
const closeReport = async (reportId, userId) => {
|
||||
const db = await getDb();
|
||||
|
||||
// 현재 상태 확인
|
||||
@@ -707,11 +626,11 @@ const closeReport = async (reportId, userId, callback) => {
|
||||
);
|
||||
|
||||
if (current.length === 0) {
|
||||
return callback(new Error('신고를 찾을 수 없습니다.'));
|
||||
throw new Error('신고를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
if (current[0].status !== 'completed') {
|
||||
return callback(new Error('완료된 상태에서만 종료할 수 있습니다.'));
|
||||
throw new Error('완료된 상태에서만 종료할 수 있습니다.');
|
||||
}
|
||||
|
||||
const [result] = await db.query(
|
||||
@@ -728,17 +647,13 @@ const closeReport = async (reportId, userId, callback) => {
|
||||
[reportId, userId]
|
||||
);
|
||||
|
||||
callback(null, result);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 상태 변경 이력 조회
|
||||
*/
|
||||
const getStatusLogs = async (reportId, callback) => {
|
||||
try {
|
||||
const getStatusLogs = async (reportId) => {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(
|
||||
`SELECT wisl.log_id, wisl.report_id, wisl.previous_status, wisl.new_status,
|
||||
@@ -750,26 +665,19 @@ const getStatusLogs = async (reportId, callback) => {
|
||||
ORDER BY wisl.changed_at ASC`,
|
||||
[reportId]
|
||||
);
|
||||
callback(null, rows);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return rows;
|
||||
};
|
||||
|
||||
/**
|
||||
* m_project_id 업데이트 (System 3 연동 후)
|
||||
*/
|
||||
const updateMProjectId = async (reportId, mProjectId, callback) => {
|
||||
try {
|
||||
const updateMProjectId = async (reportId, mProjectId) => {
|
||||
const db = await getDb();
|
||||
await db.query(
|
||||
`UPDATE work_issue_reports SET m_project_id = ? WHERE report_id = ?`,
|
||||
[mProjectId, reportId]
|
||||
);
|
||||
callback(null);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
// ==================== 통계 ====================
|
||||
@@ -777,8 +685,7 @@ const updateMProjectId = async (reportId, mProjectId, callback) => {
|
||||
/**
|
||||
* 신고 통계 요약
|
||||
*/
|
||||
const getStatsSummary = async (filters = {}, callback) => {
|
||||
try {
|
||||
const getStatsSummary = async (filters = {}) => {
|
||||
const db = await getDb();
|
||||
|
||||
let whereClause = '1=1';
|
||||
@@ -812,17 +719,13 @@ const getStatsSummary = async (filters = {}, callback) => {
|
||||
params
|
||||
);
|
||||
|
||||
callback(null, rows[0]);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return rows[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* 카테고리별 통계
|
||||
*/
|
||||
const getStatsByCategory = async (filters = {}, callback) => {
|
||||
try {
|
||||
const getStatsByCategory = async (filters = {}) => {
|
||||
const db = await getDb();
|
||||
|
||||
let whereClause = '1=1';
|
||||
@@ -845,17 +748,13 @@ const getStatsByCategory = async (filters = {}, callback) => {
|
||||
params
|
||||
);
|
||||
|
||||
callback(null, rows);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return rows;
|
||||
};
|
||||
|
||||
/**
|
||||
* 작업장별 통계
|
||||
*/
|
||||
const getStatsByWorkplace = async (filters = {}, callback) => {
|
||||
try {
|
||||
const getStatsByWorkplace = async (filters = {}) => {
|
||||
const db = await getDb();
|
||||
|
||||
let whereClause = 'wir.workplace_id IS NOT NULL';
|
||||
@@ -885,17 +784,13 @@ const getStatsByWorkplace = async (filters = {}, callback) => {
|
||||
params
|
||||
);
|
||||
|
||||
callback(null, rows);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return rows;
|
||||
};
|
||||
|
||||
/**
|
||||
* 유형 이관 (category_type 변경)
|
||||
*/
|
||||
const transferCategoryType = async (reportId, newCategoryType, userId, callback) => {
|
||||
try {
|
||||
const transferCategoryType = async (reportId, newCategoryType, userId) => {
|
||||
const db = await getDb();
|
||||
|
||||
// 기존 데이터 조회
|
||||
@@ -905,14 +800,14 @@ const transferCategoryType = async (reportId, newCategoryType, userId, callback)
|
||||
);
|
||||
|
||||
if (existing.length === 0) {
|
||||
return callback(new Error('신고를 찾을 수 없습니다.'));
|
||||
throw new Error('신고를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
const current = existing[0];
|
||||
const oldCategoryType = current.category_type;
|
||||
|
||||
if (oldCategoryType === newCategoryType) {
|
||||
return callback(new Error('현재 유형과 동일합니다.'));
|
||||
throw new Error('현재 유형과 동일합니다.');
|
||||
}
|
||||
|
||||
// 수정 이력 추가
|
||||
@@ -934,17 +829,13 @@ const transferCategoryType = async (reportId, newCategoryType, userId, callback)
|
||||
[newCategoryType, JSON.stringify(existingHistory), reportId]
|
||||
);
|
||||
|
||||
callback(null, result);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 공장/작업장 이름 조회 (System 3 연동용)
|
||||
*/
|
||||
const getLocationNames = async (factoryCategoryId, workplaceId, callback) => {
|
||||
try {
|
||||
const getLocationNames = async (factoryCategoryId, workplaceId) => {
|
||||
const db = await getDb();
|
||||
let factoryName = null;
|
||||
let workplaceName = null;
|
||||
@@ -965,10 +856,7 @@ const getLocationNames = async (factoryCategoryId, workplaceId, callback) => {
|
||||
if (rows.length > 0) workplaceName = rows[0].workplace_name;
|
||||
}
|
||||
|
||||
callback(null, { factory_name: factoryName, workplace_name: workplaceName });
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
return { factory_name: factoryName, workplace_name: workplaceName };
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
|
||||
Reference in New Issue
Block a user