From 3381e6d5dfd6983ebe324041c87ac8b5c26d4692 Mon Sep 17 00:00:00 2001 From: manoj Date: Sat, 26 Nov 2022 17:43:39 +0530 Subject: [PATCH] otp, email and other improvement added --- .env.test | 8 +- Makefile | 6 +- .../db/providers/couchbase/email_template.go | 142 +++++++++++++++++- server/db/providers/couchbase/env.go | 31 +++- server/db/providers/couchbase/otp.go | 89 ++++++++++- server/db/providers/couchbase/provider.go | 5 +- server/db/providers/couchbase/session.go | 9 ++ server/db/providers/couchbase/user.go | 44 +++--- .../couchbase/verification_requests.go | 32 +++- server/db/providers/couchbase/webhook.go | 3 +- server/db/providers/couchbase/webhook_log.go | 39 ++++- server/test/resolvers_test.go | 12 +- server/test/revoke_access_test.go | 2 + 13 files changed, 365 insertions(+), 57 deletions(-) diff --git a/.env.test b/.env.test index 0df0238..50124dc 100644 --- a/.env.test +++ b/.env.test @@ -1,6 +1,10 @@ ENV=test -DATABASE_URL=test.db -DATABASE_TYPE=sqlite +DATABASE_TYPE=couchbase +COUCHBASE_SCOPE=_default +DATABASE_USERNAME=admin +DATABASE_PASSWORD=123456 +COUCHBASE_BUCKET=auth +DATABASE_URL=couchbase://127.0.0.1 CUSTOM_ACCESS_TOKEN_SCRIPT="function(user,tokenPayload){var data = tokenPayload;data.extra = {'x-extra-id': user.id};return data;}" SMTP_HOST=smtp.mailtrap.io SMTP_PORT=2525 diff --git a/Makefile b/Makefile index fc1e5b9..046cd35 100644 --- a/Makefile +++ b/Makefile @@ -28,9 +28,9 @@ test-dynamodb: cd server && go clean --testcache && TEST_DBS="dynamodb" go test -p 1 -v ./test docker rm -vf dynamodb-local-test test-couchbase: - docker run -d --name couchbase-local-test -p 8091-8097:8091-8097 -p 11210:11210 -p 11207:11207 -p 18091-18095:18091-18095 -p 18096:18096 -p 18097:18097 couchbase:latest - cd server && go clean --testcache && TEST_DBS="couchdb" go test -p 1 -v ./test - docker rm -vf couchbase-local-test + # docker run -d --name couchbase-local-test -p 8091-8097:8091-8097 -p 11210:11210 -p 11207:11207 -p 18091-18095:18091-18095 -p 18096:18096 -p 18097:18097 couchbase:latest + cd server && go clean --testcache && TEST_DBS="couchbase" go test -p 1 -v ./test + # docker rm -vf couchbase-local-test test-all-db: rm -rf server/test/test.db && rm -rf test.db docker run -d --name authorizer_scylla_db -p 9042:9042 scylladb/scylla diff --git a/server/db/providers/couchbase/email_template.go b/server/db/providers/couchbase/email_template.go index 714b6be..7ca94db 100644 --- a/server/db/providers/couchbase/email_template.go +++ b/server/db/providers/couchbase/email_template.go @@ -2,15 +2,22 @@ package couchbase import ( "context" + "encoding/json" + "fmt" + "log" + "reflect" + "strings" "time" "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/graph/model" + "github.com/couchbase/gocb/v2" "github.com/google/uuid" ) // AddEmailTemplate to add EmailTemplate func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { + if emailTemplate.ID == "" { emailTemplate.ID = uuid.New().String() } @@ -18,31 +25,158 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.Em emailTemplate.Key = emailTemplate.ID emailTemplate.CreatedAt = time.Now().Unix() emailTemplate.UpdatedAt = time.Now().Unix() + insertOpt := gocb.InsertOptions{ + Context: ctx, + } + + _, err := p.db.Collection(models.Collections.EmailTemplate).Insert(emailTemplate.ID, emailTemplate, &insertOpt) + if err != nil { + return emailTemplate.AsAPIEmailTemplate(), err + } + return emailTemplate.AsAPIEmailTemplate(), nil } // UpdateEmailTemplate to update EmailTemplate func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) { - emailTemplate.UpdatedAt = time.Now().Unix() + scope := p.db.Scope("_default") + bytes, err := json.Marshal(emailTemplate) + if err != nil { + return nil, err + } + // use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling + decoder := json.NewDecoder(strings.NewReader(string(bytes))) + decoder.UseNumber() + emailTemplateMap := map[string]interface{}{} + err = decoder.Decode(&emailTemplateMap) + if err != nil { + return nil, err + } + + updateFields := "" + for key, value := range emailTemplateMap { + if key == "_id" { + continue + } + + if key == "_key" { + continue + } + + if value == nil { + updateFields += fmt.Sprintf("%s = null,", key) + continue + } + + valueType := reflect.TypeOf(value) + if valueType.Name() == "string" { + updateFields += fmt.Sprintf("%s = '%s', ", key, value.(string)) + } else { + updateFields += fmt.Sprintf("%s = %v, ", key, value) + } + } + updateFields = strings.Trim(updateFields, " ") + updateFields = strings.TrimSuffix(updateFields, ",") + + query := fmt.Sprintf("UPDATE auth._default.%s SET %s WHERE _id = '%s'", models.Collections.EmailTemplate, updateFields, emailTemplate.ID) + _, err = scope.Query(query, &gocb.QueryOptions{}) + if err != nil { + return nil, err + } return emailTemplate.AsAPIEmailTemplate(), nil } // ListEmailTemplates to list EmailTemplate func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) { - return nil, nil + emailTemplates := []*model.EmailTemplate{} + // r := p.db.Collection(models.Collections.User). + paginationClone := pagination + + scope := p.db.Scope("_default") + userQuery := fmt.Sprintf("SELECT _id, event_name, subject, design, template, created_at, updated_at FROM auth._default.%s ORDER BY _id OFFSET %d LIMIT %d", models.Collections.EmailTemplate, paginationClone.Offset, paginationClone.Limit) + + queryResult, err := scope.Query(userQuery, &gocb.QueryOptions{ + ScanConsistency: gocb.QueryScanConsistencyRequestPlus, + }) + + if err != nil { + return nil, err + } + + for queryResult.Next() { + emailTemplate := models.EmailTemplate{} + err := queryResult.Row(&emailTemplate) + if err != nil { + log.Fatal(err) + } + emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate()) + } + + if err := queryResult.Err(); err != nil { + return nil, err + + } + + return &model.EmailTemplates{ + Pagination: &paginationClone, + EmailTemplates: emailTemplates, + }, nil } // GetEmailTemplateByID to get EmailTemplate by id func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) { - return nil, nil + emailTemplate := models.EmailTemplate{} + time.Sleep(200 * time.Millisecond) + + scope := p.db.Scope("_default") + query := fmt.Sprintf(`SELECT _id, event_name, subject, design, template, created_at, updated_at FROM auth._default.%s WHERE _id = '%s' LIMIT 1`, models.Collections.EmailTemplate, emailTemplateID) + q, err := scope.Query(query, &gocb.QueryOptions{}) + + if err != nil { + return nil, err + } + err = q.One(&emailTemplate) + + if err != nil { + return nil, err + } + + return emailTemplate.AsAPIEmailTemplate(), nil } // GetEmailTemplateByEventName to get EmailTemplate by event_name func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) { - return nil, nil + emailTemplate := models.EmailTemplate{} + time.Sleep(200 * time.Millisecond) + + scope := p.db.Scope("_default") + query := fmt.Sprintf("SELECT _id, event_name, subject, design, template, created_at, updated_at FROM auth._default.%s WHERE event_name=$1 LIMIT 1", models.Collections.EmailTemplate) + q, err := scope.Query(query, &gocb.QueryOptions{ + Context: ctx, + PositionalParameters: []interface{}{eventName}, + }) + + if err != nil { + return nil, err + } + err = q.One(&emailTemplate) + + time.Sleep(20 * time.Second) + if err != nil { + return nil, err + } + + return emailTemplate.AsAPIEmailTemplate(), nil } // DeleteEmailTemplate to delete EmailTemplate func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error { + removeOpt := gocb.RemoveOptions{ + Context: ctx, + } + _, err := p.db.Collection(models.Collections.EmailTemplate).Remove(emailTemplate.ID, &removeOpt) + if err != nil { + return err + } return nil } diff --git a/server/db/providers/couchbase/env.go b/server/db/providers/couchbase/env.go index 6bc3f78..ad60180 100644 --- a/server/db/providers/couchbase/env.go +++ b/server/db/providers/couchbase/env.go @@ -2,9 +2,11 @@ package couchbase import ( "context" + "fmt" "time" "github.com/authorizerdev/authorizer/server/db/models" + "github.com/couchbase/gocb/v2" "github.com/google/uuid" ) @@ -13,21 +15,48 @@ func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, erro if env.ID == "" { env.ID = uuid.New().String() } - env.CreatedAt = time.Now().Unix() env.UpdatedAt = time.Now().Unix() + env.Key = env.ID + + insertOpt := gocb.InsertOptions{ + Context: ctx, + } + _, err := p.db.Collection(models.Collections.Env).Insert(env.ID, env, &insertOpt) + if err != nil { + return env, err + } return env, nil } // UpdateEnv to update environment information in database func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) { env.UpdatedAt = time.Now().Unix() + scope := p.db.Scope("_default") + + updateEnvQuery := fmt.Sprintf("UPDATE auth._default.%s SET env = '%s', updated_at = %d WHERE _id = '%s'", models.Collections.Env, env.EnvData, env.UpdatedAt, env.ID) + _, err := scope.Query(updateEnvQuery, &gocb.QueryOptions{}) + + if err != nil { + return env, err + } + return env, nil } // GetEnv to get environment information from database func (p *provider) GetEnv(ctx context.Context) (models.Env, error) { var env models.Env + scope := p.db.Scope("_default") + query := fmt.Sprintf("SELECT _id, env, created_at, updated_at FROM auth._default.%s LIMIT 1", models.Collections.Env) + q, err := scope.Query(query, &gocb.QueryOptions{}) + if err != nil { + return env, err + } + err = q.One(&env) + if err != nil { + return env, err + } return env, nil } diff --git a/server/db/providers/couchbase/otp.go b/server/db/providers/couchbase/otp.go index 6447ccf..dac3766 100644 --- a/server/db/providers/couchbase/otp.go +++ b/server/db/providers/couchbase/otp.go @@ -2,21 +2,104 @@ package couchbase import ( "context" + "fmt" + "time" "github.com/authorizerdev/authorizer/server/db/models" + "github.com/couchbase/gocb/v2" + "github.com/google/uuid" ) // UpsertOTP to add or update otp -func (p *provider) UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP, error) { - return nil, nil +func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) { + // otp, _ = p.GetOTPByEmail(ctx, otp.Email) + // if otp == nil { + // id := uuid.NewString() + // otp = &models.OTP{ + // ID: id, + // Key: id, + // Otp: otp.Otp, + // Email: otp.Email, + // ExpiresAt: otp.ExpiresAt, + // CreatedAt: time.Now().Unix(), + // } + // } + + // otp.UpdatedAt = time.Now().Unix() + // unsertOpt := gocb.UpsertOptions{ + // Context: ctx, + // } + // _, err := p.db.Collection(models.Collections.OTP).Upsert(otp.ID, otp, &unsertOpt) + // if err != nil { + // return nil, err + // } + + // return otp, nil + otp, _ := p.GetOTPByEmail(ctx, otpParam.Email) + + shouldCreate := false + if otp == nil { + shouldCreate = true + otp = &models.OTP{ + ID: uuid.NewString(), + Otp: otpParam.Otp, + Email: otpParam.Email, + ExpiresAt: otpParam.ExpiresAt, + CreatedAt: time.Now().Unix(), + UpdatedAt: time.Now().Unix(), + } + } else { + otp.Otp = otpParam.Otp + otp.ExpiresAt = otpParam.ExpiresAt + } + + otp.UpdatedAt = time.Now().Unix() + if shouldCreate { + insertOpt := gocb.InsertOptions{ + Context: ctx, + } + _, err := p.db.Collection(models.Collections.OTP).Insert(otp.ID, otp, &insertOpt) + if err != nil { + return otp, err + } + } else { + query := fmt.Sprintf(`UPDATE auth._default.%s SET otp = '%s', expires_at = %d, updated_at = %d WHERE id = '%s'`, models.Collections.OTP, otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID) + scope := p.db.Scope("_default") + _, err := scope.Query(query, &gocb.QueryOptions{}) + if err != nil { + return otp, err + } + } + return otp, nil } // GetOTPByEmail to get otp for a given email address func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) { - return nil, nil + otp := models.OTP{} + query := fmt.Sprintf(`SELECT _id, email, otp, expires_at, created_at, updated_at FROM auth._default.%s WHERE email = '%s' LIMIT 1`, models.Collections.OTP, emailAddress) + q, err := p.db.Scope("_default").Query(query, &gocb.QueryOptions{ + ScanConsistency: gocb.QueryScanConsistencyRequestPlus, + }) + if err != nil { + return nil, err + } + err = q.One(&otp) + + if err != nil { + return nil, err + } + + return &otp, nil } // DeleteOTP to delete otp func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error { + removeOpt := gocb.RemoveOptions{ + Context: ctx, + } + _, err := p.db.Collection(models.Collections.OTP).Remove(otp.ID, &removeOpt) + if err != nil { + return err + } return nil } diff --git a/server/db/providers/couchbase/provider.go b/server/db/providers/couchbase/provider.go index d32ba14..97a83d4 100644 --- a/server/db/providers/couchbase/provider.go +++ b/server/db/providers/couchbase/provider.go @@ -34,7 +34,6 @@ func NewProvider() (*provider, error) { if err != nil { return nil, err } - bucket := cluster.Bucket(bucketName) v := reflect.ValueOf(models.Collections) @@ -47,9 +46,9 @@ func NewProvider() (*provider, error) { collectionOpts := gocb.CreateCollectionOptions{ Context: context.TODO(), } - bucket.Collections().CreateCollection(user, &collectionOpts) + _ = bucket.Collections().CreateCollection(user, &collectionOpts) } - // bucket.Collection(models.Collections.User).Insert() + return &provider{ db: bucket, }, nil diff --git a/server/db/providers/couchbase/session.go b/server/db/providers/couchbase/session.go index ea150a6..6f0d84f 100644 --- a/server/db/providers/couchbase/session.go +++ b/server/db/providers/couchbase/session.go @@ -5,6 +5,7 @@ import ( "time" "github.com/authorizerdev/authorizer/server/db/models" + "github.com/couchbase/gocb/v2" "github.com/google/uuid" ) @@ -16,6 +17,14 @@ func (p *provider) AddSession(ctx context.Context, session models.Session) error session.CreatedAt = time.Now().Unix() session.UpdatedAt = time.Now().Unix() + insertOpt := gocb.InsertOptions{ + Context: ctx, + } + _, err := p.db.Collection(models.Collections.Session).Insert(session.ID, session, &insertOpt) + if err != nil { + return err + } + return nil } diff --git a/server/db/providers/couchbase/user.go b/server/db/providers/couchbase/user.go index 2577409..a5b356e 100644 --- a/server/db/providers/couchbase/user.go +++ b/server/db/providers/couchbase/user.go @@ -59,9 +59,9 @@ func (p *provider) DeleteUser(ctx context.Context, user models.User) error { removeOpt := gocb.RemoveOptions{ Context: ctx, } + _, err := p.db.Collection(models.Collections.User).Remove(user.ID, &removeOpt) // query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+models.Collections.User, fields, values) - // sessionCollection := p.db.Collection(models.Collections.Session).Queue() // _, err = sessionCollection.DeleteMany(ctx, bson.M{"user_id": user.ID}, options.Delete()) // if err != nil { @@ -110,45 +110,36 @@ func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) ( // GetUserByEmail to get user information from database using email address func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) { - var user models.User - // inventoryScope := p.db.Scope("_default") - // userQuery := fmt.Sprintf("SELECT * FROM auth._default.%s WHERE email = '%s' LIMIT %d", models.Collections.User, email, 1) - queryResult, err := p.db.Collection(models.Collections.User).Get("email:"+email, &gocb.GetOptions{}) - if err != nil { - return user, err - } - - // queryResult, err := inventoryScope.Query(userQuery, &gocb.QueryOptions{}) - err = queryResult.Content(&user) + user := models.User{} + scope := p.db.Scope("_default") + query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM auth._default.%s WHERE email = '%s' LIMIT 1", models.Collections.User, email) + q, err := scope.Query(query, &gocb.QueryOptions{}) if err != nil { return user, err } - - // for queryResult.Next() { - // var user models.User - // err := queryResult.Row(&user) - // if err != nil { - // log.Fatal(err) - // } - // return user, nil - // } + err = q.One(&user) + if err != nil { + return user, err + } return user, nil } // GetUserByID to get user information from database using user ID func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) { - var user models.User - queryResult, err := p.db.Collection(models.Collections.User).Get("id:"+id, &gocb.GetOptions{}) + user := models.User{} + scope := p.db.Scope("_default") + query := fmt.Sprintf("SELECT _id, email, email_verified_at, `password`, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM auth._default.%s WHERE _id = '%s' LIMIT 1", models.Collections.User, id) + q, err := scope.Query(query, &gocb.QueryOptions{}) + if err != nil { + return user, err + } + err = q.One(&user) if err != nil { return user, err } - err = queryResult.Content(&user) - if err != nil { - return user, err - } return user, nil } @@ -185,6 +176,7 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, if ids != nil && len(ids) > 0 { for _, v := range ids { userQuery := fmt.Sprintf("UPDATE auth._default.%s SET %s WHERE id = '%s'", models.Collections.User, updateFields, v) + _, err := inventoryScope.Query(userQuery, &gocb.QueryOptions{}) if err != nil { return err diff --git a/server/db/providers/couchbase/verification_requests.go b/server/db/providers/couchbase/verification_requests.go index 87840d5..7456e3c 100644 --- a/server/db/providers/couchbase/verification_requests.go +++ b/server/db/providers/couchbase/verification_requests.go @@ -18,6 +18,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque verificationRequest.ID = uuid.New().String() } + verificationRequest.Key = verificationRequest.ID verificationRequest.CreatedAt = time.Now().Unix() verificationRequest.UpdatedAt = time.Now().Unix() insertOpt := gocb.InsertOptions{ @@ -33,15 +34,22 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque // GetVerificationRequestByToken to get verification request from database using token func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) { - var verificationRequest models.VerificationRequest + verificationRequest := models.VerificationRequest{} scope := p.db.Scope("_default") + params := make(map[string]interface{}, 1) + params["token"] = token + query := fmt.Sprintf("SELECT _id, token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM auth._default.%s WHERE token=$1 LIMIT 1", models.Collections.VerificationRequest) + + queryResult, err := scope.Query(query, &gocb.QueryOptions{ + Context: ctx, + PositionalParameters: []interface{}{token}, + }) - query := fmt.Sprintf("SELECT _id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM auth._default.%s WHERE token = '%s' LIMIT 1", models.Collections.VerificationRequest, token) - queryResult, err := scope.Query(query, &gocb.QueryOptions{}) if err != nil { return verificationRequest, err } err = queryResult.One(&verificationRequest) + if err != nil { return verificationRequest, err } @@ -50,15 +58,23 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri // GetVerificationRequestByEmail to get verification request by email from database func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) { - var verificationRequest models.VerificationRequest - scope := p.db.Scope("_default") - query := fmt.Sprintf("SELECT _id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM auth._default.%s WHERE email = '%s' AND identifier = '%s' LIMIT 1", models.Collections.VerificationRequest, email, identifier) - queryResult, err := scope.Query(query, &gocb.QueryOptions{}) + scope := p.db.Scope("_default") + time.Sleep(200 * time.Millisecond) + + query := fmt.Sprintf("SELECT _id, identifier, token, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM auth._default.%s WHERE email=$1 AND identifier=$2 LIMIT 1", models.Collections.VerificationRequest) + queryResult, err := scope.Query(query, &gocb.QueryOptions{ + Context: ctx, + PositionalParameters: []interface{}{email, identifier}, + }) + verificationRequest := models.VerificationRequest{} + if err != nil { return verificationRequest, err } + err = queryResult.One(&verificationRequest) + if err != nil { return verificationRequest, err } @@ -101,7 +117,7 @@ func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRe removeOpt := gocb.RemoveOptions{ Context: ctx, } - _, err := p.db.Collection(models.Collections.Webhook).Remove(verificationRequest.ID, &removeOpt) + _, err := p.db.Collection(models.Collections.VerificationRequest).Remove(verificationRequest.ID, &removeOpt) if err != nil { return err } diff --git a/server/db/providers/couchbase/webhook.go b/server/db/providers/couchbase/webhook.go index f13d6e8..7414995 100644 --- a/server/db/providers/couchbase/webhook.go +++ b/server/db/providers/couchbase/webhook.go @@ -94,7 +94,7 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) scope := p.db.Scope("_default") paginationClone := pagination - query := fmt.Sprintf("SELECT _id, env, created_at, updated_at FROM auth._default.%s OFFSET %d LIMIT %d", models.Collections.Env, paginationClone.Offset, paginationClone.Limit) + query := fmt.Sprintf("SELECT _id, env, created_at, updated_at FROM auth._default.%s OFFSET %d LIMIT %d", models.Collections.Webhook, paginationClone.Offset, paginationClone.Limit) queryResult, err := scope.Query(query, &gocb.QueryOptions{}) if err != nil { @@ -143,6 +143,7 @@ func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) scope := p.db.Scope("_default") query := fmt.Sprintf(`SELECT _id, event_name, endpoint, headers, enabled, created_at, updated_at FROM auth._default.%s WHERE event_name = '%s' LIMIT 1`, models.Collections.Webhook, eventName) q, err := scope.Query(query, &gocb.QueryOptions{}) + if err != nil { return nil, err } diff --git a/server/db/providers/couchbase/webhook_log.go b/server/db/providers/couchbase/webhook_log.go index 7080db1..b7d046f 100644 --- a/server/db/providers/couchbase/webhook_log.go +++ b/server/db/providers/couchbase/webhook_log.go @@ -2,10 +2,13 @@ package couchbase import ( "context" + "fmt" + "log" "time" "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/graph/model" + "github.com/couchbase/gocb/v2" "github.com/google/uuid" ) @@ -18,10 +21,44 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookL webhookLog.Key = webhookLog.ID webhookLog.CreatedAt = time.Now().Unix() webhookLog.UpdatedAt = time.Now().Unix() + + insertOpt := gocb.InsertOptions{ + Context: ctx, + } + _, err := p.db.Collection(models.Collections.WebhookLog).Insert(webhookLog.ID, webhookLog, &insertOpt) + if err != nil { + return webhookLog.AsAPIWebhookLog(), err + } + return webhookLog.AsAPIWebhookLog(), nil } // ListWebhookLogs to list webhook logs func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) { - return nil, nil + webhookLogs := []*model.WebhookLog{} + scope := p.db.Scope("_default") + paginationClone := pagination + query := fmt.Sprintf("SELECT _id, env, created_at, updated_at FROM auth._default.%s OFFSET %d LIMIT %d", models.Collections.Env, paginationClone.Offset, paginationClone.Limit) + queryResult, err := scope.Query(query, &gocb.QueryOptions{}) + + if err != nil { + return nil, err + } + for queryResult.Next() { + var webhookLog models.WebhookLog + err := queryResult.Row(&webhookLog) + if err != nil { + log.Fatal(err) + } + webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog()) + } + + if err := queryResult.Err(); err != nil { + return nil, err + + } + return &model.WebhookLogs{ + Pagination: &paginationClone, + WebhookLogs: webhookLogs, + }, nil } diff --git a/server/test/resolvers_test.go b/server/test/resolvers_test.go index 1fc6060..6e662c7 100644 --- a/server/test/resolvers_test.go +++ b/server/test/resolvers_test.go @@ -16,11 +16,12 @@ import ( func TestResolvers(t *testing.T) { databases := map[string]string{ - constants.DbTypeSqlite: "../../test.db", - constants.DbTypeArangodb: "http://localhost:8529", - constants.DbTypeMongodb: "mongodb://localhost:27017", - constants.DbTypeScyllaDB: "127.0.0.1:9042", - constants.DbTypeDynamoDB: "http://127.0.0.1:8000", + constants.DbTypeSqlite: "../../test.db", + constants.DbTypeArangodb: "http://localhost:8529", + constants.DbTypeMongodb: "mongodb://localhost:27017", + constants.DbTypeScyllaDB: "127.0.0.1:9042", + constants.DbTypeDynamoDB: "http://127.0.0.1:8000", + constants.DbTypeCouchbaseDB: "couchbase://127.0.0.1", } testDBs := strings.Split(os.Getenv("TEST_DBS"), ",") @@ -44,6 +45,7 @@ func TestResolvers(t *testing.T) { defer s.Server.Close() for dbType, dbURL := range databases { + ctx := context.Background() memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabaseURL, dbURL) diff --git a/server/test/revoke_access_test.go b/server/test/revoke_access_test.go index 4223a0d..9560697 100644 --- a/server/test/revoke_access_test.go +++ b/server/test/revoke_access_test.go @@ -3,6 +3,7 @@ package test import ( "fmt" "testing" + "time" "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/crypto" @@ -22,6 +23,7 @@ func revokeAccessTest(t *testing.T, s TestSetup) { Email: email, }) assert.NoError(t, err) + time.Sleep(4 * time.Second) verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeMagicLinkLogin) verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ Token: verificationRequest.Token,