mirror of
https://github.com/ceratic/project_vollidioten_website.git
synced 2026-05-14 00:16:47 +02:00
241 lines
7.7 KiB
JavaScript
241 lines
7.7 KiB
JavaScript
const mysql = require('mysql2');
|
|
|
|
// Database Config from Env
|
|
const dbConfig = {
|
|
host: process.env.DB_HOST || 'localhost',
|
|
user: process.env.DB_USER || 'root',
|
|
password: process.env.DB_PASS || '',
|
|
database: process.env.DB_NAME || 'obsidian_db',
|
|
waitForConnections: true,
|
|
connectionLimit: 10,
|
|
queueLimit: 0
|
|
};
|
|
|
|
let pool;
|
|
|
|
// Mock Data for Seeding
|
|
const SEED_PLAYERS = [
|
|
{
|
|
uuid: '80301bff-74df-4579-bcfc-082ac8d26b5b',
|
|
username: 'kaiwastoshort',
|
|
isOnline: 1,
|
|
isNpc: 0,
|
|
isAdmin: 0,
|
|
tags: JSON.stringify(['#Bürger', '#Händler']),
|
|
stats: JSON.stringify({ playtimeHours: 482, level: 45, role: 'Bürger', organizationId: 'org-3' }),
|
|
inventory: JSON.stringify([]),
|
|
storyMarkdown: '# Der Bauplan von V\n\n> "Stein erinnert sich..."'
|
|
},
|
|
{
|
|
uuid: '8984c0b5-d912-4462-b189-c864fba4a1af',
|
|
username: 'DrKButz',
|
|
isOnline: 0,
|
|
isNpc: 0,
|
|
isAdmin: 1, // DrKButz is admin for testing
|
|
tags: JSON.stringify(['#Bauunternehmer']),
|
|
stats: JSON.stringify({ playtimeHours: 120, level: 12, role: 'Unternehmer', organizationId: 'org-4' }),
|
|
inventory: JSON.stringify([]),
|
|
storyMarkdown: '# Forschungslogbuch:\n\nSpezialisiert auf...'
|
|
}
|
|
];
|
|
|
|
const SEED_ORGS = [
|
|
{
|
|
id: 'org-3',
|
|
name: 'Provisorium Null',
|
|
type: 'City',
|
|
description: 'Die erste Siedlung...',
|
|
memberCount: 6,
|
|
status: 'active',
|
|
mayor: '',
|
|
establishedYear: 'Day 0',
|
|
bannerUrl: 'images/screenshots/2025-12-28_01.11.10.png',
|
|
gallery: JSON.stringify(['images/screenshots/2025-12-28_01.12.07.png']),
|
|
cityStats: JSON.stringify({ taxRate: 3.5, biome: 'Ebene', defenseRating: 8, government: 'Feudal', specialty: 'Handel' })
|
|
},
|
|
{
|
|
id: 'org-4',
|
|
name: 'Sakura',
|
|
type: 'City',
|
|
description: 'Eine dunkle, biolumineszente Hafenstadt...',
|
|
memberCount: 2,
|
|
status: 'active',
|
|
mayor: 'Kampfzwerk',
|
|
establishedYear: 'Ära 2',
|
|
bannerUrl: 'images/screenshots/2025-12-28_01.11.32.png',
|
|
gallery: JSON.stringify([]),
|
|
cityStats: JSON.stringify({ taxRate: 15.0, biome: 'Deep Dark', defenseRating: 4, government: 'Syndikat', specialty: 'Schmuggel' })
|
|
}
|
|
];
|
|
|
|
const SEED_PROJECTS = [
|
|
{
|
|
id: 'ven-1',
|
|
title: 'DrkButz Architektur',
|
|
description: 'Führendes Architekturbüro...',
|
|
category: 'Enterprise',
|
|
status: 'active',
|
|
progress: 85,
|
|
owner: 'DrKButz',
|
|
employees: JSON.stringify([]),
|
|
hiring: 0,
|
|
foundedDate: 'Zyklus 12',
|
|
associatedOrgId: 'org-4',
|
|
bannerImageId: null,
|
|
shopCatalog: JSON.stringify([])
|
|
}
|
|
];
|
|
|
|
// Retry connection logic for Docker
|
|
function init() {
|
|
const tryConnect = () => {
|
|
console.log("Attempting to connect to MySQL...");
|
|
const tempPool = mysql.createPool(dbConfig);
|
|
|
|
tempPool.getConnection((err, connection) => {
|
|
if (err) {
|
|
console.error("Database connection failed. Retrying in 5s...", err.code);
|
|
setTimeout(tryConnect, 5000);
|
|
} else {
|
|
console.log("MySQL Connected!");
|
|
pool = tempPool;
|
|
connection.release();
|
|
setupTables();
|
|
}
|
|
});
|
|
};
|
|
tryConnect();
|
|
}
|
|
|
|
function setupTables() {
|
|
const queries = [
|
|
`CREATE TABLE IF NOT EXISTS players (
|
|
uuid VARCHAR(36) PRIMARY KEY,
|
|
username VARCHAR(255),
|
|
isOnline TINYINT,
|
|
isNpc TINYINT DEFAULT 0,
|
|
isAdmin TINYINT DEFAULT 0,
|
|
tags JSON,
|
|
stats JSON,
|
|
inventory JSON,
|
|
storyMarkdown TEXT,
|
|
discordId VARCHAR(255)
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS orgs (
|
|
id VARCHAR(50) PRIMARY KEY,
|
|
name VARCHAR(255),
|
|
type VARCHAR(50),
|
|
description TEXT,
|
|
memberCount INTEGER,
|
|
status VARCHAR(50),
|
|
mayor VARCHAR(255),
|
|
establishedYear VARCHAR(100),
|
|
bannerImageId VARCHAR(50),
|
|
logoImageId VARCHAR(50),
|
|
gallery JSON,
|
|
cityStats JSON
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS images (
|
|
id VARCHAR(50) PRIMARY KEY,
|
|
filename VARCHAR(255) NOT NULL,
|
|
originalName VARCHAR(255),
|
|
mimeType VARCHAR(100),
|
|
size INTEGER,
|
|
uploadDate DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
altText VARCHAR(255),
|
|
entityType VARCHAR(50), -- 'project', 'org', 'player'
|
|
entityId VARCHAR(50), -- ID of the owning entity
|
|
imageType VARCHAR(50) -- 'banner', 'gallery'
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS projects (
|
|
id VARCHAR(50) PRIMARY KEY,
|
|
title VARCHAR(255),
|
|
description TEXT,
|
|
category VARCHAR(50),
|
|
status VARCHAR(50),
|
|
progress INTEGER,
|
|
owner VARCHAR(255),
|
|
employees JSON,
|
|
hiring TINYINT,
|
|
foundedDate VARCHAR(100),
|
|
associatedOrgId VARCHAR(50),
|
|
bannerImageId VARCHAR(50),
|
|
logoImageId VARCHAR(50),
|
|
shopCatalog JSON,
|
|
gallery JSON
|
|
)`
|
|
];
|
|
|
|
queries.forEach(q => {
|
|
pool.query(q, (err) => {
|
|
if (err) console.error("Error creating table:", err);
|
|
});
|
|
});
|
|
|
|
seedData();
|
|
}
|
|
|
|
function seedData() {
|
|
// Check if players exist
|
|
pool.query("SELECT COUNT(*) as count FROM players", (err, rows) => {
|
|
if (!err && rows[0].count === 0) {
|
|
console.log("Seeding Players...");
|
|
SEED_PLAYERS.forEach(p => {
|
|
pool.query("INSERT INTO players VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
[p.uuid, p.username, p.isOnline, p.isNpc, p.isAdmin, p.tags, p.stats, p.inventory, p.storyMarkdown, null]);
|
|
});
|
|
}
|
|
});
|
|
|
|
pool.query("SELECT COUNT(*) as count FROM orgs", (err, rows) => {
|
|
if (!err && rows[0].count === 0) {
|
|
console.log("Seeding Orgs...");
|
|
SEED_ORGS.forEach(o => {
|
|
pool.query("INSERT INTO orgs VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
[o.id, o.name, o.type, o.description, o.memberCount, o.status, o.mayor, o.establishedYear, null, null, o.gallery, o.cityStats]);
|
|
});
|
|
}
|
|
});
|
|
|
|
pool.query("SELECT COUNT(*) as count FROM projects", (err, rows) => {
|
|
if (!err && rows[0].count === 0) {
|
|
console.log("Seeding Projects...");
|
|
SEED_PROJECTS.forEach(p => {
|
|
pool.query("INSERT INTO projects VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
[p.id, p.title, p.description, p.category, p.status, p.progress, p.owner, p.employees, p.hiring, p.foundedDate, p.associatedOrgId, p.bannerImageId, null, p.shopCatalog, '[]']);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Wrapper to mimic SQLite API for easy migration in server.js
|
|
const dbWrapper = {
|
|
get: (sql, params, cb) => {
|
|
if (!pool) return cb(new Error("DB not ready"));
|
|
pool.query(sql, params, (err, rows) => {
|
|
if (err) return cb(err);
|
|
cb(null, rows[0]);
|
|
});
|
|
},
|
|
all: (sql, params, cb) => {
|
|
// Handle case where params is omitted and cb is second parameter
|
|
if (typeof params === 'function') {
|
|
cb = params;
|
|
params = [];
|
|
}
|
|
if (!pool) return cb(new Error("DB not ready"));
|
|
pool.query(sql, params || [], (err, rows) => {
|
|
cb(err, rows);
|
|
});
|
|
},
|
|
run: (sql, params, cb) => {
|
|
if (!pool) return cb(new Error("DB not ready"));
|
|
pool.query(sql, params, function(err, result) {
|
|
// "this" context in sqlite callback contains changes, mock it if needed
|
|
if (cb) cb(err);
|
|
});
|
|
}
|
|
};
|
|
|
|
module.exports = { db: dbWrapper, init };
|