mirror of
https://github.com/f/awesome-chatgpt-prompts.git
synced 2026-02-12 15:52:47 +00:00
feat(prisma): add db:resetadmin and db:setup scripts for database management
This commit is contained in:
@@ -13,6 +13,8 @@
|
||||
"db:push": "prisma db push",
|
||||
"db:studio": "prisma studio",
|
||||
"db:seed": "prisma db seed",
|
||||
"db:resetadmin": "npx tsx prisma/reset-admin.ts",
|
||||
"db:setup": "prisma generate && prisma migrate dev && db:seed",
|
||||
"setup": "node scripts/setup.js",
|
||||
"generate:examples": "npx tsx scripts/generate-examples.ts",
|
||||
"postinstall": "prisma generate"
|
||||
|
||||
3
prisma/migrations/20260106071035/migration.sql
Normal file
3
prisma/migrations/20260106071035/migration.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "users" ALTER COLUMN "dailyGenerationLimit" SET DEFAULT 3,
|
||||
ALTER COLUMN "generationCreditsRemaining" SET DEFAULT 3;
|
||||
40
prisma/reset-admin.ts
Normal file
40
prisma/reset-admin.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import bcrypt from "bcryptjs";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log("🔐 Resetting admin user...");
|
||||
|
||||
const password = await bcrypt.hash("password123", 12);
|
||||
|
||||
const admin = await prisma.user.upsert({
|
||||
where: { email: "admin@prompts.chat" },
|
||||
update: {
|
||||
password: password,
|
||||
role: "ADMIN",
|
||||
},
|
||||
create: {
|
||||
email: "admin@prompts.chat",
|
||||
username: "admin",
|
||||
name: "Admin User",
|
||||
password: password,
|
||||
role: "ADMIN",
|
||||
locale: "en",
|
||||
},
|
||||
});
|
||||
|
||||
console.log("✅ Admin user reset successfully!");
|
||||
console.log("\n📋 Credentials:");
|
||||
console.log(" Email: admin@prompts.chat");
|
||||
console.log(" Password: password123");
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error("❌ Failed to reset admin:", e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
1095
prisma/seed.ts
1095
prisma/seed.ts
File diff suppressed because it is too large
Load Diff
198
scripts/setup.js
198
scripts/setup.js
@@ -10,10 +10,86 @@
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
const p = require('@clack/prompts');
|
||||
const color = require('picocolors');
|
||||
|
||||
const CONFIG_FILE = path.join(__dirname, '..', 'prompts.config.ts');
|
||||
const ENV_FILE = path.join(__dirname, '..', '.env');
|
||||
|
||||
function generateAuthSecret() {
|
||||
return crypto.randomBytes(32).toString('base64');
|
||||
}
|
||||
|
||||
function buildDatabaseUrl(config) {
|
||||
const { host, port, username, password, database } = config;
|
||||
return `postgresql://${username}:${password}@${host}:${port}/${database}`;
|
||||
}
|
||||
|
||||
function generateEnvFile(config) {
|
||||
const isLocalhost = config.env.domain.includes('localhost');
|
||||
const protocol = isLocalhost ? 'http' : 'https';
|
||||
|
||||
let envContent = `# Generated by setup script
|
||||
# prompts.chat environment configuration
|
||||
|
||||
# Database
|
||||
DATABASE_URL="${config.env.databaseUrl}"
|
||||
|
||||
# Authentication
|
||||
AUTH_SECRET="${config.env.authSecret}"
|
||||
AUTH_URL="${protocol}://${config.env.domain}"
|
||||
AUTH_TRUST_HOST=true
|
||||
|
||||
# Cron Job Secret
|
||||
CRON_SECRET="${crypto.randomBytes(16).toString('hex')}"
|
||||
`;
|
||||
|
||||
if (config.auth.providers.includes('github')) {
|
||||
envContent += `
|
||||
# GitHub OAuth (configure at https://github.com/settings/developers)
|
||||
AUTH_GITHUB_ID=""
|
||||
AUTH_GITHUB_SECRET=""
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.auth.providers.includes('google')) {
|
||||
envContent += `
|
||||
# Google OAuth (configure at https://console.cloud.google.com/apis/credentials)
|
||||
AUTH_GOOGLE_ID=""
|
||||
AUTH_GOOGLE_SECRET=""
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.auth.providers.includes('apple')) {
|
||||
envContent += `
|
||||
# Apple Sign In
|
||||
AUTH_APPLE_ID=""
|
||||
AUTH_APPLE_SECRET=""
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.auth.providers.includes('azure')) {
|
||||
envContent += `
|
||||
# Microsoft Azure AD
|
||||
AUTH_AZURE_AD_CLIENT_ID=""
|
||||
AUTH_AZURE_AD_CLIENT_SECRET=""
|
||||
AUTH_AZURE_AD_ISSUER=""
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.features.aiSearch || config.features.aiGeneration) {
|
||||
envContent += `
|
||||
# AI Features
|
||||
OPENAI_API_KEY=""
|
||||
# OPENAI_BASE_URL=https://api.openai.com/v1
|
||||
# OPENAI_EMBEDDING_MODEL=text-embedding-3-small
|
||||
# OPENAI_GENERATIVE_MODEL=gpt-4o-mini
|
||||
`;
|
||||
}
|
||||
|
||||
return envContent;
|
||||
}
|
||||
|
||||
function generateConfig(config) {
|
||||
const sponsorsSection = config.sponsors.length > 0
|
||||
@@ -97,6 +173,7 @@ async function main() {
|
||||
p.intro(color.bgCyan(color.black(' prompts.chat - Private Clone Setup ')));
|
||||
|
||||
const config = {
|
||||
env: {},
|
||||
branding: {},
|
||||
theme: {},
|
||||
auth: {},
|
||||
@@ -105,6 +182,53 @@ async function main() {
|
||||
sponsors: []
|
||||
};
|
||||
|
||||
// === ENVIRONMENT ===
|
||||
p.log.step(color.cyan('Environment Configuration'));
|
||||
|
||||
const envConfig = await p.group({
|
||||
domain: () => p.text({
|
||||
message: 'Application domain',
|
||||
placeholder: 'localhost:3000',
|
||||
defaultValue: 'localhost:3000',
|
||||
}),
|
||||
}, { onCancel: handleCancel });
|
||||
|
||||
config.env.domain = envConfig.domain;
|
||||
config.env.authSecret = generateAuthSecret();
|
||||
|
||||
// === DATABASE ===
|
||||
p.log.step(color.cyan('Database Configuration'));
|
||||
|
||||
const dbConfig = await p.group({
|
||||
host: () => p.text({
|
||||
message: 'Database host',
|
||||
placeholder: 'localhost',
|
||||
defaultValue: 'localhost',
|
||||
}),
|
||||
port: () => p.text({
|
||||
message: 'Database port',
|
||||
placeholder: '5432',
|
||||
defaultValue: '5432',
|
||||
}),
|
||||
database: () => p.text({
|
||||
message: 'Database name',
|
||||
placeholder: 'prompts',
|
||||
defaultValue: 'prompts',
|
||||
}),
|
||||
username: () => p.text({
|
||||
message: 'Database username',
|
||||
placeholder: 'postgres',
|
||||
defaultValue: 'postgres',
|
||||
}),
|
||||
password: () => p.password({
|
||||
message: 'Database password',
|
||||
mask: '*',
|
||||
}),
|
||||
}, { onCancel: handleCancel });
|
||||
|
||||
config.env.database = dbConfig;
|
||||
config.env.databaseUrl = buildDatabaseUrl(dbConfig);
|
||||
|
||||
// === BRANDING ===
|
||||
p.log.step(color.cyan('Branding'));
|
||||
|
||||
@@ -190,12 +314,13 @@ async function main() {
|
||||
const authProviders = await p.multiselect({
|
||||
message: 'Select authentication providers',
|
||||
options: [
|
||||
{ value: 'credentials', label: 'Email/Password', hint: 'Traditional auth (recommended)' },
|
||||
{ value: 'github', label: 'GitHub OAuth', hint: 'Most popular for developers' },
|
||||
{ value: 'google', label: 'Google OAuth', hint: 'Widely used' },
|
||||
{ value: 'apple', label: 'Apple Sign In', hint: 'Sign in with Apple' },
|
||||
{ value: 'azure', label: 'Microsoft Azure AD', hint: 'Enterprise SSO' },
|
||||
{ value: 'credentials', label: 'Email/Password', hint: 'Traditional auth' },
|
||||
],
|
||||
initialValues: ['credentials'],
|
||||
required: false,
|
||||
});
|
||||
|
||||
@@ -370,57 +495,56 @@ async function main() {
|
||||
s.stop('Generated prompts.config.ts');
|
||||
|
||||
// === ENV FILE ===
|
||||
const envExample = path.join(__dirname, '..', '.env.example');
|
||||
const envFile = path.join(__dirname, '..', '.env');
|
||||
s.start('Creating .env file...');
|
||||
|
||||
const envContent = generateEnvFile(config);
|
||||
fs.writeFileSync(ENV_FILE, envContent);
|
||||
|
||||
s.stop('Created .env file');
|
||||
|
||||
if (!fs.existsSync(envFile) && fs.existsSync(envExample)) {
|
||||
const createEnv = await p.confirm({
|
||||
message: 'Create .env file from .env.example?',
|
||||
initialValue: true,
|
||||
});
|
||||
if (!p.isCancel(createEnv) && createEnv) {
|
||||
fs.copyFileSync(envExample, envFile);
|
||||
p.log.success('Created .env file');
|
||||
}
|
||||
}
|
||||
|
||||
// === REQUIRED ENV VARS ===
|
||||
const envVars = [
|
||||
'DATABASE_URL - PostgreSQL connection string',
|
||||
'AUTH_SECRET - NextAuth secret (openssl rand -base64 32)',
|
||||
];
|
||||
// === ADDITIONAL ENV VARS NEEDED ===
|
||||
const additionalEnvVars = [];
|
||||
|
||||
if (config.auth.providers.includes('github')) {
|
||||
envVars.push('AUTH_GITHUB_ID - GitHub OAuth client ID');
|
||||
envVars.push('AUTH_GITHUB_SECRET - GitHub OAuth client secret');
|
||||
additionalEnvVars.push('AUTH_GITHUB_ID - GitHub OAuth client ID');
|
||||
additionalEnvVars.push('AUTH_GITHUB_SECRET - GitHub OAuth client secret');
|
||||
}
|
||||
if (config.auth.providers.includes('google')) {
|
||||
envVars.push('AUTH_GOOGLE_ID - Google OAuth client ID');
|
||||
envVars.push('AUTH_GOOGLE_SECRET - Google OAuth client secret');
|
||||
additionalEnvVars.push('AUTH_GOOGLE_ID - Google OAuth client ID');
|
||||
additionalEnvVars.push('AUTH_GOOGLE_SECRET - Google OAuth client secret');
|
||||
}
|
||||
if (config.auth.providers.includes('azure')) {
|
||||
envVars.push('AUTH_AZURE_AD_CLIENT_ID - Azure AD client ID');
|
||||
envVars.push('AUTH_AZURE_AD_CLIENT_SECRET - Azure AD client secret');
|
||||
envVars.push('AUTH_AZURE_AD_ISSUER - Azure AD issuer URL');
|
||||
additionalEnvVars.push('AUTH_AZURE_AD_CLIENT_ID - Azure AD client ID');
|
||||
additionalEnvVars.push('AUTH_AZURE_AD_CLIENT_SECRET - Azure AD client secret');
|
||||
additionalEnvVars.push('AUTH_AZURE_AD_ISSUER - Azure AD issuer URL');
|
||||
}
|
||||
if (config.auth.providers.includes('apple')) {
|
||||
envVars.push('AUTH_APPLE_ID - Apple Services ID');
|
||||
envVars.push('AUTH_APPLE_SECRET - Apple secret key');
|
||||
additionalEnvVars.push('AUTH_APPLE_ID - Apple Services ID');
|
||||
additionalEnvVars.push('AUTH_APPLE_SECRET - Apple secret key');
|
||||
}
|
||||
if (config.features.aiSearch || config.features.aiGeneration) {
|
||||
envVars.push('OPENAI_API_KEY - OpenAI API key for AI features');
|
||||
additionalEnvVars.push('OPENAI_API_KEY - OpenAI API key for AI features');
|
||||
}
|
||||
|
||||
p.note(envVars.join('\n'), 'Required environment variables');
|
||||
if (additionalEnvVars.length > 0) {
|
||||
p.log.warn(color.yellow('⚠️ Action required: You must configure the following in .env before the app will work:'));
|
||||
additionalEnvVars.forEach(v => p.log.message(` ${color.yellow('→')} ${v}`));
|
||||
p.log.message('');
|
||||
}
|
||||
|
||||
// === NEXT STEPS ===
|
||||
p.note(
|
||||
`1. Edit ${color.cyan('.env')} with your database and auth credentials\n` +
|
||||
`2. Add your logo files to the ${color.cyan('public/')} folder\n` +
|
||||
`3. Run: ${color.cyan('npm run db:push')}\n` +
|
||||
`4. Run: ${color.cyan('npm run dev')}`,
|
||||
'Next steps'
|
||||
);
|
||||
const nextSteps = additionalEnvVars.length > 0
|
||||
? `1. Edit ${color.cyan('.env')} to add OAuth credentials (if using OAuth providers)\n` +
|
||||
`2. Add your logo files to the ${color.cyan('public/')} folder\n` +
|
||||
`3. Run: ${color.cyan('npm run db:push')}\n` +
|
||||
`4. Run: ${color.cyan('npm run db:seed')} (optional - seed with prompts)\n` +
|
||||
`5. Run: ${color.cyan('npm run dev')}`
|
||||
: `1. Add your logo files to the ${color.cyan('public/')} folder\n` +
|
||||
`2. Run: ${color.cyan('npm run db:push')}\n` +
|
||||
`3. Run: ${color.cyan('npm run db:seed')} (optional - seed with prompts)\n` +
|
||||
`4. Run: ${color.cyan('npm run dev')}`;
|
||||
|
||||
p.note(nextSteps, 'Next steps');
|
||||
|
||||
p.outro(color.green('Setup complete! See SELF-HOSTING.md for more details.'));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user