Create flow to add password after account activation
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -45,7 +45,7 @@ type (
|
||||
NewPassword string
|
||||
}
|
||||
|
||||
CreateIdentityFromInvitationRequest struct {
|
||||
ActivateAccountRequest struct {
|
||||
InvitationToken string
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ func NewAuthService(svc *Service) *AuthService {
|
||||
return &AuthService{Service: svc}
|
||||
}
|
||||
|
||||
func (req CreateIdentityFromInvitationRequest) Validate() error {
|
||||
func (req ActivateAccountRequest) Validate() error {
|
||||
v := validator.New()
|
||||
|
||||
v.Check(req.InvitationToken, "invitationToken", validator.NotEmpty())
|
||||
@@ -132,8 +132,8 @@ func (req CreateIdentityWithPasswordRequest) Validate() error {
|
||||
|
||||
func (s *AuthService) ActivateAccount(
|
||||
ctx context.Context,
|
||||
req *CreateIdentityFromInvitationRequest,
|
||||
) (*coredata.MembershipProfile, *coredata.Session, error) {
|
||||
req *ActivateAccountRequest,
|
||||
) (*coredata.MembershipProfile, *string, error) {
|
||||
if err := req.Validate(); err != nil {
|
||||
return nil, nil, fmt.Errorf("invalid request: %w", err)
|
||||
}
|
||||
@@ -144,11 +144,12 @@ func (s *AuthService) ActivateAccount(
|
||||
}
|
||||
|
||||
var (
|
||||
scope = coredata.NewScopeFromObjectID(payload.Data.InvitationID)
|
||||
invitation = &coredata.Invitation{}
|
||||
profile *coredata.MembershipProfile
|
||||
session *coredata.Session
|
||||
now = time.Now()
|
||||
scope = coredata.NewScopeFromObjectID(payload.Data.InvitationID)
|
||||
invitation = &coredata.Invitation{}
|
||||
profile *coredata.MembershipProfile
|
||||
identity *coredata.Identity
|
||||
now = time.Now()
|
||||
createPasswordToken *string
|
||||
)
|
||||
|
||||
err = s.pg.WithTx(
|
||||
@@ -185,7 +186,7 @@ func (s *AuthService) ActivateAccount(
|
||||
}
|
||||
}
|
||||
|
||||
identity := &coredata.Identity{}
|
||||
identity = &coredata.Identity{}
|
||||
if err := identity.LoadByID(ctx, tx, profile.IdentityID); err != nil {
|
||||
return fmt.Errorf("cannot load identity: %w", err)
|
||||
}
|
||||
@@ -220,12 +221,6 @@ func (s *AuthService) ActivateAccount(
|
||||
return fmt.Errorf("cannot expire pending invitations: %w", err)
|
||||
}
|
||||
|
||||
session = coredata.NewRootSession(identity.ID, coredata.AuthMethodPassword, s.sessionDuration)
|
||||
err = session.Insert(ctx, tx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot insert session: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
@@ -234,7 +229,21 @@ func (s *AuthService) ActivateAccount(
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return profile, session, nil
|
||||
if identity.HashedPassword == nil {
|
||||
token, err := statelesstoken.NewToken(
|
||||
s.tokenSecret,
|
||||
TokenTypePasswordReset,
|
||||
s.passwordResetTokenValidity,
|
||||
PasswordResetData{Email: identity.EmailAddress},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("cannot generate password create token: %w", err)
|
||||
}
|
||||
|
||||
createPasswordToken = &token
|
||||
}
|
||||
|
||||
return profile, createPasswordToken, nil
|
||||
}
|
||||
|
||||
func (s AuthService) ResetPassword(
|
||||
|
||||
@@ -796,13 +796,10 @@ type SignOutPayload {
|
||||
}
|
||||
|
||||
type ActivateAccountPayload {
|
||||
createPasswordToken: String
|
||||
profile: Profile
|
||||
}
|
||||
|
||||
type CreatePasswordPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type ForgotPasswordPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
@@ -80,7 +80,8 @@ type ComplexityRoot struct {
|
||||
}
|
||||
|
||||
ActivateAccountPayload struct {
|
||||
Profile func(childComplexity int) int
|
||||
CreatePasswordToken func(childComplexity int) int
|
||||
Profile func(childComplexity int) int
|
||||
}
|
||||
|
||||
AssumeOrganizationSessionPayload struct {
|
||||
@@ -108,10 +109,6 @@ type ComplexityRoot struct {
|
||||
Organization func(childComplexity int) int
|
||||
}
|
||||
|
||||
CreatePasswordPayload struct {
|
||||
Success func(childComplexity int) int
|
||||
}
|
||||
|
||||
CreatePersonalAPIKeyPayload struct {
|
||||
PersonalAPIKeyEdge func(childComplexity int) int
|
||||
Token func(childComplexity int) int
|
||||
@@ -654,6 +651,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
|
||||
return e.complexity.AcceptInvitationPayload.Membership(childComplexity), true
|
||||
|
||||
case "ActivateAccountPayload.createPasswordToken":
|
||||
if e.complexity.ActivateAccountPayload.CreatePasswordToken == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.ActivateAccountPayload.CreatePasswordToken(childComplexity), true
|
||||
case "ActivateAccountPayload.profile":
|
||||
if e.complexity.ActivateAccountPayload.Profile == nil {
|
||||
break
|
||||
@@ -731,13 +734,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
|
||||
return e.complexity.CreateOrganizationPayload.Organization(childComplexity), true
|
||||
|
||||
case "CreatePasswordPayload.success":
|
||||
if e.complexity.CreatePasswordPayload.Success == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.CreatePasswordPayload.Success(childComplexity), true
|
||||
|
||||
case "CreatePersonalAPIKeyPayload.personalAPIKeyEdge":
|
||||
if e.complexity.CreatePersonalAPIKeyPayload.PersonalAPIKeyEdge == nil {
|
||||
break
|
||||
@@ -3281,13 +3277,10 @@ type SignOutPayload {
|
||||
}
|
||||
|
||||
type ActivateAccountPayload {
|
||||
createPasswordToken: String
|
||||
profile: Profile
|
||||
}
|
||||
|
||||
type CreatePasswordPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type ForgotPasswordPayload {
|
||||
success: Boolean!
|
||||
}
|
||||
@@ -4327,6 +4320,35 @@ func (ec *executionContext) fieldContext_AcceptInvitationPayload_invitation(_ co
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _ActivateAccountPayload_createPasswordToken(ctx context.Context, field graphql.CollectedField, obj *types.ActivateAccountPayload) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
ec.OperationContext,
|
||||
field,
|
||||
ec.fieldContext_ActivateAccountPayload_createPasswordToken,
|
||||
func(ctx context.Context) (any, error) {
|
||||
return obj.CreatePasswordToken, nil
|
||||
},
|
||||
nil,
|
||||
ec.marshalOString2ᚖstring,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_ActivateAccountPayload_createPasswordToken(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "ActivateAccountPayload",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type String does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _ActivateAccountPayload_profile(ctx context.Context, field graphql.CollectedField, obj *types.ActivateAccountPayload) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
@@ -4756,35 +4778,6 @@ func (ec *executionContext) fieldContext_CreateOrganizationPayload_membership(_
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _CreatePasswordPayload_success(ctx context.Context, field graphql.CollectedField, obj *types.CreatePasswordPayload) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
ec.OperationContext,
|
||||
field,
|
||||
ec.fieldContext_CreatePasswordPayload_success,
|
||||
func(ctx context.Context) (any, error) {
|
||||
return obj.Success, nil
|
||||
},
|
||||
nil,
|
||||
ec.marshalNBoolean2bool,
|
||||
true,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_CreatePasswordPayload_success(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "CreatePasswordPayload",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type Boolean does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _CreatePersonalAPIKeyPayload_personalAPIKeyEdge(ctx context.Context, field graphql.CollectedField, obj *types.CreatePersonalAPIKeyPayload) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
@@ -6636,6 +6629,8 @@ func (ec *executionContext) fieldContext_Mutation_activateAccount(ctx context.Co
|
||||
IsResolver: true,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
switch field.Name {
|
||||
case "createPasswordToken":
|
||||
return ec.fieldContext_ActivateAccountPayload_createPasswordToken(ctx, field)
|
||||
case "profile":
|
||||
return ec.fieldContext_ActivateAccountPayload_profile(ctx, field)
|
||||
}
|
||||
@@ -16764,6 +16759,8 @@ func (ec *executionContext) _ActivateAccountPayload(ctx context.Context, sel ast
|
||||
switch field.Name {
|
||||
case "__typename":
|
||||
out.Values[i] = graphql.MarshalString("ActivateAccountPayload")
|
||||
case "createPasswordToken":
|
||||
out.Values[i] = ec._ActivateAccountPayload_createPasswordToken(ctx, field, obj)
|
||||
case "profile":
|
||||
out.Values[i] = ec._ActivateAccountPayload_profile(ctx, field, obj)
|
||||
default:
|
||||
@@ -17037,45 +17034,6 @@ func (ec *executionContext) _CreateOrganizationPayload(ctx context.Context, sel
|
||||
return out
|
||||
}
|
||||
|
||||
var createPasswordPayloadImplementors = []string{"CreatePasswordPayload"}
|
||||
|
||||
func (ec *executionContext) _CreatePasswordPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreatePasswordPayload) graphql.Marshaler {
|
||||
fields := graphql.CollectFields(ec.OperationContext, sel, createPasswordPayloadImplementors)
|
||||
|
||||
out := graphql.NewFieldSet(fields)
|
||||
deferred := make(map[string]*graphql.FieldSet)
|
||||
for i, field := range fields {
|
||||
switch field.Name {
|
||||
case "__typename":
|
||||
out.Values[i] = graphql.MarshalString("CreatePasswordPayload")
|
||||
case "success":
|
||||
out.Values[i] = ec._CreatePasswordPayload_success(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
}
|
||||
out.Dispatch(ctx)
|
||||
if out.Invalids > 0 {
|
||||
return graphql.Null
|
||||
}
|
||||
|
||||
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
|
||||
|
||||
for label, dfs := range deferred {
|
||||
ec.processDeferredGroup(graphql.DeferredGroup{
|
||||
Label: label,
|
||||
Path: graphql.GetPath(ctx),
|
||||
FieldSet: dfs,
|
||||
Context: ctx,
|
||||
})
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
var createPersonalAPIKeyPayloadImplementors = []string{"CreatePersonalAPIKeyPayload"}
|
||||
|
||||
func (ec *executionContext) _CreatePersonalAPIKeyPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreatePersonalAPIKeyPayload) graphql.Marshaler {
|
||||
|
||||
@@ -39,7 +39,8 @@ type ActivateAccountInput struct {
|
||||
}
|
||||
|
||||
type ActivateAccountPayload struct {
|
||||
Profile *Profile `json:"profile,omitempty"`
|
||||
CreatePasswordToken *string `json:"createPasswordToken,omitempty"`
|
||||
Profile *Profile `json:"profile,omitempty"`
|
||||
}
|
||||
|
||||
type AssumeOrganizationSessionInput struct {
|
||||
@@ -91,10 +92,6 @@ type CreateOrganizationPayload struct {
|
||||
Membership *Membership `json:"membership"`
|
||||
}
|
||||
|
||||
type CreatePasswordPayload struct {
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
|
||||
type CreatePersonalAPIKeyInput struct {
|
||||
Name string `json:"name"`
|
||||
ExpiresAt time.Time `json:"expiresAt"`
|
||||
|
||||
@@ -384,9 +384,9 @@ func (r *mutationResolver) SignOut(ctx context.Context) (*types.SignOutPayload,
|
||||
|
||||
// ActivateAccount is the resolver for the signUpFromInvitation field.
|
||||
func (r *mutationResolver) ActivateAccount(ctx context.Context, input types.ActivateAccountInput) (*types.ActivateAccountPayload, error) {
|
||||
user, session, err := r.iam.AuthService.ActivateAccount(
|
||||
user, createPasswordToken, err := r.iam.AuthService.ActivateAccount(
|
||||
ctx,
|
||||
&iam.CreateIdentityFromInvitationRequest{
|
||||
&iam.ActivateAccountRequest{
|
||||
InvitationToken: input.Token,
|
||||
},
|
||||
)
|
||||
@@ -411,11 +411,9 @@ func (r *mutationResolver) ActivateAccount(ctx context.Context, input types.Acti
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
w := gqlutils.HTTPResponseWriterFromContext(ctx)
|
||||
r.sessionCookie.Set(w, session)
|
||||
|
||||
return &types.ActivateAccountPayload{
|
||||
Profile: types.NewProfile(user),
|
||||
CreatePasswordToken: createPasswordToken,
|
||||
Profile: types.NewProfile(user),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user