Completed
Push — master ( 1c54e2...48ad84 )
by Armando
02:22
created

Botan   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 228
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 30
c 2
b 0
f 0
lcom 1
cbo 8
dl 0
loc 228
ccs 0
cts 125
cp 0
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A initializeBotan() 0 21 3
A lock() 0 6 2
D track() 0 91 18
C shortenUrl() 0 39 7
1
<?php
2
/**
3
 * This file is part of the TelegramBot package.
4
 *
5
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Longman\TelegramBot;
12
13
use GuzzleHttp\Client;
14
use GuzzleHttp\Exception\RequestException;
15
use Longman\TelegramBot\Entities\Update;
16
use Longman\TelegramBot\Exception\TelegramException;
17
18
/**
19
 * Class Botan
20
 *
21
 * Integration with http://botan.io statistics service for Telegram bots
22
 */
23
class Botan
24
{
25
    /**
26
     * Botan.io API URL
27
     *
28
     * @var string
29
     */
30
    protected static $api_base_uri = 'https://api.botan.io';
31
32
    /**
33
     * Yandex AppMetrica application key
34
     *
35
     * @var string
36
     */
37
    protected static $token = '';
38
39
    /**
40
     * Guzzle Client object
41
     *
42
     * @var \GuzzleHttp\Client
43
     */
44
    private static $client;
45
46
    /**
47
     * The actual command that is going to be reported
48
     *
49
     *  Set as public to let the developers either:
50
     *  - block tracking from inside commands by setting the value to non-existent command
51
     *  - override which command is tracked when commands call other commands with executeCommand()
52
     *
53
     * @var string
54
     */
55
    public static $command = '';
56
57
    /**
58
     * Initialize Botan
59
     *
60
     * @param  string $token
61
     * @param  array  $options
62
     *
63
     * @throws \Longman\TelegramBot\Exception\TelegramException
64
     */
65
    public static function initializeBotan($token, array $options = [])
66
    {
67
        if (empty($token)) {
68
            throw new TelegramException('Botan token is empty!');
69
        }
70
71
        $options_default = [
72
            'timeout' => 3,
73
        ];
74
75
        $options = array_merge($options_default, $options);
76
77
        if (!is_numeric($options['timeout'])) {
78
            throw new TelegramException('Timeout must be a number!');
79
        }
80
81
        self::$token = $token;
82
        self::$client = new Client(['base_uri' => self::$api_base_uri, 'timeout' => $options['timeout']]);
83
84
        BotanDB::initializeBotanDb();
85
    }
86
87
    /**
88
     * Lock function to make sure only the first command is reported (the one user requested)
89
     *
90
     *  This is in case commands are calling other commands with executeCommand()
91
     *
92
     * @param string $command
93
     */
94
    public static function lock($command = '')
95
    {
96
        if (empty(self::$command)) {
97
            self::$command = strtolower($command);
98
        }
99
    }
100
101
    /**
102
     * Track function
103
     *
104
     * @param \Longman\TelegramBot\Entities\Update $update
105
     * @param string                               $command
106
     *
107
     * @return bool|string
108
     * @throws \Longman\TelegramBot\Exception\TelegramException
109
     */
110
    public static function track(Update $update, $command = '')
111
    {
112
        $command = strtolower($command);
113
114
        if (empty(self::$token) || $command !== self::$command) {
115
            return false;
116
        }
117
118
        if ($update === null) {
119
            throw new TelegramException('Update object is empty!');
120
        }
121
122
        // Release the lock in case this is getUpdates instance in foreach loop
123
        self::$command = '';
124
125
        $data = [];
126
        $update_data = (array) $update; // For now, this is the only way
127
        $update_type = $update->getUpdateType();
128
129
        $update_object_names = [
130
            'message'              => 'Message',
131
            'edited_message'       => 'Edited Message',
132
            'channel_post'         => 'Channel Post',
133
            'edited_channel_post'  => 'Edited Channel Post',
134
            'inline_query'         => 'Inline Query',
135
            'chosen_inline_result' => 'Chosen Inline Result',
136
            'callback_query'       => 'Callback Query',
137
        ];
138
139
        if (array_key_exists($update_type, $update_object_names)) {
140
            $data = $update_data[$update_type];
141
            $event_name = $update_object_names[$update_type];
142
143
            if ($update_type === 'message' && $entities = $update->getMessage()->getEntities()) {
144
                foreach ($entities as $entity) {
145
                    if ($entity->getType() === 'bot_command' && $entity->getOffset() === 0) {
146
                        if ($command === 'generic') {
147
                            $command = 'Generic';
148
                        } elseif ($command === 'genericmessage') {  // This should not happen as it equals normal message but leaving it as a fail-safe
149
                            $command = 'Generic Message';
150
                        } else {
151
                            $command = '/' . $command;
152
                        }
153
154
                        $event_name = 'Command (' . $command . ')';
155
                        break;
156
                    }
157
                }
158
            }
159
        }
160
161
        if (empty($event_name)) {
162
            TelegramLog::error('Botan.io stats report failed, no suitable update object found!');
163
164
            return false;
165
        }
166
167
        // In case there is no from field assign id = 0
168
        $uid = isset($data['from']['id']) ? $data['from']['id'] : 0;
169
170
        try {
171
            $response = self::$client->post(
172
                sprintf(
173
                    '/track?token=%1$s&uid=%2$s&name=%3$s',
174
                    self::$token,
175
                    $uid,
176
                    urlencode($event_name)
177
                ),
178
                [
179
                    'headers' => [
180
                        'Content-Type' => 'application/json',
181
                    ],
182
                    'json'    => $data,
183
                ]
184
            );
185
186
            $result = (string) $response->getBody();
187
        } catch (RequestException $e) {
188
            $result = $e->getMessage();
189
        }
190
191
        $responseData = json_decode($result, true);
192
193
        if (!$responseData || $responseData['status'] !== 'accepted') {
194
            TelegramLog::debug('Botan.io stats report failed: %s', $result ?: 'empty response');
195
196
            return false;
197
        }
198
199
        return $responseData;
200
    }
201
202
    /**
203
     * Url Shortener function
204
     *
205
     * @param string  $url
206
     * @param integer $user_id
207
     *
208
     * @return string
209
     * @throws \Longman\TelegramBot\Exception\TelegramException
210
     */
211
    public static function shortenUrl($url, $user_id)
212
    {
213
        if (empty(self::$token)) {
214
            return $url;
215
        }
216
217
        if (empty($user_id)) {
218
            throw new TelegramException('User id is empty!');
219
        }
220
221
        if ($cached = BotanDB::selectShortUrl($url, $user_id)) {
222
            return $cached;
223
        }
224
225
        try {
226
            $response = self::$client->post(
227
                sprintf(
228
                    '/s?token=%1$s&user_ids=%2$s&url=%3$s',
229
                    self::$token,
230
                    $user_id,
231
                    urlencode($url)
232
                )
233
            );
234
235
            $result = (string) $response->getBody();
236
        } catch (RequestException $e) {
237
            $result = $e->getMessage();
238
        }
239
240
        if (filter_var($result, FILTER_VALIDATE_URL) === false) {
241
            TelegramLog::debug('Botan.io URL shortening failed for "%s": %s', $url, $result ?: 'empty response');
242
243
            return $url;
244
        }
245
246
        BotanDB::insertShortUrl($url, $user_id, $result);
247
248
        return $result;
249
    }
250
}
251