blackcoffee2 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +664 -0
- package/LICENSE +201 -0
- package/NOTICE +25 -0
- package/README.md +246 -0
- package/apps.zip +0 -0
- package/bin/adminclient +105 -0
- package/bin/blackcoffee +133 -0
- package/cli/admin-users.js +282 -0
- package/cli/commands/app.js +561 -0
- package/cli/commands/config.js +182 -0
- package/cli/commands/db.js +257 -0
- package/cli/commands/server.js +200 -0
- package/config/applications.json +5 -0
- package/config/database.json +28 -0
- package/config/database.json.example +23 -0
- package/config/server.json +32 -0
- package/controllers/admin/AdminController.js +529 -0
- package/controllers/admin/AdminViewController.js +90 -0
- package/controllers/admin/AuthController.js +293 -0
- package/controllers/admin/DatabaseAdminController.js +218 -0
- package/core/SQLiteAdapter.js +333 -0
- package/core/appLoader.js +385 -0
- package/core/databasePoolManager.js +431 -0
- package/core/hotReload.js +363 -0
- package/data/ADMIN-README.md +145 -0
- package/data/CHANGELOG.md +48 -0
- package/data/GTK3-NODE-PROPOSALS.md +410 -0
- package/data/admin-db.js +150 -0
- package/data/admin-gui.js +452 -0
- package/data/blackcoffee_admin.db-shm +0 -0
- package/data/blackcoffee_admin.db-wal +0 -0
- package/data/migrations/001_create_admin_users.sql +33 -0
- package/docs/APP_HOOKS_HANDLER.md +432 -0
- package/docs/APP_HOOKS_REQUIREMENTS.md +588 -0
- package/docs/ARCHITECTURE.md +435 -0
- package/docs/CREAR_APP_Y_USAR_POOLS.md +1595 -0
- package/docs/EVENTS_APP_MANUAL.md +289 -0
- package/docs/INSITU_BINARY_UPLOAD_PROPOSAL.md +186 -0
- package/docs/INSITU_FIREWALL_EXCEPTION.md +187 -0
- package/docs/ROADMAP.md +242 -0
- package/docs/ROADMAP.md.backup +243 -0
- package/includes/404-hooks.js +423 -0
- package/includes/adminAuth.js +214 -0
- package/includes/adminExtension.js +53 -0
- package/includes/appHooks.js +302 -0
- package/includes/initAdminDb.js +115 -0
- package/includes/routeLoader.js +67 -0
- package/includes/sessions.js +223 -0
- package/issues/001-duplicate-module-loading.md +92 -0
- package/manuales/ADMIN_EXTENSION_COMMANDS_MANUAL.md +261 -0
- package/manuales/ADMIN_EXTENSION_HOOK_EXAMPLE.md +28 -0
- package/manuales/ADMIN_EXTENSION_INTEGRATION_MANUAL.md +232 -0
- package/manuales/CACHE_REGEX_COMMANDS.md +136 -0
- package/manuales/CACHE_SYSTEM_MAP.md +206 -0
- package/manuales/CREACION_DE_CONTROLADORES_INSITU.md +383 -0
- package/manuales/QUEUE_CLI_MODULE_MANUAL.md +289 -0
- package/manuales/QUEUE_SYSTEM_MANUAL.md +320 -0
- package/manuales/ROUTE_CACHE_MODULE_MANUAL.md +205 -0
- package/manuales/SESSION_MANAGER_GUIDE.md +529 -0
- package/manuales/SESSION_SECURITY_FLAGS.md +174 -0
- package/manuales/WAF_MODULE_MANUAL.md +229 -0
- package/manuales/after_route_handler_filter_example.md +116 -0
- package/manuales/after_route_handler_usage.md +130 -0
- package/manuales/an/303/241lisis-completo-insitu-framework.md +213 -0
- package/manuales/async_hooks_promises_guide.md +325 -0
- package/manuales/before_route_handler_filter_example.md +97 -0
- package/manuales/before_route_handler_usage.md +122 -0
- package/manuales/hooks_chaining_conditions_guide.md +261 -0
- package/manuales/hooks_filters_documentation.md +493 -0
- package/manuales/hooks_filters_documentation_en.md +493 -0
- package/manuales/hooks_vs_middlewares_comparison.md +87 -0
- package/manuales/manual-mvc-completo.md +934 -0
- package/manuales/modulos_administracion.md +89 -0
- package/manuales/router_execution_points.md +74 -0
- package/manuales/static_file_hooks_usage.md +222 -0
- package/models/AdminUserModel.js +132 -0
- package/package.json +45 -0
- package/programatically/PRoutes.js +89 -0
- package/programatically/initFlow.js +211 -0
- package/public/admin/css/db-pools.css +336 -0
- package/public/admin/css/styles.css +310 -0
- package/public/admin/database.html +312 -0
- package/public/admin/index.html +116 -0
- package/public/admin/js/app.js +470 -0
- package/public/admin/js/db-pools.js +253 -0
- package/public/admin/login.html +278 -0
- package/public/assets/css/styles.css +477 -0
- package/public/assets/js/main.js +89 -0
- package/public/index.html +136 -0
- package/public/templates/404.html +158 -0
- package/routes/admin-views.json +20 -0
- package/routes/admin.json +38 -0
- package/routes/auth.json +32 -0
- package/routes/static.json +18 -0
- package/server.js +299 -0
- package/test-aplicacion.con-logisession/BlackCoffee.js +226 -0
- package/test-aplicacion.con-logisession/SSL_SETUP.md +53 -0
- package/test-aplicacion.con-logisession/certs/ca-certificate.pem +32 -0
- package/test-aplicacion.con-logisession/certs/ca-private-key.pem +52 -0
- package/test-aplicacion.con-logisession/certs/certificate-2048.pem +22 -0
- package/test-aplicacion.con-logisession/certs/certificate.pem +32 -0
- package/test-aplicacion.con-logisession/certs/private-key-2048.pem +28 -0
- package/test-aplicacion.con-logisession/certs/private-key.pem +52 -0
- package/test-aplicacion.con-logisession/config/iaQueueSetup.js +84 -0
- package/test-aplicacion.con-logisession/config/qwen-rules.json +39 -0
- package/test-aplicacion.con-logisession/controllers/analyticsController.js +117 -0
- package/test-aplicacion.con-logisession/controllers/auth/AdminAuthController.js +142 -0
- package/test-aplicacion.con-logisession/controllers/auth/AuthController.js +439 -0
- package/test-aplicacion.con-logisession/controllers/auth/AuthViewController.js +223 -0
- package/test-aplicacion.con-logisession/controllers/endpointController.js +66 -0
- package/test-aplicacion.con-logisession/controllers/example.js +183 -0
- package/test-aplicacion.con-logisession/controllers/iaQueueController.js +367 -0
- package/test-aplicacion.con-logisession/controllers/queueController.js +206 -0
- package/test-aplicacion.con-logisession/controllers/qwenQueueController.js +197 -0
- package/test-aplicacion.con-logisession/controllers/test.js +0 -0
- package/test-aplicacion.con-logisession/controllers/tracking/EventsNoFinishController.js +78 -0
- package/test-aplicacion.con-logisession/controllers/tracking/TrackingController.js +412 -0
- package/test-aplicacion.con-logisession/controllers/tracking/TrackingControllerWithLoadModel.js +437 -0
- package/test-aplicacion.con-logisession/hooks/admin-hooks.js +20 -0
- package/test-aplicacion.con-logisession/hooks/general-hooks.js +97 -0
- package/test-aplicacion.con-logisession/hooks/queue-hooks.js +64 -0
- package/test-aplicacion.con-logisession/hooks/route-directory-hooks.js +38 -0
- package/test-aplicacion.con-logisession/hooks/security-hooks.js +24 -0
- package/test-aplicacion.con-logisession/insitu-admin-client/README.md +69 -0
- package/test-aplicacion.con-logisession/insitu-admin-client/package.json +23 -0
- package/test-aplicacion.con-logisession/insitu-admin-client.js +257 -0
- package/test-aplicacion.con-logisession/models/ExampleModel.js +88 -0
- package/test-aplicacion.con-logisession/models/QueueJobModel.js +263 -0
- package/test-aplicacion.con-logisession/models/TokenModel.js +207 -0
- package/test-aplicacion.con-logisession/models/auth/AuthModel.js +66 -0
- package/test-aplicacion.con-logisession/models/auth/UserModel.js +189 -0
- package/test-aplicacion.con-logisession/models/tracking/CompletedCartModel.js +213 -0
- package/test-aplicacion.con-logisession/models/tracking/EventModel.js +366 -0
- package/test-aplicacion.con-logisession/models/tracking/EventsNoFinishModel.js +131 -0
- package/test-aplicacion.con-logisession/models/tracking/SessionModel.js +360 -0
- package/test-aplicacion.con-logisession/models/tracking/SiteFlowModel.js +286 -0
- package/test-aplicacion.con-logisession/models/tracking/TokenModel.js +207 -0
- package/test-aplicacion.con-logisession/package-lock.json +3313 -0
- package/test-aplicacion.con-logisession/package.json +32 -0
- package/test-aplicacion.con-logisession/public/blackcoffee-welcome/index.html +1339 -0
- package/test-aplicacion.con-logisession/public/css/style.css +64 -0
- package/test-aplicacion.con-logisession/public/ejemplo-estatica/index.html +18 -0
- package/test-aplicacion.con-logisession/public/ejemplo-estatica/script.js +16 -0
- package/test-aplicacion.con-logisession/public/ejemplo-estatica/styles.css +43 -0
- package/test-aplicacion.con-logisession/public/images/logo.svg +7 -0
- package/test-aplicacion.con-logisession/public/js/main.js +67 -0
- package/test-aplicacion.con-logisession/routes/analytics-routes.json +8 -0
- package/test-aplicacion.con-logisession/routes/auth-routes.json +98 -0
- package/test-aplicacion.con-logisession/routes/blackcoffee-welcome-routes.json +20 -0
- package/test-aplicacion.con-logisession/routes/duplicate-test-routes.json.disabled +16 -0
- package/test-aplicacion.con-logisession/routes/ejemplo-estatica-routes.json +11 -0
- package/test-aplicacion.con-logisession/routes/endpoints-routes.json +8 -0
- package/test-aplicacion.con-logisession/routes/ia-queue-routes.json +26 -0
- package/test-aplicacion.con-logisession/routes/product-routes.json.disabled +20 -0
- package/test-aplicacion.con-logisession/routes/queue-routes.json +32 -0
- package/test-aplicacion.con-logisession/routes/qwen-routes.json +14 -0
- package/test-aplicacion.con-logisession/routes/static-routes.json +29 -0
- package/test-aplicacion.con-logisession/routes/tracking-routes.json +58 -0
- package/test-aplicacion.con-logisession/routes/tracking-with-loadmodel-routes.json +51 -0
- package/test-aplicacion.con-logisession/utils/dbAdapter.js +88 -0
- package/test-aplicacion.con-logisession/utils/qbWrapper.js +4 -0
- package/test-aplicacion.con-logisession/utils/queueProcessor.js +305 -0
- package/test-aplicacion.con-logisession/utils/qwenRulesService.js +131 -0
- package/test-aplicacion.con-logisession/utils/tokenHelper.js +22 -0
- package/test-aplicacion.con-logisession/views/auth/dashboard.html +443 -0
- package/test-aplicacion.con-logisession/views/auth/forgot-password.html +200 -0
- package/test-aplicacion.con-logisession/views/auth/login.html +213 -0
- package/test-aplicacion.con-logisession/views/auth/register.html +294 -0
- package/test-aplicacion.con-logisession/views/contact/form.html +47 -0
- package/test-aplicacion.con-logisession/views/products/index.html +39 -0
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// admin-gui.js - Interfaz gráfica GTK3 para administrar usuarios BlackCoffee
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
Button,
|
|
6
|
+
Label,
|
|
7
|
+
Box,
|
|
8
|
+
Scroll,
|
|
9
|
+
Window,
|
|
10
|
+
init,
|
|
11
|
+
run,
|
|
12
|
+
Entry,
|
|
13
|
+
TextView
|
|
14
|
+
} = require('gtk3-node');
|
|
15
|
+
|
|
16
|
+
const AdminDatabase = require('./admin-db.js');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
// ============================================
|
|
20
|
+
// ARGUMENTOS DE LÍNEA DE COMANDOS
|
|
21
|
+
// ============================================
|
|
22
|
+
|
|
23
|
+
function parseArgs() {
|
|
24
|
+
const args = process.argv.slice(2);
|
|
25
|
+
const options = {
|
|
26
|
+
db: null,
|
|
27
|
+
action: null,
|
|
28
|
+
help: false
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
for (let i = 0; i < args.length; i++) {
|
|
32
|
+
if (args[i] === '--db' && args[i + 1]) {
|
|
33
|
+
options.db = args[i + 1];
|
|
34
|
+
i++;
|
|
35
|
+
} else if (args[i] === '-d' && args[i + 1]) {
|
|
36
|
+
options.db = args[i + 1];
|
|
37
|
+
i++;
|
|
38
|
+
} else if (args[i] === '--edit' && args[i + 1]) {
|
|
39
|
+
options.action = { type: 'edit', id: parseInt(args[i + 1]) };
|
|
40
|
+
i++;
|
|
41
|
+
} else if (args[i] === '--delete' && args[i + 1]) {
|
|
42
|
+
options.action = { type: 'delete', id: parseInt(args[i + 1]) };
|
|
43
|
+
i++;
|
|
44
|
+
} else if (args[i] === '--toggle' && args[i + 1]) {
|
|
45
|
+
options.action = { type: 'toggle', id: parseInt(args[i + 1]) };
|
|
46
|
+
i++;
|
|
47
|
+
} else if (args[i] === '--help' || args[i] === '-h') {
|
|
48
|
+
options.help = true;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return options;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function showHelp() {
|
|
56
|
+
console.log(`
|
|
57
|
+
╔═══════════════════════════════════════════════════════════╗
|
|
58
|
+
║ BlackCoffee Admin Panel - Gestión de Usuarios ║
|
|
59
|
+
╠═══════════════════════════════════════════════════════════╣
|
|
60
|
+
║ Uso: node admin-gui.js [opciones] ║
|
|
61
|
+
╠═══════════════════════════════════════════════════════════╣
|
|
62
|
+
║ Opciones: ║
|
|
63
|
+
║ --db, -d <ruta> Ruta a la base de datos SQLite ║
|
|
64
|
+
║ --edit <id> Editar usuario por ID ║
|
|
65
|
+
║ --delete <id> Eliminar usuario por ID ║
|
|
66
|
+
║ --toggle <id> Activar/Desactivar usuario ║
|
|
67
|
+
║ --help, -h Mostrar esta ayuda ║
|
|
68
|
+
╠═══════════════════════════════════════════════════════════╣
|
|
69
|
+
║ Ejemplos: ║
|
|
70
|
+
║ node admin-gui.js ║
|
|
71
|
+
║ node admin-gui.js --db ./blackcoffee_admin.db ║
|
|
72
|
+
║ node admin-gui.js -d /ruta/a/mibase.db ║
|
|
73
|
+
║ node admin-gui.js --edit 1 ║
|
|
74
|
+
╚═══════════════════════════════════════════════════════════╝
|
|
75
|
+
`);
|
|
76
|
+
process.exit(0);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ============================================
|
|
80
|
+
// INICIALIZACIÓN
|
|
81
|
+
// ============================================
|
|
82
|
+
|
|
83
|
+
const options = parseArgs();
|
|
84
|
+
|
|
85
|
+
if (options.help) {
|
|
86
|
+
showHelp();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Inicializar GTK
|
|
90
|
+
init();
|
|
91
|
+
|
|
92
|
+
// Instanciar base de datos
|
|
93
|
+
const dbPath = options.db ? path.resolve(options.db) : null;
|
|
94
|
+
const db = new AdminDatabase(dbPath);
|
|
95
|
+
|
|
96
|
+
// ============================================
|
|
97
|
+
// ACCIONES POR LÍNEA DE COMANDOS
|
|
98
|
+
// ============================================
|
|
99
|
+
|
|
100
|
+
if (options.action) {
|
|
101
|
+
const { type, id } = options.action;
|
|
102
|
+
const user = db.getUserById(id);
|
|
103
|
+
|
|
104
|
+
if (!user) {
|
|
105
|
+
console.log(`❌ Usuario #${id} no encontrado`);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (type === 'edit') {
|
|
110
|
+
console.log(`✏️ Editar usuario #${id}: ${user.username}`);
|
|
111
|
+
console.log(' Email actual:', user.email);
|
|
112
|
+
console.log(' Rol actual:', user.role);
|
|
113
|
+
console.log(' Estado:', user.active ? 'Activo' : 'Inactivo');
|
|
114
|
+
console.log('\nUse la interfaz gráfica para editar.');
|
|
115
|
+
} else if (type === 'delete') {
|
|
116
|
+
console.log(`🗑️ Eliminar usuario #${id}: ${user.username}`);
|
|
117
|
+
db.deleteUser(id);
|
|
118
|
+
console.log('✅ Usuario eliminado');
|
|
119
|
+
process.exit(0);
|
|
120
|
+
} else if (type === 'toggle') {
|
|
121
|
+
console.log(`🔄 Toggle usuario #${id}: ${user.username}`);
|
|
122
|
+
db.toggleUserActive(id);
|
|
123
|
+
console.log('✅ Estado actualizado');
|
|
124
|
+
process.exit(0);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ============================================
|
|
129
|
+
// ESTADO GLOBAL
|
|
130
|
+
// ============================================
|
|
131
|
+
|
|
132
|
+
let usersList = [];
|
|
133
|
+
let editingUserId = null;
|
|
134
|
+
|
|
135
|
+
// ============================================
|
|
136
|
+
// FUNCIONES DE DATOS
|
|
137
|
+
// ============================================
|
|
138
|
+
|
|
139
|
+
function loadUsers() {
|
|
140
|
+
try {
|
|
141
|
+
return db.getAllUsers();
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.error('Error cargando usuarios:', error.message);
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function refreshAndRestart() {
|
|
149
|
+
// Pequeño hack: recargar la aplicación
|
|
150
|
+
setTimeout(() => {
|
|
151
|
+
db.close();
|
|
152
|
+
const { spawn } = require('child_process');
|
|
153
|
+
spawn(process.argv[0], process.argv.slice(1), { detached: true, stdio: 'ignore' });
|
|
154
|
+
process.exit(0);
|
|
155
|
+
}, 300);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ============================================
|
|
159
|
+
// VENTANAS DE DIÁLOGO (Modales simulados)
|
|
160
|
+
// ============================================
|
|
161
|
+
|
|
162
|
+
function createAddUserWindow() {
|
|
163
|
+
const win = new Window('Nuevo Usuario', 400, 280);
|
|
164
|
+
const formBox = new Box('vertical');
|
|
165
|
+
|
|
166
|
+
formBox.add(new Label(''));
|
|
167
|
+
formBox.add(new Label('Nombre de usuario:'));
|
|
168
|
+
const usernameEntry = new Entry('');
|
|
169
|
+
formBox.add(usernameEntry);
|
|
170
|
+
|
|
171
|
+
formBox.add(new Label('Email:'));
|
|
172
|
+
const emailEntry = new Entry('');
|
|
173
|
+
formBox.add(emailEntry);
|
|
174
|
+
|
|
175
|
+
formBox.add(new Label('Rol:'));
|
|
176
|
+
const roleEntry = new Entry('admin');
|
|
177
|
+
formBox.add(roleEntry);
|
|
178
|
+
|
|
179
|
+
formBox.add(new Label(''));
|
|
180
|
+
|
|
181
|
+
const buttonBox = new Box('horizontal');
|
|
182
|
+
|
|
183
|
+
const saveBtn = new Button('💾 Guardar');
|
|
184
|
+
saveBtn.onClick(() => {
|
|
185
|
+
try {
|
|
186
|
+
db.createUser(usernameEntry.text, emailEntry.text, roleEntry.text);
|
|
187
|
+
console.log('✅ Usuario creado:', usernameEntry.text);
|
|
188
|
+
refreshAndRestart();
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.error('❌ Error:', error.message);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const cancelBtn = new Button('Cancelar');
|
|
195
|
+
cancelBtn.onClick(() => {
|
|
196
|
+
console.log('Operación cancelada');
|
|
197
|
+
refreshAndRestart();
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
buttonBox.add(saveBtn);
|
|
201
|
+
buttonBox.add(cancelBtn);
|
|
202
|
+
formBox.add(buttonBox);
|
|
203
|
+
|
|
204
|
+
win.add(formBox);
|
|
205
|
+
win.show();
|
|
206
|
+
|
|
207
|
+
return win;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function createEditUserWindow(user) {
|
|
211
|
+
const win = new Window(`Editar: ${user.username}`, 400, 320);
|
|
212
|
+
const formBox = new Box('vertical');
|
|
213
|
+
|
|
214
|
+
formBox.add(new Label(''));
|
|
215
|
+
formBox.add(new Label('ID: ' + user.id));
|
|
216
|
+
|
|
217
|
+
formBox.add(new Label('Nombre de usuario:'));
|
|
218
|
+
const usernameEntry = new Entry(user.username);
|
|
219
|
+
formBox.add(usernameEntry);
|
|
220
|
+
|
|
221
|
+
formBox.add(new Label('Email:'));
|
|
222
|
+
const emailEntry = new Entry(user.email || '');
|
|
223
|
+
formBox.add(emailEntry);
|
|
224
|
+
|
|
225
|
+
formBox.add(new Label('Rol:'));
|
|
226
|
+
const roleEntry = new Entry(user.role);
|
|
227
|
+
formBox.add(roleEntry);
|
|
228
|
+
|
|
229
|
+
formBox.add(new Label(''));
|
|
230
|
+
formBox.add(new Label(`Estado: ${user.active ? '🟢 Activo' : '🔴 Inactivo'}`));
|
|
231
|
+
formBox.add(new Label(''));
|
|
232
|
+
|
|
233
|
+
const buttonBox = new Box('horizontal');
|
|
234
|
+
|
|
235
|
+
const saveBtn = new Button('💾 Guardar Cambios');
|
|
236
|
+
saveBtn.onClick(() => {
|
|
237
|
+
try {
|
|
238
|
+
db.updateUser(user.id, {
|
|
239
|
+
username: usernameEntry.text,
|
|
240
|
+
email: emailEntry.text,
|
|
241
|
+
role: roleEntry.text
|
|
242
|
+
});
|
|
243
|
+
console.log('✅ Usuario actualizado:', user.id);
|
|
244
|
+
refreshAndRestart();
|
|
245
|
+
} catch (error) {
|
|
246
|
+
console.error('❌ Error:', error.message);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const cancelBtn = new Button('Cancelar');
|
|
251
|
+
cancelBtn.onClick(() => {
|
|
252
|
+
console.log('Operación cancelada');
|
|
253
|
+
refreshAndRestart();
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
buttonBox.add(saveBtn);
|
|
257
|
+
buttonBox.add(cancelBtn);
|
|
258
|
+
formBox.add(buttonBox);
|
|
259
|
+
|
|
260
|
+
win.add(formBox);
|
|
261
|
+
win.show();
|
|
262
|
+
|
|
263
|
+
return win;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function createConfirmWindow(title, message, onConfirm) {
|
|
267
|
+
const win = new Window(title, 350, 150);
|
|
268
|
+
const contentBox = new Box('vertical');
|
|
269
|
+
|
|
270
|
+
contentBox.add(new Label(''));
|
|
271
|
+
contentBox.add(new Label(message));
|
|
272
|
+
contentBox.add(new Label(''));
|
|
273
|
+
|
|
274
|
+
const buttonBox = new Box('horizontal');
|
|
275
|
+
|
|
276
|
+
const confirmBtn = new Button('Confirmar');
|
|
277
|
+
confirmBtn.onClick(() => {
|
|
278
|
+
onConfirm();
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
const cancelBtn = new Button('Cancelar');
|
|
282
|
+
cancelBtn.onClick(() => {
|
|
283
|
+
console.log('Operación cancelada');
|
|
284
|
+
refreshAndRestart();
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
buttonBox.add(confirmBtn);
|
|
288
|
+
buttonBox.add(cancelBtn);
|
|
289
|
+
contentBox.add(buttonBox);
|
|
290
|
+
|
|
291
|
+
win.add(contentBox);
|
|
292
|
+
win.show();
|
|
293
|
+
|
|
294
|
+
return win;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// ============================================
|
|
298
|
+
// VISTA PRINCIPAL
|
|
299
|
+
// ============================================
|
|
300
|
+
|
|
301
|
+
function createMainView() {
|
|
302
|
+
const mainLayout = new Box('vertical');
|
|
303
|
+
|
|
304
|
+
// Header con stats
|
|
305
|
+
const stats = db.getStats();
|
|
306
|
+
const headerLabel = new Label(`👥 BlackCoffee Admin - Total: ${stats.total} | 🟢 Activos: ${stats.active} | 🔴 Inactivos: ${stats.inactive}`);
|
|
307
|
+
mainLayout.add(headerLabel);
|
|
308
|
+
|
|
309
|
+
// Toolbar
|
|
310
|
+
const toolbarBox = new Box('horizontal');
|
|
311
|
+
|
|
312
|
+
const addBtn = new Button('➕ Nuevo');
|
|
313
|
+
addBtn.onClick(() => {
|
|
314
|
+
createAddUserWindow();
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
const refreshBtn = new Button('🔄 Refrescar');
|
|
318
|
+
refreshBtn.onClick(() => {
|
|
319
|
+
refreshAndRestart();
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
const closeBtn = new Button('❌ Salir');
|
|
323
|
+
closeBtn.onClick(() => {
|
|
324
|
+
db.close();
|
|
325
|
+
Window.quit();
|
|
326
|
+
process.exit(0);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
toolbarBox.add(addBtn);
|
|
330
|
+
toolbarBox.add(refreshBtn);
|
|
331
|
+
toolbarBox.add(closeBtn);
|
|
332
|
+
mainLayout.add(toolbarBox);
|
|
333
|
+
|
|
334
|
+
// Separador
|
|
335
|
+
mainLayout.add(new Label(''));
|
|
336
|
+
mainLayout.add(new Label('═══════════════════════════════════════════════════════════'));
|
|
337
|
+
|
|
338
|
+
// Encabezados de columna
|
|
339
|
+
const headerBox = new Box('horizontal');
|
|
340
|
+
headerBox.add(new Label(' ID '));
|
|
341
|
+
headerBox.add(new Label(' Usuario '));
|
|
342
|
+
headerBox.add(new Label(' Email '));
|
|
343
|
+
headerBox.add(new Label(' Rol '));
|
|
344
|
+
headerBox.add(new Label(' Estado '));
|
|
345
|
+
headerBox.add(new Label(' Acciones'));
|
|
346
|
+
mainLayout.add(headerBox);
|
|
347
|
+
|
|
348
|
+
mainLayout.add(new Label('─────────────────────────────────────────────────────────────'));
|
|
349
|
+
|
|
350
|
+
// Lista de usuarios
|
|
351
|
+
usersList = loadUsers();
|
|
352
|
+
|
|
353
|
+
if (usersList.length === 0) {
|
|
354
|
+
mainLayout.add(new Label(' No hay usuarios registrados.'));
|
|
355
|
+
mainLayout.add(new Label(' Use "➕ Nuevo" para crear uno.'));
|
|
356
|
+
} else {
|
|
357
|
+
usersList.forEach(user => {
|
|
358
|
+
const rowBox = new Box('horizontal');
|
|
359
|
+
|
|
360
|
+
const statusIcon = user.active ? '🟢' : '🔴';
|
|
361
|
+
const roleIcon = user.role === 'superadmin' ? '👑' : '🔹';
|
|
362
|
+
const statusText = user.active ? 'Activo ' : 'Inactivo ';
|
|
363
|
+
|
|
364
|
+
let emailDisplay = user.email || 'sin@email.com';
|
|
365
|
+
if (emailDisplay.length > 28) {
|
|
366
|
+
emailDisplay = emailDisplay.substring(0, 25) + '...';
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const idStr = user.id.toString().padStart(4, ' ');
|
|
370
|
+
const usernameStr = user.username.padEnd(18, ' ');
|
|
371
|
+
const emailStr = emailDisplay.padEnd(28, ' ');
|
|
372
|
+
const roleStr = user.role.padEnd(10, ' ');
|
|
373
|
+
|
|
374
|
+
rowBox.add(new Label(` ${idStr} `));
|
|
375
|
+
rowBox.add(new Label(` ${statusIcon} ${usernameStr} `));
|
|
376
|
+
rowBox.add(new Label(` ${emailStr} `));
|
|
377
|
+
rowBox.add(new Label(` ${roleIcon} ${roleStr} `));
|
|
378
|
+
rowBox.add(new Label(` ${statusText} `));
|
|
379
|
+
|
|
380
|
+
// Botón Editar
|
|
381
|
+
const editBtn = new Button('✏️');
|
|
382
|
+
editBtn.onClick(() => {
|
|
383
|
+
createEditUserWindow(user);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// Botón Toggle
|
|
387
|
+
const toggleBtn = new Button(user.active ? '🔓' : '🔒');
|
|
388
|
+
toggleBtn.onClick(() => {
|
|
389
|
+
const action = user.active ? 'desactivar' : 'activar';
|
|
390
|
+
createConfirmWindow(
|
|
391
|
+
`Confirmar ${action}`,
|
|
392
|
+
`¿${action.charAt(0).toUpperCase() + action.slice(1)} a "${user.username}"?`,
|
|
393
|
+
() => {
|
|
394
|
+
db.toggleUserActive(user.id);
|
|
395
|
+
console.log(`✅ Usuario ${action}do:`, user.id);
|
|
396
|
+
refreshAndRestart();
|
|
397
|
+
}
|
|
398
|
+
);
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// Botón Eliminar
|
|
402
|
+
const deleteBtn = new Button('🗑️');
|
|
403
|
+
deleteBtn.onClick(() => {
|
|
404
|
+
createConfirmWindow(
|
|
405
|
+
'Confirmar Eliminación',
|
|
406
|
+
`¿Eliminar usuario "${user.username}"?\nEsta acción no se puede deshacer.`,
|
|
407
|
+
() => {
|
|
408
|
+
db.deleteUser(user.id);
|
|
409
|
+
console.log('✅ Usuario eliminado:', user.id);
|
|
410
|
+
refreshAndRestart();
|
|
411
|
+
}
|
|
412
|
+
);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
rowBox.add(editBtn);
|
|
416
|
+
rowBox.add(toggleBtn);
|
|
417
|
+
rowBox.add(deleteBtn);
|
|
418
|
+
|
|
419
|
+
mainLayout.add(rowBox);
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Separador inferior
|
|
424
|
+
mainLayout.add(new Label('─────────────────────────────────────────────────────────────'));
|
|
425
|
+
mainLayout.add(new Label(` Total: ${usersList.length} usuario(s)`));
|
|
426
|
+
|
|
427
|
+
return mainLayout;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// ============================================
|
|
431
|
+
// VENTANA PRINCIPAL
|
|
432
|
+
// ============================================
|
|
433
|
+
|
|
434
|
+
const mainWindow = new Window('BlackCoffee Admin Panel', 950, 500);
|
|
435
|
+
|
|
436
|
+
const scroll = new Scroll();
|
|
437
|
+
const mainView = createMainView();
|
|
438
|
+
scroll.add(mainView);
|
|
439
|
+
|
|
440
|
+
mainWindow.add(scroll);
|
|
441
|
+
mainWindow.show();
|
|
442
|
+
|
|
443
|
+
console.log('╔═══════════════════════════════════════════════════════════╗');
|
|
444
|
+
console.log('║ BlackCoffee Admin Panel - Gestión de Usuarios ║');
|
|
445
|
+
console.log('╠═══════════════════════════════════════════════════════════╣');
|
|
446
|
+
console.log(`║ Usuarios cargados: ${usersList.length.toString().padEnd(35)} ║`);
|
|
447
|
+
console.log('║ ║');
|
|
448
|
+
console.log('║ 🟢 Activo | 🔴 Inactivo | ✏️ Editar | 🗑️ Eliminar ║');
|
|
449
|
+
console.log('╚═══════════════════════════════════════════════════════════╝');
|
|
450
|
+
|
|
451
|
+
// Iniciar loop de eventos GTK
|
|
452
|
+
run();
|
|
Binary file
|
|
File without changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
-- Migración: Crear tabla de usuarios administradores
|
|
2
|
+
-- BlackCoffee Admin Users Table
|
|
3
|
+
|
|
4
|
+
CREATE TABLE IF NOT EXISTS admin_users (
|
|
5
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
6
|
+
username TEXT UNIQUE NOT NULL,
|
|
7
|
+
password_hash TEXT NOT NULL,
|
|
8
|
+
email TEXT UNIQUE,
|
|
9
|
+
role TEXT DEFAULT 'admin',
|
|
10
|
+
active INTEGER DEFAULT 1,
|
|
11
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
12
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
13
|
+
last_login DATETIME
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
-- Índice para búsquedas por username
|
|
17
|
+
CREATE INDEX IF NOT EXISTS idx_admin_users_username ON admin_users(username);
|
|
18
|
+
|
|
19
|
+
-- Índice para estado activo
|
|
20
|
+
CREATE INDEX IF NOT EXISTS idx_admin_users_active ON admin_users(active);
|
|
21
|
+
|
|
22
|
+
-- Insertar usuario admin por defecto (password: bl4ckc0ff33)
|
|
23
|
+
-- El hash se genera con: salt + ':' + pbkdf2(password, salt, 1000, 64, sha512)
|
|
24
|
+
-- NOTA: Este usuario debe ser cambiado en producción
|
|
25
|
+
|
|
26
|
+
INSERT OR IGNORE INTO admin_users (username, password_hash, email, role, active)
|
|
27
|
+
VALUES (
|
|
28
|
+
'admin',
|
|
29
|
+
'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6:8f4e5d6c7b8a9f0e1d2c3b4a5f6e7d8c9b0a1f2e3d4c5b6a7f8e9d0c1b2a3f4e5d6c7b8a9f0e1d2c3b4a5f6e7d8c9b0a1f2e3d4c5b6a7f8e9d0c1b2a3f4',
|
|
30
|
+
'admin@blackcoffee.local',
|
|
31
|
+
'superadmin',
|
|
32
|
+
1
|
|
33
|
+
);
|