discord.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package discord
  2. import (
  3. "fmt"
  4. "time"
  5. "github.com/bwmarrin/discordgo"
  6. "github.com/ente-io/museum/pkg/repo"
  7. t "github.com/ente-io/museum/pkg/utils/time"
  8. log "github.com/sirupsen/logrus"
  9. "github.com/spf13/viper"
  10. )
  11. // DiscordController is an devops aid. If Discord credentials are configured,
  12. // then it will send notifications to Discord channels on specified events.
  13. type DiscordController struct {
  14. MonaLisa *discordgo.Session
  15. ChaChing *discordgo.Session
  16. HostName string
  17. Environment string
  18. UserRepo *repo.UserRepository
  19. }
  20. func NewDiscordController(userRepo *repo.UserRepository, hostName string, environment string) *DiscordController {
  21. return &DiscordController{
  22. MonaLisa: createBot("Mona Lisa", "discord.bot.mona-lisa.token"),
  23. ChaChing: createBot("Cha Ching", "discord.bot.cha-ching.token"),
  24. HostName: hostName,
  25. Environment: environment,
  26. UserRepo: userRepo,
  27. }
  28. }
  29. func createBot(name string, tokenConfigKey string) *discordgo.Session {
  30. silent := viper.GetBool("internal.silent")
  31. if silent {
  32. return nil
  33. }
  34. token := viper.GetString(tokenConfigKey)
  35. if token == "" {
  36. return nil
  37. }
  38. session, err := discordgo.New("Bot " + token)
  39. if err != nil {
  40. log.Warnf("Could not create Discord bot %s: %s", name, err)
  41. }
  42. return session
  43. }
  44. // The actual send
  45. func (c *DiscordController) sendMessage(bot *discordgo.Session, channel string, message string) {
  46. if bot == nil {
  47. log.Infof("Skipping sending Discord message: %s", message)
  48. return
  49. }
  50. _, err := bot.ChannelMessageSend(channel, message)
  51. if err != nil {
  52. log.Warnf("Could not send message {%s} to Discord channel {%s} due to error {%s}", message, channel, err)
  53. }
  54. }
  55. // Send a message related to server status or important events/errors.
  56. func (c *DiscordController) Notify(message string) {
  57. c.sendMessage(c.MonaLisa, viper.GetString("discord.bot.mona-lisa.channel"), message)
  58. }
  59. // Send a message related to subscriptions.
  60. func (c *DiscordController) NotifyNewSub(userID int64, paymentProvider string, amount string) {
  61. message := fmt.Sprintf("New subscriber via `%s`, after %s of signing up! 🫂 (%s)",
  62. paymentProvider, c.getTimeSinceSignUp(userID), amount)
  63. c.sendMessage(c.ChaChing, viper.GetString("discord.bot.cha-ching.channel"), message)
  64. }
  65. // Send a message related to subscriptions.
  66. func (c *DiscordController) NotifyBlackFridayUser(userID int64, amount string) {
  67. message := fmt.Sprintf("BlackFriday subscription purchased after %s of signing up! 🫂 (%s)",
  68. c.getTimeSinceSignUp(userID), amount)
  69. c.sendMessage(c.ChaChing, viper.GetString("discord.bot.cha-ching.channel"), message)
  70. }
  71. // Convenience wrappers over the primitive notify types.
  72. //
  73. // By keeping them separate we later allow them to be routed easily to different
  74. // Discord channels.
  75. func (c *DiscordController) NotifyStartup() {
  76. c.Notify(c.HostName + " has taken off 🚀")
  77. }
  78. func (c *DiscordController) NotifyShutdown() {
  79. c.Notify(c.HostName + " is down ☠️")
  80. }
  81. func (c *DiscordController) NotifyAdminAction(message string) {
  82. c.Notify(message)
  83. }
  84. func (c *DiscordController) NotifyAccountDelete(userID int64, paymentProvider string, productID string) {
  85. message := fmt.Sprintf("User on %s (%s) initiated delete after using us for %s",
  86. paymentProvider, productID, c.getTimeSinceSignUp(userID))
  87. c.Notify(message)
  88. }
  89. func (c *DiscordController) NotifyPotentialAbuse(message string) {
  90. c.Notify(fmt.Sprintf("%s: %s", c.HostName, message))
  91. }
  92. func (c *DiscordController) getTimeSinceSignUp(userID int64) string {
  93. timeSinceSignUp := "unknown time"
  94. user, err := c.UserRepo.GetUserByIDInternal(userID)
  95. if err != nil {
  96. log.Error(err)
  97. } else {
  98. since := time.Since(time.UnixMicro(user.CreationTime))
  99. timeSinceSignUp = t.DaysOrHoursOrMinutes(since)
  100. }
  101. return timeSinceSignUp
  102. }