feat(admin): centralize subscriptions under /admin?tab=subscriptions
Replaced the dedicated /admin/subscriptions page with a redirect to the central admin panel’s subscriptions tab. Removed session checks, imports, and the AdminSubscriptionDashboard since routing and access are now handled centrally. This streamlines admin UX and keeps access control unified.
This commit is contained in:
1 parent
d8e7d5d7e6
commit
62ab5b2608
19 files changed
+3091
-357
No files matched your search
@@ -9,212 +9,20 @@
|
||||
|
||||
import { config } from "dotenv";
|
||||
import { resolve } from "path";
|
||||
import path from "node:path";
|
||||
|
||||
// Carregar variáveis de ambiente
|
||||
config({ path: resolve(process.cwd(), ".env.local") });
|
||||
config({ path: resolve(process.cwd(), ".env") });
|
||||
|
||||
import { getPool, query } from "../lib/db/index";
|
||||
import { enToPtCategoryMap } from "../lib/item-images";
|
||||
|
||||
// Mapeamento de tabelas PT para categorias EN
|
||||
const ptToEnCategoryMap: Record<string, string> = {
|
||||
espadas: "weapon",
|
||||
armaduras: "armor",
|
||||
capacetes: "helmet",
|
||||
calcas: "legs",
|
||||
botas: "boots",
|
||||
escudos: "shield",
|
||||
amuletos: "amulet",
|
||||
aneis: "ring",
|
||||
runas: "rune",
|
||||
ferramentas: "tool",
|
||||
municao: "ammunition",
|
||||
};
|
||||
|
||||
function getDatabase() {
|
||||
let Database: any;
|
||||
try {
|
||||
Database = require("better-sqlite3");
|
||||
} catch (err) {
|
||||
console.error("better-sqlite3 não está instalado");
|
||||
return null;
|
||||
}
|
||||
|
||||
const dbPath = path.join(process.cwd(), "data", "tibiawiki.db");
|
||||
const db = new Database(dbPath, { readonly: true, fileMustExist: true });
|
||||
return db;
|
||||
}
|
||||
|
||||
interface ItemRow {
|
||||
id: number;
|
||||
nome: string;
|
||||
image_url?: string;
|
||||
image_local_path?: string;
|
||||
rarity?: string;
|
||||
lvl?: number;
|
||||
peso?: number;
|
||||
peso_em_oz?: number;
|
||||
slots?: number;
|
||||
skill_para_usar?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
import { importItemsFromSQLite } from "@/lib/items/import-from-sqlite";
|
||||
import { secureLogger } from "@/lib/secure-logger";
|
||||
|
||||
async function populateItemsTable() {
|
||||
console.log("🚀 Iniciando população da tabela items...\n");
|
||||
config({ path: resolve(process.cwd(), ".env.local") });
|
||||
config({ path: resolve(process.cwd(), ".env") });
|
||||
|
||||
const db = getDatabase();
|
||||
if (!db) {
|
||||
console.error("⌠Não foi possÃvel conectar ao SQLite");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
// Obter todas as tabelas
|
||||
const tables = db
|
||||
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'")
|
||||
.all() as { name: string }[];
|
||||
|
||||
console.log(`📋 Encontradas ${tables.length} tabelas\n`);
|
||||
|
||||
let totalInserted = 0;
|
||||
let totalSkipped = 0;
|
||||
|
||||
for (const table of tables) {
|
||||
const tableName = table.name;
|
||||
const categoryEn = ptToEnCategoryMap[tableName] || "other";
|
||||
|
||||
console.log(`📦 Processando tabela: ${tableName} (categoria: ${categoryEn})...`);
|
||||
|
||||
try {
|
||||
// Verificar se a tabela tem as colunas necessárias
|
||||
const columns = db
|
||||
.prepare(`PRAGMA table_info(${tableName})`)
|
||||
.all() as { name: string; type: string }[];
|
||||
|
||||
const colNames = new Set(columns.map((c) => c.name.toLowerCase()));
|
||||
|
||||
if (!colNames.has("id") || !colNames.has("nome")) {
|
||||
console.log(` âš ï¸ Tabela ${tableName} não tem colunas id/nome, pulando...`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Buscar todos os itens da tabela
|
||||
const items = db.prepare(`SELECT * FROM ${tableName}`).all() as ItemRow[];
|
||||
|
||||
console.log(` 📊 Encontrados ${items.length} itens`);
|
||||
|
||||
for (const item of items) {
|
||||
try {
|
||||
// Verificar se já existe (baseado em source_table_name + source_table_id)
|
||||
const existing = await query<{ item_id: number }>(
|
||||
`SELECT item_id FROM items
|
||||
WHERE source_table_name = $1 AND source_table_id = $2`,
|
||||
[tableName, item.id]
|
||||
);
|
||||
|
||||
if (existing.rows.length > 0) {
|
||||
totalSkipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Preparar dados do item
|
||||
const itemName = item.nome || "";
|
||||
const imageUrl = item.image_url || null;
|
||||
const imageLocalPath = item.image_local_path || null;
|
||||
const rarity = item.rarity || null;
|
||||
const level = item.lvl || null;
|
||||
|
||||
// Peso (pode ser em peso ou peso_em_oz)
|
||||
const weight = item.peso || item.peso_em_oz || null;
|
||||
|
||||
const slots = item.slots || null;
|
||||
const skill = item.skill_para_usar || null;
|
||||
|
||||
// Metadata com campos extras
|
||||
const metadata: Record<string, any> = {};
|
||||
|
||||
// Adicionar campos extras ao metadata
|
||||
const extraFields = [
|
||||
"voc",
|
||||
"volume",
|
||||
"bonus_de_skill",
|
||||
"protecao",
|
||||
"dropa_de",
|
||||
];
|
||||
|
||||
for (const field of extraFields) {
|
||||
if (colNames.has(field) && item[field] !== undefined && item[field] !== null) {
|
||||
metadata[field] = item[field];
|
||||
}
|
||||
}
|
||||
|
||||
// Inserir na tabela items
|
||||
await query(
|
||||
`INSERT INTO items (
|
||||
source_table_id,
|
||||
source_table_name,
|
||||
item_name,
|
||||
category,
|
||||
image_local_path,
|
||||
image_url,
|
||||
rarity,
|
||||
level,
|
||||
weight,
|
||||
slots,
|
||||
skill,
|
||||
metadata
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`,
|
||||
[
|
||||
item.id,
|
||||
tableName,
|
||||
itemName,
|
||||
categoryEn,
|
||||
imageLocalPath,
|
||||
imageUrl,
|
||||
rarity,
|
||||
level,
|
||||
weight,
|
||||
slots,
|
||||
skill,
|
||||
JSON.stringify(metadata),
|
||||
]
|
||||
);
|
||||
|
||||
totalInserted++;
|
||||
} catch (error: any) {
|
||||
if (error.code === "23505") {
|
||||
// Unique constraint violation - já existe
|
||||
totalSkipped++;
|
||||
} else {
|
||||
console.error(` ⌠Erro ao inserir item ${item.nome}:`, error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(` ✅ Tabela ${tableName} processada\n`);
|
||||
} catch (error: any) {
|
||||
console.error(` ⌠Erro ao processar tabela ${tableName}:`, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("\n📊 Resumo:");
|
||||
console.log(` ✅ Itens inseridos: ${totalInserted}`);
|
||||
console.log(` âï¸ Itens ignorados (já existentes): ${totalSkipped}`);
|
||||
console.log(` 📦 Total processado: ${totalInserted + totalSkipped}\n`);
|
||||
|
||||
console.log("✨ População concluÃda com sucesso!");
|
||||
} finally {
|
||||
db.close();
|
||||
const pool = getPool();
|
||||
await pool.end();
|
||||
}
|
||||
secureLogger.info("Iniciando importação manual de itens (script standalone).");
|
||||
const stats = await importItemsFromSQLite();
|
||||
secureLogger.info("Importação manual finalizada.", stats);
|
||||
}
|
||||
|
||||
// Executar
|
||||
populateItemsTable().catch((error) => {
|
||||
console.error("⌠Erro fatal:", error);
|
||||
secureLogger.error("Erro ao executar importação manual de itens", error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user