chore(api): update seed script
This commit is contained in:
+256
-94
@@ -1,109 +1,271 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { AccessScopeType, AdminRole, AdminStatus, PrismaClient } from '@prisma/client';
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log('Seeding default demo campaign and prizes...');
|
||||
const PERMISSIONS = [
|
||||
// Campaigns
|
||||
{ code: 'campaigns:read', module: 'campaigns', name: 'مشاهده کمپینها', description: 'مشاهده لیست و جزئیات کمپینها' },
|
||||
{ code: 'campaigns:create', module: 'campaigns', name: 'ایجاد کمپین', description: 'ثبت کمپین جدید' },
|
||||
{ code: 'campaigns:update', module: 'campaigns', name: 'ویرایش کمپین', description: 'تغییر تنظیمات و وضعیت کمپین' },
|
||||
{ code: 'campaigns:delete', module: 'campaigns', name: 'حذف کمپین', description: 'حذف کمپین از سامانه' },
|
||||
|
||||
// Prizes
|
||||
{ code: 'prizes:read', module: 'prizes', name: 'مشاهده جوایز', description: 'مشاهده لیست جوایز کمپینها' },
|
||||
{ code: 'prizes:manage', module: 'prizes', name: 'مدیریت جوایز', description: 'افزودن، ویرایش و تنظیم ظرفیت جوایز' },
|
||||
|
||||
// Users & Chances
|
||||
{ code: 'users:read', module: 'users', name: 'مشاهده کاربران', description: 'مشاهده لیست کاربران شرکتکننده و پروفایل' },
|
||||
{ code: 'users:block', module: 'users', name: 'مسدودسازی کاربران', description: 'بلاک یا آنبلاک کردن کاربران' },
|
||||
{ code: 'chances:adjust', module: 'chances', name: 'تنظیم دستی شانس', description: 'افزایش یا کاهش شانس با ثبت لاگ' },
|
||||
|
||||
// Winners & Spins
|
||||
{ code: 'spins:read', module: 'spins', name: 'مشاهده لاگ چرخشها', description: 'بررسی تاریخچه اسپینهای کاربران' },
|
||||
{ code: 'winners:read', module: 'winners', name: 'مشاهده برندگان', description: 'مشاهده لیست برندگان و کدهای هدیه' },
|
||||
{ code: 'winners:manage', module: 'winners', name: 'مدیریت وضعیت جوایز', description: 'تغییر وضعیت کدهای جایزه به تحویلشده و...' },
|
||||
|
||||
// SMS & Logs
|
||||
{ code: 'sms:read', module: 'sms', name: 'مشاهده لاگ پیامک', description: 'مشاهده پیامکهای ارسالی OTP و برندگان' },
|
||||
{ code: 'sms:resend', module: 'sms', name: 'ارسال مجدد پیامک', description: 'ارسال دوباره پیامکهای ناموفق' },
|
||||
{ code: 'audit:read', module: 'audit', name: 'مشاهده لاگ بازرسی', description: 'مشاهده ردپای عملیات و تغییرات مدیران' },
|
||||
|
||||
// Reports
|
||||
{ code: 'reports:read', module: 'reports', name: 'مشاهده گزارشها و آمار', description: 'مشاهده نمودارها، آمار زنده و داشبورد' },
|
||||
{ code: 'reports:export', module: 'reports', name: 'خروجی دادهها', description: 'دریافت خروجی اکسل و CSV گزارشها' },
|
||||
|
||||
// Access Control & Admins
|
||||
{ code: 'admins:read', module: 'admins', name: 'مشاهده مدیران', description: 'مشاهده لیست مدیران و همکاران' },
|
||||
{ code: 'admins:manage', module: 'admins', name: 'مدیریت مدیران', description: 'ایجاد، ویرایش، تغییر رمز و غیرفعالسازی مدیران' },
|
||||
{ code: 'roles:manage', module: 'roles', name: 'مدیریت نقشها و مجوزها', description: 'تعریف نقش جدید و تخصیص مجوزها' },
|
||||
{ code: 'workspaces:manage', module: 'workspaces', name: 'مدیریت فضاهای کاری', description: 'تعریف و مدیریت فضاهای کاری سازمانی' },
|
||||
];
|
||||
|
||||
async function main() {
|
||||
console.log('Seeding database with Workspaces, RBAC, Admin, and Demo Campaign...');
|
||||
|
||||
// 1. Ensure Default Workspace exists
|
||||
let defaultWorkspace = await prisma.workspace.findUnique({
|
||||
where: { slug: 'default-workspace' },
|
||||
});
|
||||
|
||||
if (!defaultWorkspace) {
|
||||
defaultWorkspace = await prisma.workspace.create({
|
||||
data: {
|
||||
name: 'فضای کاری اصلی',
|
||||
slug: 'default-workspace',
|
||||
description: 'فضای کاری پیشفرض و سراسری سیستم گردونه شانس',
|
||||
status: 'ACTIVE',
|
||||
},
|
||||
});
|
||||
console.log('Created default workspace:', defaultWorkspace.id);
|
||||
}
|
||||
|
||||
// 2. Seed Permissions
|
||||
const permissionMap = new Map<string, string>();
|
||||
for (const perm of PERMISSIONS) {
|
||||
const p = await prisma.permission.upsert({
|
||||
where: { code: perm.code },
|
||||
update: {
|
||||
module: perm.module,
|
||||
name: perm.name,
|
||||
description: perm.description,
|
||||
},
|
||||
create: {
|
||||
code: perm.code,
|
||||
module: perm.module,
|
||||
name: perm.name,
|
||||
description: perm.description,
|
||||
},
|
||||
});
|
||||
permissionMap.set(p.code, p.id);
|
||||
}
|
||||
|
||||
// 3. Seed Roles
|
||||
const superAdminRole = await prisma.role.upsert({
|
||||
where: { code: 'SUPER_ADMIN' },
|
||||
update: {
|
||||
name: 'مدیر ارشد سامانه',
|
||||
description: 'دسترسی کامل و بدون محدودیت به تمامی بخشها و تنظیمات سامانه',
|
||||
isSystem: true,
|
||||
},
|
||||
create: {
|
||||
code: 'SUPER_ADMIN',
|
||||
name: 'مدیر ارشد سامانه',
|
||||
description: 'دسترسی کامل و بدون محدودیت به تمامی بخشها و تنظیمات سامانه',
|
||||
isSystem: true,
|
||||
},
|
||||
});
|
||||
|
||||
const operatorRole = await prisma.role.upsert({
|
||||
where: { code: 'OPERATOR' },
|
||||
update: {
|
||||
name: 'اپراتور سامانه',
|
||||
description: 'مدیریت کمپینها، جوایز، شانسها، برندگان و کاربران بدون دسترسی به مدیریت ادمینها',
|
||||
isSystem: true,
|
||||
},
|
||||
create: {
|
||||
code: 'OPERATOR',
|
||||
name: 'اپراتور سامانه',
|
||||
description: 'مدیریت کمپینها، جوایز، شانسها، برندگان و کاربران بدون دسترسی به مدیریت ادمینها',
|
||||
isSystem: true,
|
||||
},
|
||||
});
|
||||
|
||||
const supportRole = await prisma.role.upsert({
|
||||
where: { code: 'SUPPORT' },
|
||||
update: {
|
||||
name: 'کارشناس پشتیبانی',
|
||||
description: 'مشاهده کاربران، برندگان، پیامکها و تغییر وضعیت تحویل جوایز',
|
||||
isSystem: true,
|
||||
},
|
||||
create: {
|
||||
code: 'SUPPORT',
|
||||
name: 'کارشناس پشتیبانی',
|
||||
description: 'مشاهده کاربران، برندگان، پیامکها و تغییر وضعیت تحویل جوایز',
|
||||
isSystem: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Assign permissions to roles
|
||||
for (const permId of permissionMap.values()) {
|
||||
await prisma.rolePermission.upsert({
|
||||
where: {
|
||||
roleId_permissionId: {
|
||||
roleId: superAdminRole.id,
|
||||
permissionId: permId,
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
create: {
|
||||
roleId: superAdminRole.id,
|
||||
permissionId: permId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const operatorPermCodes = [
|
||||
'campaigns:read', 'campaigns:create', 'campaigns:update', 'campaigns:delete',
|
||||
'prizes:read', 'prizes:manage',
|
||||
'users:read', 'users:block', 'chances:adjust',
|
||||
'spins:read',
|
||||
'winners:read', 'winners:manage',
|
||||
'sms:read', 'sms:resend',
|
||||
'reports:read', 'reports:export',
|
||||
'audit:read',
|
||||
];
|
||||
for (const code of operatorPermCodes) {
|
||||
const permId = permissionMap.get(code);
|
||||
if (permId) {
|
||||
await prisma.rolePermission.upsert({
|
||||
where: { roleId_permissionId: { roleId: operatorRole.id, permissionId: permId } },
|
||||
update: {},
|
||||
create: { roleId: operatorRole.id, permissionId: permId },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const supportPermCodes = [
|
||||
'campaigns:read', 'prizes:read', 'users:read', 'spins:read', 'winners:read', 'winners:manage', 'sms:read',
|
||||
];
|
||||
for (const code of supportPermCodes) {
|
||||
const permId = permissionMap.get(code);
|
||||
if (permId) {
|
||||
await prisma.rolePermission.upsert({
|
||||
where: { roleId_permissionId: { roleId: supportRole.id, permissionId: permId } },
|
||||
update: {},
|
||||
create: { roleId: supportRole.id, permissionId: permId },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Ensure Default Super Admin Exists
|
||||
const defaultAdminEmail = 'admin@luckywheel.local';
|
||||
let defaultAdmin = await prisma.admin.findUnique({
|
||||
where: { email: defaultAdminEmail },
|
||||
});
|
||||
|
||||
if (!defaultAdmin) {
|
||||
const passwordHash = await bcrypt.hash('Admin@SecurePass2026', 10);
|
||||
defaultAdmin = await prisma.admin.create({
|
||||
data: {
|
||||
email: defaultAdminEmail,
|
||||
name: 'مدیر ارشد سامانه',
|
||||
mobile: '09120000000',
|
||||
passwordHash,
|
||||
role: AdminRole.SUPER_ADMIN,
|
||||
isSuperAdmin: true,
|
||||
status: AdminStatus.ACTIVE,
|
||||
},
|
||||
});
|
||||
console.log('Created default Super Admin account:', defaultAdmin.email);
|
||||
}
|
||||
|
||||
// Backfill admin assignments
|
||||
const admins = await prisma.admin.findMany();
|
||||
for (const admin of admins) {
|
||||
const isSuper = admin.role === AdminRole.SUPER_ADMIN || admin.isSuperAdmin;
|
||||
await prisma.admin.update({
|
||||
where: { id: admin.id },
|
||||
data: { isSuperAdmin: isSuper },
|
||||
});
|
||||
|
||||
const targetRoleId = isSuper ? superAdminRole.id : admin.role === 'OPERATOR' ? operatorRole.id : supportRole.id;
|
||||
await prisma.adminRoleAssignment.upsert({
|
||||
where: { adminId_roleId: { adminId: admin.id, roleId: targetRoleId } },
|
||||
update: {},
|
||||
create: { adminId: admin.id, roleId: targetRoleId },
|
||||
});
|
||||
|
||||
await prisma.adminWorkspaceAssignment.upsert({
|
||||
where: { adminId_workspaceId: { adminId: admin.id, workspaceId: defaultWorkspace.id } },
|
||||
update: {},
|
||||
create: { adminId: admin.id, workspaceId: defaultWorkspace.id, scopeType: AccessScopeType.ALL },
|
||||
});
|
||||
}
|
||||
|
||||
// 5. Ensure Default Campaign Exists
|
||||
const existingCampaign = await prisma.campaign.findUnique({
|
||||
where: { slug: 'default-campaign' },
|
||||
});
|
||||
|
||||
if (existingCampaign) {
|
||||
console.log('Default campaign already exists.');
|
||||
return;
|
||||
if (!existingCampaign) {
|
||||
const campaign = await prisma.campaign.create({
|
||||
data: {
|
||||
title: 'گردونه شانس جشنواره بزرگ نوروزی',
|
||||
slug: 'default-campaign',
|
||||
description: 'هر روز با چرخاندن گردونه، شانس برنده شدن آیفون، سکه طلا، و کدهای تخفیف شگفتانگیز را داشته باشید!',
|
||||
startAt: new Date(Date.now() - 24 * 3600 * 1000),
|
||||
endAt: new Date(Date.now() + 60 * 24 * 3600 * 1000),
|
||||
status: 'ACTIVE',
|
||||
defaultChances: 3,
|
||||
ctaText: 'بچرخون و برنده شو!',
|
||||
wheelDesign: 'CLASSIC_CASINO',
|
||||
workspaceId: defaultWorkspace.id,
|
||||
rules: '۱. هر کاربر در بدو ورود ۳ شانس چرخاندن رایگان دریافت میکند.\n۲. جوایز فیزیکی پس از هماهنگی تلفنی توسط پشتیبانی ارسال خواهد شد.\n۳. کدهای تخفیف بلافاصله پیامک شده و تا ۷ روز پس از دریافت معتبر هستند.',
|
||||
prizes: {
|
||||
create: [
|
||||
{ title: 'آیفون ۱۵ پرو', type: 'PHYSICAL', stockType: 'LIMITED', initialStock: 3, remainingStock: 3, weight: 1, sortOrder: 1, segmentColor: '#b91c1c' },
|
||||
{ title: 'تخفیف ۵۰٪ دیجیکالا', type: 'DISCOUNT_CODE', stockType: 'UNLIMITED', weight: 25, sortOrder: 2, segmentColor: '#1e293b' },
|
||||
{ title: 'کارت هدیه ۵۰۰ تومانی', type: 'CREDIT', stockType: 'LIMITED', initialStock: 50, remainingStock: 50, weight: 10, sortOrder: 3, segmentColor: '#b91c1c' },
|
||||
{ title: 'پوچ (دفعه بعد)', type: 'NO_PRIZE', stockType: 'UNLIMITED', weight: 20, sortOrder: 4, segmentColor: '#1e293b' },
|
||||
{ title: 'تخفیف ۳۰٪ اسنپ', type: 'DISCOUNT_CODE', stockType: 'UNLIMITED', weight: 20, sortOrder: 5, segmentColor: '#b91c1c' },
|
||||
{ title: 'ساعت هوشمند', type: 'PHYSICAL', stockType: 'LIMITED', initialStock: 10, remainingStock: 10, weight: 4, sortOrder: 6, segmentColor: '#1e293b' },
|
||||
{ title: 'شانس مجدد', type: 'OTHER', stockType: 'UNLIMITED', weight: 15, sortOrder: 7, segmentColor: '#b91c1c' },
|
||||
{ title: 'پوچ (بدون جایزه)', type: 'NO_PRIZE', stockType: 'UNLIMITED', weight: 5, sortOrder: 8, segmentColor: '#1e293b' },
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
console.log(`Campaign created with ID: ${campaign.id} and 8 prizes.`);
|
||||
}
|
||||
|
||||
const campaign = await prisma.campaign.create({
|
||||
data: {
|
||||
title: 'گردونه شانس جشنواره بزرگ نوروزی',
|
||||
slug: 'default-campaign',
|
||||
description: 'هر روز با چرخاندن گردونه، شانس برنده شدن آیفون، سکه طلا، و کدهای تخفیف شگفتانگیز را داشته باشید!',
|
||||
startAt: new Date(Date.now() - 24 * 3600 * 1000),
|
||||
endAt: new Date(Date.now() + 60 * 24 * 3600 * 1000),
|
||||
status: 'ACTIVE',
|
||||
defaultChances: 3,
|
||||
ctaText: 'بچرخون و برنده شو!',
|
||||
wheelDesign: 'CLASSIC_CASINO',
|
||||
rules: '۱. هر کاربر در بدو ورود ۳ شانس چرخاندن رایگان دریافت میکند.\n۲. جوایز فیزیکی پس از هماهنگی تلفنی توسط پشتیبانی ارسال خواهد شد.\n۳. کدهای تخفیف بلافاصله پیامک شده و تا ۷ روز پس از دریافت معتبر هستند.',
|
||||
prizes: {
|
||||
create: [
|
||||
{
|
||||
title: 'آیفون ۱۵ پرو',
|
||||
type: 'PHYSICAL',
|
||||
stockType: 'LIMITED',
|
||||
initialStock: 3,
|
||||
remainingStock: 3,
|
||||
weight: 1,
|
||||
sortOrder: 1,
|
||||
segmentColor: '#b91c1c',
|
||||
},
|
||||
{
|
||||
title: 'تخفیف ۵۰٪ دیجیکالا',
|
||||
type: 'DISCOUNT_CODE',
|
||||
stockType: 'UNLIMITED',
|
||||
weight: 25,
|
||||
sortOrder: 2,
|
||||
segmentColor: '#1e293b',
|
||||
},
|
||||
{
|
||||
title: 'کارت هدیه ۵۰۰ تومانی',
|
||||
type: 'CREDIT',
|
||||
stockType: 'LIMITED',
|
||||
initialStock: 50,
|
||||
remainingStock: 50,
|
||||
weight: 10,
|
||||
sortOrder: 3,
|
||||
segmentColor: '#b91c1c',
|
||||
},
|
||||
{
|
||||
title: 'پوچ (دفعه بعد)',
|
||||
type: 'NO_PRIZE',
|
||||
stockType: 'UNLIMITED',
|
||||
weight: 20,
|
||||
sortOrder: 4,
|
||||
segmentColor: '#1e293b',
|
||||
},
|
||||
{
|
||||
title: 'تخفیف ۳۰٪ اسنپ',
|
||||
type: 'DISCOUNT_CODE',
|
||||
stockType: 'UNLIMITED',
|
||||
weight: 20,
|
||||
sortOrder: 5,
|
||||
segmentColor: '#b91c1c',
|
||||
},
|
||||
{
|
||||
title: 'ساعت هوشمند',
|
||||
type: 'PHYSICAL',
|
||||
stockType: 'LIMITED',
|
||||
initialStock: 10,
|
||||
remainingStock: 10,
|
||||
weight: 4,
|
||||
sortOrder: 6,
|
||||
segmentColor: '#1e293b',
|
||||
},
|
||||
{
|
||||
title: 'شانس مجدد',
|
||||
type: 'OTHER',
|
||||
stockType: 'UNLIMITED',
|
||||
weight: 15,
|
||||
sortOrder: 7,
|
||||
segmentColor: '#b91c1c',
|
||||
},
|
||||
{
|
||||
title: 'پوچ (بدون جایزه)',
|
||||
type: 'NO_PRIZE',
|
||||
stockType: 'UNLIMITED',
|
||||
weight: 5,
|
||||
sortOrder: 8,
|
||||
segmentColor: '#1e293b',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
// Link any unassigned campaigns to default workspace
|
||||
await prisma.campaign.updateMany({
|
||||
where: { workspaceId: null },
|
||||
data: { workspaceId: defaultWorkspace.id },
|
||||
});
|
||||
|
||||
console.log(`Campaign created with ID: ${campaign.id} and 8 prizes.`);
|
||||
console.log('Database seeding finished successfully.');
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user