Add resolver to resend verify email link

Resolves #20
This commit is contained in:
Lakhan Samani 2021-07-18 12:56:17 +05:30
parent e2fc610762
commit 2840a085ca
8 changed files with 193 additions and 11 deletions

View File

@ -22,6 +22,7 @@ type Manager interface {
GetVerificationByToken(token string) (VerificationRequest, error)
DeleteToken(email string) error
GetVerificationRequests() ([]VerificationRequest, error)
GetVerificationByEmail(email string) (VerificationRequest, error)
}
type manager struct {

View File

@ -41,6 +41,18 @@ func (mgr *manager) GetVerificationByToken(token string) (VerificationRequest, e
return verification, nil
}
func (mgr *manager) GetVerificationByEmail(email string) (VerificationRequest, error) {
var verification VerificationRequest
result := mgr.db.Where("email = ?", email).First(&verification)
if result.Error != nil {
log.Println(`Error getting verification token:`, result.Error)
return verification, result.Error
}
return verification, nil
}
func (mgr *manager) DeleteToken(email string) error {
var verification VerificationRequest
result := mgr.db.Where("email = ?", email).Delete(&verification)

View File

@ -56,11 +56,12 @@ type ComplexityRoot struct {
}
Mutation struct {
Login func(childComplexity int, params model.LoginInput) int
Logout func(childComplexity int) int
Signup func(childComplexity int, params model.SignUpInput) int
UpdateProfile func(childComplexity int, params model.UpdateProfileInput) int
VerifyEmail func(childComplexity int, params model.VerifyEmailInput) int
Login func(childComplexity int, params model.LoginInput) int
Logout func(childComplexity int) int
ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int
Signup func(childComplexity int, params model.SignUpInput) int
UpdateProfile func(childComplexity int, params model.UpdateProfileInput) int
VerifyEmail func(childComplexity int, params model.VerifyEmailInput) int
}
Query struct {
@ -104,6 +105,7 @@ type MutationResolver interface {
Logout(ctx context.Context) (*model.Response, error)
UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error)
VerifyEmail(ctx context.Context, params model.VerifyEmailInput) (*model.LoginResponse, error)
ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error)
}
type QueryResolver interface {
Users(ctx context.Context) ([]*model.User, error)
@ -188,6 +190,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Mutation.Logout(childComplexity), true
case "Mutation.resendVerifyEmail":
if e.complexity.Mutation.ResendVerifyEmail == nil {
break
}
args, err := ec.field_Mutation_resendVerifyEmail_args(context.TODO(), rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.ResendVerifyEmail(childComplexity, args["params"].(model.ResendVerifyEmailInput)), true
case "Mutation.signup":
if e.complexity.Mutation.Signup == nil {
break
@ -504,6 +518,10 @@ input VerifyEmailInput {
token: String!
}
input ResendVerifyEmailInput {
email: String!
}
input UpdateProfileInput {
oldPassword: String
newPassword: String
@ -520,6 +538,7 @@ type Mutation {
logout: Response!
updateProfile(params: UpdateProfileInput!): Response!
verifyEmail(params: VerifyEmailInput!): LoginResponse!
resendVerifyEmail(params: ResendVerifyEmailInput!): Response!
}
type Query {
@ -551,6 +570,21 @@ func (ec *executionContext) field_Mutation_login_args(ctx context.Context, rawAr
return args, nil
}
func (ec *executionContext) field_Mutation_resendVerifyEmail_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
var arg0 model.ResendVerifyEmailInput
if tmp, ok := rawArgs["params"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params"))
arg0, err = ec.unmarshalNResendVerifyEmailInput2githubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐResendVerifyEmailInput(ctx, tmp)
if err != nil {
return nil, err
}
}
args["params"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_signup_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
@ -1053,6 +1087,48 @@ func (ec *executionContext) _Mutation_verifyEmail(ctx context.Context, field gra
return ec.marshalNLoginResponse2ᚖgithubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐLoginResponse(ctx, field.Selections, res)
}
func (ec *executionContext) _Mutation_resendVerifyEmail(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "Mutation",
Field: field,
Args: nil,
IsMethod: true,
IsResolver: true,
}
ctx = graphql.WithFieldContext(ctx, fc)
rawArgs := field.ArgumentMap(ec.Variables)
args, err := ec.field_Mutation_resendVerifyEmail_args(ctx, rawArgs)
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
fc.Args = args
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Mutation().ResendVerifyEmail(rctx, args["params"].(model.ResendVerifyEmailInput))
})
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ᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res)
}
func (ec *executionContext) _Query_users(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@ -2967,6 +3043,26 @@ func (ec *executionContext) unmarshalInputLoginInput(ctx context.Context, obj in
return it, nil
}
func (ec *executionContext) unmarshalInputResendVerifyEmailInput(ctx context.Context, obj interface{}) (model.ResendVerifyEmailInput, error) {
var it model.ResendVerifyEmailInput
var asMap = obj.(map[string]interface{})
for k, v := range asMap {
switch k {
case "email":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email"))
it.Email, err = ec.unmarshalNString2string(ctx, v)
if err != nil {
return it, err
}
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputSignUpInput(ctx context.Context, obj interface{}) (model.SignUpInput, error) {
var it model.SignUpInput
var asMap = obj.(map[string]interface{})
@ -3228,6 +3324,11 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null {
invalids++
}
case "resendVerifyEmail":
out.Values[i] = ec._Mutation_resendVerifyEmail(ctx, field)
if out.Values[i] == graphql.Null {
invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
@ -3733,6 +3834,11 @@ func (ec *executionContext) marshalNLoginResponse2ᚖgithubᚗcomᚋyauthdevᚋy
return ec._LoginResponse(ctx, sel, v)
}
func (ec *executionContext) unmarshalNResendVerifyEmailInput2githubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐResendVerifyEmailInput(ctx context.Context, v interface{}) (model.ResendVerifyEmailInput, error) {
res, err := ec.unmarshalInputResendVerifyEmailInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNResponse2githubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐResponse(ctx context.Context, sel ast.SelectionSet, v model.Response) graphql.Marshaler {
return ec._Response(ctx, sel, &v)
}

View File

@ -19,6 +19,10 @@ type LoginResponse struct {
User *User `json:"user"`
}
type ResendVerifyEmailInput struct {
Email string `json:"email"`
}
type Response struct {
Message string `json:"message"`
}

View File

@ -60,6 +60,10 @@ input VerifyEmailInput {
token: String!
}
input ResendVerifyEmailInput {
email: String!
}
input UpdateProfileInput {
oldPassword: String
newPassword: String
@ -76,6 +80,7 @@ type Mutation {
logout: Response!
updateProfile(params: UpdateProfileInput!): Response!
verifyEmail(params: VerifyEmailInput!): LoginResponse!
resendVerifyEmail(params: ResendVerifyEmailInput!): Response!
}
type Query {

View File

@ -31,6 +31,10 @@ func (r *mutationResolver) VerifyEmail(ctx context.Context, params model.VerifyE
return resolvers.VerifyEmail(ctx, params)
}
func (r *mutationResolver) ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error) {
return resolvers.ResendVerifyEmail(ctx, params)
}
func (r *queryResolver) Users(ctx context.Context) ([]*model.User, error) {
return resolvers.Users(ctx)
}

View File

@ -0,0 +1,49 @@
package resolvers
import (
"context"
"fmt"
"log"
"strings"
"time"
"github.com/yauthdev/yauth/server/db"
"github.com/yauthdev/yauth/server/graph/model"
"github.com/yauthdev/yauth/server/utils"
)
func ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error) {
var res *model.Response
params.Email = strings.ToLower(params.Email)
if !utils.IsValidEmail(params.Email) {
return res, fmt.Errorf("invalid email")
}
verificationRequest, err := db.Mgr.GetVerificationByEmail(params.Email)
if err != nil {
return res, fmt.Errorf(`verification request not found`)
}
token, err := utils.CreateVerificationToken(params.Email, verificationRequest.Identifier)
if err != nil {
log.Println(`Error generating token`, err)
}
db.Mgr.AddVerification(db.VerificationRequest{
Token: token,
Identifier: verificationRequest.Identifier,
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
Email: params.Email,
})
// exec it as go routin so that we can reduce the api latency
go func() {
utils.SendVerificationMail(params.Email, token)
}()
res = &model.Response{
Message: `Verification email has been sent. Please check your inbox`,
}
return res, nil
}

View File

@ -27,12 +27,13 @@ func VerificationRequests(ctx context.Context) ([]*model.VerificationRequest, er
for _, verificationRequest := range verificationRequests {
res = append(res, &model.VerificationRequest{
ID: fmt.Sprintf("%d", verificationRequest.ID),
Email: &verificationRequest.Email,
Token: &verificationRequest.Token,
Expires: &verificationRequest.ExpiresAt,
CreatedAt: &verificationRequest.CreatedAt,
UpdatedAt: &verificationRequest.UpdatedAt,
ID: fmt.Sprintf("%d", verificationRequest.ID),
Email: &verificationRequest.Email,
Token: &verificationRequest.Token,
Identifier: &verificationRequest.Identifier,
Expires: &verificationRequest.ExpiresAt,
CreatedAt: &verificationRequest.CreatedAt,
UpdatedAt: &verificationRequest.UpdatedAt,
})
}