From bfce1f6ce41fd020ec7052cac78a169b63cf9a38 Mon Sep 17 00:00:00 2001 From: Ash Keel Date: Tue, 18 May 2021 15:50:58 +0200 Subject: [PATCH] Handle goal redemption via stulbe --- go.mod | 2 +- go.sum | 4 +- modules/loyalty/manager.go | 65 +++++++++++++++++++++++-- modules/twitch/commands.go | 97 +++++++++++++++----------------------- 4 files changed, 102 insertions(+), 66 deletions(-) diff --git a/go.mod b/go.mod index 9c4e544..9fd5014 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,6 @@ require ( github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 github.com/sirupsen/logrus v1.8.1 github.com/strimertul/kilovolt/v4 v4.0.1 - github.com/strimertul/stulbe v0.4.2 + github.com/strimertul/stulbe v0.4.3 github.com/strimertul/stulbe-client-go v0.2.0 ) diff --git a/go.sum b/go.sum index 27c805f..313a61e 100644 --- a/go.sum +++ b/go.sum @@ -113,8 +113,8 @@ github.com/strimertul/kilovolt/v4 v4.0.1/go.mod h1:AO2ZFQtSB+AcjCw0RTkXjbM6XBAjh github.com/strimertul/strimertul v1.3.0/go.mod h1:1pSe9zVWF4BYt56ii1Hg+xTxvtfqfvT4FQ7bYffWsUA= github.com/strimertul/stulbe v0.2.5/go.mod h1:0AsY4OVf1dNCwOn9s7KySuAxJ85w88pXeostu1n9E7w= github.com/strimertul/stulbe v0.3.0/go.mod h1:Pb0UQCKdyES7UKSKm2i2g9parkgXSJAFeMH/LSOSbgQ= -github.com/strimertul/stulbe v0.4.2 h1:dxxjGtLiUEyMu/V7Rc7kurcY6DHS7jXS8/GEfQPSFR4= -github.com/strimertul/stulbe v0.4.2/go.mod h1:Pb0UQCKdyES7UKSKm2i2g9parkgXSJAFeMH/LSOSbgQ= +github.com/strimertul/stulbe v0.4.3 h1:apDTvFaChCoMxUokc1Y51Wn43hWyf0qqMNkptnlIj/c= +github.com/strimertul/stulbe v0.4.3/go.mod h1:Pb0UQCKdyES7UKSKm2i2g9parkgXSJAFeMH/LSOSbgQ= github.com/strimertul/stulbe-client-go v0.1.0/go.mod h1:KtfuDhxCHZ9DCFHnrBOHqb2Pu9zoj+EqA8ZRIUqLD/w= github.com/strimertul/stulbe-client-go v0.2.0 h1:zoUu+/ssOWz9VsoioJkQNMU88qJ/lQzAu6ak8GcTYxY= github.com/strimertul/stulbe-client-go v0.2.0/go.mod h1:5S+nDMyzkeoBHi9fq3s37A4mv3XUPJhwgW94UtGzp28= diff --git a/modules/loyalty/manager.go b/modules/loyalty/manager.go index 8f6e5be..e36bf5c 100644 --- a/modules/loyalty/manager.go +++ b/modules/loyalty/manager.go @@ -16,7 +16,8 @@ import ( ) var ( - ErrGoalNotFound = errors.New("goal not found") + ErrGoalNotFound = errors.New("goal not found") + ErrGoalAlreadyReached = errors.New("goal already reached") ) type Manager struct { @@ -171,7 +172,7 @@ func (m *Manager) handleRemote(kvs []database.ModifiedKV) error { break } // Find reward - reward := m.getReward(redeemRequest.RewardID) + reward := m.GetReward(redeemRequest.RewardID) if reward.ID == "" { m.logger.WithField("reward-id", redeemRequest.RewardID).Warn("redeem request contains invalid reward id") break @@ -186,6 +187,24 @@ func (m *Manager) handleRemote(kvs []database.ModifiedKV) error { if err != nil { m.logger.WithError(err).Warn("error performing redeem request") } + case api.KVExLoyaltyContribute: + // Parse request + var contributeRequest api.ExLoyaltyContribute + err := jsoniter.ConfigFastest.Unmarshal(kv.Data, &contributeRequest) + if err != nil { + m.logger.WithError(err).Warn("error decoding contribution request") + break + } + // Find goal + goal := m.GetGoal(contributeRequest.GoalID) + if goal.ID == "" { + m.logger.WithField("goal-id", contributeRequest.GoalID).Warn("contribute request contains invalid goal id") + break + } + err = m.PerformContribution(goal, contributeRequest.Username, contributeRequest.Amount) + if err != nil { + m.logger.WithError(err).Warn("error performing contribution request") + } } } return nil @@ -305,13 +324,42 @@ func (m *Manager) ContributeGoal(goal Goal, user string, points int64) error { return ErrGoalNotFound } +func (m *Manager) PerformContribution(goal Goal, user string, points int64) error { + // Get user balance + balance := m.GetPoints(user) + + // If user specified more points than they have, pick the maximum possible + if points > balance { + points = balance + } + + // Check if goal was reached already + if goal.Contributed >= goal.TotalGoal { + return ErrGoalAlreadyReached + } + + // If remaining points are lower than what user is contributing, only take what's needed + remaining := goal.TotalGoal - goal.Contributed + if points > remaining { + points = remaining + } + + // Remove points from user + if err := m.TakePoints(map[string]int64{user: points}); err != nil { + return err + } + + // Add points to goal + return m.ContributeGoal(goal, user, points) +} + func (m *Manager) Rewards() []Reward { m.mu.Lock() defer m.mu.Unlock() return m.rewards[:] } -func (m *Manager) getReward(id string) Reward { +func (m *Manager) GetReward(id string) Reward { m.mu.Lock() defer m.mu.Unlock() for _, reward := range m.rewards { @@ -322,6 +370,17 @@ func (m *Manager) getReward(id string) Reward { return Reward{} } +func (m *Manager) GetGoal(id string) Goal { + m.mu.Lock() + defer m.mu.Unlock() + for _, goal := range m.goals { + if goal.ID == id { + return goal + } + } + return Goal{} +} + func (m *Manager) Config() Config { m.mu.Lock() defer m.mu.Unlock() diff --git a/modules/twitch/commands.go b/modules/twitch/commands.go index 8ff69d7..705a6c0 100644 --- a/modules/twitch/commands.go +++ b/modules/twitch/commands.go @@ -69,47 +69,44 @@ func cmdRedeemReward(bot *Bot, message irc.PrivateMessage) { redeemID := parts[1] // Find reward - for _, reward := range bot.Loyalty.Rewards() { - if reward.ID != redeemID { - continue - } - - // Reward not active, return early - if !reward.Enabled { - return - } - - // Get user balance - balance := bot.Loyalty.GetPoints(message.User.Name) - config := bot.Loyalty.Config() - - // Check if user can afford the reward - if balance-reward.Price < 0 { - bot.Client.Say(message.Channel, fmt.Sprintf("I'm sorry %s but you cannot afford this (have %d %s, need %d)", message.User.DisplayName, balance, config.Currency, reward.Price)) - return - } - - text := "" - if len(parts) > 2 { - text = strings.Join(parts[2:], " ") - } - - // Perform redeem - if err := bot.Loyalty.PerformRedeem(loyalty.Redeem{ - Username: message.User.Name, - DisplayName: message.User.DisplayName, - When: time.Now(), - Reward: reward, - RequestText: text, - }); err != nil { - bot.logger.WithError(err).Error("error while performing redeem") - return - } - - bot.Client.Say(message.Channel, fmt.Sprintf("HolidayPresent %s has redeemed %s! (new balance: %d %s)", message.User.DisplayName, reward.Name, bot.Loyalty.GetPoints(message.User.Name), config.Currency)) - + reward := bot.Loyalty.GetReward(redeemID) + if reward.ID == "" { return } + + // Reward not active, return early + if !reward.Enabled { + return + } + + // Get user balance + balance := bot.Loyalty.GetPoints(message.User.Name) + config := bot.Loyalty.Config() + + // Check if user can afford the reward + if balance-reward.Price < 0 { + bot.Client.Say(message.Channel, fmt.Sprintf("I'm sorry %s but you cannot afford this (have %d %s, need %d)", message.User.DisplayName, balance, config.Currency, reward.Price)) + return + } + + text := "" + if len(parts) > 2 { + text = strings.Join(parts[2:], " ") + } + + // Perform redeem + if err := bot.Loyalty.PerformRedeem(loyalty.Redeem{ + Username: message.User.Name, + DisplayName: message.User.DisplayName, + When: time.Now(), + Reward: reward, + RequestText: text, + }); err != nil { + bot.logger.WithError(err).Error("error while performing redeem") + return + } + + bot.Client.Say(message.Channel, fmt.Sprintf("HolidayPresent %s has redeemed %s! (new balance: %d %s)", message.User.DisplayName, reward.Name, bot.Loyalty.GetPoints(message.User.Name), config.Currency)) } func cmdGoalList(bot *Bot, message irc.PrivateMessage) { @@ -192,14 +189,6 @@ func cmdContributeGoal(bot *Bot, message irc.PrivateMessage) { } } - // Get user balance - balance := bot.Loyalty.GetPoints(message.User.Name) - - // If user specified more points than they have, pick the maximum possible - if points > balance { - points = balance - } - // Get goal selectedGoal := goals[goalIndex] @@ -209,20 +198,8 @@ func cmdContributeGoal(bot *Bot, message irc.PrivateMessage) { return } - // If remaining points are lower than what user is contributing, only take what's needed - remaining := selectedGoal.TotalGoal - selectedGoal.Contributed - if points > remaining { - points = remaining - } - - // Remove points from user - if err := bot.Loyalty.TakePoints(map[string]int64{message.User.Name: points}); err != nil { - bot.logger.WithError(err).Error("error while taking points for redeem") - return - } - // Add points to goal - if err := bot.Loyalty.ContributeGoal(selectedGoal, message.User.Name, points); err != nil { + if err := bot.Loyalty.PerformContribution(selectedGoal, message.User.Name, points); err != nil { bot.logger.WithError(err).Error("error while contributing to goal") return }