1
0
mirror of https://github.com/muety/wakapi.git synced 2023-08-10 21:12:56 +03:00

chore: generate leaderboard when enabled in user settings

This commit is contained in:
Ferdinand Mütsch 2022-10-02 10:13:39 +02:00
parent 13a3d9f03a
commit 4a22a19cb0
7 changed files with 49 additions and 10 deletions

View File

@ -66,7 +66,7 @@ var env string
type appConfig struct { type appConfig struct {
AggregationTime string `yaml:"aggregation_time" default:"02:15" env:"WAKAPI_AGGREGATION_TIME"` AggregationTime string `yaml:"aggregation_time" default:"02:15" env:"WAKAPI_AGGREGATION_TIME"`
LeaderboardGenerationTime string `yaml:"leaderboard_generation_time" default:"06:00,18:00" env:"WAKAPI_LEADERBOARD_GENERATION_TIME"` LeaderboardGenerationTime string `yaml:"leaderboard_generation_time" default:"06:00;18:00" env:"WAKAPI_LEADERBOARD_GENERATION_TIME"`
ReportTimeWeekly string `yaml:"report_time_weekly" default:"fri,18:00" env:"WAKAPI_REPORT_TIME_WEEKLY"` ReportTimeWeekly string `yaml:"report_time_weekly" default:"fri,18:00" env:"WAKAPI_REPORT_TIME_WEEKLY"`
ImportBackoffMin int `yaml:"import_backoff_min" default:"5" env:"WAKAPI_IMPORT_BACKOFF_MIN"` ImportBackoffMin int `yaml:"import_backoff_min" default:"5" env:"WAKAPI_IMPORT_BACKOFF_MIN"`
ImportBatchSize int `yaml:"import_batch_size" default:"50" env:"WAKAPI_IMPORT_BATCH_SIZE"` ImportBatchSize int `yaml:"import_batch_size" default:"50" env:"WAKAPI_IMPORT_BATCH_SIZE"`

View File

@ -66,9 +66,10 @@ type CredentialsReset struct {
} }
type UserDataUpdate struct { type UserDataUpdate struct {
Email string `schema:"email"` Email string `schema:"email"`
Location string `schema:"location"` Location string `schema:"location"`
ReportsWeekly bool `schema:"reports_weekly"` ReportsWeekly bool `schema:"reports_weekly"`
PublicLeaderboard bool `schema:"public_leaderboard"`
} }
type TimeByUser struct { type TimeByUser struct {

View File

@ -24,6 +24,15 @@ func (r *LeaderboardRepository) InsertBatch(items []*models.LeaderboardItem) err
return nil return nil
} }
func (r *LeaderboardRepository) CountAllByUser(userId string) (int64, error) {
var count int64
err := r.db.
Table("leaderboard_items").
Where("user_id = ?", userId).
Count(&count).Error
return count, err
}
func (r *LeaderboardRepository) GetAllAggregatedByInterval(key *models.IntervalKey, by *uint8) ([]*models.LeaderboardItem, error) { func (r *LeaderboardRepository) GetAllAggregatedByInterval(key *models.IntervalKey, by *uint8) ([]*models.LeaderboardItem, error) {
// TODO: distinct by (user, key) to filter out potential duplicates ? // TODO: distinct by (user, key) to filter out potential duplicates ?
var items []*models.LeaderboardItem var items []*models.LeaderboardItem

View File

@ -88,6 +88,7 @@ type IUserRepository interface {
type ILeaderboardRepository interface { type ILeaderboardRepository interface {
InsertBatch([]*models.LeaderboardItem) error InsertBatch([]*models.LeaderboardItem) error
CountAllByUser(string) (int64, error)
DeleteByUserAndInterval(string, *models.IntervalKey) error DeleteByUserAndInterval(string, *models.IntervalKey) error
GetAllAggregatedByInterval(*models.IntervalKey, *uint8) ([]*models.LeaderboardItem, error) GetAllAggregatedByInterval(*models.IntervalKey, *uint8) ([]*models.LeaderboardItem, error)
GetAggregatedByUserAndInterval(string, *models.IntervalKey, *uint8) ([]*models.LeaderboardItem, error) GetAggregatedByUserAndInterval(string, *models.IntervalKey, *uint8) ([]*models.LeaderboardItem, error)

View File

@ -182,6 +182,7 @@ func (h *SettingsHandler) actionUpdateUser(w http.ResponseWriter, r *http.Reques
user.Email = payload.Email user.Email = payload.Email
user.Location = payload.Location user.Location = payload.Location
user.ReportsWeekly = payload.ReportsWeekly user.ReportsWeekly = payload.ReportsWeekly
user.PublicLeaderboard = payload.PublicLeaderboard
if _, err := h.userSrvc.Update(user); err != nil { if _, err := h.userSrvc.Update(user); err != nil {
return http.StatusInternalServerError, "", conf.ErrInternalServerError return http.StatusInternalServerError, "", conf.ErrInternalServerError

View File

@ -2,6 +2,7 @@ package services
import ( import (
"github.com/emvi/logbuch" "github.com/emvi/logbuch"
"github.com/go-co-op/gocron"
"github.com/leandro-lugaresi/hub" "github.com/leandro-lugaresi/hub"
"github.com/muety/wakapi/config" "github.com/muety/wakapi/config"
"github.com/muety/wakapi/models" "github.com/muety/wakapi/models"
@ -21,7 +22,7 @@ type LeaderboardService struct {
} }
func NewLeaderboardService(leaderboardRepo repositories.ILeaderboardRepository, summaryService ISummaryService, userService IUserService) *LeaderboardService { func NewLeaderboardService(leaderboardRepo repositories.ILeaderboardRepository, summaryService ISummaryService, userService IUserService) *LeaderboardService {
return &LeaderboardService{ srv := &LeaderboardService{
config: config.Get(), config: config.Get(),
cache: cache.New(24*time.Hour, 24*time.Hour), cache: cache.New(24*time.Hour, 24*time.Hour),
eventBus: config.EventBus(), eventBus: config.EventBus(),
@ -29,6 +30,28 @@ func NewLeaderboardService(leaderboardRepo repositories.ILeaderboardRepository,
summaryService: summaryService, summaryService: summaryService,
userService: userService, userService: userService,
} }
onUserUpdate := srv.eventBus.Subscribe(0, config.EventUserUpdate)
go func(sub *hub.Subscription) {
for m := range sub.Receiver {
// generate leaderboard for updated user, if leaderboard enabled and none present, yet
user := m.Fields[config.FieldPayload].(*models.User)
if user.PublicLeaderboard {
exists, err := srv.ExistsAnyByUser(user.ID)
if err != nil {
config.Log().Error("failed to check existing leaderboards upon user update - %v", err)
}
if !exists {
logbuch.Info("generating leaderboard for '%s' after settings update", user.ID)
srv.Run([]*models.User{user}, models.IntervalPast7Days, []uint8{models.SummaryLanguage})
}
}
}
}(&onUserUpdate)
return srv
} }
func (srv *LeaderboardService) ScheduleDefault() { func (srv *LeaderboardService) ScheduleDefault() {
@ -42,11 +65,9 @@ func (srv *LeaderboardService) ScheduleDefault() {
srv.Run(users, interval, by) srv.Run(users, interval, by)
} }
runAllUsers(models.IntervalPast7Days, []uint8{models.SummaryLanguage}) s := gocron.NewScheduler(time.Local)
s.Every(1).Day().At(srv.config.App.LeaderboardGenerationTime).Do(runAllUsers, models.IntervalPast7Days, []uint8{models.SummaryLanguage})
//s := gocron.NewScheduler(time.Local) s.StartBlocking()
//s.Every(1).Day().At(srv.config.App.LeaderboardGenerationTime).Do(runAllUsers, models.IntervalPast7Days, []uint8{models.SummaryLanguage})
//s.StartBlocking()
} }
func (srv *LeaderboardService) Run(users []*models.User, interval *models.IntervalKey, by []uint8) error { func (srv *LeaderboardService) Run(users []*models.User, interval *models.IntervalKey, by []uint8) error {
@ -92,6 +113,11 @@ func (srv *LeaderboardService) Run(users []*models.User, interval *models.Interv
return nil return nil
} }
func (srv *LeaderboardService) ExistsAnyByUser(userId string) (bool, error) {
count, err := srv.repository.CountAllByUser(userId)
return count > 0, err
}
func (srv *LeaderboardService) GetByInterval(interval *models.IntervalKey) ([]*models.LeaderboardItem, error) { func (srv *LeaderboardService) GetByInterval(interval *models.IntervalKey) ([]*models.LeaderboardItem, error) {
return srv.GetAggregatedByInterval(interval, nil) return srv.GetAggregatedByInterval(interval, nil)
} }

View File

@ -100,6 +100,7 @@ type IReportService interface {
type ILeaderboardService interface { type ILeaderboardService interface {
ScheduleDefault() ScheduleDefault()
Run([]*models.User, *models.IntervalKey, []uint8) error Run([]*models.User, *models.IntervalKey, []uint8) error
ExistsAnyByUser(string) (bool, error)
GetByInterval(*models.IntervalKey) ([]*models.LeaderboardItem, error) GetByInterval(*models.IntervalKey) ([]*models.LeaderboardItem, error)
GetAggregatedByInterval(*models.IntervalKey, *uint8) ([]*models.LeaderboardItem, error) GetAggregatedByInterval(*models.IntervalKey, *uint8) ([]*models.LeaderboardItem, error)
GenerateByUser(*models.User, *models.IntervalKey) (*models.LeaderboardItem, error) GenerateByUser(*models.User, *models.IntervalKey) (*models.LeaderboardItem, error)