feat: notify by telegram while new memo create by HTTP (#2215)

* Inject telegram bot into API service

* Add support for send telegram message

* Send notification by telegram while new memo post
This commit is contained in:
Athurg Gooth 2023-09-13 21:36:43 +08:00 committed by GitHub
parent 36209eaef1
commit 626ff5e3a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 12 deletions

View File

@ -11,8 +11,10 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/usememos/memos/api/auth" "github.com/usememos/memos/api/auth"
"github.com/usememos/memos/common/log"
"github.com/usememos/memos/common/util" "github.com/usememos/memos/common/util"
"github.com/usememos/memos/store" "github.com/usememos/memos/store"
"go.uber.org/zap"
) )
// Visibility is the type of a visibility. // Visibility is the type of a visibility.
@ -351,6 +353,38 @@ func (s *APIV1Service) CreateMemo(c echo.Context) error {
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to compose memo response").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to compose memo response").SetInternal(err)
} }
// send notification by telegram bot if memo is not Private
if memoResponse.Visibility != Private {
// fetch all telegram UserID
userSettings, err := s.Store.ListUserSettings(ctx, &store.FindUserSetting{Key: UserSettingTelegramUserIDKey.String()})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to ListUserSettings").SetInternal(err)
}
for _, userSetting := range userSettings {
// parse telegram UserID setting value into a int64
var tgUserIDStr string
err := json.Unmarshal([]byte(userSetting.Value), &tgUserIDStr)
if err != nil {
log.Error("failed to parse Telegram UserID", zap.Error(err))
continue
}
tgUserID, err := strconv.ParseInt(tgUserIDStr, 10, 64)
if err != nil {
log.Error("failed to parse Telegram UserID", zap.Error(err))
continue
}
// send notification to telegram
content := memoResponse.CreatorName + " Says:\n\n" + memoResponse.Content
_, err = s.telegramBot.SendMessage(ctx, tgUserID, content)
if err != nil {
log.Error("Failed to send Telegram notification", zap.Error(err))
continue
}
}
}
return c.JSON(http.StatusOK, memoResponse) return c.JSON(http.StatusOK, memoResponse)
} }

View File

@ -2,14 +2,16 @@ package v1
import ( import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/usememos/memos/plugin/telegram"
"github.com/usememos/memos/server/profile" "github.com/usememos/memos/server/profile"
"github.com/usememos/memos/store" "github.com/usememos/memos/store"
) )
type APIV1Service struct { type APIV1Service struct {
Secret string Secret string
Profile *profile.Profile Profile *profile.Profile
Store *store.Store Store *store.Store
telegramBot *telegram.Bot
} }
// @title memos API // @title memos API
@ -31,11 +33,12 @@ type APIV1Service struct {
// @in query // @in query
// @name openId // @name openId
// @description Insert your Open ID API Key here. // @description Insert your Open ID API Key here.
func NewAPIV1Service(secret string, profile *profile.Profile, store *store.Store) *APIV1Service { func NewAPIV1Service(secret string, profile *profile.Profile, store *store.Store, telegramBot *telegram.Bot) *APIV1Service {
return &APIV1Service{ return &APIV1Service{
Secret: secret, Secret: secret,
Profile: profile, Profile: profile,
Store: store, Store: store,
telegramBot: telegramBot,
} }
} }

View File

@ -9,9 +9,12 @@ import (
// SendReplyMessage make a sendMessage api request. // SendReplyMessage make a sendMessage api request.
func (b *Bot) SendReplyMessage(ctx context.Context, chatID, replyID int64, text string) (*Message, error) { func (b *Bot) SendReplyMessage(ctx context.Context, chatID, replyID int64, text string) (*Message, error) {
formData := url.Values{ formData := url.Values{
"reply_to_message_id": {strconv.FormatInt(replyID, 10)}, "chat_id": {strconv.FormatInt(chatID, 10)},
"chat_id": {strconv.FormatInt(chatID, 10)}, "text": {text},
"text": {text}, }
if replyID > 0 {
formData.Set("reply_to_message_id", strconv.FormatInt(replyID, 10))
} }
var result Message var result Message
@ -22,3 +25,8 @@ func (b *Bot) SendReplyMessage(ctx context.Context, chatID, replyID int64, text
return &result, nil return &result, nil
} }
// SendMessage make a sendMessage api request.
func (b *Bot) SendMessage(ctx context.Context, chatID int64, text string) (*Message, error) {
return b.SendReplyMessage(ctx, chatID, 0, text)
}

View File

@ -46,6 +46,7 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
e.HideBanner = true e.HideBanner = true
e.HidePort = true e.HidePort = true
telegramBot := telegram.NewBotWithHandler(newTelegramHandler(store))
s := &Server{ s := &Server{
e: e, e: e,
Store: store, Store: store,
@ -53,7 +54,7 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
// Asynchronous runners. // Asynchronous runners.
backupRunner: service.NewBackupRunner(store), backupRunner: service.NewBackupRunner(store),
telegramBot: telegram.NewBotWithHandler(newTelegramHandler(store)), telegramBot: telegramBot,
} }
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{ e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
@ -103,7 +104,7 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
s.Secret = secret s.Secret = secret
rootGroup := e.Group("") rootGroup := e.Group("")
apiV1Service := apiv1.NewAPIV1Service(s.Secret, profile, store) apiV1Service := apiv1.NewAPIV1Service(s.Secret, profile, store, telegramBot)
apiV1Service.Register(rootGroup) apiV1Service.Register(rootGroup)
s.apiV2Service = apiv2.NewAPIV2Service(s.Secret, profile, store, s.Profile.Port+1) s.apiV2Service = apiv2.NewAPIV2Service(s.Secret, profile, store, s.Profile.Port+1)