mirror of
https://github.com/muety/wakapi.git
synced 2025-12-05 22:20:24 -08:00
fix: purge user durations as part of data cleanup (relates to #785)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
4
main.go
4
main.go
@@ -232,13 +232,13 @@ func main() {
|
||||
|
||||
// MVC Handlers
|
||||
summaryHandler := routes.NewSummaryHandler(summaryService, userService, keyValueService, durationService, aliasService)
|
||||
settingsHandler := routes.NewSettingsHandler(userService, heartbeatService, summaryService, aliasService, aggregationService, languageMappingService, projectLabelService, keyValueService, mailService)
|
||||
settingsHandler := routes.NewSettingsHandler(userService, heartbeatService, durationService, summaryService, aliasService, aggregationService, languageMappingService, projectLabelService, keyValueService, mailService)
|
||||
subscriptionHandler := routes.NewSubscriptionHandler(userService, mailService, keyValueService)
|
||||
projectsHandler := routes.NewProjectsHandler(userService, heartbeatService)
|
||||
homeHandler := routes.NewHomeHandler(userService, keyValueService)
|
||||
loginHandler := routes.NewLoginHandler(userService, mailService, keyValueService)
|
||||
imprintHandler := routes.NewImprintHandler(keyValueService)
|
||||
leaderboardHandler := condition.TernaryOperator[bool, routes.Handler](config.App.LeaderboardEnabled, routes.NewLeaderboardHandler(userService, leaderboardService), routes.NewNoopHandler())
|
||||
leaderboardHandler := condition.Ternary[bool, routes.Handler](config.App.LeaderboardEnabled, routes.NewLeaderboardHandler(userService, leaderboardService), routes.NewNoopHandler())
|
||||
|
||||
// Other Handlers
|
||||
relayHandler := relay.NewRelayHandler()
|
||||
|
||||
@@ -46,7 +46,7 @@ func init() {
|
||||
if err := tx.Migrator().CreateTable(&models.Duration{}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Exec("insert into durations(user_id, time, duration, project, language, editor, operating_system, machine, category, branch, entity, num_heartbeats, group_hash, timeout) select user_id, time, duration, project, language, editor, operating_system, machine, category, branch, entity, num_heartbeats, group_hash, timeout from durations_old").Error; err != nil {
|
||||
if err := tx.Exec("insert into durations(user_id, time, duration, project, language, editor, operating_system, machine, category, branch, entity, num_heartbeats, group_hash, timeout) select * from durations_old").Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Migrator().DropTable("durations_old"); err != nil {
|
||||
|
||||
@@ -21,3 +21,8 @@ func (m *DurationServiceMock) Regenerate(u *models.User, b bool) {
|
||||
|
||||
func (m *DurationServiceMock) RegenerateAll() {
|
||||
}
|
||||
|
||||
func (m *DurationServiceMock) DeleteByUser(u *models.User) error {
|
||||
args := m.Called(u)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ type SettingsHandler struct {
|
||||
userSrvc services.IUserService
|
||||
summarySrvc services.ISummaryService
|
||||
heartbeatSrvc services.IHeartbeatService
|
||||
durationSrvc services.IDurationService
|
||||
aliasSrvc services.IAliasService
|
||||
aggregationSrvc services.IAggregationService
|
||||
languageMappingSrvc services.ILanguageMappingService
|
||||
@@ -60,6 +61,7 @@ var credentialsDecoder = schema.NewDecoder()
|
||||
func NewSettingsHandler(
|
||||
userService services.IUserService,
|
||||
heartbeatService services.IHeartbeatService,
|
||||
durationService services.IDurationService,
|
||||
summaryService services.ISummaryService,
|
||||
aliasService services.IAliasService,
|
||||
aggregationService services.IAggregationService,
|
||||
@@ -77,6 +79,7 @@ func NewSettingsHandler(
|
||||
projectLabelSrvc: projectLabelService,
|
||||
userSrvc: userService,
|
||||
heartbeatSrvc: heartbeatService,
|
||||
durationSrvc: durationService,
|
||||
keyValueSrvc: keyValueService,
|
||||
mailSrvc: mailService,
|
||||
httpClient: &http.Client{Timeout: 10 * time.Second},
|
||||
@@ -750,6 +753,11 @@ func (h *SettingsHandler) actionClearData(w http.ResponseWriter, r *http.Request
|
||||
conf.Log().Request(r).Error("failed to clear summaries", "error", err)
|
||||
}
|
||||
|
||||
slog.Info("deleting durations for user", "userID", user.ID)
|
||||
if err := h.durationSrvc.DeleteByUser(user); err != nil {
|
||||
conf.Log().Request(r).Error("failed to clear durations", "error", err)
|
||||
}
|
||||
|
||||
slog.Info("deleting heartbeats for user", "userID", user.ID)
|
||||
if err := h.heartbeatSrvc.DeleteByUser(user); err != nil {
|
||||
conf.Log().Request(r).Error("failed to clear heartbeats", "error", err)
|
||||
|
||||
@@ -22,10 +22,10 @@ const generateDurationsInterval = 12 * time.Hour
|
||||
type DurationService struct {
|
||||
config *config.Config
|
||||
eventBus *hub.Hub
|
||||
durationRepository repositories.IDurationRepository
|
||||
repository repositories.IDurationRepository
|
||||
heartbeatService IHeartbeatService
|
||||
userService IUserService
|
||||
LanguageMappingService ILanguageMappingService
|
||||
languageMappingService ILanguageMappingService
|
||||
lastUserJob map[string]time.Time
|
||||
queue *artifex.Dispatcher
|
||||
}
|
||||
@@ -36,8 +36,8 @@ func NewDurationService(durationRepository repositories.IDurationRepository, hea
|
||||
eventBus: config.EventBus(),
|
||||
heartbeatService: heartbeatService,
|
||||
userService: userService,
|
||||
LanguageMappingService: languageMappingService,
|
||||
durationRepository: durationRepository,
|
||||
languageMappingService: languageMappingService,
|
||||
repository: durationRepository,
|
||||
lastUserJob: make(map[string]time.Time),
|
||||
queue: config.GetQueue(config.QueueProcessing),
|
||||
}
|
||||
@@ -109,7 +109,7 @@ func (srv *DurationService) Get(from, to time.Time, user *models.User, filters *
|
||||
|
||||
func (srv *DurationService) Regenerate(user *models.User, forceAll bool) {
|
||||
var from time.Time
|
||||
latest, err := srv.durationRepository.GetLatestByUser(user)
|
||||
latest, err := srv.repository.GetLatestByUser(user)
|
||||
if err == nil && latest != nil && !forceAll {
|
||||
from = latest.TimeEnd()
|
||||
}
|
||||
@@ -126,13 +126,13 @@ func (srv *DurationService) Regenerate(user *models.User, forceAll bool) {
|
||||
}
|
||||
|
||||
if forceAll {
|
||||
if err := srv.durationRepository.DeleteByUser(user); err != nil {
|
||||
if err := srv.repository.DeleteByUser(user); err != nil {
|
||||
config.Log().Error("failed to delete old durations while generating ephemeral new ones", "user", user.ID, "error", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := srv.durationRepository.InsertBatch(durations); err != nil {
|
||||
if err := srv.repository.InsertBatch(durations); err != nil {
|
||||
config.Log().Error("failed to persist new ephemeral durations for user", "user", user.ID, "error", err)
|
||||
return
|
||||
}
|
||||
@@ -154,12 +154,16 @@ func (srv *DurationService) RegenerateAll() {
|
||||
}
|
||||
}
|
||||
|
||||
func (srv *DurationService) DeleteByUser(user *models.User) error {
|
||||
return srv.repository.DeleteByUser(user)
|
||||
}
|
||||
|
||||
func (srv *DurationService) getCached(from, to time.Time, user *models.User, filters *models.Filters) (models.Durations, error) {
|
||||
languageMappings, err := srv.LanguageMappingService.ResolveByUser(user.ID)
|
||||
languageMappings, err := srv.languageMappingService.ResolveByUser(user.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
durations, err := srv.durationRepository.GetAllWithinByFilters(from, to, user, srv.filtersToColumnMap(filters))
|
||||
durations, err := srv.repository.GetAllWithinByFilters(from, to, user, srv.filtersToColumnMap(filters))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@ type IDurationService interface {
|
||||
Get(time.Time, time.Time, *models.User, *models.Filters, *time.Duration, bool) (models.Durations, error)
|
||||
Regenerate(*models.User, bool)
|
||||
RegenerateAll()
|
||||
DeleteByUser(*models.User) error
|
||||
}
|
||||
|
||||
type ISummaryService interface {
|
||||
|
||||
Reference in New Issue
Block a user