feat: merge with mailgun
All checks were successful
deploy / deploy (push) Successful in 1m32s

This commit is contained in:
Stepan Vladovskiy 2024-04-11 17:14:25 -03:00
commit 8eb9650142
15 changed files with 266 additions and 26 deletions

View File

@ -33,3 +33,4 @@ jobs:
branch: 'main' branch: 'main'
git_remote_url: 'ssh://dokku@staging.discours.io:22/authorizer' git_remote_url: 'ssh://dokku@staging.discours.io:22/authorizer'
ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }} ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}
git_push_flags: '--force'

20
go.mod Normal file
View File

@ -0,0 +1,20 @@
module server
go 1.21.5
require (
github.com/99designs/gqlgen v0.17.43 // indirect
github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sosodev/duration v1.1.0 // indirect
github.com/urfave/cli/v2 v2.25.5 // indirect
github.com/vektah/gqlparser/v2 v2.5.11 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/tools v0.9.3 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

31
go.sum Normal file
View File

@ -0,0 +1,31 @@
github.com/99designs/gqlgen v0.17.43 h1:I4SYg6ahjowErAQcHFVKy5EcWuwJ3+Xw9z2fLpuFCPo=
github.com/99designs/gqlgen v0.17.43/go.mod h1:lO0Zjy8MkZgBdv4T1U91x09r0e0WFOdhVUutlQs1Rsc=
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sosodev/duration v1.1.0 h1:kQcaiGbJaIsRqgQy7VGlZrVw1giWO+lDoX3MCPnpVO4=
github.com/sosodev/duration v1.1.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
github.com/urfave/cli/v2 v2.25.5 h1:d0NIAyhh5shGscroL7ek/Ya9QYQE0KNabJgiUinIQkc=
github.com/urfave/cli/v2 v2.25.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
github.com/vektah/gqlparser/v2 v2.5.11 h1:JJxLtXIoN7+3x6MBdtIP59TP1RANnY7pXOaDnADQSf8=
github.com/vektah/gqlparser/v2 v2.5.11/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -19,6 +19,7 @@ require (
github.com/google/uuid v1.3.1 github.com/google/uuid v1.3.1
github.com/guregu/dynamo v1.20.2 github.com/guregu/dynamo v1.20.2
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/mailgun/mailgun-go/v4 v4.12.0
github.com/pquerna/otp v1.4.0 github.com/pquerna/otp v1.4.0
github.com/redis/go-redis/v9 v9.2.1 github.com/redis/go-redis/v9 v9.2.1
github.com/robertkrimen/otto v0.2.1 github.com/robertkrimen/otto v0.2.1
@ -83,7 +84,6 @@ require (
github.com/leodido/go-urn v1.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect
github.com/libsql/libsql-client-go v0.0.0-20231026052543-fce76c0f39a7 // indirect github.com/libsql/libsql-client-go v0.0.0-20231026052543-fce76c0f39a7 // indirect
github.com/libsql/sqlite-antlr4-parser v0.0.0-20230802215326-5cb5bb604475 // indirect github.com/libsql/sqlite-antlr4-parser v0.0.0-20230802215326-5cb5bb604475 // indirect
github.com/mailgun/mailgun-go/v4 v4.12.0 // indirect
github.com/maruel/rs v1.1.0 // indirect github.com/maruel/rs v1.1.0 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-isatty v0.0.19 // indirect
github.com/microsoft/go-mssqldb v1.6.0 // indirect github.com/microsoft/go-mssqldb v1.6.0 // indirect

View File

@ -81,8 +81,11 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/ekristen/gorm-libsql v0.0.0-20231101204708-6e113112bcc2 h1:3f6DAUkYKbZSJ1bBM0/RiX5NHVt7YgmB0BWzKWUd45g= github.com/ekristen/gorm-libsql v0.0.0-20231101204708-6e113112bcc2 h1:3f6DAUkYKbZSJ1bBM0/RiX5NHVt7YgmB0BWzKWUd45g=
github.com/ekristen/gorm-libsql v0.0.0-20231101204708-6e113112bcc2/go.mod h1:5g9wSYpR/MvkR6W7SumX9zdha7Yt1iM4nxOAWfRfcPA= github.com/ekristen/gorm-libsql v0.0.0-20231101204708-6e113112bcc2/go.mod h1:5g9wSYpR/MvkR6W7SumX9zdha7Yt1iM4nxOAWfRfcPA=
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y=
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=

View File

@ -236,6 +236,7 @@ type ComplexityRoot struct {
AdminSession func(childComplexity int) int AdminSession func(childComplexity int) int
EmailTemplates func(childComplexity int, params *model.PaginatedInput) int EmailTemplates func(childComplexity int, params *model.PaginatedInput) int
Env func(childComplexity int) int Env func(childComplexity int) int
IsRegistered func(childComplexity int, email string) int
Meta func(childComplexity int) int Meta func(childComplexity int) int
Profile func(childComplexity int) int Profile func(childComplexity int) int
Session func(childComplexity int, params *model.SessionQueryInput) int Session func(childComplexity int, params *model.SessionQueryInput) int
@ -392,6 +393,7 @@ type QueryResolver interface {
Meta(ctx context.Context) (*model.Meta, error) Meta(ctx context.Context) (*model.Meta, error)
Session(ctx context.Context, params *model.SessionQueryInput) (*model.AuthResponse, error) Session(ctx context.Context, params *model.SessionQueryInput) (*model.AuthResponse, error)
Profile(ctx context.Context) (*model.User, error) Profile(ctx context.Context) (*model.User, error)
IsRegistered(ctx context.Context, email string) (*model.Response, error)
ValidateJwtToken(ctx context.Context, params model.ValidateJWTTokenInput) (*model.ValidateJWTTokenResponse, error) ValidateJwtToken(ctx context.Context, params model.ValidateJWTTokenInput) (*model.ValidateJWTTokenResponse, error)
ValidateSession(ctx context.Context, params *model.ValidateSessionInput) (*model.ValidateSessionResponse, error) ValidateSession(ctx context.Context, params *model.ValidateSessionInput) (*model.ValidateSessionResponse, error)
Users(ctx context.Context, params *model.PaginatedInput) (*model.Users, error) Users(ctx context.Context, params *model.PaginatedInput) (*model.Users, error)
@ -1666,6 +1668,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Query.Env(childComplexity), true return e.complexity.Query.Env(childComplexity), true
case "Query.is_registered":
if e.complexity.Query.IsRegistered == nil {
break
}
args, err := ec.field_Query_is_registered_args(context.TODO(), rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Query.IsRegistered(childComplexity, args["email"].(string)), true
case "Query.meta": case "Query.meta":
if e.complexity.Query.Meta == nil { if e.complexity.Query.Meta == nil {
break break
@ -3036,6 +3050,7 @@ type Query {
meta: Meta! meta: Meta!
session(params: SessionQueryInput): AuthResponse! session(params: SessionQueryInput): AuthResponse!
profile: User! profile: User!
is_registered(email: String!): Response! # custom api
validate_jwt_token(params: ValidateJWTTokenInput!): ValidateJWTTokenResponse! validate_jwt_token(params: ValidateJWTTokenInput!): ValidateJWTTokenResponse!
validate_session(params: ValidateSessionInput): ValidateSessionResponse! validate_session(params: ValidateSessionInput): ValidateSessionResponse!
# admin only apis # admin only apis
@ -3612,6 +3627,21 @@ func (ec *executionContext) field_Query__webhooks_args(ctx context.Context, rawA
return args, nil return args, nil
} }
func (ec *executionContext) field_Query_is_registered_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
var arg0 string
if tmp, ok := rawArgs["email"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email"))
arg0, err = ec.unmarshalNString2string(ctx, tmp)
if err != nil {
return nil, err
}
}
args["email"] = arg0
return args, nil
}
func (ec *executionContext) field_Query_session_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { func (ec *executionContext) field_Query_session_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error var err error
args := map[string]interface{}{} args := map[string]interface{}{}
@ -11208,6 +11238,65 @@ func (ec *executionContext) fieldContext_Query_profile(ctx context.Context, fiel
return fc, nil return fc, nil
} }
func (ec *executionContext) _Query_is_registered(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Query_is_registered(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Query().IsRegistered(rctx, fc.Args["email"].(string))
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*model.Response)
fc.Result = res
return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Query_is_registered(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Query",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "message":
return ec.fieldContext_Response_message(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type Response", field.Name)
},
}
defer func() {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
ec.Error(ctx, err)
}
}()
ctx = graphql.WithFieldContext(ctx, fc)
if fc.Args, err = ec.field_Query_is_registered_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return fc, err
}
return fc, nil
}
func (ec *executionContext) _Query_validate_jwt_token(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { func (ec *executionContext) _Query_validate_jwt_token(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Query_validate_jwt_token(ctx, field) fc, err := ec.fieldContext_Query_validate_jwt_token(ctx, field)
if err != nil { if err != nil {
@ -20511,6 +20600,28 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
} }
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) })
case "is_registered":
field := field
innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
}
}()
res = ec._Query_is_registered(ctx, field)
if res == graphql.Null {
atomic.AddUint32(&fs.Invalids, 1)
}
return res
}
rrm := func(ctx context.Context) graphql.Marshaler {
return ec.OperationContext.RootResolverMiddleware(ctx,
func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
}
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) })
case "validate_jwt_token": case "validate_jwt_token":
field := field field := field

