diff --git a/pkg/iam/organization_service.go b/pkg/iam/organization_service.go index e177b85c9..b77547b96 100644 --- a/pkg/iam/organization_service.go +++ b/pkg/iam/organization_service.go @@ -273,6 +273,15 @@ func (s *OrganizationService) UpdateMempership( return fmt.Errorf("cannot update membership: %w", err) } + profile := &coredata.MembershipProfile{} + if err := profile.LoadByIdentityIDAndOrganizationID(ctx, tx, scope, membership.IdentityID, membership.OrganizationID); err != nil { + return fmt.Errorf("cannot load profile: %w", err) + } + + if err := webhook.InsertData(ctx, tx, scope, organizationID, coredata.WebhookEventTypeUserUpdated, webhooktypes.NewUser(profile, &membership)); err != nil { + return fmt.Errorf("cannot insert webhook event: %w", err) + } + return nil }, ); err != nil { @@ -323,7 +332,7 @@ func (s *OrganizationService) RemoveUser( } } - if err := webhook.InsertData(ctx, tx, scope, organizationID, coredata.WebhookEventTypeUserDeleted, webhooktypes.NewUser(&profile)); err != nil { + if err := webhook.InsertData(ctx, tx, scope, organizationID, coredata.WebhookEventTypeUserDeleted, webhooktypes.NewUser(&profile, membership)); err != nil { return fmt.Errorf("cannot insert webhook event: %w", err) } @@ -946,7 +955,7 @@ func (s *OrganizationService) CreateUser(ctx context.Context, req *CreateUserReq return fmt.Errorf("cannot insert membership: %w", err) } - if err := webhook.InsertData(ctx, conn, scope, req.OrganizationID, coredata.WebhookEventTypeUserCreated, webhooktypes.NewUser(profile)); err != nil { + if err := webhook.InsertData(ctx, conn, scope, req.OrganizationID, coredata.WebhookEventTypeUserCreated, webhooktypes.NewUser(profile, membership)); err != nil { return fmt.Errorf("cannot insert webhook event: %w", err) } @@ -999,7 +1008,12 @@ func (s *OrganizationService) UpdateUser(ctx context.Context, req *UpdateUserReq return fmt.Errorf("cannot update profile: %w", err) } - if err := webhook.InsertData(ctx, conn, scope, profile.OrganizationID, coredata.WebhookEventTypeUserUpdated, webhooktypes.NewUser(profile)); err != nil { + membership := &coredata.Membership{} + if err := membership.LoadByIdentityIDAndOrganizationID(ctx, conn, scope, profile.IdentityID, profile.OrganizationID); err != nil { + return fmt.Errorf("cannot load membership: %w", err) + } + + if err := webhook.InsertData(ctx, conn, scope, profile.OrganizationID, coredata.WebhookEventTypeUserUpdated, webhooktypes.NewUser(profile, membership)); err != nil { return fmt.Errorf("cannot insert webhook event: %w", err) } diff --git a/pkg/iam/scim/service.go b/pkg/iam/scim/service.go index cb8c5f81b..2cc14c996 100644 --- a/pkg/iam/scim/service.go +++ b/pkg/iam/scim/service.go @@ -330,7 +330,7 @@ func (s *Service) CreateUser( } } - if err := webhook.InsertData(ctx, tx, scope, config.OrganizationID, eventType, webhooktypes.NewUser(profile)); err != nil { + if err := webhook.InsertData(ctx, tx, scope, config.OrganizationID, eventType, webhooktypes.NewUser(profile, membership)); err != nil { return fmt.Errorf("cannot insert webhook event: %w", err) } @@ -748,7 +748,7 @@ func (s *Service) updateUser( } } - if err := webhook.InsertData(ctx, tx, scope, config.OrganizationID, coredata.WebhookEventTypeUserUpdated, webhooktypes.NewUser(profile)); err != nil { + if err := webhook.InsertData(ctx, tx, scope, config.OrganizationID, coredata.WebhookEventTypeUserUpdated, webhooktypes.NewUser(profile, membership)); err != nil { return fmt.Errorf("cannot insert webhook event: %w", err) } @@ -797,25 +797,30 @@ func (s *Service) DeleteUser( return fmt.Errorf("cannot expire pending invitations: %w", err) } - membership := &coredata.Membership{} - if err := membership.LoadByIdentityIDAndOrganizationID( + var membership *coredata.Membership + m := &coredata.Membership{} + if err := m.LoadByIdentityIDAndOrganizationID( ctx, tx, scope, profile.IdentityID, config.OrganizationID, ); err != nil { if !errors.Is(err, coredata.ErrResourceNotFound) { return fmt.Errorf("cannot load membership: %w", err) } } else { - if err := membership.Delete(ctx, tx, scope, membership.ID); err != nil { - return fmt.Errorf("cannot delete membership: %w", err) - } + membership = m + } + + if err := webhook.InsertData(ctx, tx, scope, config.OrganizationID, coredata.WebhookEventTypeUserDeleted, webhooktypes.NewUser(profile, membership)); err != nil { + return fmt.Errorf("cannot insert webhook event: %w", err) } if err := profile.Delete(ctx, tx, scope, profile.ID); err != nil { return fmt.Errorf("cannot delete profile: %w", err) } - if err := webhook.InsertData(ctx, tx, scope, config.OrganizationID, coredata.WebhookEventTypeUserDeleted, webhooktypes.NewUser(profile)); err != nil { - return fmt.Errorf("cannot insert webhook event: %w", err) + if membership != nil { + if err := membership.Delete(ctx, tx, scope, membership.ID); err != nil { + return fmt.Errorf("cannot delete membership: %w", err) + } } return nil diff --git a/pkg/probod/probod.go b/pkg/probod/probod.go index bdc61e91a..4794c6d77 100644 --- a/pkg/probod/probod.go +++ b/pkg/probod/probod.go @@ -612,6 +612,7 @@ func (impl *Implm) Run( Interval: time.Duration(impl.cfg.Notifications.Webhook.SenderInterval) * time.Second, CacheTTL: time.Duration(impl.cfg.Notifications.Webhook.CacheTTL) * time.Second, EncryptionKey: encryptionKey, + Host: baseURL.String(), }) wg.Go( func() { diff --git a/pkg/webhook/sender.go b/pkg/webhook/sender.go index fc18f4a64..0f298467f 100644 --- a/pkg/webhook/sender.go +++ b/pkg/webhook/sender.go @@ -43,6 +43,7 @@ type ( logger *log.Logger httpClient *http.Client encryptionKey cipher.EncryptionKey + host string cache sync.Map cacheCreatedAt time.Time cacheTTL time.Duration @@ -60,6 +61,7 @@ type ( Timeout time.Duration CacheTTL time.Duration EncryptionKey cipher.EncryptionKey + Host string } pendingDelivery struct { @@ -88,6 +90,7 @@ func NewSender(pg *pg.Client, logger *log.Logger, cfg Config) *Sender { logger: logger, httpClient: httpclient.DefaultPooledClient(httpclient.WithLogger(logger)), encryptionKey: cfg.EncryptionKey, + host: cfg.Host, cacheCreatedAt: time.Now(), cacheTTL: cfg.CacheTTL, interval: cfg.Interval, @@ -310,6 +313,7 @@ func (s *Sender) doHTTPCall( req.Header.Set("X-Probo-Webhook-Organization-Id", webhookData.OrganizationID.String()) req.Header.Set("X-Probo-Webhook-Timestamp", timestamp) req.Header.Set("X-Probo-Webhook-Signature", signature) + req.Header.Set("X-Probo-Webhook-Host", s.host) resp, err := s.httpClient.Do(req) if err != nil { diff --git a/pkg/webhook/types/user.go b/pkg/webhook/types/user.go index b456a15d2..b9d16a29f 100644 --- a/pkg/webhook/types/user.go +++ b/pkg/webhook/types/user.go @@ -22,31 +22,38 @@ import ( "go.probo.inc/probo/pkg/mail" ) -type User struct { - ID gid.GID `json:"id"` - OrganizationID gid.GID `json:"organizationId"` - EmailAddress mail.Addr `json:"emailAddress"` - FullName string `json:"fullName"` - Kind *string `json:"kind"` - Source coredata.ProfileSource `json:"source"` - State coredata.ProfileState `json:"state"` - AdditionalEmailAddresses mail.Addrs `json:"additionalEmailAddresses"` - Position *string `json:"position"` - ContractStartDate *time.Time `json:"contractStartDate"` - ContractEndDate *time.Time `json:"contractEndDate"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` -} +type ( + User struct { + ID gid.GID `json:"id"` + OrganizationID gid.GID `json:"organizationId"` + EmailAddress mail.Addr `json:"emailAddress"` + FullName string `json:"fullName"` + Kind *string `json:"kind"` + Source coredata.ProfileSource `json:"source"` + AdditionalEmailAddresses mail.Addrs `json:"additionalEmailAddresses"` + Position *string `json:"position"` + ContractStartDate *time.Time `json:"contractStartDate"` + ContractEndDate *time.Time `json:"contractEndDate"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + Membership *UserMembership `json:"membership"` + } -func NewUser(p *coredata.MembershipProfile) *User { - return &User{ + UserMembership struct { + ID gid.GID `json:"id"` + Role coredata.MembershipRole `json:"role"` + State coredata.ProfileState `json:"state"` + } +) + +func NewUser(p *coredata.MembershipProfile, m *coredata.Membership) *User { + u := &User{ ID: p.ID, OrganizationID: p.OrganizationID, EmailAddress: p.EmailAddress, FullName: p.FullName, Kind: p.Kind, Source: p.Source, - State: p.State, AdditionalEmailAddresses: p.AdditionalEmailAddresses, Position: p.Position, ContractStartDate: p.ContractStartDate, @@ -54,4 +61,14 @@ func NewUser(p *coredata.MembershipProfile) *User { CreatedAt: p.CreatedAt, UpdatedAt: p.UpdatedAt, } + + if m != nil { + u.Membership = &UserMembership{ + ID: m.ID, + Role: m.Role, + State: p.State, + } + } + + return u }