Registry, tw interface draft, sub handler

This commit is contained in:
2026-07-25 09:49:42 +03:00
parent 67a04ef82f
commit fc5c3d07e4
4 changed files with 384 additions and 4 deletions
+131 -1
View File
@@ -1,4 +1,12 @@
from typing import Optional
from typing import Any, Optional
import datetime as dt
from datetime import datetime, timedelta
from data import ORDER, Condition
from data.conditions import NULL, condition
from utils.lib import utc_now
from .lib import LOWER, asexpr
from .data import (
CampaignData,
Campaign,
@@ -6,6 +14,55 @@ from .data import (
)
class RewardCampaign:
def __init__(self, row: Campaign):
self.row = row
@property
def is_active(self):
return self.row.started_at is not None and self.row.completed_at is None
async def start(self):
"""Start the reward campaign."""
if self.row.started_at is not None:
raise ValueError("This campaign has already been started.")
await self.row.update(started_at=utc_now())
async def finish(self):
"""End the reward campaign."""
if self.row.completed_at is not None:
raise ValueError("This campaign is already finished.")
await self.row.update(completed_at=utc_now())
async def add_reward(
self,
profileid: int,
earned_reason: str,
event_id: Optional[int] = None,
twitch_user_id: Optional[str] = None,
twitch_user_name: Optional[str] = None,
earned_at: Optional[datetime] = None,
) -> EarnedReward:
row = await EarnedReward.create(
campaign_id=self.row.campaign_id,
profileid=profileid,
earned_reason=earned_reason,
event_id=event_id,
twitch_user_id=twitch_user_id,
twitch_user_name=twitch_user_name,
earned_at=earned_at or utc_now(),
)
return row
async def get_rewards(self) -> list[EarnedReward]:
rows = await EarnedReward.fetch_where(
campaign_id=self.row.campaign_id
).order_by("earned_at", direction=ORDER.ASC)
return rows
class CampaignRegistry:
VERSION = CampaignData.VERSION
@@ -14,3 +71,76 @@ class CampaignRegistry:
async def init(self):
await self.data.init()
async def fetch_campaign(self, campaign_id: int) -> RewardCampaign:
"""
Fetch a campaign by id. The campaign must exist.
"""
row = await Campaign.fetch(campaign_id)
if row is None:
raise ValueError("Campign %s doesn't exist." % campaign_id)
camp = RewardCampaign(row)
return camp
async def fetch_campaigns(
self,
cid: int,
*,
active: bool | None = True,
) -> list[RewardCampaign]:
"""
Fetch all campaigns in the given community, matching the given conditions.
"""
condition = Campaign.communityid == cid
if active is not None:
active_condition = (
Campaign.started_at != NULL and Campaign.completed_at == NULL
)
if active:
condition = condition and active_condition
else:
condition = condition and ~active_condition
rows = await Campaign.fetch_where(condition)
campaigns = [RewardCampaign(row) for row in rows]
return campaigns
async def fetch_campaign_by_name(
self, cid: int, name: str
) -> Optional[RewardCampaign]:
"""
Fetch a campaign for this community by name.
The name is matched without case.
"""
results = await Campaign.fetch_where(
Condition._expression_equality(
LOWER(Campaign.campaign_name.expr), LOWER(asexpr(name))
),
campaignid=cid,
)
if results:
row = results[0]
camp = RewardCampaign(row)
else:
camp = None
return camp
async def create_campaign(
self,
cid: int,
campaign_name: str,
target_rewards: Optional[int] = None,
) -> RewardCampaign:
"""
Create a new campaign.
The name must be unique (ignoring case) to facilitate easy lookup.
"""
row = await Campaign.create(
communityid=cid,
target_rewards=target_rewards,
campaign_name=campaign_name,
)
return RewardCampaign(row)