View File

@ -610,7 +610,6 @@ input GetUserRequest {
} }
type Mutation { type Mutation {
is_registered(email: String): AuthResponse! # custom api
signup(params: SignUpInput!): AuthResponse! signup(params: SignUpInput!): AuthResponse!
# Deprecated from v1.2.0 # Deprecated from v1.2.0
mobile_signup(params: MobileSignUpInput): AuthResponse! mobile_signup(params: MobileSignUpInput): AuthResponse!
@ -652,6 +651,7 @@ type Query {
meta: Meta! meta: Meta!
session(params: SessionQueryInput): AuthResponse! session(params: SessionQueryInput): AuthResponse!
profile: User! profile: User!
is_registered(email: String!): Response! # custom api
validate_jwt_token(params: ValidateJWTTokenInput!): ValidateJWTTokenResponse! validate_jwt_token(params: ValidateJWTTokenInput!): ValidateJWTTokenResponse!
validate_session(params: ValidateSessionInput): ValidateSessionResponse! validate_session(params: ValidateSessionInput): ValidateSessionResponse!
# admin only apis # admin only apis

View File

@ -12,11 +12,6 @@ import (
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
) )
// Signup is the resolver for the signup field.
func (r *queryResolver) IsRegistered(ctx context.Context, email string) (*model.AuthResponse, error) {
return resolvers.IsRegisteredResolver(ctx, email)
}
// Signup is the resolver for the signup field. // Signup is the resolver for the signup field.
func (r *mutationResolver) Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error) { func (r *mutationResolver) Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error) {
return resolvers.SignupResolver(ctx, params) return resolvers.SignupResolver(ctx, params)
@ -192,6 +187,11 @@ func (r *queryResolver) Profile(ctx context.Context) (*model.User, error) {
return resolvers.ProfileResolver(ctx) return resolvers.ProfileResolver(ctx)
} }
// IsRegistered is the resolver for the signup field.
func (r *queryResolver) IsRegistered(ctx context.Context, email string) (*model.Response, error) {
return resolvers.IsRegisteredResolver(ctx, email)
}
// ValidateJwtToken is the resolver for the validate_jwt_token field. // ValidateJwtToken is the resolver for the validate_jwt_token field.
func (r *queryResolver) ValidateJwtToken(ctx context.Context, params model.ValidateJWTTokenInput) (*model.ValidateJWTTokenResponse, error) { func (r *queryResolver) ValidateJwtToken(ctx context.Context, params model.ValidateJWTTokenInput) (*model.ValidateJWTTokenResponse, error) {
return resolvers.ValidateJwtTokenResolver(ctx, params) return resolvers.ValidateJwtTokenResolver(ctx, params)

View File

@ -3,8 +3,11 @@ package inmemory
import ( import (
"fmt" "fmt"
"os" "os"
"errors"
log "github.com/sirupsen/logrus"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/memorystore/providers/redis"
) )
// SetUserSession sets the user session for given user identifier in form recipe:user_id // SetUserSession sets the user session for given user identifier in form recipe:user_id
@ -119,3 +122,25 @@ func (c *provider) GetBoolStoreEnvVariable(key string) (bool, error) {
} }
return res.(bool), nil return res.(bool), nil
} }
// GetUserAppDataFromRedis retrieves user profile and follows from Redis, combines them into a JSON format,
// and assigns the JSON string to the provided user's ID.
func (c *provider) GetUserAppDataFromRedis(userId string) (string, error) {
redisURL := os.Getenv(constants.EnvKeyRedisURL)
if redisURL == "" {
return "", errors.New("Redis URL not found")
}
log.Info("Initializing Redis provider")
red, err := redis.NewRedisProvider(redisURL)
if err != nil {
return "", fmt.Errorf("failed to initialize Redis provider: %w", err)
}
combinedData, err := red.GetUserAppDataFromRedis(userId)
if err != nil {
return "", fmt.Errorf("failed to get Redis app data: %w", err)
}
return combinedData, nil
}

