fixed verification code
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/tech/sendico/pkg/auth"
|
||||
@@ -13,13 +14,12 @@ import (
|
||||
"github.com/tech/sendico/pkg/db/account"
|
||||
"github.com/tech/sendico/pkg/db/organization"
|
||||
"github.com/tech/sendico/pkg/db/policy"
|
||||
"github.com/tech/sendico/pkg/db/transaction"
|
||||
"github.com/tech/sendico/pkg/db/verification"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"github.com/tech/sendico/server/interface/middleware"
|
||||
"github.com/tech/sendico/server/internal/mutil/flrstring"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -31,9 +31,9 @@ type service struct {
|
||||
enforcer auth.Enforcer
|
||||
roleManager management.Role
|
||||
config *middleware.PasswordConfig
|
||||
tf transaction.Factory
|
||||
|
||||
policyDB policy.DB
|
||||
vdb verification.DB
|
||||
}
|
||||
|
||||
func validateUserRequest(u *model.Account) error {
|
||||
@@ -112,7 +112,6 @@ func (s *service) ValidateAccount(acct *model.Account) error {
|
||||
return err
|
||||
}
|
||||
|
||||
acct.VerifyToken = flrstring.CreateRandString(s.config.TokenLength)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -121,32 +120,50 @@ func (s *service) CreateAccount(
|
||||
org *model.Organization,
|
||||
acct *model.Account,
|
||||
roleDescID bson.ObjectID,
|
||||
) error {
|
||||
) (string, error) {
|
||||
if org == nil {
|
||||
return merrors.InvalidArgument("Organization must not be nil")
|
||||
return "", merrors.InvalidArgument("Organization must not be nil")
|
||||
}
|
||||
if acct == nil || len(acct.Login) == 0 {
|
||||
return merrors.InvalidArgument("Account must have a non-empty login")
|
||||
return "", merrors.InvalidArgument("Account must have a non-empty login")
|
||||
}
|
||||
if roleDescID == bson.NilObjectID {
|
||||
return merrors.InvalidArgument("Role description must be provided")
|
||||
return "", merrors.InvalidArgument("Role description must be provided")
|
||||
}
|
||||
|
||||
// 1) Create the account
|
||||
acct.Status = model.AccountPendingVerification
|
||||
if err := s.accountDB.Create(ctx, acct); err != nil {
|
||||
if errors.Is(err, merrors.ErrDataConflict) {
|
||||
s.logger.Info("Username is already taken", zap.String("login", acct.Login))
|
||||
} else {
|
||||
s.logger.Warn("Failed to signup a user", zap.Error(err), zap.String("login", acct.Login))
|
||||
}
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 2) Add to organization
|
||||
if err := s.JoinOrganization(ctx, org, acct, roleDescID); err != nil {
|
||||
s.logger.Warn("Failed to register new organization member", zap.Error(err), mzap.StorableRef(acct))
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
return nil
|
||||
|
||||
// 3) Issue verification token
|
||||
return s.VerifyAccount(ctx, acct)
|
||||
}
|
||||
|
||||
func (s *service) VerifyAccount(
|
||||
ctx context.Context,
|
||||
acct *model.Account,
|
||||
) (verificationToken string, err error) {
|
||||
verificationToken, err = s.vdb.Create(ctx, *acct.GetID(), model.PurposeAccountActivation, "", time.Duration(time.Hour*24))
|
||||
if err != nil {
|
||||
s.logger.Warn("Failed to create verification token for new account", zap.Error(err), mzap.StorableRef(acct))
|
||||
return "", err
|
||||
}
|
||||
|
||||
return verificationToken, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *service) DeleteAccount(
|
||||
@@ -213,20 +230,16 @@ func (s *service) RemoveAccountFromOrganization(
|
||||
func (s *service) ResetPassword(
|
||||
ctx context.Context,
|
||||
acct *model.Account,
|
||||
) error {
|
||||
acct.ResetPasswordToken = flrstring.CreateRandString(s.config.TokenLength)
|
||||
return s.accountDB.Update(ctx, acct)
|
||||
) (string, error) {
|
||||
return s.vdb.Create(ctx, *acct.GetID(), model.PurposePasswordReset, "", time.Duration(time.Hour*1))
|
||||
}
|
||||
|
||||
func (s *service) UpdateLogin(
|
||||
ctx context.Context,
|
||||
acct *model.Account,
|
||||
newLogin string,
|
||||
) error {
|
||||
acct.EmailBackup = acct.Login
|
||||
acct.Login = newLogin
|
||||
acct.VerifyToken = flrstring.CreateRandString(s.config.TokenLength)
|
||||
return s.accountDB.Update(ctx, acct)
|
||||
) (string, error) {
|
||||
return s.vdb.Create(ctx, *acct.GetID(), model.PurposeEmailChange, newLogin, time.Duration(time.Hour*1))
|
||||
}
|
||||
|
||||
func (s *service) JoinOrganization(
|
||||
@@ -311,27 +324,19 @@ func (s *service) DeleteOrganization(
|
||||
s.logger.Info("Starting organization deletion", mzap.StorableRef(org))
|
||||
|
||||
// Use transaction to ensure atomicity
|
||||
_, err := s.tf.CreateTransaction().Execute(ctx, func(ctx context.Context) (any, error) {
|
||||
// 8. Delete all roles and role descriptions in the organization
|
||||
if err := s.deleteOrganizationRoles(ctx, org.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 8. Delete all roles and role descriptions in the organization
|
||||
if err := s.deleteOrganizationRoles(ctx, org.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 9. Delete all policies in the organization
|
||||
if err := s.deleteOrganizationPolicies(ctx, org.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 9. Delete all policies in the organization
|
||||
if err := s.deleteOrganizationPolicies(ctx, org.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 10. Finally, delete the organization itself
|
||||
if err := s.orgDB.Delete(ctx, bson.NilObjectID, org.ID); err != nil {
|
||||
s.logger.Warn("Failed to delete organization", zap.Error(err), mzap.StorableRef(org))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to delete organization", zap.Error(err), mzap.StorableRef(org))
|
||||
// 10. Finally, delete the organization itself
|
||||
if err := s.orgDB.Delete(ctx, bson.NilObjectID, org.ID); err != nil {
|
||||
s.logger.Warn("Failed to delete organization", zap.Error(err), mzap.StorableRef(org))
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -347,23 +352,14 @@ func (s *service) DeleteAll(
|
||||
s.logger.Info("Starting complete deletion (organization + account)",
|
||||
mzap.StorableRef(org), mzap.ObjRef("account_ref", accountRef))
|
||||
|
||||
// Use transaction to ensure atomicity
|
||||
_, err := s.tf.CreateTransaction().Execute(ctx, func(ctx context.Context) (any, error) {
|
||||
// 1. First delete the organization and all its data
|
||||
if err := s.DeleteOrganization(ctx, org); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 1. First delete the organization and all its data
|
||||
if err := s.DeleteOrganization(ctx, org); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 2. Then delete the account
|
||||
if err := s.accountDB.Delete(ctx, accountRef); err != nil {
|
||||
s.logger.Warn("Failed to delete account", zap.Error(err), mzap.ObjRef("account_ref", accountRef))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
})
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to delete all data", zap.Error(err), mzap.StorableRef(org), mzap.ObjRef("account_ref", accountRef))
|
||||
// 2. Then delete the account
|
||||
if err := s.accountDB.Delete(ctx, accountRef); err != nil {
|
||||
s.logger.Warn("Failed to delete account", zap.Error(err), mzap.ObjRef("account_ref", accountRef))
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -390,7 +386,6 @@ func NewAccountService(
|
||||
enforcer: enforcer,
|
||||
roleManager: ra,
|
||||
config: config,
|
||||
tf: dbf.TransactionFactory(),
|
||||
}
|
||||
var err error
|
||||
if res.accountDB, err = dbf.NewAccountDB(); err != nil {
|
||||
@@ -407,6 +402,9 @@ func NewAccountService(
|
||||
logger.Warn("Failed to create policies database", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if res.vdb, err = dbf.NewVerificationsDB(); err != nil {
|
||||
logger.Warn("Failed to create verification database", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user