主要变更: - 添加完整的项目结构和模块(admin、articles、comments、users、session、oauth2、email、moderation、analytics、jobs 等) - 实现系统初始化 API(/init/status 和 /init/run) - 重写部署流程:迁移到 package.json scripts,删除 Makefile - 优化部署脚本:deploy.sh、healthcheck.sh、backup.sh、restore.sh、verify-env.sh - 更新 README.md:简化文档,整合部署指南 - 优化 AGENTS.md:精简到约 150 行,包含完整的代码规范和命令速查 - 配置 Docker Compose 自动化部署(prisma migrate deploy + seed) - 生成 OAuth2 RSA 密钥对支持 - 添加环境变量验证和数据库备份恢复功能
117 lines
3.1 KiB
TypeScript
117 lines
3.1 KiB
TypeScript
import { PrismaClient } from '@prisma/client';
|
|
import * as bcrypt from 'bcrypt';
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
async function main() {
|
|
// 创建默认 OAuth2 客户端
|
|
const defaultClient = await prisma.oAuth2Client.upsert({
|
|
where: { clientId: 'web-client' },
|
|
update: {},
|
|
create: {
|
|
clientId: 'web-client',
|
|
clientSecret: 'change_me',
|
|
redirectUris: ['http://localhost:3000/auth/callback'],
|
|
scopes: 'read write',
|
|
},
|
|
});
|
|
console.log('Default OAuth2 client:', defaultClient.clientId);
|
|
|
|
// 检查是否已有管理员用户
|
|
const existingAdmin = await prisma.user.findFirst({
|
|
where: { email: 'admin@example.com' },
|
|
});
|
|
|
|
let admin;
|
|
if (!existingAdmin) {
|
|
const passwordHash = await bcrypt.hash('password123', 12);
|
|
admin = await prisma.user.create({
|
|
data: {
|
|
email: 'admin@example.com',
|
|
username: 'admin',
|
|
passwordHash,
|
|
displayName: 'Admin',
|
|
role: 'admin',
|
|
},
|
|
});
|
|
console.log('Created admin user:', admin.email);
|
|
} else {
|
|
admin = existingAdmin;
|
|
console.log('Admin user already exists:', admin.email);
|
|
}
|
|
|
|
// 检查是否已有版主用户
|
|
const existingModerator = await prisma.user.findFirst({
|
|
where: { email: 'moderator@example.com' },
|
|
});
|
|
|
|
if (!existingModerator) {
|
|
const modPasswordHash = await bcrypt.hash('moderator123', 12);
|
|
await prisma.user.create({
|
|
data: {
|
|
email: 'moderator@example.com',
|
|
username: 'moderator',
|
|
passwordHash: modPasswordHash,
|
|
displayName: 'Moderator',
|
|
role: 'moderator',
|
|
},
|
|
});
|
|
console.log('Created moderator user: moderator@example.com');
|
|
} else {
|
|
console.log('Moderator user already exists:', existingModerator.email);
|
|
}
|
|
|
|
// 创建示例文章
|
|
const existingArticle = await prisma.article.findFirst({
|
|
where: { slug: 'welcome' },
|
|
});
|
|
|
|
if (!existingArticle) {
|
|
const article = await prisma.article.create({
|
|
data: {
|
|
slug: 'welcome',
|
|
title: 'Welcome to LinkShare Blog',
|
|
content: 'This is a sample article. You can edit or delete it.',
|
|
excerpt: 'Short excerpt',
|
|
status: 'published',
|
|
visibility: 'public',
|
|
publishedAt: new Date(),
|
|
authorId: admin.id,
|
|
},
|
|
});
|
|
console.log('Created sample article:', article.slug);
|
|
} else {
|
|
console.log('Sample article already exists:', existingArticle.slug);
|
|
}
|
|
|
|
// 创建 link-access token 示例
|
|
const article = await prisma.article.findFirst({
|
|
where: { slug: 'welcome' },
|
|
});
|
|
if (article) {
|
|
const existingLink = await prisma.linkAccess.findFirst({
|
|
where: { articleId: article.id },
|
|
});
|
|
if (!existingLink) {
|
|
await prisma.linkAccess.create({
|
|
data: {
|
|
token: 'sample-token-123',
|
|
articleId: article.id,
|
|
maxViews: 100,
|
|
},
|
|
});
|
|
console.log('Created link-access token for article:', article.slug);
|
|
}
|
|
}
|
|
}
|
|
|
|
main()
|
|
.then(async () => {
|
|
await prisma.$disconnect();
|
|
})
|
|
.catch(async (e) => {
|
|
console.error(e);
|
|
await prisma.$disconnect();
|
|
process.exit(1);
|
|
});
|