- notificationRecipientModel에 ntfy CRUD 메서드 추가 (같은 DB 직접 쿼리) - ntfy 라우트 3개 추가 (GET/POST/DELETE, /:type 위에 배치) - 알림 수신자 탭 상단에 ntfy 구독 관리 카드 렌더링 - ntfy 추가 모달에 앱 설정 안내 문구 포함 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
191 lines
5.1 KiB
JavaScript
191 lines
5.1 KiB
JavaScript
// models/notificationRecipientModel.js
|
|
const { getPool } = require('./userModel');
|
|
|
|
const NOTIFICATION_TYPES = {
|
|
repair: '설비수리',
|
|
safety: '안전신고',
|
|
nonconformity: '부적합 신고',
|
|
system: '시스템',
|
|
partner_work: '협력업체 작업',
|
|
day_labor: '일용공 신청'
|
|
};
|
|
|
|
const NOTIFICATION_CATEGORIES = {
|
|
production: {
|
|
label: '생산',
|
|
icon: 'fa-industry',
|
|
types: ['repair', 'nonconformity']
|
|
},
|
|
safety: {
|
|
label: '안전',
|
|
icon: 'fa-shield-alt',
|
|
types: ['safety']
|
|
},
|
|
purchase: {
|
|
label: '구매',
|
|
icon: 'fa-shopping-cart',
|
|
types: ['partner_work', 'day_labor']
|
|
},
|
|
system: {
|
|
label: '시스템',
|
|
icon: 'fa-server',
|
|
types: ['system']
|
|
}
|
|
};
|
|
|
|
const notificationRecipientModel = {
|
|
// 알림 유형 목록 가져오기
|
|
getTypes() {
|
|
return { types: NOTIFICATION_TYPES, categories: NOTIFICATION_CATEGORIES };
|
|
},
|
|
|
|
// 유형별 수신자 목록 조회
|
|
async getByType(notificationType) {
|
|
const db = getPool();
|
|
const [rows] = await db.query(
|
|
`SELECT nr.*, u.username, u.name as user_name
|
|
FROM notification_recipients nr
|
|
JOIN sso_users u ON nr.user_id = u.user_id
|
|
WHERE nr.notification_type = ? AND nr.is_active = 1
|
|
ORDER BY u.name`,
|
|
[notificationType]
|
|
);
|
|
return rows;
|
|
},
|
|
|
|
// 전체 수신자 목록 조회 (유형별 그룹화)
|
|
async getAll() {
|
|
const db = getPool();
|
|
const [rows] = await db.query(
|
|
`SELECT nr.*, u.username, u.name as user_name
|
|
FROM notification_recipients nr
|
|
JOIN sso_users u ON nr.user_id = u.user_id
|
|
WHERE nr.is_active = 1
|
|
ORDER BY nr.notification_type, u.name`
|
|
);
|
|
|
|
// 유형별로 그룹화
|
|
const grouped = {};
|
|
for (const type in NOTIFICATION_TYPES) {
|
|
grouped[type] = {
|
|
label: NOTIFICATION_TYPES[type],
|
|
recipients: []
|
|
};
|
|
}
|
|
|
|
rows.forEach(row => {
|
|
if (grouped[row.notification_type]) {
|
|
grouped[row.notification_type].recipients.push(row);
|
|
}
|
|
});
|
|
|
|
return grouped;
|
|
},
|
|
|
|
// 수신자 추가
|
|
async add(notificationType, userId, createdBy = null) {
|
|
const db = getPool();
|
|
const [result] = await db.query(
|
|
`INSERT INTO notification_recipients (notification_type, user_id, created_by)
|
|
VALUES (?, ?, ?)
|
|
ON DUPLICATE KEY UPDATE is_active = 1`,
|
|
[notificationType, userId, createdBy]
|
|
);
|
|
return result.insertId || result.affectedRows > 0;
|
|
},
|
|
|
|
// 수신자 제거 (soft delete)
|
|
async remove(notificationType, userId) {
|
|
const db = getPool();
|
|
const [result] = await db.query(
|
|
`UPDATE notification_recipients SET is_active = 0
|
|
WHERE notification_type = ? AND user_id = ?`,
|
|
[notificationType, userId]
|
|
);
|
|
return result.affectedRows > 0;
|
|
},
|
|
|
|
// 수신자 완전 삭제
|
|
async delete(notificationType, userId) {
|
|
const db = getPool();
|
|
const [result] = await db.query(
|
|
`DELETE FROM notification_recipients
|
|
WHERE notification_type = ? AND user_id = ?`,
|
|
[notificationType, userId]
|
|
);
|
|
return result.affectedRows > 0;
|
|
},
|
|
|
|
// 유형별 수신자 user_id 목록만 가져오기 (알림 생성용)
|
|
async getRecipientIds(notificationType) {
|
|
const db = getPool();
|
|
const [rows] = await db.query(
|
|
`SELECT user_id FROM notification_recipients
|
|
WHERE notification_type = ? AND is_active = 1`,
|
|
[notificationType]
|
|
);
|
|
return rows.map(r => r.user_id);
|
|
},
|
|
|
|
// 사용자가 특정 유형의 수신자인지 확인
|
|
async isRecipient(notificationType, userId) {
|
|
const db = getPool();
|
|
const [[row]] = await db.query(
|
|
`SELECT 1 FROM notification_recipients
|
|
WHERE notification_type = ? AND user_id = ? AND is_active = 1`,
|
|
[notificationType, userId]
|
|
);
|
|
return !!row;
|
|
},
|
|
|
|
// === ntfy 구독 관리 ===
|
|
|
|
async getNtfySubscribers() {
|
|
const db = getPool();
|
|
const [rows] = await db.query(`
|
|
SELECT ns.user_id, ns.created_at, u.username, u.name as user_name
|
|
FROM ntfy_subscriptions ns
|
|
JOIN sso_users u ON u.user_id = ns.user_id
|
|
ORDER BY u.name
|
|
`);
|
|
return rows;
|
|
},
|
|
|
|
async addNtfySubscription(userId) {
|
|
const db = getPool();
|
|
await db.query('INSERT IGNORE INTO ntfy_subscriptions (user_id) VALUES (?)', [userId]);
|
|
},
|
|
|
|
async removeNtfySubscription(userId) {
|
|
const db = getPool();
|
|
await db.query('DELETE FROM ntfy_subscriptions WHERE user_id = ?', [userId]);
|
|
},
|
|
|
|
// 유형별 수신자 일괄 설정
|
|
async setRecipients(notificationType, userIds, createdBy = null) {
|
|
const db = getPool();
|
|
|
|
// 기존 수신자 비활성화
|
|
await db.query(
|
|
`UPDATE notification_recipients SET is_active = 0
|
|
WHERE notification_type = ?`,
|
|
[notificationType]
|
|
);
|
|
|
|
// 새 수신자 추가
|
|
if (userIds && userIds.length > 0) {
|
|
const values = userIds.map(userId => [notificationType, userId, createdBy]);
|
|
await db.query(
|
|
`INSERT INTO notification_recipients (notification_type, user_id, created_by)
|
|
VALUES ?
|
|
ON DUPLICATE KEY UPDATE is_active = 1`,
|
|
[values]
|
|
);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
module.exports = notificationRecipientModel;
|