package permissionsimp import ( "context" "encoding/json" "net/http" "github.com/tech/sendico/pkg/api/http/response" "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" mutil "github.com/tech/sendico/server/internal/mutil/param" "go.mongodb.org/mongo-driver/v2/bson" "go.uber.org/zap" ) func (a *PermissionsAPI) changeRole(r *http.Request, account *model.Account, _ *sresponse.TokenData) http.HandlerFunc { orgRef, err := mutil.GetOrganizationRef(r) if err != nil { a.logger.Warn("Failed to restore organization reference", zap.Error(err), zap.String("organization_ref", mutil.GetOrganizationID(r))) return response.BadReference(a.logger, a.Name(), mutil.OrganizationRefName(), mutil.GetOrganizationID(r), err) } var req srequest.ChangeRole if err := json.NewDecoder(r.Body).Decode(&req); err != nil { a.logger.Warn("Failed to decode change role request", zap.Error(err)) return response.BadPayload(a.logger, mservice.Roles, err) } ctx := r.Context() res, err := a.enforcer.Enforce(ctx, a.rolesPermissionRef, account.ID, orgRef, req.AccountRef, model.ActionUpdate) if err != nil { a.logger.Warn("Failed to check permissions while assigning new role", zap.Error(err), mzap.ObjRef("requesting_account_ref", account.ID), mzap.AccRef(req.AccountRef), mzap.ObjRef("role_description_ref", req.NewRoleDescriptionRef)) } if !res { a.logger.Debug("Permission denied to set new role", mzap.ObjRef("requesting_account_ref", account.ID), mzap.AccRef(req.AccountRef), mzap.ObjRef("role_description_ref", req.NewRoleDescriptionRef)) return response.AccessDenied(a.logger, a.Name(), "no permission to change user roles") } var roleDescription model.RoleDescription if err := a.rdb.Get(ctx, req.NewRoleDescriptionRef, &roleDescription); err != nil { a.logger.Warn("Failed to fetch and validate role description", zap.Error(err), mzap.ObjRef("requesting_account_ref", account.ID), mzap.AccRef(req.AccountRef), mzap.ObjRef("role_description_ref", req.NewRoleDescriptionRef)) return response.Auto(a.logger, a.Name(), err) } return a.changeRoleImp(ctx, &req, orgRef, account) } func (a *PermissionsAPI) changeRoleImp(ctx context.Context, req *srequest.ChangeRole, organizationRef bson.ObjectID, account *model.Account) http.HandlerFunc { roles, err := a.enforcer.GetRoles(ctx, req.AccountRef, organizationRef) // TODO: add check that role revocation won't leave venue without the owner if err != nil { a.logger.Warn("Failed to fetch account roles", zap.Error(err), mzap.ObjRef("requesting_account_ref", account.ID), mzap.AccRef(req.AccountRef), mzap.ObjRef("role_description_ref", req.NewRoleDescriptionRef)) return response.Auto(a.logger, a.Name(), err) } for _, role := range roles { if err := a.manager.Role().Revoke(ctx, role.DescriptionRef, req.AccountRef, organizationRef); err != nil { a.logger.Warn("Failed to revoke old role", zap.Error(err), mzap.ObjRef("requesting_account_ref", account.ID), mzap.AccRef(req.AccountRef), mzap.ObjRef("role_description_ref", req.NewRoleDescriptionRef), mzap.ObjRef("role_ref", role.DescriptionRef)) // continue... } } role := model.Role{ AccountRef: req.AccountRef, OrganizationRef: organizationRef, DescriptionRef: req.NewRoleDescriptionRef, } if err := a.manager.Role().Assign(ctx, &role); err != nil { a.logger.Warn("Failed to assign new role", zap.Error(err), mzap.ObjRef("requesting_account_ref", account.ID), mzap.AccRef(req.AccountRef), mzap.ObjRef("role_description_ref", req.NewRoleDescriptionRef), mzap.ObjRef("role_ref", req.NewRoleDescriptionRef)) return response.Auto(a.logger, a.Name(), err) } return response.Success(a.logger) }