yourtar-cli 1.3.3 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/bin/backTemplate/Makefile +7 -0
  2. package/bin/backTemplate/config/packages/monolog.yaml +61 -0
  3. package/bin/backTemplate/docker/config/promtail/config.yml +18 -0
  4. package/bin/backTemplate/docker/docker-compose.prod.yml +11 -0
  5. package/bin/backTemplate/docker/docker-compose.stage.yml +11 -0
  6. package/bin/backTemplate/src/Logging/YTExtraDataProcessor.php +20 -0
  7. package/bin/botTemplate/.env.dev-example +4 -2
  8. package/bin/botTemplate/.env.prod-example +4 -2
  9. package/bin/botTemplate/.env.stage-example +4 -2
  10. package/bin/botTemplate/Makefile +21 -2
  11. package/bin/botTemplate/config/packages/monolog.yaml +61 -0
  12. package/bin/botTemplate/docker/config/promtail/config.yml +18 -0
  13. package/bin/botTemplate/docker/docker-compose.prod.yml +11 -0
  14. package/bin/botTemplate/docker/docker-compose.stage.yml +11 -0
  15. package/bin/botTemplate/src/Controller/MessageController.php +74 -11
  16. package/bin/botTemplate/src/Entity/Chat.php +39 -25
  17. package/bin/botTemplate/src/Entity/DialogContext.php +1 -32
  18. package/bin/botTemplate/src/Entity/User.php +93 -0
  19. package/bin/botTemplate/src/Logging/YTExtraDataProcessor.php +20 -0
  20. package/bin/botTemplate/src/Repository/UserRepository.php +43 -0
  21. package/bin/botTemplate/src/Service/Service/MessageProcessService.php +34 -0
  22. package/bin/botTemplate/src/Service/Service/MessageThemeService/CustomMessageService.php +164 -0
  23. package/bin/botTemplate/src/Service/Service/MessageThemeService/MessageServiceTemplate.php +79 -0
  24. package/bin/botTemplate/src/Service/Service/MessageThemeService/MessageThemeInterface.php +8 -0
  25. package/bin/botTemplate/src/Service/Service/MessengerService/MaxService.php +275 -0
  26. package/bin/botTemplate/src/Service/Service/MessengerService/MessengerInterface.php +22 -0
  27. package/bin/botTemplate/src/Service/Service/MessengerService/TelegramService.php +195 -0
  28. package/bin/botTemplate/src/Service/Service/MessengerService/VkService.php +590 -0
  29. package/bin/index.js +5 -2
  30. package/package.json +1 -1
  31. package/bin/botTemplate/src/Service/MessageProcessService.php +0 -256
  32. package/bin/botTemplate/src/Service/TelegramService.php +0 -227
