Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
#!/usr/bin/env python3
|
| 2 |
|
| 3 |
import os
|
| 4 |
from flask import Flask, request, Response, render_template_string, jsonify, redirect, url_for
|
|
@@ -98,10 +97,9 @@ def load_visitor_data():
|
|
| 98 |
|
| 99 |
return visitor_data_cache
|
| 100 |
|
| 101 |
-
def save_visitor_data(
|
| 102 |
with _data_lock:
|
| 103 |
try:
|
| 104 |
-
visitor_data_cache.update(data)
|
| 105 |
with open(DATA_FILE, 'w', encoding='utf-8') as f:
|
| 106 |
json.dump(visitor_data_cache, f, ensure_ascii=False, indent=4)
|
| 107 |
logging.info(f"Visitor data successfully saved to {DATA_FILE}.")
|
|
@@ -1452,7 +1450,7 @@ def verify_data():
|
|
| 1452 |
user_id_to_save = new_user_id
|
| 1453 |
|
| 1454 |
all_data[user_id_to_save] = user_entry
|
| 1455 |
-
save_visitor_data(
|
| 1456 |
return jsonify({"status": "ok", "verified": True, "user_id": user_id_to_save})
|
| 1457 |
else:
|
| 1458 |
return jsonify({"status": "error", "verified": True, "message": "User ID not found"}), 400
|
|
@@ -1481,25 +1479,23 @@ def submit_referral():
|
|
| 1481 |
user['has_been_welcomed'] = True
|
| 1482 |
|
| 1483 |
if referral_code:
|
| 1484 |
-
|
| 1485 |
|
| 1486 |
-
if not
|
| 1487 |
return jsonify({"status": "error", "message": "Промокод не найден."}), 404
|
| 1488 |
|
| 1489 |
-
if
|
| 1490 |
return jsonify({"status": "error", "message": "Нельзя использовать свой промокод."}), 400
|
| 1491 |
|
| 1492 |
-
user['referred_by'] =
|
|
|
|
| 1493 |
if 'referrals' not in referrer: referrer['referrals'] = []
|
| 1494 |
referrer['referrals'].append(user_id)
|
| 1495 |
|
| 1496 |
-
|
| 1497 |
-
all_data[referrer['id']] = referrer
|
| 1498 |
-
save_visitor_data(all_data)
|
| 1499 |
return jsonify({"status": "ok", "message": "Промокод успешно применен!"}), 200
|
| 1500 |
else:
|
| 1501 |
-
|
| 1502 |
-
save_visitor_data(all_data)
|
| 1503 |
return jsonify({"status": "ok", "message": "Добро пожаловать!"}), 200
|
| 1504 |
|
| 1505 |
except Exception as e:
|
|
@@ -1511,14 +1507,12 @@ def admin_panel():
|
|
| 1511 |
all_data = load_visitor_data()
|
| 1512 |
users_list = []
|
| 1513 |
|
| 1514 |
-
# Create a map of user_id to user_name for quick lookup
|
| 1515 |
user_name_map = {uid: f"{ud.get('first_name', '')} {ud.get('last_name', '')}".strip() or f"ID: {uid}" for uid, ud in all_data.items() if uid != "organization_details"}
|
| 1516 |
|
| 1517 |
for user_id, user_data in all_data.items():
|
| 1518 |
if user_id == "organization_details": continue
|
| 1519 |
user_data['id'] = user_id
|
| 1520 |
|
| 1521 |
-
# Add referral info
|
| 1522 |
user_data['referrals_count'] = len(user_data.get('referrals', []))
|
| 1523 |
referrer_id = user_data.get('referred_by')
|
| 1524 |
user_data['referrer_info'] = user_name_map.get(referrer_id, None)
|
|
@@ -1560,7 +1554,7 @@ def add_client():
|
|
| 1560 |
'referral_code': f'PROMO{new_id}', 'referred_by': None, 'referrals': [], 'has_been_welcomed': True
|
| 1561 |
}
|
| 1562 |
all_data[new_id] = new_client
|
| 1563 |
-
save_visitor_data(
|
| 1564 |
return jsonify({"status": "ok", "message": "Client added successfully"}), 201
|
| 1565 |
except Exception as e:
|
| 1566 |
logging.exception("Error in /admin/add_client endpoint")
|
|
@@ -1598,8 +1592,7 @@ def add_transaction():
|
|
| 1598 |
if add_debt_amount > 0: user['debt_history'].append({"type": "accrual", "amount": round(add_debt_amount, 2), "description": "Добавление долга", "date": now_iso, "date_str": now_str})
|
| 1599 |
if repay_debt_amount > 0: user['debt_history'].append({"type": "payment", "amount": round(repay_debt_amount, 2), "description": "Погашение долга", "date": now_iso, "date_str": now_str})
|
| 1600 |
|
| 1601 |
-
|
| 1602 |
-
save_visitor_data(all_data)
|
| 1603 |
return jsonify({"status": "ok", "message": "Transaction successful", "new_balance": user['bonuses'], "new_debt": user['debts']}), 200
|
| 1604 |
except Exception as e:
|
| 1605 |
logging.exception("Error in /admin/add_transaction endpoint")
|
|
@@ -1630,8 +1623,7 @@ def add_invoice():
|
|
| 1630 |
if 'invoices' not in user: user['invoices'] = []
|
| 1631 |
user['invoices'].append(new_invoice)
|
| 1632 |
|
| 1633 |
-
|
| 1634 |
-
save_visitor_data(all_data)
|
| 1635 |
return jsonify({"status": "ok", "message": "Invoice added successfully", "invoice_id": invoice_id}), 200
|
| 1636 |
except Exception as e:
|
| 1637 |
logging.exception("Error in /admin/add_invoice endpoint")
|
|
@@ -1654,8 +1646,7 @@ def delete_invoice():
|
|
| 1654 |
user['invoices'] = [inv for inv in user['invoices'] if inv.get('invoice_id') != invoice_id]
|
| 1655 |
if len(user['invoices']) == original_count: return jsonify({"status": "error", "message": "Invoice not found for this user"}), 404
|
| 1656 |
|
| 1657 |
-
|
| 1658 |
-
save_visitor_data(all_data)
|
| 1659 |
return jsonify({"status": "ok", "message": "Invoice deleted successfully"}), 200
|
| 1660 |
except Exception as e:
|
| 1661 |
logging.exception("Error in /admin/delete_invoice endpoint")
|
|
@@ -1665,15 +1656,21 @@ def delete_invoice():
|
|
| 1665 |
def delete_client():
|
| 1666 |
try:
|
| 1667 |
user_id = str(request.get_json().get('user_id'))
|
| 1668 |
-
if not user_id:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1669 |
|
| 1670 |
-
with _data_lock:
|
| 1671 |
-
all_data = load_visitor_data()
|
| 1672 |
-
if user_id not in all_data: return jsonify({"status": "error", "message": "User not found"}), 404
|
| 1673 |
-
if all_data[user_id].get('telegram_id') is not None: return jsonify({"status": "error", "message": "Cannot delete a Telegram-linked user"}), 403
|
| 1674 |
-
|
| 1675 |
-
del all_data[user_id]
|
| 1676 |
-
save_visitor_data(all_data)
|
| 1677 |
return jsonify({"status": "ok", "message": "Client deleted successfully"}), 200
|
| 1678 |
except Exception as e:
|
| 1679 |
logging.exception("Error in /admin/delete_client endpoint")
|
|
@@ -1699,7 +1696,7 @@ def save_organization_details():
|
|
| 1699 |
}
|
| 1700 |
all_data = load_visitor_data()
|
| 1701 |
all_data['organization_details'] = new_org_details
|
| 1702 |
-
save_visitor_data(
|
| 1703 |
return jsonify({"status": "ok", "message": "Organization details saved successfully"}), 200
|
| 1704 |
except Exception as e:
|
| 1705 |
logging.exception("Error saving organization details")
|
|
@@ -1708,16 +1705,27 @@ def save_organization_details():
|
|
| 1708 |
if __name__ == '__main__':
|
| 1709 |
print("--- BONUS SYSTEM SERVER ---")
|
| 1710 |
print(f"Server starting on http://{HOST}:{PORT}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1711 |
if not HF_TOKEN_READ or not HF_TOKEN_WRITE:
|
| 1712 |
print("WARNING: Hugging Face token(s) not set. Backup/restore functionality will be limited.")
|
| 1713 |
-
|
| 1714 |
-
print("Attempting initial data download from Hugging Face...")
|
| 1715 |
-
download_data_from_hf()
|
| 1716 |
-
load_visitor_data()
|
| 1717 |
print("WARNING: The /admin route is NOT protected. Implement proper authentication for production.")
|
|
|
|
| 1718 |
if HF_TOKEN_WRITE:
|
| 1719 |
backup_thread = threading.Thread(target=periodic_backup, daemon=True)
|
| 1720 |
backup_thread.start()
|
| 1721 |
print("Periodic backup thread started (every hour).")
|
|
|
|
| 1722 |
print("--- Server Ready ---")
|
| 1723 |
-
app.run(host=HOST, port=PORT, debug=False)
|
|
|
|
|
|
|
| 1 |
|
| 2 |
import os
|
| 3 |
from flask import Flask, request, Response, render_template_string, jsonify, redirect, url_for
|
|
|
|
| 97 |
|
| 98 |
return visitor_data_cache
|
| 99 |
|
| 100 |
+
def save_visitor_data():
|
| 101 |
with _data_lock:
|
| 102 |
try:
|
|
|
|
| 103 |
with open(DATA_FILE, 'w', encoding='utf-8') as f:
|
| 104 |
json.dump(visitor_data_cache, f, ensure_ascii=False, indent=4)
|
| 105 |
logging.info(f"Visitor data successfully saved to {DATA_FILE}.")
|
|
|
|
| 1450 |
user_id_to_save = new_user_id
|
| 1451 |
|
| 1452 |
all_data[user_id_to_save] = user_entry
|
| 1453 |
+
save_visitor_data()
|
| 1454 |
return jsonify({"status": "ok", "verified": True, "user_id": user_id_to_save})
|
| 1455 |
else:
|
| 1456 |
return jsonify({"status": "error", "verified": True, "message": "User ID not found"}), 400
|
|
|
|
| 1479 |
user['has_been_welcomed'] = True
|
| 1480 |
|
| 1481 |
if referral_code:
|
| 1482 |
+
referrer_id = next((u_id for u_id, u in all_data.items() if u_id != "organization_details" and u.get('referral_code') == referral_code), None)
|
| 1483 |
|
| 1484 |
+
if not referrer_id:
|
| 1485 |
return jsonify({"status": "error", "message": "Промокод не найден."}), 404
|
| 1486 |
|
| 1487 |
+
if referrer_id == user_id:
|
| 1488 |
return jsonify({"status": "error", "message": "Нельзя использовать свой промокод."}), 400
|
| 1489 |
|
| 1490 |
+
user['referred_by'] = referrer_id
|
| 1491 |
+
referrer = all_data[referrer_id]
|
| 1492 |
if 'referrals' not in referrer: referrer['referrals'] = []
|
| 1493 |
referrer['referrals'].append(user_id)
|
| 1494 |
|
| 1495 |
+
save_visitor_data()
|
|
|
|
|
|
|
| 1496 |
return jsonify({"status": "ok", "message": "Промокод успешно применен!"}), 200
|
| 1497 |
else:
|
| 1498 |
+
save_visitor_data()
|
|
|
|
| 1499 |
return jsonify({"status": "ok", "message": "Добро пожаловать!"}), 200
|
| 1500 |
|
| 1501 |
except Exception as e:
|
|
|
|
| 1507 |
all_data = load_visitor_data()
|
| 1508 |
users_list = []
|
| 1509 |
|
|
|
|
| 1510 |
user_name_map = {uid: f"{ud.get('first_name', '')} {ud.get('last_name', '')}".strip() or f"ID: {uid}" for uid, ud in all_data.items() if uid != "organization_details"}
|
| 1511 |
|
| 1512 |
for user_id, user_data in all_data.items():
|
| 1513 |
if user_id == "organization_details": continue
|
| 1514 |
user_data['id'] = user_id
|
| 1515 |
|
|
|
|
| 1516 |
user_data['referrals_count'] = len(user_data.get('referrals', []))
|
| 1517 |
referrer_id = user_data.get('referred_by')
|
| 1518 |
user_data['referrer_info'] = user_name_map.get(referrer_id, None)
|
|
|
|
| 1554 |
'referral_code': f'PROMO{new_id}', 'referred_by': None, 'referrals': [], 'has_been_welcomed': True
|
| 1555 |
}
|
| 1556 |
all_data[new_id] = new_client
|
| 1557 |
+
save_visitor_data()
|
| 1558 |
return jsonify({"status": "ok", "message": "Client added successfully"}), 201
|
| 1559 |
except Exception as e:
|
| 1560 |
logging.exception("Error in /admin/add_client endpoint")
|
|
|
|
| 1592 |
if add_debt_amount > 0: user['debt_history'].append({"type": "accrual", "amount": round(add_debt_amount, 2), "description": "Добавление долга", "date": now_iso, "date_str": now_str})
|
| 1593 |
if repay_debt_amount > 0: user['debt_history'].append({"type": "payment", "amount": round(repay_debt_amount, 2), "description": "Погашение долга", "date": now_iso, "date_str": now_str})
|
| 1594 |
|
| 1595 |
+
save_visitor_data()
|
|
|
|
| 1596 |
return jsonify({"status": "ok", "message": "Transaction successful", "new_balance": user['bonuses'], "new_debt": user['debts']}), 200
|
| 1597 |
except Exception as e:
|
| 1598 |
logging.exception("Error in /admin/add_transaction endpoint")
|
|
|
|
| 1623 |
if 'invoices' not in user: user['invoices'] = []
|
| 1624 |
user['invoices'].append(new_invoice)
|
| 1625 |
|
| 1626 |
+
save_visitor_data()
|
|
|
|
| 1627 |
return jsonify({"status": "ok", "message": "Invoice added successfully", "invoice_id": invoice_id}), 200
|
| 1628 |
except Exception as e:
|
| 1629 |
logging.exception("Error in /admin/add_invoice endpoint")
|
|
|
|
| 1646 |
user['invoices'] = [inv for inv in user['invoices'] if inv.get('invoice_id') != invoice_id]
|
| 1647 |
if len(user['invoices']) == original_count: return jsonify({"status": "error", "message": "Invoice not found for this user"}), 404
|
| 1648 |
|
| 1649 |
+
save_visitor_data()
|
|
|
|
| 1650 |
return jsonify({"status": "ok", "message": "Invoice deleted successfully"}), 200
|
| 1651 |
except Exception as e:
|
| 1652 |
logging.exception("Error in /admin/delete_invoice endpoint")
|
|
|
|
| 1656 |
def delete_client():
|
| 1657 |
try:
|
| 1658 |
user_id = str(request.get_json().get('user_id'))
|
| 1659 |
+
if not user_id:
|
| 1660 |
+
return jsonify({"status": "error", "message": "User ID is required"}), 400
|
| 1661 |
+
|
| 1662 |
+
all_data = load_visitor_data()
|
| 1663 |
+
|
| 1664 |
+
if user_id not in all_data:
|
| 1665 |
+
return jsonify({"status": "error", "message": "User not found"}), 404
|
| 1666 |
+
|
| 1667 |
+
if all_data[user_id].get('telegram_id') is not None:
|
| 1668 |
+
return jsonify({"status": "error", "message": "Cannot delete a Telegram-linked user"}), 403
|
| 1669 |
+
|
| 1670 |
+
del all_data[user_id]
|
| 1671 |
+
|
| 1672 |
+
save_visitor_data()
|
| 1673 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1674 |
return jsonify({"status": "ok", "message": "Client deleted successfully"}), 200
|
| 1675 |
except Exception as e:
|
| 1676 |
logging.exception("Error in /admin/delete_client endpoint")
|
|
|
|
| 1696 |
}
|
| 1697 |
all_data = load_visitor_data()
|
| 1698 |
all_data['organization_details'] = new_org_details
|
| 1699 |
+
save_visitor_data()
|
| 1700 |
return jsonify({"status": "ok", "message": "Organization details saved successfully"}), 200
|
| 1701 |
except Exception as e:
|
| 1702 |
logging.exception("Error saving organization details")
|
|
|
|
| 1705 |
if __name__ == '__main__':
|
| 1706 |
print("--- BONUS SYSTEM SERVER ---")
|
| 1707 |
print(f"Server starting on http://{HOST}:{PORT}")
|
| 1708 |
+
|
| 1709 |
+
print("Loading local data file...")
|
| 1710 |
+
load_visitor_data()
|
| 1711 |
+
|
| 1712 |
+
if (not visitor_data_cache or len(visitor_data_cache) <= 1) and HF_TOKEN_READ:
|
| 1713 |
+
print("Local data not found or empty. Attempting to restore from Hugging Face backup...")
|
| 1714 |
+
download_data_from_hf()
|
| 1715 |
+
elif not visitor_data_cache or len(visitor_data_cache) <= 1:
|
| 1716 |
+
print("Starting with a fresh, empty database.")
|
| 1717 |
+
else:
|
| 1718 |
+
print("Successfully loaded data from local file.")
|
| 1719 |
+
|
| 1720 |
if not HF_TOKEN_READ or not HF_TOKEN_WRITE:
|
| 1721 |
print("WARNING: Hugging Face token(s) not set. Backup/restore functionality will be limited.")
|
| 1722 |
+
|
|
|
|
|
|
|
|
|
|
| 1723 |
print("WARNING: The /admin route is NOT protected. Implement proper authentication for production.")
|
| 1724 |
+
|
| 1725 |
if HF_TOKEN_WRITE:
|
| 1726 |
backup_thread = threading.Thread(target=periodic_backup, daemon=True)
|
| 1727 |
backup_thread.start()
|
| 1728 |
print("Periodic backup thread started (every hour).")
|
| 1729 |
+
|
| 1730 |
print("--- Server Ready ---")
|
| 1731 |
+
app.run(host=HOST, port=PORT, debug=False)
|