Skip to content

Commit

Permalink
feat: allow confirming silence and clearing the keyboard (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
freak12techno authored Dec 3, 2024
1 parent 0377f95 commit fb01b97
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 10 deletions.
1 change: 1 addition & 0 deletions pkg/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ func (a *App) Start() {
a.Bot.Handle("\f"+constants.GrafanaRenderChooseDashboardPrefix, a.HandleRenderChooseDashboardFromCallback)
a.Bot.Handle("\f"+constants.GrafanaRenderChoosePanelPrefix, a.HandleRenderPanelChoosePanelFromCallback)
a.Bot.Handle("\f"+constants.GrafanaRenderRenderPanelPrefix, a.HandleRenderPanelFromCallback)
a.Bot.Handle("\f"+constants.ClearKeyboardPrefix, a.ClearKeyboard)

for _, alertSourceWithSilenceManager := range a.AlertSourcesWithSilenceManager {
alertSource := alertSourceWithSilenceManager.AlertSource
Expand Down
6 changes: 5 additions & 1 deletion pkg/app/silences_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package app
import (
"fmt"
"main/pkg/alert_source"
"main/pkg/constants"
"main/pkg/silence_manager"
"main/pkg/types"
"main/pkg/types/render"
Expand Down Expand Up @@ -139,9 +140,12 @@ func (a *App) HandleNewSilenceGeneric(

menu := &tele.ReplyMarkup{ResizeKeyboard: true}
menu.Inline(menu.Row(menu.Data(
"✅Confirm",
constants.ClearKeyboardPrefix,
)), menu.Row(menu.Data(
"❌Unsilence",
silenceManager.Prefixes().Unsilence,
silence.ID,
silence.ID+" 1",
)))

return a.ReplyRender(c, "silences_create", render.RenderStruct{
Expand Down
17 changes: 10 additions & 7 deletions pkg/app/silences_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,13 +283,16 @@ func TestAppCreateSilenceOk(t *testing.T) {
"https://api.telegram.org/botxxx:yyy/sendMessage",
types.TelegramResponseHasBytesAndMarkup(assets.GetBytesOrPanic("responses/silence-create-ok.html"), types.TelegramInlineKeyboardResponse{
InlineKeyboard: [][]types.TelegramInlineKeyboard{
{
{
Unique: "grafana_unsilence_",
Text: "❌Unsilence",
CallbackData: "\fgrafana_unsilence_|4de5faa2-8c0c-4c66-bd31-25c3bf5fa231",
},
},
{{
Unique: "clear_keyboard_",
Text: "✅Confirm",
CallbackData: "\fclear_keyboard_",
}},
{{
Unique: "grafana_unsilence_",
Text: "❌Unsilence",
CallbackData: "\fgrafana_unsilence_|4de5faa2-8c0c-4c66-bd31-25c3bf5fa231 1",
}},
},
}),
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("telegram-send-message-ok.json")),
Expand Down
10 changes: 8 additions & 2 deletions pkg/app/silences_delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,14 @@ func (a *App) HandleCallbackDeleteSilence(silenceManager silence_manager.Silence

callback := c.Callback()

a.RemoveKeyboardItemByCallback(c, callback)
return a.HandleDeleteSilenceGeneric(c, silenceManager, callback.Data)
dataSplit := strings.Split(callback.Data, " ")
if len(dataSplit) == 2 {
_ = a.ClearKeyboard(c)
} else {
a.RemoveKeyboardItemByCallback(c, callback)
}

return a.HandleDeleteSilenceGeneric(c, silenceManager, dataSplit[0])
}
}

Expand Down
58 changes: 58 additions & 0 deletions pkg/app/silences_delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,3 +407,61 @@ func TestAppDeleteSilenceCallbackOk(t *testing.T) {
err := app.HandleCallbackDeleteSilence(app.AlertSourcesWithSilenceManager[0].SilenceManager)(ctx)
require.NoError(t, err)
}

//nolint:paralleltest // disabled
func TestAppDeleteSilenceCallbackOkWithDeleteKeyboard(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()

config := &configPkg.Config{
Timezone: "Etc/GMT",
Log: configPkg.LogConfig{LogLevel: "info"},
Telegram: configPkg.TelegramConfig{Token: "xxx:yyy", Admins: []int64{1, 2}},
Grafana: configPkg.GrafanaConfig{
URL: "https://example.com",
Silences: null.BoolFrom(true),
},
Alertmanager: nil,
Prometheus: nil,
}

httpmock.RegisterResponder(
"POST",
"https://api.telegram.org/botxxx:yyy/getMe",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("telegram-bot-ok.json")))

httpmock.RegisterResponder(
"GET",
"https://example.com/api/alertmanager/grafana/api/v2/silences",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("alertmanager-silences-ok.json")))

httpmock.RegisterMatcherResponder(
"POST",
"https://api.telegram.org/botxxx:yyy/sendMessage",
types.TelegramResponseHasText("Silence is not found by ID or matchers: 123"),
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("telegram-send-message-ok.json")),
)

app := NewApp(config, "1.2.3")
ctx := app.Bot.NewContext(tele.Update{
ID: 1,
Message: &tele.Message{
Sender: &tele.User{Username: "testuser"},
Text: "/grafana_unsilence 123",
Chat: &tele.Chat{ID: 2},
},
Callback: &tele.Callback{
Sender: &tele.User{Username: "testuser"},
Unique: "\f" + constants.GrafanaUnsilencePrefix,
Data: "123 1",
Message: &tele.Message{
Sender: &tele.User{Username: "testuser"},
Text: "/grafana_unsilence 123 1",
Chat: &tele.Chat{ID: 2},
},
},
})

err := app.HandleCallbackDeleteSilence(app.AlertSourcesWithSilenceManager[0].SilenceManager)(ctx)
require.NoError(t, err)
}
24 changes: 24 additions & 0 deletions pkg/app/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,30 @@ func (a *App) RemoveKeyboardItemByCallback(c tele.Context, callback *tele.Callba
}
}

func (a *App) ClearKeyboard(c tele.Context) error {
a.Logger.Info().
Str("sender", c.Sender().Username).
Msg("Got new clear keyboard query")

callback := c.Callback()
if callback.Message == nil || callback.Message.ReplyMarkup == nil {
return nil
}

if _, err := a.Bot.EditReplyMarkup(
callback.Message,
nil,
); err != nil {
a.Logger.Error().
Str("sender", c.Sender().Username).
Err(err).
Msg("Error clearing keyboard when editing a callback")
return err
}

return nil
}

func (a *App) GenerateSilenceForAlert(
c tele.Context,
groups types.GrafanaAlertGroups,
Expand Down
126 changes: 126 additions & 0 deletions pkg/app/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,129 @@ func TestAppRemoveKeyboardItemFailedToDelete(t *testing.T) {

app.RemoveKeyboardItemByCallback(ctx, ctx.Callback())
}

//nolint:paralleltest // disabled
func TestAppClearKeyboardFailedToDelete(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()

config := &configPkg.Config{
Timezone: "Etc/GMT",
Log: configPkg.LogConfig{LogLevel: "info"},
Telegram: configPkg.TelegramConfig{Token: "xxx:yyy", Admins: []int64{1, 2}},
Grafana: configPkg.GrafanaConfig{URL: "https://example.com", User: "admin", Password: "admin"},
Alertmanager: nil,
Prometheus: nil,
}

httpmock.RegisterResponder(
"POST",
"https://api.telegram.org/botxxx:yyy/getMe",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("telegram-bot-ok.json")))

httpmock.RegisterResponder(
"POST",
"https://api.telegram.org/botxxx:yyy/editMessageReplyMarkup",
httpmock.NewErrorResponder(errors.New("custom error")),
)

app := NewApp(config, "1.2.3")
ctx := app.Bot.NewContext(tele.Update{
ID: 1,
Message: &tele.Message{
Sender: &tele.User{Username: "testuser"},
Text: "/grafana_silence 4",
Chat: &tele.Chat{ID: 2},
},
Callback: &tele.Callback{
Sender: &tele.User{Username: "testuser"},
Unique: "\f" + constants.GrafanaSilencePrefix,
Data: "48h 123",
Message: &tele.Message{
Sender: &tele.User{Username: "testuser"},
Text: "/grafana_silence",
Chat: &tele.Chat{ID: 2},
ReplyMarkup: &tele.ReplyMarkup{InlineKeyboard: [][]tele.InlineButton{
{
{
Text: "text",
Unique: "\f" + constants.GrafanaSilencePrefix,
Data: constants.GrafanaSilencePrefix + "|48h 123",
},
{
Text: "text",
Unique: constants.GrafanaUnsilencePrefix,
Data: "random",
},
},
}},
},
},
})

err := app.ClearKeyboard(ctx)
require.Error(t, err)
require.ErrorContains(t, err, "custom error")
}

//nolint:paralleltest // disabled
func TestAppClearKeyboardOk(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()

config := &configPkg.Config{
Timezone: "Etc/GMT",
Log: configPkg.LogConfig{LogLevel: "info"},
Telegram: configPkg.TelegramConfig{Token: "xxx:yyy", Admins: []int64{1, 2}},
Grafana: configPkg.GrafanaConfig{URL: "https://example.com", User: "admin", Password: "admin"},
Alertmanager: nil,
Prometheus: nil,
}

httpmock.RegisterResponder(
"POST",
"https://api.telegram.org/botxxx:yyy/getMe",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("telegram-bot-ok.json")))

httpmock.RegisterResponder(
"POST",
"https://api.telegram.org/botxxx:yyy/editMessageReplyMarkup",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("telegram-send-message-ok.json")))

app := NewApp(config, "1.2.3")
ctx := app.Bot.NewContext(tele.Update{
ID: 1,
Message: &tele.Message{
Sender: &tele.User{Username: "testuser"},
Text: "/grafana_silence 4",
Chat: &tele.Chat{ID: 2},
},
Callback: &tele.Callback{
Sender: &tele.User{Username: "testuser"},
Unique: "\f" + constants.GrafanaSilencePrefix,
Data: "48h 123",
Message: &tele.Message{
Sender: &tele.User{Username: "testuser"},
Text: "/grafana_silence",
Chat: &tele.Chat{ID: 2},
ReplyMarkup: &tele.ReplyMarkup{InlineKeyboard: [][]tele.InlineButton{
{
{
Text: "text",
Unique: "\f" + constants.GrafanaSilencePrefix,
Data: constants.GrafanaSilencePrefix + "|48h 123",
},
{
Text: "text",
Unique: constants.GrafanaUnsilencePrefix,
Data: "random",
},
},
}},
},
},
})

err := app.ClearKeyboard(ctx)
require.NoError(t, err)
}
1 change: 1 addition & 0 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ const (
GrafanaRenderChooseDashboardPrefix = "grafana_render_choose_dashboard_"
GrafanaRenderChoosePanelPrefix = "grafana_render_choose_panel_"
GrafanaRenderRenderPanelPrefix = "grafana_render_render_panel"
ClearKeyboardPrefix = "clear_keyboard_"
)

0 comments on commit fb01b97

Please sign in to comment.