forked from retoor/devplacepy
feat: add telegram notification channel with outbox service and per-user preferences
Extend the notification system with a third channel (telegram) alongside existing in_app and push channels. Add `telegram_enabled` column to `notification_preferences` table, update `NOTIFICATION_CHANNELS` and `_NOTIFICATION_CHANNEL_COLUMNS` mappings, and set telegram default to off (`_NOTIFICATION_CHANNEL_DEFAULTS`). Create `telegram_outbox` table with columns for uid, user_uid, chat_id, text, status, attempts, created_at, and sent_at, plus an index on status/id for efficient polling. Register `TelegramOutboxService` in the service manager lifecycle. Update API documentation strings to describe the new channel and its pairing requirement. Extend admin notification defaults view to include telegram column. Pass `notif_telegram_paired` flag to profile template based on `telegram_store.is_paired()` check. Update `NotificationPrefForm` and `NotificationDefaultForm` model literals to accept "telegram" as a valid channel value.
This commit is contained in:
@@ -128,6 +128,34 @@ def level_progress(xp: int) -> dict:
|
||||
}
|
||||
|
||||
|
||||
SCORE_PRESTIGE = 5000
|
||||
SCORE_HARVEST = 10
|
||||
SCORE_COIN_DIVISOR = 20
|
||||
SCORE_CI = 250
|
||||
SCORE_PLOT = 200
|
||||
SCORE_PERK = 120
|
||||
SCORE_STREAK = 15
|
||||
SCORE_STREAK_CAP = 30
|
||||
|
||||
|
||||
def farm_score(farm: dict) -> int:
|
||||
def value(key: str, default: int = 0) -> int:
|
||||
raw = farm.get(key)
|
||||
return int(raw) if raw is not None else default
|
||||
|
||||
perk_total = sum(value(f"perk_{perk.key}") for perk in PERKS)
|
||||
return (
|
||||
value("xp")
|
||||
+ value("prestige") * SCORE_PRESTIGE
|
||||
+ value("total_harvests") * SCORE_HARVEST
|
||||
+ value("coins") // SCORE_COIN_DIVISOR
|
||||
+ (value("ci_tier", 1) - 1) * SCORE_CI
|
||||
+ (value("plot_count", STARTING_PLOTS) - STARTING_PLOTS) * SCORE_PLOT
|
||||
+ perk_total * SCORE_PERK
|
||||
+ min(value("streak"), SCORE_STREAK_CAP) * SCORE_STREAK
|
||||
)
|
||||
|
||||
|
||||
def unlocked_crops(level: int) -> list[Crop]:
|
||||
return [crop for crop in CROPS if crop.min_level <= level]
|
||||
|
||||
|
||||
@@ -475,7 +475,7 @@ def steal(thief: dict, owner: dict, slot: int) -> dict:
|
||||
def leaderboard(limit: int = 25) -> list[dict]:
|
||||
farms = sorted(
|
||||
_farms().find(),
|
||||
key=lambda row: (int(row.get("level", 1)), int(row.get("xp", 0)), int(row.get("total_harvests", 0))),
|
||||
key=economy.farm_score,
|
||||
reverse=True,
|
||||
)[:limit]
|
||||
if not farms:
|
||||
@@ -496,6 +496,8 @@ def leaderboard(limit: int = 25) -> list[dict]:
|
||||
"xp": int(farm.get("xp", 0)),
|
||||
"coins": int(farm.get("coins", 0)),
|
||||
"total_harvests": int(farm.get("total_harvests", 0)),
|
||||
"prestige": int(farm.get("prestige") or 0),
|
||||
"score": economy.farm_score(farm),
|
||||
}
|
||||
)
|
||||
return entries
|
||||
|
||||
Reference in New Issue
Block a user