fix(alerting): Resolve Telegram issue with bad payload when condition has " in it
				
					
				
			This commit is contained in:
		| @ -2,6 +2,7 @@ package telegram | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| @ -36,7 +37,7 @@ func (provider *AlertProvider) IsValid() bool { | ||||
|  | ||||
| // Send an alert using the provider | ||||
| func (provider *AlertProvider) Send(endpoint *core.Endpoint, alert *alert.Alert, result *core.Result, resolved bool) error { | ||||
| 	buffer := bytes.NewBuffer([]byte(provider.buildRequestBody(endpoint, alert, result, resolved))) | ||||
| 	buffer := bytes.NewBuffer(provider.buildRequestBody(endpoint, alert, result, resolved)) | ||||
| 	apiURL := provider.APIURL | ||||
| 	if apiURL == "" { | ||||
| 		apiURL = defaultAPIURL | ||||
| @ -58,13 +59,19 @@ func (provider *AlertProvider) Send(endpoint *core.Endpoint, alert *alert.Alert, | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| type Body struct { | ||||
| 	ChatID    string `json:"chat_id"` | ||||
| 	Text      string `json:"text"` | ||||
| 	ParseMode string `json:"parse_mode"` | ||||
| } | ||||
|  | ||||
| // buildRequestBody builds the request body for the provider | ||||
| func (provider *AlertProvider) buildRequestBody(endpoint *core.Endpoint, alert *alert.Alert, result *core.Result, resolved bool) string { | ||||
| func (provider *AlertProvider) buildRequestBody(endpoint *core.Endpoint, alert *alert.Alert, result *core.Result, resolved bool) []byte { | ||||
| 	var message, results string | ||||
| 	if resolved { | ||||
| 		message = fmt.Sprintf("An alert for *%s* has been resolved:\\n—\\n    _healthcheck passing successfully %d time(s) in a row_\\n—  ", endpoint.DisplayName(), alert.FailureThreshold) | ||||
| 		message = fmt.Sprintf("An alert for *%s* has been resolved:\n—\n    _healthcheck passing successfully %d time(s) in a row_\n—  ", endpoint.DisplayName(), alert.FailureThreshold) | ||||
| 	} else { | ||||
| 		message = fmt.Sprintf("An alert for *%s* has been triggered:\\n—\\n    _healthcheck failed %d time(s) in a row_\\n—  ", endpoint.DisplayName(), alert.FailureThreshold) | ||||
| 		message = fmt.Sprintf("An alert for *%s* has been triggered:\n—\n    _healthcheck failed %d time(s) in a row_\n—  ", endpoint.DisplayName(), alert.FailureThreshold) | ||||
| 	} | ||||
| 	for _, conditionResult := range result.ConditionResults { | ||||
| 		var prefix string | ||||
| @ -73,15 +80,20 @@ func (provider *AlertProvider) buildRequestBody(endpoint *core.Endpoint, alert * | ||||
| 		} else { | ||||
| 			prefix = "❌" | ||||
| 		} | ||||
| 		results += fmt.Sprintf("%s - `%s`\\n", prefix, conditionResult.Condition) | ||||
| 		results += fmt.Sprintf("%s - `%s`\n", prefix, conditionResult.Condition) | ||||
| 	} | ||||
| 	var text string | ||||
| 	if len(alert.GetDescription()) > 0 { | ||||
| 		text = fmt.Sprintf("⛑ *Gatus* \\n%s \\n*Description* \\n_%s_  \\n\\n*Condition results*\\n%s", message, alert.GetDescription(), results) | ||||
| 		text = fmt.Sprintf("⛑ *Gatus* \n%s \n*Description* \n_%s_  \n\n*Condition results*\n%s", message, alert.GetDescription(), results) | ||||
| 	} else { | ||||
| 		text = fmt.Sprintf("⛑ *Gatus* \\n%s \\n*Condition results*\\n%s", message, results) | ||||
| 		text = fmt.Sprintf("⛑ *Gatus* \n%s \n*Condition results*\n%s", message, results) | ||||
| 	} | ||||
| 	return fmt.Sprintf(`{"chat_id": "%s", "text": "%s", "parse_mode": "MARKDOWN"}`, provider.ID, text) | ||||
| 	body, _ := json.Marshal(Body{ | ||||
| 		ChatID:    provider.ID, | ||||
| 		Text:      text, | ||||
| 		ParseMode: "MARKDOWN", | ||||
| 	}) | ||||
| 	return body | ||||
| } | ||||
|  | ||||
| // GetDefaultAlert returns the provider's default alert configuration | ||||
|  | ||||
| @ -124,14 +124,14 @@ func TestAlertProvider_buildRequestBody(t *testing.T) { | ||||
| 			Provider:     AlertProvider{ID: "123"}, | ||||
| 			Alert:        alert.Alert{Description: &firstDescription, SuccessThreshold: 5, FailureThreshold: 3}, | ||||
| 			Resolved:     false, | ||||
| 			ExpectedBody: "{\"chat_id\": \"123\", \"text\": \"⛑ *Gatus* \\nAn alert for *endpoint-name* has been triggered:\\n—\\n    _healthcheck failed 3 time(s) in a row_\\n—   \\n*Description* \\n_description-1_  \\n\\n*Condition results*\\n❌ - `[CONNECTED] == true`\\n❌ - `[STATUS] == 200`\\n\", \"parse_mode\": \"MARKDOWN\"}", | ||||
| 			ExpectedBody: "{\"chat_id\":\"123\",\"text\":\"⛑ *Gatus* \\nAn alert for *endpoint-name* has been triggered:\\n—\\n    _healthcheck failed 3 time(s) in a row_\\n—   \\n*Description* \\n_description-1_  \\n\\n*Condition results*\\n❌ - `[CONNECTED] == true`\\n❌ - `[STATUS] == 200`\\n\",\"parse_mode\":\"MARKDOWN\"}", | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name:         "resolved", | ||||
| 			Provider:     AlertProvider{ID: "123"}, | ||||
| 			Alert:        alert.Alert{Description: &secondDescription, SuccessThreshold: 5, FailureThreshold: 3}, | ||||
| 			Resolved:     true, | ||||
| 			ExpectedBody: "{\"chat_id\": \"123\", \"text\": \"⛑ *Gatus* \\nAn alert for *endpoint-name* has been resolved:\\n—\\n    _healthcheck passing successfully 3 time(s) in a row_\\n—   \\n*Description* \\n_description-2_  \\n\\n*Condition results*\\n✅ - `[CONNECTED] == true`\\n✅ - `[STATUS] == 200`\\n\", \"parse_mode\": \"MARKDOWN\"}", | ||||
| 			ExpectedBody: "{\"chat_id\":\"123\",\"text\":\"⛑ *Gatus* \\nAn alert for *endpoint-name* has been resolved:\\n—\\n    _healthcheck passing successfully 3 time(s) in a row_\\n—   \\n*Description* \\n_description-2_  \\n\\n*Condition results*\\n✅ - `[CONNECTED] == true`\\n✅ - `[STATUS] == 200`\\n\",\"parse_mode\":\"MARKDOWN\"}", | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, scenario := range scenarios { | ||||
| @ -147,11 +147,11 @@ func TestAlertProvider_buildRequestBody(t *testing.T) { | ||||
| 				}, | ||||
| 				scenario.Resolved, | ||||
| 			) | ||||
| 			if body != scenario.ExpectedBody { | ||||
| 				t.Errorf("expected %s, got %s", scenario.ExpectedBody, body) | ||||
| 			if string(body) != scenario.ExpectedBody { | ||||
| 				t.Errorf("expected:\n%s\ngot:\n%s", scenario.ExpectedBody, body) | ||||
| 			} | ||||
| 			out := make(map[string]interface{}) | ||||
| 			if err := json.Unmarshal([]byte(body), &out); err != nil { | ||||
| 			if err := json.Unmarshal(body, &out); err != nil { | ||||
| 				t.Error("expected body to be valid JSON, got error:", err.Error()) | ||||
| 			} | ||||
| 		}) | ||||
|  | ||||
		Reference in New Issue
	
	Block a user