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,213 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Iniciar Sesión - BlackCoffee</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
body {
|
|
16
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
17
|
+
min-height: 100vh;
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
padding: 20px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.login-container {
|
|
25
|
+
background: white;
|
|
26
|
+
padding: 40px;
|
|
27
|
+
border-radius: 10px;
|
|
28
|
+
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1);
|
|
29
|
+
width: 100%;
|
|
30
|
+
max-width: 400px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.login-header {
|
|
34
|
+
text-align: center;
|
|
35
|
+
margin-bottom: 30px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.login-header h1 {
|
|
39
|
+
color: #333;
|
|
40
|
+
font-size: 28px;
|
|
41
|
+
margin-bottom: 10px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.login-header p {
|
|
45
|
+
color: #666;
|
|
46
|
+
font-size: 14px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.form-group {
|
|
50
|
+
margin-bottom: 20px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.form-group label {
|
|
54
|
+
display: block;
|
|
55
|
+
margin-bottom: 8px;
|
|
56
|
+
color: #333;
|
|
57
|
+
font-weight: 500;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.form-group input {
|
|
61
|
+
width: 100%;
|
|
62
|
+
padding: 12px 15px;
|
|
63
|
+
border: 2px solid #e1e1e1;
|
|
64
|
+
border-radius: 5px;
|
|
65
|
+
font-size: 16px;
|
|
66
|
+
transition: border-color 0.3s ease;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.form-group input:focus {
|
|
70
|
+
outline: none;
|
|
71
|
+
border-color: #667eea;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.btn {
|
|
75
|
+
width: 100%;
|
|
76
|
+
padding: 12px;
|
|
77
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
78
|
+
color: white;
|
|
79
|
+
border: none;
|
|
80
|
+
border-radius: 5px;
|
|
81
|
+
font-size: 16px;
|
|
82
|
+
font-weight: 600;
|
|
83
|
+
cursor: pointer;
|
|
84
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.btn:hover {
|
|
88
|
+
transform: translateY(-2px);
|
|
89
|
+
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.btn:active {
|
|
93
|
+
transform: translateY(0);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.login-footer {
|
|
97
|
+
text-align: center;
|
|
98
|
+
margin-top: 20px;
|
|
99
|
+
color: #666;
|
|
100
|
+
font-size: 14px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.login-footer a {
|
|
104
|
+
color: #667eea;
|
|
105
|
+
text-decoration: none;
|
|
106
|
+
font-weight: 500;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.login-footer a:hover {
|
|
110
|
+
text-decoration: underline;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.error-message {
|
|
114
|
+
display: none;
|
|
115
|
+
background: #fee;
|
|
116
|
+
color: #c33;
|
|
117
|
+
padding: 10px;
|
|
118
|
+
border-radius: 5px;
|
|
119
|
+
margin-bottom: 15px;
|
|
120
|
+
text-align: center;
|
|
121
|
+
font-size: 14px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.success-message {
|
|
125
|
+
display: none;
|
|
126
|
+
background: #efe;
|
|
127
|
+
color: #363;
|
|
128
|
+
padding: 10px;
|
|
129
|
+
border-radius: 5px;
|
|
130
|
+
margin-bottom: 15px;
|
|
131
|
+
text-align: center;
|
|
132
|
+
font-size: 14px;
|
|
133
|
+
}
|
|
134
|
+
</style>
|
|
135
|
+
</head>
|
|
136
|
+
<body>
|
|
137
|
+
<div class="login-container">
|
|
138
|
+
<div class="login-header">
|
|
139
|
+
<h1>Iniciar Sesión</h1>
|
|
140
|
+
<p>Accede a tu cuenta para continuar</p>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
<div id="errorMessage" class="error-message"></div>
|
|
144
|
+
<div id="successMessage" class="success-message"></div>
|
|
145
|
+
|
|
146
|
+
<form id="loginForm">
|
|
147
|
+
<div class="form-group">
|
|
148
|
+
<label for="username">Usuario o Email</label>
|
|
149
|
+
<input type="text" id="username" name="username" required placeholder="Ingresa tu usuario o email">
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<div class="form-group">
|
|
153
|
+
<label for="password">Contraseña</label>
|
|
154
|
+
<input type="password" id="password" name="password" required placeholder="Ingresa tu contraseña">
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
<button type="submit" class="btn">Iniciar Sesión</button>
|
|
158
|
+
</form>
|
|
159
|
+
|
|
160
|
+
<div class="login-footer">
|
|
161
|
+
<p>¿No tienes una cuenta? <a href="/register">Regístrate aquí</a></p>
|
|
162
|
+
<p><a href="/forgot-password">¿Olvidaste tu contraseña?</a></p>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
<script>
|
|
167
|
+
document.getElementById('loginForm').addEventListener('submit', async (e) => {
|
|
168
|
+
e.preventDefault();
|
|
169
|
+
|
|
170
|
+
const username = document.getElementById('username').value;
|
|
171
|
+
const password = document.getElementById('password').value;
|
|
172
|
+
const errorMessage = document.getElementById('errorMessage');
|
|
173
|
+
const successMessage = document.getElementById('successMessage');
|
|
174
|
+
|
|
175
|
+
// Ocultar mensajes anteriores
|
|
176
|
+
errorMessage.style.display = 'none';
|
|
177
|
+
successMessage.style.display = 'none';
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
const response = await fetch('/api/auth/login', {
|
|
181
|
+
method: 'POST',
|
|
182
|
+
headers: {
|
|
183
|
+
'Content-Type': 'application/json',
|
|
184
|
+
},
|
|
185
|
+
body: JSON.stringify({ username, password })
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const data = await response.json();
|
|
189
|
+
|
|
190
|
+
if (data.success) {
|
|
191
|
+
// Guardar el token en localStorage
|
|
192
|
+
localStorage.setItem('authToken', data.token);
|
|
193
|
+
|
|
194
|
+
// Mostrar mensaje de éxito
|
|
195
|
+
successMessage.textContent = 'Inicio de sesión exitoso. Redirigiendo...';
|
|
196
|
+
successMessage.style.display = 'block';
|
|
197
|
+
|
|
198
|
+
// Redirigir al dashboard o página principal
|
|
199
|
+
window.location.href = '/dashboard';
|
|
200
|
+
} else {
|
|
201
|
+
// Mostrar mensaje de error
|
|
202
|
+
errorMessage.textContent = data.error || 'Credenciales inválidas';
|
|
203
|
+
errorMessage.style.display = 'block';
|
|
204
|
+
}
|
|
205
|
+
} catch (error) {
|
|
206
|
+
console.error('Error en el inicio de sesión:', error);
|
|
207
|
+
errorMessage.textContent = 'Error de conexión. Por favor, inténtalo de nuevo.';
|
|
208
|
+
errorMessage.style.display = 'block';
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
</script>
|
|
212
|
+
</body>
|
|
213
|
+
</html>
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Registrarse - BlackCoffee</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
body {
|
|
16
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
17
|
+
min-height: 100vh;
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
padding: 20px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.register-container {
|
|
25
|
+
background: white;
|
|
26
|
+
padding: 40px;
|
|
27
|
+
border-radius: 10px;
|
|
28
|
+
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1);
|
|
29
|
+
width: 100%;
|
|
30
|
+
max-width: 450px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.register-header {
|
|
34
|
+
text-align: center;
|
|
35
|
+
margin-bottom: 30px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.register-header h1 {
|
|
39
|
+
color: #333;
|
|
40
|
+
font-size: 28px;
|
|
41
|
+
margin-bottom: 10px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.register-header p {
|
|
45
|
+
color: #666;
|
|
46
|
+
font-size: 14px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.form-group {
|
|
50
|
+
margin-bottom: 20px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.form-group label {
|
|
54
|
+
display: block;
|
|
55
|
+
margin-bottom: 8px;
|
|
56
|
+
color: #333;
|
|
57
|
+
font-weight: 500;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.form-group input {
|
|
61
|
+
width: 100%;
|
|
62
|
+
padding: 12px 15px;
|
|
63
|
+
border: 2px solid #e1e1e1;
|
|
64
|
+
border-radius: 5px;
|
|
65
|
+
font-size: 16px;
|
|
66
|
+
transition: border-color 0.3s ease;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.form-group input:focus {
|
|
70
|
+
outline: none;
|
|
71
|
+
border-color: #667eea;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.btn {
|
|
75
|
+
width: 100%;
|
|
76
|
+
padding: 12px;
|
|
77
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
78
|
+
color: white;
|
|
79
|
+
border: none;
|
|
80
|
+
border-radius: 5px;
|
|
81
|
+
font-size: 16px;
|
|
82
|
+
font-weight: 600;
|
|
83
|
+
cursor: pointer;
|
|
84
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.btn:hover {
|
|
88
|
+
transform: translateY(-2px);
|
|
89
|
+
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.btn:active {
|
|
93
|
+
transform: translateY(0);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.register-footer {
|
|
97
|
+
text-align: center;
|
|
98
|
+
margin-top: 20px;
|
|
99
|
+
color: #666;
|
|
100
|
+
font-size: 14px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.register-footer a {
|
|
104
|
+
color: #667eea;
|
|
105
|
+
text-decoration: none;
|
|
106
|
+
font-weight: 500;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.register-footer a:hover {
|
|
110
|
+
text-decoration: underline;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.error-message {
|
|
114
|
+
display: none;
|
|
115
|
+
background: #fee;
|
|
116
|
+
color: #c33;
|
|
117
|
+
padding: 10px;
|
|
118
|
+
border-radius: 5px;
|
|
119
|
+
margin-bottom: 15px;
|
|
120
|
+
text-align: center;
|
|
121
|
+
font-size: 14px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.success-message {
|
|
125
|
+
display: none;
|
|
126
|
+
background: #efe;
|
|
127
|
+
color: #363;
|
|
128
|
+
padding: 10px;
|
|
129
|
+
border-radius: 5px;
|
|
130
|
+
margin-bottom: 15px;
|
|
131
|
+
text-align: center;
|
|
132
|
+
font-size: 14px;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.password-strength {
|
|
136
|
+
height: 5px;
|
|
137
|
+
background: #eee;
|
|
138
|
+
border-radius: 3px;
|
|
139
|
+
margin-top: 5px;
|
|
140
|
+
overflow: hidden;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.strength-meter {
|
|
144
|
+
height: 100%;
|
|
145
|
+
width: 0%;
|
|
146
|
+
background: #ccc;
|
|
147
|
+
transition: width 0.3s, background 0.3s;
|
|
148
|
+
}
|
|
149
|
+
</style>
|
|
150
|
+
</head>
|
|
151
|
+
<body>
|
|
152
|
+
<div class="register-container">
|
|
153
|
+
<div class="register-header">
|
|
154
|
+
<h1>Crear Cuenta</h1>
|
|
155
|
+
<p>Regístrate para acceder a todas las funcionalidades</p>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<div id="errorMessage" class="error-message"></div>
|
|
159
|
+
<div id="successMessage" class="success-message"></div>
|
|
160
|
+
|
|
161
|
+
<form id="registerForm">
|
|
162
|
+
<div class="form-group">
|
|
163
|
+
<label for="username">Nombre de Usuario</label>
|
|
164
|
+
<input type="text" id="username" name="username" required placeholder="Ingresa tu nombre de usuario">
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
<div class="form-group">
|
|
168
|
+
<label for="email">Email</label>
|
|
169
|
+
<input type="email" id="email" name="email" required placeholder="Ingresa tu email">
|
|
170
|
+
</div>
|
|
171
|
+
|
|
172
|
+
<div class="form-group">
|
|
173
|
+
<label for="password">Contraseña</label>
|
|
174
|
+
<input type="password" id="password" name="password" required placeholder="Crea una contraseña segura">
|
|
175
|
+
<div class="password-strength">
|
|
176
|
+
<div id="strengthMeter" class="strength-meter"></div>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<div class="form-group">
|
|
181
|
+
<label for="confirmPassword">Confirmar Contraseña</label>
|
|
182
|
+
<input type="password" id="confirmPassword" name="confirmPassword" required placeholder="Confirma tu contraseña">
|
|
183
|
+
</div>
|
|
184
|
+
|
|
185
|
+
<button type="submit" class="btn">Registrarse</button>
|
|
186
|
+
</form>
|
|
187
|
+
|
|
188
|
+
<div class="register-footer">
|
|
189
|
+
<p>¿Ya tienes una cuenta? <a href="/login">Inicia sesión aquí</a></p>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
<script>
|
|
194
|
+
// Función para evaluar la fortaleza de la contraseña
|
|
195
|
+
function checkPasswordStrength(password) {
|
|
196
|
+
let strength = 0;
|
|
197
|
+
const length = password.length;
|
|
198
|
+
const hasLower = /[a-z]/.test(password);
|
|
199
|
+
const hasUpper = /[A-Z]/.test(password);
|
|
200
|
+
const hasNumber = /\d/.test(password);
|
|
201
|
+
const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/.test(password);
|
|
202
|
+
|
|
203
|
+
if (length > 0) strength += 1;
|
|
204
|
+
if (length >= 6) strength += 1;
|
|
205
|
+
if (length >= 8) strength += 1;
|
|
206
|
+
if (hasLower) strength += 1;
|
|
207
|
+
if (hasUpper) strength += 1;
|
|
208
|
+
if (hasNumber) strength += 1;
|
|
209
|
+
if (hasSpecial) strength += 1;
|
|
210
|
+
|
|
211
|
+
return Math.min(strength, 7);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Actualizar la barra de fortaleza de contraseña
|
|
215
|
+
document.getElementById('password').addEventListener('input', function() {
|
|
216
|
+
const password = this.value;
|
|
217
|
+
const strength = checkPasswordStrength(password);
|
|
218
|
+
const meter = document.getElementById('strengthMeter');
|
|
219
|
+
const percentage = (strength / 7) * 100;
|
|
220
|
+
|
|
221
|
+
meter.style.width = percentage + '%';
|
|
222
|
+
|
|
223
|
+
// Cambiar color según la fortaleza
|
|
224
|
+
if (strength < 3) {
|
|
225
|
+
meter.style.background = '#ff4757';
|
|
226
|
+
} else if (strength < 5) {
|
|
227
|
+
meter.style.background = '#ffa502';
|
|
228
|
+
} else {
|
|
229
|
+
meter.style.background = '#2ed573';
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
document.getElementById('registerForm').addEventListener('submit', async (e) => {
|
|
234
|
+
e.preventDefault();
|
|
235
|
+
|
|
236
|
+
const username = document.getElementById('username').value;
|
|
237
|
+
const email = document.getElementById('email').value;
|
|
238
|
+
const password = document.getElementById('password').value;
|
|
239
|
+
const confirmPassword = document.getElementById('confirmPassword').value;
|
|
240
|
+
const errorMessage = document.getElementById('errorMessage');
|
|
241
|
+
const successMessage = document.getElementById('successMessage');
|
|
242
|
+
|
|
243
|
+
// Validar que las contraseñas coincidan
|
|
244
|
+
if (password !== confirmPassword) {
|
|
245
|
+
errorMessage.textContent = 'Las contraseñas no coinciden';
|
|
246
|
+
errorMessage.style.display = 'block';
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Validar longitud mínima de contraseña
|
|
251
|
+
if (password.length < 6) {
|
|
252
|
+
errorMessage.textContent = 'La contraseña debe tener al menos 6 caracteres';
|
|
253
|
+
errorMessage.style.display = 'block';
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Ocultar mensajes anteriores
|
|
258
|
+
errorMessage.style.display = 'none';
|
|
259
|
+
successMessage.style.display = 'none';
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
const response = await fetch('/api/auth/register', {
|
|
263
|
+
method: 'POST',
|
|
264
|
+
headers: {
|
|
265
|
+
'Content-Type': 'application/json',
|
|
266
|
+
},
|
|
267
|
+
body: JSON.stringify({ username, email, password })
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
const data = await response.json();
|
|
271
|
+
|
|
272
|
+
if (data.success) {
|
|
273
|
+
// Mostrar mensaje de éxito
|
|
274
|
+
successMessage.textContent = 'Registro exitoso. Redirigiendo al inicio de sesión...';
|
|
275
|
+
successMessage.style.display = 'block';
|
|
276
|
+
|
|
277
|
+
// Redirigir al login después de 2 segundos
|
|
278
|
+
setTimeout(() => {
|
|
279
|
+
window.location.href = '/login';
|
|
280
|
+
}, 2000);
|
|
281
|
+
} else {
|
|
282
|
+
// Mostrar mensaje de error
|
|
283
|
+
errorMessage.textContent = data.error || 'Error en el registro';
|
|
284
|
+
errorMessage.style.display = 'block';
|
|
285
|
+
}
|
|
286
|
+
} catch (error) {
|
|
287
|
+
console.error('Error en el registro:', error);
|
|
288
|
+
errorMessage.textContent = 'Error de conexión. Por favor, inténtalo de nuevo.';
|
|
289
|
+
errorMessage.style.display = 'block';
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
</script>
|
|
293
|
+
</body>
|
|
294
|
+
</html>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>{{title}}</title>
|
|
7
|
+
<link rel="stylesheet" href="/static/css/style.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="header">
|
|
11
|
+
<h1>{{title}}</h1>
|
|
12
|
+
<nav>
|
|
13
|
+
<a href="/" class="button">Inicio</a>
|
|
14
|
+
<a href="/contact" class="button">Contacto</a>
|
|
15
|
+
</nav>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div class="content">
|
|
19
|
+
<h2>Contáctanos</h2>
|
|
20
|
+
|
|
21
|
+
<form id="contact-form">
|
|
22
|
+
<div style="margin-bottom: 15px;">
|
|
23
|
+
<label for="name" style="display: block; margin-bottom: 5px;">Nombre:</label>
|
|
24
|
+
<input type="text" id="name" name="name" required style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px;">
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div style="margin-bottom: 15px;">
|
|
28
|
+
<label for="email" style="display: block; margin-bottom: 5px;">Email:</label>
|
|
29
|
+
<input type="email" id="email" name="email" required style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px;">
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div style="margin-bottom: 15px;">
|
|
33
|
+
<label for="message" style="display: block; margin-bottom: 5px;">Mensaje:</label>
|
|
34
|
+
<textarea id="message" name="message" required rows="5" style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px;"></textarea>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<button type="submit" class="button">Enviar Mensaje</button>
|
|
38
|
+
</form>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div class="footer">
|
|
42
|
+
<p>© 2026 Tienda JERK Framework. Todos los derechos reservados.</p>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<script src="/static/js/main.js"></script>
|
|
46
|
+
</body>
|
|
47
|
+
</html>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>{{title}}</title>
|
|
7
|
+
<link rel="stylesheet" href="/static/css/style.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="header">
|
|
11
|
+
<h1>{{title}}</h1>
|
|
12
|
+
<nav>
|
|
13
|
+
<a href="/" class="button">Inicio</a>
|
|
14
|
+
<a href="/contact" class="button">Contacto</a>
|
|
15
|
+
</nav>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div class="content">
|
|
19
|
+
<h2>Nuestros Productos</h2>
|
|
20
|
+
|
|
21
|
+
<div id="product-list">
|
|
22
|
+
{{foreach:products}}
|
|
23
|
+
<div class="product-card">
|
|
24
|
+
<h3>{{item.name}}</h3>
|
|
25
|
+
<p>{{item.description}}</p>
|
|
26
|
+
<p><strong>Precio:</strong> ${{item.price}}</p>
|
|
27
|
+
<p><strong>Categoría:</strong> {{item.category}}</p>
|
|
28
|
+
</div>
|
|
29
|
+
{{endforeach}}
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="footer">
|
|
34
|
+
<p>© 2026 Tienda JERK Framework. Todos los derechos reservados.</p>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<script src="/static/js/main.js"></script>
|
|
38
|
+
</body>
|
|
39
|
+
</html>
|