Completed
Push — master ( 51670f...2fc919 )
by Roannel Fernández
03:06
created

sendMessage(String,Long)   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 2
eloc 2
rs 10
cc 1
1
package com.github.netkorp.telegram.framework.bots;
2
3
import com.github.netkorp.telegram.framework.commands.interfaces.Command;
4
import com.github.netkorp.telegram.framework.commands.interfaces.MultistageCommand;
5
import com.github.netkorp.telegram.framework.exceptions.CommandNotActive;
6
import com.github.netkorp.telegram.framework.exceptions.CommandNotFound;
7
import com.github.netkorp.telegram.framework.managers.CommandManager;
8
import com.github.netkorp.telegram.framework.managers.SecurityManager;
9
import org.slf4j.Logger;
10
import org.slf4j.LoggerFactory;
11
import org.springframework.beans.factory.annotation.Autowired;
12
import org.springframework.beans.factory.annotation.Value;
13
import org.springframework.context.annotation.Lazy;
14
import org.springframework.stereotype.Component;
15
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
16
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
17
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
18
import org.telegram.telegrambots.meta.api.objects.Update;
19
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
20
21
import java.lang.invoke.MethodHandles;
22
import java.util.Optional;
23
24
/**
25
 * Provides the component for sharing information with Telegram using
26
 * <a href="https://core.telegram.org/bots/api#getupdates">long-polling</a> method.
27
 * It has the responsibility to execute the proper command when an incoming message is received.
28
 */
