Merge pull request #1 from F4ilji/add_news_module

add_vk_module
This commit is contained in:
F4ilji
2025-06-18 20:37:55 +05:00
committed by GitHub
18 changed files with 1432 additions and 62 deletions
Vendored
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
@@ -9,6 +9,7 @@ use App\Services\Filament\Domain\Posts\PostDataProcessor;
use App\Services\Filament\Domain\Posts\PostNotificationService;
use App\Services\Filament\Domain\Posts\PostSliderService;
use App\Services\Filament\Domain\Posts\VkPostPublisher;
use App\Services\Filament\Domain\Posts\TgPostPublisher;
use App\Services\Filament\Traits\SeoGenerate;
use Filament\Resources\Pages\CreateRecord;
@@ -48,6 +49,7 @@ class CreatePost extends CreateRecord
$this->createSeo($this->record);
$this->sendNotifications();
$this->publishToVk();
$this->publishToTg();
}
protected function handleSlides(): void
@@ -74,6 +76,11 @@ class CreatePost extends CreateRecord
(new VkPostPublisher())->publish($this->publicationAgreements, $this->record);
}
protected function publishToTg(): void
{
(new TgPostPublisher())->publish($this->publicationAgreements, $this->record);
}
+318
View File
@@ -0,0 +1,318 @@
<?php
namespace App\Jobs;
use App\Services\VK\Album\VkAlbumService;
use App\Services\VK\VkAuthService;
use App\Services\VK\VkService;
use App\Services\VK\Wall\VkWallService;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use VK\Client\VKApiClient;
class CreateVkPostJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $post_id;
protected $title;
protected $message;
protected $images;
protected $videos;
protected $documents;
protected $publish_date;
protected $public_id;
public function __construct(
int $post_id, string $title, string $message, array $images = [], array $videos = [], array $documents = [], ?int $publish_date = null
)
{
$this->post_id = $post_id;
$this->title = $title;
$this->message = $message;
$this->images = $images;
$this->videos = $videos;
$this->documents = $documents;
$this->publish_date = $publish_date;
$this->public_id = env('PUBLIC_ID');
}
public function handle()
{
$vk = new VKApiClient();
$wallService = new VkWallService($vk);
$from_group = 1;
$doc_attachments = !empty($this->documents) ? $this->prepareDocuments($this->documents) : '';
$doc_list = $doc_attachments ? explode(',', $doc_attachments) : [];
$doc_count = count($doc_list);
if ($doc_count >= 10) {
$selected_attachments = array_slice($doc_list, 0, 10);
$image_list = [];
} else {
$video_attachments = !empty($this->videos) ? $this->prepareVideos($this->videos) : '';
$video_list = $video_attachments ? explode(',', $video_attachments) : [];
$available_slots = 10 - $doc_count;
$attached_videos = array_slice($video_list, 0, min(count($video_list), $available_slots));
$remaining_slots = $available_slots - count($attached_videos);
if ($remaining_slots > 0 && !empty($this->images)) {
// Подготовка только тех изображений, которые поместятся
$images_to_attach = array_slice($this->images, 0, $remaining_slots);
$image_attachments = $this->prepareWallPhotos($images_to_attach);
$image_list = $image_attachments ? explode(',', $image_attachments) : [];
} else {
$image_list = [];
}
// Собираем все вложения с учетом приоритетов
$selected_attachments = array_merge($doc_list, $attached_videos, $image_list);
}
// Проверяем, все ли изображения прикреплены
if (count($this->images) > count($image_list)) {
// Если не все изображения вошли, создаем альбом
$album = $this->createAlbum($this->title, $this->images);
if (isset($album['id'])) {
$albumLink = "https://vk.com/album-{$this->public_id}_{$album['id']}";
$this->message .= "\n\n[{$albumLink}|Ссылка на все фотографии]";
} else {
Log::error('Не удалось создать альбом');
}
}
$attachmentString = implode(',', $selected_attachments);
$vk_post = $wallService->createPost($this->message, $from_group, $attachmentString, $this->publish_date);
DB::table('posts_vk_posts')->insert(
[
'post_id' => $this->post_id,
'vk_post_id' => $vk_post['post_id'],
'unchange_time_after' => Carbon::now()->addWeek(),
]
);
}
private function prepareWallPhotos(array $images): string
{
$baseUrl = config('app.url');
try {
$imagePaths = array_map(function($img) use ($baseUrl) {
return $baseUrl . $img;
}, $images);
$photos = $this->uploadWallPhotos($imagePaths, $this->public_id);
return implode(',', array_map(function($photo) {
return "photo{$photo['owner_id']}_{$photo['id']}";
}, $photos));
} catch (\Exception $e) {
Log::error("Ошибка при подготовке фотографий: " . $e->getMessage());
return '';
}
}
private function prepareVideos(array $videos): string
{
$baseUrl = config('app.url');
$videoPaths = array_map(function($vid) use ($baseUrl) {
return $baseUrl . $vid;
}, $videos);
$uploadedVideos = $this->uploadVideos($videoPaths, $this->public_id);
return implode(',', $uploadedVideos);
}
private function prepareDocuments(array $documents): string
{
$baseUrl = config('app.url');
try {
$documentPaths = array_map(function($doc) use ($baseUrl) {
return $baseUrl . $doc;
}, $documents);
Log::info(json_encode($documentPaths));
$uploadedDocs = $this->uploadDocuments($documentPaths, $this->public_id);
return implode(',', $uploadedDocs);
} catch (\Exception $e) {
Log::error("Ошибка при подготовке документов: " . $e->getMessage());
return '';
}
}
private function uploadWallPhotos(array $imagePaths, ?int $groupId = null): array
{
$uploadedPhotos = [];
foreach ($imagePaths as $imagePath) {
try {
$uploadServerResponse = Http::get('https://api.vk.com/method/photos.getWallUploadServer', [
'group_id' => $groupId,
'access_token' => (new VkAuthService())->getToken()->access_token,
'v' => '5.131',
]);
$uploadServerData = $uploadServerResponse->json();
if (!isset($uploadServerData['response']['upload_url'])) {
throw new \Exception('Не удалось получить сервер для загрузки: ' . $imagePath);
}
$uploadUrl = $uploadServerData['response']['upload_url'];
$uploadResponse = Http::attach(
'photo',
file_get_contents($imagePath),
basename($imagePath)
)->post($uploadUrl);
$uploadData = $uploadResponse->json();
if (!isset($uploadData['photo']) || !isset($uploadData['server']) || !isset($uploadData['hash'])) {
throw new \Exception('Не удалось загрузить фотографию: ' . $imagePath);
}
$saveResponse = Http::get('https://api.vk.com/method/photos.saveWallPhoto', [
'group_id' => $groupId,
'photo' => $uploadData['photo'],
'server' => $uploadData['server'],
'hash' => $uploadData['hash'],
'access_token' => (new VkAuthService())->getToken()->access_token,
'v' => '5.131',
]);
$saveData = $saveResponse->json();
if (!isset($saveData['response'][0])) {
throw new \Exception('Не удалось сохранить фотографию: ' . $imagePath);
}
$uploadedPhotos[] = $saveData['response'][0];
Log::info("Фотография загружена. ID: " . $saveData['response'][0]['id']);
} catch (\Exception $e) {
Log::error("Ошибка при загрузке {$imagePath}: " . $e->getMessage());
}
}
return $uploadedPhotos;
}
private function uploadVideos(array $videoPaths, ?int $groupId = null): array
{
$uploadedVideos = [];
foreach ($videoPaths as $videoPath) {
try {
$saveResponse = Http::timeout(360)->get('https://api.vk.com/method/video.save', [
'group_id' => $groupId,
'access_token' => (new VkAuthService())->getToken()->access_token,
'v' => '5.131',
]);
$saveData = $saveResponse->json();
if (!isset($saveData['response']['upload_url'])) {
throw new \Exception('Не удалось получить сервер для загрузки видео: ' . $videoPath);
}
$uploadUrl = $saveData['response']['upload_url'];
$uploadResponse = Http::timeout(360)->attach(
'video_file',
file_get_contents($videoPath),
basename($videoPath)
)->post($uploadUrl);
$uploadData = $uploadResponse->json();
if (!isset($uploadData['video_id']) || !isset($uploadData['owner_id'])) {
throw new \Exception('Не удалось загрузить видео: ' . $videoPath);
}
$attachment = "video{$uploadData['owner_id']}_{$uploadData['video_id']}";
$uploadedVideos[] = $attachment;
} catch (\Exception $e) {
Log::error("Ошибка при загрузке видео {$videoPath}: " . $e->getMessage());
}
}
return $uploadedVideos;
}
private function uploadDocuments(array $documentPaths, ?int $groupId = null): array
{
$uploadedDocs = [];
foreach ($documentPaths as $docPath) {
try {
// Получение сервера для загрузки документов на стену группы
$uploadServerResponse = Http::get('https://api.vk.com/method/docs.getWallUploadServer', [
'group_id' => $groupId,
'access_token' => (new VkAuthService())->getToken()->access_token,
'v' => '5.131',
]);
$uploadServerData = $uploadServerResponse->json();
Log::info($uploadServerData);
if (!isset($uploadServerData['response']['upload_url'])) {
throw new \Exception('Не удалось получить сервер для загрузки документа: ' . $docPath);
}
$uploadUrl = $uploadServerData['response']['upload_url'];
// Загрузка документа на сервер
$uploadResponse = Http::attach(
'file',
file_get_contents($docPath),
basename($docPath)
)->post($uploadUrl);
$uploadData = $uploadResponse->json();
if (!isset($uploadData['file'])) {
throw new \Exception('Не удалось загрузить документ: ' . $docPath);
}
// Сохранение документа
$saveResponse = Http::get('https://api.vk.com/method/docs.save', [
'file' => $uploadData['file'],
'access_token' => (new VkAuthService())->getToken()->access_token,
'v' => '5.131',
]);
$saveData = $saveResponse->json();
// Проверка наличия данных о документе
if (!isset($saveData['response']['doc'])) {
throw new \Exception('Не удалось сохранить документ: ' . $docPath);
}
// Получение данных о документе
$doc = $saveData['response']['doc'];
$attachment = "doc{$doc['owner_id']}_{$doc['id']}";
$uploadedDocs[] = $attachment;
} catch (\Exception $e) {
Log::error("Ошибка при загрузке документа {$docPath}: " . $e->getMessage());
}
}
return $uploadedDocs;
}
public function createAlbum(string $title, $images)
{
$vk = new VKApiClient();
$album = (new VkAlbumService($vk))->createAlbum($title);
$uploadServer = (new VkAlbumService($vk))->getServerForUploadImages($album['id'], env('PUBLIC_ID'));
foreach (array_chunk($images, 4) as $images_slice) {
$images_data = (new VkAlbumService($vk))->uploadImagesToUploadServer($uploadServer['upload_url'], $images_slice);
(new VkAlbumService($vk))->saveImagesToUploadServer(
$images_data['aid'],
$images_data['server'],
$images_data['photos_list'],
$images_data['hash']
);
}
return $album;
}
}
+340
View File
@@ -0,0 +1,340 @@
<?php
namespace App\Jobs;
use App\Services\VK\Album\VkAlbumService;
use App\Services\VK\VkAuthService;
use App\Services\VK\VkService;
use App\Services\VK\Wall\VkWallService;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use VK\Client\VKApiClient;
class UpdateVkPostJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $post_id;
protected $title;
protected $message;
protected $images;
protected $videos;
protected $documents;
protected $publish_date;
protected $public_id;
public function __construct(
int $post_id, string $title, string $message, array $images = [], array $videos = [], array $documents = [], ?int $publish_date = null
)
{
$this->post_id = $post_id;
$this->title = $title;
$this->message = $message;
$this->images = $images;
$this->videos = $videos;
$this->documents = $documents;
$this->publish_date = $publish_date;
$this->public_id = env('PUBLIC_ID');
}
public function handle()
{
$vk = new VKApiClient();
$wallService = new VkWallService($vk);
$albumService = new VkAlbumService($vk);
$postRelation = DB::table('posts_vk_posts')->select()->where('post_id', $this->post_id)->first();
$this->post_id = $postRelation->vk_post_id;
$vk_post = $wallService->getPostById($this->post_id);
// доделать
if ($vk_post['attachments']) {
Log::info($vk_post);
if ($this->getAlbumAttachment($vk_post['attachments'])) {
Log::info('вход в аттачментс вк');
$album = $this->getAlbumAttachment($vk_post['attachments']);
Log::info($album);
$albumService->deleteAlbum($album['album']['id'], $this->public_id);
}
}
$from_group = 1;
// Подготовка документов
$doc_attachments = !empty($this->documents) ? $this->prepareDocuments($this->documents) : '';
$doc_list = $doc_attachments ? explode(',', $doc_attachments) : [];
$doc_count = count($doc_list);
if ($doc_count >= 10) {
// Если документов 10 или больше, прикрепляем только первые 10
$selected_attachments = array_slice($doc_list, 0, 10);
$image_list = [];
} else {
// Подготовка видео
$video_attachments = !empty($this->videos) ? $this->prepareVideos($this->videos) : '';
$video_list = $video_attachments ? explode(',', $video_attachments) : [];
$available_slots = 10 - $doc_count;
$attached_videos = array_slice($video_list, 0, min(count($video_list), $available_slots));
$remaining_slots = $available_slots - count($attached_videos);
if ($remaining_slots > 0 && !empty($this->images)) {
// Подготовка только тех изображений, которые поместятся
$images_to_attach = array_slice($this->images, 0, $remaining_slots);
$image_attachments = $this->prepareWallPhotos($images_to_attach);
$image_list = $image_attachments ? explode(',', $image_attachments) : [];
} else {
$image_list = [];
}
// Собираем все вложения с учетом приоритетов
$selected_attachments = array_merge($doc_list, $attached_videos, $image_list);
}
// Проверяем, все ли изображения прикреплены
if (count($this->images) > count($image_list)) {
// Если не все изображения вошли, создаем альбом
$album = $this->createAlbum($this->title, $this->images);
if (isset($album['id'])) {
$albumLink = "https://vk.com/album-{$this->public_id}_{$album['id']}";
$this->message .= "\n\n[{$albumLink}|Ссылка на все фотографии]";
} else {
Log::error('Не удалось создать альбом');
}
}
$attachmentString = implode(',', $selected_attachments);
$wallService->updatePost($this->post_id, $this->message, $from_group, $attachmentString, $this->publish_date);
}
private function getAlbumAttachment(array $attachments)
{
$data = collect($attachments);
$filteredAttachment = $data->filter(function($attachment) {
return $attachment['type'] === 'album';
});
return (isset($filteredAttachment[0]) ? $filteredAttachment[0] : null);
}
private function prepareWallPhotos(array $images): string
{
$baseUrl = config('app.url');
try {
$imagePaths = array_map(function($img) use ($baseUrl) {
return $baseUrl . $img;
}, $images);
$photos = $this->uploadWallPhotos($imagePaths, $this->public_id);
return implode(',', array_map(function($photo) {
return "photo{$photo['owner_id']}_{$photo['id']}";
}, $photos));
} catch (\Exception $e) {
Log::error("Ошибка при подготовке фотографий: " . $e->getMessage());
return '';
}
}
private function prepareVideos(array $videos): string
{
$baseUrl = config('app.url');
$videoPaths = array_map(function($vid) use ($baseUrl) {
return $baseUrl . $vid;
}, $videos);
$uploadedVideos = $this->uploadVideos($videoPaths, $this->public_id);
return implode(',', $uploadedVideos);
}
private function prepareDocuments(array $documents): string
{
$baseUrl = config('app.url');
try {
$documentPaths = array_map(function($doc) use ($baseUrl) {
return $baseUrl . $doc;
}, $documents);
Log::info(json_encode($documentPaths));
$uploadedDocs = $this->uploadDocuments($documentPaths, $this->public_id);
return implode(',', $uploadedDocs);
} catch (\Exception $e) {
Log::error("Ошибка при подготовке документов: " . $e->getMessage());
return '';
}
}
private function uploadWallPhotos(array $imagePaths, ?int $groupId = null): array
{
$uploadedPhotos = [];
foreach ($imagePaths as $imagePath) {
try {
$uploadServerResponse = Http::get('https://api.vk.com/method/photos.getWallUploadServer', [
'group_id' => $groupId,
'access_token' => (new VkAuthService())->getToken()->access_token,
'v' => '5.131',
]);
$uploadServerData = $uploadServerResponse->json();
if (!isset($uploadServerData['response']['upload_url'])) {
throw new \Exception('Не удалось получить сервер для загрузки: ' . $imagePath);
}
$uploadUrl = $uploadServerData['response']['upload_url'];
$uploadResponse = Http::attach(
'photo',
file_get_contents($imagePath),
basename($imagePath)
)->post($uploadUrl);
$uploadData = $uploadResponse->json();
if (!isset($uploadData['photo']) || !isset($uploadData['server']) || !isset($uploadData['hash'])) {
throw new \Exception('Не удалось загрузить фотографию: ' . $imagePath);
}
$saveResponse = Http::get('https://api.vk.com/method/photos.saveWallPhoto', [
'group_id' => $groupId,
'photo' => $uploadData['photo'],
'server' => $uploadData['server'],
'hash' => $uploadData['hash'],
'access_token' => (new VkAuthService())->getToken()->access_token,
'v' => '5.131',
]);
$saveData = $saveResponse->json();
if (!isset($saveData['response'][0])) {
throw new \Exception('Не удалось сохранить фотографию: ' . $imagePath);
}
$uploadedPhotos[] = $saveData['response'][0];
Log::info("Фотография загружена. ID: " . $saveData['response'][0]['id']);
} catch (\Exception $e) {
Log::error("Ошибка при загрузке {$imagePath}: " . $e->getMessage());
}
}
return $uploadedPhotos;
}
private function uploadVideos(array $videoPaths, ?int $groupId = null): array
{
$uploadedVideos = [];
foreach ($videoPaths as $videoPath) {
try {
$saveResponse = Http::timeout(360)->get('https://api.vk.com/method/video.save', [
'group_id' => $groupId,
'access_token' => (new VkAuthService())->getToken()->access_token,
'v' => '5.131',
]);
$saveData = $saveResponse->json();
if (!isset($saveData['response']['upload_url'])) {
throw new \Exception('Не удалось получить сервер для загрузки видео: ' . $videoPath);
}
$uploadUrl = $saveData['response']['upload_url'];
$uploadResponse = Http::timeout(360)->attach(
'video_file',
file_get_contents($videoPath),
basename($videoPath)
)->post($uploadUrl);
$uploadData = $uploadResponse->json();
if (!isset($uploadData['video_id']) || !isset($uploadData['owner_id'])) {
throw new \Exception('Не удалось загрузить видео: ' . $videoPath);
}
$attachment = "video{$uploadData['owner_id']}_{$uploadData['video_id']}";
$uploadedVideos[] = $attachment;
} catch (\Exception $e) {
Log::error("Ошибка при загрузке видео {$videoPath}: " . $e->getMessage());
}
}
return $uploadedVideos;
}
private function uploadDocuments(array $documentPaths, ?int $groupId = null): array
{
$uploadedDocs = [];
foreach ($documentPaths as $docPath) {
try {
// Получение сервера для загрузки документов на стену группы
$uploadServerResponse = Http::get('https://api.vk.com/method/docs.getWallUploadServer', [
'group_id' => $groupId,
'access_token' => (new VkAuthService())->getToken()->access_token,
'v' => '5.131',
]);
$uploadServerData = $uploadServerResponse->json();
Log::info($uploadServerData);
if (!isset($uploadServerData['response']['upload_url'])) {
throw new \Exception('Не удалось получить сервер для загрузки документа: ' . $docPath);
}
$uploadUrl = $uploadServerData['response']['upload_url'];
// Загрузка документа на сервер
$uploadResponse = Http::attach(
'file',
file_get_contents($docPath),
basename($docPath)
)->post($uploadUrl);
$uploadData = $uploadResponse->json();
if (!isset($uploadData['file'])) {
throw new \Exception('Не удалось загрузить документ: ' . $docPath);
}
// Сохранение документа
$saveResponse = Http::get('https://api.vk.com/method/docs.save', [
'file' => $uploadData['file'],
'access_token' => (new VkAuthService())->getToken()->access_token,
'v' => '5.131',
]);
$saveData = $saveResponse->json();
// Проверка наличия данных о документе
if (!isset($saveData['response']['doc'])) {
throw new \Exception('Не удалось сохранить документ: ' . $docPath);
}
// Получение данных о документе
$doc = $saveData['response']['doc'];
$attachment = "doc{$doc['owner_id']}_{$doc['id']}";
$uploadedDocs[] = $attachment;
} catch (\Exception $e) {
Log::error("Ошибка при загрузке документа {$docPath}: " . $e->getMessage());
}
}
return $uploadedDocs;
}
public function createAlbum(string $title, $images)
{
$vk = new VKApiClient();
$album = (new VkAlbumService($vk))->createAlbum($title);
$uploadServer = (new VkAlbumService($vk))->getServerForUploadImages($album['id'], env('PUBLIC_ID'));
foreach (array_chunk($images, 4) as $images_slice) {
$images_data = (new VkAlbumService($vk))->uploadImagesToUploadServer($uploadServer['upload_url'], $images_slice);
(new VkAlbumService($vk))->saveImagesToUploadServer(
$images_data['aid'],
$images_data['server'],
$images_data['photos_list'],
$images_data['hash']
);
}
return $album;
}
}
+2
View File
@@ -3,6 +3,7 @@
namespace App\Observers;
use App\Containers\Article\Models\Post;
use App\Services\VK\VkService;
use App\Services\App\Cache\PostCacheService;
class PostObserver
@@ -36,6 +37,7 @@ class PostObserver
public function deleted(Post $post)
{
$this->postCacheService->clearAllCacheByModel();
app(VkService::class)->deletePost($post->id);
}
/**
@@ -0,0 +1,228 @@
<?php
namespace App\Services\Filament\Domain\Posts;
use App\Enums\PostStatus;
use App\Jobs\CreateTgPost;
use App\Jobs\CreateTgPostJob;
use App\Jobs\UpdateTgPost;
use App\Models\Post;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
class TgPostPublisher
{
/**
* Публикует пост в социальных сетях.
*
* @param array $settings
* @param Post $post
* @return void
*/
public function publish(array $settings, Post $post): void
{
if ($post->status === PostStatus::PUBLISHED) {
if ($settings['telegram']) {
$imagesFromPost = $post->images;
$imagesFromContent = $this->extractImagesFromContent($post->content);
$allImages = array_merge($imagesFromPost, $imagesFromContent);
$imageLinks = $this->generateImagesForTg($allImages);
$text = $this->generateContentForTg($post, $allImages);
$videos = $this->extractVideosFromContent($post->content);
$documents = $this->extractFilesFromContent($post->content);
$publishDate = $post->publish_at > now() ? $post->publish_at->timestamp : null;
dispatch(new CreateTgPostJob($post->id, $post->title, $text, $imageLinks, $videos, $documents, $publishDate));
}
}
}
public function update(array $settings, Post $post): void
{
Log::info(json_encode($settings));
if ($post->status === PostStatus::PUBLISHED) {
if ($settings['telegram']) {
$text = $this->generateContentForTg($post->title, $post->content, $post->slug, $post->images);
$images = $this->generateImagesForTg($post->images);
$publishDate = $post->publish_at > now() ? $post->publish_at->timestamp : null;
dispatch(new UpdateTgPost($text, $images, $post->id, $publishDate));
}
}
}
private function generateContentForTg($post, $images): string
{
$message = '';
$message .= "*{$post->title}*\n\n";
if (is_array($post->content)) {
$message .= $this->parseContentBlocks($post->content);
} elseif (is_string($post->content)) {
$contentBlocks = json_decode($post->content, true);
if (is_array($contentBlocks)) {
$message .= $this->parseContentBlocks($contentBlocks);
} else {
$message .= $this->convertToMarkdown($post->content);
}
} else {
$message .= $this->convertToMarkdown((string) $post->content);
}
if (isset($post->authors) && is_array($post->authors) && !empty($post->authors)) {
$authors = array_map(function($author) {
return json_decode('"' . $author . '"');
}, $post->authors);
$authorLabel = (count($authors) === 1) ? "Автор:" : "Авторы:";
$message .= "\n\n$authorLabel " . implode(', ', $authors);
}
if ($post->slug) {
$url = config('app.url') . "/posts/{$post->slug}";
$linkText = "\n\n[Читать полностью]($url)";
$linkLength = mb_strlen($linkText);
$maxLength = $images ? 1024 : 4096;
if (mb_strlen($message) > $maxLength - $linkLength) {
$truncated = mb_substr($message, 0, $maxLength - $linkLength);
$lastSpace = mb_strrpos($truncated, ' ');
if ($lastSpace !== false) {
$truncated = mb_substr($truncated, 0, $lastSpace);
}
$message = $truncated . '...';
$message .= $linkText;
} elseif (count($images) > 10) {
$message .= $linkText;
}
}
return trim($message);
}
/**
* Генерирует ссылки на изображения для Телеграмм.
*
* @param array $images
* @return array
*/
private function generateImagesForTg(array $images): array
{
return array_map(function ($file) {
return Storage::url($file); // Генерируем полный URL для изображения
}, $images);
}
private function parseContentBlocks(array $blocks): string
{
$text = '';
foreach ($blocks as $block) {
switch ($block['type'] ?? '') {
case 'heading':
if (isset($block['data']['content'])) {
$level = $block['data']['level'] ?? 1; // Уровень заголовка, по умолчанию 1
$content = $this->convertToMarkdown($block['data']['content']);
$text .= str_repeat('#', $level) . ' ' . $content . "\n\n";
}
break;
case 'paragraph':
if (isset($block['data']['content'])) {
$text .= $this->convertToMarkdown($block['data']['content']) . "\n\n";
}
break;
case 'list':
if (isset($block['data']['items']) && is_array($block['data']['items'])) {
foreach ($block['data']['items'] as $item) {
$text .= "- " . $item . "\n";
}
$text .= "\n";
}
break;
}
}
return $text;
}
private function extractImagesFromContent(array $blocks): array
{
$images = [];
foreach ($blocks as $block) {
if ($block['type'] === 'image' && isset($block['data']['url']) && is_array($block['data']['url'])) {
foreach ($block['data']['url'] as $imagePath) {
$images[] = $imagePath;
}
}
}
return $images;
}
private function extractVideosFromContent(array $blocks): array
{
$videos = [];
foreach ($blocks as $block) {
if ($block['type'] === 'video' && isset($block['data']['path'])) {
$path = Storage::url($block['data']['path']);
$path = stripslashes($path);
$videos[] = $path;
}
}
return $videos;
}
private function extractFilesFromContent(array $blocks): array
{
$files = [];
foreach ($blocks as $block) {
if ($block['type'] === 'files' && isset($block['data']['file']) && is_array($block['data']['file'])) {
foreach ($block['data']['file'] as $file) {
if (isset($file['path'])) {
$files[] = Storage::url($file['path']);
}
}
}
}
return $files;
}
private function convertToMarkdown(string $text): string
{
// Декодируем HTML-сущности (например, &nbsp; становится \u00A0)
$text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
// Заменяем неразрывные пробелы на обычные
$text = str_replace("\xc2\xa0", " ", $text); // \xc2\xa0 — это \u00A0 в UTF-8
// Обрабатываем цитаты
$text = preg_replace_callback('/<blockquote>(.*?)<\/blockquote>/s', function($match) {
$content = $match[1];
// Удаляем <p> и заменяем </p> на \n
$content = preg_replace('/<p>(.*?)<\/p>/', "$1\n", $content);
// Разбиваем на строки и убираем пустые
$lines = array_filter(explode("\n", $content), function($line) {
return trim($line) !== '';
});
// Добавляем > перед каждой непустой строкой
$quoted = array_map(function($line) {
return '> ' . trim($line);
}, $lines);
return implode("\n", $quoted) . "\n";
}, $text);
// Удаляем <p> и заменяем </p> на \n\n для параграфов
$text = preg_replace('/<p>/', '', $text);
$text = preg_replace('/<\/p>/', "\n", $text);
// Обрабатываем жирный текст и курсив, убирая лишние пробелы
$text = preg_replace_callback('/<strong>(.*?)<\/strong>/', function($match) {
return '*' . trim($match[1]) . '*';
}, $text);
$text = preg_replace_callback('/<em>(.*?)<\/em>/', function($match) {
return '_' . trim($match[1]) . '_';
}, $text);
// Удаляем оставшиеся HTML-теги
$text = strip_tags($text);
// Убираем лишние пробелы и пустые строки в начале и конце
return trim($text);
}
}
@@ -7,6 +7,9 @@ use App\Containers\Article\Models\Post;
use App\Jobs\CreateVkPost;
use App\Jobs\UpdateVkPost;
use Illuminate\Support\Facades\Storage;
use App\Jobs\CreateVkPostJob;
use App\Jobs\UpdateVkPostJob;
use Illuminate\Support\Facades\Log;
class VkPostPublisher
{
@@ -19,59 +22,187 @@ class VkPostPublisher
*/
public function publish(array $settings, Post $post): void
{
if ($post->status->value === PostStatus::PUBLISHED->value) {
if ($post->status === PostStatus::PUBLISHED) {
if ($settings['vk']) {
$text = $this->generateContentForVk($post->content);
$images = $this->generateImageLinksForVk($post->images);
$text = $this->generateContentForVk($post);
$imagesFromPost = $post->images;
$imagesFromContent = $this->extractImagesFromContent($post->content);
$allImages = array_merge($imagesFromPost, $imagesFromContent);
$imageLinks = $this->generateImageLinksForVk($allImages);
$videos = $this->extractVideosFromContent($post->content);
$documents = $this->extractFilesFromContent($post->content);
$publishDate = $post->publish_at > now() ? $post->publish_at->timestamp : null;
dispatch(new CreateVkPost($post->title, $text, $images, $post->id, $publishDate));
dispatch(new CreateVkPostJob(
$post->id,
$post->title,
$text,
$imageLinks,
$videos,
$documents,
$publishDate));
}
}
}
public function update(array $settings, Post $post): void
{
if ($post->status->value === PostStatus::PUBLISHED->value) {
if ($post->status === PostStatus::PUBLISHED) {
if ($settings['vk']) {
$text = $this->generateContentForVk($post);
$imagesFromPost = $post->images;
$imagesFromContent = $this->extractImagesFromContent($post->content);
$allImages = array_merge($imagesFromPost, $imagesFromContent);
$imageLinks = $this->generateImageLinksForVk($allImages);
$videos = $this->extractVideosFromContent($post->content);
$documents = $this->extractFilesFromContent($post->content);
$text = $this->generateContentForVk($post->content);
$images = $this->generateImageLinksForVk($post->images);
$publishDate = $post->publish_at > now() ? $post->publish_at->timestamp : null;
dispatch(new UpdateVkPost($post->title, $text, $images, $post->id, $publishDate));
dispatch(new UpdateVkPostJob(
$post->id,
$post->title,
$text,
$imageLinks,
$videos,
$documents,
$publishDate));
}
}
//
// if ($post->status === PostStatus::PUBLISHED) {
// if ($settings['vk']) {
// $text = $this->generateContentForVk($post->title, $post->content);
// $images = $this->generateImageLinksForVk($post->images);
// $publishDate = $post->publish_at > now() ? $post->publish_at->timestamp : null;
//
// dispatch(new UpdateVkPost($post->title, $text, $images, $post->id, $publishDate));
// }
// }
}
/**
* Генерирует текстовый контент для ВКонтакте.
*
* @param array $content
* @return string
*/
private function generateContentForVk(array $content): string
private function generateContentForVk($post): string
{
$message = '';
$message .= "Название: $post->title\n\n";
if (is_array($post->content)) {
$message .= $this->parseContentBlocks($post->content);
} elseif (is_string($post->content)) {
$contentBlocks = json_decode($post->content, true);
if (is_array($contentBlocks)) {
$message .= $this->parseContentBlocks($contentBlocks);
} else {
$message .= strip_tags($post->content);
}
}
if (isset($post->authors) && is_array($post->authors) && !empty($post->authors)) {
$authors = array_map(function($author) {
return json_decode('"' . $author . '"');
}, $post->authors);
$authorLabel = (count($authors) === 1) ? "Автор:" : "Авторы:";
$message .= "\n\n$authorLabel " . implode(', ', $authors);
}
$message = html_entity_decode($message);
// $maxLength = 16000;
// $reservedSpace = 200;
// $linkText = '';
// if ($post->slug) {
// $url = config('app.url') . "/posts/{$post->slug}";
// $linkText = "\n\n[{$url}|Читать полностью]";
// }
//
// $linkLength = mb_strlen($linkText);
//
// $maxMLength = $maxLength - $reservedSpace - $linkLength;
//
// if (mb_strlen($message) > $maxMLength) {
// $truncated = mb_substr($message, 0, $maxMLength);
// $lastSpace = mb_strrpos($truncated, ' ');
// if ($lastSpace !== false) {
// $truncated = mb_substr($truncated, 0, $lastSpace);
// }
// $message = $truncated . '...';
// }
//
// $message .= $linkText;
return $message;
}
private function parseContentBlocks(array $blocks): string
{
$text = '';
foreach ($content as $block) {
switch ($block['type']) {
case 'paragraph':
$text .= strip_tags($block['data']['content']) . "\n\n";
break;
foreach ($blocks as $block) {
switch ($block['type'] ?? '') {
case 'heading':
$text .= strip_tags($block['data']['content']) . "\n\n";
case 'paragraph':
if (isset($block['data']['content'])) {
$text .= strip_tags($block['data']['content']) . "\n\n";
}
break;
case 'list':
if (isset($block['data']['items']) && is_array($block['data']['items'])) {
foreach ($block['data']['items'] as $item) {
$text .= "- " . $item . "\n";
}
$text .= "\n";
}
break;
}
}
return trim($text);
}
/**
* Генерирует ссылки на изображения для ВКонтакте.
*
* @param array $images
* @return array
*/
private function extractImagesFromContent(array $blocks): array
{
$images = [];
foreach ($blocks as $block) {
if ($block['type'] === 'image' && isset($block['data']['url']) && is_array($block['data']['url'])) {
foreach ($block['data']['url'] as $imagePath) {
$images[] = $imagePath;
}
}
}
return $images;
}
private function extractVideosFromContent(array $blocks): array
{
$videos = [];
foreach ($blocks as $block) {
if ($block['type'] === 'video' && isset($block['data']['path'])) {
$path = Storage::url($block['data']['path']);
$path = stripslashes($path);
$videos[] = $path;
}
}
return $videos;
}
private function extractFilesFromContent(array $blocks): array
{
$files = [];
foreach ($blocks as $block) {
if ($block['type'] === 'files' && isset($block['data']['file']) && is_array($block['data']['file'])) {
foreach ($block['data']['file'] as $file) {
if (isset($file['path'])) {
$files[] = Storage::url($file['path']);
}
}
}
}
return $files;
}
private function generateImageLinksForVk(array $images): array
{
return array_map(function ($file) {
@@ -79,3 +210,4 @@ class VkPostPublisher
}, $images);
}
}
+9 -3
View File
@@ -36,6 +36,15 @@ class VkAlbumService
);
}
public function getServerForUploadImagesOnWall($group_id)
{
return $this->vk->photos()->getWallUploadServer(
$this->vkAuthService->getToken()->access_token,
array(
'group_id' => $group_id,
)
);
}
public function uploadImagesToUploadServer($uploadUrl, $images)
@@ -83,8 +92,6 @@ class VkAlbumService
// Обработка ответа
$responseData = json_decode($response, true);
// Удаление временных файлов
foreach ($localFiles as $localFile) {
unlink($localFile);
@@ -167,5 +174,4 @@ class VkAlbumService
];
}
}
}
+40 -17
View File
@@ -33,28 +33,51 @@ class VkAuthService
}
}
// public function redirectToProvider()
// {
// $state = bin2hex(random_bytes(16)); // Генерация случайной строки состояния
// session(['vk_state' => $state]); //
//
// $code_verifier = $this->generateCodeVerifier();
// $code_challenge = $this->generateCodeChallenge($code_verifier);
//
// session(['vk_code_verifier' => $code_verifier]);
//
//
// $url = 'https://id.vk.com/authorize?' . http_build_query([
// 'response_type' => 'code',
// 'client_id' => env('VK_APP_ID'),
// 'redirect_uri' => env('VK_REDIRECT_URI'),
// 'state' => $state,
// 'scope' => 'photos wall video docs',
// 'code_challenge' => $code_challenge,
// 'code_challenge_method' => 's256',
// ]);
//
// return redirect($url);
// }
public function redirectToProvider()
{
$state = bin2hex(random_bytes(16)); // Генерация случайной строки состояния
session(['vk_state' => $state]);
$state = bin2hex(random_bytes(16)); // Генерирует случайную строку состояния (state) для защиты от CSRF-атак.
session(['vk_state' => $state]); // Сохраняет строку состояния в сессии под ключом 'vk_state'.
$code_verifier = $this->generateCodeVerifier();
$code_challenge = $this->generateCodeChallenge($code_verifier);
$code_verifier = $this->generateCodeVerifier(); // Создает случайную строку code_verifier для протокола PKCE.
$code_challenge = $this->generateCodeChallenge($code_verifier); // Генерирует code_challenge на основе code_verifier (обычно хеш SHA-256).
session(['vk_code_verifier' => $code_verifier]);
session(['vk_code_verifier' => $code_verifier]); // Сохраняет code_verifier в сессии под ключом 'vk_code_verifier'.
$url = 'https://id.vk.com/authorize?' . http_build_query([
'response_type' => 'code',
'client_id' => env('VK_APP_ID'),
'redirect_uri' => env('VK_REDIRECT_URI'),
'state' => $state,
'scope' => 'photos wall', // Укажите необходимые права доступа
'code_challenge' => $code_challenge, // Добавьте код, если используете PKCE
'code_challenge_method' => 's256',
$url = 'https://id.vk.com/authorize?' . http_build_query([ // Формирует URL для перенаправления на страницу авторизации VK ID с параметрами:
'response_type' => 'code', // Указывает, что нужен код авторизации.
'client_id' => env('VK_APP_ID'), // ID приложения VK из переменных окружения.
'redirect_uri' => env('VK_REDIRECT_URI'), // URI для перенаправления после авторизации.
'state' => $state, // Передает строку состояния для проверки.
'scope' => 'photos wall video docs', // Запрашивает доступ к фото, стене, видео и документам.
'code_challenge' => $code_challenge, // Передает code_challenge для PKCE.
'code_challenge_method' => 's256', // Указывает метод генерации code_challenge (SHA-256).
]);
return redirect($url);
return redirect($url); // Перенаправляет пользователя на сформированный URL для авторизации.
}
public function handleProviderCallback(Request $request)
@@ -97,7 +120,7 @@ class VkAuthService
'client_id' => env('VK_APP_ID'),
'device_id' => $request->device_id,
'state' => $request->state,
'scope' => 'photos wall',
'scope' => 'photos wall video docs',
])->object();
}
@@ -109,7 +132,7 @@ class VkAuthService
'client_id' => env('VK_APP_ID'),
'device_id' => $device_id,
'state' => $state,
'scope' => 'photos wall',
'scope' => 'photos wall video docs',
]);
if ($response->failed()) {
+177 -6
View File
@@ -4,6 +4,10 @@ namespace App\Services\VK;
use App\Services\VK\Album\VkAlbumService;
use App\Services\VK\Wall\VkWallService;
use Exception;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use VK\Client\VKApiClient;
class VkService
@@ -16,6 +20,7 @@ class VkService
$this->wallService = new VkWallService($vk);
$this->albumService = new VkAlbumService($vk);
$this->public_id = env('PUBLIC_ID');
$this->vkAuthService = new VkAuthService();
}
public function getPosts(int $count = 10)
@@ -28,16 +33,50 @@ class VkService
return $this->wallService->getPostById($id);
}
public function createPost(string $title, string $message, array $images = [], int|null $publish_date = null)
// public function createPost(string $title, string $message, array $images = [], array $videos = [], int|null $publish_date = null)
// {
// $from_group = 1;
// $attachments = [];
//
// if (!empty($images)) {
// if (count($images) <= 10) {
// $attachments[] = $this->prepareWallPhotos($images);
// }
// else{
// $album = $this->createAlbum($title, $images);
// $attachments[] = $this->createAlbumAttachmentParam($album['id']);
// }
// }
//
// $attachmentString = implode(',', $attachments);
//
// return $this->wallService->createPost($message, $from_group, $attachmentString, $publish_date);
// }
public function createPost(string $title, string $message, array $images = [], array $videos = [], int|null $publish_date = null)
{
$from_group = 1;
$album_attachment = '';
if ($images !== []) {
$album = $this->createAlbum($title, $images);
$album_attachment = $this->createAlbumAttachmentParam($album['id']);
$attachments = [];
if (!empty($images)) {
if (count($images) <= 10) {
$attachments[] = $this->prepareWallPhotos($images);
} else {
$attachments[] = $this->prepareWallPhotos(array_slice($images, 0, 10));
$album = $this->createAlbum($title, $images);
if (isset($album['id'])) {
$albumLink = "https://vk.com/album-{$this->public_id}_{$album['id']}";
$message .= "\n[{$albumLink}|Ссылка на все фотографии]";
} else {
Log::error('Не удалось создать альбом');
}
}
}
return $this->wallService->createPost($message, $from_group, $album_attachment, $publish_date);
$attachmentString = implode(',', $attachments);
return $this->wallService->createPost($message, $from_group, $attachmentString, $publish_date);
}
public function updatePost(int $id, string $title, string $message, array $images = [], int|null $publish_date = null)
@@ -59,6 +98,13 @@ class VkService
return $this->wallService->updatePost($id, $message, $from_group, $album_attachment, $publish_date);
}
public function deletePost(int $post_id){
$postRelation = DB::table('posts_vk_posts')->select()->where('post_id', $post_id)->first();
$post_id = $postRelation->vk_post_id;
$vk_post = $this->getPostById($post_id);
$this->wallService->deletePost($vk_post['id']);
}
public function createAlbum(string $title, $images)
{
$album = $this->albumService->createAlbum($title);
@@ -89,4 +135,129 @@ class VkService
return (isset($filteredAttachment[0]) ? $filteredAttachment[0] : null);
}
private function prepareWallPhotos(array $images){
$baseUrl = config('app.url');
try {
$imagePaths = array_map(function($img) use ($baseUrl) {
return $baseUrl . $img;
}, $images);
$photos = $this->uploadWallPhotos($imagePaths, env('PUBLIC_ID'));
return implode(',', array_map(function($photo) {
return "photo{$photo['owner_id']}_{$photo['id']}";
}, $photos));
} catch (Exception $e) {
Log::error("Ошибка: " . $e->getMessage());
}
}
private function prepareVideos(array $videos)
{
$baseUrl = config('app.url');
$videoPaths = array_map(function($vid) use ($baseUrl) {
return $baseUrl . $vid;
}, $videos);
return $this->uploadVideos($videoPaths, env('PUBLIC_ID')); // Возвращает массив, например: ['video123_456', 'video789_012']
}
private function uploadVideos(array $videoPaths, ?int $groupId = null): array
{
$uploadedVideos = [];
foreach ($videoPaths as $videoPath) {
try {
// Шаг 1: Получение сервера для загрузки
$saveResponse = Http::get('https://api.vk.com/method/video.save', [
'group_id' => $groupId,
'access_token' => $this->vkAuthService->getToken()->access_token,
'v' => '5.131',
]);
$saveData = $saveResponse->json();
if (!isset($saveData['response']['upload_url'])) {
throw new Exception('Не удалось получить сервер для загрузки видео: ' . $videoPath);
}
$uploadUrl = $saveData['response']['upload_url'];
// Шаг 2: Загрузка видео на сервер
$uploadResponse = Http::attach(
'video_file',
file_get_contents($videoPath),
basename($videoPath)
)->post($uploadUrl);
$uploadData = $uploadResponse->json();
if (!isset($uploadData['video_id']) || !isset($uploadData['owner_id'])) {
throw new Exception('Не удалось загрузить видео: ' . $videoPath);
}
$attachment = "video{$uploadData['owner_id']}_{$uploadData['video_id']}";
$uploadedVideos[] = $attachment;
} catch (Exception $e) {
Log::error("Ошибка при загрузке видео {$videoPath}: " . $e->getMessage());
}
}
return $uploadedVideos;
}
private function uploadWallPhotos(array $imagePaths, ?int $groupId = null): array
{
$uploadedPhotos = [];
foreach ($imagePaths as $imagePath) {
try {
$uploadServerResponse = Http::get('https://api.vk.com/method/photos.getWallUploadServer', [
'group_id' => $groupId,
'access_token' => $this->vkAuthService->getToken()->access_token,
'v' => '5.131',
]);
$uploadServerData = $uploadServerResponse->json();
if (!isset($uploadServerData['response']['upload_url'])) {
throw new Exception('Не удалось получить сервер для загрузки для изображения: ' . $imagePath);
}
$uploadUrl = $uploadServerData['response']['upload_url'];
// Шаг 2: Загрузка фотографии на сервер
$uploadResponse = Http::attach(
'photo',
file_get_contents($imagePath),
basename($imagePath)
)->post($uploadUrl);
$uploadData = $uploadResponse->json();
if (!isset($uploadData['photo']) || !isset($uploadData['server']) || !isset($uploadData['hash'])) {
throw new Exception('Не удалось загрузить фотографию: ' . $imagePath);
}
// Шаг 3: Сохранение фотографии
$saveResponse = Http::get('https://api.vk.com/method/photos.saveWallPhoto', [
'group_id' => $groupId,
'photo' => $uploadData['photo'],
'server' => $uploadData['server'],
'hash' => $uploadData['hash'],
'access_token' => $this->vkAuthService->getToken()->access_token,
'v' => '5.131',
]);
$saveData = $saveResponse->json();
if (!isset($saveData['response'][0])) {
throw new Exception('Не удалось сохранить фотографию: ' . $imagePath);
}
// Добавляем данные о загруженной фотографии в массив
$uploadedPhotos[] = $saveData['response'][0];
Log::info("Фотография успешно загружена. ID: " . $saveData['response'][0]['id']);
} catch (Exception $e) {
// Логируем ошибку, но продолжаем загрузку остальных изображений
Log::error("Ошибка при загрузке изображения {$imagePath}: " . $e->getMessage());
}
}
return $uploadedPhotos; // Возвращаем массив с данными о загруженных фотографиях
}
}
+44 -9
View File
@@ -12,6 +12,7 @@ use VK\Client\VKApiClient;
class VkWallService
{
private VKApiClient $vk;
private VkAuthService $vkAuthService;
private string $wallToken;
private string $serviceToken;
private string $publicId;
@@ -24,7 +25,6 @@ class VkWallService
$this->publicId = env('PUBLIC_ID');
$this->publicDomain = env('PUBLIC_DOMAIN');
$this->vkAuthService = new VkAuthService();
}
public function getPosts(int $count)
@@ -38,22 +38,25 @@ class VkWallService
public function getPostById(int $id)
{
$post = $this->vk->wall()->getById($this->serviceToken, array(
'posts' => '-'. $this->publicId . '_' . $id,
));
return $post[0];
try {
$post = $this->vk->wall()->getById($this->vkAuthService->getToken()->access_token, array(
'posts' => '-'. $this->publicId . '_' . $id,
));
return $post[0];
} catch (\Exception $e) {
Log::error('Ошибка при попытке получения айди ' . $e->getMessage());
}
}
public function createPost(string $message, int $from_group, string $attachments = '', int|null $publish_date = null)
{
$token = $this->vkAuthService->getToken()->access_token;
$params = [
'owner_id' => '-' . $this->publicId,
'from_group' => $from_group,
'message' => $message,
'attachments' => $attachments,
'access_token' => $this->wallToken,
'access_token' => $token,
'publish_date' => $publish_date,
'v' => '5.131',
];
@@ -88,7 +91,6 @@ class VkWallService
];
}
try {
return $this->vk->wall()->edit(
$this->vkAuthService->getToken()->access_token,
@@ -108,6 +110,36 @@ class VkWallService
];
}
}
public function deletePost(int $post_id)
{
$token = $this->vkAuthService->getToken()->access_token;
$params = [
'owner_id' => '-' . $this->publicId,
'post_id' => $post_id,
'access_token' => $token,
'v' => '5.131',
];
try {
$response = Http::asForm()->post('https://api.vk.com/method/wall.delete', $params);
if ($response->successful() && isset($response['response']) && $response['response'] == 1) {
return [
'success' => true,
];
} else {
throw new \Exception('Ошибка API: ' . json_encode($response->json()));
}
} catch (\Exception $e) {
Log::error('Ошибка при удалении поста: ' . $e->getMessage());
return [
'success' => false,
'message' => 'Не удалось удалить пост: ' . $e->getMessage(),
];
}
}
public function generateAttachmentsParams(string $attachmentType, int $attachmentId)
{
$pubic_id = env('PUBLIC_ID');
@@ -117,6 +149,9 @@ class VkWallService
}
case 'doc': {
}
case 'photo': {
}
}
}
+1
View File
@@ -14,6 +14,7 @@
"filament/filament": "v3.2.127",
"filament/spatie-laravel-settings-plugin": "^3.2",
"filament/spatie-laravel-tags-plugin": "v3.2.113",
"defstudio/telegraph": "^1.59",
"guava/filament-icon-picker": "2.2.4",
"guzzlehttp/guzzle": "^7.8",
"imangazaliev/didom": "^2.0",
BIN
View File
Binary file not shown.
@@ -0,0 +1,23 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class () extends Migration {
public function up(): void
{
Schema::create('telegraph_bots', function (Blueprint $table) {
$table->id();
$table->string('token')->unique();
$table->string('name')->nullable();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('telegraph_bots');
}
};
@@ -0,0 +1,26 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class () extends Migration {
public function up(): void
{
Schema::create('telegraph_chats', function (Blueprint $table) {
$table->id();
$table->string('chat_id');
$table->string('name')->nullable();
$table->foreignId('telegraph_bot_id')->constrained('telegraph_bots')->cascadeOnDelete();
$table->timestamps();
$table->unique(['chat_id', 'telegraph_bot_id']);
});
}
public function down(): void
{
Schema::dropIfExists('telegraph_chats');
}
};
@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('posts_tg_posts', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('post_id'); // Поле post_id
$table->unsignedBigInteger('tg_post_id'); // Поле vk_post_id
$table->dateTime('unchange_time_after');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('posts_tg_posts');
}
};
@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('posts_tg_posts', function (Blueprint $table) {
$table->text('media_content')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('posts_tg_posts', function (Blueprint $table) {
$table->dropColumn('media_content');
});
}
};