@@ -0,0 +1,590 @@
1
+ <?php
2
+
3
+ namespace App\Service\MessengerService;
4
+
5
+ use App\Entity\Chat;
6
+ use CURLFile;
7
+ use Psr\Log\LoggerInterface;
8
+
9
+ class VkService implements MessengerInterface
10
+ {
11
+ private ?Chat $chat = null;
12
+
13
+ public function __construct(?Chat $chat = null)
14
+ {
15
+ $this->chat = $chat;
16
+ }
17
+
18
+ public function normalizeMessage(array $message): array
19
+ {
20
+ $result = array();
21
+
22
+ if (array_key_exists('object', $message)) {
23
+ $message = $message['object'];
24
+ // 2. username
25
+ // 4. phone
26
+ if (array_key_exists('message', $message)) {
27
+ if (array_key_exists('message', $message) && array_key_exists('text', $message['message'])) $result['message'] = $message['message']['text'];
28
+ if (array_key_exists('message', $message) && array_key_exists('peer_id', $message['message'])) $result['from'] = $message['message']['peer_id'];
29
+ if (array_key_exists('message', $message) && array_key_exists('from_id', $message['message'])) $result['userId'] = $message['message']['from_id'];
30
+ if (array_key_exists('message', $message) && array_key_exists('conversation_message_id', $message['message'])) $result['message_id'] = $message['message']['conversation_message_id'];
31
+ if (array_key_exists('message', $message) && array_key_exists('payload', $message['message'])) {
32
+ $result['data'] = json_decode($message['message']['payload'], true);
33
+ if (is_array($result['data']) && isset($result['data']['command']) && is_string($result['data']['command'])) {
34
+ $cmd = trim((string)$result['data']['command']);
35
+ if ($cmd !== '' && (str_starts_with($cmd, 't2i') || str_starts_with($cmd, 't2v') || $cmd === 'start')) {
36
+ $this->logger?->error('VK payload(message) ' . json_encode([
37
+ 'from' => $result['from'] ?? null,
38
+ 'payload_raw' => $message['message']['payload'],
39
+ 'payload_decoded' => $result['data'],
40
+ ]));
41
+ }
42
+ }
43
+ if (is_array($result['data']) && isset($result['data']['command']) && is_string($result['data']['command'])) {
44
+ if ($result['data']['command'] === 'start') {
45
+ $result['message'] = '/start';
46
+ if (array_key_exists('ref', $message['message'])) $result['message'] .= ' ' . $message['message']['ref'];
47
+ } elseif (str_contains($result['data']['command'], '/')) $result['message'] = $result['data']['command'];
48
+ else unset($result['message']);
49
+ }
50
+ }
51
+ if (array_key_exists('message', $message) && array_key_exists('attachments', $message['message']) && count($message['message']['attachments']) > 0) {
52
+ foreach ($message['message']['attachments'] as $attach) {
53
+ switch ($attach['type']) {
54
+ case 'photo':
55
+ if (!array_key_exists('photos', $result)) $result['photos'] = array();
56
+ $url = null;
57
+ if (isset($attach['photo']['orig_photo']['url']) && is_string($attach['photo']['orig_photo']['url'])) {
58
+ $url = trim((string)$attach['photo']['orig_photo']['url']);
59
+ }
60
+ if ((!is_string($url) || $url === '') && isset($attach['photo']['sizes']) && is_array($attach['photo']['sizes'])) {
61
+ $best = null;
62
+ $bestArea = 0;
63
+ foreach ($attach['photo']['sizes'] as $sz) {
64
+ if (!is_array($sz)) continue;
65
+ $u = $sz['url'] ?? null;
66
+ if (!is_string($u) || trim($u) === '') continue;
67
+ $w = isset($sz['width']) ? (int)$sz['width'] : 0;
68
+ $h = isset($sz['height']) ? (int)$sz['height'] : 0;
69
+ $area = ($w > 0 && $h > 0) ? ($w * $h) : 0;
70
+ if ($best === null || $area > $bestArea) {
71
+ $best = trim((string)$u);
72
+ $bestArea = $area;
73
+ }
74
+ }
75
+ if (is_string($best) && $best !== '') {
76
+ $url = $best;
77
+ }
78
+ }
79
+
80
+ $ext = '';
81
+ if (is_string($url) && $url !== '') {
82
+ $path = (string)(parse_url($url, PHP_URL_PATH) ?? '');
83
+ $base = (string)basename($path);
84
+ $ext = strtolower((string)pathinfo($base, PATHINFO_EXTENSION));
85
+ }
86
+ if ($ext === '') {
87
+ $ext = 'jpg';
88
+ }
89
+ $result['photos'][] = array(
90
+ 'url' => is_string($url) ? $url : '',
91
+ 'ext' => $ext,
92
+ );
93
+ break;
94
+ case 'doc':
95
+ if (!array_key_exists('documents', $result)) $result['documents'] = array();
96
+ $result['documents'][] = array(
97
+ 'url' => $attach['doc']['url'],
98
+ 'ext' => $attach['doc']['ext'],
99
+ 'access' => $attach['doc']['access_key'],
100
+ );
101
+ break;
102
+ default:
103
+ break;
104
+ }
105
+ }
106
+ }
107
+ } else {
108
+ if (array_key_exists('peer_id', $message)) $result['from'] = $message['peer_id'];
109
+ if (array_key_exists('user_id', $message)) $result['userId'] = $message['user_id'];
110
+ if (!array_key_exists('userId', $result) && array_key_exists('from_id', $message)) $result['userId'] = $message['from_id'];
111
+ if (!array_key_exists('from', $result) && array_key_exists('from_id', $message)) $result['from'] = $message['from_id'];
112
+ if (array_key_exists('conversation_message_id', $message)) $result['message_id'] = $message['conversation_message_id'];
113
+ if (array_key_exists('payload', $message)) {
114
+ $result['data'] = $message['payload'];
115
+ if (is_string($result['data'])) {
116
+ $decoded = json_decode($result['data'], true);
117
+ $cmd = is_array($decoded) && isset($decoded['command']) && is_string($decoded['command']) ? trim((string)$decoded['command']) : '';
118
+ if ($cmd !== '' && (str_starts_with($cmd, 't2i') || str_starts_with($cmd, 't2v') || $cmd === 'start')) {
119
+ $this->logger?->error('VK payload(root) ' . json_encode([
120
+ 'from' => $result['from'] ?? null,
121
+ 'payload_raw' => $result['data'],
122
+ 'payload_decoded' => $decoded,
123
+ ]));
124
+ }
125
+ }
126
+ if (is_array($result['data']) && isset($result['data']['command']) && is_string($result['data']['command'])) {
127
+ if ($result['data']['command'] === 'start') $result['message'] = '/start';
128
+ elseif (str_contains($result['data']['command'], '/')) $result['message'] = $result['data']['command'];
129
+ else unset($result['message']);
130
+ }
131
+ }
132
+ }
133
+
134
+ $result['type'] = 'VK';
135
+ }
136
+
137
+ return $result;
138
+ }
139
+
140
+ public function sendMessage(string $message, ?array $buttons = null, ?array $photos = null, ?string $editMsgId = null)
141
+ {
142
+ $attachs = null;
143
+ if (is_array($photos) && count($photos) > 0) {
144
+ foreach ($photos as $photo) {
145
+ $url = $this->_vkApi_call('photos.getMessagesUploadServer', array(
146
+ 'peer_id' => $this->chat->getChatId(),
147
+ ));
148
+
149
+ // $curl = curl_init(str_replace('\\', '', $url['upload_url']));
150
+ // curl_setopt($curl, CURLOPT_POST, true);
151
+ // curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
152
+ // curl_setopt($curl, CURLOPT_POSTFIELDS, array('photo' => new CURLfile("/var/www/html/public/downloads/$photo")));
153
+ // $json = curl_exec($curl);
154
+ // $error = curl_error($curl);
155
+
156
+ // curl_close($curl);
157
+ // $response = json_decode($json, true);
158
+ $curl = curl_init();
159
+ curl_setopt_array($curl, array(
160
+ CURLOPT_URL => str_replace('\\', '', $url['upload_url']),
161
+ CURLOPT_RETURNTRANSFER => true,
162
+ CURLOPT_ENCODING => '',
163
+ CURLOPT_MAXREDIRS => 10,
164
+ CURLOPT_TIMEOUT => 0,
165
+ CURLOPT_FOLLOWLOCATION => true,
166
+ CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
167
+ CURLOPT_CUSTOMREQUEST => 'POST',
168
+ CURLOPT_POSTFIELDS => array('photo' => new CURLFILE("/var/www/html/public/downloads/$photo")),
169
+ ));
170
+ $json = curl_exec($curl);
171
+ curl_close($curl);
172
+ $response = json_decode($json, true);
173
+
174
+ $attach = $this->_vkApi_call('photos.saveMessagesPhoto', array(
175
+ 'photo' => $response['photo'],
176
+ 'server' => $response['server'],
177
+ 'hash' => $response['hash'],
178
+ ));
179
+
180
+ if (is_null($attachs)) $attachs = "";
181
+ else $attachs .= ",";
182
+ $attachs .= 'photo' . $attach[0]['owner_id'] . '_' . $attach[0]['id'] . '_' . $attach[0]['access_key'];
183
+ // $attach = explode('?', $attach['photo']['url'])[0];
184
+ // $attach = explode('/', $attach);
185
+ // $attach = end($attach);
186
+ }
187
+
188
+ }
189
+
190
+ $btns = array();
191
+ if (is_array($buttons) && count($buttons) > 0) foreach ($buttons as $btn) {
192
+ $btns[] = array();
193
+ foreach ($btn as $btnItem) {
194
+ $btns[count($btns) - 1][] = array(
195
+ 'action' => array(
196
+ 'type' => 'callback',
197
+ 'label' => $btnItem['text'],
198
+ ),
199
+ );
200
+ if (array_key_exists('callback_data', $btnItem))
201
+ $btns[count($btns) - 1][count($btns[count($btns) - 1]) - 1]['action']['payload'] = $btnItem['callback_data'];
202
+ if (array_key_exists('url', $btnItem)) {
203
+ $btns[count($btns) - 1][count($btns[count($btns) - 1]) - 1]['action']['type'] = 'open_link';
204
+ $btns[count($btns) - 1][count($btns[count($btns) - 1]) - 1]['action']['link'] = $btnItem['url'];
205
+ }
206
+ }
207
+ }
208
+
209
+ $params = array(
210
+ 'random_id' => random_int(0, 31767),
211
+ 'peer_id' => $this->chat->getChatId(),
212
+ 'message' => $message,
213
+ 'keyboard' => json_encode([
214
+ 'inline' => true,
215
+ 'buttons' => $btns,
216
+ ], JSON_UNESCAPED_SLASHES),
217
+ );
218
+ if (!is_null($attachs)) $params['attachment'] = $attachs;
219
+
220
+ if (is_null($editMsgId)) $result = $this->_vkApi_call('messages.send', $params);
221
+ else {
222
+ $params['conversation_message_id'] = $editMsgId;
223
+ $this->_vkApi_call('messages.edit', $params);
224
+ }
225
+ return $result;
226
+ }
227
+
228
+ public function getShortLink(string $link)
229
+ {
230
+ $params = array(
231
+ 'url' => $link,
232
+ 'private' => 0,
233
+ );
234
+ $result = $this->_vkApi_call('utils.getShortLink', $params);
235
+
236
+ return $result;
237
+ }
238
+
239
+ public function sendKeyboardMessage(string $message, ?array $buttons = null)
240
+ {
241
+ $btns = array();
242
+ if (is_array($buttons) && count($buttons) > 0) foreach ($buttons as $btn) {
243
+ $btns[] = array();
244
+ foreach ($btn as $btnItem) {
245
+ $btns[count($btns) - 1][] = array(
246
+ 'action' => array(
247
+ 'type' => 'text',
248
+ 'label' => $btnItem['text'],
249
+ ),
250
+ 'color' => 'primary',
251
+ );
252
+ if (array_key_exists('callback_data', $btnItem))
253
+ $btns[count($btns) - 1][count($btns[count($btns) - 1]) - 1]['action']['payload'] = $btnItem['callback_data'];
254
+ if (array_key_exists('url', $btnItem)) {
255
+ $btns[count($btns) - 1][count($btns[count($btns) - 1]) - 1]['type'] = 'open_link';
256
+ $btns[count($btns) - 1][count($btns[count($btns) - 1]) - 1]['link'] = $btnItem['url'];
257
+ }
258
+ }
259
+ }
260
+
261
+ return $this->_vkApi_call('messages.send', array(
262
+ 'random_id' => random_int(0, 31767),
263
+ 'peer_id' => $this->chat->getChatId(),
264
+ 'message' => $message,
265
+ // 'attachment' => implode(',', $photos),
266
+ 'keyboard' => json_encode([
267
+ 'inline' => false,
268
+ 'buttons' => $btns,
269
+ ]),
270
+ ));
271
+ }
272
+
273
+ public function sendVideo(string $message, ?string $video = null)
274
+ {
275
+ if (is_string($video) && $video !== '' && !str_contains($video, '/var/www/html/public/downloads/')) {
276
+ $video = '/var/www/html/public/downloads/' . ltrim($video, '/');
277
+ }
278
+
279
+ if (!is_string($video) || $video === '' || !is_file($video)) {
280
+ if (!is_null($this->logger)) {
281
+ $this->logger->error('VK sendVideo: file not found ' . json_encode(['video' => $video]));
282
+ }
283
+ return $this->sendMessage($message ?: 'Видео', $this->chat->getChatId());
284
+ }
285
+
286
+ // Попытка загрузить видео через VK video.save API
287
+ try {
288
+ $videoSave = $this->_vkApi_call('video.save', [
289
+ 'name' => mb_substr($message, 0, 128) ?: 'Video',
290
+ 'description' => $message ?: '',
291
+ 'is_private' => 1,
292
+ 'wallpost' => 0,
293
+ 'no_comments' => 1,
294
+ ]);
295
+
296
+ if (is_array($videoSave) && isset($videoSave['upload_url'])) {
297
+ $curl = curl_init(str_replace('\\', '', $videoSave['upload_url']));
298
+ curl_setopt_array($curl, [
299
+ CURLOPT_RETURNTRANSFER => true,
300
+ CURLOPT_ENCODING => '',
301
+ CURLOPT_MAXREDIRS => 10,
302
+ CURLOPT_TIMEOUT => 300,
303
+ CURLOPT_FOLLOWLOCATION => true,
304
+ CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
305
+ CURLOPT_CUSTOMREQUEST => 'POST',
306
+ CURLOPT_POSTFIELDS => ['video_file' => new CURLFILE($video)],
307
+ ]);
308
+ $json = curl_exec($curl);
309
+ $error = curl_error($curl);
310
+ curl_close($curl);
311
+
312
+ if (!is_null($this->logger)) {
313
+ $this->logger->error('VK video upload response: ' . substr((string)$json, 0, 500));
314
+ }
315
+
316
+ $uploadResult = is_string($json) ? json_decode($json, true) : null;
317
+ $ownerId = $videoSave['owner_id'] ?? ($uploadResult['owner_id'] ?? null);
318
+ $videoId = $videoSave['video_id'] ?? ($uploadResult['vid'] ?? ($uploadResult['video_id'] ?? null));
319
+ $accessKey = $videoSave['access_key'] ?? ($uploadResult['access_key'] ?? null);
320
+
321
+ if ((is_string($ownerId) || is_int($ownerId)) && (is_string($videoId) || is_int($videoId))) {
322
+ $attach = 'video' . $ownerId . '_' . $videoId;
323
+ if (is_string($accessKey) && $accessKey !== '') {
324
+ $attach .= '_' . $accessKey;
325
+ }
326
+
327
+ $params = [
328
+ 'random_id' => random_int(0, 32767),
329
+ 'peer_id' => $this->chat->getChatId(),
330
+ 'message' => $message ?: 'Видео',
331
+ 'attachment' => $attach,
332
+ ];
333
+
334
+ return $this->_vkApi_call('messages.send', $params);
335
+ }
336
+ }
337
+ } catch (\Throwable $e) {
338
+ if (!is_null($this->logger)) {
339
+ $this->logger->error('VK video.save failed, falling back to document: ' . $e->getMessage());
340
+ }
341
+ }
342
+
343
+ // Фолбэк: отправить как документ
344
+ $filename = basename($video);
345
+ return $this->sendDocument($message ?: 'Видео', $filename, $this->chat->getChatId());
346
+ }
347
+
348
+ public function getFile(array|string $id): bool|string
349
+ {
350
+ // $filename = explode('?', $file['url'])[0];
351
+ // $filename = explode('/', $filename);
352
+ // $filename = end($filename);
353
+ // $filename = $filename . (!str_contains($filename, '.') ? '.' . $file['ext'] : '');
354
+ // $filename = explode('.', $filename);
355
+ // $filename = uniqid() . '.' . end($filename);
356
+ // file_put_contents("/var/www/html/public/downloads/$filename", str_replace('\\', '', $file['url']));
357
+
358
+ $fileUrl = '';
359
+ $ext = '';
360
+ if (is_array($id)) {
361
+ $fileUrl = isset($file['url']) && is_string($file['url']) ? (string)$file['url'] : '';
362
+ $ext = isset($file['ext']) && is_string($file['ext']) ? (string)$file['ext'] : '';
363
+ } else {
364
+ $fileUrl = (string)$id;
365
+ }
366
+
367
+ $fileUrl = str_replace('\\', '', $fileUrl);
368
+ $fileUrl = trim($fileUrl);
369
+ if ($fileUrl === '') {
370
+ return false;
371
+ }
372
+
373
+ $cleanBase = (string)basename(parse_url($fileUrl, PHP_URL_PATH) ?? '');
374
+ $pathExt = strtolower((string)pathinfo($cleanBase, PATHINFO_EXTENSION));
375
+ $ext = strtolower(trim($ext));
376
+ if ($ext === '') {
377
+ $ext = $pathExt;
378
+ }
379
+ if ($ext === '') {
380
+ $ext = 'jpg';
381
+ }
382
+
383
+ $name = uniqid() . "." . $ext;
384
+ $savePath = "/var/www/html/public/downloads/" . $name;
385
+ $fileHandle = fopen($savePath, 'w+');
386
+ $ch = curl_init($fileUrl);
387
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Return the transfer as a string instead of outputting it directly
388
+ curl_setopt($ch, CURLOPT_FILE, $fileHandle); // Save the file to the open file handle
389
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // Follow redirects
390
+ curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'); // Mimic a browser user agent
391
+ curl_setopt($ch, CURLOPT_TIMEOUT, 28800); // Set timeout (e.g., 8 hours for large files)
392
+ $success = curl_exec($ch);
393
+ $err = curl_error($ch);
394
+ curl_close($ch);
395
+ fclose($fileHandle);
396
+
397
+ if ($success === false) {
398
+ @unlink($savePath);
399
+ return false;
400
+ }
401
+
402
+ // Ensure correct extension for images (VK URLs sometimes miss ext; wrong ext breaks downstream consumers)
403
+ try {
404
+ $detectedExt = null;
405
+ if (function_exists('exif_imagetype')) {
406
+ $imgType = @exif_imagetype($savePath);
407
+ if (is_int($imgType)) {
408
+ $detectedExt = match ($imgType) {
409
+ IMAGETYPE_JPEG => 'jpg',
410
+ IMAGETYPE_PNG => 'png',
411
+ IMAGETYPE_GIF => 'gif',
412
+ IMAGETYPE_WEBP => 'webp',
413
+ default => null,
414
+ };
415
+ }
416
+ }
417
+
418
+ if ($detectedExt === null && function_exists('finfo_open')) {
419
+ $fi = @finfo_open(FILEINFO_MIME_TYPE);
420
+ if ($fi) {
421
+ $mime = @finfo_file($fi, $savePath);
422
+ @finfo_close($fi);
423
+ if (is_string($mime)) {
424
+ $mime = strtolower(trim($mime));
425
+ $detectedExt = match ($mime) {
426
+ 'image/jpeg' => 'jpg',
427
+ 'image/png' => 'png',
428
+ 'image/gif' => 'gif',
429
+ 'image/webp' => 'webp',
430
+ default => null,
431
+ };
432
+ }
433
+ }
434
+ }
435
+
436
+ if (is_string($detectedExt) && $detectedExt !== '' && strtolower($ext) !== strtolower($detectedExt)) {
437
+ $newName = uniqid() . '.' . $detectedExt;
438
+ $newPath = "/var/www/html/public/downloads/" . $newName;
439
+ if (@rename($savePath, $newPath)) {
440
+ $name = $newName;
441
+ $savePath = $newPath;
442
+ }
443
+ }
444
+ } catch (\Throwable $e) {
445
+ if (!is_null($this->logger)) {
446
+ $this->logger->error('VK getFile detect type failed ' . json_encode([
447
+ 'path' => $savePath,
448
+ 'error' => $e->getMessage(),
449
+ ]));
450
+ }
451
+ }
452
+
453
+ // return $filename;
454
+ return $name;
455
+ }
456
+
457
+ public function deleteMessage(string $id)
458
+ {
459
+ return $this->_vkApi_call('messages.delete', array(
460
+ 'peer_id' => $this->chat->getChatId(),
461
+ 'cmids' => $id,
462
+ 'delete_for_all' => 1,
463
+ ));
464
+ }
465
+
466
+ public function checkSubscribe($userId)
467
+ {
468
+ // $channelId = '@igromania';
469
+ // $curl = curl_init();
470
+ // curl_setopt_array($curl, array(
471
+ // CURLOPT_URL => 'https://api.telegram.org/bot' . $this->botToken . '/getChatMember?chat_id=' . $channelId . '&user_id=' . $userId,
472
+ // CURLOPT_RETURNTRANSFER => true,
473
+ // CURLOPT_ENCODING => '',
474
+ // CURLOPT_MAXREDIRS => 10,
475
+ // CURLOPT_TIMEOUT => 0,
476
+ // CURLOPT_FOLLOWLOCATION => true,
477
+ // CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
478
+ // CURLOPT_CUSTOMREQUEST => 'GET',
479
+ // ));
480
+ // $resp = json_decode(curl_exec($curl), true);
481
+ // curl_close($curl);
482
+
483
+ // return $resp;
484
+ }
485
+
486
+ public function sendDocument(string $message, string $document, ?array $buttons = null)
487
+ {
488
+ if (is_string($document) && $document !== '' && !str_contains($document, '/var/www/html/public/downloads/')) {
489
+ $document = '/var/www/html/public/downloads/' . ltrim($document, '/');
490
+ }
491
+
492
+ if (!is_string($document) || $document === '' || !is_file($document)) {
493
+ return $this->sendMessage($message ?: 'Документ', $this->chat->getChatId());
494
+ }
495
+
496
+ $url = $this->_vkApi_call('docs.getMessagesUploadServer', array(
497
+ 'peer_id' => $this->chat->getChatId(),
498
+ 'type' => 'doc',
499
+ ));
500
+
501
+ $curl = curl_init($url['upload_url']);
502
+ curl_setopt($curl, CURLOPT_POST, true);
503
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
504
+ curl_setopt($curl, CURLOPT_TIMEOUT, 300);
505
+ curl_setopt($curl, CURLOPT_POSTFIELDS, array('file' => new CURLfile($document)));
506
+ $json = curl_exec($curl);
507
+ $error = curl_error($curl);
508
+
509
+ curl_close($curl);
510
+ $response = json_decode($json, true);
511
+
512
+ $saveResult = $this->_vkApi_call('docs.save', array(
513
+ 'file' => $response['file'],
514
+ 'title' => basename($document),
515
+ ));
516
+
517
+ // Формируем корректный attachment для VK: doc<owner_id>_<doc_id>
518
+ $attach = '';
519
+ if (is_array($saveResult) && isset($saveResult['doc'])) {
520
+ $doc = $saveResult['doc'];
521
+ $attach = 'doc' . $doc['owner_id'] . '_' . $doc['id'];
522
+ if (isset($doc['access_key']) && is_string($doc['access_key']) && $doc['access_key'] !== '') {
523
+ $attach .= '_' . $doc['access_key'];
524
+ }
525
+ }
526
+
527
+ if ($attach === '') {
528
+ return $this->sendMessage($message ?: 'Документ', $this->chat->getChatId());
529
+ }
530
+
531
+ $btns = array();
532
+ if (is_array($buttons) && count($buttons) > 0) foreach ($buttons as $btn) {
533
+ $btns[] = array();
534
+ foreach ($btn as $btnItem) {
535
+ $btns[count($btns) - 1][] = array(
536
+ 'action' => array(
537
+ 'type' => 'callback',
538
+ 'label' => $btnItem['text'],
539
+ ),
540
+ 'color' => 'primary',
541
+ );
542
+ if (array_key_exists('callback_data', $btnItem))
543
+ $btns[count($btns) - 1][count($btns[count($btns) - 1]) - 1]['action']['payload'] = $btnItem['callback_data'];
544
+ if (array_key_exists('url', $btnItem)) {
545
+ $btns[count($btns) - 1][count($btns[count($btns) - 1]) - 1]['type'] = 'open_link';
546
+ $btns[count($btns) - 1][count($btns[count($btns) - 1]) - 1]['link'] = $btnItem['url'];
547
+ }
548
+ }
549
+ }
550
+
551
+ return $this->_vkApi_call('messages.send', array(
552
+ 'random_id' => random_int(0, 31767),
553
+ 'peer_id' => $this->chat->getChatId(),
554
+ 'message' => $message,
555
+ 'attachment' => $attach,
556
+ 'keyboard' => json_encode([
557
+ 'inline' => true,
558
+ 'buttons' => $btns,
559
+ ]),
560
+ ));
561
+ }
562
+
563
+ function _vkApi_call($method, $params = array())
564
+ {
565
+ $params['access_token'] = $_ENV['VK_TOKEN'];
566
+ $params['v'] = '5.199';
567
+
568
+ $query = http_build_query($params, "", null, PHP_QUERY_RFC3986);
569
+ $url = 'https://api.vk.com/method/' . $method . '?' . $query;
570
+
571
+ $curl = curl_init($url);
572
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
573
+ $json = curl_exec($curl);
574
+ $error = curl_error($curl);
575
+ if ($error) {
576
+ if (!is_null($this->logger)) $this->logger->critical('VK ERROR ' . json_encode($error));
577
+ throw new \Exception("Failed {$method} request");
578
+ }
579
+
580
+ curl_close($curl);
581
+
582
+ $response = json_decode($json, true);
583
+ if (!$response || !isset($response['response'])) {
584
+ if (!is_null($this->logger)) $this->logger->critical('VK JSON ERROR ' . json_encode($json));
585
+ throw new \Exception("Invalid response for {$method} request");
586
+ }
587
+
588
+ return $response['response'];
589
+ }
590
+ }
package/bin/index.js CHANGED
@@ -62,6 +62,7 @@ programm.command('create')
62
62
  console.error("ERROR!!! We don't know about this type: " + answers.platform);
