|
|
@ -363,6 +363,114 @@ func (s *LogService) Delete(ctx context.Context, id string) (*models.Log, error) |
|
|
|
return log, nil |
|
|
|
} |
|
|
|
|
|
|
|
func (s *LogService) FixImportDateBug(ctx context.Context) error { |
|
|
|
start := time.Now() |
|
|
|
|
|
|
|
logs, err := s.logs.List(ctx, models.LogFilter{}) |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
eg := errgroup.Group{} |
|
|
|
for i := range logs { |
|
|
|
l := logs[i] |
|
|
|
|
|
|
|
eg.Go(func() error { |
|
|
|
return s.fixImportDateBug(ctx, *l) |
|
|
|
}) |
|
|
|
} |
|
|
|
err = eg.Wait() |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
log.Printf("Date import bug check finished: logs: %d, duration: %s", len(logs), time.Since(start)) |
|
|
|
|
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
func (s *LogService) fixImportDateBug(ctx context.Context, l models.Log) error { |
|
|
|
// Find the log's posts.
|
|
|
|
posts, err := s.ListPosts(ctx, &models.PostFilter{LogID: &l.ShortID}) |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
if len(posts) < 8 { |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
// Find first action post
|
|
|
|
first := posts[0] |
|
|
|
fi := 0 |
|
|
|
for first.Kind != "action" && first.Kind != "text" { |
|
|
|
fi++ |
|
|
|
if fi >= len(posts) { |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
first = posts[fi] |
|
|
|
} |
|
|
|
last := posts[len(posts)-1] |
|
|
|
if first == last { |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
// Stop here if this log probably isn't affected
|
|
|
|
if last.Time.Sub(first.Time) < time.Hour*72 { |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
// Find the first post past midnight.
|
|
|
|
midnight := first |
|
|
|
mi := fi |
|
|
|
for i, post := range posts[fi+1:] { |
|
|
|
if post.Time.Hour() < first.Time.Hour() { |
|
|
|
midnight = post |
|
|
|
mi = fi + 1 + i |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
|
if midnight == last { |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
if len(posts[mi+1:]) == 1 { |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
hits := 0 |
|
|
|
prev := midnight |
|
|
|
for _, offender := range posts[mi+1:] { |
|
|
|
if offender.Time.Day() != prev.Time.Day() { |
|
|
|
hits += 1 |
|
|
|
} |
|
|
|
|
|
|
|
prev = offender |
|
|
|
} |
|
|
|
if hits < ((len(posts[mi+1:]) * 3) / 4) { |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
for _, offender := range posts[mi+1:] { |
|
|
|
ot := offender.Time.UTC() |
|
|
|
mt := midnight.Time.UTC() |
|
|
|
|
|
|
|
y, m, d := mt.Date() |
|
|
|
hr, mi, se, ns := ot.Hour(), ot.Minute(), ot.Second(), ot.Nanosecond() |
|
|
|
|
|
|
|
newTime := time.Date(y, m, d, hr, mi, se, ns, time.UTC) |
|
|
|
|
|
|
|
_, err := s.posts.Update(ctx, *offender, models.PostUpdate{Time: &newTime}) |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
log.Printf("Fixed import date bug in %d posts in log %s", len(posts[mi+1:]), l.ID) |
|
|
|
|
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
func (s *LogService) RefreshAllLogCharacters(ctx context.Context) error { |
|
|
|
start := time.Now() |
|
|
|
|
|
|
|