feat: add http as sms provider (#8540)

# Which Problems Are Solved

Send SMS messages as a HTTP call to a relay, for own logic on handling
different SMS providers.

# How the Problems Are Solved

Add HTTP as SMS provider type and handling of webhook messages in the
notification handlers.

# Additional Changes

Clean up old Twilio events, which were supposed to handle the general
SMS providers with deactivate, activate and remove.

# Additional Context

Partially closes #8270

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Stefan Benz
2024-09-06 15:11:36 +02:00
committed by GitHub
parent d2e0ac07f1
commit 5bdf1a4547
26 changed files with 2536 additions and 593 deletions

View File

@@ -18,12 +18,17 @@ func init() {
eventstore.RegisterFilterEventMapper(AggregateType, SMTPConfigDeactivatedEventType, SMTPConfigDeactivatedEventMapper)
eventstore.RegisterFilterEventMapper(AggregateType, SMTPConfigPasswordChangedEventType, SMTPConfigPasswordChangedEventMapper)
eventstore.RegisterFilterEventMapper(AggregateType, SMTPConfigRemovedEventType, SMTPConfigRemovedEventMapper)
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigTwilioAddedEventType, SMSConfigTwilioAddedEventMapper)
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigTwilioChangedEventType, SMSConfigTwilioChangedEventMapper)
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigTwilioTokenChangedEventType, SMSConfigTwilioTokenChangedEventMapper)
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigActivatedEventType, SMSConfigActivatedEventMapper)
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigDeactivatedEventType, SMSConfigDeactivatedEventMapper)
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigRemovedEventType, SMSConfigRemovedEventMapper)
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigTwilioAddedEventType, eventstore.GenericEventMapper[SMSConfigTwilioAddedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigTwilioChangedEventType, eventstore.GenericEventMapper[SMSConfigTwilioChangedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigTwilioTokenChangedEventType, eventstore.GenericEventMapper[SMSConfigTwilioTokenChangedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigHTTPAddedEventType, eventstore.GenericEventMapper[SMSConfigHTTPAddedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigHTTPChangedEventType, eventstore.GenericEventMapper[SMSConfigHTTPChangedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigTwilioActivatedEventType, eventstore.GenericEventMapper[SMSConfigTwilioActivatedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigTwilioDeactivatedEventType, eventstore.GenericEventMapper[SMSConfigTwilioDeactivatedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigTwilioRemovedEventType, eventstore.GenericEventMapper[SMSConfigTwilioRemovedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigActivatedEventType, eventstore.GenericEventMapper[SMSConfigActivatedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigDeactivatedEventType, eventstore.GenericEventMapper[SMSConfigDeactivatedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigRemovedEventType, eventstore.GenericEventMapper[SMSConfigRemovedEvent])
eventstore.RegisterFilterEventMapper(AggregateType, DebugNotificationProviderFileAddedEventType, DebugNotificationProviderFileAddedEventMapper)
eventstore.RegisterFilterEventMapper(AggregateType, DebugNotificationProviderFileChangedEventType, DebugNotificationProviderFileChangedEventMapper)
eventstore.RegisterFilterEventMapper(AggregateType, DebugNotificationProviderFileRemovedEventType, DebugNotificationProviderFileRemovedEventMapper)

View File

@@ -11,18 +11,25 @@ import (
const (
smsConfigPrefix = "sms.config"
smsConfigTwilioPrefix = "twilio."
smsConfigHTTPPrefix = "http."
SMSConfigTwilioAddedEventType = instanceEventTypePrefix + smsConfigPrefix + smsConfigTwilioPrefix + "added"
SMSConfigTwilioChangedEventType = instanceEventTypePrefix + smsConfigPrefix + smsConfigTwilioPrefix + "changed"
SMSConfigHTTPAddedEventType = instanceEventTypePrefix + smsConfigPrefix + smsConfigHTTPPrefix + "added"
SMSConfigHTTPChangedEventType = instanceEventTypePrefix + smsConfigPrefix + smsConfigHTTPPrefix + "changed"
SMSConfigTwilioTokenChangedEventType = instanceEventTypePrefix + smsConfigPrefix + smsConfigTwilioPrefix + "token.changed"
SMSConfigActivatedEventType = instanceEventTypePrefix + smsConfigPrefix + smsConfigTwilioPrefix + "activated"
SMSConfigDeactivatedEventType = instanceEventTypePrefix + smsConfigPrefix + smsConfigTwilioPrefix + "deactivated"
SMSConfigRemovedEventType = instanceEventTypePrefix + smsConfigPrefix + smsConfigTwilioPrefix + "removed"
SMSConfigTwilioActivatedEventType = instanceEventTypePrefix + smsConfigPrefix + smsConfigTwilioPrefix + "activated"
SMSConfigTwilioDeactivatedEventType = instanceEventTypePrefix + smsConfigPrefix + smsConfigTwilioPrefix + "deactivated"
SMSConfigTwilioRemovedEventType = instanceEventTypePrefix + smsConfigPrefix + smsConfigTwilioPrefix + "removed"
SMSConfigActivatedEventType = instanceEventTypePrefix + smsConfigPrefix + "activated"
SMSConfigDeactivatedEventType = instanceEventTypePrefix + smsConfigPrefix + "deactivated"
SMSConfigRemovedEventType = instanceEventTypePrefix + smsConfigPrefix + "removed"
)
type SMSConfigTwilioAddedEvent struct {
eventstore.BaseEvent `json:"-"`
*eventstore.BaseEvent `json:"-"`
ID string `json:"id,omitempty"`
Description string `json:"description,omitempty"`
SID string `json:"sid,omitempty"`
Token *crypto.CryptoValue `json:"token,omitempty"`
SenderNumber string `json:"senderNumber,omitempty"`
@@ -32,23 +39,29 @@ func NewSMSConfigTwilioAddedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
id,
description string,
sid,
senderNumber string,
token *crypto.CryptoValue,
) *SMSConfigTwilioAddedEvent {
return &SMSConfigTwilioAddedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
SMSConfigTwilioAddedEventType,
),
ID: id,
Description: description,
SID: sid,
Token: token,
SenderNumber: senderNumber,
}
}
func (e *SMSConfigTwilioAddedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *SMSConfigTwilioAddedEvent) Payload() interface{} {
return e
}
@@ -57,22 +70,11 @@ func (e *SMSConfigTwilioAddedEvent) UniqueConstraints() []*eventstore.UniqueCons
return nil
}
func SMSConfigTwilioAddedEventMapper(event eventstore.Event) (eventstore.Event, error) {
smsConfigAdded := &SMSConfigTwilioAddedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := event.Unmarshal(smsConfigAdded)
if err != nil {
return nil, zerrors.ThrowInternal(err, "IAM-smwiR", "unable to unmarshal sms config twilio added")
}
return smsConfigAdded, nil
}
type SMSConfigTwilioChangedEvent struct {
eventstore.BaseEvent `json:"-"`
*eventstore.BaseEvent `json:"-"`
ID string `json:"id,omitempty"`
Description *string `json:"description,omitempty"`
SID *string `json:"sid,omitempty"`
SenderNumber *string `json:"senderNumber,omitempty"`
}
@@ -87,7 +89,7 @@ func NewSMSConfigTwilioChangedEvent(
return nil, zerrors.ThrowPreconditionFailed(nil, "IAM-smn8e", "Errors.NoChangesFound")
}
changeEvent := &SMSConfigTwilioChangedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
SMSConfigTwilioChangedEventType,
@@ -108,12 +110,22 @@ func ChangeSMSConfigTwilioSID(sid string) func(event *SMSConfigTwilioChangedEven
}
}
func ChangeSMSConfigTwilioDescription(description string) func(event *SMSConfigTwilioChangedEvent) {
return func(e *SMSConfigTwilioChangedEvent) {
e.Description = &description
}
}
func ChangeSMSConfigTwilioSenderNumber(senderNumber string) func(event *SMSConfigTwilioChangedEvent) {
return func(e *SMSConfigTwilioChangedEvent) {
e.SenderNumber = &senderNumber
}
}
func (e *SMSConfigTwilioChangedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *SMSConfigTwilioChangedEvent) Payload() interface{} {
return e
}
@@ -122,20 +134,8 @@ func (e *SMSConfigTwilioChangedEvent) UniqueConstraints() []*eventstore.UniqueCo
return nil
}
func SMSConfigTwilioChangedEventMapper(event eventstore.Event) (eventstore.Event, error) {
smsConfigChanged := &SMSConfigTwilioChangedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := event.Unmarshal(smsConfigChanged)
if err != nil {
return nil, zerrors.ThrowInternal(err, "IAM-smwiR", "unable to unmarshal sms config twilio added")
}
return smsConfigChanged, nil
}
type SMSConfigTwilioTokenChangedEvent struct {
eventstore.BaseEvent `json:"-"`
*eventstore.BaseEvent `json:"-"`
ID string `json:"id,omitempty"`
Token *crypto.CryptoValue `json:"token,omitempty"`
@@ -148,7 +148,7 @@ func NewSMSConfigTokenChangedEvent(
token *crypto.CryptoValue,
) *SMSConfigTwilioTokenChangedEvent {
return &SMSConfigTwilioTokenChangedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
SMSConfigTwilioTokenChangedEventType,
@@ -158,6 +158,10 @@ func NewSMSConfigTokenChangedEvent(
}
}
func (e *SMSConfigTwilioTokenChangedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *SMSConfigTwilioTokenChangedEvent) Payload() interface{} {
return e
}
@@ -166,30 +170,130 @@ func (e *SMSConfigTwilioTokenChangedEvent) UniqueConstraints() []*eventstore.Uni
return nil
}
func SMSConfigTwilioTokenChangedEventMapper(event eventstore.Event) (eventstore.Event, error) {
smtpConfigTokenChagned := &SMSConfigTwilioTokenChangedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := event.Unmarshal(smtpConfigTokenChagned)
if err != nil {
return nil, zerrors.ThrowInternal(err, "IAM-fi9Wf", "unable to unmarshal sms config token changed")
}
type SMSConfigHTTPAddedEvent struct {
*eventstore.BaseEvent `json:"-"`
return smtpConfigTokenChagned, nil
ID string `json:"id,omitempty"`
Description string `json:"description,omitempty"`
Endpoint string `json:"endpoint,omitempty"`
}
func NewSMSConfigHTTPAddedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
id,
description,
endpoint string,
) *SMSConfigHTTPAddedEvent {
return &SMSConfigHTTPAddedEvent{
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
SMSConfigHTTPAddedEventType,
),
ID: id,
Description: description,
Endpoint: endpoint,
}
}
func (e *SMSConfigHTTPAddedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *SMSConfigHTTPAddedEvent) Payload() interface{} {
return e
}
func (e *SMSConfigHTTPAddedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
return nil
}
type SMSConfigHTTPChangedEvent struct {
*eventstore.BaseEvent `json:"-"`
ID string `json:"id,omitempty"`
Description *string `json:"description,omitempty"`
Endpoint *string `json:"endpoint,omitempty"`
}
func NewSMSConfigHTTPChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
id string,
changes []SMSConfigHTTPChanges,
) (*SMSConfigHTTPChangedEvent, error) {
if len(changes) == 0 {
return nil, zerrors.ThrowPreconditionFailed(nil, "IAM-smn8e", "Errors.NoChangesFound")
}
changeEvent := &SMSConfigHTTPChangedEvent{
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
SMSConfigHTTPChangedEventType,
),
ID: id,
}
for _, change := range changes {
change(changeEvent)
}
return changeEvent, nil
}
type SMSConfigHTTPChanges func(event *SMSConfigHTTPChangedEvent)
func ChangeSMSConfigHTTPDescription(description string) func(event *SMSConfigHTTPChangedEvent) {
return func(e *SMSConfigHTTPChangedEvent) {
e.Description = &description
}
}
func ChangeSMSConfigHTTPEndpoint(endpoint string) func(event *SMSConfigHTTPChangedEvent) {
return func(e *SMSConfigHTTPChangedEvent) {
e.Endpoint = &endpoint
}
}
func (e *SMSConfigHTTPChangedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *SMSConfigHTTPChangedEvent) Payload() interface{} {
return e
}
func (e *SMSConfigHTTPChangedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
return nil
}
type SMSConfigTwilioActivatedEvent struct {
*eventstore.BaseEvent `json:"-"`
ID string `json:"id,omitempty"`
}
func (e *SMSConfigTwilioActivatedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *SMSConfigTwilioActivatedEvent) Payload() interface{} {
return e
}
func (e *SMSConfigTwilioActivatedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
return nil
}
type SMSConfigActivatedEvent struct {
eventstore.BaseEvent `json:"-"`
ID string `json:"id,omitempty"`
*eventstore.BaseEvent `json:"-"`
ID string `json:"id,omitempty"`
}
func NewSMSConfigTwilioActivatedEvent(
func NewSMSConfigActivatedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
id string,
) *SMSConfigActivatedEvent {
return &SMSConfigActivatedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
SMSConfigActivatedEventType,
@@ -198,6 +302,10 @@ func NewSMSConfigTwilioActivatedEvent(
}
}
func (e *SMSConfigActivatedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *SMSConfigActivatedEvent) Payload() interface{} {
return e
}
@@ -206,21 +314,26 @@ func (e *SMSConfigActivatedEvent) UniqueConstraints() []*eventstore.UniqueConstr
return nil
}
func SMSConfigActivatedEventMapper(event eventstore.Event) (eventstore.Event, error) {
smsConfigActivated := &SMSConfigActivatedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := event.Unmarshal(smsConfigActivated)
if err != nil {
return nil, zerrors.ThrowInternal(err, "IAM-dn92f", "unable to unmarshal sms config twilio activated changed")
}
type SMSConfigTwilioDeactivatedEvent struct {
*eventstore.BaseEvent `json:"-"`
ID string `json:"id,omitempty"`
}
return smsConfigActivated, nil
func (e *SMSConfigTwilioDeactivatedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *SMSConfigTwilioDeactivatedEvent) Payload() interface{} {
return e
}
func (e *SMSConfigTwilioDeactivatedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
return nil
}
type SMSConfigDeactivatedEvent struct {
eventstore.BaseEvent `json:"-"`
ID string `json:"id,omitempty"`
*eventstore.BaseEvent `json:"-"`
ID string `json:"id,omitempty"`
}
func NewSMSConfigDeactivatedEvent(
@@ -229,7 +342,7 @@ func NewSMSConfigDeactivatedEvent(
id string,
) *SMSConfigDeactivatedEvent {
return &SMSConfigDeactivatedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
SMSConfigDeactivatedEventType,
@@ -238,6 +351,10 @@ func NewSMSConfigDeactivatedEvent(
}
}
func (e *SMSConfigDeactivatedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *SMSConfigDeactivatedEvent) Payload() interface{} {
return e
}
@@ -246,21 +363,26 @@ func (e *SMSConfigDeactivatedEvent) UniqueConstraints() []*eventstore.UniqueCons
return nil
}
func SMSConfigDeactivatedEventMapper(event eventstore.Event) (eventstore.Event, error) {
smsConfigDeactivated := &SMSConfigDeactivatedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := event.Unmarshal(smsConfigDeactivated)
if err != nil {
return nil, zerrors.ThrowInternal(err, "IAM-dn92f", "unable to unmarshal sms config twilio deactivated changed")
}
type SMSConfigTwilioRemovedEvent struct {
*eventstore.BaseEvent `json:"-"`
ID string `json:"id,omitempty"`
}
return smsConfigDeactivated, nil
func (e *SMSConfigTwilioRemovedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *SMSConfigTwilioRemovedEvent) Payload() interface{} {
return e
}
func (e *SMSConfigTwilioRemovedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
return nil
}
type SMSConfigRemovedEvent struct {
eventstore.BaseEvent `json:"-"`
ID string `json:"id,omitempty"`
*eventstore.BaseEvent `json:"-"`
ID string `json:"id,omitempty"`
}
func NewSMSConfigRemovedEvent(
@@ -269,7 +391,7 @@ func NewSMSConfigRemovedEvent(
id string,
) *SMSConfigRemovedEvent {
return &SMSConfigRemovedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
BaseEvent: eventstore.NewBaseEventForPush(
ctx,
aggregate,
SMSConfigRemovedEventType,
@@ -278,6 +400,10 @@ func NewSMSConfigRemovedEvent(
}
}
func (e *SMSConfigRemovedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = event
}
func (e *SMSConfigRemovedEvent) Payload() interface{} {
return e
}
@@ -285,15 +411,3 @@ func (e *SMSConfigRemovedEvent) Payload() interface{} {
func (e *SMSConfigRemovedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
return nil
}
func SMSConfigRemovedEventMapper(event eventstore.Event) (eventstore.Event, error) {
smsConfigRemoved := &SMSConfigRemovedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := event.Unmarshal(smsConfigRemoved)
if err != nil {
return nil, zerrors.ThrowInternal(err, "IAM-99iNF", "unable to unmarshal sms config removed")
}
return smsConfigRemoved, nil
}