Cleanup: Remoción masiva de restos de WordPress y consolidación de archivos GKACHELE™

This commit is contained in:
komkida91
2026-01-27 18:00:16 +01:00
parent d9aad67066
commit 7083aa3893
874 changed files with 137670 additions and 137443 deletions

View File

@@ -0,0 +1,7 @@
---
description: Gestión de funcionalidades del Plan Base
---
1. Los temas permitidos son únicamente los marcados como `plan: base` en `config.json`.
2. El Customizer permite cambios básicos de colores y texto.
3. El rubro por defecto es `restaurante`.

View File

@@ -0,0 +1,7 @@
---
description: Gestión de funcionalidades del Plan Premium
---
1. Acceso total a todas las plantillas (`base`, `pro`, `premium`).
2. Funcionalidades exclusivas como Custom Domains y soporte prioritario.
3. Capacidad de usar el Customizer Premium completo sin restricciones.

View File

@@ -0,0 +1,7 @@
---
description: Gestión de funcionalidades del Plan Pro
---
1. Incluye acceso a plantillas marcadas como `plan: pro` y `plan: base`.
2. Habilita bloques avanzados de video e imágenes.
3. El soporte para personalización de tipografía está activado.

View File

@@ -20,7 +20,7 @@ def init_db():
password TEXT NOT NULL, password TEXT NOT NULL,
role TEXT DEFAULT 'subscriber', role TEXT DEFAULT 'subscriber',
plan TEXT DEFAULT 'base', plan TEXT DEFAULT 'base',
rubro TEXT DEFAULT 'gimnasio', rubro TEXT DEFAULT 'restaurante',
status TEXT DEFAULT 'active', status TEXT DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)''') )''')

View File

@@ -11,10 +11,21 @@ customizer_bp = Blueprint('customizer', __name__)
@customizer_bp.route('/api/themes') @customizer_bp.route('/api/themes')
def list_themes(): def list_themes():
"""Listar todos los templates disponibles""" """Listar todos los templates disponibles filtrados por plan"""
from utils.theme_engine import get_themes_by_rubro from utils.theme_engine import get_themes_by_rubro
rubro = request.args.get('rubro', None) rubro = request.args.get('rubro', None)
themes = get_themes_by_rubro(rubro) if rubro else scan_available_themes() user_id = session.get('user_id')
user_plan = 'base'
if user_id:
conn = sqlite3.connect(MAIN_DB)
c = conn.cursor()
c.execute('SELECT plan FROM users WHERE id = ?', (user_id,))
res = c.fetchone()
conn.close()
if res: user_plan = res[0]
themes = get_themes_by_rubro(rubro, user_plan) if rubro else scan_available_themes()
return jsonify({'success': True, 'themes': themes, 'total': len(themes)}) return jsonify({'success': True, 'themes': themes, 'total': len(themes)})
@customizer_bp.route('/customizer/<int:site_id>') @customizer_bp.route('/customizer/<int:site_id>')
@@ -42,7 +53,16 @@ def customizer_view(site_id):
theme_template = f.read() theme_template = f.read()
theme_config = get_theme_config(theme) theme_config = get_theme_config(theme)
available_themes = scan_available_themes()
# Obtener plan del usuario para filtrar templates
c = conn.cursor()
c.execute('SELECT plan, rubro FROM users WHERE id = ?', (site[0],))
user_data = c.fetchone()
user_plan = user_data[0] if user_data else 'base'
user_rubro = user_data[1] if user_data else 'restaurante'
from utils.theme_engine import get_themes_by_rubro
available_themes = get_themes_by_rubro(user_rubro, user_plan)
return render_template('customizer.html', return render_template('customizer.html',
site_id=site_id, site_id=site_id,
@@ -51,7 +71,8 @@ def customizer_view(site_id):
content=content, content=content,
theme_template=theme_template, theme_template=theme_template,
theme_config=theme_config, theme_config=theme_config,
available_themes=available_themes) available_themes=available_themes,
user_plan=user_plan)
@customizer_bp.route('/api/customizer/save', methods=['POST']) @customizer_bp.route('/api/customizer/save', methods=['POST'])
def save_customizer(): def save_customizer():

