Skip to content

Commit

Permalink
fixed trigger issue in kyc/quiz
Browse files Browse the repository at this point in the history
  • Loading branch information
ice-ares committed Feb 2, 2024
1 parent 5bf9437 commit cfe98ff
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 34 deletions.
15 changes: 15 additions & 0 deletions cmd/eskimo-hut/api/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,12 @@ const docTemplate = `{
"name": "X-Account-Metadata",
"in": "header"
},
{
"type": "string",
"description": "the type of the client calling this API. I.E. ` + "`" + `web` + "`" + `",
"name": "x_client_type",
"in": "query"
},
{
"type": "string",
"description": "ID of the user",
Expand Down Expand Up @@ -1708,6 +1714,9 @@ const docTemplate = `{
"kycQuizAvailabilityEndedAt": {
"type": "string"
},
"kycQuizAvailabilityStartedAt": {
"type": "string"
},
"kycQuizAvailable": {
"type": "boolean"
},
Expand Down Expand Up @@ -2042,6 +2051,9 @@ const docTemplate = `{
"kycQuizAvailabilityEndedAt": {
"type": "string"
},
"kycQuizAvailabilityStartedAt": {
"type": "string"
},
"kycQuizAvailable": {
"type": "boolean"
},
Expand Down Expand Up @@ -2208,6 +2220,9 @@ const docTemplate = `{
"kycQuizAvailabilityEndedAt": {
"type": "string"
},
"kycQuizAvailabilityStartedAt": {
"type": "string"
},
"kycQuizAvailable": {
"type": "boolean"
},
Expand Down
15 changes: 15 additions & 0 deletions cmd/eskimo-hut/api/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,12 @@
"name": "X-Account-Metadata",
"in": "header"
},
{
"type": "string",
"description": "the type of the client calling this API. I.E. `web`",
"name": "x_client_type",
"in": "query"
},
{
"type": "string",
"description": "ID of the user",
Expand Down Expand Up @@ -1702,6 +1708,9 @@
"kycQuizAvailabilityEndedAt": {
"type": "string"
},
"kycQuizAvailabilityStartedAt": {
"type": "string"
},
"kycQuizAvailable": {
"type": "boolean"
},
Expand Down Expand Up @@ -2036,6 +2045,9 @@
"kycQuizAvailabilityEndedAt": {
"type": "string"
},
"kycQuizAvailabilityStartedAt": {
"type": "string"
},
"kycQuizAvailable": {
"type": "boolean"
},
Expand Down Expand Up @@ -2202,6 +2214,9 @@
"kycQuizAvailabilityEndedAt": {
"type": "string"
},
"kycQuizAvailabilityStartedAt": {
"type": "string"
},
"kycQuizAvailable": {
"type": "boolean"
},
Expand Down
10 changes: 10 additions & 0 deletions cmd/eskimo-hut/api/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ definitions:
type: string
kycQuizAvailabilityEndedAt:
type: string
kycQuizAvailabilityStartedAt:
type: string
kycQuizAvailable:
type: boolean
kycQuizCompleted:
Expand Down Expand Up @@ -334,6 +336,8 @@ definitions:
type: string
kycQuizAvailabilityEndedAt:
type: string
kycQuizAvailabilityStartedAt:
type: string
kycQuizAvailable:
type: boolean
kycQuizCompleted:
Expand Down Expand Up @@ -447,6 +451,8 @@ definitions:
properties:
kycQuizAvailabilityEndedAt:
type: string
kycQuizAvailabilityStartedAt:
type: string
kycQuizAvailable:
type: boolean
kycQuizCompleted:
Expand Down Expand Up @@ -917,6 +923,10 @@ paths:
in: header
name: X-Account-Metadata
type: string
- description: the type of the client calling this API. I.E. `web`
in: query
name: x_client_type
type: string
- description: ID of the user
in: path
name: userId
Expand Down
6 changes: 4 additions & 2 deletions cmd/eskimo-hut/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,10 @@ type (
SelectedOption *uint8 `form:"selectedOption" required:"true" swaggerignore:"true" example:"0"`
Language string `form:"language" required:"true" swaggerignore:"true" example:"en"`
}
CheckKYCStep4StatusRequestBody struct{}
TryResetKYCStepsRequestBody struct {
CheckKYCStep4StatusRequestBody struct {
XClientType string `form:"x_client_type" swaggerignore:"true" required:"false" example:"web"`
}
TryResetKYCStepsRequestBody struct {
Authorization string `header:"Authorization" swaggerignore:"true" required:"true" example:"some token"`
XAccountMetadata string `header:"X-Account-Metadata" swaggerignore:"true" required:"false" example:"some token"`
UserID string `uri:"userId" required:"true" allowForbiddenWriteOperation:"true" swaggerignore:"true" example:"did:ethr:0x4B73C58370AEfcEf86A6021afCDe5673511376B2"` //nolint:lll // .
Expand Down
4 changes: 3 additions & 1 deletion cmd/eskimo-hut/kyc.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ func (s *service) StartOrContinueKYCStep4Session( //nolint:gocritic,funlen // .
//
// @Param Authorization header string true "Insert your access token" default(Bearer <Add access token here>)
// @Param X-Account-Metadata header string false "Insert your metadata token" default(<Add metadata token here>)
// @Param x_client_type query string false "the type of the client calling this API. I.E. `web`"
// @Param userId path string true "ID of the user"
// @Success 200 {object} kycquiz.QuizStatus
// @Failure 400 {object} server.ErrorResponse "if validations fail"
Expand All @@ -146,6 +147,7 @@ func (s *service) CheckKYCStep4Status( //nolint:gocritic // .
ctx context.Context,
req *server.Request[CheckKYCStep4StatusRequestBody, kycquiz.QuizStatus],
) (*server.Response[kycquiz.QuizStatus], *server.Response[server.ErrorResponse]) {
ctx = kycquiz.ContextWithClientType(ctx, req.Data.XClientType) //nolint:revive // .
resp, err := s.quizRepository.CheckQuizStatus(ctx, req.AuthenticatedUser.UserID)
if err != nil {
return nil, server.Unexpected(errors.Wrapf(err, "failed to CheckQuizStatus for userID:%v", req.AuthenticatedUser.UserID))
Expand Down Expand Up @@ -242,7 +244,7 @@ func validateVerifySocialKYCStep(req *server.Request[kycsocial.VerificationMetad
// @Param Authorization header string true "Insert your access token" default(Bearer <Add access token here>)
// @Param X-Account-Metadata header string false "Insert your metadata token" default(<Add metadata token here>)
// @Param userId path string true "ID of the user"
// @Param skipKYCSteps query []int false "the kyc steps you wish to skip" collectionFormat(multi)
// @Param skipKYCSteps query []int false "the kyc steps you wish to skip" collectionFormat(multi)
// @Success 200 {object} User
// @Failure 400 {object} server.ErrorResponse "if validations fail"
// @Failure 401 {object} server.ErrorResponse "if not authorized"
Expand Down
31 changes: 24 additions & 7 deletions kyc/quiz/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@ type (
}

QuizStatus struct { //nolint:revive // Nope cuz we want to be able to embed this
KYCQuizAvailabilityEndedAt *time.Time `json:"kycQuizAvailabilityEndedAt" db:"kyc_quiz_availability_ended_at"`
KYCQuizResetAt []*time.Time `json:"kycQuizResetAt,omitempty" db:"kyc_quiz_reset_at"`
KYCQuizRemainingAttempts uint8 `json:"kycQuizRemainingAttempts,omitempty" db:"kyc_quiz_remaining_attempts"`
KYCQuizAvailable bool `json:"kycQuizAvailable" db:"kyc_quiz_available"`
KYCQuizDisabled bool `json:"kycQuizDisabled" db:"kyc_quiz_disabled"`
KYCQuizCompleted bool `json:"kycQuizCompleted" db:"kyc_quiz_completed"`
HasUnfinishedSessions bool `json:"-"`
KYCQuizAvailabilityStartedAt *time.Time `json:"kycQuizAvailabilityStartedAt" db:"kyc_quiz_availability_started_at"`
KYCQuizAvailabilityEndedAt *time.Time `json:"kycQuizAvailabilityEndedAt" db:"kyc_quiz_availability_ended_at"`
KYCQuizResetAt []*time.Time `json:"kycQuizResetAt,omitempty" db:"kyc_quiz_reset_at"`
KYCQuizRemainingAttempts uint8 `json:"kycQuizRemainingAttempts,omitempty" db:"kyc_quiz_remaining_attempts"`
KYCQuizAvailable bool `json:"kycQuizAvailable" db:"kyc_quiz_available"`
KYCQuizDisabled bool `json:"kycQuizDisabled" db:"kyc_quiz_disabled"`
KYCQuizCompleted bool `json:"kycQuizCompleted" db:"kyc_quiz_completed"`
HasUnfinishedSessions bool `json:"-"`
}

Result string
Expand Down Expand Up @@ -90,6 +91,8 @@ var (
const (
applicationYamlKey = "kyc/quiz"

clientTypeCtxValueKey = "clientTypeCtxValueKey"

requestDeadline = 25 * stdlibtime.Second
)

Expand Down Expand Up @@ -118,9 +121,23 @@ type (
Users UserRepository
config
}

kycConfigJSON struct {
QuizKYC struct {
DisabledVersions []string `json:"disabledVersions"`
ForceKYCForUserIds []string `json:"forceKYCForUserIds"` //nolint:tagliatelle // .
Enabled bool `json:"enabled"`
} `json:"quiz-kyc"` //nolint:tagliatelle // .
WebQuizKYC struct {
Enabled bool `json:"enabled"`
} `json:"web-quiz-kyc"` //nolint:tagliatelle // .
}

config struct {
alertFrequency *atomic.Pointer[stdlibtime.Duration]
kycConfigJSON *atomic.Pointer[kycConfigJSON]
globalStartDate *time.Time
ConfigJSONURL string `yaml:"config-json-url" mapstructure:"config-json-url"` //nolint:tagliatelle // .
MaxResetCount *uint8 `yaml:"maxResetCount"`
GlobalStartDate string `yaml:"globalStartDate" example:"YYYY-MM-DD"` //nolint:revive // .
Environment string `yaml:"environment" mapstructure:"environment"`
Expand Down
30 changes: 17 additions & 13 deletions kyc/quiz/quiz.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ func newError(msg string) error {
func NewRepository(ctx context.Context, userRepo UserRepository) Repository {
repo := newRepositoryImpl(ctx, userRepo)
go repo.startAlerter(ctx)
go repo.startKYCConfigJSONSyncer(ctx)

return repo
}
Expand Down Expand Up @@ -111,21 +112,18 @@ func (r *repositoryImpl) CheckUserKYC(ctx context.Context, userID UserID) error
return r.validateKycStep(profile.User)
}

//nolint:revive // .
func (r *repositoryImpl) validateKycStep(user *users.User) error {
if user.KYCStepBlocked != nil && *user.KYCStepBlocked >= users.QuizKYCStep {
if user.KYCStepBlocked != nil && *user.KYCStepBlocked > users.NoneKYCStep {
return ErrNotAvailable
}

if sessionCoolDown := stdlibtime.Duration(r.config.SessionCoolDownSeconds) * stdlibtime.Second; user.KYCStepPassed == nil ||
*user.KYCStepPassed < users.QuizKYCStep-1 ||
*user.KYCStepPassed < users.LivenessDetectionKYCStep ||
(user.KYCStepPassed != nil &&
*user.KYCStepPassed == users.QuizKYCStep-1 &&
user.KYCStepsLastUpdatedAt != nil &&
len(*user.KYCStepsLastUpdatedAt) >= int(users.QuizKYCStep) &&
!(*user.KYCStepsLastUpdatedAt)[users.QuizKYCStep-1].IsNil() &&
time.Now().Sub(*(*user.KYCStepsLastUpdatedAt)[users.QuizKYCStep-1].Time) < sessionCoolDown) ||
(user.KYCStepPassed != nil && *user.KYCStepPassed >= users.QuizKYCStep) {
time.Now().Sub(*(*user.KYCStepsLastUpdatedAt)[users.QuizKYCStep-1].Time) < sessionCoolDown) {
return ErrInvalidKYCState
}

Expand Down Expand Up @@ -267,6 +265,7 @@ func (r *repositoryImpl) getQuizStatus(ctx context.Context, userID UserID) (*Qui
(qr.user_id IS NOT NULL AND cardinality(qr.resets) > $4) AS kyc_quiz_disabled,
qr.resets AS kyc_quiz_reset_at,
(qs.user_id IS NOT NULL AND qs.ended_at is not null AND qs.ended_successfully = true) AS kyc_quiz_completed,
GREATEST(u.created_at,$2) AS kyc_quiz_availability_started_at,
GREATEST(u.created_at,$2) + (interval '1 second' * $3) AS kyc_quiz_availability_ended_at,
(u.kyc_step_passed >= 2 AND u.kyc_step_blocked = 0) AS kyc_quiz_available,
(qs.user_id IS NOT NULL AND qs.ended_at IS NULL) AS has_unfinished_sessions
Expand Down Expand Up @@ -296,6 +295,7 @@ func (r *repositoryImpl) getQuizStatus(ctx context.Context, userID UserID) (*Qui
if errors.Is(err, storage.ErrNotFound) {
err = ErrUnknownSession
}
quizStatus.KYCQuizAvailable = quizStatus.KYCQuizAvailable && r.isKYCEnabled(ctx)

return quizStatus, errors.Wrapf(err, "failed to exec CheckQuizStatus sql for userID:%v", userID)
}
Expand Down Expand Up @@ -822,6 +822,7 @@ func (r *repositoryImpl) fetchUserProfileForModify(ctx context.Context, userID U

usr := new(users.User)
usr.ID = userID
usr.KYCStepPassed = profile.KYCStepPassed
usr.KYCStepsLastUpdatedAt = profile.KYCStepsLastUpdatedAt
usr.KYCStepsCreatedAt = profile.KYCStepsCreatedAt

Expand All @@ -847,18 +848,21 @@ func (r *repositoryImpl) modifyUser(ctx context.Context, success, blocked bool,
usr.ID = user.ID

newKYCStep := users.QuizKYCStep
if success {
usr.KYCStepPassed = &newKYCStep
} else if blocked {
usr.KYCStepBlocked = &newKYCStep
if success || blocked {
if user.KYCStepPassed != nil && *user.KYCStepPassed == newKYCStep-1 {
usr.KYCStepPassed = &newKYCStep
}

if blocked {
usr.KYCStepBlocked = &newKYCStep
}
}

usr.KYCStepsLastUpdatedAt = user.KYCStepsLastUpdatedAt
if len(*usr.KYCStepsLastUpdatedAt) < int(newKYCStep) {
for len(*usr.KYCStepsLastUpdatedAt) < int(newKYCStep) {
*usr.KYCStepsLastUpdatedAt = append(*usr.KYCStepsLastUpdatedAt, now)
} else {
(*usr.KYCStepsLastUpdatedAt)[int(newKYCStep)-1] = now
}
(*usr.KYCStepsLastUpdatedAt)[int(newKYCStep)-1] = now

return errors.Wrapf(r.Users.ModifyUser(ctx, usr, nil), "failed to modify user %#v", usr)
}
Expand Down
Loading

0 comments on commit cfe98ff

Please sign in to comment.