Added VKBot
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class VkBotController extends Controller
|
||||
{
|
||||
public function handle(Request $request)
|
||||
{
|
||||
// Получаем данные от VK в формате массива
|
||||
$data = $request->all();
|
||||
|
||||
// Проверяем тип запроса
|
||||
if (! isset($data['type'])) { return response('ok', 200); }
|
||||
|
||||
// 1. Подтверждение сервера для VK (срабатывает один раз)
|
||||
if ($data['type'] === 'confirmation') {
|
||||
// Замените ЭТУ_СТРОКУ на код из настроек Callback API в VK
|
||||
return response('ЭТУ_СТРОКУ', 200)
|
||||
->header('Content-Type', 'text/plain');
|
||||
}
|
||||
|
||||
// 2. Получение новой записи на стене (новости)
|
||||
if ($data['type'] === 'wall_post_new') {
|
||||
$post = $data['object']; // Здесь вся информация о посте
|
||||
|
||||
// Временно запишем в лог (storage/logs/laravel.log), чтобы увидеть структуру
|
||||
Log::info('Новый пост от VK:', $post);
|
||||
|
||||
// TODO: Здесь будет код сохранения $post в вашу базу данных
|
||||
|
||||
// VK требует всегда возвращать строку "ok" на любые события
|
||||
return response('ok', 200)
|
||||
->header('Content-Type', 'text/plain');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Library\VK\Entity;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
class VkPost
|
||||
{
|
||||
private int $id;
|
||||
private bool $post = true;
|
||||
private string $text;
|
||||
private int $author_id;
|
||||
private int $owner_id;
|
||||
private array $attachments = [];
|
||||
private Carbon $date;
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'post' => (int) $this->post,
|
||||
'text' => $this->text,
|
||||
'author_id' => $this->author_id,
|
||||
'owner_id' => $this->owner_id,
|
||||
'date' => $this->getDate()->toIso8601String(),
|
||||
'attachments' => $this->attachments,
|
||||
];
|
||||
}
|
||||
|
||||
public function isEmpty(): bool
|
||||
{
|
||||
return empty($this->text);
|
||||
}
|
||||
|
||||
public function isPost(): bool
|
||||
{
|
||||
return $this->post;
|
||||
}
|
||||
|
||||
public function isRepost(): bool
|
||||
{
|
||||
return ! $this->post;
|
||||
}
|
||||
|
||||
public function setIsPost(): void
|
||||
{
|
||||
$this->post = true;
|
||||
}
|
||||
|
||||
public function setIsRepost(): void
|
||||
{
|
||||
$this->post = false;
|
||||
}
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getText(): string
|
||||
{
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
public function getAuthorId(): int
|
||||
{
|
||||
return $this->author_id;
|
||||
}
|
||||
|
||||
public function getDate(): Carbon
|
||||
{
|
||||
return $this->date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOwnerId(): int
|
||||
{
|
||||
return $this->owner_id;
|
||||
}
|
||||
|
||||
public function setId(int $id): void
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function setText(string $text): void
|
||||
{
|
||||
$this->text = $text;
|
||||
}
|
||||
|
||||
public function setAuthorId(int $author_id): void
|
||||
{
|
||||
$this->author_id = $author_id;
|
||||
}
|
||||
|
||||
public function setDate(string|int $date): void
|
||||
{
|
||||
$this->date = Carbon::parse($date);
|
||||
}
|
||||
|
||||
public function setOwnerId(int $owner_id): void
|
||||
{
|
||||
$this->owner_id = $owner_id;
|
||||
}
|
||||
|
||||
public function setAttachments(array $attachments = []): void
|
||||
{
|
||||
$this->attachments = $attachments;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Library\VK\Mapper;
|
||||
|
||||
class AttachmentMapper
|
||||
{
|
||||
public function map(array $attachments = []): array
|
||||
{
|
||||
$photos = [];
|
||||
foreach ($attachments as $attachment) {
|
||||
if( ($attachment['type'] === 'photo') && $attachment['photo']['sizes'] ) {
|
||||
$photos[] = end($attachment['photo']['sizes'])['url'];
|
||||
}
|
||||
}
|
||||
|
||||
return $photos;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Library\VK\Mapper;
|
||||
|
||||
use App\Library\VK\Entity\VkPost;
|
||||
use App\Library\VK\Mapper\Strategy\Interfaces\MappingStrategyInterface;
|
||||
use App\Library\VK\Mapper\Strategy\MappingStrategyFactory;
|
||||
|
||||
class PostMapper
|
||||
{
|
||||
public function __construct(
|
||||
private MappingStrategyFactory $mappingStrategyFactory,
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
public function map(array $item): VkPost
|
||||
{
|
||||
$isRepost = isset($item['copy_history']);
|
||||
|
||||
/** @var MappingStrategyInterface $strategy */
|
||||
$strategy = $this->mappingStrategyFactory->getStrategy($isRepost);
|
||||
|
||||
return $strategy->map($item);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Library\VK\Mapper\Strategy\Interfaces;
|
||||
|
||||
use App\Library\VK\Entity\VkPost;
|
||||
|
||||
interface MappingStrategyInterface
|
||||
{
|
||||
public function map(array $item): VkPost;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Library\VK\Mapper\Strategy;
|
||||
|
||||
use App\Library\VK\Mapper\AttachmentMapper;
|
||||
use App\Library\VK\Mapper\Strategy\Interfaces\MappingStrategyInterface;
|
||||
|
||||
class MappingStrategyFactory
|
||||
{
|
||||
public function __construct(private AttachmentMapper $attachmentMapper) {}
|
||||
|
||||
public function getStrategy(bool $isRepost): MappingStrategyInterface
|
||||
{
|
||||
return $isRepost
|
||||
? new RepostStrategy($this->attachmentMapper)
|
||||
: new SimplePostStrategy($this->attachmentMapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Library\VK\Mapper\Strategy;
|
||||
|
||||
use App\Library\VK\Entity\VkPost;
|
||||
use App\Library\VK\Mapper\AttachmentMapper;
|
||||
use App\Library\VK\Mapper\Strategy\Interfaces\MappingStrategyInterface;
|
||||
|
||||
class RepostStrategy implements MappingStrategyInterface
|
||||
{
|
||||
public function __construct(private AttachmentMapper $attachmentMapper) {}
|
||||
|
||||
public function map(array $item): VkPost
|
||||
{
|
||||
$post = new VkPost();
|
||||
$post->setId($item['id']);
|
||||
$post->setOwnerId($item['owner_id']);
|
||||
$post->setAuthorId($item['from_id']);
|
||||
$post->setDate($item['date']);
|
||||
$post->setIsRepost();
|
||||
$post->setText($item['text'] ?? '');
|
||||
|
||||
// Переключаемся на оригинал для контента
|
||||
$original = $this->getOriginalPost($item);
|
||||
|
||||
$post->setText($original['text'] ?? '');
|
||||
|
||||
// Вложения берем именно из оригинала
|
||||
if (! empty($original['attachments'])) {
|
||||
$attachments = $this->attachmentMapper->map($original['attachments']);
|
||||
$post->setAttachments($attachments);
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
private function getOriginalPost(array $item): array
|
||||
{
|
||||
$copy_history_length = count($item['copy_history']);
|
||||
|
||||
if($copy_history_length > 0) {
|
||||
return end($item['copy_history']);
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Library\VK\Mapper\Strategy;
|
||||
|
||||
use App\Library\VK\Entity\VkPost;
|
||||
use App\Library\VK\Mapper\AttachmentMapper;
|
||||
use App\Library\VK\Mapper\Strategy\Interfaces\MappingStrategyInterface;
|
||||
|
||||
class SimplePostStrategy implements MappingStrategyInterface
|
||||
{
|
||||
public function __construct(private AttachmentMapper $attachmentMapper) {}
|
||||
|
||||
public function map(array $item): VkPost
|
||||
{
|
||||
$post = new VkPost();
|
||||
$post->setId($item['id']);
|
||||
$post->setOwnerId($item['owner_id']);
|
||||
$post->setAuthorId($item['from_id']);
|
||||
$post->setDate($item['date']);
|
||||
$post->setIsPost();
|
||||
$post->setText($item['text'] ?? '');
|
||||
|
||||
if (! empty($item['attachments'])) {
|
||||
$attachments = $this->attachmentMapper->map($item['attachments']);
|
||||
$post->setAttachments($attachments);
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Library\VK\Resources;
|
||||
|
||||
use App\Library\VK\VkApiClient;
|
||||
|
||||
class WallResource
|
||||
{
|
||||
public function __construct(private VkApiClient $api) {}
|
||||
|
||||
public function get(string $domain, int $count = 50, int $offset = 0): array
|
||||
{
|
||||
$result = $this->api->call('wall.get', [
|
||||
'domain' => $domain,
|
||||
'offset' => $offset,
|
||||
'count' => $count,
|
||||
'copy_history_depth' => 10
|
||||
]);
|
||||
|
||||
return $result['response'] ?? [ 'count' => 0, 'items' => [] ];
|
||||
}
|
||||
|
||||
// id = '-93243530_2113'
|
||||
public function getById(string $id): array
|
||||
{
|
||||
$result = $this->api->call('wall.getById',
|
||||
[
|
||||
'posts' => [ $id ],
|
||||
'copy_history_depth' => 10
|
||||
]);
|
||||
|
||||
return $result['response'] ?? [ 'items' => [] ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Library\VK\Service;
|
||||
|
||||
use App\Library\VK\Mapper\PostMapper;
|
||||
use App\Library\VK\Resources\WallResource;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class VkPostImportService
|
||||
{
|
||||
public function __construct(
|
||||
private WallResource $resource,
|
||||
private PostMapper $mapper
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
//$result = $this->resource->get('ledstarband', 1, 100);
|
||||
|
||||
if (empty ($result['items']) ) {
|
||||
Log::info('Post import failed: no items found');
|
||||
}
|
||||
|
||||
# echo "\nFound items: ".$result['count']."\n";
|
||||
// foreach ($result['items'] as $item) {
|
||||
// $post = $this->mapper->map($item);
|
||||
// if(! $post->isEmpty()) {
|
||||
// # print_r($post->toArray());
|
||||
// }
|
||||
// }
|
||||
|
||||
$res = $this->resource->getById('-93243530_2113');
|
||||
foreach ($res as $item) {
|
||||
$post = $this->mapper->map($item);
|
||||
if(! $post->isEmpty()) {
|
||||
print_r($post->toArray());
|
||||
}
|
||||
}
|
||||
|
||||
# print_r($res);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Library\VK;
|
||||
|
||||
use Exception;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
|
||||
final class VkApiClient
|
||||
{
|
||||
public function __construct(
|
||||
protected ClientInterface $http,
|
||||
protected string $token,
|
||||
protected string $url,
|
||||
protected string $version = '5.131'
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function call(
|
||||
string $method,
|
||||
array $params = []
|
||||
): array {
|
||||
$response = $this->http->request('POST', "{$this->url}/{$method}", [
|
||||
'form_params' => array_merge($params, [
|
||||
'access_token' => $this->token,
|
||||
'v' => $this->version,
|
||||
]),
|
||||
]);
|
||||
|
||||
if (isset($result['error'])) {
|
||||
throw new Exception("VK API Error: " . $result['error']['error_msg']);
|
||||
}
|
||||
|
||||
return json_decode($response->getBody()->getContents(), true);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Pagination\Paginator;
|
||||
use App\Library\VK\VkApiClient;
|
||||
use GuzzleHttp\Client as GuzzleHttpClient;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -12,7 +14,14 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
//
|
||||
$this->app->singleton(VkApiClient::class, function ($app) {
|
||||
return new VkApiClient(
|
||||
new GuzzleHttpClient(), // Создаем экземпляр Guzzle
|
||||
config('services.vk.token'), // Берем из config/services.php
|
||||
config('services.vk.url'), // Добавляем URL api
|
||||
config('services.vk.version'), // Берем из config/services.php
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user