63
63
  }
64
64
 
65
+ await exec('git rev-parse --is-inside-work-tree >/dev/null 2>&1 || git init');
65
66
  await copyTemplate(templateFolder, './' + projectFolder, answers.name);
66
67
 
67
68
  switch(answers.platform) {
@@ -69,11 +70,12 @@ programm.command('create')
69
70
  break;
70
71
  case 'back':
71
72
  //install packages
73
+ if (fs.existsSync('./' + projectFolder + '/.env.dev')) await fs.unlink('./' + projectFolder + '/.env.dev');
72
74
  await fs.copyFileSync('./' + projectFolder + '/.env.dev-example', './' + projectFolder + '/.env-main');
73
75
  await fs.renameSync('./' + projectFolder + '/.env-main', './' + projectFolder + '/.env');
74
76
  await fs.copyFileSync('./' + projectFolder + '/.env', './' + projectFolder + '/docker/.env');
75
77
  await exec('docker compose -f ./' + projectFolder + '/docker/docker-compose.dev.yml up -d --build');
76
- await exec('cd ' + projectFolder + '/docker && docker compose -f docker-compose.dev.yml exec php_' + answers.name + '_back composer require serializer security cors orm');
78
+ await exec('cd ' + projectFolder + '/docker && docker compose -f docker-compose.dev.yml exec php_' + answers.name + '_back composer require serializer security cors orm monolog');
77
79
  if (fs.existsSync('./' + projectFolder + '/compose.yaml')) fs.unlinkSync('./' + projectFolder + '/compose.yaml');
78
80
  if (fs.existsSync('./' + projectFolder + '/compose.override.yaml')) fs.unlinkSync('./' + projectFolder + '/compose.override.yaml');
79
81
  await exec('cd ' + projectFolder + '/docker && docker compose -f docker-compose.dev.yml exec php_' + answers.name + '_back composer require --dev symfony/maker-bundle');
@@ -81,11 +83,12 @@ programm.command('create')
81
83
  break;
82
84
  case 'bot':
83
85
  //install packages
86
+ if (fs.existsSync('./' + projectFolder + '/.env.dev')) await fs.unlink('./' + projectFolder + '/.env.dev');
84
87
  await fs.copyFileSync('./' + projectFolder + '/.env.dev-example', './' + projectFolder + '/.env-main');
85
88
  await fs.renameSync('./' + projectFolder + '/.env-main', './' + projectFolder + '/.env');
86
89
  await fs.copyFileSync('./' + projectFolder + '/.env', './' + projectFolder + '/docker/.env');
87
90
  await exec('docker compose -f ./' + projectFolder + '/docker/docker-compose.dev.yml up -d --build');
88
- await exec('cd ' + projectFolder + '/docker && docker compose -f docker-compose.dev.yml exec php_' + answers.name + '_back composer require serializer security cors orm');
91
+ await exec('cd ' + projectFolder + '/docker && docker compose -f docker-compose.dev.yml exec php_' + answers.name + '_back composer require serializer security cors orm monolog');
89
92
  if (fs.existsSync('./' + projectFolder + '/compose.yaml')) fs.unlinkSync('./' + projectFolder + '/compose.yaml');
90
93
  if (fs.existsSync('./' + projectFolder + '/compose.override.yaml')) fs.unlinkSync('./' + projectFolder + '/compose.override.yaml');
91
94
  await exec('cd ' + projectFolder + '/docker && docker compose -f docker-compose.dev.yml exec php_' + answers.name + '_back composer require --dev symfony/maker-bundle');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yourtar-cli",
3
- "version": "1.3.3",
3
+ "version": "2.0.1",
4
4
  "description": "This CLI for YourTar developers and our clients ;-)",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {