| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 	"unsafe" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/alerting/notify" | 
					
						
							|  |  |  | 	"github.com/grafana/alerting/receivers" | 
					
						
							|  |  |  | 	jsoniter "github.com/json-iterator/go" | 
					
						
							|  |  |  | 	"github.com/modern-go/reflect2" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/util" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ContactPointFromContactPointExport parses the database model of the contact point (group of integrations) where settings are represented in JSON,
 | 
					
						
							|  |  |  | // to strongly typed ContactPoint.
 | 
					
						
							|  |  |  | func ContactPointFromContactPointExport(rawContactPoint definitions.ContactPointExport) (definitions.ContactPoint, error) { | 
					
						
							|  |  |  | 	j := jsoniter.ConfigCompatibleWithStandardLibrary | 
					
						
							|  |  |  | 	j.RegisterExtension(&contactPointsExtension{}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	contactPoint := definitions.ContactPoint{ | 
					
						
							|  |  |  | 		Name: rawContactPoint.Name, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var errs []error | 
					
						
							|  |  |  | 	for _, rawIntegration := range rawContactPoint.Receivers { | 
					
						
							|  |  |  | 		err := parseIntegration(j, &contactPoint, rawIntegration.Type, rawIntegration.DisableResolveMessage, json.RawMessage(rawIntegration.Settings)) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			// accumulate errors to report all at once.
 | 
					
						
							|  |  |  | 			errs = append(errs, fmt.Errorf("failed to parse %s integration (uid:%s): %w", rawIntegration.Type, rawIntegration.UID, err)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return contactPoint, errors.Join(errs...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ContactPointToContactPointExport converts definitions.ContactPoint to notify.APIReceiver.
 | 
					
						
							|  |  |  | // It uses special extension for json-iterator API that properly handles marshalling of some specific fields.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //nolint:gocyclo
 | 
					
						
							|  |  |  | func ContactPointToContactPointExport(cp definitions.ContactPoint) (notify.APIReceiver, error) { | 
					
						
							|  |  |  | 	j := jsoniter.ConfigCompatibleWithStandardLibrary | 
					
						
							|  |  |  | 	// use json iterator with custom extension that has special codec for some field.
 | 
					
						
							|  |  |  | 	// This is needed to keep the API models clean and convert from database model
 | 
					
						
							|  |  |  | 	j.RegisterExtension(&contactPointsExtension{}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 	contactPointsLength := len(cp.Alertmanager) + len(cp.Dingding) + len(cp.Discord) + len(cp.Email) + | 
					
						
							|  |  |  | 		len(cp.Googlechat) + len(cp.Kafka) + len(cp.Line) + len(cp.Opsgenie) + | 
					
						
							|  |  |  | 		len(cp.Pagerduty) + len(cp.OnCall) + len(cp.Pushover) + len(cp.Sensugo) + | 
					
						
							|  |  |  | 		len(cp.Sns) + len(cp.Slack) + len(cp.Teams) + len(cp.Telegram) + | 
					
						
							|  |  |  | 		len(cp.Threema) + len(cp.Victorops) + len(cp.Webhook) + len(cp.Wecom) + | 
					
						
							| 
									
										
										
										
											2024-08-22 22:47:48 +08:00
										 |  |  | 		len(cp.Webex) + len(cp.Mqtt) | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	integration := make([]*notify.GrafanaIntegrationConfig, 0, contactPointsLength) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var errs []error | 
					
						
							|  |  |  | 	for _, i := range cp.Alertmanager { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "prometheus-alertmanager", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.Dingding { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "dingding", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.Discord { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "discord", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.Email { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "email", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.Googlechat { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "googlechat", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-02-22 01:51:38 +08:00
										 |  |  | 	for _, i := range cp.Jira { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "jira", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		integration = append(integration, el) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	for _, i := range cp.Kafka { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "kafka", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.Line { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "line", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-08-22 22:47:48 +08:00
										 |  |  | 	for _, i := range cp.Mqtt { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "mqtt", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		integration = append(integration, el) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	for _, i := range cp.Opsgenie { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "opsgenie", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.Pagerduty { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "pagerduty", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.OnCall { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "oncall", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.Pushover { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "pushover", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.Sensugo { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "sensugo", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-06-07 23:49:49 +08:00
										 |  |  | 	for _, i := range cp.Sns { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "sns", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2024-06-07 23:49:49 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	for _, i := range cp.Slack { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "slack", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.Teams { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "teams", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.Telegram { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "telegram", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.Threema { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "threema", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.Victorops { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "victorops", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.Webhook { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "webhook", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.Wecom { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "wecom", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range cp.Webex { | 
					
						
							|  |  |  | 		el, err := marshallIntegration(j, "webex", i, i.DisableResolveMessage) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs = append(errs, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 		integration = append(integration, el) | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	if len(errs) > 0 { | 
					
						
							|  |  |  | 		return notify.APIReceiver{}, errors.Join(errs...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	contactPoint := notify.APIReceiver{ | 
					
						
							|  |  |  | 		ConfigReceiver:      notify.ConfigReceiver{Name: cp.Name}, | 
					
						
							|  |  |  | 		GrafanaIntegrations: notify.GrafanaIntegrations{Integrations: integration}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return contactPoint, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // marshallIntegration converts the API model integration to the storage model that contains settings in the JSON format.
 | 
					
						
							|  |  |  | // The secret fields are not encrypted.
 | 
					
						
							|  |  |  | func marshallIntegration(json jsoniter.API, integrationType string, integration interface{}, disableResolveMessage *bool) (*notify.GrafanaIntegrationConfig, error) { | 
					
						
							|  |  |  | 	data, err := json.Marshal(integration) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("failed to marshall integration '%s' to JSON: %w", integrationType, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	e := ¬ify.GrafanaIntegrationConfig{ | 
					
						
							|  |  |  | 		Type:     integrationType, | 
					
						
							|  |  |  | 		Settings: data, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if disableResolveMessage != nil { | 
					
						
							|  |  |  | 		e.DisableResolveMessage = *disableResolveMessage | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return e, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //nolint:gocyclo
 | 
					
						
							|  |  |  | func parseIntegration(json jsoniter.API, result *definitions.ContactPoint, receiverType string, disableResolveMessage bool, data json.RawMessage) error { | 
					
						
							|  |  |  | 	var err error | 
					
						
							|  |  |  | 	var disable *bool | 
					
						
							|  |  |  | 	if disableResolveMessage { // populate only if true
 | 
					
						
							|  |  |  | 		disable = util.Pointer(disableResolveMessage) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	switch strings.ToLower(receiverType) { | 
					
						
							|  |  |  | 	case "prometheus-alertmanager": | 
					
						
							|  |  |  | 		integration := definitions.AlertmanagerIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Alertmanager = append(result.Alertmanager, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "dingding": | 
					
						
							|  |  |  | 		integration := definitions.DingdingIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Dingding = append(result.Dingding, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "discord": | 
					
						
							|  |  |  | 		integration := definitions.DiscordIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Discord = append(result.Discord, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "email": | 
					
						
							|  |  |  | 		integration := definitions.EmailIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Email = append(result.Email, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "googlechat": | 
					
						
							|  |  |  | 		integration := definitions.GooglechatIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Googlechat = append(result.Googlechat, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-02-22 01:51:38 +08:00
										 |  |  | 	case "jira": | 
					
						
							|  |  |  | 		integration := definitions.JiraIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Jira = append(result.Jira, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	case "kafka": | 
					
						
							|  |  |  | 		integration := definitions.KafkaIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Kafka = append(result.Kafka, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "line": | 
					
						
							|  |  |  | 		integration := definitions.LineIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Line = append(result.Line, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-08-22 22:47:48 +08:00
										 |  |  | 	case "mqtt": | 
					
						
							|  |  |  | 		integration := definitions.MqttIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Mqtt = append(result.Mqtt, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	case "opsgenie": | 
					
						
							|  |  |  | 		integration := definitions.OpsgenieIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Opsgenie = append(result.Opsgenie, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "pagerduty": | 
					
						
							|  |  |  | 		integration := definitions.PagerdutyIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Pagerduty = append(result.Pagerduty, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "oncall": | 
					
						
							|  |  |  | 		integration := definitions.OnCallIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.OnCall = append(result.OnCall, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "pushover": | 
					
						
							|  |  |  | 		integration := definitions.PushoverIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Pushover = append(result.Pushover, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "sensugo": | 
					
						
							|  |  |  | 		integration := definitions.SensugoIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Sensugo = append(result.Sensugo, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-07 23:49:49 +08:00
										 |  |  | 	case "sns": | 
					
						
							|  |  |  | 		integration := definitions.SnsIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Sns = append(result.Sns, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | 	case "slack": | 
					
						
							|  |  |  | 		integration := definitions.SlackIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Slack = append(result.Slack, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "teams": | 
					
						
							|  |  |  | 		integration := definitions.TeamsIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Teams = append(result.Teams, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "telegram": | 
					
						
							|  |  |  | 		integration := definitions.TelegramIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Telegram = append(result.Telegram, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "threema": | 
					
						
							|  |  |  | 		integration := definitions.ThreemaIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Threema = append(result.Threema, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "victorops": | 
					
						
							|  |  |  | 		integration := definitions.VictoropsIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Victorops = append(result.Victorops, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "webhook": | 
					
						
							|  |  |  | 		integration := definitions.WebhookIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Webhook = append(result.Webhook, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "wecom": | 
					
						
							|  |  |  | 		integration := definitions.WecomIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Wecom = append(result.Wecom, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case "webex": | 
					
						
							|  |  |  | 		integration := definitions.WebexIntegration{DisableResolveMessage: disable} | 
					
						
							|  |  |  | 		if err = json.Unmarshal(data, &integration); err == nil { | 
					
						
							|  |  |  | 			result.Webex = append(result.Webex, integration) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		err = fmt.Errorf("integration %s is not supported", receiverType) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // contactPointsExtension extends jsoniter with special codecs for some integrations' fields that are encoded differently in the legacy configuration.
 | 
					
						
							|  |  |  | type contactPointsExtension struct { | 
					
						
							|  |  |  | 	jsoniter.DummyExtension | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c contactPointsExtension) UpdateStructDescriptor(structDescriptor *jsoniter.StructDescriptor) { | 
					
						
							|  |  |  | 	if structDescriptor.Type == reflect2.TypeOf(definitions.EmailIntegration{}) { | 
					
						
							|  |  |  | 		bind := structDescriptor.GetField("Addresses") | 
					
						
							|  |  |  | 		codec := &emailAddressCodec{} | 
					
						
							|  |  |  | 		bind.Decoder = codec | 
					
						
							|  |  |  | 		bind.Encoder = codec | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if structDescriptor.Type == reflect2.TypeOf(definitions.PushoverIntegration{}) { | 
					
						
							|  |  |  | 		codec := &numberAsStringCodec{} | 
					
						
							|  |  |  | 		for _, field := range []string{"AlertingPriority", "OKPriority"} { | 
					
						
							|  |  |  | 			desc := structDescriptor.GetField(field) | 
					
						
							|  |  |  | 			desc.Decoder = codec | 
					
						
							|  |  |  | 			desc.Encoder = codec | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// the same logic is in the pushover.NewConfig in alerting module
 | 
					
						
							|  |  |  | 		codec = &numberAsStringCodec{ignoreError: true} | 
					
						
							|  |  |  | 		for _, field := range []string{"Retry", "Expire"} { | 
					
						
							|  |  |  | 			desc := structDescriptor.GetField(field) | 
					
						
							|  |  |  | 			desc.Decoder = codec | 
					
						
							|  |  |  | 			desc.Encoder = codec | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if structDescriptor.Type == reflect2.TypeOf(definitions.WebhookIntegration{}) { | 
					
						
							|  |  |  | 		codec := &numberAsStringCodec{ignoreError: true} | 
					
						
							|  |  |  | 		desc := structDescriptor.GetField("MaxAlerts") | 
					
						
							|  |  |  | 		desc.Decoder = codec | 
					
						
							|  |  |  | 		desc.Encoder = codec | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if structDescriptor.Type == reflect2.TypeOf(definitions.OnCallIntegration{}) { | 
					
						
							|  |  |  | 		codec := &numberAsStringCodec{ignoreError: true} | 
					
						
							|  |  |  | 		desc := structDescriptor.GetField("MaxAlerts") | 
					
						
							|  |  |  | 		desc.Decoder = codec | 
					
						
							|  |  |  | 		desc.Encoder = codec | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-09-18 03:11:16 +08:00
										 |  |  | 	if structDescriptor.Type == reflect2.TypeOf(definitions.MqttIntegration{}) { | 
					
						
							|  |  |  | 		codec := &numberAsStringCodec{ignoreError: true} | 
					
						
							|  |  |  | 		desc := structDescriptor.GetField("QoS") | 
					
						
							|  |  |  | 		desc.Decoder = codec | 
					
						
							|  |  |  | 		desc.Encoder = codec | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-07-21 22:24:24 +08:00
										 |  |  | 	if structDescriptor.Type == reflect2.TypeOf(definitions.JiraIntegration{}) { | 
					
						
							|  |  |  | 		bind := structDescriptor.GetField("Fields") | 
					
						
							|  |  |  | 		codec := &mapToJSONStringCodec{} | 
					
						
							|  |  |  | 		bind.Decoder = codec | 
					
						
							|  |  |  | 		bind.Encoder = codec | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-10-13 05:33:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type emailAddressCodec struct{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *emailAddressCodec) IsEmpty(ptr unsafe.Pointer) bool { | 
					
						
							|  |  |  | 	f := *(*[]string)(ptr) | 
					
						
							|  |  |  | 	return len(f) == 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *emailAddressCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) { | 
					
						
							|  |  |  | 	f := *(*[]string)(ptr) | 
					
						
							|  |  |  | 	addresses := strings.Join(f, ";") | 
					
						
							|  |  |  | 	stream.WriteString(addresses) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *emailAddressCodec) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { | 
					
						
							|  |  |  | 	s := iter.ReadString() | 
					
						
							|  |  |  | 	emails := strings.FieldsFunc(strings.Trim(s, "\""), func(r rune) bool { | 
					
						
							|  |  |  | 		switch r { | 
					
						
							|  |  |  | 		case ',', ';', '\n': | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	*((*[]string)(ptr)) = emails | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // converts a string representation of a number to *int64
 | 
					
						
							|  |  |  | type numberAsStringCodec struct { | 
					
						
							|  |  |  | 	ignoreError bool // if true, then ignores the error and keeps value nil
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *numberAsStringCodec) IsEmpty(ptr unsafe.Pointer) bool { | 
					
						
							|  |  |  | 	return *((*(*int))(ptr)) == nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *numberAsStringCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) { | 
					
						
							|  |  |  | 	val := *((*(*int))(ptr)) | 
					
						
							|  |  |  | 	if val == nil { | 
					
						
							|  |  |  | 		stream.WriteNil() | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	stream.WriteInt(*val) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *numberAsStringCodec) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { | 
					
						
							|  |  |  | 	valueType := iter.WhatIsNext() | 
					
						
							|  |  |  | 	var value int64 | 
					
						
							|  |  |  | 	switch valueType { | 
					
						
							|  |  |  | 	case jsoniter.NumberValue: | 
					
						
							|  |  |  | 		value = iter.ReadInt64() | 
					
						
							|  |  |  | 	case jsoniter.StringValue: | 
					
						
							|  |  |  | 		var num receivers.OptionalNumber | 
					
						
							|  |  |  | 		err := num.UnmarshalJSON(iter.ReadStringAsSlice()) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			iter.ReportError("numberAsStringCodec", fmt.Sprintf("failed to unmarshall string as OptionalNumber: %s", err.Error())) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if num.String() == "" { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		value, err = num.Int64() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			if !d.ignoreError { | 
					
						
							|  |  |  | 				iter.ReportError("numberAsStringCodec", fmt.Sprintf("string does not represent an integer number: %s", err.Error())) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case jsoniter.NilValue: | 
					
						
							|  |  |  | 		iter.ReadNil() | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		iter.ReportError("numberAsStringCodec", "not number or string") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	*((*(*int64))(ptr)) = &value | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-07-21 22:24:24 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | type mapToJSONStringCodec struct{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *mapToJSONStringCodec) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { | 
					
						
							|  |  |  | 	var str string | 
					
						
							|  |  |  | 	switch iter.WhatIsNext() { | 
					
						
							|  |  |  | 	case jsoniter.ObjectValue: | 
					
						
							|  |  |  | 		var raw map[string]any | 
					
						
							|  |  |  | 		iter.ReadVal(&raw) | 
					
						
							|  |  |  | 		b, err := json.Marshal(raw) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			iter.ReportError("mapToJSONStringCodec.Decode", err.Error()) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		str = string(b) | 
					
						
							|  |  |  | 	case jsoniter.NilValue: | 
					
						
							|  |  |  | 		iter.ReadNil() | 
					
						
							|  |  |  | 		*(**string)(ptr) = nil | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		iter.ReportError("mapToJSONStringCodec.Decode", "unsupported input type") | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Allocate a new string and set the pointer.
 | 
					
						
							|  |  |  | 	newStr := str | 
					
						
							|  |  |  | 	*(**string)(ptr) = &newStr | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // IsEmpty is used by Encoder to determine if the field is empty.
 | 
					
						
							|  |  |  | func (d *mapToJSONStringCodec) IsEmpty(ptr unsafe.Pointer) bool { | 
					
						
							|  |  |  | 	strPtr := *(**string)(ptr) | 
					
						
							|  |  |  | 	return strPtr == nil || *strPtr == "" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This method is not used in production code, but is required by a test that ensure marshalling and unmarshalling does not change the value.
 | 
					
						
							|  |  |  | func (d *mapToJSONStringCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) { | 
					
						
							|  |  |  | 	strPtr := *(**string)(ptr) | 
					
						
							|  |  |  | 	if strPtr == nil { | 
					
						
							|  |  |  | 		stream.WriteNil() | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Validate the string contains valid JSON
 | 
					
						
							|  |  |  | 	var raw any | 
					
						
							|  |  |  | 	if err := json.Unmarshal([]byte(*strPtr), &raw); err != nil { | 
					
						
							|  |  |  | 		stream.Error = fmt.Errorf("invalid JSON in *string field: %w", err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Write the parsed value as native JSON (object, array, etc.)
 | 
					
						
							|  |  |  | 	stream.WriteVal(raw) | 
					
						
							|  |  |  | } |