Compare commits

...

5 Commits

4 changed files with 120 additions and 8 deletions
+20 -2
View File
@@ -62,6 +62,7 @@ class RewardCampaign:
twitch_user_id: Optional[str] = None, twitch_user_id: Optional[str] = None,
twitch_user_name: Optional[str] = None, twitch_user_name: Optional[str] = None,
earned_at: Optional[datetime] = None, earned_at: Optional[datetime] = None,
**kwargs,
) -> EarnedReward: ) -> EarnedReward:
row = await EarnedReward.create( row = await EarnedReward.create(
campaign_id=self.row.campaign_id, campaign_id=self.row.campaign_id,
@@ -71,6 +72,7 @@ class RewardCampaign:
twitch_user_id=twitch_user_id, twitch_user_id=twitch_user_id,
twitch_user_name=twitch_user_name, twitch_user_name=twitch_user_name,
earned_at=earned_at or utc_now(), earned_at=earned_at or utc_now(),
**kwargs,
) )
await self.try_to_log_reward(row) await self.try_to_log_reward(row)
@@ -85,12 +87,28 @@ class RewardCampaign:
await reward.update(**kwargs) await reward.update(**kwargs)
await self.try_to_log_reward(reward) await self.try_to_log_reward(reward)
async def delete_reward(self, rewardid: int):
reward = await EarnedReward.fetch(rewardid)
if reward is None:
raise ValueError("Reward doesn't exist")
await self.try_to_unlog_reward(reward)
await reward.delete()
async def get_rewards(self) -> list[EarnedReward]: async def get_rewards(self) -> list[EarnedReward]:
rows = await EarnedReward.fetch_where( rows = await EarnedReward.fetch_where(
campaign_id=self.row.campaign_id campaign_id=self.row.campaign_id
).order_by("earned_at", direction=ORDER.ASC) ).order_by("earned_at", direction=ORDER.ASC)
return rows return rows
async def try_to_unlog_reward(self, reward: EarnedReward):
import discord
try:
if self.webhook and reward.log_messageid:
await self.webhook.delete_message(reward.log_messageid)
except discord.HTTPException:
pass
async def try_to_log_reward(self, reward: EarnedReward): async def try_to_log_reward(self, reward: EarnedReward):
import discord import discord
@@ -203,8 +221,8 @@ class CampaignRegistry:
condition = Campaign.communityid == cid condition = Campaign.communityid == cid
if active is not None: if active is not None:
active_condition = ( active_condition = (Campaign.started_at != NULL) & (
(Campaign.started_at != NULL) & (Campaign.completed_at == NULL) Campaign.completed_at == NULL
) )
if active: if active:
condition = condition & active_condition condition = condition & active_condition
+52 -1
View File
@@ -7,6 +7,7 @@ from discord.ext import commands as cmds
from discord import Forbidden, User, app_commands as appcmds from discord import Forbidden, User, app_commands as appcmds
from meta import LionBot, LionCog, LionContext from meta import LionBot, LionCog, LionContext
from meta import logger
from meta.errors import SafeCancellation, UserInputError from meta.errors import SafeCancellation, UserInputError
from meta.logger import log_wrap from meta.logger import log_wrap
from utils.lib import utc_now from utils.lib import utc_now
@@ -79,6 +80,7 @@ class CampaignCog(LionCog):
sorted_campaigns = sorted( sorted_campaigns = sorted(
campaigns, campaigns,
key=lambda camp: (camp.is_active, camp.row.started_at, camp.row.created_at), key=lambda camp: (camp.is_active, camp.row.started_at, camp.row.created_at),
reverse=True,
) )
names = [ names = [
camp.row.campaign_name camp.row.campaign_name
@@ -258,7 +260,7 @@ class CampaignCog(LionCog):
update_args["campaign_name"] = new_name update_args["campaign_name"] = new_name
if new_cap is not None: if new_cap is not None:
update_args["total_rewards"] = new_cap if new_cap > 0 else None update_args["target_rewards"] = new_cap if new_cap > 0 else None
# If logging webhook is given, check that it works # If logging webhook is given, check that it works
if logging_webhook is not None: if logging_webhook is not None:
@@ -317,6 +319,53 @@ class CampaignCog(LionCog):
campaign_rewards_cmd.autocomplete("campaign_name")(_campaign_acmpl) campaign_rewards_cmd.autocomplete("campaign_name")(_campaign_acmpl)
@campaign_group.command(
name="delreward",
description="Remove a campaign reward",
)
@appcmds.describe(
rewardid="Earned reward to delete",
)
@appcmds.rename(rewardid="reward")
async def campaign_delreward_cmd(
self,
ctx: LionContext,
rewardid: str,
):
# For this we'll just open the reward editor
# Will need to identify the reward with autocomplete. Can use the reward id directly..
if not rewardid.isdigit():
raise UserInputError(
"Please enter the reward number or select a reward from the argument menu"
)
reward = await EarnedReward.fetch(int(rewardid))
if not reward:
raise UserInputError(
"Reward not found. Please enter the reward number or select a reward from the argument menu"
)
# Fetch campaign and then do a perm check
campaign = await self.campaigns.fetch_campaign(reward.campaign_id)
if campaign is None:
raise SafeCancellation("Something went wrong.. please try again soon.")
if campaign.row.communityid != ctx.community.communityid:
raise UserInputError("This reward doesn't belong to this community!")
if not await self.campaign_modcheck(campaign, ctx.author):
await ctx.interaction.response.send_message(
"You need to be an administrator or have the configured modrole to use that!",
ephemeral=True,
)
return
# Okay, they have permission, let's delete the reward.
await campaign.delete_reward(reward.earned_id)
# Ack
await ctx.reply(content="Campaign reward deleted!", ephemeral=True)
@campaign_group.command( @campaign_group.command(
name="editreward", name="editreward",
description="Add or edit details for a given reward in a campaign (see also /campaign rewards)", description="Add or edit details for a given reward in a campaign (see also /campaign rewards)",
@@ -432,6 +481,7 @@ class CampaignCog(LionCog):
cname=campaign.row.campaign_name, cname=campaign.row.campaign_name,
) )
@campaign_delreward_cmd.autocomplete("rewardid")
@campaign_editreward_cmd.autocomplete("rewardid") @campaign_editreward_cmd.autocomplete("rewardid")
async def _reward_acmpl( async def _reward_acmpl(
self, interaction: discord.Interaction, partial: str self, interaction: discord.Interaction, partial: str
@@ -457,6 +507,7 @@ class CampaignCog(LionCog):
sorted_campaigns = sorted( sorted_campaigns = sorted(
campaigns, campaigns,
key=lambda camp: (camp.is_active, camp.row.started_at, camp.row.created_at), key=lambda camp: (camp.is_active, camp.row.started_at, camp.row.created_at),
reverse=True,
) )
for campaign in sorted_campaigns: for campaign in sorted_campaigns:
rewards = await campaign.get_rewards() rewards = await campaign.get_rewards()
+10
View File
@@ -63,6 +63,16 @@ class ThreadedWebhook(discord.Webhook):
kwargs.setdefault("thread", discord.Object(self.thread_id)) kwargs.setdefault("thread", discord.Object(self.thread_id))
return await super().edit_message(*args, **kwargs) return await super().edit_message(*args, **kwargs)
async def delete_message(self, *args, **kwargs):
if self.thread_id is not None:
kwargs.setdefault("thread", discord.Object(self.thread_id))
return await super().delete_message(*args, **kwargs)
async def fetch_message(self, *args, **kwargs):
if self.thread_id is not None:
kwargs.setdefault("thread", discord.Object(self.thread_id))
return await super().fetch_message(*args, **kwargs)
async def test_webhook(self): async def test_webhook(self):
embed = discord.Embed( embed = discord.Embed(
title="Testing", description="Testing logging webhook, feel free to delete." title="Testing", description="Testing logging webhook, feel free to delete."
+38 -5
View File
@@ -80,8 +80,41 @@ class CampaignComponent(cmds.Component):
twitch_user_name=data["chatter_user_name"], twitch_user_name=data["chatter_user_name"],
) )
await self.dispatch_update(campaign) await self.dispatch_update(campaign)
# TODO: Webhook logging maybe.. (do this in campaign)
# Or just general logging. (also do this in campaign, but we can do again here) # @cmds.Component.listener()
async def event_custom_redemption_add(self, payload):
if payload.reward.title not in (
"hi!",
"hydrate",
"stretch",
"save file",
"pet lilac",
):
return
community = await self.bot.profiles.fetch_community(payload.broadcaster)
cid = community.communityid
profile = await self.bot.profiles.fetch_profile(payload.user)
pid = profile.profileid
campaigns = await self.campaigns.fetch_campaigns(cid)
for campaign in campaigns:
reward_progress = len(await campaign.get_rewards())
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=pid,
earned_from=f"(REDEEM) User redeemed {payload.reward.title}",
event_id=None,
twitch_user_id=payload.user.id,
twitch_user_name=payload.user.name,
reference=f"Redeem text: {payload.user_input}",
)
await self.dispatch_update(campaign)
# @cmds.Component.listener() # @cmds.Component.listener()
async def event_message(self, payload): async def event_message(self, payload):
@@ -131,7 +164,6 @@ class CampaignComponent(cmds.Component):
# ------ Commands ----- # ------ Commands -----
@cmds.group(name="campaign", invoke_fallback=True) @cmds.group(name="campaign", invoke_fallback=True)
@cmds.is_moderator()
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)
@@ -174,6 +206,7 @@ class CampaignComponent(cmds.Component):
cap=reward_cap, cap=reward_cap,
) )
await ctx.reply(formatted) await ctx.reply(formatted)
await self.dispatch_update(campaign)
@group_campaign.command(name="setup", aliases=["start"]) @group_campaign.command(name="setup", aliases=["start"])
@cmds.is_moderator() @cmds.is_moderator()
@@ -261,9 +294,9 @@ class CampaignComponent(cmds.Component):
reward_cap = campaign.row.target_rewards reward_cap = campaign.row.target_rewards
if reward_cap is not None: if reward_cap is not None:
response = f"Completed {name}: {rewards_earned} rewards earned out of {reward_cap}!" response = "Completed {name}: {given} rewards earned out of {cap}!"
else: else:
response = f"Completed {name}: {rewards_earned} rewards earned so far!" response = "Completed {name}: {given} rewards earned so far!"
formatted = response.format( formatted = response.format(
name=campaign.row.campaign_name, name=campaign.row.campaign_name,
given=rewards_earned, given=rewards_earned,