ente/server/pkg/controller/email/email_notification.go
2024-03-01 13:37:01 +05:30

158 lines
5.8 KiB
Go

package email
import (
"fmt"
"strconv"
"github.com/avct/uasurfer"
"github.com/ente-io/museum/pkg/controller/lock"
"github.com/ente-io/museum/pkg/repo"
"github.com/ente-io/museum/pkg/utils/email"
"github.com/ente-io/museum/pkg/utils/time"
log "github.com/sirupsen/logrus"
)
const (
WebAppFirstUploadTemplate = "web_app_first_upload.html"
MobileAppFirstUploadTemplate = "mobile_app_first_upload.html"
FirstUploadEmailSubject = "Congratulations! 🎉"
StorageLimitExceededMailLock = "storage_limit_exceeded_mail_lock"
StorageLimitExceededTemplateID = "storage_limit_exceeded"
StorageLimitExceededTemplate = "storage_limit_exceeded.html"
FilesCollectedTemplate = "files_collected.html"
FilesCollectedTemplateID = "files_collected"
FilesCollectedSubject = "You've got photos!"
SubscriptionUpgradedTemplate = "subscription_upgraded.html"
SubscriptionUpgradedSubject = "Thank you for choosing ente!"
FilesCollectedMuteDurationInMinutes = 10
StorageLimitExceededSubject = "[Alert] You have exceeded your storage limit"
ReferralSuccessfulTemplate = "successful_referral.html"
ReferralSuccessfulSubject = "You've earned 10 GB on ente! 🎁"
)
type EmailNotificationController struct {
UserRepo *repo.UserRepository
LockController *lock.LockController
NotificationHistoryRepo *repo.NotificationHistoryRepository
isSendingStorageLimitExceededMails bool
}
func (c *EmailNotificationController) OnFirstFileUpload(userID int64, userAgent string) {
user, err := c.UserRepo.Get(userID)
if err != nil {
return
}
os := getOSFromUA(userAgent)
template := WebAppFirstUploadTemplate
if os == uasurfer.OSAndroid || os == uasurfer.OSiOS {
template = MobileAppFirstUploadTemplate
}
err = email.SendTemplatedEmail([]string{user.Email}, "team@ente.io", "team@ente.io", FirstUploadEmailSubject, template, nil, nil)
if err != nil {
log.Error("Error sending first upload email ", err)
}
}
func getOSFromUA(ua string) uasurfer.OSName {
return uasurfer.Parse(ua).OS.Name
}
func (c *EmailNotificationController) OnSuccessfulReferral(userID int64) {
user, err := c.UserRepo.Get(userID)
if err != nil {
return
}
err = email.SendTemplatedEmail([]string{user.Email}, "team@ente.io", "team@ente.io", ReferralSuccessfulSubject, ReferralSuccessfulTemplate, nil, nil)
if err != nil {
log.Error("Error sending first upload email ", err)
}
}
func (c *EmailNotificationController) OnFilesCollected(userID int64) {
user, err := c.UserRepo.Get(userID)
if err != nil {
return
}
lastNotificationTime, err := c.NotificationHistoryRepo.GetLastNotificationTime(userID, FilesCollectedTemplateID)
logger := log.WithFields(log.Fields{
"user_id": userID,
})
if err != nil {
logger.Error("Could not fetch last notification time", err)
return
}
if lastNotificationTime > time.MicrosecondsAfterMinutes(-FilesCollectedMuteDurationInMinutes) {
logger.Info("Not notifying user about a collected file")
return
}
lockName := "files_collected_" + strconv.FormatInt(userID, 10)
lockStatus := c.LockController.TryLock(lockName, time.MicrosecondsAfterMinutes(FilesCollectedMuteDurationInMinutes))
if !lockStatus {
log.Error("Could not acquire lock to send file collected mails")
return
}
defer c.LockController.ReleaseLock(lockName)
logger.Info("Notifying about files collected")
err = email.SendTemplatedEmail([]string{user.Email}, "team@ente.io", "team@ente.io", FilesCollectedSubject, FilesCollectedTemplate, nil, nil)
if err != nil {
log.Error("Error sending files collected email ", err)
}
c.NotificationHistoryRepo.SetLastNotificationTimeToNow(userID, FilesCollectedTemplateID)
}
func (c *EmailNotificationController) OnAccountUpgrade(userID int64) {
user, err := c.UserRepo.Get(userID)
if err != nil {
log.Error("Could not find user to email", err)
return
}
log.Info(fmt.Sprintf("Emailing on account upgrade %d", user.ID))
err = email.SendTemplatedEmail([]string{user.Email}, "team@ente.io", "team@ente.io", SubscriptionUpgradedSubject, SubscriptionUpgradedTemplate, nil, nil)
if err != nil {
log.Error("Error sending files collected email ", err)
}
}
func (c *EmailNotificationController) SendStorageLimitExceededMails() {
if c.isSendingStorageLimitExceededMails {
log.Info("Skipping sending storage limit exceeded mails as another instance is still running")
return
}
c.setStorageLimitExceededMailerJobStatus(true)
defer c.setStorageLimitExceededMailerJobStatus(false)
lockStatus := c.LockController.TryLock(StorageLimitExceededMailLock, time.MicrosecondsAfterHours(24))
if !lockStatus {
log.Error("Could not acquire lock to send storage limit exceeded mails")
return
}
defer c.LockController.ReleaseLock(StorageLimitExceededMailLock)
users, err := c.UserRepo.GetUsersWithIndividualPlanWhoHaveExceededStorageQuota()
if err != nil {
log.Error("Error while fetching user list", err)
return
}
for _, u := range users {
lastNotificationTime, err := c.NotificationHistoryRepo.GetLastNotificationTime(u.ID, StorageLimitExceededTemplateID)
logger := log.WithFields(log.Fields{
"user_id": u.ID,
})
if err != nil {
logger.Error("Could not fetch last notification time", err)
continue
}
if lastNotificationTime > 0 {
continue
}
logger.Info("Alerting about storage limit exceeded")
err = email.SendTemplatedEmail([]string{u.Email}, "team@ente.io", "team@ente.io", StorageLimitExceededSubject, StorageLimitExceededTemplate, nil, nil)
if err != nil {
logger.Info("Error notifying", err)
continue
}
c.NotificationHistoryRepo.SetLastNotificationTimeToNow(u.ID, StorageLimitExceededTemplateID)
}
}
func (c *EmailNotificationController) setStorageLimitExceededMailerJobStatus(isSending bool) {
c.isSendingStorageLimitExceededMails = isSending
}