Skip to content

Commit 7c5ce5b

Browse files
committed
Add 'cleanup' command
1 parent 0d59d04 commit 7c5ce5b

File tree

1 file changed

+282
-0
lines changed

1 file changed

+282
-0
lines changed
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
<?php
2+
/**
3+
* This file is part of the TelegramBot package.
4+
*
5+
* (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
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\Commands\AdminCommands;
12+
13+
use Longman\TelegramBot\Commands\AdminCommand;
14+
use Longman\TelegramBot\DB;
15+
use Longman\TelegramBot\Exception\TelegramException;
16+
use Longman\TelegramBot\Request;
17+
use Longman\TelegramBot\TelegramLog;
18+
use PDOException;
19+
20+
/**
21+
* User "/cleanup" command
22+
*/
23+
class CleanupCommand extends AdminCommand
24+
{
25+
/**
26+
* @var string
27+
*/
28+
protected $name = 'cleanup';
29+
30+
/**
31+
* @var string
32+
*/
33+
protected $description = 'Clean up the database from old records';
34+
35+
/**
36+
* @var string
37+
*/
38+
protected $usage = '/cleanup';
39+
40+
/**
41+
* @var string
42+
*/
43+
protected $version = '1.0.0';
44+
45+
/**
46+
* Set command config
47+
*
48+
* @param string $custom_time
49+
*
50+
* @return array
51+
*/
52+
private function getSettings($custom_time = '')
53+
{
54+
// default tables to clean, cleaning 'chat', 'user' and 'user_chat' will be a bad practice!
55+
$tables_to_clean = [
56+
'botan_shortener',
57+
'callback_query',
58+
'chosen_inline_result',
59+
'conversation',
60+
'edited_message',
61+
'inline_query',
62+
'message',
63+
'request_limiter',
64+
'telegram_update',
65+
];
66+
67+
// remove records from these tables older than these X days/hours/anything
68+
$time_to_clean = [
69+
'botan_shortener' => '30 days',
70+
'chat' => '365 days',
71+
'callback_query' => '30 days',
72+
'chosen_inline_result' => '30 days',
73+
'conversation' => '30 days',
74+
'edited_message' => '30 days',
75+
'inline_query' => '30 days',
76+
'message' => '30 days',
77+
'request_limiter' => '1 minute',
78+
'telegram_update' => '30 days',
79+
'user' => '365 days',
80+
'user_chat' => '365 days',
81+
];
82+
83+
$user_tables_to_clean = $this->getConfig('tables_to_clean');
84+
if (!is_null($user_tables_to_clean)) {
85+
if (!is_array($user_tables_to_clean)) {
86+
throw new TelegramException('Variable \'tables_to_clean\' must be an array!');
87+
}
88+
89+
$tables_to_clean = $user_tables_to_clean;
90+
}
91+
92+
$user_time_to_clean = $this->getConfig('time_to_clean');
93+
if (!is_null($user_tables_to_clean)) {
94+
if (!$this->isAssociativeArray($user_time_to_clean)) {
95+
throw new TelegramException('Variable \'time_to_clean\' must be an associative array!');
96+
}
97+
98+
$time_to_clean = array_merge($time_to_clean, $user_time_to_clean);
99+
}
100+
101+
$settings['tables_to_clean'] = $tables_to_clean;
102+
$settings['time_to_clean'] = $time_to_clean;
103+
104+
if (is_numeric($custom_time)) {
105+
$custom_time = $custom_time . ' days';
106+
}
107+
108+
foreach ($settings['tables_to_clean'] as $table_to_clean) {
109+
if (!empty($custom_time)) {
110+
$settings['time_to_clean'][$table_to_clean] = $custom_time;
111+
}
112+
}
113+
114+
return $settings;
115+
}
116+
117+
/**
118+
* Little function to return whenever array is associative or not
119+
*
120+
* @param array $arr
121+
*
122+
* @return bool
123+
*/
124+
private function isAssociativeArray(array $arr)
125+
{
126+
if (!is_array($arr) || empty($arr)) {
127+
return false;
128+
}
129+
130+
return array_keys($arr) !== range(0, count($arr) - 1);
131+
}
132+
133+
/**
134+
* Get SQL queries array based on settings provided
135+
*
136+
* @param $settings
137+
*
138+
* @return array
139+
* @throws TelegramException
140+
*/
141+
private function getQueries($settings)
142+
{
143+
if (empty($settings) || !is_array($settings)) {
144+
throw new TelegramException('Settings variable is not an array or is empty!');
145+
}
146+
147+
$queries = [];
148+
149+
if (in_array('telegram_update', $settings['tables_to_clean'])) {
150+
$queries[] = 'DELETE FROM `telegram_update` WHERE
151+
`id` != \'' . $this->getUpdate()->getUpdateId() . '\' AND
152+
`chat_id` NOT IN (SELECT `id` FROM `chat` WHERE `chat_id` = `chat`.`id`) AND
153+
(`message_id` IS NOT NULL AND `message_id` IN (SELECT f.id FROM `message` f WHERE `date` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['telegram_update'])) . '\')) OR
154+
(`edited_message_id` IS NOT NULL AND `edited_message_id` IN (SELECT f.id FROM `edited_message` f WHERE `edit_date` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['telegram_update'])) . '\')) OR
155+
(`inline_query_id` IS NOT NULL AND `inline_query_id` IN (SELECT f.id FROM `inline_query` f WHERE `created_at` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['telegram_update'])) . '\')) OR
156+
(`chosen_inline_result_id` IS NOT NULL AND `chosen_inline_result_id` IN (SELECT f.id FROM `chosen_inline_result` f WHERE `created_at` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['telegram_update'])) . '\')) OR
157+
(`callback_query_id` IS NOT NULL AND `callback_query_id` IN (SELECT f.id FROM `callback_query` f WHERE `created_at` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['telegram_update'])) . '\'))';
158+
}
159+
160+
if (in_array('user_chat', $settings['tables_to_clean'])) {
161+
$queries[] = 'DELETE FROM `user_chat` WHERE `user_id` IN (SELECT f.id FROM `user` f WHERE `updated_at` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['chat'])) . '\')' . PHP_EOL;
162+
}
163+
164+
if (in_array('user', $settings['tables_to_clean'])) {
165+
$queries[] = 'DELETE FROM `user` WHERE `updated_at` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['user'])) . '\'' . PHP_EOL;
166+
}
167+
168+
if (in_array('chat', $settings['tables_to_clean'])) {
169+
$queries[] = 'DELETE FROM `chat` WHERE `updated_at` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['chat'])) . '\'' . PHP_EOL;
170+
}
171+
172+
if (in_array('inline_query', $settings['tables_to_clean'])) {
173+
$queries[] = 'DELETE FROM `inline_query` WHERE `created_at` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['inline_query'])) . '\' AND `id` NOT IN (SELECT `inline_query_id` FROM `telegram_update` WHERE `inline_query_id` = `inline_query`.`id`)';
174+
}
175+
176+
if (in_array('chosen_inline_result', $settings['tables_to_clean'])) {
177+
$queries[] = 'DELETE FROM `chosen_inline_result` WHERE `created_at` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['chosen_inline_result'])) . '\' AND `id` NOT IN (SELECT `chosen_inline_result_id` FROM `telegram_update` WHERE `chosen_inline_result_id` = `chosen_inline_result`.`id`)';
178+
}
179+
180+
if (in_array('callback_query', $settings['tables_to_clean'])) {
181+
$queries[] = 'DELETE FROM `callback_query` WHERE `created_at` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['callback_query'])) . '\' AND `id` NOT IN (SELECT `callback_query_id` FROM `telegram_update` WHERE `callback_query_id` = `callback_query`.`id`)' . PHP_EOL;
182+
}
183+
184+
if (in_array('edited_message', $settings['tables_to_clean'])) {
185+
$queries[] = 'DELETE FROM `edited_message` WHERE `edit_date` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['edited_message'])) . '\' AND `id` NOT IN (SELECT `message_id` FROM `telegram_update` WHERE `edited_message_id` = `edited_message`.`id`)' . PHP_EOL;
186+
}
187+
188+
if (in_array('message', $settings['tables_to_clean'])) {
189+
$queries[] = 'DELETE FROM `message` WHERE `date` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['message'])) . '\' AND `id` NOT IN (SELECT `message_id` FROM `callback_query` WHERE `message_id` = `message`.`id`) AND `id` NOT IN (SELECT `message_id` FROM `telegram_update` WHERE `message_id` = `message`.`id`)' . PHP_EOL;
190+
}
191+
192+
if (in_array('botan_shortener', $settings['tables_to_clean'])) {
193+
$queries[] = 'DELETE FROM `botan_shortener` WHERE `created_at` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['botan_shortener'])) . '\'';
194+
}
195+
196+
if (in_array('conversation', $settings['tables_to_clean'])) {
197+
$queries[] = 'DELETE FROM `conversation` WHERE `updated_at` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['conversation'])) . '\'';
198+
}
199+
200+
if (in_array('request_limiter', $settings['tables_to_clean'])) {
201+
$queries[] = 'DELETE FROM `request_limiter` WHERE `created_at` < \'' . date('Y-m-d H:i:s', strtotime('-' . $settings['time_to_clean']['request_limiter'])) . '\'';
202+
}
203+
204+
return $queries;
205+
}
206+
207+
/**
208+
* Command execute method
209+
*
210+
* @return \Longman\TelegramBot\Entities\ServerResponse
211+
* @throws \Longman\TelegramBot\Exception\TelegramException
212+
*/
213+
public function execute()
214+
{
215+
$message = $this->getMessage();
216+
$chat_id = $message->getFrom()->getId();
217+
$text = $message->getText(true);
218+
219+
$data = [];
220+
$data['chat_id'] = $chat_id;
221+
$data['parse_mode'] = 'Markdown';
222+
223+
if (!$message->getChat()->isPrivateChat()) {
224+
$data['text'] = 'Only available in a private chat.';
225+
226+
return Request::sendMessage($data);
227+
}
228+
229+
$settings = $this->getSettings($text);
230+
$queries = $this->getQueries($settings);
231+
232+
$tables = '';
233+
foreach ($settings['tables_to_clean'] as $table) {
234+
if (!empty($tables)) {
235+
$tables .= ', ';
236+
}
237+
238+
$tables .= '*' . $table . '*';
239+
$time = $settings['time_to_clean'][$table];
240+
241+
if (isset($time)) {
242+
$tables .= ' (' . $time . ')';
243+
}
244+
}
245+
246+
$data['text'] = 'Cleaning up tables:' . PHP_EOL . ' ' . $tables;
247+
248+
Request::sendMessage($data);
249+
250+
$rows = 0;
251+
$pdo = DB::getPdo();
252+
try {
253+
$pdo->beginTransaction();
254+
255+
foreach ($queries as $query) {
256+
$dbq = $pdo->prepare($query);
257+
if ($dbq->execute()) {
258+
$rows += $dbq->rowCount();
259+
} else {
260+
TelegramLog::error('Error while executing query: ' . $query . PHP_EOL);
261+
}
262+
}
263+
} catch (PDOException $e) {
264+
$pdo->rollBack(); // rollback changes on exception (useful if you want to track down error - you can't replicate it when some of the data is already deleted...)
265+
throw new TelegramException($e->getMessage());
266+
} finally {
267+
$pdo->commit(); // commit changes to the database and end transaction
268+
}
269+
270+
if (isset($rows)) {
271+
if ($rows > 0) {
272+
$data['text'] = '*Database cleanup done!* _(removed ' . $rows .' rows)_';
273+
} else {
274+
$data['text'] = '*No data to clean!*';
275+
}
276+
} else {
277+
$data['text'] = '*Database cleanup failed!*';
278+
}
279+
280+
return Request::sendMessage($data);
281+
}
282+
}

0 commit comments

Comments
 (0)