diff --git a/cmd/bot/handle_message.go b/cmd/bot/handle_message.go index 22c4135..63983cc 100644 --- a/cmd/bot/handle_message.go +++ b/cmd/bot/handle_message.go @@ -40,7 +40,9 @@ func handlePre() func(context.Context, tg.Entities, *tg.UpdateNewMessage, *cmd.H case flags.RemoveTag: return flags.Remove(ctx, m, user, answer) case flags.AddTag: - return flags.Add(ctx, m, user, answer) + return flags.AddOne(ctx, m, user, answer) + case flags.AddTags: + return flags.AddMany(ctx, m, user, answer) case flags.CheckTag: return flags.Check(ctx, m, user, answer) default: diff --git a/cmd/bot/main.go b/cmd/bot/main.go index 817d219..35e7b7f 100644 --- a/cmd/bot/main.go +++ b/cmd/bot/main.go @@ -41,7 +41,9 @@ func run(ctx context.Context) error { "start": cmd.Start, "help": cmd.Help, "cancel": cmd.Cancel, + "done": cmd.Done, "tag": cmd.Tag, + "tags": cmd.Tags, "remove": cmd.Remove, "global": cmd.Global, "check": cmd.Check, diff --git a/commands/done.go b/commands/done.go new file mode 100644 index 0000000..c37f961 --- /dev/null +++ b/commands/done.go @@ -0,0 +1,11 @@ +package commands + +import ( + "context" + "github.com/gotd/td/tg" +) + +func Done(ctx context.Context, e tg.Entities, upd *tg.UpdateNewMessage, c *HelperCapture, _ string) error { + _, err := c.Sender.Answer(e, upd).Text(ctx, "Нечего завершать!") + return err +} diff --git a/commands/tag.go b/commands/tag.go index f3dfdb8..5d3e0b3 100644 --- a/commands/tag.go +++ b/commands/tag.go @@ -5,6 +5,7 @@ package commands import ( "context" "errors" + "fmt" "github.com/gotd/td/tg" db "github.com/koenigskraut/piktagbot/database" "github.com/koenigskraut/piktagbot/flags" @@ -12,19 +13,74 @@ import ( "strings" ) -func Tag(ctx context.Context, e tg.Entities, upd *tg.UpdateNewMessage, c *HelperCapture, clear string) (err error) { - m, user := c.UserCapture.(*MessageSemaphore).MessageUserFromUpdate(upd) - answer := c.Sender.Answer(e, upd) - text := strings.TrimSpace(clear) +const ( + errNoTag = iota + errNoSticker + errExists + successFlag + successRe +) + +const ( + errNoTagOne = "Вы не написали тег, который хотите прикрепить к стикеру!" + errNoTagMany = "Вы не написали тег, который хотите прикрепить к стикерам!" + + errNoStickerOne = `В прикреплённом сообщении нет стикера, действие отменено%.s` + errNoStickerMany = `В прикреплённом сообщении нет стикера! Отправьте мне стикеры для тега "%s"` + + errGeneral = "Что-то пошло не так, попробуйте ещё раз!" - // if there is no tag in a message return immediately - if text == "" { - _, err := answer.Text(ctx, "Вы не написали тег, который хотите прикрепить к стикеру!") - return err + errExistsOne = "У этого стикера уже есть этот тег, действие отменено" + errExistsMany = "У этого стикера уже есть этот тег, отправьте другие!" + + successFlagOne = "Теперь отправьте мне стикер, к которому нужно прикрепить тег" + successFlagMany = "Теперь отправьте мне стикеры, к которым нужно прикрепить теги" + + successReOne = "Тег добавлен!" + successReMany = "Тег добавлен! Пришлите мне следующий стикер или завершите действие командой /done" +) + +type sm map[bool]string + +func handleTag(isOne bool) CommandHandler { + chooseStr := map[uint8]map[bool]string{ + errNoTag: sm{true: errNoTagOne, false: errNoTagMany}, + errNoSticker: sm{true: errNoStickerOne, false: errNoStickerMany}, + errExists: sm{true: errExistsOne, false: errExistsMany}, + successFlag: sm{true: successFlagOne, false: successFlagMany}, + successRe: sm{true: successReOne, false: successReMany}, } + flag := map[bool]int8{true: flags.AddTag, false: flags.AddTags} + return func(ctx context.Context, e tg.Entities, upd *tg.UpdateNewMessage, c *HelperCapture, clear string) (err error) { + m, user := c.UserCapture.(*MessageSemaphore).MessageUserFromUpdate(upd) + answer := c.Sender.Answer(e, upd) + text := strings.TrimSpace(clear) + + // if there is no tag in a message return immediately + if text == "" { + _, err := answer.Text(ctx, chooseStr[errNoTag][isOne]) + return err + } + + // case 1: message is not a reply + // remember the tag and set a waiting-for-a-sticker flag + if m.ReplyTo == nil { + if err := user.SetFlag(flag[isOne], text); err != nil { + _, msgErr := answer.Text(ctx, errGeneral) + return errors.Join(err, msgErr) + } + _, err = answer.Text(ctx, chooseStr[successFlag][isOne]) + return err + } - // case 1: message is a reply, handle re message - if m.ReplyTo != nil { + // case 2: message is a reply, handle re message + // many stickers wanted? set flag immediately + if !isOne { + if err := user.SetFlag(flag[isOne], text); err != nil { + _, msgErr := answer.Text(ctx, errGeneral) + return errors.Join(err, msgErr) + } + } // get re message mRep, _ := c.Client.MessagesGetMessages( ctx, @@ -32,31 +88,37 @@ func Tag(ctx context.Context, e tg.Entities, upd *tg.UpdateNewMessage, c *Helper ) // check if there is a sticker in it media := mRep.(*tg.MessagesMessages).Messages[0].(*tg.Message).Media - if sticker, ok := util.StickerFromMedia(media); ok { - // if true, check if it has such a tag, add one if not - sTag := db.StickerTag{ - User: user.UserID, - StickerID: sticker.ID, - Tag: text, - } - resp, _ := sTag.CheckAndAdd() - _, err := answer.Text(ctx, resp) + sticker, ok := util.StickerFromMedia(media) + // if false return + if !ok { + fmt.Println() + _, err := answer.Textf( + ctx, + chooseStr[errNoSticker][isOne], + text, + ) return err } - _, err := answer.Textf( - ctx, - "В прикреплённом сообщении нет стикера! Отправьте мне стикер для тега \"%s\"", - text, - ) - return err - } - - // case 2: message is not a reply - // remember the tag and set a waiting-for-a-sticker flag - if err := user.SetFlag(flags.AddTag, text); err != nil { - _, msgErr := answer.Text(ctx, "Что-то пошло не так, попробуйте ещё раз!") - return errors.Join(err, msgErr) + // if true, check if sticker has such a tag, add one if not + sTag := db.StickerTag{ + User: user.UserID, + StickerID: sticker.ID, + Tag: text, + } + err = sTag.CheckAndAdd() + var errTwo error + switch err { + case nil: + _, errTwo = answer.Text(ctx, chooseStr[successRe][isOne]) + case db.StickerTagExists: + err = nil + _, errTwo = answer.Text(ctx, chooseStr[errExists][isOne]) + default: + _, errTwo = answer.Text(ctx, errGeneral) + } + return errors.Join(err, errTwo) } - _, err = answer.Text(ctx, "Теперь отправьте мне стикер, к которому нужно прикрепить тег") - return err } + +var Tag = handleTag(true) +var Tags = handleTag(false) diff --git a/flags/add.go b/flags/add.go index ac496d2..92fb5de 100644 --- a/flags/add.go +++ b/flags/add.go @@ -10,35 +10,89 @@ import ( "strings" ) -func Add(ctx context.Context, m *tg.Message, u *database.User, answer *message.RequestBuilder) error { - if strings.HasPrefix(m.Message, "/cancel") { - u.Flag, u.FlagData = NoFlag, "" - if err := u.Save(); err != nil { +const ( + finish = iota + errNoSticker + errExists +) + +const ( + finishCancel = "Действие отменено" + finishDone = "Действие завершено" + + errNoStickerOne = "В сообщении нет стикера! Отправьте мне стикер для добавления тегов или отмените действие командой /cancel" + errNoStickerMany = "В сообщении нет стикера! Отправьте мне стикеры для добавления тегов или завершите действие командой /done" + + errGeneral = "Что-то пошло не так, попробуйте ещё раз" + + errExistsOne = "У этого стикера уже есть этот тег, действие отменено" + errExistsMany = "У этого стикера уже есть этот тег, отправьте другие!" + + successOne = "Тег добавлен!" + successMany = "Тег добавлен! Пришлите мне следующий стикер или завершите действие командой /done" +) + +type sm map[bool]string + +func handleAdd(isOne bool) FlagHandler { + chooseStr := map[uint8]map[bool]string{ + finish: sm{true: finishDone, false: finishCancel}, + errNoSticker: sm{true: errNoStickerOne, false: errNoStickerMany}, + errExists: sm{true: errExistsOne, false: errExistsMany}, + } + //flag := map[bool]int8{true: flags.AddTag, false: flags.AddTags} + return func(ctx context.Context, m *tg.Message, u *database.User, answer *message.RequestBuilder) error { + done := strings.HasPrefix(m.Message, "/done") + cancel := strings.HasPrefix(m.Message, "/cancel") + if done || cancel { + u.Flag, u.FlagData = NoFlag, "" + if err := u.Save(); err != nil { + return err + } + _, err := answer.Text(ctx, chooseStr[finish][done]) + return err + } + sticker, ok := util.StickerFromMedia(m.Media) + if !ok { + _, err := answer.Text(ctx, chooseStr[errNoSticker][isOne]) + return err + } + // if there is a sticker, check if there is such a tag attached to it, + // if not — add one + sTag := database.StickerTag{ + User: u.UserID, + StickerID: sticker.ID, + Tag: u.FlagData, + } + errDB := sTag.CheckAndAdd() + if errDB != nil { + if !errors.Is(errDB, database.StickerTagExists) { + _, errMsg := answer.Text(ctx, errGeneral) + return errors.Join(errDB, errMsg) + } + if isOne { + u.Flag, u.FlagData = NoFlag, "" + if err := u.Save(); err != nil { + _, errMsg := answer.Text(ctx, errGeneral) + return errors.Join(err, errMsg) + } + } + _, errMsg := answer.Text(ctx, chooseStr[errExists][isOne]) + return errMsg + } + if !isOne { + _, err := answer.Text(ctx, successMany) return err } - _, err := answer.Text(ctx, "Действие отменено") - return err - } - sticker, ok := util.StickerFromMedia(m.Media) - if !ok { - _, err := answer.Text(ctx, "В сообщении нет стикера! Отправьте мне стикер для удаления тегов или "+ - "отмените действие командой /cancel") - return err - } - // if there is a sticker, check if there is such a tag attached to it, - // if not — add one - sTag := database.StickerTag{ - User: u.UserID, - StickerID: sticker.ID, - Tag: u.FlagData, - } - text, errDB := sTag.CheckAndAdd() - if errDB == nil { u.Flag, u.FlagData = NoFlag, "" if err := u.Save(); err != nil { - return err + _, errMsg := answer.Text(ctx, errGeneral) + return errors.Join(err, errMsg) } + _, err := answer.Text(ctx, successOne) + return err } - _, errMsg := answer.Text(ctx, text) - return errors.Join(errDB, errMsg) } + +var AddOne = handleAdd(true) +var AddMany = handleAdd(false) diff --git a/flags/base.go b/flags/base.go index 9144c8a..2a2d1df 100644 --- a/flags/base.go +++ b/flags/base.go @@ -1,8 +1,18 @@ package flags +import ( + "context" + "github.com/gotd/td/telegram/message" + "github.com/gotd/td/tg" + "github.com/koenigskraut/piktagbot/database" +) + const ( NoFlag = iota RemoveTag AddTag + AddTags CheckTag ) + +type FlagHandler func(ctx context.Context, m *tg.Message, u *database.User, answer *message.RequestBuilder) error