fx build fix
This commit is contained in:
176
api/server/internal/server/accountapiimp/signup.go
Normal file
176
api/server/internal/server/accountapiimp/signup.go
Normal file
@@ -0,0 +1,176 @@
|
||||
package accountapiimp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/pkg/api/http/response"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"github.com/tech/sendico/server/interface/api/srequest"
|
||||
"github.com/tech/sendico/server/interface/api/sresponse"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (a *AccountAPI) createAnonymousAccount(ctx context.Context, org *model.Organization, sr *srequest.Signup) error {
|
||||
anonymousUser := &model.Account{
|
||||
AccountPublic: model.AccountPublic{
|
||||
AccountBase: model.AccountBase{
|
||||
Describable: sr.AnonymousUser,
|
||||
},
|
||||
UserDataBase: sr.Account.UserDataBase,
|
||||
},
|
||||
}
|
||||
r, err := a.pmanager.Role().Create(ctx, org.ID, &sr.AnonymousRole)
|
||||
if err != nil {
|
||||
a.logger.Warn("Failed to create anonymous role", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
if err := a.accService.CreateAccount(ctx, org, anonymousUser, r.ID); err != nil {
|
||||
a.logger.Warn("Failed to create account", zap.Error(err), zap.String("login", anonymousUser.Login))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AccountAPI) createOrg(ctx context.Context, sr *srequest.Signup, permissionRef primitive.ObjectID) (*model.Organization, error) {
|
||||
if _, err := time.LoadLocation(sr.OrganizationTimeZone); err != nil {
|
||||
return nil, merrors.DataConflict(fmt.Sprintf("invalid time zone '%s' provided, error %s", sr.OrganizationTimeZone, err.Error()))
|
||||
}
|
||||
|
||||
org := &model.Organization{
|
||||
OrganizationBase: model.OrganizationBase{
|
||||
PermissionBound: model.PermissionBound{
|
||||
PermissionRef: permissionRef,
|
||||
},
|
||||
Describable: model.Describable{
|
||||
Name: sr.OrganizationName,
|
||||
},
|
||||
TimeZone: sr.OrganizationTimeZone,
|
||||
},
|
||||
Members: []primitive.ObjectID{},
|
||||
}
|
||||
if err := a.odb.Unprotected().Create(ctx, org); err != nil {
|
||||
a.logger.Warn("Failed to create organization", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return org, nil
|
||||
}
|
||||
|
||||
// signupHandler handles user sign up
|
||||
func (a *AccountAPI) signup(r *http.Request) http.HandlerFunc {
|
||||
// Validate user input
|
||||
var sr srequest.Signup
|
||||
if err := json.NewDecoder(r.Body).Decode(&sr); err != nil {
|
||||
a.logger.Warn("Failed to decode signup request", zap.Error(err))
|
||||
return response.BadRequest(a.logger, a.Name(), "", err.Error())
|
||||
}
|
||||
|
||||
newAccount := sr.Account.ToAccount()
|
||||
if res := a.accService.ValidateAccount(newAccount); res != nil {
|
||||
a.logger.Warn("Invalid signup account received", zap.Error(res), zap.String("account", newAccount.Login))
|
||||
return response.BadPayload(a.logger, a.Name(), res)
|
||||
}
|
||||
|
||||
if err := a.executeSignupTransaction(r.Context(), &sr, newAccount); err != nil {
|
||||
if errors.Is(err, merrors.ErrDataConflict) {
|
||||
a.logger.Info("Failed to register account", zap.Error(err), zap.String("login", newAccount.Login))
|
||||
return response.DataConflict(a.logger, "user_already_registered", "User has already been registered")
|
||||
}
|
||||
a.logger.Info("Failed to create new user", zap.Error(err), zap.String("login", newAccount.Login))
|
||||
return response.Internal(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
if err := a.sendWelcomeEmail(newAccount); err != nil {
|
||||
a.logger.Warn("Failed to send welcome email", zap.Error(err), mzap.StorableRef(newAccount))
|
||||
}
|
||||
|
||||
return sresponse.SignUp(a.logger, newAccount)
|
||||
}
|
||||
|
||||
func (a *AccountAPI) executeSignupTransaction(ctxt context.Context, sr *srequest.Signup, newAccount *model.Account) error {
|
||||
_, err := a.tf.CreateTransaction().Execute(ctxt, func(ctx context.Context) (any, error) {
|
||||
return a.signupTransactionBody(ctx, sr, newAccount)
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *AccountAPI) signupTransactionBody(ctx context.Context, sr *srequest.Signup, newAccount *model.Account) (any, error) {
|
||||
var orgPolicy model.PolicyDescription
|
||||
if err := a.plcdb.GetBuiltInPolicy(ctx, mservice.Organizations, &orgPolicy); err != nil {
|
||||
a.logger.Warn("Failed to fetch built-in organization policy", zap.Error(err), zap.String("login", newAccount.Login))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
org, err := a.createOrg(ctx, sr, orgPolicy.ID)
|
||||
if err != nil {
|
||||
a.logger.Warn("Failed to create organization", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roleDescription, err := a.pmanager.Role().Create(ctx, org.ID, &sr.OwnerRole)
|
||||
if err != nil {
|
||||
a.logger.Warn("Failed to create owner role", zap.Error(err), zap.String("login", newAccount.Login))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := a.grantAllPermissions(ctx, org.ID, roleDescription.ID, newAccount); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := a.accService.CreateAccount(ctx, org, newAccount, roleDescription.ID); err != nil {
|
||||
a.logger.Warn("Failed to create account", zap.Error(err), zap.String("login", newAccount.Login))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := a.createAnonymousAccount(ctx, org, sr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (a *AccountAPI) grantAllPermissions(ctx context.Context, organizationRef primitive.ObjectID, roleID primitive.ObjectID, newAccount *model.Account) error {
|
||||
om := a.pmanager.Permission()
|
||||
policies, err := a.plcdb.All(ctx, organizationRef)
|
||||
if err != nil {
|
||||
a.logger.Warn("Failed to fetch permissions", zap.Error(err), mzap.StorableRef(newAccount))
|
||||
return err
|
||||
}
|
||||
|
||||
actions := []model.Action{model.ActionCreate, model.ActionRead, model.ActionUpdate, model.ActionDelete}
|
||||
for _, policy := range policies {
|
||||
for _, action := range actions {
|
||||
a.logger.Debug("Adding permission", mzap.StorableRef(&policy), zap.String("action", string(action)),
|
||||
mzap.ObjRef("role_ref", roleID), mzap.ObjRef("policy_ref", policy.ID), mzap.ObjRef("organization_ref", organizationRef))
|
||||
policy := model.RolePolicy{
|
||||
Policy: model.Policy{
|
||||
OrganizationRef: organizationRef,
|
||||
DescriptionRef: policy.ID,
|
||||
ObjectRef: nil, // all objects are affected
|
||||
Effect: model.ActionEffect{Action: action, Effect: model.EffectAllow},
|
||||
},
|
||||
RoleDescriptionRef: roleID,
|
||||
}
|
||||
if err := om.GrantToRole(ctx, &policy); err != nil {
|
||||
a.logger.Warn("Failed to grant permission", zap.Error(err), mzap.StorableRef(newAccount))
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := om.Save(); err != nil {
|
||||
a.logger.Warn("Failed to save permissions", zap.Error(err), mzap.StorableRef(newAccount))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user