fix: dynamic days remaining via tariff_end_at timestamp; auto-downgrade when expired

This commit is contained in:
SashegDev
2026-05-23 14:27:43 +00:00
parent dc6d1212d6
commit 09f1b7b261
+34 -16
View File
@@ -81,6 +81,12 @@ def clear_cache(sub_id: str = None):
_links_cache.clear()
_traffic_cache.clear()
def get_remaining_days(user: dict) -> int:
end = user.get("tariff_end_at", 0)
if end:
return max(0, (end - int(time.time())) // 86400)
return user.get("tariff_days_remaining", 0)
def load_json(path: str, default: dict) -> dict:
if os.path.exists(path):
try:
@@ -107,12 +113,19 @@ def init_db():
tier TEXT DEFAULT 'free',
tariff_days_bought INTEGER DEFAULT 0,
tariff_days_remaining INTEGER DEFAULT 0,
tariff_end_at INTEGER DEFAULT 0,
total_paid_rubles INTEGER DEFAULT 0,
traffic_limit_gb INTEGER DEFAULT 0,
is_active BOOLEAN DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
try:
conn.execute("ALTER TABLE users ADD COLUMN tariff_end_at INTEGER DEFAULT 0")
except:
pass
now = int(time.time())
conn.execute("UPDATE users SET tariff_end_at = ? + tariff_days_remaining * 86400 WHERE tariff_end_at = 0 AND tariff_days_remaining > 0", (now,))
conn.commit()
conn.close()
@@ -376,7 +389,7 @@ VALUES (?, ?, 'free', 0, 0, 0, 0, 1)
user = dict(user)
if user['tier'] == 'paid' and user['tariff_days_remaining'] <= 0:
if user['tier'] == 'paid' and get_remaining_days(user) <= 0:
conn.execute("UPDATE users SET tier = 'free' WHERE id = ?", (user['id'],))
conn.commit()
user['tier'] = 'free'
@@ -554,8 +567,9 @@ async def get_subscription(request: Request, subscription_id: str, format: str =
lines.append(f"#support-url: {support_url}")
expire_ts = 0
if user.get("tariff_days_remaining", 0) > 0:
expire_ts = int((datetime.now() + timedelta(days=user["tariff_days_remaining"])).timestamp())
rem_days = get_remaining_days(user)
if rem_days > 0:
expire_ts = int((datetime.now() + timedelta(days=rem_days)).timestamp())
lines.append("#sub-expire: 1")
if support_url:
lines.append(f"#sub-expire-button-link: {support_url}")
@@ -624,7 +638,7 @@ async def get_web_page(subscription_id: str):
tier_name = tier_config.get("name", "Free")
tier_badge = f'<span class="tier-badge" style="background: {tier_color}">{tier_name}</span>'
days_remaining = user.get("tariff_days_remaining", 0)
days_remaining = get_remaining_days(user)
days_info = f"<p>⏳ Осталось дней: {days_remaining}</p>" if tier == "paid" and days_remaining > 0 else ""
traffic = get_cached_traffic(subscription_id)
@@ -728,14 +742,15 @@ async def webhook_donationalerts(request: Request):
conn = get_db()
try:
now_ts = int(time.time())
conn.execute("""
UPDATE users SET
tier = ?,
tariff_days_bought = tariff_days_bought + ?,
tariff_days_remaining = tariff_days_remaining + ?,
tariff_end_at = MAX(COALESCE(tariff_end_at, 0), ?) + ? * 86400,
total_paid_rubles = total_paid_rubles + ?
WHERE id = ?
""", (tier, days, days, amount, user["id"]))
""", (tier, days, now_ts, days, amount, user["id"]))
conn.commit()
finally:
conn.close()
@@ -764,18 +779,19 @@ async def admin_users(request: Request):
traffic = f'{u["traffic_limit_gb"]} GB' if u['traffic_limit_gb'] > 0 else '&#8734;'
active = '&#10003;' if u['is_active'] else '&#10007;'
tier_display = u['tier'].upper()
rem_days = get_remaining_days(u)
users_rows += f'''<tr>
<td>{u['id']}</td>
<td style="font-weight:600;color:var(--text)">{u['username']}</td>
<td><code>{u['subscription_id']}</code></td>
<td><span class="badge badge-{u['tier']}">{tier_display}</span></td>
<td>{u['tariff_days_remaining']}</td>
<td>{rem_days}</td>
<td>{u['total_paid_rubles']}&#8381;</td>
<td>{traffic}</td>
<td>{active}</td>
<td>{u['created_at'][:10]}</td>
<td>
<button class="btn-sm" onclick="editUser({u['id']}, '{u['tier']}', {u['tariff_days_remaining']}, {u['traffic_limit_gb']}, {1 if u['is_active'] else 0})">&#9997;&#65039;</button>
<button class="btn-sm" onclick="editUser({u['id']}, '{u['tier']}', {rem_days}, {u['traffic_limit_gb']}, {1 if u['is_active'] else 0})">&#9997;&#65039;</button>
<button class="btn-sm danger" onclick="deleteUser({u['id']}, '{u['username']}')">&#128465;&#65039;</button>
</td>
</tr>'''
@@ -1185,6 +1201,7 @@ async def update_user(request: Request, data: dict):
user_id = int(data.get("id", 0))
tier = str(data.get("tier", "free"))
tariff_days_remaining = int(data.get("tariff_days_remaining", 0) or 0)
tariff_end_at = int(time.time()) + tariff_days_remaining * 86400 if tariff_days_remaining > 0 else 0
traffic_limit_gb = int(data.get("traffic_limit_gb", 0) or 0)
is_active = 1 if data.get("is_active") in [True, "true", "on", "1", 1] else 0
@@ -1193,9 +1210,9 @@ async def update_user(request: Request, data: dict):
conn = get_db()
try:
conn.execute("""
UPDATE users SET tier = ?, tariff_days_remaining = ?, traffic_limit_gb = ?, is_active = ?
UPDATE users SET tier = ?, tariff_days_remaining = ?, tariff_end_at = ?, traffic_limit_gb = ?, is_active = ?
WHERE id = ?
""", (tier, tariff_days_remaining, traffic_limit_gb, is_active, user_id))
""", (tier, tariff_days_remaining, tariff_end_at, traffic_limit_gb, is_active, user_id))
conn.commit()
updated = conn.execute("SELECT * FROM users WHERE id = ?", (user_id,)).fetchone()
@@ -1374,20 +1391,21 @@ async def poll_donationalerts():
user = conn.execute("SELECT * FROM users WHERE username = ? COLLATE NOCASE", (username,)).fetchone()
if user:
current_expiry = user.get("tariff_days_remaining", 0)
if current_expiry > 0:
new_expiry = current_expiry + days
now_ts = int(time.time())
current_end = user.get("tariff_end_at", 0)
if current_end > now_ts:
new_end = current_end + days * 86400
else:
new_expiry = days
new_end = now_ts + days * 86400
conn.execute("""
UPDATE users SET
tier = ?,
tariff_days_bought = tariff_days_bought + ?,
tariff_days_remaining = ?,
tariff_end_at = ?,
total_paid_rubles = total_paid_rubles + ?
WHERE id = ?
""", (tier, days, new_expiry, amount, user["id"]))
""", (tier, days, new_end, amount, user["id"]))
conn.commit()
sub_id = user["subscription_id"]