Commit 355271cd authored by Andrei Mihu's avatar Andrei Mihu
Browse files

Report correct active periods in tournament listings if the start time is in the future.

parent b376c99e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ The format is based on [keep a changelog](http://keepachangelog.com) and this pr
- Use correct parameter type for creator ID in group update queries.
- Use correct parameter name for lang tag in group update queries.
- Do not allow users to send friend requests to the root user.
- Tournament listings now report correct active periods if the start time is in the future.

## [2.2.1] - 2018-11-20
### Added
+1 −1
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ func LeaderboardRecordsList(ctx context.Context, logger *zap.Logger, db *sql.DB,
	if expiryTime == 0 {
		now := time.Now().UTC()
		if leaderboard.IsTournament() {
			_, _, expiryTime = calculateTournamentDeadlines(leaderboard, now)
			_, _, expiryTime = calculateTournamentDeadlines(leaderboard.StartTime, leaderboard.EndTime, int64(leaderboard.Duration), leaderboard.ResetSchedule, now)
		} else if leaderboard.ResetSchedule != nil {
			expiryTime = leaderboard.ResetSchedule.Next(now).UTC().Unix()
		}
+26 −39
Original line number Diff line number Diff line
@@ -133,7 +133,7 @@ func TournamentJoin(ctx context.Context, logger *zap.Logger, db *sql.DB, cache L

	now := time.Now().UTC()
	nowUnix := now.Unix()
	_, endActive, expiryTime := calculateTournamentDeadlines(leaderboard, now)
	_, endActive, expiryTime := calculateTournamentDeadlines(leaderboard.StartTime, leaderboard.EndTime, int64(leaderboard.Duration), leaderboard.ResetSchedule, now)
	if endActive <= nowUnix {
		logger.Info("Cannot join tournament outside of tournament duration.")
		return ErrTournamentOutsideDuration
@@ -281,7 +281,7 @@ func TournamentRecordWrite(ctx context.Context, logger *zap.Logger, db *sql.DB,
	nowTime := time.Now().UTC()
	nowUnix := nowTime.Unix()

	startActiveUnix, endActiveUnix, expiryUnix := calculateTournamentDeadlines(leaderboard, nowTime)
	startActiveUnix, endActiveUnix, expiryUnix := calculateTournamentDeadlines(leaderboard.StartTime, leaderboard.EndTime, int64(leaderboard.Duration), leaderboard.ResetSchedule, nowTime)
	if startActiveUnix > nowUnix || endActiveUnix <= nowUnix {
		logger.Info("Cannot write tournament record as it is outside of tournament duration.", zap.String("id", leaderboard.Id))
		return nil, ErrTournamentOutsideDuration
@@ -456,38 +456,38 @@ func TournamentRecordsHaystack(ctx context.Context, logger *zap.Logger, db *sql.

	sortOrder := leaderboard.SortOrder

	_, _, expiry := calculateTournamentDeadlines(leaderboard, time.Now().UTC())
	_, _, expiry := calculateTournamentDeadlines(leaderboard.StartTime, leaderboard.EndTime, int64(leaderboard.Duration), leaderboard.ResetSchedule, time.Now().UTC())
	expiryTime := time.Unix(expiry, 0).UTC()

	return getLeaderboardRecordsHaystack(ctx, logger, db, rankCache, ownerId, limit, leaderboard.Id, sortOrder, expiryTime)
}

func calculateTournamentDeadlines(leaderboard *Leaderboard, t time.Time) (int64, int64, int64) {
	if leaderboard.ResetSchedule != nil {
		schedules := leaderboard.ResetSchedule.NextN(t, 2)
func calculateTournamentDeadlines(startTime, endTime, duration int64, resetSchedule *cronexpr.Expression, t time.Time) (int64, int64, int64) {
	if resetSchedule != nil {
		schedules := resetSchedule.NextN(t, 2)
		schedule0Unix := schedules[0].UTC().Unix()
		schedule1Unix := schedules[1].UTC().Unix()

		startActiveUnix := schedule0Unix - (schedule1Unix - schedule0Unix)
		endActiveUnix := startActiveUnix + int64(leaderboard.Duration)
		endActiveUnix := startActiveUnix + duration
		expiryUnix := schedule0Unix

		if leaderboard.StartTime > endActiveUnix {
		if startTime > endActiveUnix {
			// The start time after the end of the current active period but before the next reset.
			// e.g. Reset schedule is daily at noon, duration is 1 hour, but time is currently 3pm.
			startActiveUnix = leaderboard.ResetSchedule.Next(time.Unix(leaderboard.StartTime, 0).UTC()).UTC().Unix()
			endActiveUnix = startActiveUnix + int64(leaderboard.Duration)
			startActiveUnix = resetSchedule.Next(time.Unix(startTime, 0).UTC()).UTC().Unix()
			endActiveUnix = startActiveUnix + duration
			expiryUnix = startActiveUnix + (schedule1Unix - schedule0Unix)
		}

		return startActiveUnix, endActiveUnix, expiryUnix
	} else {
		endActiveUnix := int64(0)
		if leaderboard.StartTime <= t.Unix() {
			endActiveUnix = leaderboard.StartTime + int64(leaderboard.Duration)
		if startTime <= t.Unix() {
			endActiveUnix = startTime + duration
		}
		expiryUnix := leaderboard.EndTime
		return leaderboard.StartTime, endActiveUnix, expiryUnix
		expiryUnix := endTime
		return startTime, endActiveUnix, expiryUnix
	}
}

@@ -512,30 +512,17 @@ func parseTournament(scannable Scannable, now time.Time) (*api.Tournament, error
		return nil, err
	}

	canEnter := true
	endActive := int64(0)
	nextReset := int64(0)

	var resetSchedule *cronexpr.Expression
	if dbResetSchedule.Valid {
		cron := cronexpr.MustParse(dbResetSchedule.String)
		schedules := cron.NextN(now, 2)
		sessionStartTime := schedules[0].Unix() - (schedules[1].Unix() - schedules[0].Unix())

		if dbStartTime.Time.UTC().After(now) {
			endActive = 0
		} else {
			endActive = sessionStartTime + int64(dbDuration)
		}
		nextReset = schedules[0].Unix()
	} else {
		if dbStartTime.Time.UTC().After(now) {
			endActive = 0
		} else {
			endActive = dbStartTime.Time.UTC().Unix() + int64(dbDuration)
		}
		resetSchedule = cronexpr.MustParse(dbResetSchedule.String)
	}

	if endActive < now.Unix() {
	canEnter := true
	endTime := dbEndTime.Time.UTC().Unix()

	_, endActiveUnix, expiryUnix := calculateTournamentDeadlines(dbStartTime.Time.UTC().Unix(), endTime, int64(dbDuration), resetSchedule, now)

	if endActiveUnix < now.Unix() {
		canEnter = false
	}

@@ -553,16 +540,16 @@ func parseTournament(scannable Scannable, now time.Time) (*api.Tournament, error
		MaxSize:     uint32(dbMaxSize),
		MaxNumScore: uint32(dbMaxNumScore),
		CanEnter:    canEnter,
		EndActive:   uint32(endActive),
		NextReset:   uint32(nextReset),
		EndActive:   uint32(endActiveUnix),
		NextReset:   uint32(expiryUnix),
		Metadata:    dbMetadata,
		CreateTime:  &timestamp.Timestamp{Seconds: dbCreateTime.Time.UTC().Unix()},
		StartTime:   &timestamp.Timestamp{Seconds: dbStartTime.Time.UTC().Unix()},
		Duration:    uint32(dbDuration),
	}

	if dbEndTime.Time.Unix() > 0 {
		tournament.EndTime = &timestamp.Timestamp{Seconds: dbEndTime.Time.UTC().Unix()}
	if endTime > 0 {
		tournament.EndTime = &timestamp.Timestamp{Seconds: endTime}
	}

	return tournament, nil
+1 −1
Original line number Diff line number Diff line
@@ -154,7 +154,7 @@ func (ls *LocalLeaderboardScheduler) Update() {
	for _, l := range leaderboards {
		if l.Duration > 0 {
			// Tournament.
			_, endActive, expiry := calculateTournamentDeadlines(l, now)
			_, endActive, expiry := calculateTournamentDeadlines(l.StartTime, l.EndTime, int64(l.Duration), l.ResetSchedule, now)

			if l.EndTime > 0 && l.EndTime < nowUnix {
				// Tournament has ended permanently.