Files
msgapp/prisma/seed.js

217 lines
7.1 KiB
JavaScript

const { PrismaClient } = require("@prisma/client");
const prisma = new PrismaClient();
async function upsertRoles() {
const roles = [
{ name: "admin", description: "관리자" },
{ name: "editor", description: "운영진" },
{ name: "user", description: "일반 사용자" }
];
for (const r of roles) {
await prisma.role.upsert({
where: { name: r.name },
update: { description: r.description },
create: r,
});
}
// 기본 권한 매핑
const roleMap = {
admin: [
["ADMIN", "ADMINISTER"],
["BOARD", "MODERATE"],
["POST", "CREATE"],
["POST", "UPDATE"],
["POST", "DELETE"],
["COMMENT", "DELETE"],
["USER", "UPDATE"],
],
editor: [
["BOARD", "MODERATE"],
["POST", "UPDATE"],
["POST", "DELETE"],
["COMMENT", "DELETE"],
],
user: [
["POST", "CREATE"],
["COMMENT", "CREATE"],
["POST", "READ"],
["COMMENT", "READ"],
],
};
for (const [roleName, perms] of Object.entries(roleMap)) {
const role = await prisma.role.findUnique({ where: { name: roleName } });
if (!role) continue;
for (const [resource, action] of perms) {
await prisma.rolePermission.upsert({
where: {
roleId_resource_action: {
roleId: role.roleId,
resource,
action,
},
},
update: { allowed: true },
create: { roleId: role.roleId, resource, action, allowed: true },
});
}
}
}
async function upsertAdmin() {
const admin = await prisma.user.upsert({
where: { nickname: "admin" },
update: {},
create: {
nickname: "admin",
name: "Administrator",
birth: new Date("1990-01-01"),
phone: "010-0000-0001",
agreementTermsAt: new Date(),
authLevel: "ADMIN",
},
});
const adminRole = await prisma.role.findUnique({ where: { name: "admin" } });
if (adminRole) {
await prisma.userRole.upsert({
where: {
userId_roleId: { userId: admin.userId, roleId: adminRole.roleId },
},
update: {},
create: { userId: admin.userId, roleId: adminRole.roleId },
});
}
return admin;
}
async function upsertBoards(admin) {
const boards = [
// 일반
{ name: "공지사항", slug: "notice", description: "공지", type: "general", sortOrder: 1, writeLevel: "moderator" },
{ name: "가입인사", slug: "greetings", description: "가입인사", type: "general", sortOrder: 2 },
{ name: "버그건의", slug: "bug-report", description: "버그/건의", type: "general", sortOrder: 3 },
{ name: "이벤트", slug: "event", description: "이벤트", type: "general", sortOrder: 4, requiredTags: { required: ["이벤트"] } },
{ name: "자유게시판", slug: "free", description: "자유", type: "general", sortOrder: 5 },
{ name: "무엇이든", slug: "qna", description: "무엇이든 물어보세요", type: "general", sortOrder: 6 },
{ name: "마사지꿀팁", slug: "tips", description: "팁", type: "general", sortOrder: 7 },
{ name: "익명게시판", slug: "anonymous", description: "익명", type: "general", sortOrder: 8, allowAnonymousPost: true, allowSecretComment: true },
{ name: "관리사찾아요", slug: "find-therapist", description: "구인/구직", type: "general", sortOrder: 9 },
{ name: "청와대", slug: "blue-house", description: "레벨 제한", type: "general", sortOrder: 10, readLevel: "member" },
{ name: "방문후기", slug: "reviews", description: "운영자 승인 후 공개", type: "general", sortOrder: 11, requiresApproval: true, requiredTags: { anyOf: ["업체명", "지역"] } },
// 특수
{ name: "출석부", slug: "attendance", description: "데일리 체크인", type: "special", sortOrder: 12 },
{ name: "주변 제휴업체", slug: "nearby-partners", description: "위치 기반", type: "special", sortOrder: 13 },
{ name: "회원랭킹", slug: "ranking", description: "랭킹", type: "special", sortOrder: 14 },
{ name: "무료쿠폰", slug: "free-coupons", description: "쿠폰", type: "special", sortOrder: 15 },
{ name: "월간집계", slug: "monthly-stats", description: "월간 통계", type: "special", sortOrder: 16 },
// 제휴업소 일반(사진)
{ name: "제휴업소 일반(사진)", slug: "partners-photos", description: "사진 전용 게시판", type: "general", sortOrder: 17, requiredFields: { imageOnly: true, minImages: 1, maxImages: 10 } },
];
const created = [];
for (const b of boards) {
const board = await prisma.board.upsert({
where: { slug: b.slug },
update: {
description: b.description,
sortOrder: b.sortOrder,
type: b.type,
requiresApproval: !!b.requiresApproval,
allowAnonymousPost: !!b.allowAnonymousPost,
readLevel: b.readLevel || undefined,
},
create: {
name: b.name,
slug: b.slug,
description: b.description,
sortOrder: b.sortOrder,
type: b.type,
requiresApproval: !!b.requiresApproval,
allowAnonymousPost: !!b.allowAnonymousPost,
readLevel: b.readLevel || undefined,
},
});
created.push(board);
// 공지/운영 보드는 관리자 모더레이터 지정
if (["notice", "bug-report"].includes(board.slug)) {
await prisma.boardModerator.upsert({
where: {
boardId_userId: { boardId: board.id, userId: admin.userId },
},
update: {},
create: { boardId: board.id, userId: admin.userId, role: "MANAGER" },
});
}
}
return created;
}
async function seedPolicies() {
// 금칙어 예시
const banned = [
{ pattern: "광고", appliesTo: "POST", severity: 1 },
{ pattern: "욕설", appliesTo: "COMMENT", severity: 2 },
{ pattern: "스팸", appliesTo: "POST", severity: 2 },
];
for (const k of banned) {
await prisma.bannedKeyword.upsert({
where: { pattern: k.pattern },
update: { appliesTo: k.appliesTo, severity: k.severity, active: true },
create: k,
});
}
// 레벨 임계 예시
const levels = [
{ level: 1, minPoints: 0 },
{ level: 2, minPoints: 100 },
{ level: 3, minPoints: 300 },
];
for (const l of levels) {
await prisma.levelThreshold.upsert({
where: { level: l.level },
update: { minPoints: l.minPoints },
create: l,
});
}
}
async function main() {
await upsertRoles();
const admin = await upsertAdmin();
const boards = await upsertBoards(admin);
// 샘플 글 하나
const free = boards.find((b) => b.slug === "free") || boards[0];
const post = await prisma.post.create({
data: {
boardId: free.id,
authorId: admin.userId,
title: "첫 글",
content: "메시지 앱 초기 설정 완료",
status: "published",
},
});
await prisma.comment.createMany({
data: [
{ postId: post.id, authorId: admin.userId, content: "환영합니다!" },
{ postId: post.id, authorId: admin.userId, content: "댓글 테스트" },
],
});
await seedPolicies();
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});