View File

@ -38,4 +38,6 @@ type Provider interface {
GetStringStoreEnvVariable(key string) (string, error) GetStringStoreEnvVariable(key string) (string, error)
// GetBoolStoreEnvVariable to get the bool env variable from env store // GetBoolStoreEnvVariable to get the bool env variable from env store
GetBoolStoreEnvVariable(key string) (bool, error) GetBoolStoreEnvVariable(key string) (bool, error)
GetUserAppDataFromRedis(userId string) (string, error)
} }

View File

@ -218,3 +218,16 @@ func (c *provider) GetBoolStoreEnvVariable(key string) (bool, error) {
return data == "1", nil return data == "1", nil
} }
// GetUserAppDataFromRedis retrieves user profile and follows from Redis, combines them into a JSON format,
// and assigns the JSON string to the provided user's ID.
func (c *provider) GetUserAppDataFromRedis(userId string) (string, error) {
// Retrieve user data from Redis
userProfile := c.store.Get(c.ctx, fmt.Sprintf(`user:%s:author`, userId))
userFollows := c.store.Get(c.ctx, fmt.Sprintf(`user:%s:follows`, userId))
// Combine user data into a JSON string
combinedData := fmt.Sprintf(`{"profile": %s, "follows": %s}`, userProfile, userFollows)
return combinedData, nil
}

