telegram.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package server
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "path"
  7. "strconv"
  8. "github.com/pkg/errors"
  9. "github.com/usememos/memos/api"
  10. apiv1 "github.com/usememos/memos/api/v1"
  11. "github.com/usememos/memos/common"
  12. "github.com/usememos/memos/plugin/telegram"
  13. "github.com/usememos/memos/store"
  14. )
  15. type telegramHandler struct {
  16. store *store.Store
  17. }
  18. func newTelegramHandler(store *store.Store) *telegramHandler {
  19. return &telegramHandler{store: store}
  20. }
  21. func (t *telegramHandler) BotToken(ctx context.Context) string {
  22. return t.store.GetSystemSettingValueOrDefault(&ctx, api.SystemSettingTelegramBotTokenName, "")
  23. }
  24. const (
  25. workingMessage = "Working on send your memo..."
  26. successMessage = "Success"
  27. )
  28. func (t *telegramHandler) MessageHandle(ctx context.Context, bot *telegram.Bot, message telegram.Message, blobs map[string][]byte) error {
  29. reply, err := bot.SendReplyMessage(ctx, message.Chat.ID, message.MessageID, workingMessage)
  30. if err != nil {
  31. return fmt.Errorf("fail to SendReplyMessage: %s", err)
  32. }
  33. var creatorID int
  34. userSettingList, err := t.store.ListUserSettings(ctx, &store.FindUserSetting{
  35. Key: apiv1.UserSettingTelegramUserIDKey.String(),
  36. })
  37. if err != nil {
  38. return errors.Wrap(err, "Failed to find userSettingList")
  39. }
  40. for _, userSetting := range userSettingList {
  41. var value string
  42. if err := json.Unmarshal([]byte(userSetting.Value), &value); err != nil {
  43. continue
  44. }
  45. if value == strconv.Itoa(message.From.ID) {
  46. creatorID = userSetting.UserID
  47. }
  48. }
  49. if creatorID == 0 {
  50. _, err := bot.EditMessage(ctx, message.Chat.ID, reply.MessageID, fmt.Sprintf("Please set your telegram userid %d in UserSetting of Memos", message.From.ID), nil)
  51. return err
  52. }
  53. // create memo
  54. memoCreate := api.CreateMemoRequest{
  55. CreatorID: creatorID,
  56. Visibility: api.Private,
  57. }
  58. if message.Text != nil {
  59. memoCreate.Content = *message.Text
  60. }
  61. if blobs != nil && message.Caption != nil {
  62. memoCreate.Content = *message.Caption
  63. }
  64. memoMessage, err := t.store.CreateMemo(ctx, convertCreateMemoRequestToMemoMessage(&memoCreate))
  65. if err != nil {
  66. _, err := bot.EditMessage(ctx, message.Chat.ID, reply.MessageID, fmt.Sprintf("failed to CreateMemo: %s", err), nil)
  67. return err
  68. }
  69. if err := createMemoCreateActivity(ctx, t.store, memoMessage); err != nil {
  70. _, err := bot.EditMessage(ctx, message.Chat.ID, reply.MessageID, fmt.Sprintf("failed to createMemoCreateActivity: %s", err), nil)
  71. return err
  72. }
  73. // create resources
  74. for filename, blob := range blobs {
  75. // TODO support more
  76. mime := "application/octet-stream"
  77. switch path.Ext(filename) {
  78. case ".jpg":
  79. mime = "image/jpeg"
  80. case ".png":
  81. mime = "image/png"
  82. }
  83. resourceCreate := api.ResourceCreate{
  84. CreatorID: creatorID,
  85. Filename: filename,
  86. Type: mime,
  87. Size: int64(len(blob)),
  88. Blob: blob,
  89. PublicID: common.GenUUID(),
  90. }
  91. resource, err := t.store.CreateResource(ctx, &resourceCreate)
  92. if err != nil {
  93. _, err := bot.EditMessage(ctx, message.Chat.ID, reply.MessageID, fmt.Sprintf("failed to CreateResource: %s", err), nil)
  94. return err
  95. }
  96. if err := createResourceCreateActivity(ctx, t.store, resource); err != nil {
  97. _, err := bot.EditMessage(ctx, message.Chat.ID, reply.MessageID, fmt.Sprintf("failed to createResourceCreateActivity: %s", err), nil)
  98. return err
  99. }
  100. _, err = t.store.UpsertMemoResource(ctx, &api.MemoResourceUpsert{
  101. MemoID: memoMessage.ID,
  102. ResourceID: resource.ID,
  103. })
  104. if err != nil {
  105. _, err := bot.EditMessage(ctx, message.Chat.ID, reply.MessageID, fmt.Sprintf("failed to UpsertMemoResource: %s", err), nil)
  106. return err
  107. }
  108. }
  109. keyboard := generateKeyboardForMemoID(memoMessage.ID)
  110. _, err = bot.EditMessage(ctx, message.Chat.ID, reply.MessageID, fmt.Sprintf("Saved as %s Memo %d", memoMessage.Visibility, memoMessage.ID), keyboard)
  111. return err
  112. }
  113. func (t *telegramHandler) CallbackQueryHandle(ctx context.Context, bot *telegram.Bot, callbackQuery telegram.CallbackQuery) error {
  114. var memoID int
  115. var visibility store.Visibility
  116. n, err := fmt.Sscanf(callbackQuery.Data, "%s %d", &visibility, &memoID)
  117. if err != nil || n != 2 {
  118. return bot.AnswerCallbackQuery(ctx, callbackQuery.ID, fmt.Sprintf("fail to parse callbackQuery.Data %s", callbackQuery.Data))
  119. }
  120. update := store.UpdateMemoMessage{
  121. ID: memoID,
  122. Visibility: &visibility,
  123. }
  124. err = t.store.UpdateMemo(ctx, &update)
  125. if err != nil {
  126. return bot.AnswerCallbackQuery(ctx, callbackQuery.ID, fmt.Sprintf("fail to call UpdateMemo %s", err))
  127. }
  128. keyboard := generateKeyboardForMemoID(memoID)
  129. _, err = bot.EditMessage(ctx, callbackQuery.Message.Chat.ID, callbackQuery.Message.MessageID, fmt.Sprintf("Saved as %s Memo %d", visibility, memoID), keyboard)
  130. if err != nil {
  131. return bot.AnswerCallbackQuery(ctx, callbackQuery.ID, fmt.Sprintf("fail to EditMessage %s", err))
  132. }
  133. return bot.AnswerCallbackQuery(ctx, callbackQuery.ID, fmt.Sprintf("Success change Memo %d to %s", memoID, visibility))
  134. }
  135. func generateKeyboardForMemoID(id int) [][]telegram.InlineKeyboardButton {
  136. allVisibility := []store.Visibility{
  137. store.Public,
  138. store.Protected,
  139. store.Private,
  140. }
  141. buttons := make([]telegram.InlineKeyboardButton, 0, len(allVisibility))
  142. for _, v := range allVisibility {
  143. button := telegram.InlineKeyboardButton{
  144. Text: v.String(),
  145. CallbackData: fmt.Sprintf("%s %d", v, id),
  146. }
  147. buttons = append(buttons, button)
  148. }
  149. return [][]telegram.InlineKeyboardButton{buttons}
  150. }