View File

@@ -1,4 +1,5 @@
from flask import Blueprint, render_template, send_from_directory, sqlite3 from flask import Blueprint, render_template, send_from_directory
import sqlite3
import json import json
import os import os
from config import MAIN_DB, UPLOADS_DIR from config import MAIN_DB, UPLOADS_DIR
@@ -14,7 +15,6 @@ def landing():
@public_bp.route('/site/<slug>') @public_bp.route('/site/<slug>')
def public_site(slug): def public_site(slug):
"""Sitio público del cliente""" """Sitio público del cliente"""
import sqlite3
conn = sqlite3.connect(MAIN_DB) conn = sqlite3.connect(MAIN_DB)
c = conn.cursor() c = conn.cursor()
c.execute('SELECT id, theme, content_json, status, user_id FROM sites WHERE slug = ?', (slug,)) c.execute('SELECT id, theme, content_json, status, user_id FROM sites WHERE slug = ?', (slug,))

View File

@@ -1,20 +1,24 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="es"> <html lang="es">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard - Administración del Sitio</title> <title>Dashboard - Administración del Sitio</title>
<style> <style>
* { box-sizing: border-box; } * {
body { box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
margin: 0; margin: 0;
background: #f0f0f1; background: #f0f0f1;
display: flex; display: flex;
height: 100vh; height: 100vh;
color: #3c434a; color: #3c434a;
} }
/* Sidebar similar a WP */ /* Sidebar similar a WP */
.sidebar { .sidebar {
width: 160px; width: 160px;
@@ -24,12 +28,14 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.sidebar-header { .sidebar-header {
padding: 10px 0 10px 20px; padding: 10px 0 10px 20px;
font-weight: 600; font-weight: 600;
font-size: 14px; font-size: 14px;
color: #fff; color: #fff;
} }
.menu-item { .menu-item {
display: block; display: block;
padding: 10px 20px; padding: 10px 20px;
@@ -39,13 +45,20 @@
border-left: 4px solid transparent; border-left: 4px solid transparent;
cursor: pointer; cursor: pointer;
} }
.menu-item:hover, .menu-item.active {
.menu-item:hover,
.menu-item.active {
background: #2c3338; background: #2c3338;
color: #72aee6; color: #72aee6;
border-left-color: #72aee6; border-left-color: #72aee6;
} }
.menu-item i { margin-right: 8px; width: 16px; text-align: center; }
.menu-item i {
margin-right: 8px;
width: 16px;
text-align: center;
}
/* Main Content */ /* Main Content */
.main-content { .main-content {
flex-grow: 1; flex-grow: 1;
@@ -53,7 +66,7 @@
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
} }
/* Top Bar */ /* Top Bar */
.top-bar { .top-bar {
height: 32px; height: 32px;
@@ -65,27 +78,40 @@
justify-content: space-between; justify-content: space-between;
font-size: 13px; font-size: 13px;
} }
.top-bar a { color: #fff; text-decoration: none; margin-left: 20px; }
.top-bar a:hover { color: #72aee6; } .top-bar a {
color: #fff;
text-decoration: none;
margin-left: 20px;
}
.top-bar a:hover {
color: #72aee6;
}
/* Content Area */ /* Content Area */
.wp-content { .gk-content {
padding: 20px; padding: 20px;
overflow-y: auto; overflow-y: auto;
flex-grow: 1; flex-grow: 1;
} }
h1 { font-size: 23px; font-weight: 400; margin: 0 0 20px 0; padding: 0; } h1 {
font-size: 23px;
font-weight: 400;
margin: 0 0 20px 0;
padding: 0;
}
.card { .card {
background: #fff; background: #fff;
border: 1px solid #c3c4c7; border: 1px solid #c3c4c7;
padding: 20px; padding: 20px;
margin-bottom: 20px; margin-bottom: 20px;
max-width: 800px; max-width: 800px;
box-shadow: 0 1px 1px rgba(0,0,0,.04); box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
} }
.welcome-panel { .welcome-panel {
background: #fff; background: #fff;
padding: 30px; padding: 30px;
@@ -95,7 +121,7 @@
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
} }
.btn-primary { .btn-primary {
background: #2271b1; background: #2271b1;
border-color: #2271b1; border-color: #2271b1;
@@ -107,11 +133,28 @@
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;
} }
.btn-primary:hover { background: #135e96; }
.btn-primary:hover {
table { width: 100%; border-collapse: collapse; margin-top: 10px; } background: #135e96;
th, td { text-align: left; padding: 10px; border-bottom: 1px solid #f0f0f1; } }
th { font-weight: 600; }
table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
th,
td {
text-align: left;
padding: 10px;
border-bottom: 1px solid #f0f0f1;
}
th {
font-weight: 600;
}
.status-badge { .status-badge {
background: #f0f0f1; background: #f0f0f1;
color: #646970; color: #646970;
@@ -120,18 +163,27 @@
font-size: 11px; font-size: 11px;
font-weight: 600; font-weight: 600;
} }
.status-badge.published { background: #edfaef; color: #008a20; }
.status-badge.pending { background: #fff8e5; color: #996800; } .status-badge.published {
background: #edfaef;
color: #008a20;
}
.status-badge.pending {
background: #fff8e5;
color: #996800;
}
</style> </style>
<!-- FontAwesome simplificado para iconos --> <!-- FontAwesome simplificado para iconos -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head> </head>
<body> <body>
<!-- Sidebar --> <!-- Sidebar -->
<div class="sidebar"> <div class="sidebar">
<div class="sidebar-header"> <div class="sidebar-header">
<i class="fab fa-wordpress-simple"></i> GKACHELE <i class="fas fa-cube"></i> GKACHELE
</div> </div>
<a href="#" class="menu-item active"><i class="fas fa-tachometer-alt"></i> Escritorio</a> <a href="#" class="menu-item active"><i class="fas fa-tachometer-alt"></i> Escritorio</a>
<a href="#" class="menu-item"><i class="fas fa-thumbtack"></i> Entradas</a> <a href="#" class="menu-item"><i class="fas fa-thumbtack"></i> Entradas</a>
@@ -156,45 +208,48 @@
</div> </div>
</div> </div>
<!-- WP Content --> <!-- GK Content -->
<div class="wp-content"> <div class="gk-content">
<h1>Escritorio</h1> <h1>Escritorio</h1>
<div class="welcome-panel"> <div class="welcome-panel">
<div> <div>
<h2 style="margin-top: 0;">¡Te damos la bienvenida a tu panel!</h2> <h2 style="margin-top: 0;">¡Te damos la bienvenida a tu panel!</h2>
<p style="color: #646970;">Aquí puedes gestionar todos tus sitios y contenidos de forma profesional.</p> <p style="color: #646970;">Aquí puedes gestionar todos tus sitios y contenidos de forma profesional.
</p>
</div> </div>
<button class="btn-primary" onclick="window.location.href='/dashboard/create'">+ Crear Nuevo Sitio</button> <button class="btn-primary" onclick="window.location.href='/dashboard/create'">+ Crear Nuevo
Sitio</button>
</div> </div>
<div class="card"> <div class="card">
<h3><i class="fas fa-globe"></i> Tus Sitios Web</h3> <h3><i class="fas fa-globe"></i> Tus Sitios Web</h3>
{% if not sites %} {% if not sites %}
<p>No tienes sitios creados. ¡Empieza ahora!</p> <p>No tienes sitios creados. ¡Empieza ahora!</p>
{% else %} {% else %}
<table> <table>
<thead> <thead>
<tr> <tr>
<th>Nombre (Slug)</th> <th>Nombre (Slug)</th>
<th>Tema</th> <th>Tema</th>
<th>Estado</th> <th>Estado</th>
<th>Acciones</th> <th>Acciones</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for site in sites %} {% for site in sites %}
<tr> <tr>
<td><strong>{{ site.slug }}</strong></td> <td><strong>{{ site.slug }}</strong></td>
<td>{{ site.theme }}</td> <td>{{ site.theme }}</td>
<td><span class="status-badge {{ site.status }}">{{ site.status|upper }}</span></td> <td><span class="status-badge {{ site.status }}">{{ site.status|upper }}</span></td>
<td> <td>
<a href="/customizer/{{ site.id }}" class="btn-primary" style="padding: 4px 8px; font-size: 11px;">Personalizar</a> <a href="/customizer/{{ site.id }}" class="btn-primary"
</td> style="padding: 4px 8px; font-size: 11px;">Personalizar</a>
</tr> </td>
{% endfor %} </tr>
</tbody> {% endfor %}
</table> </tbody>
</table>
{% endif %} {% endif %}
</div> </div>
@@ -216,4 +271,5 @@
</div> </div>
</body> </body>
</html>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
{ {
"name": "Restaurante Asiático", "name": "Restaurante Asiático",
"rubro": "restaurante", "rubro": "restaurante",
"plan": "premium",
"description": "Tema moderno y elegante para restaurantes asiáticos", "description": "Tema moderno y elegante para restaurantes asiáticos",
"sections": [ "sections": [
"hero", "hero",
@@ -29,4 +30,4 @@
"especialidad_culinaria": true, "especialidad_culinaria": true,
"galeria": true "galeria": true
} }
} }

View File

@@ -1,6 +1,7 @@
{ {
"name": "Restaurante Elegante", "name": "Restaurante Elegante",
"rubro": "restaurante", "rubro": "restaurante",
"plan": "pro",
"description": "Tema sofisticado y elegante para restaurantes de alta cocina", "description": "Tema sofisticado y elegante para restaurantes de alta cocina",
"sections": [ "sections": [
"hero", "hero",
@@ -29,4 +30,4 @@
"especialidad_culinaria": true, "especialidad_culinaria": true,
"galeria": true "galeria": true
} }
} }

View File

@@ -1,6 +1,7 @@
{ {
"name": "Restaurante Moderno", "name": "Restaurante Moderno",
"rubro": "restaurante", "rubro": "restaurante",
"plan": "base",
"description": "Tema elegante para restaurantes", "description": "Tema elegante para restaurantes",
"sections": [ "sections": [
"hero", "hero",
@@ -27,4 +28,4 @@
"capacidad": true, "capacidad": true,
"especialidad_culinaria": true "especialidad_culinaria": true
} }
} }

View File

@@ -30,6 +30,7 @@ def scan_available_themes():
'name': config.get('name', theme_dir), 'name': config.get('name', theme_dir),
'description': config.get('description', ''), 'description': config.get('description', ''),
'rubro': config.get('rubro', 'general'), 'rubro': config.get('rubro', 'general'),
'plan': config.get('plan', 'base'),
'sections': config.get('sections', []), 'sections': config.get('sections', []),
'colors': config.get('colors', {}), 'colors': config.get('colors', {}),
'typography': config.get('typography', {}), 'typography': config.get('typography', {}),
@@ -55,10 +56,19 @@ def get_theme_config(theme_id):
print(f"⚠️ Error cargando config de {theme_id}: {e}") print(f"⚠️ Error cargando config de {theme_id}: {e}")
return None return None
def get_themes_by_rubro(rubro): def get_themes_by_rubro(rubro, user_plan='base'):
"""Obtener templates filtrados por rubro""" """Obtener templates filtrados por rubro y plan del usuario"""
all_themes = scan_available_themes() all_themes = scan_available_themes()
return {k: v for k, v in all_themes.items() if v.get('rubro') == rubro or v.get('rubro') == 'general'} plan_priority = {'base': 1, 'pro': 2, 'premium': 3}
user_level = plan_priority.get(user_plan, 1)
filtered_themes = {}
for k, v in all_themes.items():
theme_level = plan_priority.get(v.get('plan', 'base'), 1)
# Solo mostrar temas del rubro (o general) que estén dentro del plan del usuario
if (v.get('rubro') == rubro or v.get('rubro') == 'general') and theme_level <= user_level:
filtered_themes[k] = v
return filtered_themes
def get_site_menus(site_id, user_id): def get_site_menus(site_id, user_id):
"""Obtener menús del sitio organizados por ubicación""" """Obtener menús del sitio organizados por ubicación"""
@@ -175,5 +185,20 @@ def render_gkachele_template(theme, content, site_id=None, user_id=None):
return template.render(**template_data) return template.render(**template_data)
full_template = header + theme_template + sidebar + footer full_template = header + theme_template + sidebar + footer
template = Template(full_template)
# Inject WhatsApp Button if configured
whatsapp = content.get('redes_sociales', {}).get('whatsapp')
if whatsapp:
wa_html = f'''
<a href="https://wa.me/{whatsapp}" class="whatsapp-float" target="_blank" style="position:fixed; width:60px; height:60px; bottom:40px; right:40px; background-color:#25d366; color:#FFF; border-radius:50px; text-align:center; font-size:30px; box-shadow: 2px 2px 3px #999; z-index:10000; display:flex; align-items:center; justify-content:center; text-decoration:none;">
<i class="fab fa-whatsapp"></i>
</a>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
'''
if is_full_page:
theme_template = theme_template.replace('</body>', wa_html + '</body>')
else:
footer = footer.replace('</body>', wa_html + '</body>')
template = Template(theme_template if is_full_page else header + theme_template + sidebar + footer)
return template.render(**template_data) return template.render(**template_data)

35
deploy_modular.sh Normal file
View File

@@ -0,0 +1,35 @@
#!/bin/bash
# GKACHELE™ SaaS - Modular Deployment Script
# Despliega la nueva estructura (routes, utils, config) a la Raspberry Pi
# Configuración
RASPBERRY_USER="pi"
RASPBERRY_HOST="192.168.1.134"
RASPBERRY_PORT="2222"
RASPBERRY_PASS="Gdk1983gdk45@"
RASPBERRY_PATH="/home/pi/gkachele-saas"
LOCAL_PATH="/mnt/c/word/demo"
echo "🚀 Iniciando despliegue modular de GKACHELE™..."
# 1. Asegurar directorios en la Raspberry
sshpass -p "$RASPBERRY_PASS" ssh -p $RASPBERRY_PORT -o StrictHostKeyChecking=no $RASPBERRY_USER@$RASPBERRY_HOST "mkdir -p $RASPBERRY_PATH/routes $RASPBERRY_PATH/utils $RASPBERRY_PATH/templates $RASPBERRY_PATH/themes"
# 2. Copiar archivos core
echo "📦 Copiando archivos base..."
sshpass -p "$RASPBERRY_PASS" scp -P $RASPBERRY_PORT -o StrictHostKeyChecking=no $LOCAL_PATH/app.py $LOCAL_PATH/config.py $LOCAL_PATH/database.py $RASPBERRY_USER@$RASPBERRY_HOST:$RASPBERRY_PATH/
# 3. Copiar rutas y utilidades (la nueva modularización)
echo "📦 Copiando módulos (routes & utils)..."
sshpass -p "$RASPBERRY_PASS" scp -P $RASPBERRY_PORT -o StrictHostKeyChecking=no -r $LOCAL_PATH/routes/* $RASPBERRY_USER@$RASPBERRY_HOST:$RASPBERRY_PATH/routes/
sshpass -p "$RASPBERRY_PASS" scp -P $RASPBERRY_PORT -o StrictHostKeyChecking=no -r $LOCAL_PATH/utils/* $RASPBERRY_USER@$RASPBERRY_HOST:$RASPBERRY_PATH/utils/
# 4. Copiar templates (por si hubo cambios)
echo "📦 Copiando templates..."
sshpass -p "$RASPBERRY_PASS" scp -P $RASPBERRY_PORT -o StrictHostKeyChecking=no -r $LOCAL_PATH/templates/* $RASPBERRY_USER@$RASPBERRY_HOST:$RASPBERRY_PATH/templates/
# 5. Reiniciar el servicio
echo "🔄 Reiniciando servicio GKACHELE™..."
sshpass -p "$RASPBERRY_PASS" ssh -p $RASPBERRY_PORT -o StrictHostKeyChecking=no $RASPBERRY_USER@$RASPBERRY_HOST "sudo systemctl restart gkachele-saas || (sudo pkill -f 'python3 app.py' && cd $RASPBERRY_PATH && nohup python3 app.py > /tmp/app_modular.log 2>&1 &)"
echo "✅ Despliegue completado con éxito."

Some files were not shown because too many files have changed in this diff Show More