feat: add couchbase provider
This commit is contained in:
parent
b39f0b87fd
commit
44879f1a8f
|
@ -27,4 +27,6 @@ const (
|
||||||
DbTypePlanetScaleDB = "planetscale"
|
DbTypePlanetScaleDB = "planetscale"
|
||||||
// DbTypeDynamoDB is the Dynamo database type
|
// DbTypeDynamoDB is the Dynamo database type
|
||||||
DbTypeDynamoDB = "dynamodb"
|
DbTypeDynamoDB = "dynamodb"
|
||||||
|
// DbTypeCouchbaseDB is the Couchbase database type
|
||||||
|
DbTypeCouchbaseDB = "couchbase"
|
||||||
)
|
)
|
||||||
|
|
|
@ -43,6 +43,10 @@ const (
|
||||||
EnvKeyDatabaseCertKey = "DATABASE_CERT_KEY"
|
EnvKeyDatabaseCertKey = "DATABASE_CERT_KEY"
|
||||||
// EnvKeyDatabaseCACert key for env variable DATABASE_CA_CERT
|
// EnvKeyDatabaseCACert key for env variable DATABASE_CA_CERT
|
||||||
EnvKeyDatabaseCACert = "DATABASE_CA_CERT"
|
EnvKeyDatabaseCACert = "DATABASE_CA_CERT"
|
||||||
|
// EnvCouchbaseBucket key for env variable COUCHBASE_BUCKET
|
||||||
|
EnvCouchbaseBucket = "COUCHBASE_BUCKET"
|
||||||
|
// EnvCouchbaseBucket key for env variable COUCHBASE_SCOPE
|
||||||
|
EnvCouchbaseScope = "COUCHBASE_SCOPE"
|
||||||
// EnvKeySmtpHost key for env variable SMTP_HOST
|
// EnvKeySmtpHost key for env variable SMTP_HOST
|
||||||
EnvKeySmtpHost = "SMTP_HOST"
|
EnvKeySmtpHost = "SMTP_HOST"
|
||||||
// EnvKeySmtpPort key for env variable SMTP_PORT
|
// EnvKeySmtpPort key for env variable SMTP_PORT
|
||||||
|
|
|
@ -21,7 +21,7 @@ func InitDB() error {
|
||||||
|
|
||||||
envs := memorystore.RequiredEnvStoreObj.GetRequiredEnv()
|
envs := memorystore.RequiredEnvStoreObj.GetRequiredEnv()
|
||||||
|
|
||||||
isSQL := envs.DatabaseType != constants.DbTypeArangodb && envs.DatabaseType != constants.DbTypeMongodb && envs.DatabaseType != constants.DbTypeCassandraDB && envs.DatabaseType != constants.DbTypeScyllaDB && envs.DatabaseType != constants.DbTypeDynamoDB
|
isSQL := envs.DatabaseType != constants.DbTypeArangodb && envs.DatabaseType != constants.DbTypeMongodb && envs.DatabaseType != constants.DbTypeCassandraDB && envs.DatabaseType != constants.DbTypeScyllaDB && envs.DatabaseType != constants.DbTypeDynamoDB && envs.DatabaseType != constants.DbTypeCouchbaseDB
|
||||||
isArangoDB := envs.DatabaseType == constants.DbTypeArangodb
|
isArangoDB := envs.DatabaseType == constants.DbTypeArangodb
|
||||||
isMongoDB := envs.DatabaseType == constants.DbTypeMongodb
|
isMongoDB := envs.DatabaseType == constants.DbTypeMongodb
|
||||||
isCassandra := envs.DatabaseType == constants.DbTypeCassandraDB || envs.DatabaseType == constants.DbTypeScyllaDB
|
isCassandra := envs.DatabaseType == constants.DbTypeCassandraDB || envs.DatabaseType == constants.DbTypeScyllaDB
|
||||||
|
|
164
server/db/providers/couchbase/email_template.go
Normal file
164
server/db/providers/couchbase/email_template.go
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"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()
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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, params := GetSetFields(emailTemplateMap)
|
||||||
|
params["emailId"] = emailTemplate.ID
|
||||||
|
|
||||||
|
query := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id = $emailId", p.scopeName, models.Collections.EmailTemplate, updateFields)
|
||||||
|
|
||||||
|
_, err = p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
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) {
|
||||||
|
emailTemplates := []*model.EmailTemplate{}
|
||||||
|
paginationClone := pagination
|
||||||
|
|
||||||
|
_, paginationClone.Total = p.GetTotalDocs(ctx, models.Collections.EmailTemplate)
|
||||||
|
|
||||||
|
userQuery := fmt.Sprintf("SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s ORDER BY _id OFFSET $1 LIMIT $2", p.scopeName, models.Collections.EmailTemplate)
|
||||||
|
|
||||||
|
queryResult, err := p.db.Query(userQuery, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
PositionalParameters: []interface{}{paginationClone.Offset, paginationClone.Limit},
|
||||||
|
})
|
||||||
|
|
||||||
|
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) {
|
||||||
|
emailTemplate := models.EmailTemplate{}
|
||||||
|
|
||||||
|
query := fmt.Sprintf(`SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1`, p.scopeName, models.Collections.EmailTemplate)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
PositionalParameters: []interface{}{emailTemplateID},
|
||||||
|
})
|
||||||
|
|
||||||
|
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) {
|
||||||
|
emailTemplate := models.EmailTemplate{}
|
||||||
|
|
||||||
|
query := fmt.Sprintf("SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s WHERE event_name=$1 LIMIT 1", p.scopeName, models.Collections.EmailTemplate)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
PositionalParameters: []interface{}{eventName},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = q.One(&emailTemplate)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
67
server/db/providers/couchbase/env.go
Normal file
67
server/db/providers/couchbase/env.go
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddEnv to save environment information in database
|
||||||
|
func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
||||||
|
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()
|
||||||
|
|
||||||
|
updateEnvQuery := fmt.Sprintf("UPDATE %s.%s SET env = $1, updated_at = $2 WHERE _id = $3", p.scopeName, models.Collections.Env)
|
||||||
|
_, err := p.db.Query(updateEnvQuery, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{env.EnvData, env.UpdatedAt, env.UpdatedAt, env.ID},
|
||||||
|
})
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
query := fmt.Sprintf("SELECT _id, env, created_at, updated_at FROM %s.%s LIMIT 1", p.scopeName, models.Collections.Env)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return env, err
|
||||||
|
}
|
||||||
|
err = q.One(&env)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return env, err
|
||||||
|
}
|
||||||
|
return env, nil
|
||||||
|
}
|
84
server/db/providers/couchbase/otp.go
Normal file
84
server/db/providers/couchbase/otp.go
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
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, otpParam *models.OTP) (*models.OTP, error) {
|
||||||
|
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 %s.%s SET otp=$1, expires_at=$2, updated_at=$3 WHERE _id=$4`, p.scopeName, models.Collections.OTP)
|
||||||
|
_, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
PositionalParameters: []interface{}{otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID},
|
||||||
|
})
|
||||||
|
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) {
|
||||||
|
otp := models.OTP{}
|
||||||
|
query := fmt.Sprintf(`SELECT _id, email, otp, expires_at, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1`, p.scopeName, models.Collections.OTP)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
PositionalParameters: []interface{}{emailAddress},
|
||||||
|
})
|
||||||
|
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
|
||||||
|
}
|
151
server/db/providers/couchbase/provider.go
Normal file
151
server/db/providers/couchbase/provider.go
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO change following provider to new db provider
|
||||||
|
type provider struct {
|
||||||
|
db *gocb.Scope
|
||||||
|
scopeName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProvider returns a new SQL provider
|
||||||
|
// TODO change following provider to new db provider
|
||||||
|
func NewProvider() (*provider, error) {
|
||||||
|
// scopeName := os.Getenv(constants.EnvCouchbaseScope)
|
||||||
|
bucketName := os.Getenv(constants.EnvCouchbaseBucket)
|
||||||
|
scopeName := os.Getenv(constants.EnvCouchbaseScope)
|
||||||
|
|
||||||
|
dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL
|
||||||
|
userName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseUsername
|
||||||
|
password := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabasePassword
|
||||||
|
|
||||||
|
opts := gocb.ClusterOptions{
|
||||||
|
Username: userName,
|
||||||
|
Password: password,
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster, err := gocb.Connect(dbURL, opts)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// To create the bucket and scope if not exist
|
||||||
|
bucket, err := CreateBucketAndScope(cluster, bucketName, scopeName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
scope := bucket.Scope(scopeName)
|
||||||
|
|
||||||
|
scopeIdentifier := fmt.Sprintf("%s.%s", bucketName, scopeName)
|
||||||
|
|
||||||
|
v := reflect.ValueOf(models.Collections)
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
field := v.Field(i)
|
||||||
|
user := gocb.CollectionSpec{
|
||||||
|
Name: field.String(),
|
||||||
|
ScopeName: scopeName,
|
||||||
|
}
|
||||||
|
collectionOpts := gocb.CreateCollectionOptions{
|
||||||
|
Context: context.TODO(),
|
||||||
|
}
|
||||||
|
_ = bucket.Collections().CreateCollection(user, &collectionOpts)
|
||||||
|
// if err != nil && !errors.Is(err, gocb.ErrCollectionExists) {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
indexQuery := fmt.Sprintf("CREATE PRIMARY INDEX ON %s.%s", scopeIdentifier, field.String())
|
||||||
|
scope.Query(indexQuery, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
indices := GetIndex(scopeIdentifier)
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
field := v.Field(i)
|
||||||
|
for _, indexQuery := range indices[field.String()] {
|
||||||
|
scope.Query(indexQuery, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &provider{
|
||||||
|
db: scope,
|
||||||
|
scopeName: scopeIdentifier,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateBucketAndScope(cluster *gocb.Cluster, bucketName string, scopeName string) (*gocb.Bucket, error) {
|
||||||
|
settings := gocb.BucketSettings{
|
||||||
|
Name: bucketName,
|
||||||
|
RAMQuotaMB: 1000,
|
||||||
|
NumReplicas: 1,
|
||||||
|
BucketType: gocb.CouchbaseBucketType,
|
||||||
|
EvictionPolicy: gocb.EvictionPolicyTypeValueOnly,
|
||||||
|
FlushEnabled: true,
|
||||||
|
CompressionMode: gocb.CompressionModeActive,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := cluster.Buckets().CreateBucket(gocb.CreateBucketSettings{
|
||||||
|
BucketSettings: settings,
|
||||||
|
ConflictResolutionType: gocb.ConflictResolutionTypeSequenceNumber,
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
bucket := cluster.Bucket(bucketName)
|
||||||
|
|
||||||
|
if err != nil && !errors.Is(err, gocb.ErrBucketExists) {
|
||||||
|
return bucket, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bucket.Collections().CreateScope(scopeName, nil)
|
||||||
|
|
||||||
|
if err != nil && !errors.Is(err, gocb.ErrScopeExists) {
|
||||||
|
return bucket, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bucket, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetIndex(scopeName string) map[string][]string {
|
||||||
|
indices := make(map[string][]string)
|
||||||
|
|
||||||
|
// User Index
|
||||||
|
userIndex1 := fmt.Sprintf("CREATE INDEX userEmailIndex ON %s.%s(email)", scopeName, models.Collections.User)
|
||||||
|
userIndex2 := fmt.Sprintf("CREATE INDEX userPhoneIndex ON %s.%s(phone_number)", scopeName, models.Collections.User)
|
||||||
|
indices[models.Collections.User] = []string{userIndex1, userIndex2}
|
||||||
|
|
||||||
|
// VerificationRequest
|
||||||
|
verificationIndex1 := fmt.Sprintf("CREATE INDEX verificationRequestTokenIndex ON %s.%s(token)", scopeName, models.Collections.VerificationRequest)
|
||||||
|
verificationIndex2 := fmt.Sprintf("CREATE INDEX verificationRequestEmailAndIdentifierIndex ON %s.%s(email,identifier)", scopeName, models.Collections.VerificationRequest)
|
||||||
|
indices[models.Collections.VerificationRequest] = []string{verificationIndex1, verificationIndex2}
|
||||||
|
|
||||||
|
// Session index
|
||||||
|
sessionIndex1 := fmt.Sprintf("CREATE INDEX SessionUserIdIndex ON %s.%s(user_id)", scopeName, models.Collections.Session)
|
||||||
|
indices[models.Collections.Session] = []string{sessionIndex1}
|
||||||
|
|
||||||
|
// Webhook index
|
||||||
|
webhookIndex1 := fmt.Sprintf("CREATE INDEX webhookEventNameIndex ON %s.%s(event_name)", scopeName, models.Collections.Webhook)
|
||||||
|
indices[models.Collections.Webhook] = []string{webhookIndex1}
|
||||||
|
|
||||||
|
// WebhookLog index
|
||||||
|
webhookLogIndex1 := fmt.Sprintf("CREATE INDEX webhookLogIdIndex ON %s.%s(webhook_id)", scopeName, models.Collections.WebhookLog)
|
||||||
|
indices[models.Collections.Webhook] = []string{webhookLogIndex1}
|
||||||
|
|
||||||
|
// WebhookLog index
|
||||||
|
emailTempIndex1 := fmt.Sprintf("CREATE INDEX EmailTemplateEventNameIndex ON %s.%s(event_name)", scopeName, models.Collections.EmailTemplate)
|
||||||
|
indices[models.Collections.EmailTemplate] = []string{emailTempIndex1}
|
||||||
|
|
||||||
|
// OTP index
|
||||||
|
otpIndex1 := fmt.Sprintf("CREATE INDEX OTPEmailIndex ON %s.%s(email)", scopeName, models.Collections.OTP)
|
||||||
|
indices[models.Collections.OTP] = []string{otpIndex1}
|
||||||
|
|
||||||
|
return indices
|
||||||
|
}
|
34
server/db/providers/couchbase/session.go
Normal file
34
server/db/providers/couchbase/session.go
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddSession to save session information in database
|
||||||
|
func (p *provider) AddSession(ctx context.Context, session models.Session) error {
|
||||||
|
if session.ID == "" {
|
||||||
|
session.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSession to delete session information from database
|
||||||
|
func (p *provider) DeleteSession(ctx context.Context, userId string) error {
|
||||||
|
return nil
|
||||||
|
}
|
65
server/db/providers/couchbase/shared.go
Normal file
65
server/db/providers/couchbase/shared.go
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetSetFields(webhookMap map[string]interface{}) (string, map[string]interface{}) {
|
||||||
|
params := make(map[string]interface{}, 1)
|
||||||
|
|
||||||
|
updateFields := ""
|
||||||
|
|
||||||
|
for key, value := range webhookMap {
|
||||||
|
if key == "_id" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if key == "_key" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if value == nil {
|
||||||
|
updateFields += fmt.Sprintf("%s=$%s,", key, key)
|
||||||
|
params[key] = "null"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
valueType := reflect.TypeOf(value)
|
||||||
|
if valueType.Name() == "string" {
|
||||||
|
updateFields += fmt.Sprintf("%s = $%s, ", key, key)
|
||||||
|
params[key] = value.(string)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
updateFields += fmt.Sprintf("%s = $%s, ", key, key)
|
||||||
|
params[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateFields = strings.Trim(updateFields, " ")
|
||||||
|
updateFields = strings.TrimSuffix(updateFields, ",")
|
||||||
|
return updateFields, params
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provider) GetTotalDocs(ctx context.Context, collection string) (error, int64) {
|
||||||
|
totalDocs := TotalDocs{}
|
||||||
|
|
||||||
|
countQuery := fmt.Sprintf("SELECT COUNT(*) as Total FROM %s.%s", p.scopeName, collection)
|
||||||
|
queryRes, err := p.db.Query(countQuery, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
})
|
||||||
|
|
||||||
|
queryRes.One(&totalDocs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err, totalDocs.Total
|
||||||
|
}
|
||||||
|
return nil, totalDocs.Total
|
||||||
|
}
|
||||||
|
|
||||||
|
type TotalDocs struct {
|
||||||
|
Total int64
|
||||||
|
}
|
203
server/db/providers/couchbase/user.go
Normal file
203
server/db/providers/couchbase/user.go
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/couchbase/gocb/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddUser to save user information in database
|
||||||
|
func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) {
|
||||||
|
if user.ID == "" {
|
||||||
|
user.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.Roles == "" {
|
||||||
|
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
user.Roles = defaultRoles
|
||||||
|
}
|
||||||
|
|
||||||
|
user.CreatedAt = time.Now().Unix()
|
||||||
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
insertOpt := gocb.InsertOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.User).Insert(user.ID, user, &insertOpt)
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUser to update user information in database
|
||||||
|
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
||||||
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
unsertOpt := gocb.UpsertOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.User).Upsert(user.ID, user, &unsertOpt)
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteUser to delete user information from database
|
||||||
|
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)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListUsers to get list of users from database
|
||||||
|
func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
|
||||||
|
users := []*model.User{}
|
||||||
|
paginationClone := pagination
|
||||||
|
|
||||||
|
userQuery := 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 %s.%s ORDER BY id OFFSET $1 LIMIT $2", p.scopeName, models.Collections.User)
|
||||||
|
|
||||||
|
queryResult, err := p.db.Query(userQuery, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{paginationClone.Offset, paginationClone.Limit},
|
||||||
|
})
|
||||||
|
|
||||||
|
_, paginationClone.Total = p.GetTotalDocs(ctx, models.Collections.User)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for queryResult.Next() {
|
||||||
|
var user models.User
|
||||||
|
err := queryResult.Row(&user)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
users = append(users, user.AsAPIUser())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := queryResult.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return &model.Users{
|
||||||
|
Pagination: &paginationClone,
|
||||||
|
Users: users,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserByEmail to get user information from database using email address
|
||||||
|
func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) {
|
||||||
|
user := models.User{}
|
||||||
|
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 %s.%s WHERE email = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{email},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
user := models.User{}
|
||||||
|
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 %s.%s WHERE _id = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{id},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
err = q.One(&user)
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUsers to update multiple users, with parameters of user IDs slice
|
||||||
|
// If ids set to nil / empty all the users will be updated
|
||||||
|
func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error {
|
||||||
|
// set updated_at time for all users
|
||||||
|
data["updated_at"] = time.Now().Unix()
|
||||||
|
|
||||||
|
updateFields, params := GetSetFields(data)
|
||||||
|
|
||||||
|
if ids != nil && len(ids) > 0 {
|
||||||
|
for _, id := range ids {
|
||||||
|
params["id"] = id
|
||||||
|
userQuery := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id = $id", p.scopeName, models.Collections.User, updateFields)
|
||||||
|
|
||||||
|
_, err := p.db.Query(userQuery, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
Context: ctx,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
userQuery := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id IS NOT NULL", p.scopeName, models.Collections.User, updateFields)
|
||||||
|
_, err := p.db.Query(userQuery, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
Context: ctx,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var user *models.User
|
||||||
|
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 %s.%s WHERE phone_number = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{phoneNumber},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
err = q.One(&user)
|
||||||
|
if err != nil {
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
128
server/db/providers/couchbase/verification_requests.go
Normal file
128
server/db/providers/couchbase/verification_requests.go
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddVerification to save verification request in database
|
||||||
|
func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) {
|
||||||
|
if verificationRequest.ID == "" {
|
||||||
|
verificationRequest.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
verificationRequest.Key = verificationRequest.ID
|
||||||
|
verificationRequest.CreatedAt = time.Now().Unix()
|
||||||
|
verificationRequest.UpdatedAt = time.Now().Unix()
|
||||||
|
insertOpt := gocb.InsertOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.VerificationRequest).Insert(verificationRequest.ID, verificationRequest, &insertOpt)
|
||||||
|
if err != nil {
|
||||||
|
return verificationRequest, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return verificationRequest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVerificationRequestByToken to get verification request from database using token
|
||||||
|
func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) {
|
||||||
|
verificationRequest := models.VerificationRequest{}
|
||||||
|
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 %s.%s WHERE token=$1 LIMIT 1", p.scopeName, models.Collections.VerificationRequest)
|
||||||
|
|
||||||
|
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{token},
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return verificationRequest, err
|
||||||
|
}
|
||||||
|
err = queryResult.One(&verificationRequest)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return verificationRequest, err
|
||||||
|
}
|
||||||
|
return verificationRequest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVerificationRequestByEmail to get verification request by email from database
|
||||||
|
func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) {
|
||||||
|
|
||||||
|
query := fmt.Sprintf("SELECT _id, identifier, token, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s.%s WHERE email=$1 AND identifier=$2 LIMIT 1", p.scopeName, models.Collections.VerificationRequest)
|
||||||
|
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
PositionalParameters: []interface{}{email, identifier},
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
})
|
||||||
|
verificationRequest := models.VerificationRequest{}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return verificationRequest, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = queryResult.One(&verificationRequest)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return verificationRequest, err
|
||||||
|
}
|
||||||
|
return verificationRequest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListVerificationRequests to get list of verification requests from database
|
||||||
|
func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
|
||||||
|
var verificationRequests []*model.VerificationRequest
|
||||||
|
paginationClone := pagination
|
||||||
|
|
||||||
|
_, paginationClone.Total = p.GetTotalDocs(ctx, models.Collections.VerificationRequest)
|
||||||
|
|
||||||
|
query := fmt.Sprintf("SELECT _id, env, created_at, updated_at FROM %s.%s OFFSET $1 LIMIT $2", p.scopeName, models.Collections.VerificationRequest)
|
||||||
|
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
PositionalParameters: []interface{}{paginationClone.Offset, paginationClone.Limit},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for queryResult.Next() {
|
||||||
|
var verificationRequest models.VerificationRequest
|
||||||
|
err := queryResult.Row(&verificationRequest)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
verificationRequests = append(verificationRequests, verificationRequest.AsAPIVerificationRequest())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := queryResult.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
|
||||||
|
}
|
||||||
|
return &model.VerificationRequests{
|
||||||
|
VerificationRequests: verificationRequests,
|
||||||
|
Pagination: &paginationClone,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteVerificationRequest to delete verification request from database
|
||||||
|
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
|
||||||
|
removeOpt := gocb.RemoveOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.VerificationRequest).Remove(verificationRequest.ID, &removeOpt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
187
server/db/providers/couchbase/webhook.go
Normal file
187
server/db/providers/couchbase/webhook.go
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
package couchbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddWebhook to add webhook
|
||||||
|
func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
||||||
|
if webhook.ID == "" {
|
||||||
|
webhook.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
webhook.Key = webhook.ID
|
||||||
|
webhook.CreatedAt = time.Now().Unix()
|
||||||
|
webhook.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
insertOpt := gocb.InsertOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.Webhook).Insert(webhook.ID, webhook, &insertOpt)
|
||||||
|
if err != nil {
|
||||||
|
return webhook.AsAPIWebhook(), err
|
||||||
|
}
|
||||||
|
return webhook.AsAPIWebhook(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateWebhook to update webhook
|
||||||
|
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
|
||||||
|
webhook.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
bytes, err := json.Marshal(webhook)
|
||||||
|
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()
|
||||||
|
webhookMap := map[string]interface{}{}
|
||||||
|
err = decoder.Decode(&webhookMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFields, params := GetSetFields(webhookMap)
|
||||||
|
|
||||||
|
query := fmt.Sprintf(`UPDATE %s.%s SET %s WHERE _id='%s'`, p.scopeName, models.Collections.Webhook, updateFields, webhook.ID)
|
||||||
|
|
||||||
|
_, err = p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return webhook.AsAPIWebhook(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListWebhooks to list webhook
|
||||||
|
func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) {
|
||||||
|
webhooks := []*model.Webhook{}
|
||||||
|
paginationClone := pagination
|
||||||
|
|
||||||
|
params := make(map[string]interface{}, 1)
|
||||||
|
params["offset"] = paginationClone.Offset
|
||||||
|
params["limit"] = paginationClone.Limit
|
||||||
|
|
||||||
|
query := fmt.Sprintf("SELECT _id, env, created_at, updated_at FROM %s.%s OFFSET $offset LIMIT $limit", p.scopeName, models.Collections.Webhook)
|
||||||
|
|
||||||
|
_, paginationClone.Total = p.GetTotalDocs(ctx, models.Collections.Webhook)
|
||||||
|
|
||||||
|
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for queryResult.Next() {
|
||||||
|
var webhook models.Webhook
|
||||||
|
err := queryResult.Row(&webhook)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
webhooks = append(webhooks, webhook.AsAPIWebhook())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := queryResult.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
|
||||||
|
}
|
||||||
|
return &model.Webhooks{
|
||||||
|
Pagination: &paginationClone,
|
||||||
|
Webhooks: webhooks,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWebhookByID to get webhook by id
|
||||||
|
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
|
||||||
|
var webhook models.Webhook
|
||||||
|
|
||||||
|
params := make(map[string]interface{}, 1)
|
||||||
|
params["_id"] = webhookID
|
||||||
|
|
||||||
|
query := fmt.Sprintf(`SELECT _id, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s.%s WHERE _id=$_id LIMIT 1`, p.scopeName, models.Collections.Webhook)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = q.One(&webhook)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return webhook.AsAPIWebhook(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWebhookByEventName to get webhook by event_name
|
||||||
|
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
|
||||||
|
var webhook models.Webhook
|
||||||
|
params := make(map[string]interface{}, 1)
|
||||||
|
params["event_name"] = eventName
|
||||||
|
|
||||||
|
query := fmt.Sprintf(`SELECT _id, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s.%s WHERE event_name=$event_name LIMIT 1`, p.scopeName, models.Collections.Webhook)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = q.One(&webhook)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return webhook.AsAPIWebhook(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteWebhook to delete webhook
|
||||||
|
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
|
||||||
|
|
||||||
|
params := make(map[string]interface{}, 1)
|
||||||
|
params["webhook_id"] = webhook.ID
|
||||||
|
removeOpt := gocb.RemoveOptions{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
_, err := p.db.Collection(models.Collections.Webhook).Remove(webhook.ID, &removeOpt)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
query := fmt.Sprintf(`DELETE FROM %s.%s WHERE webhook_id=$webhook_id`, p.scopeName, models.Collections.WebhookLog)
|
||||||
|
_, err = p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
83
server/db/providers/couchbase/webhook_log.go
Normal file
83
server/db/providers/couchbase/webhook_log.go
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddWebhookLog to add webhook log
|
||||||
|
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) {
|
||||||
|
if webhookLog.ID == "" {
|
||||||
|
webhookLog.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
var query string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
webhookLogs := []*model.WebhookLog{}
|
||||||
|
params := make(map[string]interface{}, 1)
|
||||||
|
paginationClone := pagination
|
||||||
|
|
||||||
|
params["webhookID"] = webhookID
|
||||||
|
params["offset"] = paginationClone.Offset
|
||||||
|
params["limit"] = paginationClone.Limit
|
||||||
|
|
||||||
|
_, paginationClone.Total = p.GetTotalDocs(ctx, models.Collections.WebhookLog)
|
||||||
|
|
||||||
|
if webhookID != "" {
|
||||||
|
query = fmt.Sprintf(`SELECT _id, http_status, response, request, webhook_id, created_at, updated_at FROM %s.%s WHERE webhook_id=$webhookID`, p.scopeName, models.Collections.WebhookLog)
|
||||||
|
} else {
|
||||||
|
query = fmt.Sprintf("SELECT _id, http_status, response, request, webhook_id, created_at, updated_at FROM %s.%s OFFSET $offset LIMIT $limit", p.scopeName, models.Collections.WebhookLog)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
Context: ctx,
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
NamedParameters: params,
|
||||||
|
})
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ require (
|
||||||
github.com/arangodb/go-driver v1.2.1
|
github.com/arangodb/go-driver v1.2.1
|
||||||
github.com/aws/aws-sdk-go v1.44.109
|
github.com/aws/aws-sdk-go v1.44.109
|
||||||
github.com/coreos/go-oidc/v3 v3.1.0
|
github.com/coreos/go-oidc/v3 v3.1.0
|
||||||
|
github.com/couchbase/gocb/v2 v2.6.0 // indirect
|
||||||
github.com/gin-gonic/gin v1.8.1
|
github.com/gin-gonic/gin v1.8.1
|
||||||
github.com/glebarez/sqlite v1.5.0
|
github.com/glebarez/sqlite v1.5.0
|
||||||
github.com/go-playground/validator/v10 v10.11.1 // indirect
|
github.com/go-playground/validator/v10 v10.11.1 // indirect
|
||||||
|
|
|
@ -77,6 +77,11 @@ github.com/coreos/go-oidc/v3 v3.1.0 h1:6avEvcdvTa1qYsOZ6I5PRkSYHzpTNWgKYmaJfaYbr
|
||||||
github.com/coreos/go-oidc/v3 v3.1.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo=
|
github.com/coreos/go-oidc/v3 v3.1.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
|
github.com/couchbase/gocb/v2 v2.6.0 h1:DhkLNatDcddCcS411D6kNwZspSEAWVeI/N3abzt/HLc=
|
||||||
|
github.com/couchbase/gocb/v2 v2.6.0/go.mod h1:5su8b1gBF3V4j07SiGw+CA0bK9a84YWEb6UH7up0MEs=
|
||||||
|
github.com/couchbase/gocbcore/v10 v10.2.0 h1:ZoSBLtcmt+lXbxVVT4SAhXDVNR+D48iSOZWNzHucVVk=
|
||||||
|
github.com/couchbase/gocbcore/v10 v10.2.0/go.mod h1:qkPnOBziCs0guMEEvd0cRFo+AjOW0yEL99cU3I4n3Ao=
|
||||||
|
github.com/couchbaselabs/gocaves/client v0.0.0-20220223122017-22859b310bd2/go.mod h1:AVekAZwIY2stsJOMWLAS/0uA/+qdp7pjO8EHnl61QkY=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||||
|
@ -174,6 +179,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
|
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
|
||||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
@ -377,6 +384,7 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
|
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
|
|
@ -21,6 +21,7 @@ func TestResolvers(t *testing.T) {
|
||||||
constants.DbTypeMongodb: "mongodb://localhost:27017",
|
constants.DbTypeMongodb: "mongodb://localhost:27017",
|
||||||
constants.DbTypeScyllaDB: "127.0.0.1:9042",
|
constants.DbTypeScyllaDB: "127.0.0.1:9042",
|
||||||
constants.DbTypeDynamoDB: "http://0.0.0.0:8000",
|
constants.DbTypeDynamoDB: "http://0.0.0.0:8000",
|
||||||
|
constants.DbTypeCouchbaseDB: "couchbase://127.0.0.1",
|
||||||
}
|
}
|
||||||
|
|
||||||
testDBs := strings.Split(os.Getenv("TEST_DBS"), ",")
|
testDBs := strings.Split(os.Getenv("TEST_DBS"), ",")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user