1
0
mirror of https://github.com/raseels-repos/golang-saas-starter-kit.git synced 2025-08-08 22:36:41 +02:00

Completed user invite

This commit is contained in:
Lee Brown
2019-08-05 14:32:45 -08:00
parent 9fbab53b4c
commit 33a7fb14b6
12 changed files with 238 additions and 84 deletions

View File

@ -21,6 +21,12 @@ var (
// ErrInviteExpired occurs when the the reset hash exceeds the expiration.
ErrInviteExpired = errors.New("Invite expired")
// ErrNoPendingInvite occurs when the user does not have an entry in user_accounts with status pending.
ErrNoPendingInvite = errors.New("No pending invite.")
// ErrUserAccountActive occurs when the user already has an active user_account entry.
ErrUserAccountActive = errors.New("User already active.")
// ErrInviteUserPasswordSet occurs when the the reset hash exceeds the expiration.
ErrInviteUserPasswordSet = errors.New("User password set")
)
@ -147,7 +153,7 @@ func SendUserInvites(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, r
var inviteHashes []string
for email, userID := range emailUserIDs {
hash, err := NewInviteHash(ctx, secretKey, userID, requestIp, req.TTL, now)
hash, err := NewInviteHash(ctx, secretKey, userID, req.AccountID, requestIp, req.TTL, now)
if err != nil {
return nil, err
}
@ -174,7 +180,7 @@ func SendUserInvites(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, r
}
// AcceptInvite updates the user using the provided invite hash.
func AcceptInvite(ctx context.Context, dbConn *sqlx.DB, req AcceptInviteRequest, secretKey string, now time.Time) error {
func AcceptInvite(ctx context.Context, dbConn *sqlx.DB, req AcceptInviteRequest, secretKey string, now time.Time) (string, error) {
span, ctx := tracer.StartSpanFromContext(ctx, "internal.user_account.invite.AcceptInvite")
defer span.Finish()
@ -183,40 +189,59 @@ func AcceptInvite(ctx context.Context, dbConn *sqlx.DB, req AcceptInviteRequest,
// Validate the request.
err := v.StructCtx(ctx, req)
if err != nil {
return err
return "", err
}
hash, err := ParseInviteHash(ctx, secretKey, req.InviteHash, now)
if err != nil {
return err
return "", err
}
u, err := user.Read(ctx, auth.Claims{}, dbConn,
user.UserReadRequest{ID: hash.UserID, IncludeArchived: true})
if err != nil {
return err
return "", err
}
if u.ArchivedAt != nil && !u.ArchivedAt.Time.IsZero() {
err = user.Restore(ctx, auth.Claims{}, dbConn, user.UserRestoreRequest{ID: hash.UserID}, now)
if err != nil {
return err
return "", err
}
} else if len(u.PasswordHash) > 0 {
// Do not update the password for a user that already has a password set.
err = errors.WithMessage(ErrInviteUserPasswordSet, "Invite user already has a password set.")
return err
}
usrAcc, err := user_account.Read(ctx, auth.Claims{}, dbConn, user_account.UserAccountReadRequest{
UserID: hash.UserID,
AccountID: hash.AccountID,
})
if err != nil {
return "", nil
}
// Ensure the entry has the status of invited.
if usrAcc.Status != user_account.UserAccountStatus_Invited {
// If the entry is already active
if usrAcc.Status == user_account.UserAccountStatus_Active {
return u.ID, errors.WithStack(ErrUserAccountActive)
}
return "", errors.WithStack(ErrNoPendingInvite)
}
if len(u.PasswordHash) > 0 {
// Do not update the password for a user that already has a password set.
return "", errors.WithStack(ErrInviteUserPasswordSet)
}
// These two calls, user.Update and user.UpdatePassword should probably be in a transaction!
err = user.Update(ctx, auth.Claims{}, dbConn, user.UserUpdateRequest{
ID: hash.UserID,
Email: &req.Email,
Email: &req.Email,
FirstName: &req.FirstName,
LastName: &req.LastName,
Timezone: req.Timezone,
}, now)
if err != nil {
return err
return "", err
}
err = user.UpdatePassword(ctx, auth.Claims{}, dbConn, user.UserUpdatePasswordRequest{
@ -225,8 +250,18 @@ func AcceptInvite(ctx context.Context, dbConn *sqlx.DB, req AcceptInviteRequest,
PasswordConfirm: req.PasswordConfirm,
}, now)
if err != nil {
return err
return "", err
}
return nil
activeStatus := user_account.UserAccountStatus_Active
err = user_account.Update(ctx, auth.Claims{}, dbConn, user_account.UserAccountUpdateRequest{
UserID: usrAcc.UserID,
AccountID: usrAcc.AccountID,
Status: &activeStatus,
}, now)
if err != nil {
return "", err
}
return hash.UserID, nil
}