dnote/pkg/server/job/digest/digest.go
Sung Won Cho 23a511dbe0
Improve package structure (#207)
* Improve package structure

* Set up travis
2019-06-25 19:20:19 +10:00

137 lines
3.9 KiB
Go

/* Copyright (C) 2019 Monomax Software Pty Ltd
*
* This file is part of Dnote.
*
* Dnote is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dnote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
*/
package digest
import (
"log"
"time"
"github.com/dnote/dnote/pkg/server/database"
"github.com/dnote/dnote/pkg/server/mailer"
"github.com/pkg/errors"
)
// Make builds a weekly digest email
func Make(user database.User, emailAddr string) (*mailer.Email, error) {
log.Printf("Sending for %s", emailAddr)
db := database.DBConn
subject := "Weekly Digest"
tok, err := mailer.GetEmailPreferenceToken(user)
if err != nil {
return nil, errors.Wrap(err, "getting email frequency token")
}
now := time.Now()
threshold1 := int(now.AddDate(0, 0, -1).UnixNano())
threshold2 := int(now.AddDate(0, 0, -3).UnixNano())
threshold3 := int(now.AddDate(0, 0, -7).UnixNano())
var stage1 []database.Note
var stage2 []database.Note
var stage3 []database.Note
// TODO: ordering by random() does not scale if table grows large
if err := db.Where("user_id = ? AND added_on > ? AND added_on < ?", user.ID, threshold2, threshold1).Order("random()").Limit(4).Preload("Book").Find(&stage1).Error; err != nil {
return nil, errors.Wrap(err, "Failed to get notes with threshold 1")
}
if err := db.Where("user_id = ? AND added_on > ? AND added_on < ?", user.ID, threshold3, threshold2).Order("random()").Limit(4).Preload("Book").Find(&stage2).Error; err != nil {
return nil, errors.Wrap(err, "Failed to get notes with threshold 2")
}
if err := db.Where("user_id = ? AND added_on < ?", user.ID, threshold3).Order("random()").Limit(4).Preload("Book").Find(&stage3).Error; err != nil {
return nil, errors.Wrap(err, "Failed to get notes with threshold 3")
}
notes := append(append(stage1, stage2...), stage3...)
digest := database.Digest{
UserID: user.ID,
Notes: notes,
}
if err := db.Save(&digest).Error; err != nil {
return nil, errors.Wrap(err, "saving digest")
}
bookCount := 0
bookMap := map[string]bool{}
for _, n := range notes {
if ok := bookMap[n.Book.Label]; !ok {
bookCount++
bookMap[n.Book.Label] = true
}
}
tmplData := mailer.DigestTmplData{
Subject: subject,
DigestUUID: digest.UUID,
ActiveBookCount: bookCount,
ActiveNoteCount: len(notes),
EmailSessionToken: tok.Value,
}
email := mailer.NewEmail("notebot@dnote.io", []string{emailAddr}, subject)
if err := email.ParseTemplate(mailer.EmailTypeWeeklyDigest, tmplData); err != nil {
return nil, err
}
return email, nil
}
// Send sends the weekly digests to users
func Send() error {
db := database.DBConn
var users []database.User
if err := db.
Preload("Account").
Where("cloud = ?", true).
Find(&users).Error; err != nil {
return err
}
for _, user := range users {
account := user.Account
if !account.Email.Valid || !account.EmailVerified {
continue
}
email, err := Make(user, account.Email.String)
if err != nil {
log.Printf("Error occurred while sending to %s: %s", account.Email.String, err.Error())
continue
}
err = email.Send()
if err != nil {
log.Printf("Error occurred while sending to %s: %s", account.Email.String, err.Error())
continue
}
notif := database.Notification{
Type: "email_weekly",
UserID: user.ID,
}
if err := db.Create(&notif).Error; err != nil {
log.Printf("Error occurred while creating notification for %s: %s", account.Email.String, err.Error())
}
}
return nil
}