|
| 1 | +package botapi |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + |
| 6 | + "github.com/gotd/td/telegram/message" |
| 7 | + "github.com/gotd/td/telegram/message/styling" |
| 8 | + "github.com/gotd/td/tg" |
| 9 | +) |
| 10 | + |
| 11 | +// InputChecklistTask describes a task to add to a checklist on creation or edit. |
| 12 | +type InputChecklistTask struct { |
| 13 | + // ID is the unique identifier of the task, positive and unique among the |
| 14 | + // tasks of the checklist. |
| 15 | + ID int |
| 16 | + // Text is the task text, 1-100 characters after entities parsing. |
| 17 | + Text string |
| 18 | + // ParseMode is the formatting mode for Text. |
| 19 | + ParseMode ParseMode |
| 20 | + // TextEntities are explicit entities; they take precedence over ParseMode. |
| 21 | + TextEntities []MessageEntity |
| 22 | +} |
| 23 | + |
| 24 | +// InputChecklist describes a checklist to create or replace. |
| 25 | +type InputChecklist struct { |
| 26 | + // Title is the checklist title, 1-255 characters after entities parsing. |
| 27 | + Title string |
| 28 | + // ParseMode is the formatting mode for Title. |
| 29 | + ParseMode ParseMode |
| 30 | + // TitleEntities are explicit title entities; they take precedence over |
| 31 | + // ParseMode. |
| 32 | + TitleEntities []MessageEntity |
| 33 | + // Tasks are the checklist tasks, 1-30 items. |
| 34 | + Tasks []InputChecklistTask |
| 35 | + // OthersCanAddTasks allows other users to add tasks to the checklist. |
| 36 | + OthersCanAddTasks bool |
| 37 | + // OthersCanMarkTasksAsDone allows other users to mark tasks as done or undone. |
| 38 | + OthersCanMarkTasksAsDone bool |
| 39 | +} |
| 40 | + |
| 41 | +// textWithEntities resolves text plus a parse mode or explicit entities into the |
| 42 | +// MTProto TextWithEntities shape. Explicit entities take precedence. |
| 43 | +func (b *Bot) textWithEntities(ctx context.Context, text string, mode ParseMode, explicit []MessageEntity) (tg.TextWithEntities, error) { |
| 44 | + if len(explicit) > 0 { |
| 45 | + return tg.TextWithEntities{Text: text, Entities: entitiesToTg(explicit)}, nil |
| 46 | + } |
| 47 | + |
| 48 | + msg, entities, err := b.styledMessage(ctx, text, mode) |
| 49 | + if err != nil { |
| 50 | + return tg.TextWithEntities{}, err |
| 51 | + } |
| 52 | + |
| 53 | + return tg.TextWithEntities{Text: msg, Entities: entities}, nil |
| 54 | +} |
| 55 | + |
| 56 | +// checklistMedia converts an InputChecklist into MTProto todo-list media. |
| 57 | +func (b *Bot) checklistMedia(ctx context.Context, c InputChecklist) (*tg.InputMediaTodo, error) { |
| 58 | + if len(c.Tasks) == 0 { |
| 59 | + return nil, &Error{Code: 400, Description: "Bad Request: checklist must include at least one task"} |
| 60 | + } |
| 61 | + |
| 62 | + title, err := b.textWithEntities(ctx, c.Title, c.ParseMode, c.TitleEntities) |
| 63 | + if err != nil { |
| 64 | + return nil, err |
| 65 | + } |
| 66 | + |
| 67 | + list := make([]tg.TodoItem, len(c.Tasks)) |
| 68 | + |
| 69 | + for i, task := range c.Tasks { |
| 70 | + taskTitle, err := b.textWithEntities(ctx, task.Text, task.ParseMode, task.TextEntities) |
| 71 | + if err != nil { |
| 72 | + return nil, err |
| 73 | + } |
| 74 | + |
| 75 | + list[i] = tg.TodoItem{ID: task.ID, Title: taskTitle} |
| 76 | + } |
| 77 | + |
| 78 | + return &tg.InputMediaTodo{Todo: tg.TodoList{ |
| 79 | + OthersCanAppend: c.OthersCanAddTasks, |
| 80 | + OthersCanComplete: c.OthersCanMarkTasksAsDone, |
| 81 | + Title: title, |
| 82 | + List: list, |
| 83 | + }}, nil |
| 84 | +} |
| 85 | + |
| 86 | +// SendChecklist sends a checklist on behalf of a connected business account. |
| 87 | +func (b *Bot) SendChecklist( |
| 88 | + ctx context.Context, businessConnectionID string, chat ChatID, checklist InputChecklist, opts ...SendOption, |
| 89 | +) (*Message, error) { |
| 90 | + opts = append([]SendOption{WithBusinessConnection(businessConnectionID)}, opts...) |
| 91 | + |
| 92 | + return b.sendResolvedMedia(ctx, chat, "", func(ctx context.Context, _ []styling.StyledTextOption) (message.MediaOption, error) { |
| 93 | + todo, err := b.checklistMedia(ctx, checklist) |
| 94 | + if err != nil { |
| 95 | + return nil, err |
| 96 | + } |
| 97 | + |
| 98 | + return message.Media(todo), nil |
| 99 | + }, opts...) |
| 100 | +} |
| 101 | + |
| 102 | +// EditMessageChecklist replaces the checklist in a message sent on behalf of a |
| 103 | +// connected business account. |
| 104 | +func (b *Bot) EditMessageChecklist( |
| 105 | + ctx context.Context, businessConnectionID string, chat ChatID, messageID int, checklist InputChecklist, opts ...SendOption, |
| 106 | +) (*Message, error) { |
| 107 | + var cfg sendConfig |
| 108 | + |
| 109 | + for _, o := range opts { |
| 110 | + o(&cfg) |
| 111 | + } |
| 112 | + |
| 113 | + peer, err := b.resolveInputPeer(ctx, chat) |
| 114 | + if err != nil { |
| 115 | + return nil, err |
| 116 | + } |
| 117 | + |
| 118 | + todo, err := b.checklistMedia(ctx, checklist) |
| 119 | + if err != nil { |
| 120 | + return nil, err |
| 121 | + } |
| 122 | + |
| 123 | + req := &tg.MessagesEditMessageRequest{Peer: peer, ID: messageID} |
| 124 | + req.SetMedia(todo) |
| 125 | + |
| 126 | + if cfg.markup != nil { |
| 127 | + mkp, err := replyMarkupToTg(cfg.markup) |
| 128 | + if err != nil { |
| 129 | + return nil, err |
| 130 | + } |
| 131 | + |
| 132 | + req.SetReplyMarkup(mkp) |
| 133 | + } |
| 134 | + |
| 135 | + resp, err := b.businessRaw(businessConnectionID).MessagesEditMessage(ctx, req) |
| 136 | + |
| 137 | + return b.sentMessage(ctx, peer, resp, err) |
| 138 | +} |
0 commit comments