Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dest: move slack DM to nfydest.Registry #3983

Merged
merged 24 commits into from
Jul 15, 2024
Merged
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
14007f3
Refactor to use nfydest package for destination types
mastercactapus Jul 11, 2024
008fdbd
Add provider registry for notification destinations
mastercactapus Jul 11, 2024
f291155
Refactor DestinationDisplayInfo struct usage
mastercactapus Jul 12, 2024
4e8277e
Integrate nfydest for enhanced destination handling
mastercactapus Jul 12, 2024
c2f1cb4
Merge branch 'master' into dest-registry-slack
mastercactapus Jul 12, 2024
bdf89e2
Enhance SearchByList for better pagination and filtering
mastercactapus Jul 12, 2024
e6df04e
Enable new notification provider registry
mastercactapus Jul 12, 2024
55844ee
Refactor Slack channel constants and field IDs
mastercactapus Jul 12, 2024
5c2f4eb
Add DestReg to GraphQL server config
mastercactapus Jul 12, 2024
48965ef
add slack DM to registry
mastercactapus Jul 12, 2024
ffdd2f9
Refactor validation logic in notification providers
mastercactapus Jul 12, 2024
f66a078
Enhance destination validation handling
mastercactapus Jul 12, 2024
7b0790a
Remove Slack channel and DM destination validations
mastercactapus Jul 12, 2024
f513fc4
Improve error handling in destination field validation
mastercactapus Jul 12, 2024
88163c1
Add support for Slack DM notifications
mastercactapus Jul 12, 2024
80174a8
Handle special case for Slack User Group in search
mastercactapus Jul 12, 2024
82d696e
Handle Slack User Group channel search as special case
mastercactapus Jul 12, 2024
29fa4fe
fix race
mastercactapus Jul 12, 2024
188b679
Revert "fix race"
mastercactapus Jul 12, 2024
d322f9f
handle early shutdown
mastercactapus Jul 12, 2024
2f69da2
Improve error handling in on-call dialogs
mastercactapus Jul 12, 2024
a4261ff
Set type to channel in case of re-order
mastercactapus Jul 12, 2024
27be0d7
Merge branch 'dest-registry-slack' into dest-registry-validate-dest
mastercactapus Jul 12, 2024
f87849a
Merge branch 'master' into dest-registry-validate-dest
mastercactapus Jul 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Refactor to use nfydest package for destination types
- Replaced type definitions with nfydest equivalents
- Updated type info and validation methods
- Aligned dynamic parameters and fields with new interfaces
- Adjusted imports and model mappings in graphql schema
mastercactapus committed Jul 11, 2024
commit 14007f30cc6eb1119000ada8eac51939558b171f
111 changes: 56 additions & 55 deletions graphql2/generated.go

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions graphql2/gqlgen.yml
Original file line number Diff line number Diff line change
@@ -138,3 +138,9 @@ models:
model: github.com/target/goalert/gadb.UIKRuleV1
KeyConfig:
model: github.com/target/goalert/gadb.UIKConfigV1
DestinationFieldConfig:
model: github.com/target/goalert/notification/nfydest.FieldConfig
DestinationTypeInfo:
model: github.com/target/goalert/notification/nfydest.TypeInfo
DynamicParamConfig:
model: github.com/target/goalert/notification/nfydest.DynamicParamConfig
159 changes: 83 additions & 76 deletions graphql2/graphqlapp/destinationtypes.go
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ import (
"github.com/nyaruka/phonenumbers"
"github.com/target/goalert/config"
"github.com/target/goalert/graphql2"
"github.com/target/goalert/notification/nfydest"
"github.com/target/goalert/validation"
"github.com/target/goalert/validation/validate"
)
@@ -246,15 +247,15 @@ func (q *Query) DestinationFieldValidate(ctx context.Context, input graphql2.Des
return false, validation.NewGenericError("unsupported data type")
}

