generated from HoloTech/holotech-plugin-template
Adaptions for ppp event.
Fix several typos in event handler Rewrite sub and resub event handlers to expect resub events Add ppp alias to campaign command. Add ppp test command for testing last sub calculator
This commit is contained in:
+139
-9
@@ -1,9 +1,13 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import datetime as dt
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
import twitchio
|
import twitchio
|
||||||
from twitchio.ext import commands as cmds
|
from twitchio.ext import commands as cmds
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
|
from data.queries import JOINTYPE, ORDER
|
||||||
from meta import Bot
|
from meta import Bot
|
||||||
from meta.logger import log_wrap
|
from meta.logger import log_wrap
|
||||||
from meta.sockets import Channel, register_channel
|
from meta.sockets import Channel, register_channel
|
||||||
@@ -42,7 +46,7 @@ class CampaignComponent(cmds.Component):
|
|||||||
|
|
||||||
# ------ Event Handlers -----
|
# ------ Event Handlers -----
|
||||||
@cmds.Component.listener()
|
@cmds.Component.listener()
|
||||||
async def event_safe_event_chat_notice_sub(self, payload):
|
async def event_safe_chat_notice_sub(self, payload):
|
||||||
"""
|
"""
|
||||||
This is our most important notice for this event.
|
This is our most important notice for this event.
|
||||||
|
|
||||||
@@ -61,9 +65,15 @@ class CampaignComponent(cmds.Component):
|
|||||||
if detail_row["tier"] == 3000 and detail_row["duration_months"] >= 3:
|
if detail_row["tier"] == 3000 and detail_row["duration_months"] >= 3:
|
||||||
# Check if there is an ongoing campaign
|
# Check if there is an ongoing campaign
|
||||||
campaigns = await self.campaigns.fetch_campaigns(event_row["communityid"])
|
campaigns = await self.campaigns.fetch_campaigns(event_row["communityid"])
|
||||||
|
pid = event_row["profileid"]
|
||||||
|
|
||||||
for campaign in campaigns:
|
for campaign in campaigns:
|
||||||
reward_progress = len(await campaign.get_rewards())
|
rewards = await campaign.get_rewards()
|
||||||
|
reward_progress = len(rewards)
|
||||||
|
|
||||||
|
existing = any(reward.profileid == pid for reward in rewards)
|
||||||
|
if existing:
|
||||||
|
continue
|
||||||
|
|
||||||
if (
|
if (
|
||||||
campaign.row.target_rewards is None
|
campaign.row.target_rewards is None
|
||||||
@@ -145,7 +155,7 @@ class CampaignComponent(cmds.Component):
|
|||||||
await self.dispatch_update(campaign)
|
await self.dispatch_update(campaign)
|
||||||
|
|
||||||
@cmds.Component.listener()
|
@cmds.Component.listener()
|
||||||
async def event_safe_event_chat_notice_resub(self, payload):
|
async def event_safe_chat_notice_resub(self, payload):
|
||||||
# Check that the end of the sub is past the threshold by adding duration to the previous sub
|
# Check that the end of the sub is past the threshold by adding duration to the previous sub
|
||||||
# Threshold being now + 3 months, by calendar date.
|
# Threshold being now + 3 months, by calendar date.
|
||||||
# Or even if the sub ends on at least the month that is past the three month region.
|
# Or even if the sub ends on at least the month that is past the three month region.
|
||||||
@@ -154,7 +164,72 @@ class CampaignComponent(cmds.Component):
|
|||||||
# # TODO: This logic should be done for completeness, but will postpone for now
|
# # TODO: This logic should be done for completeness, but will postpone for now
|
||||||
# This could be done in subscription_message as well, but the
|
# This could be done in subscription_message as well, but the
|
||||||
# notice has slightly more self-contained metadata.
|
# notice has slightly more self-contained metadata.
|
||||||
...
|
event_row, detail_row, data = payload
|
||||||
|
|
||||||
|
# Check the tier and duration of the subscription.
|
||||||
|
# Continue if tier = 3000 and duration is at least 3 months
|
||||||
|
if detail_row["tier"] == 3000 and detail_row["duration_months"] >= 3:
|
||||||
|
# Check if there is an ongoing campaign
|
||||||
|
campaigns = await self.campaigns.fetch_campaigns(event_row["communityid"])
|
||||||
|
pid = event_row["profileid"]
|
||||||
|
|
||||||
|
# Get user's last sub date
|
||||||
|
last_sub_date = await self.get_sub_start(
|
||||||
|
channelid=event_row["channel_id"],
|
||||||
|
userid=event_row["user_id"],
|
||||||
|
tier=3000,
|
||||||
|
)
|
||||||
|
if last_sub_date is None:
|
||||||
|
logger.error(f"T3 rsub with no history: {event_row!r}")
|
||||||
|
return
|
||||||
|
forecast_end = last_sub_date + relativedelta(
|
||||||
|
months=detail_row["duration_months"]
|
||||||
|
)
|
||||||
|
if forecast_end < dt.datetime(2026, 11, 1, tzinfo=dt.UTC):
|
||||||
|
logger.warning(f"T3 sub with forecast end too short: {event_row!r}")
|
||||||
|
return
|
||||||
|
|
||||||
|
for campaign in campaigns:
|
||||||
|
rewards = await campaign.get_rewards()
|
||||||
|
reward_progress = len(rewards)
|
||||||
|
|
||||||
|
existing = any(reward.profileid == pid for reward in rewards)
|
||||||
|
if existing:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (
|
||||||
|
campaign.row.target_rewards is None
|
||||||
|
or reward_progress < campaign.row.target_rewards
|
||||||
|
):
|
||||||
|
# Add a reward to the database with the correct info.
|
||||||
|
await campaign.add_reward(
|
||||||
|
profileid=event_row["profileid"],
|
||||||
|
earned_from=f"(RESUB NOTICE) {data.system_message}",
|
||||||
|
event_id=event_row["event_id"],
|
||||||
|
twitch_user_id=data.chatter.id,
|
||||||
|
twitch_user_name=data.chatter.name,
|
||||||
|
)
|
||||||
|
await self.dispatch_update(campaign)
|
||||||
|
else:
|
||||||
|
logger.info(f"Campaigns ignoring sub notice event: {event_row}")
|
||||||
|
|
||||||
|
async def get_sub_start(self, channelid, userid, tier=3000):
|
||||||
|
event_tracker = self.bot.get_component("TrackerComponent")
|
||||||
|
query = event_tracker.data.events.select_where(
|
||||||
|
channel_id=channelid,
|
||||||
|
user_id=userid,
|
||||||
|
tier=tier,
|
||||||
|
)
|
||||||
|
query.join("subscribe_events", using=("event_id",), join_type=JOINTYPE.INNER)
|
||||||
|
query.order_by("created_at", direction=ORDER.DESC)
|
||||||
|
query.select("created_at")
|
||||||
|
query.limit(1)
|
||||||
|
query.with_no_adapter()
|
||||||
|
rows = await query
|
||||||
|
if rows:
|
||||||
|
return rows[0]["created_at"]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
@cmds.Component.listener()
|
@cmds.Component.listener()
|
||||||
async def event_safe_subscription(self, payload): ...
|
async def event_safe_subscription(self, payload): ...
|
||||||
@@ -163,7 +238,7 @@ class CampaignComponent(cmds.Component):
|
|||||||
async def event_safe_subscription_message(self, payload): ...
|
async def event_safe_subscription_message(self, payload): ...
|
||||||
|
|
||||||
# ------ Commands -----
|
# ------ Commands -----
|
||||||
@cmds.group(name="campaign", invoke_fallback=True)
|
@cmds.group(name="campaign", aliases=["ppp"], invoke_fallback=True)
|
||||||
async def group_campaign(self, ctx: cmds.Context, name: Optional[str] = None):
|
async def group_campaign(self, ctx: cmds.Context, name: Optional[str] = None):
|
||||||
"""Status of the current or named campaign."""
|
"""Status of the current or named campaign."""
|
||||||
community = await self.bot.profiles.fetch_community(ctx.broadcaster)
|
community = await self.bot.profiles.fetch_community(ctx.broadcaster)
|
||||||
@@ -196,12 +271,19 @@ class CampaignComponent(cmds.Component):
|
|||||||
rewards_earned = len(all_rewards)
|
rewards_earned = len(all_rewards)
|
||||||
reward_cap = campaign.row.target_rewards
|
reward_cap = campaign.row.target_rewards
|
||||||
|
|
||||||
if reward_cap is not None:
|
response = (
|
||||||
response = "{name}: {given} rewards earned out of {cap}!"
|
"event details can be found here: {event_link} "
|
||||||
else:
|
"there are {remaining} sketch slots remaining! ♡♡ "
|
||||||
response = "{name}: {given} rewards earned so far!"
|
)
|
||||||
|
|
||||||
|
# if reward_cap is not None:
|
||||||
|
# response = "{name}: {given} rewards earned out of {cap}!"
|
||||||
|
# else:
|
||||||
|
# response = "{name}: {given} rewards earned so far!"
|
||||||
formatted = response.format(
|
formatted = response.format(
|
||||||
name=campaign.row.campaign_name,
|
name=campaign.row.campaign_name,
|
||||||
|
event_link="https://lilac.thewisewolf.dev/provides/partner_plus_poster2.jpg",
|
||||||
|
remaining=reward_cap - rewards_earned,
|
||||||
given=rewards_earned,
|
given=rewards_earned,
|
||||||
cap=reward_cap,
|
cap=reward_cap,
|
||||||
)
|
)
|
||||||
@@ -344,3 +426,51 @@ class CampaignComponent(cmds.Component):
|
|||||||
f"Successfully added campaign reward to {user.mention}'s account."
|
f"Successfully added campaign reward to {user.mention}'s account."
|
||||||
)
|
)
|
||||||
await self.dispatch_update(campaign)
|
await self.dispatch_update(campaign)
|
||||||
|
|
||||||
|
@group_campaign.command(name="test")
|
||||||
|
@cmds.is_moderator()
|
||||||
|
async def cmd_campaign_test(
|
||||||
|
self,
|
||||||
|
ctx: cmds.Context,
|
||||||
|
user: twitchio.User,
|
||||||
|
channel: twitchio.User,
|
||||||
|
tier: int = 3000,
|
||||||
|
):
|
||||||
|
community = await self.bot.profiles.fetch_community(ctx.broadcaster)
|
||||||
|
cid = community.communityid
|
||||||
|
profile = await self.bot.profiles.fetch_profile(user)
|
||||||
|
name = user.display_name or profile.nickname or "Unknown"
|
||||||
|
pid = profile.profileid
|
||||||
|
campaigns = await self.campaigns.fetch_campaigns(cid)
|
||||||
|
campaign = campaigns[0]
|
||||||
|
|
||||||
|
# Get user's last sub date
|
||||||
|
last_sub_date = await self.get_sub_start(
|
||||||
|
channelid=channel.id,
|
||||||
|
userid=user.id,
|
||||||
|
tier=tier,
|
||||||
|
)
|
||||||
|
lines = []
|
||||||
|
if last_sub_date is None:
|
||||||
|
subline = f"Last {tier} sub not found"
|
||||||
|
lines.append(subline)
|
||||||
|
else:
|
||||||
|
subline = f"Last {tier} sub at {last_sub_date}"
|
||||||
|
lines.append(subline)
|
||||||
|
forecast_end = last_sub_date + relativedelta(months=3)
|
||||||
|
lines.append(f"Three months after: {forecast_end}")
|
||||||
|
|
||||||
|
if forecast_end > dt.datetime(2026, 11, 1, tzinfo=dt.UTC):
|
||||||
|
lines.append("Which is after the end of the event")
|
||||||
|
else:
|
||||||
|
lines.append("Which is not after the end of the event")
|
||||||
|
|
||||||
|
rewards = await campaign.get_rewards()
|
||||||
|
|
||||||
|
existing = any(reward.profileid == pid for reward in rewards)
|
||||||
|
if existing:
|
||||||
|
lines.append(f"This user has already been rewarded.")
|
||||||
|
else:
|
||||||
|
lines.append(f"This user might yet earn a reward")
|
||||||
|
|
||||||
|
await ctx.reply("; ".join(lines))
|
||||||
|
|||||||
Reference in New Issue
Block a user