from flask import Flask, request, render_template_string, render_template, jsonify, Response, send_from_directory, render_template import sqlite3 import os import random import requests import time import re import json import logging import csv import io from urllib.parse import quote, urlparse, parse_qsl, urlencode, parse_qs, unquote, urlencode import string from datetime import datetime import pytz import socket from unidecode import unidecode import uuid import shutil import psutil import hashlib import hmac from base64 import b64encode from collections import OrderedDict from hashlib import sha256 from hmac import HMAC from base import replace_null_with_empty_string from webhook_handler import handle_webhook # Замените на ваш реальный ключ Системы api_key_sys = os.getenv('api_key_sys') ALLOWED_ORIGIN = "https://diamonik7777-up-fail.hf.space" # Глобальные переменные для хранения настроек api_key_auth = '' api_key_apps_vk = '' vk_api_key = '' vk_st_alone = '' key_callback_vk = '' senler_token = '' wa_ak = '' wa_api_key = '' curators = '' call_api_key = '' # Замените на ваш реальный access_token СЕНДЛЕРА import logging logging.basicConfig(level=logging.DEBUG) # Глобальная переменная для управления верификацией current_curator_index = 0 verifikation_start = "1" # Глобальная переменная для управления верификацией curator_on_off = "0" # Глобальная переменная для управления назначением куратора # curators = ["Anna", "Ekaterina", "Ivan", "Maria", "Sergey", "Olga", "Alex", "Natalia", "Dmitry", "Elena"] # Глобальная переменная для wa_url = os.getenv('wa_url') ws_url_mes = "/sendMessage/" ws_url_ver = "/checkWhatsapp/" app = Flask(__name__, template_folder="./") app.config['DEBUG'] = True UPLOAD_FOLDER = 'static' UPLOAD_FOLDER_VK = 'static' HTML_FOLDER = 'html' HTML_FOLDER_VK = 'html' # Создание директорий, если они не существуют if not os.path.exists(UPLOAD_FOLDER): os.makedirs(UPLOAD_FOLDER) if not os.path.exists(UPLOAD_FOLDER_VK): os.makedirs(UPLOAD_FOLDER_VK) if not os.path.exists(HTML_FOLDER): os.makedirs(HTML_FOLDER) if not os.path.exists(HTML_FOLDER_VK): os.makedirs(HTML_FOLDER_VK) DATABASES = ['data_gc.db', 'site_data.db', 'ws_data.db', 'vk_data.db', 'tg_data.db', 'gk_data.db'] SETTINGS_DB = 'settings.db' def init_db(db_name): conn = sqlite3.connect(db_name) cursor = conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS contacts ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, phone TEXT, email TEXT, vk_id TEXT, chat_id TEXT, ws_st TEXT, ws_stop TEXT, web_st INTEGER, fin_prog INTEGER, b_city TEXT, b_fin TEXT, b_ban TEXT, b_ign TEXT, b_baners TEXT, b_butt TEXT, b_mess TEXT, orders TEXT, curator TEXT, bonus TEXT, shop_status TEXT, answers TEXT, quiz TEXT, kassa TEXT, gc_url TEXT, key_pr TEXT, n_con TEXT, canal TEXT, data_on TEXT, data_t TEXT, utm_source TEXT, utm_medium TEXT, utm_campaign TEXT, utm_term TEXT, utm_content TEXT, gcpc TEXT ) ''') conn.commit() conn.close() def init_settings_db(): conn = sqlite3.connect(SETTINGS_DB) cursor = conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS settings ( id INTEGER PRIMARY KEY AUTOINCREMENT, api_key_auth TEXT, api_key_apps_vk TEXT, vk_api_key TEXT, vk_st_alone TEXT, key_callback_vk TEXT, senler_token TEXT, wa_ak TEXT, wa_api_key TEXT, curators TEXT, call_api_key TEXT ) ''') conn.commit() conn.close() for db in DATABASES: init_db(db) init_settings_db() DATABASE_NEW = 'data_gc.db' def load_settings(): global api_key_auth, api_key_apps_vk, vk_api_key, vk_st_alone, key_callback_vk global senler_token, wa_ak, wa_api_key, curators, call_api_key default_settings = { 'api_key_auth': '', 'api_key_apps_vk': '', 'vk_api_key': '', 'vk_st_alone': '', 'key_callback_vk': '', 'senler_token': '', 'wa_ak': '', 'wa_api_key': '', 'curators': '', 'call_api_key': '' } # Загрузка данных из базы with sqlite3.connect(SETTINGS_DB) as conn: cursor = conn.cursor() cursor.execute('SELECT * FROM settings') settings = cursor.fetchone() if settings is None: settings = default_settings else: settings = {key: settings[i + 1] or '' for i, key in enumerate(default_settings)} # Заполняем глобальные переменные api_key_auth = settings['api_key_auth'] api_key_apps_vk = settings['api_key_apps_vk'] vk_api_key = settings['vk_api_key'] vk_st_alone = settings['vk_st_alone'] key_callback_vk = settings['key_callback_vk'] senler_token = settings['senler_token'] wa_ak = settings['wa_ak'] wa_api_key = settings['wa_api_key'] curators = settings['curators'] call_api_key = settings['call_api_key'] # Выводим значения в консоль print(f"wa_api_key: {wa_api_key}") print(f"wa_ak: {wa_ak}") print(f"vk_api_key: {vk_api_key}") print(f"vk_st_alone: {vk_st_alone}") print(f"key_callback_vk: {key_callback_vk}") print(f"senler_token: {senler_token}") print(f"api_key_auth: {api_key_auth}") print(f"api_key_apps_vk: {api_key_apps_vk}") print(f"curators: {curators}") print(f"call_api_key: {call_api_key}") # Возвращаем настройки, чтобы использовать в API-роуте return settings # Запуск функции для инициализации глобальных переменных при старте сервера load_settings() def save_settings(settings_dict): global api_key_auth, api_key_apps_vk, vk_api_key, vk_st_alone, key_callback_vk global senler_token, wa_ak, wa_api_key, curators, call_api_key # Удаляем api_key_sys из словаря перед сохранением if 'api_key_sys' in settings_dict: del settings_dict['api_key_sys'] conn = sqlite3.connect(SETTINGS_DB) cursor = conn.cursor() # Проверка существования записи cursor.execute('SELECT id FROM settings LIMIT 1') settings_exist = cursor.fetchone() is not None if settings_exist: # Обновляем запись cursor.execute(''' UPDATE settings SET api_key_auth = ?, api_key_apps_vk = ?, vk_api_key = ?, vk_st_alone = ?, key_callback_vk = ?, senler_token = ?, wa_ak = ?, wa_api_key = ?, curators = ?, call_api_key = ? ''', ( settings_dict.get('api_key_auth', ''), settings_dict.get('api_key_apps_vk', ''), settings_dict.get('vk_api_key', ''), settings_dict.get('vk_st_alone', ''), settings_dict.get('key_callback_vk', ''), settings_dict.get('senler_token', ''), settings_dict.get('wa_ak', ''), settings_dict.get('wa_api_key', ''), settings_dict.get('curators', ''), settings_dict.get('call_api_key', '') )) else: # Создаем новую запись cursor.execute(''' INSERT INTO settings ( api_key_auth, api_key_apps_vk, vk_api_key, vk_st_alone, key_callback_vk, senler_token, wa_ak, wa_api_key, curators, call_api_key ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''', ( settings_dict.get('api_key_auth', ''), settings_dict.get('api_key_apps_vk', ''), settings_dict.get('vk_api_key', ''), settings_dict.get('vk_st_alone', ''), settings_dict.get('key_callback_vk', ''), settings_dict.get('senler_token', ''), settings_dict.get('wa_ak', ''), settings_dict.get('wa_api_key', ''), settings_dict.get('curators', ''), settings_dict.get('call_api_key', '') )) conn.commit() conn.close() # Обновляем глобальные переменные api_key_auth = settings_dict.get('api_key_auth', '') api_key_apps_vk = settings_dict.get('api_key_apps_vk', '') vk_api_key = settings_dict.get('vk_api_key', '') vk_st_alone = settings_dict.get('vk_st_alone', '') key_callback_vk = settings_dict.get('key_callback_vk', '') senler_token = settings_dict.get('senler_token', '') wa_ak = settings_dict.get('wa_ak', '') wa_api_key = settings_dict.get('wa_api_key', '') curators = settings_dict.get('curators', '') call_api_key = settings_dict.get('call_api_key', '') # Выводим значения в консоль print(f"wa_api_key: {wa_api_key}") print(f"wa_ak: {wa_ak}") print(f"vk_api_key: {vk_api_key}") print(f"vk_st_alone: {vk_st_alone}") print(f"key_callback_vk: {key_callback_vk}") print(f"senler_token: {senler_token}") print(f"api_key_auth: {api_key_auth}") print(f"api_key_apps_vk: {api_key_apps_vk}") print(f"curators: {curators}") print(f"call_api_key: {call_api_key}") @app.route('/load_settings', methods=['POST']) def get_settings(): # Получаем ключ авторизации из запроса client_api_key_sys = request.json.get('api_key_sys') # Проверка ключа авторизации if client_api_key_sys != os.getenv('api_key_sys'): return jsonify({"error": "Unauthorized access"}), 403 # Загружаем настройки из базы данных settings = load_settings() return jsonify(settings) @app.route('/save_settings', methods=['POST']) def save_settings_route(): # Получаем ключ авторизации из запроса client_api_key_sys = request.json.get('api_key_sys') # Проверка ключа авторизации if client_api_key_sys != os.getenv('api_key_sys'): return jsonify({"error": "Unauthorized access"}), 403 data = request.json.get('data', {}) if data: # Выводим полученные данные в консоль сервера print("Received data from page:", data) save_settings(data) return jsonify({'status': 'success'}) else: return jsonify({'status': 'error', 'message': 'No data provided'}), 400 @app.route('/set') def index_set(): return render_template('settings.html') # Имя базы данных db_name = 'data_gc.db' @app.route('/vk_webhook', methods=['POST']) def vk_webhook(): data = request.json # Логируем полученные данные для отладки print(f"Received data: {data}") # Обрабатываем вебхук с помощью функции из webhook_handler.py response = handle_webhook(data, key_callback_vk, db_name) # Возвращаем ответ ВКонтакте return response mapping_template = { "username": "name", "phone": "phone", "email": "email", "city": "b_city", "finished": "b_fin", "ban": "b_ban", "ignore": "b_ign", "banners": "b_baners", "buttons": "b_butt", "messages": "b_mess" } def get_db_connection_user(): conn = sqlite3.connect(DATABASE_NEW) conn.row_factory = sqlite3.Row return conn @app.route('/user_db_set', methods=['GET']) def get_user(): # Проверка API-ключа api_key_sys_control = request.args.get('api_sys') if api_key_sys_control != api_key_sys: return jsonify({"error": "Invalid API key"}), 403 email = request.args.get('email') vk_id = request.args.get('vk_id') phone = request.args.get('phone') if not email and not vk_id and not phone: return jsonify({"error": "Either email, vk_id, or phone must be provided"}), 400 conn = get_db_connection_user() cursor = conn.cursor() query = "SELECT * FROM contacts WHERE " params = [] if email: query += "email = ?" params.append(email) if email and (vk_id or phone): query += " OR " if vk_id: query += "vk_id = ?" params.append(vk_id) if vk_id and phone: query += " OR " if phone: query += "phone = ?" params.append(phone) cursor.execute(query, params) user = cursor.fetchone() conn.close() if user: user_dict = dict(user) # Преобразование строки "orders" в JSON-объект if 'orders' in user_dict and isinstance(user_dict['orders'], str): try: user_dict['orders'] = json.loads(user_dict['orders']) except json.JSONDecodeError: user_dict['orders'] = {} # Если не удалось преобразовать, устанавливаем пустой объект # Преобразование строки "bonus" в JSON-объект if 'bonus' in user_dict and isinstance(user_dict['bonus'], str): try: user_dict['bonus'] = json.loads(user_dict['bonus']) except json.JSONDecodeError: user_dict['bonus'] = {} # Если не удалось преобразовать, устанавливаем пустой объект return jsonify(user_dict) else: return jsonify({"error": "User not found"}), 404 # Отдаем дату онлайн @app.route('/get_current_time', methods=['GET']) def get_current_time(): utc_now = datetime.utcnow() msk_tz = pytz.timezone('Europe/Moscow') msk_now = utc_now.replace(tzinfo=pytz.utc).astimezone(msk_tz) current_time = msk_now.isoformat(timespec='microseconds') return jsonify({'current_time': current_time}) # Функция для очистки номера телефона def clean_phone_number_ss(phone_number): return re.sub(r'\D', '', phone_number) # Добавляем пользователя mt_site = { 'name': 'name', 'phone': 'phone', 'email': 'email', 'utm_campaign': 'utm_campaign', 'utm_content': 'utm_content', 'utm_medium': 'utm_medium', 'utm_source': 'utm_source', 'utm_term': 'utm_term', 'gcpc': 'gcpc' } mt_vk = { 'name': 'name', 'phone': 'phone', 'email': 'email', 'vk_id': 'vk_id', 'utm_campaign': 'utm_campaign', 'utm_content': 'utm_content', 'utm_medium': 'utm_medium', 'utm_source': 'utm_source', 'utm_term': 'utm_term', 'gcpc': 'gcpc' } mt_tg = { 'name': 'name', 'phone': 'phone', 'email': 'email', 'chat_id': 'chat_id', 'utm_campaign': 'utm_campaign', 'utm_content': 'utm_content', 'utm_medium': 'utm_medium', 'utm_source': 'utm_source', 'utm_term': 'utm_term', 'gcpc': 'gcpc' } mt_gc = { 'name': 'name', 'phone': 'phone', 'email': 'email', 'b_city': 'b_city', 'vk_id': 'vk_id', 'gc_url': 'gc_url', 'utm_campaign': 'utm_campaign', 'utm_content': 'utm_content', 'utm_medium': 'utm_medium', 'utm_source': 'utm_source', 'utm_term': 'utm_term', 'gcpc': 'gcpc' } mt_pass = { 'name': 'name', 'phone': 'phone', 'email': 'email', 'kol': 'pr1', 'pr2': 'pr2', 'gen_pass': 'pr5', 'utm_campaign': 'utm_campaign', 'utm_content': 'utm_content', 'utm_medium': 'utm_medium', 'utm_source': 'utm_source', 'utm_term': 'utm_term', 'gcpc': 'gcpc' } tl_quest = { 'name': 'name', 'phone': 'phone', 'email': 'email', 'pr2': 'pr2', 'utm_campaign': 'utm_campaign', 'utm_content': 'utm_content', 'utm_medium': 'utm_medium', 'utm_source': 'utm_source', 'utm_term': 'utm_term', 'gcpc': 'gcpc' } mapp_templates = { 'site': mt_site, 'vk': mt_vk, 'tg': mt_tg, 'gc': mt_gc, 'tilda': mt_pass, 'quest': tl_quest } def verify_phone_number(phone_number): full_url_ver = f"{wa_url}{wa_ak}{ws_url_ver}{wa_api_key}" payload = {"phoneNumber": phone_number} headers = {'Content-Type': 'application/json'} response = requests.post(full_url_ver, headers=headers, json=payload) if response.status_code == 200: response_body = response.json() return response_body.get('existsWhatsapp', 'false') else: return "false" def generate_password(length=8): letters_and_digits = string.ascii_letters + string.digits return ''.join(random.choice(letters_and_digits) for i in range(length)) def add_or_update_contact(contact_data, db_name): conn = sqlite3.connect(db_name) cursor = conn.cursor() email = contact_data.get('email') if not email: logging.error(f"Missing email in contact data: {contact_data}") return utc_now = datetime.utcnow() msk_tz = pytz.timezone('Europe/Moscow') msk_now = utc_now.replace(tzinfo=pytz.utc).astimezone(msk_tz) contact_data['data_t'] = msk_now.strftime('%Y-%m-%d %H:%M:%S') fields = [ 'name', 'phone', 'email', 'vk_id', 'chat_id', 'ws_st', 'ws_stop', 'web_st', 'fin_prog', 'b_city', 'b_fin', 'b_ban', 'b_ign', 'b_baners', 'b_butt', 'b_mess', 'orders', 'curator', 'bonus', 'shop_status', 'answers', 'quiz', 'kassa', 'gc_url', 'key_pr', 'n_con', 'canal', 'data_on', 'data_t', 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'gcpc' ] for field in fields: if field not in contact_data: contact_data[field] = '' cursor.execute("SELECT id FROM contacts WHERE email = ?", (email,)) contact = cursor.fetchone() if contact: update_fields = [f"{field} = ?" for field in fields if contact_data[field] != ''] update_values = [contact_data[field] for field in fields if contact_data[field] != ''] update_values.append(contact[0]) update_query = f"UPDATE contacts SET {', '.join(update_fields)} WHERE id = ?" cursor.execute(update_query, update_values) else: insert_query = f"INSERT INTO contacts ({', '.join(fields)}) VALUES ({', '.join(['?' for _ in fields])})" cursor.execute(insert_query, tuple(contact_data[field] for field in fields)) conn.commit() conn.close() @app.route('/add_user_home', methods=['GET']) def add_user_home(): global current_curator_index veref_on_off = request.args.get('ver', '0') curator_on_off = request.args.get('cur', '0') db_name = request.args.get('db', 'data_gc.db') # Получаем имя базы данных из запроса template_key = request.args.get('player', 'site') mapping_template_cur = mapp_templates.get(template_key, mt_site) user_data = {mapping_template_cur[key]: request.args.get(key, "") for key in mapping_template_cur} logging.debug(f"Received data: {user_data}") if curator_on_off == "1": user_data['curator'] = curators[current_curator_index] current_curator_index = (current_curator_index + 1) % len(curators) else: user_data['curator'] = user_data.get('curator', '') if veref_on_off == "1": phone_number = user_data.get('phone', '') if not phone_number: logging.error("Phone number is empty") return jsonify({'status': 'error', 'message': 'Phone number is empty'}), 400 phone_verification_response = verify_phone_number(phone_number) if phone_verification_response is not None: user_data['ws_st'] = '1' if phone_verification_response else '0' else: user_data['ws_st'] = user_data.get('ws_st', '') try: add_or_update_contact(user_data, db_name) return jsonify({'status': 'success', 'message': f'User added {user_data.get("curator", "not assigned")}'}) except Exception as e: logging.error(f"Error adding user: {e}") return jsonify({'status': 'error', 'message': str(e)}), 500 @app.route('/user', methods=['GET']) def user(): global current_curator_index # Получаем параметры API-ключа и email из запроса api_sys = request.args.get('api_sys') email = request.args.get('email') # Проверка API-ключа if api_sys != os.getenv('api_key_sys'): return jsonify({"error": "Unauthorized access"}), 403 # Проверка email if not email: return jsonify({'error': 'Email is required'}), 400 veref_on_off = request.args.get('ver', '0') curator_on_off = request.args.get('cur', '0') db_name = request.args.get('db', 'data_gc.db') # Получаем имя базы данных из запроса template_key = request.args.get('player', 'site') mapping_template_cur = mapp_templates.get(template_key, mt_site) user_data = {mapping_template_cur[key]: request.args.get(key, "") for key in mapping_template_cur} logging.debug(f"Received data: {user_data}") if curator_on_off == "1": user_data['curator'] = curators[current_curator_index] current_curator_index = (current_curator_index + 1) % len(curators) else: user_data['curator'] = user_data.get('curator', '') if veref_on_off == "1": phone_number = user_data.get('phone', '') if not phone_number: logging.error("Phone number is empty") return jsonify({'status': 'error', 'message': 'Phone number is empty'}), 400 phone_verification_response = verify_phone_number(phone_number) if phone_verification_response is not None: user_data['ws_st'] = '1' if phone_verification_response else '0' else: user_data['ws_st'] = user_data.get('ws_st', '') try: add_or_update_contact(user_data, db_name) return jsonify({'status': 'success', 'message': f'User added {user_data.get("curator", "not assigned")}'}), 200 except Exception as e: logging.error(f"Error adding user: {e}") return jsonify({'status': 'error', 'message': str(e)}), 500 @app.route('/add_user_mess', methods=['GET']) def add_user_mess(): global current_curator_index veref_on_off = request.args.get('ver', '0') curator_on_off = request.args.get('cur', '0') db_name = request.args.get('db', 'site_data.db') # Получаем имя базы данных из запроса template_key = request.args.get('player', 'site') mapping_template_cur = mapp_templates.get(template_key, mt_site) user_data = {mapping_template_cur[key]: request.args.get(key, "") for key in mapping_template_cur} logging.debug(f"Received data: {user_data}") if curator_on_off == "1": user_data['curator'] = curators[current_curator_index] current_curator_index = (current_curator_index + 1) % len(curators) else: user_data['curator'] = user_data.get('curator', '') if veref_on_off == "1": phone_number = user_data.get('phone', '') if not phone_number: logging.error("Phone number is empty") return jsonify({'status': 'error', 'message': 'Phone number is empty'}), 400 phone_verification_response = verify_phone_number(phone_number) if phone_verification_response is not None: user_data['ws_st'] = '1' if phone_verification_response else '0' else: user_data['ws_st'] = user_data.get('ws_st', '') try: add_or_update_contact(user_data, db_name) return jsonify({'status': 'success', 'message': f'User added {user_data.get("curator", "not assigned")}'}) except Exception as e: logging.error(f"Error adding user: {e}") return jsonify({'status': 'error', 'message': str(e)}), 500 # Работа с ордером из сайта @app.route('/wr_order', methods=['GET','POST']) def shop_order_new(): try: logging.debug("Starting shop_order_new") api_sys_control = request.args.get('api_sys') if api_sys_control != api_key_sys: logging.warning("Unauthorized access attempt") return json.dumps({"error": "Unauthorized access"}), 403 name = request.args.get('name', '') email = request.args.get('email', '') phone = request.args.get('phone', '').lstrip('+') order = request.args.get('order', '') status = request.args.get('status', '') del_flag = request.args.get('del', '') if not email or not phone: logging.error("Email and phone are required") return json.dumps({"error": "Email and phone are required"}), 400 phone = clean_phone_number_ss(phone) conn = sqlite3.connect(DATABASE_NEW) cursor = conn.cursor() cursor.execute("SELECT * FROM contacts WHERE email = ? OR phone = ?", (email, phone)) result = cursor.fetchone() if result: shop_st = result[17] if result[17] else '{}' shop_st_data = json.loads(shop_st) logging.debug(f"Existing record found. Loaded JSON: {shop_st_data}") else: shop_st_data = {} if del_flag == '1': if order in shop_st_data: del shop_st_data[order] elif order and status: shop_st_data[order] = status shop_st_json = json.dumps(shop_st_data) utc_now = datetime.utcnow() msk_tz = pytz.timezone('Europe/Moscow') msk_now = utc_now.replace(tzinfo=pytz.utc).astimezone(msk_tz) data_on = msk_now.strftime('%Y-%m-%d %H:%M:%S') columns_to_update = ['name', 'phone', 'email', 'orders', 'data_on'] values_to_update = [name, phone, email, shop_st_json, data_on] if result: set_clause = ', '.join([f"{col} = ?" for col in columns_to_update]) query = f"UPDATE contacts SET {set_clause} WHERE email = ? OR phone = ?" cursor.execute(query, values_to_update + [email, phone]) else: query = f"INSERT INTO contacts ({', '.join(columns_to_update)}) VALUES ({', '.join(['?' for _ in columns_to_update])})" cursor.execute(query, values_to_update) conn.commit() replace_null_with_empty_string(conn) conn.close() return json.dumps(shop_st_data), 200 except Exception as e: logging.error(f"An error occurred: {str(e)}") return json.dumps({"error": str(e)}), 500 # Данные формы из ВК @app.route('/wr_form_vk', methods=['POST']) def wr_form_vk(): try: logging.debug("Starting wr_form_vk") # Читаем параметры из POST-запроса (формы) api_sys_control = request.form.get('api_sys') if api_sys_control != api_key_sys: logging.warning("Unauthorized access attempt") return json.dumps({"error": "Unauthorized access"}), 403 name = request.form.get('name', '') email = request.form.get('email', '') phone = request.form.get('phone', '').lstrip('+') vkid = request.form.get('vk_id', '') if not email or not phone: logging.error("Email and phone are required") return json.dumps({"error": "Email and phone are required"}), 400 phone = clean_phone_number_ss(phone) conn = sqlite3.connect(DATABASE_NEW) cursor = conn.cursor() # Ищем по email, phone или vk_id cursor.execute("SELECT * FROM contacts WHERE email = ? OR phone = ? OR vk_id = ?", (email, phone, vkid)) result = cursor.fetchone() columns_to_update = ['name', 'phone', 'email', 'vk_id'] values_to_update = [name, phone, email, vkid] if result: set_clause = ', '.join([f"{col} = ?" for col in columns_to_update]) query = f"UPDATE contacts SET {set_clause} WHERE email = ? OR phone = ? OR vk_id = ?" cursor.execute(query, values_to_update + [email, phone, vkid]) else: query = f"INSERT INTO contacts ({', '.join(columns_to_update)}) VALUES ({', '.join(['?' for _ in columns_to_update])})" cursor.execute(query, values_to_update) conn.commit() replace_null_with_empty_string(conn) conn.close() return json.dumps({"success": True}), 200 except Exception as e: logging.error(f"An error occurred: {str(e)}") return json.dumps({"error": str(e)}), 500 # Запись ордера по ключу и ВК ИД @app.route('/set_order_vk', methods=['POST']) def set_order_vk(): try: logging.debug("Starting wr_order_vk") # Читаем параметры из POST-запроса api_sys_control = request.form.get('api_sys') if api_sys_control != api_key_sys: logging.warning("Unauthorized access attempt") return json.dumps({"error": "Unauthorized access"}), 403 vkid = request.form.get('vk_id', '') order = request.form.get('order', '') status = request.form.get('status', '') del_flag = request.form.get('del', '') n_con_flag = request.form.get('n_con', '') if not vkid: logging.error("VK ID is required") return json.dumps({"error": "VK ID is required"}), 400 conn = sqlite3.connect(DATABASE_NEW) cursor = conn.cursor() cursor.execute("SELECT * FROM contacts WHERE vk_id = ?", (vkid,)) result = cursor.fetchone() if result: shop_st = result[17] if result[17] else '{}' shop_st_data = json.loads(shop_st) logging.debug(f"Existing record found. Loaded JSON: {shop_st_data}") else: shop_st_data = {} if del_flag == '1': if order in shop_st_data: del shop_st_data[order] elif order and status: shop_st_data[order] = status shop_st_json = json.dumps(shop_st_data) utc_now = datetime.utcnow() msk_tz = pytz.timezone('Europe/Moscow') msk_now = utc_now.replace(tzinfo=pytz.utc).astimezone(msk_tz) data_on = msk_now.strftime('%Y-%m-%d %H:%M:%S') columns_to_update = ['vk_id', 'orders', 'n_con', 'data_on'] values_to_update = [vkid, shop_st_json, n_con_flag, data_on] if result: set_clause = ', '.join([f"{col} = ?" for col in columns_to_update]) query = f"UPDATE contacts SET {set_clause} WHERE vk_id = ?" cursor.execute(query, values_to_update + [vkid]) else: query = f"INSERT INTO contacts ({', '.join(columns_to_update)}) VALUES ({', '.join(['?' for _ in columns_to_update])})" cursor.execute(query, values_to_update) conn.commit() replace_null_with_empty_string(conn) conn.close() return json.dumps(shop_st_data), 200 except Exception as e: logging.error(f"An error occurred: {str(e)}") return json.dumps({"error": str(e)}), 500 # Чтение ордера @app.route('/get_order_monitop', methods=['GET']) def get_order_monitop(): try: logging.debug("Starting set_order_monitop") # Читаем параметры из GET-запроса vkid = request.args.get('vk_id', '') order = request.args.get('order', '') if not vkid or not order: logging.error("VK ID and order are required") return json.dumps({"error": "VK ID and order are required"}), 400 conn = sqlite3.connect(DATABASE_NEW) cursor = conn.cursor() # Ищем запись по vk_id cursor.execute("SELECT orders FROM contacts WHERE vk_id = ?", (vkid,)) result = cursor.fetchone() # Получаем текущую дату и время на сервере utc_now = datetime.utcnow() msk_tz = pytz.timezone('Europe/Moscow') msk_now = utc_now.replace(tzinfo=pytz.utc).astimezone(msk_tz) current_time = msk_now.isoformat(timespec='microseconds') # Если запись по vk_id не найдена, возвращаем значение "not" для ордера if not result: logging.error(f"VK ID {vkid} not found") response = {order: 'not', 'online_date': current_time} return jsonify(response), 200 shop_st = result[0] if result[0] else '{}' shop_st_data = json.loads(shop_st) logging.debug(f"Existing record found. Loaded JSON: {shop_st_data}") # Ищем значение по ключу order value = shop_st_data.get(order, 'not') # Возвращаем данные из столбца и текущую дату и время response = {order: value, 'online_date': current_time} return jsonify(response), 200 except Exception as e: logging.error(f"An error occurred: {str(e)}") return json.dumps({"error": str(e)}), 500 # Функция для валидации подписи ВК приложения ОБЩАЯ def is_valid(*, query: dict, secret: str) -> bool: """Check VK Apps signature""" # Отфильтровываем параметры, начинающиеся с "vk_" vk_subset = OrderedDict(sorted((k, v) for k, v in query.items() if k.startswith("vk_"))) logging.debug(f"Filtered VK params: {vk_subset}") # Объединяем параметры в строку encoded_params = urlencode(vk_subset, doseq=True) logging.debug(f"Encoded params: {encoded_params}") # Вычисляем хеш-код с использованием HMAC и SHA256 hash_code = b64encode(HMAC(secret.encode(), encoded_params.encode(), sha256).digest()) decoded_hash_code = hash_code.decode('utf-8')[:-1].replace('+', '-').replace('/', '_') logging.debug(f"Calculated signature: {decoded_hash_code}") # Сравниваем с переданной подписью return query.get("sign") == decoded_hash_code # Функция для работы с базой данных def get_order_from_db(vkid): conn = sqlite3.connect(DATABASE_NEW) cursor = conn.cursor() # Ищем запись по vk_id cursor.execute("SELECT orders FROM contacts WHERE vk_id = ?", (vkid,)) result = cursor.fetchone() logging.debug(f"Database result: {result}") # Если запись по vk_id не найдена, возвращаем значение "not" для ордера if not result: logging.error(f"VK ID {vkid} not found") return None shop_st = result[0] if result[0] else '{}' logging.debug(f"Shop_st: {shop_st}") shop_st_data = json.loads(shop_st) logging.debug(f"Existing record found. Loaded JSON: {shop_st_data}") return shop_st_data # Чтение ордера по ключу и ВК ИД для приложения @app.route('/get_order', methods=['POST']) def get_order(): try: logging.debug("Starting get_order") # Читаем параметры из POST-запроса vkid = request.form.get('vk_id', '') order = request.form.get('order', '') apps_id = request.form.get('apps_id', '') # Сюда придёт ИД ВК приложения fullUrl = request.form.get('fullUrl', '') # Полный URL, который выдаёт ВКонтакте logging.debug(f"Received data: vk_id={vkid}, order={order}, apps_id={apps_id}, fullUrl={fullUrl}") # Преобразуем строку в JSON try: api_key_apps_vk_dict = json.loads(api_key_apps_vk) except json.JSONDecodeError as e: logging.error(f"Error decoding JSON: {e}") return jsonify({"status": "invalid"}), 200 # Проверка подписи для приложения if str(apps_id) not in api_key_apps_vk_dict: # Приводим apps_id к строке logging.error("Invalid apps_id") return json.dumps({"error": "Invalid apps_id"}), 400 secret = api_key_apps_vk_dict[str(apps_id)] # Приводим apps_id к строке logging.debug(f"Using secret: {secret}") # Парсим полный URL для получения параметров запроса query_params = dict(parse_qsl(urlparse(fullUrl).query, keep_blank_values=True)) logging.debug(f"Query params for signature check: {query_params}") # Проверяем подпись if not is_valid(query=query_params, secret=secret): logging.error("Invalid signature") return json.dumps({"error": "Invalid signature"}), 400 # Получаем данные из базы данных shop_st_data = get_order_from_db(vkid) if not shop_st_data: response = {order: 'not'} return jsonify(response), 200 # Ищем значение по ключу order value = shop_st_data.get(order, 'not') logging.debug(f"Value for order {order}: {value}") # Возвращаем данные из столбца response = {order: value} return jsonify(response), 200 except Exception as e: logging.error(f"An error occurred: {str(e)}") return json.dumps({"error": str(e)}), 500 # Функция для работы с базой данных - Чтение значения разрешена ли рассылка ВК def get_lo_mess_from_db(vkid): conn = sqlite3.connect(DATABASE_NEW) cursor = conn.cursor() # Ищем запись по vk_id cursor.execute("SELECT canal FROM contacts WHERE vk_id = ?", (vkid,)) result = cursor.fetchone() logging.debug(f"Database result: {result}") # Если запись по vk_id не найдена, возвращаем None if not result: logging.error(f"VK ID {vkid} not found") return None canal_data = result[0] if result[0] else '{}' logging.debug(f"Canal data: {canal_data}") canal_data_json = json.loads(canal_data) logging.debug(f"Existing record found. Loaded JSON: {canal_data_json}") return canal_data_json # Чтение значения разрешена ли рассылка ВК из базы @app.route('/get_lo_mess', methods=['POST']) def getlo_mess(): try: logging.debug("Starting get_lo_mess") # Читаем параметры из POST-запроса vkid = request.form.get('vk_id', '') grup_id = request.form.get('grup_id', '') # Сюда придёт номер сообщества, который является ключом для поиска apps_id = request.form.get('apps_id', '') # Сюда придёт ИД ВК приложения fullUrl = request.form.get('fullUrl', '') # Полный URL, который выдаёт ВКонтакте logging.debug(f"Received data: vk_id={vkid}, grup_id={grup_id}, apps_id={apps_id}, fullUrl={fullUrl}") # Преобразуем строку в JSON try: api_key_apps_vk_dict = json.loads(api_key_apps_vk) except json.JSONDecodeError as e: logging.error(f"Error decoding JSON: {e}") return jsonify({"status": "invalid"}), 200 # Проверка подписи для приложения if str(apps_id) not in api_key_apps_vk_dict: # Приводим apps_id к строке logging.error("Invalid apps_id") return json.dumps({"error": "Invalid apps_id"}), 400 secret = api_key_apps_vk_dict[str(apps_id)] # Приводим apps_id к строке logging.debug(f"Using secret: {secret}") # Парсим полный URL для получения параметров запроса query_params = dict(parse_qsl(urlparse(fullUrl).query, keep_blank_values=True)) logging.debug(f"Query params for signature check: {query_params}") # Проверяем подпись if not is_valid(query=query_params, secret=secret): logging.error("Invalid signature") return json.dumps({"error": "Invalid signature"}), 400 # Получаем данные из базы данных canal_data_json = get_lo_mess_from_db(vkid) if not canal_data_json: response = {"status": "not"} return jsonify(response), 200 # Ищем значение по ключу grup_id value = canal_data_json.get(grup_id, 'not') logging.debug(f"Value for grup_id {grup_id}: {value}") # Возвращаем данные из столбца response = {"status": value} return jsonify(response), 200 except Exception as e: logging.error(f"An error occurred: {str(e)}") return json.dumps({"error": str(e)}), 500 # Работа с бонусами из сайта без VK_ID @app.route('/wr_bonus', methods=['GET','POST']) def shop_bonus_new(): try: logging.debug("Starting shop_bonus_new") api_sys_control = request.args.get('api_sys') if api_sys_control != api_key_sys: logging.warning("Unauthorized access attempt") return json.dumps({"error": "Unauthorized access"}), 403 name = request.args.get('name', '') email = request.args.get('email', '') phone = request.args.get('phone', '').lstrip('+') bonus = request.args.get('bonus', '') status = request.args.get('status', '') del_flag = request.args.get('del', '') if not email or not phone: logging.error("Email and phone are required") return json.dumps({"error": "Email and phone are required"}), 400 phone = clean_phone_number_ss(phone) conn = sqlite3.connect(DATABASE_NEW) cursor = conn.cursor() cursor.execute("SELECT * FROM contacts WHERE email = ? OR phone = ?", (email, phone)) result = cursor.fetchone() if result: bonus_st = result[19] if result[19] else '{}' bonus_st_data = json.loads(bonus_st) logging.debug(f"Existing record found. Loaded JSON: {bonus_st_data}") else: bonus_st_data = {} if del_flag == '1': if bonus in bonus_st_data: del bonus_st_data[bonus] elif bonus and status: bonus_st_data[bonus] = status bonus_st_json = json.dumps(bonus_st_data) utc_now = datetime.utcnow() msk_tz = pytz.timezone('Europe/Moscow') msk_now = utc_now.replace(tzinfo=pytz.utc).astimezone(msk_tz) data_on = msk_now.strftime('%Y-%m-%d %H:%M:%S') columns_to_update = ['name', 'phone', 'email', 'bonus', 'data_on'] values_to_update = [name, phone, email, bonus_st_json, data_on] if result: set_clause = ', '.join([f"{col} = ?" for col in columns_to_update]) query = f"UPDATE contacts SET {set_clause} WHERE email = ? OR phone = ?" cursor.execute(query, values_to_update + [email, phone]) else: query = f"INSERT INTO contacts ({', '.join(columns_to_update)}) VALUES ({', '.join(['?' for _ in columns_to_update])})" cursor.execute(query, values_to_update) conn.commit() replace_null_with_empty_string(conn) conn.close() return json.dumps(bonus_st_data), 200 except Exception as e: logging.error(f"An error occurred: {str(e)}") return json.dumps({"error": str(e)}), 500 # Добавление пользователя в группу СЕНДЛЕРА напрямую их запроса @app.route('/add_get_senler', methods=['GET']) def add_get_senler(): # Получаем параметры из GET-запроса, если параметр отсутствует, устанавливаем значение пустой строки vk_user_id = request.args.get('vk_user_id', "") vk_group_id = request.args.get('vk_group_id', "") subscription_id = request.args.get('sub_id', "") senler_token = request.args.get('access_token', "") # Получаем access_token из запроса # Формируем данные для запроса к API Senler senler_data = { 'vk_user_id': vk_user_id, 'vk_group_id': vk_group_id, 'subscription_id': subscription_id, 'access_token': senler_token, # Передаем access_token 'v': 2 } # Отправляем GET-запрос к API Senler response = requests.get('https://senler.ru/api/subscribers/add', params=senler_data) # Проверяем успешность запроса success = response.status_code == 200 and response.json().get('success', False) # Возвращаем результат return jsonify({ 'success': success }) # Добавление пользователя в группу СЕНДЛЕРА из конструктора @app.route('/add_user_senler', methods=['POST']) def add_user_senler(): # Получаем параметры из POST-запроса, если параметр отсутствует, устанавливаем значение пустой строки vk_user_id = request.form.get('vk_user_id', "") vk_group_id = request.form.get('vk_group_id', "") subscription_id = request.form.get('sub_id', "") utm_source = request.form.get('utm_source', "") utm_medium = request.form.get('utm_medium', "") utm_campaign = request.form.get('utm_campaign', "") utm_content = request.form.get('utm_content', "") utm_term = request.form.get('utm_term', "") # Формируем данные для запроса к API Senler senler_data = { 'vk_user_id': vk_user_id, 'vk_group_id': vk_group_id, 'subscription_id': subscription_id, 'utm_source': utm_source, 'utm_medium': utm_medium, 'utm_campaign': utm_campaign, 'utm_content': utm_content, 'utm_term': utm_term, 'access_token': senler_token, 'v': 2 } # Отправляем запрос к API Senler response = requests.post('https://senler.ru/api/subscribers/add', data=senler_data) # Проверяем успешность запроса success = response.status_code == 200 and response.json().get('success', False) # Возвращаем результат return jsonify({ 'success': success }) # Добавление пользователя в группу СЕНДЛЕРА с данными из конструктора @app.route('/add_user_senler_full', methods=['POST']) def add_user_senler_full(): # Получаем параметры из POST-запроса, если параметр отсутствует, устанавливаем значение пустой строки vk_user_id = request.form.get('vk_user_id', "") vk_group_id = request.form.get('vk_group_id', "") subscription_id = request.form.get('sub_id', "") utm_source = request.form.get('utm_source', "") utm_medium = request.form.get('utm_medium', "") utm_campaign = request.form.get('utm_campaign', "") utm_content = request.form.get('utm_content', "") utm_term = request.form.get('utm_term', "") name = request.form.get('name', "") email = request.form.get('email', "") phone = request.form.get('phone', "") utms = request.form.get('utms', "") # Формируем данные для запроса к API Senler для добавления пользователя add_data = { 'vk_user_id': vk_user_id, 'vk_group_id': vk_group_id, 'subscription_id': subscription_id, 'utm_source': utm_source, 'utm_medium': utm_medium, 'utm_campaign': utm_campaign, 'utm_content': utm_content, 'utm_term': utm_term, 'access_token': senler_token, 'v': 2 } # Отправляем запрос к API Senler для добавления пользователя add_response = requests.post('https://senler.ru/api/subscribers/add', data=add_data) print("Add Data:", add_data) print("Add User Error Response:", add_response.json()) # Проверяем успешность добавления пользователя if add_response.json().get('success'): # Формируем данные для запроса к API Senler для установки name name_data = { 'vk_user_id': vk_user_id, 'vk_group_id': vk_group_id, 'name': 'gb_name', 'value': name, 'access_token': senler_token, 'v': 2 } # Формируем данные для запроса к API Senler для установки email email_data = { 'vk_user_id': vk_user_id, 'vk_group_id': vk_group_id, 'name': 'gb_email', 'value': email, 'access_token': senler_token, 'v': 2 } # Формируем данные для запроса к API Senler для установки телефона phone_data = { 'vk_user_id': vk_user_id, 'vk_group_id': vk_group_id, 'name': 'gb_phone', 'value': phone, 'access_token': senler_token, 'v': 2 } # Отправляем запрос к API Senler для установки name name_response = requests.post('https://senler.ru/api/vars/set', data=name_data) # Отправляем запрос к API Senler для установки email email_response = requests.post('https://senler.ru/api/vars/set', data=email_data) # Отправляем запрос к API Senler для установки телефона phone_response = requests.post('https://senler.ru/api/vars/set', data=phone_data) # Возвращаем результат return jsonify({ 'add_response': add_response.json(), 'name_response': name_response.json(), 'email_response': email_response.json(), 'phone_response': phone_response.json() }) else: # Возвращаем ошибку добавления пользователя return jsonify(add_response.json()) # Проверка групп СЕНДЛЕРА на рассылку @app.route('/get_Lo_Mess_senler', methods=['POST']) def get_Lo_Mess_senler(): try: # Получаем параметры из POST-запроса, если параметр отсутствует, устанавливаем значение пустой строки vk_user_id = request.form.get('vk_user_id', "") vk_group_id = request.form.get('vk_group_id', "") # Добавляем параметр vk_group_id subscription_id = request.form.get('sub_id', "") # Проверяем, что все необходимые параметры переданы if not vk_user_id or not vk_group_id or not subscription_id: return jsonify({"status": "error", "message": "Missing required parameters"}), 400 payload = { "vk_user_id": [vk_user_id], 'vk_group_id': vk_group_id, "access_token": senler_token, "v": 2 } # Выводим данные запроса для отладки logging.debug(f"Request payload: {payload}") # Выполняем запрос к API Senler response = requests.post('https://senler.ru/api/subscribers/get', data=payload) # Проверяем статус ответа if response.status_code != 200: logging.error(f"Failed to fetch data from Senler API: {response.status_code} - {response.text}") return jsonify({"status": "error", "message": "Failed to fetch data from Senler API"}), 500 # Парсим ответ data = response.json() # Выводим полный ответ от сервера Senler в консоль logging.debug(f"Senler API response: {data}") # Проверяем, что ответ содержит данные if not data.get('success'): return jsonify({"status": "error", "message": "Failed to fetch data from Senler API"}), 500 # Проверяем, что пользователь подписан на указанную группу user_subscriptions = data.get('items', []) if not user_subscriptions: return jsonify({"status": "not"}), 200 for user in user_subscriptions: subscriptions = user.get('subscriptions', []) for sub in subscriptions: if sub.get('subscription_id') == int(subscription_id): return jsonify({"status": "1"}), 200 # Если группа не найдена return jsonify({"status": "not"}), 200 except Exception as e: logging.error(f"An error occurred: {str(e)}") return jsonify({"status": "error", "message": str(e)}), 500 # Отписка пользователя от группы СЕНДЛЕРА @app.route('/del_user_senler', methods=['POST']) def del_user_senler(): try: # Получаем параметры из POST-запроса, если параметр отсутствует, устанавливаем значение пустой строки vk_user_id = request.form.get('vk_user_id', "") vk_group_id = request.form.get('vk_group_id', "") # Добавляем параметр vk_group_id subscription_id = request.form.get('sub_id', "") # Проверяем, что все необходимые параметры переданы if not vk_user_id or not vk_group_id or not subscription_id: return jsonify({"status": "error", "message": "Missing required parameters"}), 400 # Преобразуем параметры в строки, если это необходимо vk_user_id = int(vk_user_id) vk_group_id = int(vk_group_id) subscription_id = int(subscription_id) payload = { "vk_user_id": vk_user_id, 'vk_group_id': vk_group_id, "subscription_id": subscription_id, "access_token": senler_token, "v": 2 } # Выводим данные запроса для отладки logging.debug(f"Request payload: {payload}") # Выполняем запрос к API Senler для удаления подписки response = requests.post('https://senler.ru/api/subscribers/del', data=payload) # Проверяем статус ответа if response.status_code != 200: logging.error(f"Failed to delete subscription from Senler API: {response.status_code} - {response.text}") return jsonify({"status": "error", "message": "Failed to delete subscription from Senler API"}), 500 # Парсим ответ data = response.json() # Выводим полный ответ от сервера Senler в консоль logging.debug(f"Senler API response: {data}") # Проверяем, что ответ содержит данные if not data.get('success'): return jsonify({"status": "error", "message": "Failed to delete subscription from Senler API"}), 500 # Возвращаем успешный ответ return jsonify({"status": "success", "message": "Subscription deleted successfully"}), 200 except Exception as e: logging.error(f"An error occurred: {str(e)}") return jsonify({"status": "error", "message": str(e)}), 500 # ЗАПИСЫВАЕМ ДАННЫЕ В ВК СТОРИДЖ # Функция для обработки ошибок def error_finish(message): return jsonify({'success': False, 'error_type': 'Setup error', 'error_msg': message}), 400 # Функция для отправки запроса def sky_request(url, params): response = requests.post(url, data=params) return response.json() @app.route('/vk_s_set', methods=['POST']) def vk_s_set(): # Читаем контрольную переменную api_sys_control = request.form.get('api_sys') if api_sys_control != api_key_sys: return "EUR 22", 200 # Читаем параметры vk_id = request.form.get('vk_id', '') vk_key = request.form.get('vk_key', '') vk_value = request.form.get('vk_value', '') # Проверка на наличие обязательных параметров if not vk_id or not vk_key: return "Missing required parameters", 400 # Формируем URL для вызова метода storage.set url = f"https://api.vk.com/method/storage.set" params = { 'access_token': vk_api_key, 'v': '5.131', # Версия API 'key': vk_key, 'value': vk_value, 'user_id': vk_id } # Выполняем запрос к API ВКонтакте data = sky_request(url, params) # Обрабатываем результат if 'response' in data and data['response'] == 1: return jsonify({vk_key: vk_value}), 200 elif 'error' in data: error_code = data['error']['error_code'] error_msg = data['error']['error_msg'] return jsonify({"error": f"Error {error_code}: {error_msg}"}), 400 else: return jsonify({"error": "Unknown error"}), 500 # ЗАПИСЫВАЕМ ДАННЫЕ В ВК СТОРИДЖ @app.route('/vk_s_get', methods=['GET','POST']) def vk_s_get(): api_sys_control = request.args.get('api_sys') if api_sys_control != api_key_sys: return "EUR 22", 200 # Читаем параметры vk_id = request.args.get('vk_id', '') vk_key = request.args.get('vk_key', '') # Проверка на наличие обязательных параметров if not vk_id or not vk_key: return "Missing required parameters", 400 # Формируем URL для вызова метода storage.get url = f"https://api.vk.com/method/storage.get" params = { 'access_token': vk_api_key, 'v': '5.131', # Версия API 'key': vk_key, 'user_id': vk_id } # Выполняем запрос к API ВКонтакте response = requests.get(url, params=params) data = response.json() # Обрабатываем результат if 'response' in data and data['response']: value = data['response'][0]['value'] return jsonify({vk_key: value}), 200 elif 'error' in data: error_code = data['error']['error_code'] error_msg = data['error']['error_msg'] return f"Error {error_code}: {error_msg}", 400 else: return "Unknown error", 500 ## Маршрут для вывода графика регистраций по utm_source за выбранную дату @app.route('/registrations_today', methods=['GET']) def registrations_today(): # Получаем дату из параметра запроса selected_date = request.args.get('date', datetime.now().strftime('%Y-%m-%d')) # Подключаемся к базе данных conn = sqlite3.connect('data_gc.db') cursor = conn.cursor() # SQL-запрос для выборки данных query = """ SELECT utm_source, COUNT(*) as count FROM contacts WHERE date(data_t) = ? GROUP BY utm_source """ cursor.execute(query, (selected_date,)) results = cursor.fetchall() # Закрываем соединение с базой данных conn.close() # Формируем данные для графика labels = [row[0] for row in results] # Значения utm_source values = [row[1] for row in results] # Количество регистраций # Возвращаем данные в формате JSON return jsonify({ 'labels': labels, 'values': values }) # Маршрут для отображения страницы с графиком @app.route('/show_registrations', methods=['GET']) def show_registrations(): return render_template('registrations.html') # Маршрут для вывода графика регистраций по выбранной UTM-метке за период @app.route('/registrations_period', methods=['GET']) def registrations_period(): # Получаем даты и тип UTM-метки из параметров запроса start_date = request.args.get('start_date') end_date = request.args.get('end_date') utm_type = request.args.get('utm_type') # Подключаемся к базе данных conn = sqlite3.connect('data_gc.db') cursor = conn.cursor() # SQL-запрос для выборки данных за период по выбранной UTM-метке query = f""" SELECT {utm_type}, COUNT(*) as count FROM contacts WHERE date(data_t) BETWEEN ? AND ? GROUP BY {utm_type} """ cursor.execute(query, (start_date, end_date)) results = cursor.fetchall() # Закрываем соединение с базой данных conn.close() # Формируем данные для графика labels = [row[0] for row in results] # Значения выбранной UTM-метки values = [row[1] for row in results] # Количество регистраций # Рассчитываем общее количество регистраций total_count = sum(values) # Возвращаем данные в формате JSON return jsonify({ 'labels': labels, 'values': values, 'total_count': total_count # Добавляем общее количество в ответ }) # Маршрут для отображения страницы с графиком за период @app.route('/show_registrations_period', methods=['GET']) def show_registrations_period(): api_sys_control = request.args.get('api_sys') if api_sys_control != api_key_sys: return "EUR 22", 200 return render_template('registrations_period.html') @app.route('/delete_user', methods=['GET']) def delete_user(): # Получаем параметры из запроса api_sys = request.args.get('api_sys') email = request.args.get('email') # Проверка API-ключа if api_sys != os.getenv('api_key_sys'): return jsonify({"error": "Unauthorized access"}), 403 if not email: return jsonify({"error": "Email parameter is required"}), 400 # Подключаемся к базе данных conn = sqlite3.connect('data_gc.db') cursor = conn.cursor() # Проверяем, существует ли запись с таким email cursor.execute("SELECT id FROM contacts WHERE email = ?", (email,)) user = cursor.fetchone() if not user: conn.close() return jsonify({"error": "User with this email not found"}), 404 # Удаляем запись из базы данных cursor.execute("DELETE FROM contacts WHERE email = ?", (email,)) conn.commit() conn.close() return jsonify({"status": "success", "message": f"User with email {email} has been deleted"}), 200 # Поднятие страницы с таблицей @app.route('/data_gc_tab', methods=['GET']) def data_gc_tab(): api_sys_control = request.args.get('api_sys') if api_sys_control != api_key_sys: return "EUR 22", 200 return render_template('data_gc_tab.html') # Данные в таблицу @app.route('/data_gc_tab_out', methods=['GET']) def data_gc_tab_out(): try: api_sys_control = request.args.get('api_sys') if api_sys_control != api_key_sys: return "EUR 22", 200 conn = sqlite3.connect('data_gc.db') cursor = conn.cursor() cursor.execute(''' SELECT id, name, phone, email, vk_id, chat_id, ws_st, ws_stop, web_st, fin_prog, b_city, b_fin, b_ban, b_ign, b_baners, b_butt, b_mess, orders, curator, bonus, shop_status, answers, quiz, kassa, gc_url, key_pr, n_con, canal, data_on, data_t, utm_source, utm_medium, utm_campaign, utm_term, utm_content, gcpc FROM contacts ''') contacts = cursor.fetchall() conn.close() contacts_json = [{ 'id': contact[0], 'name': contact[1], 'phone': contact[2], 'email': contact[3], 'vk_id': contact[4], 'chat_id': contact[5], 'ws_st': contact[6], 'ws_stop': contact[7], 'web_st': contact[8], 'fin_prog': contact[9], 'b_city': contact[10], 'b_fin': contact[11], 'b_ban': contact[12], 'b_ign': contact[13], 'b_baners': contact[14], 'b_butt': contact[15], 'b_mess': contact[16], 'orders': contact[17], 'curator': contact[18], 'bonus': contact[19], 'shop_status': contact[20], 'answers': contact[21], 'quiz': contact[22], 'kassa': contact[23], 'gc_url': contact[24], 'key_pr': contact[25], 'n_con': contact[26], 'canal': contact[27],'data_on': contact[28], 'data_t': contact[29],'utm_source': contact[30], 'utm_medium': contact[31], 'utm_campaign': contact[32], 'utm_term': contact[33], 'utm_content': contact[34], 'gcpc': contact[34] } for contact in contacts] return jsonify(contacts_json), 200 except Exception as e: error_message = f"Error getting data from data_gc: {e}" print(error_message) return error_message, 500 # Поднимаем страницу обновления базы @app.route('/biz_v', methods=['GET']) def biz_v(): api_sys_control = request.args.get('api_sys') if api_sys_control != api_key_sys: return "EUR 22", 200 return render_template('biz_v.html') # ОБНОВЛЯЕМ CSV-файла DATABASE2 = 'data_gc.db' def parse_csv_data(data): parsed_data = [] for item in data: for key, value in item.items(): headers = key.split(';') row = value.split(';') parsed_data.append(dict(zip(headers, row))) return parsed_data def insert_data(data, verify_phone, add_curator): global current_curator_index with sqlite3.connect(DATABASE2) as conn: cursor = conn.cursor() for row in data: name = row.get('Name', '') phone = row.get('Phone', '').lstrip('+') email = row.get('Email', '') data_t = row.get('Date', '').strip('"') cursor.execute("SELECT 1 FROM contacts WHERE email = ? OR phone = ?", (email, phone)) user_exists = cursor.fetchone() if user_exists: print(f"User with email {email} or phone {phone} already exists. Skipping insert.") continue if add_curator == "1": curator = curators[current_curator_index] current_curator_index = (current_curator_index + 1) % len(curators) else: curator = row.get('curator', '') if verify_phone == "1": ws_st = verify_phone_number(phone) else: ws_st = row.get('ws_st', '') columns = ['name', 'phone', 'email', 'vk_id', 'chat_id', 'ws_st', 'ws_stop', 'web_st', 'fin_prog', 'b_city', 'b_fin', 'b_ban', 'b_ign', 'b_baners', 'b_butt', 'b_mess', 'orders', 'curator', 'bonus', 'shop_status', 'answers', 'quiz', 'kassa', 'gc_url', 'key_pr', 'n_con', 'canal', 'data_on', 'data_t', 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'gcpc'] values = [name, phone, email, row.get('vk_id', ''), row.get('chat_id', ''), ws_st, row.get('ws_stop', ''), row.get('web_st', 0), row.get('fin_prog', 0), row.get('b_city', ''), row.get('b_fin', ''), row.get('b_ban', ''), row.get('b_ign', ''), row.get('b_baners', ''), row.get('b_butt', ''), row.get('b_mess', ''), row.get('orders', ''), curator, row.get('bonus', ''), row.get('shop_status', ''), row.get('answers', ''), row.get('quiz', ''), row.get('kassa', ''), row.get('gc_url', ''), row.get('key_pr', ''), row.get('n_con', ''), row.get('canal', ''), row.get('data_on', ''), row.get('data_t', ''), row.get('utm_source', ''), row.get('utm_medium', ''), row.get('utm_campaign', ''), row.get('utm_term', ''), row.get('utm_content', ''), row.get('gcpc', '')] placeholders = ', '.join(['?' for _ in columns]) columns_str = ', '.join(columns) query = f''' INSERT INTO contacts ({columns_str}) VALUES ({placeholders}) ''' try: cursor.execute(query, values) except Exception as e: print(f"Error inserting row: {row}") print(f"Error message: {str(e)}") conn.rollback() raise conn.commit() @app.route('/upload_csv', methods=['POST']) def upload_csv(): if 'file' not in request.files: return jsonify({"error": "No file part"}), 400 file = request.files['file'] if file.filename == '': return jsonify({"error": "No selected file"}), 400 if file and file.filename.endswith('.csv'): stream = io.StringIO(file.stream.read().decode("UTF8"), newline=None) csv_input = csv.DictReader(stream) data = [row for row in csv_input] parsed_data = parse_csv_data(data) verify_phone = request.form.get('verify_phone', '0') add_curator = request.form.get('add_curator', '0') print(f"Verify Phone: {verify_phone}") print(f"Add Curator: {add_curator}") insert_data(parsed_data, verify_phone, add_curator) return jsonify({"message": "Data uploaded and inserted successfully"}) return jsonify({"error": "Invalid file format"}), 400 # ОБНОВЛЯЕМ JSON-файла DATABASE = 'data_gc.db' # Функция для очистки номера телефона def clean_phone_number_j(phone_number): return re.sub(r'\D', '', phone_number) # Функция для вставки данных в базу данных def insert_data_j(data): conn = sqlite3.connect(DATABASE) # Подключаемся к базе данных cursor = conn.cursor() for row in data: name = row.get('name', '') phone = row.get('phone', '').lstrip('+') email = row.get('email', '') data_t = row.get('data_t', '').strip('"') # Очистка номера телефона phone = clean_phone_number_j(phone) cursor.execute("SELECT 1 FROM contacts WHERE email = ? OR phone = ?", (email, phone)) user_exists = cursor.fetchone() if user_exists: print(f"User with email {email} or phone {phone} already exists. Skipping insert.") continue columns = ['name', 'phone', 'email', 'vk_id', 'chat_id', 'ws_st', 'ws_stop', 'web_st', 'fin_prog', 'b_city', 'b_fin', 'b_ban', 'b_ign', 'b_baners', 'b_butt', 'b_mess', 'orders', 'curator', 'bonus', 'shop_status', 'answers', 'quiz', 'kassa', 'gc_url', 'key_pr', 'n_con', 'canal', 'data_on', 'data_t', 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'gcpc'] values = [name, phone, email, row.get('vk_id', ''), row.get('chat_id', ''), row.get('ws_st', ''), row.get('ws_stop', ''), row.get('web_st', 0), row.get('fin_prog', 0), row.get('b_city', ''), row.get('b_fin', ''), row.get('b_ban', ''), row.get('b_ign', ''), row.get('b_baners', ''), row.get('b_butt', ''), row.get('b_mess', ''), row.get('orders', ''), row.get('curator', ''), row.get('bonus', ''), row.get('shop_status', ''), row.get('answers', ''), row.get('quiz', ''), row.get('kassa', ''), row.get('gc_url', ''), row.get('key_pr', ''), row.get('n_con', ''), row.get('canal', ''), row.get('data_on', ''), row.get('data_t', ''), row.get('utm_source', ''), row.get('utm_medium', ''), row.get('utm_campaign', ''), row.get('utm_term', ''), row.get('utm_content', ''), row.get('gcpc', '')] placeholders = ', '.join(['?' for _ in columns]) columns_str = ', '.join(columns) query = f''' INSERT INTO contacts ({columns_str}) VALUES ({placeholders}) ''' try: cursor.execute(query, values) except Exception as e: print(f"Error inserting row: {row}") print(f"Error message: {str(e)}") conn.rollback() continue conn.commit() conn.close() # Маршрут для загрузки JSON-файла @app.route('/upload_json', methods=['POST']) def upload_json(): if 'file' not in request.files: return jsonify({"error": "No file part"}), 400 file = request.files['file'] if file.filename == '': return jsonify({"error": "No selected file"}), 400 if file and file.filename.endswith('.json'): data = json.load(file) insert_data_j(data) return jsonify({"message": "Data uploaded and inserted successfully"}) return jsonify({"error": "Invalid file format"}), 400 # ОБНОВЛЯЕМ Бизон 365 DATABASE_NAME = 'data_gc.db' def update_or_insert_user(db_name, user_data, mapping_template): conn = sqlite3.connect(db_name) cursor = conn.cursor() # Получение email пользователя из данных email = user_data.get('email') if not email: logging.error(f"User data missing email: {user_data}") return logging.debug(f"Processing user with email: {email}") # Проверка существования пользователя в базе данных по email cursor.execute("SELECT web_st, ws_st, b_mess FROM contacts WHERE email = ?", (email,)) user = cursor.fetchone() logging.debug(f"User found: {user}") # Вынесение увеличения значения web_st в отдельный блок web_st_value = 1 # Инициализация значения web_st if user: # Проверка текущего значения web_st и его инкрементация current_web_st = user[0] if user[0] is not None and user[0] != "" else 0 web_st_value = int(current_web_st) + 1 logging.debug(f"Calculated web_st_value: {web_st_value}") # Обновление значения web_st cursor.execute("UPDATE contacts SET web_st = ? WHERE email = ?", (web_st_value, email)) conn.commit() conn.close() logging.debug(f"User {email} web_st updated to {web_st_value}") else: conn.close() logging.debug(f"User {email} not found, proceeding with insert") # Открываем соединение снова для остальных операций conn = sqlite3.connect(db_name) cursor = conn.cursor() # Преобразование данных пользователя на основе шаблона сопоставления transformed_data = {} for json_key, db_column in mapping_template.items(): value = user_data.get(json_key, "") if isinstance(value, list): # Проверяем тип элементов списка if all(isinstance(item, str) for item in value): transformed_data[db_column] = "; ".join(value) # Сохраняем сообщения в строку else: logging.error(f"Expected list of strings for key {json_key}, but got: {value}") transformed_data[db_column] = "" else: transformed_data[db_column] = str(value) logging.debug(f"Transformed data: {transformed_data}") # Заполнение обязательных полей значениями по умолчанию required_fields = [ "vk_id", "chat_id", "ws_st", "ws_stop", "web_st", "fin_prog", "b_city", "b_fin", "b_ban", "b_ign", "b_baners", "b_butt", "b_mess", "orders", "curator", "bonus", "shop_status", "answers", "quiz", "kassa", "gc_url", "key_pr", "n_con", "canal", "data_on", "data_t", 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'gcpc' ] for field in required_fields: if field not in transformed_data: transformed_data[field] = "" logging.debug(f"Transformed data after adding required fields: {transformed_data}") # Обработка номера телефона, если он есть if 'phone' in user_data: phone = user_data['phone'] if phone.startswith('+'): phone = phone[1:] transformed_data['phone'] = phone logging.debug(f"Transformed data after phone processing: {transformed_data}") # Добавление значения web_st в данные для вставки transformed_data['web_st'] = web_st_value # Обновление данных пользователя в базе данных if user: # Объединение новых сообщений с существующими if 'b_mess' in transformed_data and user[2]: transformed_data['b_mess'] = user[2] + "; " + transformed_data['b_mess'] update_query = "UPDATE contacts SET " update_values = [] for column, value in transformed_data.items(): if column != 'ws_st' or not user[1]: # Проверка на наличие существующего ws_st update_query += f"{column} = ?, " update_values.append(value) update_query = update_query.rstrip(", ") + " WHERE email = ?" update_values.append(email) logging.debug(f"Update query: {update_query} with values: {update_values}") cursor.execute(update_query, update_values) else: columns = ', '.join(transformed_data.keys()) placeholders = ', '.join('?' for _ in transformed_data) insert_query = f"INSERT INTO contacts ({columns}) VALUES ({placeholders})" insert_values = list(transformed_data.values()) logging.debug(f"Insert query: {insert_query} with values: {insert_values}") cursor.execute(insert_query, insert_values) # Подтверждение изменений и закрытие соединения conn.commit() conn.close() logging.debug(f"User with email {email} processed successfully") @app.route('/send_request', methods=['POST']) def send_request(): token = request.form.get('token') min_date = request.form.get('minDate') type = request.form.get('type') url = f'https://online.bizon365.ru/api/v1/webinars/reports/getlist?minDate={min_date}&limit=100&type={type}' response = requests.get(url, headers={'X-Token': token}) if response.status_code == 200: data = response.json() webinar_ids = [item['webinarId'] for item in data['list']] return jsonify(webinar_ids) else: return jsonify({'error': 'Failed to fetch data from the API'}), response.status_code @app.route('/send_get_request', methods=['GET']) def send_get_request(): token = request.args.get('token') webinarId = request.args.get('webinarId') url = f'https://online.bizon365.ru/api/v1/webinars/reports/get?webinarId={webinarId}' try: response = requests.get(url, headers={'X-Token': token}) response.raise_for_status() # Проверка на ошибки HTTP data = response.json() # Убедитесь, что report существует в данных if data is None or 'report' not in data: return jsonify({'error': 'No report data found'}), 500 report = data.get('report', {}) messages = data.get('messages', {}) # Проверка на None перед использованием if report is None: return jsonify({'error': 'No report data found in the response'}), 500 report_json_str = report.get('report', '{}') try: report_json = json.loads(report_json_str) except json.JSONDecodeError: report_json = {} messages_json_str = report.get('messages', '{}') try: messages_json = json.loads(messages_json_str) except json.JSONDecodeError: messages_json = {} users_meta = report_json.get('usersMeta', {}) processed_emails = set() for user_id, user_data in users_meta.items(): user_messages = messages_json.get(user_id, []) user_data['messages'] = user_messages email = user_data.get('email') if email and email not in processed_emails: update_or_insert_user(DATABASE_NAME, user_data, mapping_template) processed_emails.add(email) return jsonify({'status': 'User data saved successfully'}) except requests.exceptions.RequestException as e: return jsonify({'error': f'API request failed: {str(e)}'}), 500 @app.route('/webhookbz', methods=['POST']) def webhookbz(): api_sys_control = request.args.get('api_sys') if api_sys_control != api_key_sys: return "EUR 22", 200 data = request.json webinar_id = data.get('webinarId') if not webinar_id: return jsonify({'error': 'webinarId is required'}), 400 url = f'https://online.bizon365.ru/api/v1/webinars/reports/get?webinarId={webinar_id}' response = requests.get(url, headers={'X-Token': api_key_sys}) if response.status_code == 200: data = response.json() report = data.get('report', {}) messages = data.get('messages', {}) report_json_str = report.get('report', '{}') try: report_json = json.loads(report_json_str) except json.JSONDecodeError: report_json = {} messages_json_str = report.get('messages', '{}') try: messages_json = json.loads(messages_json_str) except json.JSONDecodeError: messages_json = {} users_meta = report_json.get('usersMeta', {}) processed_emails = set() for user_id, user_data in users_meta.items(): user_messages = messages_json.get(user_id, []) user_data['messages'] = user_messages email = user_data.get('email') if email and email not in processed_emails: update_or_insert_user(DATABASE_NAME, user_data, mapping_template) processed_emails.add(email) return jsonify({'status': 'User data saved successfully'}) else: return jsonify({'error': 'Failed to fetch data from the API'}), response.status_code # Отправка в НС1 в раб. дни нужно поправить нас групп @app.route('/add_ns', methods=['GET']) def handle_in1(): name = request.args.get('name') email = request.args.get('email') phone = request.args.get('phone') base_url = 'https://api.notisend.ru/v1' token = request.args.get('token') list_id = request.args.get('list_id') phone_id = request.args.get('phone_id') name_id = request.args.get('name_id') # Проверка наличия всех необходимых параметров if not all([name, email, phone, token, list_id, phone_id, name_id]): return jsonify({'error': 'Missing required parameters'}), 400 # Отправляем запросы в три разных места response_ns = send_ns(base_url, token, list_id, email, phone, name, phone_id, name_id) # Возвращаем список ответов return jsonify({'responses': [response_ns]}) @app.route('/ns_info', methods=['GET']) def ns_info(): return render_template('ns_info.html') @app.route('/api/group//parameters', methods=['GET']) def get_group_parameters(group_id): api_token = request.args.get('apiToken') if not api_token: return jsonify({'error': 'API Token is required'}), 400 url = f'https://api.notisend.ru/v1/email/lists/{group_id}/parameters' headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {api_token}' } try: response = requests.get(url, headers=headers) response.raise_for_status() data = response.json() return jsonify(data) except requests.RequestException as e: return jsonify({'error': str(e)}), 500 @app.route('/upload', methods=['POST']) def upload_file(): # Получаем ключ авторизации из запроса api_sys_control = request.form.get('api_key_sys') # Проверка ключа авторизации if api_sys_control != api_key_sys: return jsonify({"error": "Unauthorized access"}), 403 # Проверяем, что файл был отправлен if 'file' not in request.files: return jsonify({"error": "No file part"}), 400 file = request.files['file'] # Если пользователь не выбрал файл, браузер может отправить пустой файл без имени if file.filename == '': return jsonify({"error": "No selected file"}), 400 # Генерация уникального имени файла unique_filename = str(uuid.uuid4()) + os.path.splitext(file.filename)[1] save_path = os.path.join(UPLOAD_FOLDER, unique_filename) file.save(save_path) # Возвращаем полный URL загруженного файла с протоколом https full_url = request.url_root.replace('http://', 'https://') + 'uploads/' + unique_filename return jsonify({"message": "File uploaded successfully", "url": full_url}), 200 @app.route('/uploads/', methods=['GET']) def uploaded_file(filename): return send_from_directory(UPLOAD_FOLDER, filename) @app.route('/up_fa', methods=['GET']) def up_fa(): return render_template('up_fa.html') @app.route('/upload_vk', methods=['POST']) def upload_file_vk(): # Получаем ключ авторизации из запроса api_sys_control = request.form.get('api_key_sys') # Проверка ключа авторизации if api_sys_control != api_key_sys: return jsonify({"error": "Unauthorized access"}), 403 # Проверяем, что файл был отправлен if 'file' not in request.files: return jsonify({"error": "No file part"}), 400 file = request.files['file'] # Если пользователь не выбрал файл, браузер может отправить пустой файл без имени if file.filename == '': return jsonify({"error": "No selected file"}), 400 # Генерация уникального имени файла unique_filename = str(uuid.uuid4()) + os.path.splitext(file.filename)[1] save_path = os.path.join('static', unique_filename) file.save(save_path) # Возвращаем полный URL загруженного файла с протоколом https full_url = request.url_root.replace('http://', 'https://') + 'uploads_vk/' + unique_filename return jsonify({"message": "File uploaded successfully", "url": full_url}), 200 @app.route('/uploads_vk/', methods=['GET']) def uploaded_file_vk(filename): return send_from_directory('static', filename) @app.route('/up_fa_vk', methods=['GET']) def up_fa_vk(): return render_template('up_fa_vk.html') @app.route('/up_page', methods=['POST']) def upload_page(): # Получаем ключ авторизации из запроса api_sys_control = request.form.get('api_key_sys') # Проверка ключа авторизации if api_sys_control != api_key_sys: return jsonify({"error": "Unauthorized access"}), 403 if 'file' not in request.files: return jsonify({"error": "No file part"}), 400 file = request.files['file'] if file.filename == '': return jsonify({"error": "No selected file"}), 400 filename = request.form.get('filename') if not filename: return jsonify({"error": "Filename is required"}), 400 save_path = os.path.join(HTML_FOLDER, filename + '.html') file.save(save_path) # Возвращаем полный URL загруженного файла с протоколом https full_url = request.url_root.replace('http://', 'https://') + filename return jsonify({"message": "Page uploaded successfully", "url": full_url}), 200 @app.route('/', methods=['GET']) def serve_html(filename): if not filename.endswith('.html'): filename += '.html' return send_from_directory(HTML_FOLDER, filename) @app.route('/up_page', methods=['GET']) def up_page(): return render_template('up_page.html') # Дублированный маршрут для загрузки страницы через POST-запрос @app.route('/up_page_vk', methods=['POST']) def upload_page_vk(): # Получаем ключ авторизации из запроса api_sys_control = request.form.get('api_key_sys') # Проверка ключа авторизации if api_sys_control != api_key_sys: return jsonify({"error": "Unauthorized access"}), 403 if 'file' not in request.files: return jsonify({"error": "No file part"}), 400 file = request.files['file'] if file.filename == '': return jsonify({"error": "No selected file"}), 400 filename = request.form.get('filename') if not filename: return jsonify({"error": "Filename is required"}), 400 save_path = os.path.join(HTML_FOLDER_VK, filename + '.html') file.save(save_path) # Возвращаем полный URL загруженного файла с протоколом https full_url = request.url_root.replace('http://', 'https://') + 'page_vk/' + filename return jsonify({"message": "Page uploaded successfully", "url": full_url}), 200 # Дублированный маршрут для обслуживания загруженных страниц @app.route('/page_vk/', methods=['GET']) def serve_html_vk(filename): try: # Получаем параметры из GET-запроса apps_id = request.args.get('apps_id') in_url = request.args.get('fullUrl') # Проверяем, есть ли параметры if not apps_id or not in_url: return jsonify({"error": "Access denied"}), 400 # Декодируем URL перед парсингом decoded_url = unquote(in_url) # Получаем базовую часть URL (до знака вопроса) parsed_url = urlparse(decoded_url) base_url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}" logging.debug(f"Decoded URL: {decoded_url}") logging.debug(f"Parsed base URL: {base_url}") # Парсим параметры из декодированного URL query_params = dict(parse_qsl(parsed_url.query, keep_blank_values=True)) # Добавляем все возможные параметры, даже если они пустые all_params = { 'vk_access_token_settings': query_params.get('vk_access_token_settings', ''), 'vk_app_id': query_params.get('vk_app_id', ''), 'vk_are_notifications_enabled': query_params.get('vk_are_notifications_enabled', ''), 'vk_is_app_user': query_params.get('vk_is_app_user', ''), 'vk_is_favorite': query_params.get('vk_is_favorite', ''), 'vk_language': query_params.get('vk_language', ''), 'vk_platform': query_params.get('vk_platform', ''), 'vk_ref': query_params.get('vk_ref', ''), 'vk_ts': query_params.get('vk_ts', ''), 'vk_user_id': query_params.get('vk_user_id', ''), 'vk_are_notifications_enabled': query_params.get('vk_are_notifications_enabled', ''), 'vk_chat_id': query_params.get('vk_chat_id', ''), 'vk_group_id': query_params.get('vk_group_id', ''), 'vk_has_profile_button': query_params.get('vk_has_profile_button', ''), 'vk_is_favorite': query_params.get('vk_is_favorite', ''), 'vk_is_recommended': query_params.get('vk_is_recommended', ''), 'vk_is_play_machine': query_params.get('vk_is_play_machine', ''), 'vk_is_widescreen': query_params.get('vk_is_widescreen', ''), 'vk_profile_id': query_params.get('vk_profile_id', ''), 'vk_testing_group_id': query_params.get('vk_testing_group_id', ''), 'vk_viewer_group_role': query_params.get('vk_viewer_group_role', ''), 'sign': query_params.get('sign', '') } # Очищаем параметры от пустых значений, кроме vk_access_token_settings cleaned_params = {key: value for key, value in all_params.items() if value or key == 'vk_access_token_settings'} # Формирование URL с использованием f-строк fullUrl = f"{base_url}?{urlencode(cleaned_params)}" logging.debug(f"Received params: fullUrl={fullUrl}") # Преобразуем строку в JSON try: api_key_apps_vk_dict = json.loads(api_key_apps_vk) except json.JSONDecodeError as e: logging.error(f"Error decoding JSON: {e}") return jsonify({"status": "invalid"}), 200 logging.debug(f"api_key_apps_vk_dict: {api_key_apps_vk_dict}") # Проверка подписи для приложения if str(apps_id) not in api_key_apps_vk_dict: # Приводим apps_id к строке logging.error("Invalid apps_id") return jsonify({"error": "Invalid apps_id"}), 400 secret = api_key_apps_vk_dict[str(apps_id)] # Приводим apps_id к строке logging.debug(f"Using secret: {secret}") # Парсим полный URL для получения параметров запроса query_params = dict(parse_qsl(urlparse(fullUrl).query, keep_blank_values=True)) logging.debug(f"Query params for signature check: {query_params}") # Проверяем подпись if not is_valid(query=query_params, secret=secret): logging.error("Invalid signature") return jsonify({"error": "Invalid signature"}), 400 # Если верификация прошла успешно, отдаём файл if not filename.endswith('.html'): filename += '.html' return send_from_directory(HTML_FOLDER_VK, filename) except Exception as e: logging.error(f"An error occurred: {str(e)}") return jsonify({"error": str(e)}), 500 # Дублированный маршрут для отображения страницы загрузки @app.route('/up_page_vk', methods=['GET']) def up_page_vk(): return render_template('up_page_vk.html') @app.route('/monitor', methods=['GET']) def monitor(): # Получаем информацию о загруженных файлах files = os.listdir(UPLOAD_FOLDER) html_files = os.listdir(HTML_FOLDER) # Получаем информацию о дисковом пространстве total, used, free = shutil.disk_usage("/") # Преобразуем байты в гигабайты для удобства чтения total_gb = total // (2**30) used_gb = used // (2**30) free_gb = free // (2**30) # Получаем информацию об использовании оперативной памяти memory = psutil.virtual_memory() memory_total_gb = memory.total // (2**30) memory_used_gb = memory.used // (2**30) memory_free_gb = memory.free // (2**30) # Получаем информацию о количестве процессоров cpu_count = psutil.cpu_count(logical=True) return render_template('monitor.html', uploaded_files=files, uploaded_html_files=html_files, disk_space={ 'total': f"{total_gb} GB", 'used': f"{used_gb} GB", 'free': f"{free_gb} GB" }, memory_usage={ 'total': f"{memory_total_gb} GB", 'used': f"{memory_used_gb} GB", 'free': f"{memory_free_gb} GB" }, cpu_count=cpu_count) if __name__ == '__main__': app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 7860)))