View File

@ -83,6 +83,16 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
log.Debug("Failed to get user: ", err) log.Debug("Failed to get user: ", err)
return nil, fmt.Errorf(`bad user credentials`) return nil, fmt.Errorf(`bad user credentials`)
} }
if user.SignupMethods == "magic_link_login" {
user.SignupMethods = "basic_auth"
user, err = db.Provider.UpdateUser(ctx, user)
if err != nil {
log.Debug("Failed to update user signup method: ", err)
}
}
hostname := parsers.GetHost(gc) hostname := parsers.GetHost(gc)
_, nonceHash, err := utils.GenerateNonce() _, nonceHash, err := utils.GenerateNonce()
if err != nil { if err != nil {

View File

@ -11,32 +11,43 @@ import (
) )
// IsRegisteredResolver is a resolver for registered checkup query // IsRegisteredResolver is a resolver for registered checkup query
func IsRegisteredResolver(ctx context.Context, email string) (*model.AuthResponse, error) { func IsRegisteredResolver(ctx context.Context, email string) (*model.Response, error) {
var res *model.AuthResponse // Initialize the response object
email = strings.TrimSpace(refs.StringValue(&email)) res := &model.Response{}
res.Message = ""
// Convert email to lowercase
email = strings.ToLower(strings.TrimSpace(refs.StringValue(&email)))
if email == "" { if email == "" {
log.Debug("Email is required") log.Debug("Email is required")
return res, fmt.Errorf(`email is required`) return res, fmt.Errorf("email is required")
} }
// Initialize logger with a field
log := log.WithField("email", email) log := log.WithField("email", email)
// find user with email // Find user with email
existingUser, err := db.Provider.GetUserByEmail(ctx, email) existingUser, err := db.Provider.GetUserByEmail(ctx, email)
if err != nil { if err != nil {
log.Debug("Failed to get user by email: ", err) log.Debug("Failed to get user by email: ", err)
} } else {
log.Debug("Found user by email: ", existingUser)
if existingUser != nil { if existingUser != nil {
res.Message = "registered" if existingUser.SignupMethods == "magic_link_login" {
if existingUser.EmailVerifiedAt != nil { res.Message = "registered"
res.Message = "verified" } else if existingUser.EmailVerifiedAt != nil {
log.Debug("Email is already verified and signed up.") res.Message = "verified"
return res, fmt.Errorf(`%s has already signed up`, email) log.Debug("Email is already verified and signed up.")
} else if existingUser.ID != "" && existingUser.EmailVerifiedAt == nil { return res, nil
res.Message = "not verified" } else if existingUser.ID != "" && existingUser.EmailVerifiedAt == nil {
log.Debug("Email is already signed up. Verification pending...") res.Message = "not verified"
return res, fmt.Errorf("%s has already signed up. please complete the email verification process or reset the password", email) log.Debug("Email is already signed up. Verification pending...")
return res, nil
} else {
res.Message = "unknown"
log.Debug("Unknown signup method.")
return res, nil
}
} }
} }

View File

@ -316,6 +316,12 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
expiresIn = 1 expiresIn = 1
} }
appData, err := memorystore.Provider.GetUserAppDataFromRedis(user.ID)
if err == nil {
// Assign the combined data to the provided pointer
user.AppData = &appData
}
res = &model.AuthResponse{ res = &model.AuthResponse{
Message: `Logged in successfully`, Message: `Logged in successfully`,
AccessToken: &authToken.AccessToken.Token, AccessToken: &authToken.AccessToken.Token,

View File

@ -90,6 +90,12 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
expiresIn = 1 expiresIn = 1
} }
appData, err := memorystore.Provider.GetUserAppDataFromRedis(user.ID)
if err == nil {
// Assign the combined data to the provided pointer
user.AppData = &appData
}
res = &model.AuthResponse{ res = &model.AuthResponse{
Message: `Session token refreshed`, Message: `Session token refreshed`,
AccessToken: &authToken.AccessToken.Token, AccessToken: &authToken.AccessToken.Token,
@ -102,6 +108,7 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt)
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt)
if authToken.RefreshToken != nil { if authToken.RefreshToken != nil {
res.RefreshToken = &authToken.RefreshToken.Token res.RefreshToken = &authToken.RefreshToken.Token
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt)