Загрузка данных


import os
import uuid
import sqlite3
import requests
from flask import Flask, render_template_string, request, redirect, url_for, flash, session

app = Flask(__name__)
# Секретный ключ для защиты сессий Flask
app.secret_key = 'super_secret_session_key_999'

# ---------------------------------------------------------------
# СЕКРЕТНЫЙ КЛЮЧ / ПАРОЛЬ ДЛЯ ВХОДА В АДМИН-ПАНЕЛЬ
# Вы можете изменить его на любой свой пароль:
ADMIN_SECRET_KEY = "admin12345"
# ---------------------------------------------------------------

# Твой токен Яндекс.Диска
YANDEX_TOKEN = "0cb7e4fba386444fbe8007f2dceb223b"

# --- ИНИЦИАЛИЗАЦИЯ БАЗЫ ДАННЫХ ---
def init_db():
    conn = sqlite3.connect('photographer_studio.db')
    cursor = conn.cursor()
    
    # Тексты и фото для Главной и Обо мне
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS content (
            key TEXT PRIMARY KEY,
            value TEXT
        )
    ''')
    
    # Отзывы
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS reviews (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            author TEXT,
            text TEXT,
            photo_url TEXT
        )
    ''')
    
    # Подарочные сертификаты
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS certificates (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            code TEXT UNIQUE,
            client_name TEXT,
            amount_or_desc TEXT,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
    ''')
    
    # Персональные галереи для клиентов
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS client_galleries (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            unique_id TEXT UNIQUE,
            client_name TEXT,
            template TEXT,
            photos_json TEXT
        )
    ''')
    
    # Фотографии, загруженные из Яндекс.Диска
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS yandex_photos (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT,
            public_url TEXT
        )
    ''')

    # Дефолтные данные, если база пустая
    defaults = [
        ('main_title', 'Атмосферная & Эстетичная Фотография'),
        ('main_text', 'Я создаю кадры, которые сохраняют настоящие эмоции, свет и тепло ваших лучших моментов.'),
        ('main_photo', 'https://images.unsplash.com/photo-1492691527719-9d1e07e534b4?auto=format&fit=crop&w=1200&q=80'),
        ('about_title', 'Обо мне'),
        ('about_text', 'Привет! Я профессиональный фотограф с 7-летним стажем. Специализируюсь на портретах, свадьбах и индивидуальных съёмках. Мой подход — естественность и лаконичность.'),
        ('about_photo', 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?auto=format&fit=crop&w=800&q=80')
    ]
    for key, val in defaults:
        cursor.execute('INSERT OR IGNORE INTO content (key, value) VALUES (?, ?)', (key, val))
        
    conn.commit()
    conn.close()

init_db()

# --- ОБЩИЙ HTML-СТИЛЬ В ПРИЯТНЫХ ПАСТЕЛЬНЫХ ТОНАХ ---
BASE_CSS = """
<style>
    @import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,600;1,400&family=Plus+Jakarta+Sans:wght@300;400;500;600&display=swap');

    :root {
        --bg-color: #FBF9F5;
        --card-bg: #FFFFFF;
        --text-color: #332E2B;
        --accent-color: #8C7A6B;
        --accent-hover: #6E5E51;
        --light-accent: #EFECE6;
        --border-color: #E2DDD5;
    }

    * { box-sizing: border-box; margin: 0; padding: 0; }
    body {
        font-family: 'Plus Jakarta Sans', sans-serif;
        background-color: var(--bg-color);
        color: var(--text-color);
        line-height: 1.6;
    }
    
    h1, h2, h3, .serif {
        font-family: 'Cormorant Garamond', serif;
        font-weight: 600;
        color: var(--text-color);
    }

    /* Навигация */
    header {
        background: rgba(251, 249, 245, 0.95);
        backdrop-filter: blur(8px);
        position: sticky;
        top: 0;
        z-index: 100;
        border-bottom: 1px solid var(--border-color);
        padding: 20px 40px;
        display: flex;
        justify-content: space-between;
        align-items: center;
    }
    .logo { font-size: 24px; font-weight: 600; letter-spacing: 1px; color: var(--accent-color); text-decoration: none; }
    nav a { margin-left: 25px; text-decoration: none; color: var(--text-color); font-size: 15px; font-weight: 500; transition: 0.3s; }
    nav a:hover { color: var(--accent-color); }
    .admin-link { border: 1px solid var(--accent-color); padding: 6px 14px; border-radius: 20px; color: var(--accent-color); }
    .admin-link:hover { background: var(--accent-color); color: #fff; }

    /* Контейнеры */
    .container { max-width: 1100px; margin: 40px auto; padding: 0 20px; }
    .hero { text-align: center; padding: 60px 20px; }
    .hero h1 { font-size: 48px; margin-bottom: 20px; }
    .hero p { font-size: 18px; color: #666; max-width: 700px; margin: 0 auto 30px; }
    .hero-img { width: 100%; height: 500px; object-fit: cover; border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.05); }

    /* Сетка фото и отзывов */
    .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 25px; margin-top: 30px; }
    .card { background: var(--card-bg); border-radius: 10px; padding: 25px; border: 1px solid var(--border-color); }
    .card img { width: 100%; height: 250px; object-fit: cover; border-radius: 6px; margin-bottom: 15px; }

    /* Формы и кнопки */
    .btn {
        background: var(--accent-color); color: white; padding: 12px 24px; border: none;
        border-radius: 6px; cursor: pointer; font-size: 15px; transition: 0.3s; text-decoration: none; display: inline-block;
    }
    .btn:hover { background: var(--accent-hover); }
    .form-group { margin-bottom: 20px; }
    label { display: block; margin-bottom: 8px; font-weight: 500; font-size: 14px; }
    input[type="text"], input[type="password"], textarea, select {
        width: 100%; padding: 12px; border: 1px solid var(--border-color); border-radius: 6px;
        background: #FAF8F5; font-family: inherit; font-size: 14px;
    }
    textarea { height: 120px; resize: vertical; }

    /* Шаблоны галерей */
    .gallery-masonry { columns: 3 250px; column-gap: 15px; }
    .gallery-masonry img { width: 100%; margin-bottom: 15px; border-radius: 8px; display: block; }
    .gallery-slideshow { display: flex; flex-direction: column; gap: 40px; align-items: center; }
    .gallery-slideshow img { max-width: 900px; width: 100%; border-radius: 8px; }

    /* Панель админа */
    .admin-grid { display: grid; grid-template-columns: 240px 1fr; gap: 30px; margin-top: 30px; }
    .sidebar { background: var(--card-bg); padding: 20px; border-radius: 8px; border: 1px solid var(--border-color); }
    .sidebar a { display: block; padding: 10px; color: var(--text-color); text-decoration: none; border-radius: 4px; margin-bottom: 5px; }
    .sidebar a:hover { background: var(--light-accent); color: var(--accent-color); }

    footer { text-align: center; padding: 40px; border-top: 1px solid var(--border-color); margin-top: 80px; font-size: 14px; color: #888; }
</style>
"""

NAVBAR_HTML = """
<header>
    <a href="/" class="logo serif">PORTFOLIO</a>
    <nav>
        <a href="/">Главная</a>
        <a href="/about">Обо мне</a>
        <a href="/reviews">Отзывы</a>
        <a href="/certificates">Сертификаты</a>
        <a href="/admin" class="admin-link">Админ-панель</a>
    </nav>
</header>
"""

def get_db():
    conn = sqlite3.connect('photographer_studio.db')
    conn.row_factory = sqlite3.Row
    return conn

# --- ПУБЛИЧНЫЕ СТРАНИЦЫ САЙТА ---

@app.route('/')
def index():
    conn = get_db()
    content = dict(conn.execute('SELECT * FROM content').fetchall())
    photos = conn.execute('SELECT * FROM yandex_photos LIMIT 6').fetchall()
    conn.close()
    
    html = f"""
    <!DOCTYPE html><html><head><title>Главная | Фотограф</title>{BASE_CSS}</head><body>
    {NAVBAR_HTML}
    <div class="container">
        <section class="hero">
            <h1>{content.get('main_title', '')}</h1>
            <p>{content.get('main_text', '')}</p>
            <img src="{content.get('main_photo', '')}" class="hero-img" alt="Main Photo">
        </section>
        
        <h2 style="text-align: center; margin-top: 50px;" class="serif">Избранные Работы</h2>
        <div class="grid">
            {"".join([f'<div class="card"><img src="{p["public_url"]}" alt="{p["name"]}"></div>' for p in photos]) if photos else '<p style="text-align:center; grid-column:1/-1;">Фотографии пока не синхронизированы с Яндекс.Диска.</p>'}
        </div>
    </div>
    <footer>© 2026 Все права защищены. Создано с любовью.</footer>
    </body></html>
    """
    return render_template_string(html)

@app.route('/about')
def about():
    conn = get_db()
    content = dict(conn.execute('SELECT * FROM content').fetchall())
    conn.close()
    
    html = f"""
    <!DOCTYPE html><html><head><title>Обо мне | Фотограф</title>{BASE_CSS}</head><body>
    {NAVBAR_HTML}
    <div class="container">
        <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: center; margin-top: 50px;">
            <img src="{content.get('about_photo', '')}" style="width:100%; border-radius:12px;" alt="About">
            <div>
                <h1 style="font-size: 42px; margin-bottom: 20px;">{content.get('about_title', '')}</h1>
                <p style="font-size: 16px; color: #555; white-space: pre-line;">{content.get('about_text', '')}</p>
            </div>
        </div>
    </div>
    <footer>© 2026 Все права защищены.</footer>
    </body></html>
    """
    return render_template_string(html)

@app.route('/reviews')
def reviews():
    conn = get_db()
    revs = conn.execute('SELECT * FROM reviews').fetchall()
    conn.close()
    
    rev_cards = ""
    for r in revs:
        photo_tag = f'<img src="{r["photo_url"]}">' if r["photo_url"] else ""
        rev_cards += f"""
        <div class="card">
            {photo_tag}
            <p style="font-style: italic; margin-bottom: 10px;">"{r['text']}"</p>
            <h4 class="serif" style="text-align: right; color: var(--accent-color);">— {r['author']}</h4>
        </div>
        """
        
    html = f"""
    <!DOCTYPE html><html><head><title>Отзывы | Фотограф</title>{BASE_CSS}</head><body>
    {NAVBAR_HTML}
    <div class="container">
        <h1 style="text-align: center; margin: 40px 0;" class="serif">Отзывы Клиентов</h1>
        <div class="grid">
            {rev_cards if rev_cards else '<p style="text-align:center; grid-column:1/-1;">Отзывов пока нет.</p>'}
        </div>
    </div>
    <footer>© 2026 Все права защищены.</footer>
    </body></html>
    """
    return render_template_string(html)

@app.route('/certificates', methods=['GET', 'POST'])
def certificates():
    cert_info = None
    if request.method == 'POST':
        code = request.form.get('code', '').strip().upper()
        conn = get_db()
        cert_info = conn.execute('SELECT * FROM certificates WHERE code = ?', (code,)).fetchone()
        conn.close()
        
    html = f"""
    <!DOCTYPE html><html><head><title>Сертификаты | Фотограф</title>{BASE_CSS}</head><body>
    {NAVBAR_HTML}
    <div class="container" style="max-width: 600px;">
        <h1 style="text-align: center; margin-bottom: 20px;" class="serif">Подарочные Сертификаты</h1>
        <p style="text-align: center; margin-bottom: 30px; color: #666;">Проверьте уникальный код вашего сертификата здесь:</p>
        
        <div class="card">
            <form method="POST">
                <div class="form-group">
                    <label>Введите номер сертификата:</label>
                    <input type="text" name="code" placeholder="Например: CERT-A1B2C3" required style="text-transform: uppercase;">
                </div>
                <button type="submit" class="btn" style="width: 100%;">Проверить Сертификат</button>
            </form>
            
            {f'''
            <div style="margin-top: 25px; padding: 20px; background: var(--light-accent); border-radius: 6px; text-align: center;">
                {"<h3 class='serif' style='color: green;'>Сертификат Действителен!</h3><p><b>Кому:</b> " + cert_info['client_name'] + "</p><p><b>Услуга/Сумма:</b> " + cert_info['amount_or_desc'] + "</p>" if cert_info else "<h3 class='serif' style='color: red;'>Сертификат не найден</h3><p>Проверьте правильность введенного кода.</p>"}
            </div>
            ''' if request.method == 'POST' else ''}
        </div>
    </div>
    <footer>© 2026 Все права защищены.</footer>
    </body></html>
    """
    return render_template_string(html)

# --- ПЕРСОНАЛЬНАЯ КЛИЕНТСКАЯ ГАЛЕРЕЯ ---
@app.route('/gallery/<unique_id>')
def client_gallery(unique_id):
    conn = get_db()
    gallery = conn.execute('SELECT * FROM client_galleries WHERE unique_id = ?', (unique_id,)).fetchone()
    conn.close()
    
    if not gallery:
        return "<h1>Галерея не найдена или ссылка устарела.</h1>", 404
        
    photos = gallery['photos_json'].split(',') if gallery['photos_json'] else []
    template = gallery['template']
    
    if template == 'masonry':
        gallery_html = '<div class="gallery-masonry">' + "".join([f'<img src="{url}">' for url in photos]) + '</div>'
    elif template == 'slideshow':
        gallery_html = '<div class="gallery-slideshow">' + "".join([f'<img src="{url}">' for url in photos]) + '</div>'
    else:
        gallery_html = '<div class="grid">' + "".join([f'<div class="card" style="padding:0; overflow:hidden;"><img src="{url}" style="height:100%; margin:0;"></div>' for url in photos]) + '</div>'

    html = f"""
    <!DOCTYPE html><html><head><title>Персональная Галерея | {gallery['client_name']}</title>{BASE_CSS}</head><body>
    <div class="container">
        <div style="text-align: center; margin: 40px 0;">
            <p style="text-transform: uppercase; letter-spacing: 2px; color: var(--accent-color); font-size: 12px;">Персональная Галерея</p>
            <h1 class="serif" style="font-size: 42px;">{gallery['client_name']}</h1>
        </div>
        {gallery_html}
    </div>
    <footer>© 2026 Ваш Персональный Фотограф.</footer>
    </body></html>
    """
    return render_template_string(html)

# --- ПАНЕЛЬ АДМИНИСТРАТОРА И АВТОРИЗАЦИЯ (СЕКРЕТНЫЙ КЛЮЧ) ---

@app.route('/admin/logout')
def admin_logout():
    session.pop('is_admin', None)
    return redirect('/admin')

@app.route('/admin', methods=['GET', 'POST'])
def admin_panel():
    login_error = False

    # Обработка ввода секретного ключа (пароля)
    if request.method == 'POST' and request.form.get('action') == 'login':
        secret_key_input = request.form.get('secret_key', '').strip()
        if secret_key_input == ADMIN_SECRET_KEY:
            session['is_admin'] = True
            return redirect('/admin')
        else:
            login_error = True

    # Если администратор НЕ авторизован — показываем форму ввода секретного ключа
    if not session.get('is_admin'):
        login_html = f"""
        <!DOCTYPE html><html><head><title>Вход в Админ-панель</title>{BASE_CSS}</head><body>
        {NAVBAR_HTML}
        <div class="container" style="max-width: 450px; margin-top: 80px;">
            <div class="card" style="text-align: center;">
                <h2 class="serif" style="margin-bottom: 10px;">Защищенный Доступ</h2>
                <p style="color: #666; font-size: 14px; margin-bottom: 20px;">Введите секретный ключ администратора</p>
                
                {"<p style='color: red; font-size: 14px; margin-bottom: 15px;'>Неверный секретный ключ!</p>" if login_error else ""}
                
                <form method="POST">
                    <input type="hidden" name="action" value="login">
                    <div class="form-group">
                        <input type="password" name="secret_key" placeholder="Введите Ваш секретный ключ..." required style="text-align: center;">
                    </div>
                    <button type="submit" class="btn" style="width: 100%;">Войти в Панель</button>
                </form>
            </div>
        </div>
        <footer>© 2026 Безопасная админ-панель</footer>
        </body></html>
        """
        return render_template_string(login_html)

    # --- ЕСЛИ КЛЮЧ ВВЕДЕН ВЕРНО — ОТКРЫВАЕТСЯ АДМИНКА ---
    conn = get_db()
    tab = request.args.get('tab', 'main')
    
    if request.method == 'POST' and tab in ['main', 'about']:
        for key in request.form:
            if key != 'action':
                conn.execute('INSERT OR REPLACE INTO content (key, value) VALUES (?, ?)', (key, request.form[key]))
        conn.commit()

    elif request.method == 'POST' and tab == 'reviews':
        author = request.form.get('author')
        text = request.form.get('text')
        photo_url = request.form.get('photo_url')
        conn.execute('INSERT INTO reviews (author, text, photo_url) VALUES (?, ?, ?)', (author, text, photo_url))
        conn.commit()

    elif request.method == 'POST' and tab == 'certificates':
        client_name = request.form.get('client_name')
        desc = request.form.get('desc')
        code = f"CERT-{str(uuid.uuid4())[:6].upper()}"
        conn.execute('INSERT INTO certificates (code, client_name, amount_or_desc) VALUES (?, ?, ?)', (code, client_name, desc))
        conn.commit()

    elif request.method == 'POST' and tab == 'create_gallery':
        client_name = request.form.get('client_name')
        template = request.form.get('template')
        selected_photos = request.form.getlist('photos')
        unique_id = str(uuid.uuid4())[:12]
        
        photos_str = ",".join(selected_photos)
        conn.execute('INSERT INTO client_galleries (unique_id, client_name, template, photos_json) VALUES (?, ?, ?, ?)',
                     (unique_id, client_name, template, photos_str))
        conn.commit()

    content = dict(conn.execute('SELECT * FROM content').fetchall())
    reviews_list = conn.execute('SELECT * FROM reviews').fetchall()
    certs_list = conn.execute('SELECT * FROM certificates').fetchall()
    yandex_photos = conn.execute('SELECT * FROM yandex_photos').fetchall()
    galleries_list = conn.execute('SELECT * FROM client_galleries').fetchall()
    conn.close()

    tab_content = ""
    
    if tab == 'main':
        tab_content = f"""
        <h2 class="serif">Редактирование Главной Страницы</h2><br>
        <form method="POST">
            <div class="form-group"><label>Заголовок:</label><input type="text" name="main_title" value="{content.get('main_title', '')}"></div>
            <div class="form-group"><label>Текст на главной:</label><textarea name="main_text">{content.get('main_text', '')}</textarea></div>
            <div class="form-group"><label>URL главного фото:</label><input type="text" name="main_photo" value="{content.get('main_photo', '')}"></div>
            <button class="btn" type="submit">Сохранить</button>
        </form>
        """
    elif tab == 'about':
        tab_content = f"""
        <h2 class="serif">Редактирование 'Обо мне'</h2><br>
        <form method="POST">
            <div class="form-group"><label>Заголовок:</label><input type="text" name="about_title" value="{content.get('about_title', '')}"></div>
            <div class="form-group"><label>Текст Обо мне:</label><textarea name="about_text">{content.get('about_text', '')}</textarea></div>
            <div class="form-group"><label>URL Вашего Фото:</label><input type="text" name="about_photo" value="{content.get('about_photo', '')}"></div>
            <button class="btn" type="submit">Сохранить</button>
        </form>
        """
    elif tab == 'reviews':
        tab_content = f"""
        <h2 class="serif">Управление Отзывами</h2><br>
        <form method="POST">
            <div class="form-group"><label>Имя клиента:</label><input type="text" name="author" required></div>
            <div class="form-group"><label>Текст отзыва: