205 lines
7.8 KiB
Python
205 lines
7.8 KiB
Python
import os
|
|
import json
|
|
import sqlite3
|
|
from flask import current_app
|
|
from config import THEMES_DIR, MAIN_DB
|
|
|
|
def scan_available_themes():
|
|
"""Escanear todos los templates disponibles y cargar sus configuraciones"""
|
|
themes = {}
|
|
if not os.path.exists(THEMES_DIR):
|
|
return themes
|
|
|
|
for theme_dir in os.listdir(THEMES_DIR):
|
|
theme_path = os.path.join(THEMES_DIR, theme_dir)
|
|
if not os.path.isdir(theme_path) or theme_dir.startswith('_'):
|
|
continue
|
|
|
|
config_path = os.path.join(theme_path, 'config.json')
|
|
template_path = os.path.join(theme_path, 'template.html')
|
|
|
|
if not os.path.exists(config_path) or not os.path.exists(template_path):
|
|
continue
|
|
|
|
try:
|
|
with open(config_path, 'r', encoding='utf-8-sig') as f:
|
|
config = json.load(f)
|
|
|
|
themes[theme_dir] = {
|
|
'id': theme_dir,
|
|
'name': config.get('name', theme_dir),
|
|
'description': config.get('description', ''),
|
|
'rubro': config.get('rubro', 'general'),
|
|
'plan': config.get('plan', 'base'),
|
|
'sections': config.get('sections', []),
|
|
'colors': config.get('colors', {}),
|
|
'typography': config.get('typography', {}),
|
|
'features': config.get('features', {}),
|
|
'preview': f'/themes/{theme_dir}/preview.jpg' if os.path.exists(os.path.join(theme_path, 'preview.jpg')) else None
|
|
}
|
|
except Exception as e:
|
|
print(f"WARNING: Error cargando template {theme_dir}: {e}")
|
|
continue
|
|
|
|
return themes
|
|
|
|
def get_theme_config(theme_id):
|
|
"""Obtener configuración de un template específico"""
|
|
config_path = os.path.join(THEMES_DIR, theme_id, 'config.json')
|
|
if not os.path.exists(config_path):
|
|
return None
|
|
|
|
try:
|
|
with open(config_path, 'r', encoding='utf-8-sig') as f:
|
|
return json.load(f)
|
|
except Exception as e:
|
|
print(f"WARNING: Error cargando config de {theme_id}: {e}")
|
|
return None
|
|
|
|
def get_themes_by_rubro(rubro, user_plan='base'):
|
|
"""Obtener templates filtrados por rubro y plan del usuario"""
|
|
all_themes = scan_available_themes()
|
|
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):
|
|
"""Obtener menús del sitio organizados por ubicación"""
|
|
conn = sqlite3.connect(MAIN_DB)
|
|
c = conn.cursor()
|
|
c.execute('''SELECT location, title, url, order_index, parent_id
|
|
FROM menus
|
|
WHERE site_id = ? AND user_id = ?
|
|
ORDER BY location, order_index''', (site_id, user_id))
|
|
rows = c.fetchall()
|
|
conn.close()
|
|
|
|
menus = {'header': [], 'footer': [], 'sidebar': []}
|
|
for row in rows:
|
|
location, title, url, order_index, parent_id = row
|
|
menu_item = {
|
|
'title': title,
|
|
'url': url,
|
|
'order': order_index,
|
|
'parent_id': parent_id
|
|
}
|
|
if location in menus:
|
|
menus[location].append(menu_item)
|
|
|
|
return menus
|
|
|
|
def get_site_widgets(site_id, user_id, area='sidebar'):
|
|
"""Obtener widgets del sitio por área"""
|
|
conn = sqlite3.connect(MAIN_DB)
|
|
c = conn.cursor()
|
|
c.execute('''SELECT type, title, content, order_index
|
|
FROM widgets
|
|
WHERE site_id = ? AND user_id = ? AND area = ?
|
|
ORDER BY order_index''', (site_id, user_id, area))
|
|
rows = c.fetchall()
|
|
conn.close()
|
|
|
|
widgets = []
|
|
for row in rows:
|
|
widget_type, title, content, order_index = row
|
|
widgets.append({
|
|
'type': widget_type,
|
|
'title': title,
|
|
'content': content,
|
|
'order': order_index
|
|
})
|
|
|
|
return widgets
|
|
|
|
def render_gkachele_template(theme, content, site_id=None, user_id=None):
|
|
"""Renderizar template usando estructura GKACHELE (header.php, footer.php, sidebar.php)"""
|
|
menus = {'header': [], 'footer': [], 'sidebar': []}
|
|
widgets = []
|
|
if site_id and user_id:
|
|
try:
|
|
menus = get_site_menus(site_id, user_id)
|
|
widgets = get_site_widgets(site_id, user_id)
|
|
except Exception as e:
|
|
print(f"WARNING: Error obteniendo menus/widgets: {e}")
|
|
|
|
theme_template = ''
|
|
theme_path = os.path.join(THEMES_DIR, theme, 'template.html')
|
|
if os.path.exists(theme_path):
|
|
with open(theme_path, 'r', encoding='utf-8') as f:
|
|
theme_template = f.read()
|
|
else:
|
|
theme_template = '<div class="container"><h1>{{ hero_title or "Bienvenido" }}</h1></div>'
|
|
|
|
header = ''
|
|
footer = ''
|
|
sidebar = ''
|
|
|
|
header_path = os.path.join(THEMES_DIR, '_gkachele', 'header.php')
|
|
footer_path = os.path.join(THEMES_DIR, '_gkachele', 'footer.php')
|
|
sidebar_path = os.path.join(THEMES_DIR, '_gkachele', 'sidebar.php')
|
|
|
|
if os.path.exists(header_path):
|
|
with open(header_path, 'r', encoding='utf-8') as f:
|
|
header = f.read()
|
|
else:
|
|
header = '<html><body>' # Fallback simplificado
|
|
|
|
if os.path.exists(footer_path):
|
|
with open(footer_path, 'r', encoding='utf-8') as f:
|
|
footer = f.read()
|
|
else:
|
|
footer = '</body></html>'
|
|
|
|
if os.path.exists(sidebar_path):
|
|
with open(sidebar_path, 'r', encoding='utf-8') as f:
|
|
sidebar = f.read()
|
|
|
|
template_data = {
|
|
'site_name': content.get('site_name', 'GKACHELE Site'),
|
|
'hero_title': content.get('hero_title', 'Bienvenido'),
|
|
'colors': content.get('colors', {}),
|
|
'typography': content.get('typography', {}),
|
|
'horarios': content.get('horarios', {}),
|
|
'redes_sociales': content.get('redes_sociales', {}),
|
|
'blocks': content.get('blocks', []),
|
|
'menus': menus,
|
|
'widgets': widgets,
|
|
**content
|
|
}
|
|
|
|
from jinja2 import Template
|
|
|
|
is_full_page = False
|
|
if theme == 'restaurante-moderno' or '<!DOCTYPE html>' in theme_template:
|
|
is_full_page = True
|
|
|
|
if is_full_page:
|
|
template = Template(theme_template)
|
|
return template.render(**template_data)
|
|
|
|
full_template = header + theme_template + sidebar + footer
|
|
|
|
# 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)
|