func (q *Query) DestinationTypes(ctx context.Context, isDynamicAction *bool) ([]graphql2.DestinationTypeInfo, error) {
func (q *Query) DestinationTypes(ctx context.Context, isDynamicAction *bool) ([]nfydest.TypeInfo, error) {
cfg := config.FromContext(ctx)
types := []graphql2.DestinationTypeInfo{
types := []nfydest.TypeInfo{
{
Type: destAlert,
Name: "Alert",
Enabled: true,
IsDynamicAction: true,
DynamicParams: []graphql2.DynamicParamConfig{{
SupportsSignals: true,
DynamicParams: []nfydest.DynamicParamConfig{{
ParamID: "summary",
Label: "Summary",
Hint: "Short summary of the alert (used for things like SMS).",
@@ -273,13 +274,15 @@ func (q *Query) DestinationTypes(ctx context.Context, isDynamicAction *bool) ([]
}},
},
{
Type: destTwilioSMS,
Name: "Text Message (SMS)",
Enabled: cfg.Twilio.Enable,
UserDisclaimer: cfg.General.NotificationDisclaimer,
SupportsStatusUpdates: true,
IsContactMethod: true,
RequiredFields: []graphql2.DestinationFieldConfig{{
Type: destTwilioSMS,
Name: "Text Message (SMS)",
Enabled: cfg.Twilio.Enable,
UserDisclaimer: cfg.General.NotificationDisclaimer,
SupportsAlertNotifications: true,
SupportsUserVerification: true,
SupportsStatusUpdates: true,
UserVerificationRequired: true,
RequiredFields: []nfydest.FieldConfig{{
FieldID: fieldPhoneNumber,
Label: "Phone Number",
Hint: "Include country code e.g. +1 (USA), +91 (India), +44 (UK)",
@@ -290,13 +293,15 @@ func (q *Query) DestinationTypes(ctx context.Context, isDynamicAction *bool) ([]
}},
},
{
Type: destTwilioVoice,
Name: "Voice Call",
Enabled: cfg.Twilio.Enable,
UserDisclaimer: cfg.General.NotificationDisclaimer,
IsContactMethod: true,
SupportsStatusUpdates: true,
RequiredFields: []graphql2.DestinationFieldConfig{{
Type: destTwilioVoice,
Name: "Voice Call",
Enabled: cfg.Twilio.Enable,
UserDisclaimer: cfg.General.NotificationDisclaimer,
SupportsAlertNotifications: true,
SupportsUserVerification: true,
SupportsStatusUpdates: true,
UserVerificationRequired: true,
RequiredFields: []nfydest.FieldConfig{{
FieldID: fieldPhoneNumber,
Label: "Phone Number",
Hint: "Include country code e.g. +1 (USA), +91 (India), +44 (UK)",
@@ -307,20 +312,21 @@ func (q *Query) DestinationTypes(ctx context.Context, isDynamicAction *bool) ([]
}},
},
{
Type: destSMTP,
Name: "Email",
Enabled: cfg.SMTP.Enable,
IsContactMethod: true,
SupportsStatusUpdates: true,
IsDynamicAction: false,
RequiredFields: []graphql2.DestinationFieldConfig{{
Type: destSMTP,
Name: "Email",
Enabled: cfg.SMTP.Enable,
SupportsAlertNotifications: true,
SupportsUserVerification: true,
SupportsStatusUpdates: true,
UserVerificationRequired: true,
RequiredFields: []nfydest.FieldConfig{{
FieldID: fieldEmailAddress,
Label: "Email Address",
PlaceholderText: "foobar@example.com",
InputType: "email",
SupportsValidation: true,
}},
DynamicParams: []graphql2.DynamicParamConfig{{
DynamicParams: []nfydest.DynamicParamConfig{{
ParamID: "subject",
Label: "Subject",
Hint: "Subject of the email message.",
@@ -331,15 +337,16 @@ func (q *Query) DestinationTypes(ctx context.Context, isDynamicAction *bool) ([]
}},
},
{
Type: destWebhook,
Name: "Webhook",
Enabled: cfg.Webhook.Enable,
IsContactMethod: true,
IsEPTarget: true,
IsSchedOnCallNotify: true,
SupportsStatusUpdates: true,
StatusUpdatesRequired: true,
RequiredFields: []graphql2.DestinationFieldConfig{{
Type: destWebhook,
Name: "Webhook",
Enabled: cfg.Webhook.Enable,
SupportsUserVerification: true,
SupportsOnCallNotify: true,
SupportsSignals: true,
SupportsStatusUpdates: true,
SupportsAlertNotifications: true,
StatusUpdatesRequired: true,
RequiredFields: []nfydest.FieldConfig{{
FieldID: fieldWebhookURL,
Label: "Webhook URL",
PlaceholderText: "https://example.com",
@@ -348,8 +355,7 @@ func (q *Query) DestinationTypes(ctx context.Context, isDynamicAction *bool) ([]
HintURL: "/docs#webhooks",
SupportsValidation: true,
}},
IsDynamicAction: true,
DynamicParams: []graphql2.DynamicParamConfig{
DynamicParams: []nfydest.DynamicParamConfig{
{
ParamID: "body",
Label: "Body",
@@ -364,13 +370,15 @@ func (q *Query) DestinationTypes(ctx context.Context, isDynamicAction *bool) ([]
},
},
{
Type: destSlackDM,
Name: "Slack Message (DM)",
Enabled: cfg.Slack.Enable,
IsContactMethod: true,
SupportsStatusUpdates: true,
StatusUpdatesRequired: true,
RequiredFields: []graphql2.DestinationFieldConfig{{
Type: destSlackDM,
Name: "Slack Message (DM)",
Enabled: cfg.Slack.Enable,
SupportsAlertNotifications: true,
SupportsUserVerification: true,
SupportsStatusUpdates: true,
UserVerificationRequired: true,
StatusUpdatesRequired: true,
RequiredFields: []nfydest.FieldConfig{{
FieldID: fieldSlackUserID,
Label: "Slack User",
PlaceholderText: "member ID",
@@ -380,32 +388,31 @@ func (q *Query) DestinationTypes(ctx context.Context, isDynamicAction *bool) ([]
}},
},
{
Type: destSlackChan,
Name: "Slack Channel",
Enabled: cfg.Slack.Enable,
IsEPTarget: true,
IsSchedOnCallNotify: true,
IsDynamicAction: true,
SupportsStatusUpdates: true,
StatusUpdatesRequired: true,
RequiredFields: []graphql2.DestinationFieldConfig{{
Type: destSlackChan,
Name: "Slack Channel",
Enabled: cfg.Slack.Enable,
SupportsAlertNotifications: true,
SupportsStatusUpdates: true,
SupportsOnCallNotify: true,
StatusUpdatesRequired: true,
RequiredFields: []nfydest.FieldConfig{{
FieldID: fieldSlackChanID,
Label: "Slack Channel",
InputType: "text",
SupportsSearch: true,
}},
DynamicParams: []graphql2.DynamicParamConfig{{
DynamicParams: []nfydest.DynamicParamConfig{{
ParamID: "message",
Label: "Message",
Hint: "The text of the message to send.",
}},
},
{
Type: destSlackUG,
Name: "Update Slack User Group",
Enabled: cfg.Slack.Enable,
IsSchedOnCallNotify: true,
RequiredFields: []graphql2.DestinationFieldConfig{{
Type: destSlackUG,
Name: "Update Slack User Group",
Enabled: cfg.Slack.Enable,
SupportsOnCallNotify: true,
RequiredFields: []nfydest.FieldConfig{{
FieldID: fieldSlackUGID,
Label: "User Group",
InputType: "text",
@@ -420,35 +427,35 @@ func (q *Query) DestinationTypes(ctx context.Context, isDynamicAction *bool) ([]
}},
},
{
Type: destRotation,
Name: "Rotation",
Enabled: true,
IsEPTarget: true,
RequiredFields: []graphql2.DestinationFieldConfig{{
Type: destRotation,
Name: "Rotation",
Enabled: true,
SupportsAlertNotifications: true,
RequiredFields: []nfydest.FieldConfig{{
FieldID: fieldRotationID,
Label: "Rotation",
InputType: "text",
SupportsSearch: true,
}},
},
{
Type: destSchedule,
Name: "Schedule",
Enabled: true,
IsEPTarget: true,
RequiredFields: []graphql2.DestinationFieldConfig{{
Type: destSchedule,
Name: "Schedule",
Enabled: true,
SupportsAlertNotifications: true,
RequiredFields: []nfydest.FieldConfig{{
FieldID: fieldScheduleID,
Label: "Schedule",
InputType: "text",
SupportsSearch: true,
}},
},
{
Type: destUser,
Name: "User",
Enabled: true,
IsEPTarget: true,
RequiredFields: []graphql2.DestinationFieldConfig{{
Type: destUser,
Name: "User",
Enabled: true,
SupportsAlertNotifications: true,
RequiredFields: []nfydest.FieldConfig{{
FieldID: fieldUserID,
Label: "User",
InputType: "text",
@@ -457,7 +464,7 @@ func (q *Query) DestinationTypes(ctx context.Context, isDynamicAction *bool) ([]
},
}

slices.SortStableFunc(types, func(a, b graphql2.DestinationTypeInfo) int {
slices.SortStableFunc(types, func(a, b nfydest.TypeInfo) int {
if a.Enabled && !b.Enabled {
return -1
}
@@ -471,7 +478,7 @@ func (q *Query) DestinationTypes(ctx context.Context, isDynamicAction *bool) ([]

filtered := types[:0]
for _, t := range types {
if isDynamicAction != nil && *isDynamicAction != t.IsDynamicAction {
if isDynamicAction != nil && *isDynamicAction != t.IsDynamicAction() {
continue
}

62 changes: 0 additions & 62 deletions graphql2/models_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 42 additions & 0 deletions notification/nfydest/provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package nfydest

import "context"

type Provider interface {
ID() string
TypeInfo(ctx context.Context) (*TypeInfo, error)

ValidateField(ctx context.Context, fieldID, value string) (ok bool, err error)
DisplayInfo(ctx context.Context, args map[string]string) (*DisplayInfo, error)
}

type DisplayInfo struct {
Text string
IconURL string
IconAltText string
LinkURL string
}

type SearchOptions struct {
Search string
Omit []string
Cursor string
Limit int
}

type SearchResult struct {
HasNextPage bool
Cursor string
Values []FieldValue
}

type FieldValue struct {
Value string
Label string
IsFavorite bool
}

type FieldSearcher interface {
SearchField(ctx context.Context, fieldID string, options SearchOptions) (*SearchResult, error)
FieldLabel(ctx context.Context, fieldID, value string) (string, error)
}
61 changes: 61 additions & 0 deletions notification/nfydest/typeinfo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package nfydest

type TypeInfo struct {
Type string

Name string
IconURL string
IconAltText string
Enabled bool

RequiredFields []FieldConfig
DynamicParams []DynamicParamConfig

UserDisclaimer string

// Message type info
SupportsStatusUpdates bool
SupportsAlertNotifications bool
SupportsUserVerification bool
SupportsOnCallNotify bool
SupportsSignals bool

UserVerificationRequired bool
StatusUpdatesRequired bool
}

func (t TypeInfo) IsContactMethod() bool {
return t.SupportsAlertNotifications && t.SupportsUserVerification
}

func (t TypeInfo) IsEPTarget() bool {
return t.SupportsAlertNotifications && !t.UserVerificationRequired
}

func (t TypeInfo) IsSchedOnCallNotify() bool {
return t.SupportsOnCallNotify && !t.UserVerificationRequired
}

func (t TypeInfo) IsDynamicAction() bool {
return t.SupportsSignals && !t.UserVerificationRequired
}

type FieldConfig struct {
FieldID string
Label string
Hint string
HintURL string
PlaceholderText string
Prefix string
InputType string
SupportsSearch bool
SupportsValidation bool
}

type DynamicParamConfig struct {
ParamID string
Label string
Hint string
HintURL string
DefaultValue string
}