29
@Component
30
public class PollingTelegramBot extends TelegramLongPollingBot {
31
32
    private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
33
34
    /**
35
     * The bot's username.
36
     */
37
    private String botUsername;
38
39
    /**
40
     * The bot's token.
41
     */
42
    private String botToken;
43
44
    /**
45
     * The component to know which user is authorized.
46
     */
47
    private final SecurityManager securityManager;
48
49
    /**
50
     * The component for managing all of the commands available in the bot.
51
     */
52
    private final CommandManager commandManager;
53
54
    /**
55
     * Constructs a new {@link PollingTelegramBot} instance with both username and token of the bot
56
     * and the {@link SecurityManager} component instance.
57
     *
58
     * @param botUsername     the username of the bot.
59
     * @param botToken        the token of the bot.
60
     * @param securityManager the {@link SecurityManager} component instance.
61
     */
62
    @Autowired
63
    public PollingTelegramBot(@Value("${telegram.bots.username}") String botUsername,
64
                              @Value("${telegram.bots.token}") String botToken,
65
                              SecurityManager securityManager,
66
                              @Lazy CommandManager commandManager) {
67
        this.botUsername = botUsername;
68
        this.botToken = botToken;
69
        this.securityManager = securityManager;
70
        this.commandManager = commandManager;
71
    }
72
73
    /**
74
     * This method is called when receiving updates via GetUpdates method.
75
     *
76
     * @param update Update received.
77
     */
78
    @Override
79
    public void onUpdateReceived(Update update) {
80
        // We check if the update has a message and the message has text
81
        if (update.hasMessage()) {
82
            Long idChat = update.getMessage().getChatId();
83
84
            try {
85
                // Checking if this is a commands
86
                if (update.getMessage().hasText()) {
87
                    String command = update.getMessage().getText().toLowerCase();
88
89
                    // Checking if it's a free command
90
                    try {
91
                        commandManager.getFreeCommand(command).execute(update);
92
                        return;
93
                    } catch (CommandNotFound commandNotFound) {
94
                        // Do nothing
95
                    }
96
                }
97
98
                // Checking if the chat is authorized
99
                if (securityManager.isAuthorized(idChat)) {
100
                    processMessage(update);
101
                }
102
            } catch (CommandNotFound commandNotFound) {
103
                sendMessage(commandNotFound.getMessage(), idChat);
104
                commandManager.getHelpCommand().ifPresent(command -> command.execute(update));
105
            }
106
        }
107
    }
108
109
    /**
110
     * Returns the bot's username.
111
     *
112
     * @return the bot's username.
113
     */
114
    @Override
115
    public String getBotUsername() {
116
        return botUsername;
117
    }
118
119
    /**
120
     * Returns the bot's token.
121
     *
122
     * @return the bot's token.
123
     */
124
    @Override
125
    public String getBotToken() {
126
        return botToken;
127
    }
128
129
    /**
130
     * Processes a given message.
131
     *
132
     * @param update the message sent by the user.
133
     */
134
    private void processMessage(Update update) throws CommandNotFound {
135
        final Long idChat = update.getMessage().getChatId();
136
137
        // Perhaps is a commands
138
        if (update.getMessage().hasText()) {
139
            String commandText = update.getMessage().getText().toLowerCase();
140
141
            if (reservedCommands(commandText, update)) {
142
                return;
143
            }
144
145
            // Trying to get commands
146
            try {
147
                Command command = commandManager.getCommand(commandText);
148
149
                // If there is no active commands defined, we understand this is an attempt to define/execute one
150
                if (!commandManager.hasActiveCommand(idChat)) {
151
152
                    if (command instanceof MultistageCommand) {
153
                        if (((MultistageCommand) command).init(update)) {
154
                            commandManager.setActiveCommand(idChat, ((MultistageCommand) command));
155
                        }
156
                    } else {
157
                        command.execute(update);
158
                    }
159
160
                    return;
161
                }
162
            } catch (CommandNotFound commandNotFound) {
163
                // Perhaps we're talking about data here. If there is an active commands, we leave it to it.
164
                if (!commandManager.hasActiveCommand(idChat)) {
165
                    throw commandNotFound;
166
                }
167
            }
168
        }
169
170
        // If there is a commands active, we handle the messages as data
171
        try {
172
            commandManager.getActiveCommand(idChat).execute(update);
173
        } catch (CommandNotActive commandNotActive) {
174
            sendMessage(commandNotActive.getMessage(), idChat);
175
        }
176
    }
177
178
    /**
179
     * Checks if the entered text matches with some reserved command.
180
     * If this is the case it will execute the corresponding command.
181
     *
182
     * @param commandText the text entered by the user.
183
     * @param update      the message sent by the user.
184
     * @return {@code true} if some reserved command was executed; {@code false} otherwise.
185
     */
186
    private boolean reservedCommands(String commandText, Update update) {
187
        Optional<Command> closeCommand = commandManager.getCloseCommand()
188
                .filter(command -> CommandManager.getCommand(command).equals(commandText));
189
190
        if (closeCommand.isPresent()) {
191
            closeCommand.get().execute(update);
192
            return true;
193
        }
194
195
        Optional<Command> doneCommand = commandManager.getDoneCommand()
196
                .filter(command -> CommandManager.getCommand(command).equals(commandText));
197
198
        if (doneCommand.isPresent()) {
199
            doneCommand.get().execute(update);
200
            return true;
201
        }
202
203
        return false;
204
    }
205
206
    /**
207
     * Sends a text message to Telegram.
208
     * This is a shortcut for {@link #sendMessage(String, Long, boolean)} with HTML format disabled.
209
     *
210
     * @param content the message content.
211
     * @param idChat  the chat identification to which the message should be sent.
212
     */
213
    public void sendMessage(String content, Long idChat) {
214
        sendMessage(content, idChat, false);
215
    }
216
217
    /**
218
     * Sends a text message to Telegram. This is a shortcut for {@link #execute(BotApiMethod)}.
219
     *
220
     * @param content the message content.
221
     * @param idChat  the chat identification to which the message should be sent.
222
     * @param html    {@code true} if HTML format is enabled or {@code false} otherwise.
223
     */
224
    public void sendMessage(String content, Long idChat, boolean html) {
225
        SendMessage message = new SendMessage() // Create a SendMessage object with mandatory fields
226
                .setChatId(idChat).setText(content).enableHtml(html);
227
228
        try {
229
            this.execute(message); // Call method to send the message
230
        } catch (TelegramApiException e) {
231
            LOG.error(e.getMessage(), e);
232
        }
233
    }
234
}
235