pewpewpew/app.py

697 lines
28 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from flask import Flask, render_template, request, redirect, url_for, flash, session, jsonify
import sqlite3
import os
import re
from werkzeug.security import generate_password_hash, check_password_hash
from functools import wraps
from datetime import datetime
app = Flask(__name__)
app.secret_key = 'your_secret_key_here_change_in_production'
# --------------------- ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ---------------------
def get_db_connection():
conn = sqlite3.connect('horse_farm.db')
conn.row_factory = sqlite3.Row
return conn
def is_valid_email(email):
if not email:
return True
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.(ru|com)$'
return re.match(pattern, email.lower()) is not None
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if 'user_id' not in session:
flash('Пожалуйста, войдите в систему', 'warning')
return redirect(url_for('login'))
return f(*args, **kwargs)
return decorated_function
def admin_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if 'user_id' not in session:
flash('Пожалуйста, войдите в систему', 'warning')
return redirect(url_for('login'))
if session.get('role') != 'admin':
flash('Доступ запрещен. Требуются права администратора.', 'danger')
return redirect(url_for('index'))
return f(*args, **kwargs)
return decorated_function
# ------------------------- API -------------------------
@app.route('/api/services')
def api_services():
conn = get_db_connection()
services = conn.execute('SELECT id, name, price, duration FROM services').fetchall()
abonements = conn.execute('SELECT id, name, price, description FROM abonements').fetchall()
certificates = conn.execute('SELECT id, name, price, description FROM certificates').fetchall()
conn.close()
return jsonify({
'services': [dict(row) for row in services],
'abonements': [dict(row) for row in abonements],
'certificates': [dict(row) for row in certificates]
})
@app.route('/api/unread_count')
@login_required
def api_unread_count():
conn = get_db_connection()
count = conn.execute('''
SELECT COUNT(*) as count FROM messages m
JOIN orders o ON m.order_id = o.id
WHERE o.user_id = ? AND m.is_read = 0 AND m.sender_type != 'user'
''', (session['user_id'],)).fetchone()
conn.close()
return jsonify({'count': count['count'] if count else 0})
@app.route('/api/unread_by_order')
@login_required
def api_unread_by_order():
conn = get_db_connection()
unread = conn.execute('''
SELECT o.id, COUNT(*) as count
FROM messages m
JOIN orders o ON m.order_id = o.id
WHERE o.user_id = ? AND m.is_read = 0 AND m.sender_type != 'user'
GROUP BY o.id
''', (session['user_id'],)).fetchall()
conn.close()
return jsonify([dict(row) for row in unread])
@app.route('/api/mark_read', methods=['POST'])
@login_required
def mark_read():
data = request.get_json()
order_id = data.get('order_id')
conn = get_db_connection()
conn.execute('''
UPDATE messages SET is_read = 1
WHERE order_id = ? AND user_id = ? AND sender_type != 'user'
''', (order_id, session['user_id']))
conn.commit()
conn.close()
return jsonify({'success': True})
@app.route('/api/set_timezone', methods=['POST'])
def set_timezone():
data = request.get_json()
if data and 'timezone_offset' in data:
session['timezone_offset'] = data['timezone_offset']
return jsonify({'success': True})
return jsonify({'success': False}), 400
@app.route('/api/admin_unread_counts')
@admin_required
def api_admin_unread_counts():
conn = get_db_connection()
counts = conn.execute('''
SELECT order_id, COUNT(*) as count
FROM messages
WHERE is_read = 0 AND sender_type = 'user'
GROUP BY order_id
''').fetchall()
conn.close()
return jsonify({str(row['order_id']): row['count'] for row in counts})
@app.route('/api/mark_order_read', methods=['POST'])
@admin_required
def mark_order_read():
data = request.get_json()
order_id = data.get('order_id')
conn = get_db_connection()
conn.execute('UPDATE messages SET is_read = 1 WHERE order_id = ? AND sender_type = "user"', (order_id,))
conn.commit()
conn.close()
return jsonify({'success': True})
@app.route('/api/toggle_payment', methods=['POST'])
@admin_required
def toggle_payment():
data = request.get_json()
order_id = data.get('order_id')
conn = get_db_connection()
current = conn.execute('SELECT payment_status FROM orders WHERE id = ?', (order_id,)).fetchone()
new_status = 'paid' if current['payment_status'] != 'paid' else 'not_paid'
conn.execute('UPDATE orders SET payment_status = ? WHERE id = ?', (new_status, order_id))
conn.commit()
conn.close()
return jsonify({'status': new_status})
# ---------------------- СТРАНИЦЫ ----------------------
@app.route('/')
def index():
return render_template('index.html')
@app.route('/about')
def about():
return render_template('about.html')
@app.route('/services')
def services():
conn = get_db_connection()
services = conn.execute('SELECT * FROM services').fetchall()
conn.close()
return render_template('services.html', services=services)
@app.route('/abonements')
def abonements():
conn = get_db_connection()
abonements = conn.execute('SELECT * FROM abonements').fetchall()
conn.close()
return render_template('abonements.html', abonements=abonements)
@app.route('/certificates')
def certificates():
conn = get_db_connection()
certificates = conn.execute('SELECT * FROM certificates').fetchall()
conn.close()
return render_template('certificates.html', certificates=certificates)
@app.route('/gallery')
def gallery():
images_dir = os.path.join(app.static_folder, 'images/gallery')
images = []
if os.path.exists(images_dir):
images = [f for f in os.listdir(images_dir)
if f.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.webp'))]
return render_template('gallery.html', images=images)
@app.route('/discounts')
def discounts():
return render_template('discounts.html')
# ---------------------- РЕГИСТРАЦИЯ / ВХОД ----------------------
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
email = request.form.get('email', '')
if email and not is_valid_email(email):
flash('Введите корректный email адрес (должен заканчиваться на .ru или .com)', 'danger')
return redirect(url_for('register'))
conn = get_db_connection()
user = conn.execute('SELECT * FROM users WHERE username = ?', (username,)).fetchone()
if user:
flash('Пользователь с таким именем уже существует', 'danger')
conn.close()
return redirect(url_for('register'))
hashed_password = generate_password_hash(password)
conn.execute('INSERT INTO users (username, password, email, role) VALUES (?, ?, ?, ?)',
(username, hashed_password, email if email else None, 'user'))
conn.commit()
conn.close()
flash('Регистрация успешна! Теперь вы можете войти', 'success')
return redirect(url_for('login'))
return render_template('register.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
conn = get_db_connection()
user = conn.execute('SELECT * FROM users WHERE username = ?', (username,)).fetchone()
conn.close()
if user and check_password_hash(user['password'], password):
session.permanent = True
session['user_id'] = user['id']
session['username'] = user['username']
session['role'] = user['role']
flash(f'Добро пожаловать, {username}!', 'success')
return redirect(url_for('index'))
else:
flash('Неверное имя пользователя или пароль', 'danger')
return render_template('login.html')
@app.route('/logout')
def logout():
session.clear()
flash('Вы вышли из системы', 'info')
return redirect(url_for('index'))
# ---------------------- ЗАКАЗЫ ----------------------
@app.route('/order', methods=['GET', 'POST'])
@login_required
def order():
if request.method == 'POST':
service_type = request.form['service_type']
service_id = request.form.get('service_id')
service_name = request.form['service_name']
date = request.form.get('date')
time = request.form.get('time')
persons = request.form.get('persons', 1)
price = request.form.get('price', 0)
comment = request.form.get('comment', '')
try:
persons = int(float(persons)) if service_type != 'certificate' else 1
if persons < 1: persons = 1
if persons > 20: persons = 20
except:
persons = 1
conn = get_db_connection()
final_price = int(price)
discount_applied = False
discount_amount = 0
original_price = int(price)
if service_type != 'certificate':
duration_minutes = 0
duration_str = ''
if service_type == 'service':
service = conn.execute('SELECT duration FROM services WHERE id = ?', (service_id,)).fetchone()
if service:
duration_str = service['duration']
if 'минут' in duration_str:
duration_minutes = int(duration_str.split()[0])
elif 'час' in duration_str:
hours = int(duration_str.split()[0])
duration_minutes = hours * 60
try:
hour = int(time.split(':')[0])
minute = int(time.split(':')[1])
start_minutes = hour * 60 + minute
end_minutes = start_minutes + duration_minutes
if start_minutes < 540:
flash('Заказы принимаются с 9:00', 'danger')
conn.close()
return redirect(url_for('order'))
if end_minutes > 1200:
max_hour = (1200 - duration_minutes) // 60
max_minute = (1200 - duration_minutes) % 60
flash(f'Услуга длится {duration_str}. Необходимо закончить до 20:00. Максимальное время начала: {max_hour}:{max_minute:02d}', 'danger')
conn.close()
return redirect(url_for('order'))
except:
flash('Неверный формат времени', 'danger')
conn.close()
return redirect(url_for('order'))
today = datetime.now().strftime('%Y-%m-%d')
if date < today:
flash('Нельзя выбрать прошедшую дату', 'danger')
conn.close()
return redirect(url_for('order'))
if persons >= 4 and service_type == 'service':
discount_amount = int(int(price) * 0.15)
final_price = int(int(price) * 0.85)
discount_applied = True
conn.execute('''
INSERT INTO orders
(user_id, service_type, service_name, service_id, date, time, persons, price, comment, discount_applied, discount_amount, original_price, payment_status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'not_paid')
''', (session['user_id'], service_type, service_name, service_id, date, time, persons, final_price, comment, discount_applied, discount_amount, original_price))
conn.commit()
conn.close()
if discount_applied:
flash(f'Заказ успешно создан! Применена семейная скидка 15%! Итоговая цена: {final_price} руб.', 'success')
else:
flash('Заказ успешно создан!', 'success')
return redirect(url_for('my_orders'))
return render_template('order_form.html')
@app.route('/my-orders')
@login_required
def my_orders():
sort = request.args.get('sort', 'newest')
status = request.args.get('status', 'all')
conn = get_db_connection()
query = 'SELECT * FROM orders WHERE user_id = ?'
params = [session['user_id']]
if status != 'all':
query += ' AND status = ?'
params.append(status)
if sort == 'newest':
query += ' ORDER BY created_at DESC'
elif sort == 'oldest':
query += ' ORDER BY created_at ASC'
elif sort == 'price_high':
query += ' ORDER BY price DESC'
elif sort == 'price_low':
query += ' ORDER BY price ASC'
orders = conn.execute(query, params).fetchall()
orders_list = []
for order in orders:
order_dict = dict(order)
unread = conn.execute('''
SELECT COUNT(*) as count FROM messages
WHERE order_id = ? AND is_read = 0 AND sender_type != 'user'
''', (order['id'],)).fetchone()
order_dict['unread_count'] = unread['count'] if unread else 0
orders_list.append(order_dict)
conn.close()
return render_template('my_orders.html', orders=orders_list, sort=sort, status=status)
# ---------------------- ОТЗЫВЫ ----------------------
@app.route('/reviews', methods=['GET', 'POST'])
def reviews():
if request.method == 'POST':
if 'user_id' not in session:
flash('Пожалуйста, войдите в систему, чтобы оставить отзыв', 'warning')
return redirect(url_for('login'))
order_id = request.form.get('order_id')
rating = int(request.form['rating'])
comment = request.form['comment']
conn = get_db_connection()
existing_review = conn.execute('SELECT * FROM reviews WHERE user_id = ? AND order_id = ?',
(session['user_id'], order_id)).fetchone()
if existing_review:
flash('Вы уже оставляли отзыв на этот заказ', 'danger')
conn.close()
return redirect(url_for('reviews'))
order = conn.execute('SELECT * FROM orders WHERE id = ? AND user_id = ? AND status = "completed"',
(order_id, session['user_id'])).fetchone()
if not order:
flash('Вы можете оставить отзыв только на выполненные заказы', 'danger')
conn.close()
return redirect(url_for('reviews'))
conn.execute('''
INSERT INTO reviews (user_id, order_id, username, rating, comment, status)
VALUES (?, ?, ?, ?, ?, 'pending')
''', (session['user_id'], order_id, session['username'], rating, comment))
conn.commit()
conn.close()
flash('Ваш отзыв отправлен на модерацию!', 'success')
return redirect(url_for('reviews'))
sort = request.args.get('sort', 'newest')
rating_filter = request.args.get('rating', 'all')
conn = get_db_connection()
completed_orders = []
if 'user_id' in session:
completed_orders = conn.execute('''
SELECT o.* FROM orders o
LEFT JOIN reviews r ON o.id = r.order_id AND r.user_id = ?
WHERE o.user_id = ? AND o.status = 'completed' AND r.id IS NULL
ORDER BY o.created_at DESC
''', (session['user_id'], session['user_id'])).fetchall()
query = 'SELECT * FROM reviews WHERE status = "approved"'
params = []
if rating_filter != 'all':
query += ' AND rating = ?'
params.append(rating_filter)
if sort == 'newest':
query += ' ORDER BY created_at DESC'
elif sort == 'oldest':
query += ' ORDER BY created_at ASC'
elif sort == 'rating_high':
query += ' ORDER BY rating DESC'
elif sort == 'rating_low':
query += ' ORDER BY rating ASC'
approved_reviews = conn.execute(query, params).fetchall()
conn.close()
return render_template('reviews.html', reviews=approved_reviews,
completed_orders=completed_orders,
sort=sort, rating_filter=rating_filter)
# ---------------------- ЧАТ ----------------------
@app.route('/chat/<int:order_id>')
@login_required
def chat(order_id):
conn = get_db_connection()
order = conn.execute('SELECT * FROM orders WHERE id = ?', (order_id,)).fetchone()
if not order:
flash('Заказ не найден', 'danger')
return redirect(url_for('my_orders'))
if session['user_id'] != order['user_id'] and session.get('role') != 'admin':
flash('Доступ запрещен', 'danger')
return redirect(url_for('index'))
if session.get('role') == 'admin':
conn.execute('UPDATE messages SET is_read = 1 WHERE order_id = ? AND sender_type = "user"', (order_id,))
messages = conn.execute('''
SELECT m.*,
CASE
WHEN m.sender_type = 'user' THEN u.username
WHEN m.sender_type = 'admin' THEN a.username
ELSE 'Система'
END as sender_name
FROM messages m
LEFT JOIN users u ON m.user_id = u.id
LEFT JOIN users a ON m.admin_id = a.id
WHERE m.order_id = ?
ORDER BY m.created_at ASC
''', (order_id,)).fetchall()
conn.close()
return render_template('chat.html', order=order, messages=messages)
@app.route('/send_message', methods=['POST'])
@login_required
def send_message():
order_id = request.form['order_id']
message = request.form['message']
if not message or not message.strip():
return jsonify({'error': 'Сообщение не может быть пустым'}), 400
conn = get_db_connection()
order = conn.execute('SELECT * FROM orders WHERE id = ?', (order_id,)).fetchone()
if not order:
conn.close()
return jsonify({'error': 'Заказ не найден'}), 404
if session['user_id'] != order['user_id'] and session.get('role') != 'admin':
conn.close()
return jsonify({'error': 'Доступ запрещен'}), 403
if session.get('role') == 'admin':
sender_type = 'admin'
admin_id = session['user_id']
user_id = order['user_id']
else:
sender_type = 'user'
user_id = session['user_id']
admin_id = None
conn.execute('''
INSERT INTO messages (order_id, user_id, admin_id, message, sender_type)
VALUES (?, ?, ?, ?, ?)
''', (order_id, user_id, admin_id, message.strip(), sender_type))
conn.commit()
conn.close()
return jsonify({'success': True, 'message': 'Сообщение отправлено'})
# ---------------------- АДМИНКА ----------------------
@app.route('/admin')
@admin_required
def admin_panel():
return render_template('admin/index.html')
@app.route('/admin/orders')
@admin_required
def admin_orders():
sort = request.args.get('sort', 'newest')
status = request.args.get('status', 'all')
conn = get_db_connection()
query = '''
SELECT o.*, u.username,
(SELECT COUNT(*) FROM messages m WHERE m.order_id = o.id AND m.is_read = 0 AND m.sender_type != 'admin') as unread_count
FROM orders o
LEFT JOIN users u ON o.user_id = u.id
WHERE 1=1
'''
params = []
if status != 'all':
query += ' AND o.status = ?'
params.append(status)
if sort == 'newest':
query += ' ORDER BY o.created_at DESC'
elif sort == 'oldest':
query += ' ORDER BY o.created_at ASC'
elif sort == 'price_high':
query += ' ORDER BY o.price DESC'
elif sort == 'price_low':
query += ' ORDER BY o.price ASC'
orders = conn.execute(query, params).fetchall()
conn.close()
return render_template('admin/orders.html', orders=orders, sort=sort, status=status)
@app.route('/admin/orders/<int:order_id>/update', methods=['POST'])
@admin_required
def update_order(order_id):
status = request.form['status']
sort = request.args.get('sort', 'newest')
status_filter = request.args.get('status', 'all')
conn = get_db_connection()
order = conn.execute('SELECT user_id FROM orders WHERE id = ?', (order_id,)).fetchone()
conn.execute('UPDATE orders SET status = ? WHERE id = ?', (status, order_id))
if order:
conn.execute('''
INSERT INTO messages (order_id, user_id, admin_id, message, sender_type)
VALUES (?, ?, ?, ?, 'system')
''', (order_id, order['user_id'], session['user_id'], f'Статус заказа изменен на: {status}'))
conn.commit()
conn.close()
flash('Статус заказа обновлен', 'success')
return redirect(url_for('admin_orders', sort=sort, status=status_filter))
@app.route('/admin/orders/<int:order_id>/delete', methods=['POST'])
@admin_required
def delete_order(order_id):
sort = request.args.get('sort', 'newest')
status_filter = request.args.get('status', 'all')
conn = get_db_connection()
conn.execute('DELETE FROM messages WHERE order_id = ?', (order_id,))
conn.execute('DELETE FROM orders WHERE id = ?', (order_id,))
conn.commit()
conn.close()
flash('Заказ удален', 'success')
return redirect(url_for('admin_orders', sort=sort, status=status_filter))
@app.route('/admin/reviews')
@admin_required
def admin_reviews():
sort = request.args.get('sort', 'newest')
status = request.args.get('status', 'all')
rating = request.args.get('rating', 'all')
conn = get_db_connection()
query = 'SELECT * FROM reviews WHERE 1=1'
params = []
if status != 'all':
query += ' AND status = ?'
params.append(status)
if rating != 'all':
query += ' AND rating = ?'
params.append(rating)
if sort == 'newest':
query += ' ORDER BY created_at DESC'
elif sort == 'oldest':
query += ' ORDER BY created_at ASC'
elif sort == 'rating_high':
query += ' ORDER BY rating DESC'
elif sort == 'rating_low':
query += ' ORDER BY rating ASC'
reviews = conn.execute(query, params).fetchall()
conn.close()
return render_template('admin/reviews.html', reviews=reviews, sort=sort, status=status, rating=rating)
@app.route('/admin/reviews/<int:review_id>/moderate', methods=['POST'])
@admin_required
def moderate_review(review_id):
status = request.form['status']
sort = request.args.get('sort', 'newest')
status_filter = request.args.get('status', 'all')
rating_filter = request.args.get('rating', 'all')
conn = get_db_connection()
conn.execute('UPDATE reviews SET status = ? WHERE id = ?', (status, review_id))
conn.commit()
conn.close()
flash('Отзыв обработан', 'success')
return redirect(url_for('admin_reviews', sort=sort, status=status_filter, rating=rating_filter))
@app.route('/admin/reviews/<int:review_id>/delete', methods=['POST'])
@admin_required
def delete_review(review_id):
sort = request.args.get('sort', 'newest')
status_filter = request.args.get('status', 'all')
rating_filter = request.args.get('rating', 'all')
conn = get_db_connection()
conn.execute('DELETE FROM reviews WHERE id = ?', (review_id,))
conn.commit()
conn.close()
flash('Отзыв удален', 'success')
return redirect(url_for('admin_reviews', sort=sort, status=status_filter, rating=rating_filter))
@app.route('/admin/users')
@admin_required
def admin_users():
sort = request.args.get('sort', 'newest')
role = request.args.get('role', 'all')
conn = get_db_connection()
query = 'SELECT * FROM users WHERE 1=1'
params = []
if role != 'all':
query += ' AND role = ?'
params.append(role)
if sort == 'newest':
query += ' ORDER BY created_at DESC'
elif sort == 'oldest':
query += ' ORDER BY created_at ASC'
elif sort == 'name_asc':
query += ' ORDER BY username ASC'
elif sort == 'name_desc':
query += ' ORDER BY username DESC'
users = conn.execute(query, params).fetchall()
conn.close()
return render_template('admin/users.html', users=users, sort=sort, role=role)
@app.route('/admin/users/<int:user_id>/delete', methods=['POST'])
@admin_required
def delete_user(user_id):
sort = request.args.get('sort', 'newest')
role_filter = request.args.get('role', 'all')
if user_id == session['user_id']:
flash('Нельзя удалить самого себя', 'danger')
return redirect(url_for('admin_users', sort=sort, role=role_filter))
conn = get_db_connection()
conn.execute('DELETE FROM messages WHERE user_id = ?', (user_id,))
conn.execute('DELETE FROM orders WHERE user_id = ?', (user_id,))
conn.execute('DELETE FROM reviews WHERE user_id = ?', (user_id,))
conn.execute('DELETE FROM users WHERE id = ?', (user_id,))
conn.commit()
conn.close()
flash('Пользователь удален', 'success')
return redirect(url_for('admin_users', sort=sort, role=role_filter))
@app.route('/admin/users/<int:user_id>/make-admin', methods=['POST'])
@admin_required
def make_admin(user_id):
sort = request.args.get('sort', 'newest')
role_filter = request.args.get('role', 'all')
conn = get_db_connection()
conn.execute('UPDATE users SET role = "admin" WHERE id = ?', (user_id,))
conn.commit()
conn.close()
flash('Пользователь назначен администратором', 'success')
return redirect(url_for('admin_users', sort=sort, role=role_filter))
@app.route('/admin/messages')
@admin_required
def admin_messages():
conn = get_db_connection()
messages = conn.execute('''
SELECT m.*, o.id as order_id, u.username as user_name
FROM messages m
JOIN orders o ON m.order_id = o.id
JOIN users u ON o.user_id = u.id
WHERE m.sender_type = 'user' AND m.is_read = 0
ORDER BY m.created_at DESC
''').fetchall()
conn.close()
return render_template('admin/messages.html', messages=messages)
# ---------------------- ЗАПУСК ----------------------
if __name__ == '__main__':
conn = sqlite3.connect('horse_farm.db')
cursor = conn.cursor()
cursor.execute("PRAGMA table_info(orders)")
existing = [col[1] for col in cursor.fetchall()]
for col in ['discount_applied', 'discount_amount', 'original_price', 'payment_status']:
if col not in existing:
cursor.execute(f"ALTER TABLE orders ADD COLUMN {col} DEFAULT 'not_paid' if col == 'payment_status' else 0")
print(f"Добавлена колонка {col}")
cursor.execute("PRAGMA table_info(reviews)")
if 'order_id' not in [c[1] for c in cursor.fetchall()]:
cursor.execute("ALTER TABLE reviews ADD COLUMN order_id INTEGER")
cursor.execute("PRAGMA table_info(messages)")
if 'is_read' not in [c[1] for c in cursor.fetchall()]:
cursor.execute("ALTER TABLE messages ADD COLUMN is_read BOOLEAN DEFAULT 0")
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='messages'")
if not cursor.fetchone():
cursor.execute('''
CREATE TABLE messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
order_id INTEGER,
user_id INTEGER,
admin_id INTEGER,
message TEXT NOT NULL,
sender_type TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
is_read BOOLEAN DEFAULT 0
)
''')
cursor.execute("SELECT * FROM users WHERE username = 'admin'")
if not cursor.fetchone():
hashed = generate_password_hash('admin123')
cursor.execute("INSERT INTO users (username, password, email, role) VALUES (?, ?, ?, ?)",
('admin', hashed, 'admin@koniydvor.ru', 'admin'))
print("Создан администратор: admin / admin123")
conn.commit()
conn.close()
app.run(debug=True)