Skip to content

Commit

Permalink
kyc/quiz: fix cooldown for failed sessions
Browse files Browse the repository at this point in the history
  • Loading branch information
ice-dionysos committed Jan 13, 2024
1 parent 94e9f71 commit 06a29f9
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 9 deletions.
29 changes: 20 additions & 9 deletions kyc/quiz/quiz.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,17 @@ func (r *repositoryImpl) SkipQuizSession(ctx context.Context, userID UserID) err
return err
}

now := stdlibtime.Now()
now := time.Now()
for _, fn := range []func(context.Context, UserID, stdlibtime.Time, storage.QueryExecer) error{
r.CheckUserFailedSession,
r.CheckUserActiveSession,
} {
if err := fn(ctx, userID, now, r.DB); err != nil {
if err := fn(ctx, userID, *now.Time, r.DB); err != nil {
return err
}
}

return errors.Wrapf(r.UserMarkSessionAsFinished(ctx, userID, now, r.DB, false, true),
return errors.Wrapf(r.UserMarkSessionAsFinished(ctx, userID, *now.Time, r.DB, false, true),
"failed to UserMarkSessionAsFinished for userID:%v", userID)
}

Expand Down Expand Up @@ -147,11 +147,12 @@ select max(ended_at) as ended_at from failed_quiz_sessions where user_id = $1 ha

func (r *repositoryImpl) CheckUserActiveSession(ctx context.Context, userID UserID, now stdlibtime.Time, tx storage.QueryExecer) error {
type userSession struct {
StartedAt stdlibtime.Time `db:"started_at"`
Finished bool `db:"finished"`
FinishedSuccessfully bool `db:"ended_successfully"`
StartedAt time.Time `db:"started_at"`
EndedAt *time.Time `db:"ended_at"`
Finished bool `db:"finished"`
FinishedSuccessfully bool `db:"ended_successfully"`
}
const stmt = `select started_at, ended_at is not null as finished, ended_successfully from quiz_sessions where user_id = $1`
const stmt = `select started_at, ended_at, ended_at is not null as finished, ended_successfully from quiz_sessions where user_id = $1`

data, err := storage.Get[userSession](ctx, tx, stmt, userID)
if err != nil {
Expand All @@ -167,7 +168,10 @@ func (r *repositoryImpl) CheckUserActiveSession(ctx context.Context, userID User
return ErrSessionFinished
}

return ErrSessionFinishedWithError
cooldown := data.EndedAt.Add(stdlibtime.Duration(r.config.SessionCoolDownSeconds) * stdlibtime.Second)
if cooldown.After(now) {
return ErrSessionFinishedWithError
}
}

deadline := data.StartedAt.Add(stdlibtime.Duration(r.config.MaxSessionDurationSeconds) * stdlibtime.Second)
Expand Down Expand Up @@ -285,6 +289,7 @@ func (r *repositoryImpl) StartQuizSession(ctx context.Context, userID UserID, la
select
quiz_sessions.started_at,
quiz_sessions.started_at + make_interval(secs => $5) as deadline,
quiz_sessions.ended_at,
quiz_sessions.ended_at is not null as finished,
quiz_sessions.ended_successfully
from
Expand All @@ -305,7 +310,11 @@ func (r *repositoryImpl) StartQuizSession(ctx context.Context, userID UserID, la
'{}'::smallint[]
where
coalesce((select false from session_failed), true) and
coalesce((select finished is false and session_active.deadline < now() from session_active), true)
coalesce((select
(finished is false and session_active.deadline < now()) or
(finished is true and ended_successfully is false and ((ended_at + make_interval(secs => $4)) < now()))
from
session_active), true)
on conflict on constraint quiz_sessions_pkey do
update
set
Expand All @@ -325,6 +334,7 @@ func (r *repositoryImpl) StartQuizSession(ctx context.Context, userID UserID, la
session_active.deadline as active_deadline,
session_active.finished as active_finished,
session_active.ended_successfully as active_ended_successfully,
session_active.ended_at as active_ended_at,
session_upsert.started_at as upsert_started_at,
session_upsert.deadline as upsert_deadline
from
Expand All @@ -340,6 +350,7 @@ func (r *repositoryImpl) StartQuizSession(ctx context.Context, userID UserID, la
ActiveDeadline *time.Time `db:"active_deadline"`
ActiveFinished *bool `db:"active_finished"`
ActiveEndedSuccessfully *bool `db:"active_ended_successfully"`
ActiveEndedAt *time.Time `db:"active_ended_at"`
UpsertStartedAt *time.Time `db:"upsert_started_at"`
UpsertDeadline *time.Time `db:"upsert_deadline"`
}](ctx, r.DB, stmt, userID, lang, questionsToSlice(questions), r.config.SessionCoolDownSeconds, r.config.MaxSessionDurationSeconds)
Expand Down
7 changes: 7 additions & 0 deletions kyc/quiz/quiz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,13 @@ func testManagerSessionStart(ctx context.Context, t *testing.T, r *repositoryImp
_, err := r.StartQuizSession(ctx, "bogus", "en")
require.ErrorIs(t, err, ErrSessionFinishedWithError)
})
t.Run("CoolDown", func(t *testing.T) {
helperForceFinishSession(t, r, "bogus", false)
_, err := storage.Exec(ctx, r.DB, "update quiz_sessions set started_at = to_timestamp(40), ended_at = to_timestamp(42), ended_successfully = false where user_id = $1", "bogus")
require.NoError(t, err)
_, err = r.StartQuizSession(ctx, "bogus", "en")
require.NoError(t, err)
})
})
t.Run("Expired", func(t *testing.T) {
helperForceResetSessionStartedAt(t, r, "bogus")
Expand Down

0 comments on commit 06a29f9

Please sign in to comment.