Changes
This commit is contained in:
@@ -8,6 +8,7 @@ use App\Helpers\ByteConverter;
|
||||
use App\Models\Category;
|
||||
use App\Models\CustomForm;
|
||||
use App\Models\Page;
|
||||
use App\Models\PageReferenceList;
|
||||
use App\Models\Post;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Components\Builder;
|
||||
@@ -379,6 +380,13 @@ class ContentBuilderItem
|
||||
->searchable()
|
||||
->required(),
|
||||
])->label('Форма'),
|
||||
Builder\Block::make('pageResourceList')
|
||||
->schema([
|
||||
Select::make('resource')
|
||||
->options(PageReferenceList::query()->where('is_active', true)->pluck('title', 'slug'))
|
||||
->searchable()
|
||||
->required(),
|
||||
])->label('Ресурсы'),
|
||||
])
|
||||
->collapsed()
|
||||
->blockNumbers(false)
|
||||
|
||||
@@ -9,10 +9,13 @@ use App\Helpers\ByteConverter;
|
||||
use App\Models\Category;
|
||||
use App\Models\CustomForm;
|
||||
use App\Models\Page;
|
||||
use App\Models\PageReferenceList;
|
||||
use App\Models\Post;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Components\Builder;
|
||||
use Filament\Forms\Components\DateTimePicker;
|
||||
use Filament\Forms\Components\FileUpload;
|
||||
use Filament\Forms\Components\Grid;
|
||||
use Filament\Forms\Components\Hidden;
|
||||
use Filament\Forms\Components\RichEditor;
|
||||
use Filament\Forms\Components\Section;
|
||||
@@ -23,6 +26,8 @@ use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Toggle;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\Components\Tab;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
|
||||
@@ -79,6 +84,30 @@ class PostForm
|
||||
SpatieTagsInput::make('tags')->label('Тэги'),
|
||||
Forms\Components\TagsInput::make('authors')
|
||||
->label('Авторы')->placeholder('Добавить автора'),
|
||||
Section::make('Отложенная публикация')->schema([
|
||||
Grid::make(2)->schema([
|
||||
Toggle::make('publish_setting.publish_after')
|
||||
->label('Включить')
|
||||
->inline(false)
|
||||
->default(false)
|
||||
->live(),
|
||||
DateTimePicker::make('publish_setting.publish_at')
|
||||
->label('Дата публикации')
|
||||
->native()
|
||||
->displayFormat('d/m/Y')
|
||||
|
||||
->required(fn (Forms\Get $get) => $get('publish_setting.publish_after'))
|
||||
->disabled(fn (Forms\Get $get) => !$get('publish_setting.publish_after'))
|
||||
->minDate(Carbon::now()->subWeek())
|
||||
->maxDate(Carbon::now()->addMonth()),
|
||||
]),
|
||||
]),
|
||||
Section::make('Публикация в сервисах')->schema([
|
||||
Forms\Components\Grid::make()->schema([
|
||||
Toggle::make('publication.vk')->label('Публикация в VK')->default(true),
|
||||
Toggle::make('publication.telegram')->label('Публикация в Telegram')->default(true),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
Tabs\Tab::make('Содержание новости')
|
||||
->schema([
|
||||
@@ -89,7 +118,7 @@ class PostForm
|
||||
TextInput::make('content')
|
||||
->label('')
|
||||
->live(onBlur: true)
|
||||
->afterStateUpdated(function (string $operation, string $state, Forms\Set $set, $get) {
|
||||
->afterStateUpdated(function (string $operation, string|null $state, Forms\Set $set, $get) {
|
||||
}),
|
||||
]),
|
||||
Builder\Block::make('paragraph')->label('Текст')
|
||||
@@ -440,8 +469,16 @@ class PostForm
|
||||
->searchable()
|
||||
->required(),
|
||||
])->label('Форма'),
|
||||
Builder\Block::make('PageResourceList')
|
||||
->schema([
|
||||
Select::make('resource')
|
||||
->options(PageReferenceList::query()->where('is_active', true)->pluck('title', 'slug'))
|
||||
->searchable()
|
||||
->required(),
|
||||
])->label('Ресурсы'),
|
||||
])
|
||||
->collapsed()
|
||||
->required()
|
||||
->blockNumbers(false)
|
||||
->collapsible()
|
||||
->blockPickerColumns(3)
|
||||
@@ -468,7 +505,6 @@ class PostForm
|
||||
->directory('images'),
|
||||
]),
|
||||
]),
|
||||
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -125,8 +125,6 @@ class MainSliderResource extends Resource
|
||||
|
||||
Toggle::make('is_active')->default(true)->label('Активный слайдер')->inline(false),
|
||||
]),
|
||||
|
||||
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources;
|
||||
|
||||
use App\Filament\Resources\PageReferenceListResource\Pages;
|
||||
use App\Filament\Resources\PageReferenceListResource\RelationManagers;
|
||||
use App\Models\Event;
|
||||
use App\Models\Page;
|
||||
use App\Models\PageReferenceList;
|
||||
use App\Models\Post;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Components\ColorPicker;
|
||||
use Filament\Forms\Components\FileUpload;
|
||||
use Filament\Forms\Components\Repeater;
|
||||
use Filament\Forms\Components\Tabs;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Toggle;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class PageReferenceListResource extends Resource
|
||||
{
|
||||
protected static ?string $model = PageReferenceList::class;
|
||||
|
||||
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
Forms\Components\Section::make('')->schema([
|
||||
Tabs::make('Tabs')
|
||||
->tabs([
|
||||
Tabs\Tab::make('Основная информация')
|
||||
->schema([
|
||||
Forms\Components\Grid::make(2)->schema([
|
||||
TextInput::make('title')->label('Название ресурса')->required()
|
||||
->live(onBlur: true)
|
||||
->afterStateUpdated(function (string $operation, string|null $state, Forms\Set $set) {
|
||||
$set('slug', Str::slug($state));
|
||||
$set('seo.title', $state);
|
||||
}),
|
||||
TextInput::make('slug')->label('Slug')->unique(ignoreRecord: true)->readOnly()->required(),
|
||||
Toggle::make('is_active')->default(true)->label('Активный ресурс')->inline(false),
|
||||
])
|
||||
]),
|
||||
Tabs\Tab::make('Содержание новости')
|
||||
->schema([
|
||||
Repeater::make('content')->schema([
|
||||
Forms\Components\Section::make('Быстрая настройка ресурса')->schema([
|
||||
Forms\Components\Grid::make()->schema([
|
||||
Forms\Components\Select::make('model_select')
|
||||
->name('')
|
||||
->label('Выбор типа данных')
|
||||
->options([
|
||||
'Post' => 'Новость',
|
||||
'Page' => 'Страница',
|
||||
'Event' => 'Мероприятие',
|
||||
'Custom' => 'Кастомная ссылка',
|
||||
])
|
||||
->afterStateUpdated(function (string $operation, string|null $state, Forms\Set $set, Forms\Get $get) {
|
||||
if ($get('model_select') === 'Custom') {
|
||||
$set('model', null);
|
||||
$set('title', null);
|
||||
$set('content', null);
|
||||
$set('link', null);
|
||||
};
|
||||
})->live(onBlur: true),
|
||||
|
||||
Forms\Components\Select::make('model')
|
||||
->label('Поиск данных')
|
||||
->name('')
|
||||
->live(onBlur: true)
|
||||
->searchable()
|
||||
->live(onBlur: true)
|
||||
->afterStateUpdated(function (string $operation, string|null $state, Forms\Set $set, Forms\Get $get) {
|
||||
if ($get('model_select') === 'Post') {
|
||||
$post = Post::find($state);
|
||||
$set('title', $post->title);
|
||||
$relativeUrl = parse_url(route('client.post.show', $post->slug), PHP_URL_PATH);
|
||||
$set('link', $relativeUrl);
|
||||
};
|
||||
if ($get('model_select') === 'Page') {
|
||||
$page = Page::find($state);
|
||||
$set('title', $page->title);
|
||||
$set('link', $page->path);
|
||||
};
|
||||
if ($get('model_select') === 'Event') {
|
||||
$event = Event::find($state);
|
||||
$set('title', $event->title);
|
||||
$relativeUrl = parse_url(route('client.event.show', $event->slug), PHP_URL_PATH);
|
||||
$set('link', $relativeUrl);
|
||||
};
|
||||
|
||||
})
|
||||
->options(function (Forms\Get $get) {
|
||||
if ($get('model_select') === 'Post') {
|
||||
return Post::where('status', '=', 'published')->pluck('title', 'id');
|
||||
};
|
||||
if ($get('model_select') === 'Page') {
|
||||
return Page::where('title', '!=', null)->pluck('title', 'id');
|
||||
};
|
||||
if ($get('model_select') === 'Event') {
|
||||
return Event::all()->pluck('title', 'id');
|
||||
};
|
||||
if ($get('model_select') === 'Custom') {
|
||||
return [];
|
||||
};
|
||||
}),
|
||||
]),
|
||||
]),
|
||||
TextInput::make('title')->label('Title')->required(),
|
||||
FileUpload::make('image')
|
||||
->label('Изображение')
|
||||
->image()
|
||||
->optimize('webp')
|
||||
->resize(50)
|
||||
->disk('public')
|
||||
->directory('images')
|
||||
->imageEditor(),
|
||||
Forms\Components\Grid::make(2)->schema([
|
||||
Forms\Components\TextInput::make('link')
|
||||
->label('Ссылка ресурса')
|
||||
->required(),
|
||||
Forms\Components\TextInput::make('link_text')
|
||||
->default('Читать')
|
||||
->label('Текст кнопки')
|
||||
->required(),
|
||||
]),
|
||||
])->collapsed()->required(),
|
||||
]),
|
||||
|
||||
]),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
//
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->actions([
|
||||
Tables\Actions\EditAction::make(),
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\BulkActionGroup::make([
|
||||
Tables\Actions\DeleteBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => Pages\ListPageReferenceLists::route('/'),
|
||||
'create' => Pages\CreatePageReferenceList::route('/create'),
|
||||
'edit' => Pages\EditPageReferenceList::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\PageReferenceListResource\Pages;
|
||||
|
||||
use App\Filament\Resources\PageReferenceListResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreatePageReferenceList extends CreateRecord
|
||||
{
|
||||
protected static string $resource = PageReferenceListResource::class;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\PageReferenceListResource\Pages;
|
||||
|
||||
use App\Filament\Resources\PageReferenceListResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditPageReferenceList extends EditRecord
|
||||
{
|
||||
protected static string $resource = PageReferenceListResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\PageReferenceListResource\Pages;
|
||||
|
||||
use App\Filament\Resources\PageReferenceListResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListPageReferenceLists extends ListRecords
|
||||
{
|
||||
protected static string $resource = PageReferenceListResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,8 @@ class PostResource extends Resource implements HasShieldPermissions
|
||||
'update',
|
||||
'delete',
|
||||
'delete_any',
|
||||
'publish'
|
||||
'publish',
|
||||
'view_only_own_records'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,10 @@ namespace App\Filament\Resources\PostResource\Pages;
|
||||
|
||||
use App\Enums\PostStatus;
|
||||
use App\Filament\Resources\PostResource;
|
||||
use App\Jobs\CreateVkPost;
|
||||
use App\Models\Post;
|
||||
use App\Models\User;
|
||||
use App\Services\VK\VkService;
|
||||
use Carbon\Carbon;
|
||||
use Closure;
|
||||
use Filament\Actions;
|
||||
@@ -14,6 +16,7 @@ use Filament\Notifications\Notification;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Notifications\Messages\BroadcastMessage;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use PhpParser\Node\Expr\AssignOp\Mod;
|
||||
use VK\Client\VKApiClient;
|
||||
@@ -28,12 +31,17 @@ class CreatePost extends CreateRecord
|
||||
protected static string $resource = PostResource::class;
|
||||
|
||||
protected array $seoData;
|
||||
protected array $publicationAgreements;
|
||||
|
||||
|
||||
protected function mutateFormDataBeforeCreate(array $data): array
|
||||
{
|
||||
$this->publicationAgreements = $data['publication'];
|
||||
unset($data['publication']);
|
||||
$this->seoData = $this->generateSeo($data);
|
||||
$data['preview_text'] = $this->setPreviewText($data);
|
||||
$data['publish_at'] = $this->setPublishDateTime($data['status']);
|
||||
$data['publish_at'] = $this->setPublishDateTime($data['publish_setting']);
|
||||
unset($data['publish_setting']);
|
||||
$data['search_data'] = $this->generateSearchData($data['content']);
|
||||
$data['reading_time'] = $this->calculateReadingTime($data['search_data']);
|
||||
return $data;
|
||||
@@ -43,6 +51,7 @@ class CreatePost extends CreateRecord
|
||||
{
|
||||
$this->record->seo()->create($this->seoData);
|
||||
$this->sendNotify($this->record, auth()->user());
|
||||
$this->postToSocialMedia($this->publicationAgreements, $this->record->content, $this->record->title, Carbon::parse($this->record->publish_at)->timestamp);
|
||||
}
|
||||
|
||||
private function generateSeo(array $data) : array
|
||||
@@ -62,7 +71,6 @@ class CreatePost extends CreateRecord
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
private function setPreviewText(array $data) : string
|
||||
{
|
||||
$rowData = $this->getBlockBySeoActiveState('paragraph', $data['content']);
|
||||
@@ -126,10 +134,10 @@ class CreatePost extends CreateRecord
|
||||
|
||||
])->sendToDatabase($recipient);
|
||||
}
|
||||
private function setPublishDateTime(PostStatus $status) : Carbon|null
|
||||
private function setPublishDateTime(array $data) : Carbon|null
|
||||
{
|
||||
if ($status !== PostStatus::PUBLISHED) {
|
||||
return null;
|
||||
if ($data['publish_after'] === true) {
|
||||
return Carbon::parse($data['publish_at']);
|
||||
}
|
||||
return Carbon::now();
|
||||
}
|
||||
@@ -243,6 +251,58 @@ class CreatePost extends CreateRecord
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function postToSocialMedia($settings, $content, $title, $publish_date) : void
|
||||
{
|
||||
if ($this->record->status === PostStatus::PUBLISHED) {
|
||||
if ($settings['vk']) {
|
||||
$text = "";
|
||||
foreach ($content as $block) {
|
||||
$text .= $this->generateContentToVK($block);
|
||||
}
|
||||
|
||||
$images = $this->generateImageLinksToVK($this->record->images);
|
||||
|
||||
$post_id = $this->record->id;
|
||||
|
||||
|
||||
dispatch(new CreateVkPost($title, $text, $images, $post_id, $publish_date));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function generateContentToVK($block) : string
|
||||
{
|
||||
$data = "";
|
||||
|
||||
switch ($block['type']) {
|
||||
case 'paragraph':
|
||||
// Удаляем все HTML-теги и заменяем закрывающие теги p и h2 на двойной отступ
|
||||
$content = preg_replace('/<\/(p|h2)>/', "\n\n", $block['data']['content']);
|
||||
$data .= strip_tags($content);
|
||||
break;
|
||||
|
||||
case 'heading':
|
||||
// Удаляем теги заголовка и добавляем двойной отступ
|
||||
$data .= $block['data']['content'] . "\n\n";
|
||||
break;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
private function generateImageLinksToVK($images)
|
||||
{
|
||||
|
||||
$imageUrls = array_map(function ($file) {
|
||||
return url(Storage::url($file)); // Добавляем домен
|
||||
}, $images);
|
||||
|
||||
|
||||
return $imageUrls; // Возвращаем массив с полными URL изображений
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -4,9 +4,11 @@ namespace App\Filament\Resources\PostResource\Pages;
|
||||
|
||||
use App\Enums\PostStatus;
|
||||
use App\Filament\Resources\PostResource;
|
||||
use App\Jobs\UpdateVkPost;
|
||||
use Carbon\Carbon;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class EditPost extends EditRecord
|
||||
@@ -14,11 +16,14 @@ class EditPost extends EditRecord
|
||||
protected static string $resource = PostResource::class;
|
||||
|
||||
protected array $seoData;
|
||||
protected array $publicationAgreements;
|
||||
|
||||
|
||||
protected function mutateFormDataBeforeSave(array $data): array
|
||||
{
|
||||
$this->seoData = $this->generateSeo($data);
|
||||
$this->publicationAgreements = $data['publication'];
|
||||
unset($data['publication']);
|
||||
$data['preview_text'] = $this->setPreviewText($data);
|
||||
$data['publish_at'] = $this->setPublishDateTime($data['status'], $this->record->publish_at);
|
||||
$data['search_data'] = $this->generateSearchData($data['content']);
|
||||
@@ -30,6 +35,7 @@ class EditPost extends EditRecord
|
||||
protected function afterSave(): void
|
||||
{
|
||||
$this->record->seo()->update($this->seoData);
|
||||
$this->postToSocialMedia($this->publicationAgreements, $this->record->content, $this->record->title, Carbon::parse($this->record->publish_at)->timestamp);
|
||||
}
|
||||
|
||||
private function setPreviewText(array $data) : string
|
||||
@@ -59,8 +65,6 @@ class EditPost extends EditRecord
|
||||
return $block;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function generateSeo(array $data) : array
|
||||
{
|
||||
$title = $data['title'];
|
||||
@@ -166,6 +170,59 @@ class EditPost extends EditRecord
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function generateContentToVK($block) : string
|
||||
{
|
||||
$data = "";
|
||||
|
||||
switch ($block['type']) {
|
||||
case 'paragraph':
|
||||
// Удаляем все HTML-теги и заменяем закрывающие теги p и h2 на двойной отступ
|
||||
$content = preg_replace('/<\/(p|h2)>/', "\n\n", $block['data']['content']);
|
||||
$data .= strip_tags($content);
|
||||
break;
|
||||
|
||||
case 'heading':
|
||||
// Удаляем теги заголовка и добавляем двойной отступ
|
||||
$data .= $block['data']['content'] . "\n\n";
|
||||
break;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
private function postToSocialMedia($settings, $content, $title, $publish_date) : void
|
||||
{
|
||||
if ($this->record->status === PostStatus::PUBLISHED) {
|
||||
if ($settings['vk']) {
|
||||
$text = "";
|
||||
foreach ($content as $block) {
|
||||
$text .= $this->generateContentToVK($block);
|
||||
}
|
||||
|
||||
$images = $this->generateImageLinksToVK($this->record->images);
|
||||
|
||||
$post_id = $this->record->id;
|
||||
|
||||
|
||||
dispatch(new UpdateVkPost($title, $text, $images, $post_id, $publish_date));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function generateImageLinksToVK($images)
|
||||
{
|
||||
|
||||
$imageUrls = array_map(function ($file) {
|
||||
return url(Storage::url($file)); // Добавляем домен
|
||||
}, $images);
|
||||
|
||||
|
||||
return $imageUrls; // Возвращаем массив с полными URL изображений
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,21 +9,26 @@ use Filament\Actions;
|
||||
use Filament\Resources\Components\Tab;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ListPosts extends ListRecords
|
||||
{
|
||||
public \Illuminate\Support\Collection $postsByStatuses;
|
||||
protected static string $resource = PostResource::class;
|
||||
|
||||
public function __construct()
|
||||
public function getPostsByStatuses(): \Illuminate\Support\Collection
|
||||
{
|
||||
$this->postsByStatuses = Post::select('status', DB::raw('count(*) as post_count'))
|
||||
return Post::select('status', DB::raw('count(*) as post_count'))
|
||||
->groupBy('status')
|
||||
->when($this->canViewOnlyOwnRecords(), function (Builder $query) {
|
||||
$query->where('user_id', auth()->id());
|
||||
})
|
||||
->pluck('post_count', 'status');
|
||||
}
|
||||
|
||||
protected static string $resource = PostResource::class;
|
||||
protected function canViewOnlyOwnRecords(): bool
|
||||
{
|
||||
return auth()->user()->can('view_only_own_records_post');
|
||||
}
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
@@ -34,11 +39,21 @@ class ListPosts extends ListRecords
|
||||
|
||||
public function getTabs(): array
|
||||
{
|
||||
$postsByStatuses = $this->getPostsByStatuses();
|
||||
|
||||
return [
|
||||
'status' => Tab::make('Новости на рассмотрении')->modifyQueryUsing(function (Builder $query) {
|
||||
$query->where('status', '=', PostStatus::VERIFICATION->value);
|
||||
})->badge($this->postsByStatuses[PostStatus::VERIFICATION->value] ?? 0),
|
||||
'All' => Tab::make('Все новости'),
|
||||
if ($this->canViewOnlyOwnRecords()) {
|
||||
$query->where('user_id', auth()->id());
|
||||
}
|
||||
})->badge($postsByStatuses[PostStatus::VERIFICATION->value] ?? 0),
|
||||
|
||||
'All' => Tab::make('Все новости')->modifyQueryUsing(function (Builder $query) {
|
||||
if ($this->canViewOnlyOwnRecords()) {
|
||||
$query->where('user_id', auth()->id());
|
||||
}
|
||||
}),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,402 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Shield;
|
||||
|
||||
use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions;
|
||||
use BezhanSalleh\FilamentShield\Facades\FilamentShield;
|
||||
use BezhanSalleh\FilamentShield\FilamentShieldPlugin;
|
||||
use BezhanSalleh\FilamentShield\Forms\ShieldSelectAllToggle;
|
||||
use App\Filament\Resources\Shield\RoleResource\Pages;
|
||||
use BezhanSalleh\FilamentShield\Support\Utils;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Components\Component;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\HtmlString;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class RoleResource extends Resource implements HasShieldPermissions
|
||||
{
|
||||
protected static ?string $recordTitleAttribute = 'name';
|
||||
|
||||
public static function getPermissionPrefixes(): array
|
||||
{
|
||||
return [
|
||||
'view',
|
||||
'view_any',
|
||||
'create',
|
||||
'update',
|
||||
'delete',
|
||||
'delete_any',
|
||||
];
|
||||
}
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
Forms\Components\Grid::make()
|
||||
->schema([
|
||||
Forms\Components\Section::make()
|
||||
->schema([
|
||||
Forms\Components\TextInput::make('name')
|
||||
->label(__('filament-shield::filament-shield.field.name'))
|
||||
->unique(ignoreRecord: true)
|
||||
->required()
|
||||
->maxLength(255),
|
||||
|
||||
Forms\Components\TextInput::make('guard_name')
|
||||
->label(__('filament-shield::filament-shield.field.guard_name'))
|
||||
->default(Utils::getFilamentAuthGuard())
|
||||
->nullable()
|
||||
->maxLength(255),
|
||||
|
||||
ShieldSelectAllToggle::make('select_all')
|
||||
->onIcon('heroicon-s-shield-check')
|
||||
->offIcon('heroicon-s-shield-exclamation')
|
||||
->label(__('filament-shield::filament-shield.field.select_all.name'))
|
||||
->helperText(fn (): HtmlString => new HtmlString(__('filament-shield::filament-shield.field.select_all.message')))
|
||||
->dehydrated(fn ($state): bool => $state),
|
||||
|
||||
])
|
||||
->columns([
|
||||
'sm' => 2,
|
||||
'lg' => 3,
|
||||
]),
|
||||
]),
|
||||
Forms\Components\Tabs::make('Permissions')
|
||||
->contained()
|
||||
->tabs([
|
||||
static::getTabFormComponentForResources(),
|
||||
static::getTabFormComponentForPage(),
|
||||
static::getTabFormComponentForWidget(),
|
||||
static::getTabFormComponentForCustomPermissions(),
|
||||
])
|
||||
->columnSpan('full'),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('name')
|
||||
->badge()
|
||||
->label(__('filament-shield::filament-shield.column.name'))
|
||||
->formatStateUsing(fn ($state): string => Str::headline($state))
|
||||
->colors(['primary'])
|
||||
->searchable(),
|
||||
Tables\Columns\TextColumn::make('guard_name')
|
||||
->badge()
|
||||
->label(__('filament-shield::filament-shield.column.guard_name')),
|
||||
Tables\Columns\TextColumn::make('permissions_count')
|
||||
->badge()
|
||||
->label(__('filament-shield::filament-shield.column.permissions'))
|
||||
->counts('permissions')
|
||||
->colors(['success']),
|
||||
Tables\Columns\TextColumn::make('updated_at')
|
||||
->label(__('filament-shield::filament-shield.column.updated_at'))
|
||||
->dateTime(),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->actions([
|
||||
Tables\Actions\EditAction::make(),
|
||||
Tables\Actions\DeleteAction::make(),
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\DeleteBulkAction::make(),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => Pages\ListRoles::route('/'),
|
||||
'create' => Pages\CreateRole::route('/create'),
|
||||
'view' => Pages\ViewRole::route('/{record}'),
|
||||
'edit' => Pages\EditRole::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function getCluster(): ?string
|
||||
{
|
||||
return Utils::getResourceCluster() ?? static::$cluster;
|
||||
}
|
||||
|
||||
public static function getModel(): string
|
||||
{
|
||||
return Utils::getRoleModel();
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return __('filament-shield::filament-shield.resource.label.role');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return __('filament-shield::filament-shield.resource.label.roles');
|
||||
}
|
||||
|
||||
public static function shouldRegisterNavigation(): bool
|
||||
{
|
||||
return Utils::isResourceNavigationRegistered();
|
||||
}
|
||||
|
||||
public static function getNavigationGroup(): ?string
|
||||
{
|
||||
return Utils::isResourceNavigationGroupEnabled()
|
||||
? __('filament-shield::filament-shield.nav.group')
|
||||
: '';
|
||||
}
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return __('filament-shield::filament-shield.nav.role.label');
|
||||
}
|
||||
|
||||
public static function getNavigationIcon(): string
|
||||
{
|
||||
return __('filament-shield::filament-shield.nav.role.icon');
|
||||
}
|
||||
|
||||
public static function getNavigationSort(): ?int
|
||||
{
|
||||
return Utils::getResourceNavigationSort();
|
||||
}
|
||||
|
||||
public static function getSlug(): string
|
||||
{
|
||||
return Utils::getResourceSlug();
|
||||
}
|
||||
|
||||
public static function getNavigationBadge(): ?string
|
||||
{
|
||||
return Utils::isResourceNavigationBadgeEnabled()
|
||||
? strval(static::getEloquentQuery()->count())
|
||||
: null;
|
||||
}
|
||||
|
||||
public static function isScopedToTenant(): bool
|
||||
{
|
||||
return Utils::isScopedToTenant();
|
||||
}
|
||||
|
||||
public static function canGloballySearch(): bool
|
||||
{
|
||||
return Utils::isResourceGloballySearchable() && count(static::getGloballySearchableAttributes()) && static::canViewAny();
|
||||
}
|
||||
|
||||
public static function getResourceEntitiesSchema(): ?array
|
||||
{
|
||||
return collect(FilamentShield::getResources())
|
||||
->sortKeys()
|
||||
->map(function ($entity) {
|
||||
$sectionLabel = strval(
|
||||
static::shield()->hasLocalizedPermissionLabels()
|
||||
? FilamentShield::getLocalizedResourceLabel($entity['fqcn'])
|
||||
: $entity['model']
|
||||
);
|
||||
|
||||
return Forms\Components\Section::make($sectionLabel)
|
||||
->description(fn () => new HtmlString('<span style="word-break: break-word;">' . Utils::showModelPath($entity['fqcn']) . '</span>'))
|
||||
->compact()
|
||||
->schema([
|
||||
static::getCheckBoxListComponentForResource($entity),
|
||||
])
|
||||
->columnSpan(static::shield()->getSectionColumnSpan())
|
||||
->collapsible();
|
||||
})
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public static function getResourceTabBadgeCount(): ?int
|
||||
{
|
||||
return collect(FilamentShield::getResources())
|
||||
->map(fn ($resource) => count(static::getResourcePermissionOptions($resource)))
|
||||
->sum();
|
||||
}
|
||||
|
||||
public static function getResourcePermissionOptions(array $entity): array
|
||||
{
|
||||
return collect(Utils::getResourcePermissionPrefixes($entity['fqcn']))
|
||||
->flatMap(function ($permission) use ($entity) {
|
||||
$name = $permission . '_' . $entity['resource'];
|
||||
$label = static::shield()->hasLocalizedPermissionLabels()
|
||||
? FilamentShield::getLocalizedResourcePermissionLabel($permission)
|
||||
: $name;
|
||||
|
||||
return [
|
||||
$name => $label,
|
||||
];
|
||||
})
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public static function setPermissionStateForRecordPermissions(Component $component, string $operation, array $permissions, ?Model $record): void
|
||||
{
|
||||
|
||||
if (in_array($operation, ['edit', 'view'])) {
|
||||
|
||||
if (blank($record)) {
|
||||
return;
|
||||
}
|
||||
if ($component->isVisible() && count($permissions) > 0) {
|
||||
$component->state(
|
||||
collect($permissions)
|
||||
/** @phpstan-ignore-next-line */
|
||||
->filter(fn ($value, $key) => $record->checkPermissionTo($key))
|
||||
->keys()
|
||||
->toArray()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function getPageOptions(): array
|
||||
{
|
||||
return collect(FilamentShield::getPages())
|
||||
->flatMap(fn ($page) => [
|
||||
$page['permission'] => static::shield()->hasLocalizedPermissionLabels()
|
||||
? FilamentShield::getLocalizedPageLabel($page['class'])
|
||||
: $page['permission'],
|
||||
])
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public static function getWidgetOptions(): array
|
||||
{
|
||||
return collect(FilamentShield::getWidgets())
|
||||
->flatMap(fn ($widget) => [
|
||||
$widget['permission'] => static::shield()->hasLocalizedPermissionLabels()
|
||||
? FilamentShield::getLocalizedWidgetLabel($widget['class'])
|
||||
: $widget['permission'],
|
||||
])
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public static function getCustomPermissionOptions(): ?array
|
||||
{
|
||||
return FilamentShield::getCustomPermissions()
|
||||
->mapWithKeys(fn ($customPermission) => [
|
||||
$customPermission => static::shield()->hasLocalizedPermissionLabels() ? str($customPermission)->headline()->toString() : $customPermission,
|
||||
])
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public static function getTabFormComponentForResources(): Component
|
||||
{
|
||||
return static::shield()->hasSimpleResourcePermissionView()
|
||||
? static::getTabFormComponentForSimpleResourcePermissionsView()
|
||||
: Forms\Components\Tabs\Tab::make('resources')
|
||||
->label(__('filament-shield::filament-shield.resources'))
|
||||
->visible(fn (): bool => (bool) Utils::isResourceEntityEnabled())
|
||||
->badge(static::getResourceTabBadgeCount())
|
||||
->schema([
|
||||
Forms\Components\Grid::make()
|
||||
->schema(static::getResourceEntitiesSchema())
|
||||
->columns(static::shield()->getGridColumns()),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function getCheckBoxListComponentForResource(array $entity): Component
|
||||
{
|
||||
$permissionsArray = static::getResourcePermissionOptions($entity);
|
||||
|
||||
return static::getCheckboxListFormComponent($entity['resource'], $permissionsArray, false);
|
||||
}
|
||||
|
||||
public static function getTabFormComponentForPage(): Component
|
||||
{
|
||||
$options = static::getPageOptions();
|
||||
$count = count($options);
|
||||
|
||||
return Forms\Components\Tabs\Tab::make('pages')
|
||||
->label(__('filament-shield::filament-shield.pages'))
|
||||
->visible(fn (): bool => (bool) Utils::isPageEntityEnabled() && $count > 0)
|
||||
->badge($count)
|
||||
->schema([
|
||||
static::getCheckboxListFormComponent('pages_tab', $options),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function getTabFormComponentForWidget(): Component
|
||||
{
|
||||
$options = static::getWidgetOptions();
|
||||
$count = count($options);
|
||||
|
||||
return Forms\Components\Tabs\Tab::make('widgets')
|
||||
->label(__('filament-shield::filament-shield.widgets'))
|
||||
->visible(fn (): bool => (bool) Utils::isWidgetEntityEnabled() && $count > 0)
|
||||
->badge($count)
|
||||
->schema([
|
||||
static::getCheckboxListFormComponent('widgets_tab', $options),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function getTabFormComponentForCustomPermissions(): Component
|
||||
{
|
||||
$options = static::getCustomPermissionOptions();
|
||||
$count = count($options);
|
||||
|
||||
return Forms\Components\Tabs\Tab::make('custom')
|
||||
->label(__('filament-shield::filament-shield.custom'))
|
||||
->visible(fn (): bool => (bool) Utils::isCustomPermissionEntityEnabled() && $count > 0)
|
||||
->badge($count)
|
||||
->schema([
|
||||
static::getCheckboxListFormComponent('custom_permissions', $options),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function getTabFormComponentForSimpleResourcePermissionsView(): Component
|
||||
{
|
||||
$options = FilamentShield::getAllResourcePermissions();
|
||||
$count = count($options);
|
||||
|
||||
return Forms\Components\Tabs\Tab::make('resources')
|
||||
->label(__('filament-shield::filament-shield.resources'))
|
||||
->visible(fn (): bool => (bool) Utils::isResourceEntityEnabled() && $count > 0)
|
||||
->badge($count)
|
||||
->schema([
|
||||
static::getCheckboxListFormComponent('resources_tab', $options),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function getCheckboxListFormComponent(string $name, array $options, bool $searchable = true): Component
|
||||
{
|
||||
return Forms\Components\CheckboxList::make($name)
|
||||
->label('')
|
||||
->options(fn (): array => $options)
|
||||
->searchable($searchable)
|
||||
->afterStateHydrated(
|
||||
fn (Component $component, string $operation, ?Model $record) => static::setPermissionStateForRecordPermissions(
|
||||
component: $component,
|
||||
operation: $operation,
|
||||
permissions: $options,
|
||||
record: $record
|
||||
)
|
||||
)
|
||||
->dehydrated(fn ($state) => ! blank($state))
|
||||
->bulkToggleable()
|
||||
->gridDirection('row')
|
||||
->columns(static::shield()->getCheckboxListColumns())
|
||||
->columnSpan(static::shield()->getCheckboxListColumnSpan());
|
||||
}
|
||||
|
||||
public static function shield(): FilamentShieldPlugin
|
||||
{
|
||||
return FilamentShieldPlugin::get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Shield\RoleResource\Pages;
|
||||
|
||||
use App\Filament\Resources\Shield\RoleResource;
|
||||
use BezhanSalleh\FilamentShield\Support\Utils;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class CreateRole extends CreateRecord
|
||||
{
|
||||
protected static string $resource = RoleResource::class;
|
||||
|
||||
public Collection $permissions;
|
||||
|
||||
protected function mutateFormDataBeforeCreate(array $data): array
|
||||
{
|
||||
$this->permissions = collect($data)
|
||||
->filter(function ($permission, $key) {
|
||||
return ! in_array($key, ['name', 'guard_name', 'select_all']);
|
||||
})
|
||||
->values()
|
||||
->flatten()
|
||||
->unique();
|
||||
|
||||
return Arr::only($data, ['name', 'guard_name']);
|
||||
}
|
||||
|
||||
protected function afterCreate(): void
|
||||
{
|
||||
$permissionModels = collect();
|
||||
$this->permissions->each(function ($permission) use ($permissionModels) {
|
||||
$permissionModels->push(Utils::getPermissionModel()::firstOrCreate([
|
||||
/** @phpstan-ignore-next-line */
|
||||
'name' => $permission,
|
||||
'guard_name' => $this->data['guard_name'],
|
||||
]));
|
||||
});
|
||||
|
||||
$this->record->syncPermissions($permissionModels);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Shield\RoleResource\Pages;
|
||||
|
||||
use App\Filament\Resources\Shield\RoleResource;
|
||||
use BezhanSalleh\FilamentShield\Support\Utils;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class EditRole extends EditRecord
|
||||
{
|
||||
protected static string $resource = RoleResource::class;
|
||||
|
||||
public Collection $permissions;
|
||||
|
||||
protected function getActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
|
||||
protected function mutateFormDataBeforeSave(array $data): array
|
||||
{
|
||||
$this->permissions = collect($data)
|
||||
->filter(function ($permission, $key) {
|
||||
return ! in_array($key, ['name', 'guard_name', 'select_all']);
|
||||
})
|
||||
->values()
|
||||
->flatten()
|
||||
->unique();
|
||||
|
||||
return Arr::only($data, ['name', 'guard_name']);
|
||||
}
|
||||
|
||||
protected function afterSave(): void
|
||||
{
|
||||
$permissionModels = collect();
|
||||
$this->permissions->each(function ($permission) use ($permissionModels) {
|
||||
$permissionModels->push(Utils::getPermissionModel()::firstOrCreate([
|
||||
'name' => $permission,
|
||||
'guard_name' => $this->data['guard_name'],
|
||||
]));
|
||||
});
|
||||
|
||||
$this->record->syncPermissions($permissionModels);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Shield\RoleResource\Pages;
|
||||
|
||||
use App\Filament\Resources\Shield\RoleResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListRoles extends ListRecords
|
||||
{
|
||||
protected static string $resource = RoleResource::class;
|
||||
|
||||
protected function getActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Shield\RoleResource\Pages;
|
||||
|
||||
use App\Filament\Resources\Shield\RoleResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
|
||||
class ViewRole extends ViewRecord
|
||||
{
|
||||
protected static string $resource = RoleResource::class;
|
||||
|
||||
protected function getActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\EditAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -37,11 +37,24 @@ class UserResource extends Resource implements HasShieldPermissions
|
||||
->required()
|
||||
->maxLength(255),
|
||||
Forms\Components\DateTimePicker::make('email_verified_at'),
|
||||
|
||||
Forms\Components\TextInput::make('password')
|
||||
->password()
|
||||
->required(fn (string $context): bool => $context === 'create')
|
||||
->dehydrated(fn ($state) => filled($state))
|
||||
->maxLength(255),
|
||||
|
||||
Forms\Components\Select::make('roles')
|
||||
->relationship('roles', 'name')
|
||||
->multiple()
|
||||
->preload()
|
||||
->searchable(),
|
||||
|
||||
Forms\Components\Select::make('permissions')
|
||||
->relationship('permissions', 'name')
|
||||
->multiple()
|
||||
->preload()
|
||||
->searchable()
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,14 @@ use App\Enums\FormEducation;
|
||||
use App\Http\Resources\AdditionalEducationCategoryPreviewResource;
|
||||
use App\Http\Resources\AdditionalEducationCategoryResource;
|
||||
use App\Http\Resources\AdditionalEducationResource;
|
||||
use App\Http\Resources\ClientBreadcrumbPage;
|
||||
use App\Http\Resources\ClientBreadcrumbSection;
|
||||
use App\Http\Resources\ClientBreadcrumbSubSection;
|
||||
use App\Http\Resources\DirectionAdditionalEducationResource;
|
||||
use App\Models\AdditionalEducation;
|
||||
use App\Models\AdditionalEducationCategory;
|
||||
use App\Models\DirectionAdditionalEducation;
|
||||
use App\Models\Page;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
|
||||
@@ -85,19 +89,51 @@ class ClientAdditionalEducationController extends Controller
|
||||
'content' => $categoriesContent,
|
||||
],
|
||||
];
|
||||
|
||||
$routeUrl = route('client.additionalEducation.index');
|
||||
$path = ltrim(parse_url($routeUrl, PHP_URL_PATH), '/');
|
||||
|
||||
$page = Page::where('path', '=', $path)->with('section.pages.section', 'section.mainSection')->first();
|
||||
|
||||
if (isset($page->section)) {
|
||||
$breadcrumbs = [
|
||||
'mainSection' => new ClientBreadcrumbSection($page->section->mainSection),
|
||||
'subSection' => new ClientBreadcrumbSubSection($page->section),
|
||||
'page' => new ClientBreadcrumbPage($page),
|
||||
];
|
||||
} else {
|
||||
$breadcrumbs = null;
|
||||
}
|
||||
|
||||
return Inertia::render('Client/Additional-educations/Index',
|
||||
compact(
|
||||
'directionAdditionalEducations',
|
||||
'additionalEducations',
|
||||
'filters',
|
||||
'forms_education',
|
||||
'categories'
|
||||
'categories',
|
||||
'breadcrumbs'
|
||||
));
|
||||
}
|
||||
|
||||
public function show(string $slug)
|
||||
{
|
||||
$additionalEducation = new AdditionalEducationResource(AdditionalEducation::query()->with('category.direction')->where('slug', $slug)->first());
|
||||
return Inertia::render('Client/Additional-educations/Show', compact('additionalEducation'));
|
||||
$routeUrl = route('client.additionalEducation.index');
|
||||
$path = ltrim(parse_url($routeUrl, PHP_URL_PATH), '/');
|
||||
|
||||
$page = Page::where('path', '=', $path)->with('section.pages.section', 'section.mainSection')->first();
|
||||
|
||||
if (isset($page->section)) {
|
||||
$breadcrumbs = [
|
||||
'mainSection' => new ClientBreadcrumbSection($page->section->mainSection),
|
||||
'subSection' => new ClientBreadcrumbSubSection($page->section),
|
||||
'page' => new ClientBreadcrumbPage($page),
|
||||
];
|
||||
} else {
|
||||
$breadcrumbs = null;
|
||||
}
|
||||
|
||||
return Inertia::render('Client/Additional-educations/Show', compact('additionalEducation', 'breadcrumbs'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Resources\ClientBreadcrumbPage;
|
||||
use App\Http\Resources\ClientBreadcrumbSection;
|
||||
use App\Http\Resources\ClientBreadcrumbSubSection;
|
||||
use App\Http\Resources\ClientEventCategoryResource;
|
||||
use App\Http\Resources\ClientEventFullResource;
|
||||
use App\Http\Resources\ClientEventResource;
|
||||
use App\Http\Resources\ClientNavigationResource;
|
||||
use App\Models\Event;
|
||||
use App\Models\EventCategory;
|
||||
use App\Models\Page;
|
||||
use Carbon\Carbon;
|
||||
use DateTime;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -24,13 +28,44 @@ class ClientEventController extends Controller
|
||||
$events = $this->getEvents($currentDate);
|
||||
$categories = ClientEventCategoryResource::collection(EventCategory::has('events')->get());
|
||||
|
||||
return Inertia::render('Client/Events/Index', compact('eventDates', 'events', 'currentDate', 'filters', 'categories'));
|
||||
$routeUrl = route('client.event.index');
|
||||
$path = ltrim(parse_url($routeUrl, PHP_URL_PATH), '/');
|
||||
|
||||
$page = Page::where('path', '=', $path)->with('section.pages.section', 'section.mainSection')->first();
|
||||
|
||||
if (isset($page->section)) {
|
||||
$breadcrumbs = [
|
||||
'mainSection' => new ClientBreadcrumbSection($page->section->mainSection),
|
||||
'subSection' => new ClientBreadcrumbSubSection($page->section),
|
||||
'page' => new ClientBreadcrumbPage($page),
|
||||
];
|
||||
} else {
|
||||
$breadcrumbs = null;
|
||||
}
|
||||
|
||||
return Inertia::render('Client/Events/Index', compact('eventDates', 'events', 'currentDate', 'filters', 'categories', 'breadcrumbs'));
|
||||
}
|
||||
|
||||
public function show(string $slug)
|
||||
{
|
||||
$event = new ClientEventFullResource(Event::where('slug', '=', $slug)->with('category')->first());
|
||||
return Inertia::render('Client/Events/Show', compact('event'));
|
||||
|
||||
$routeUrl = route('client.event.index');
|
||||
$path = ltrim(parse_url($routeUrl, PHP_URL_PATH), '/');
|
||||
|
||||
$page = Page::where('path', '=', $path)->with('section.pages.section', 'section.mainSection')->first();
|
||||
|
||||
if (isset($page->section)) {
|
||||
$breadcrumbs = [
|
||||
'mainSection' => new ClientBreadcrumbSection($page->section->mainSection),
|
||||
'subSection' => new ClientBreadcrumbSubSection($page->section),
|
||||
'page' => new ClientBreadcrumbPage($page),
|
||||
];
|
||||
} else {
|
||||
$breadcrumbs = null;
|
||||
}
|
||||
|
||||
return Inertia::render('Client/Events/Show', compact('event', 'breadcrumbs'));
|
||||
}
|
||||
|
||||
private function getCurrentDate(Request $request): array
|
||||
|
||||
@@ -3,15 +3,21 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Resources\CategoryResource;
|
||||
use App\Http\Resources\ClientBreadcrumbPage;
|
||||
use App\Http\Resources\ClientBreadcrumbSection;
|
||||
use App\Http\Resources\ClientBreadcrumbSubSection;
|
||||
use App\Http\Resources\ClientNavigationResource;
|
||||
use App\Http\Resources\ClientPostListResource;
|
||||
use App\Http\Resources\ClientTagResource;
|
||||
use App\Http\Resources\MainSectionResource;
|
||||
use App\Http\Resources\PageResource;
|
||||
use App\Http\Resources\PostResource;
|
||||
use App\Models\Category;
|
||||
use App\Models\MainSection;
|
||||
use App\Models\Page;
|
||||
use App\Models\Post;
|
||||
use App\Models\Tag;
|
||||
use Carbon\Carbon;
|
||||
use Doctrine\DBAL\Schema\Column;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@@ -33,6 +39,7 @@ class ClientPostController extends Controller
|
||||
->with('category')
|
||||
->select('title', 'slug', 'authors', 'category_id', 'preview', 'search_data', 'created_at')
|
||||
->where('status', '=', 'published')
|
||||
->where('publish_at', '<', Carbon::now())
|
||||
->when(request()->input('search'), function ($query, $search) {
|
||||
$query->whereRaw('LOWER(title) like ?', ["%".strtolower($search)."%"]);
|
||||
})
|
||||
@@ -100,13 +107,43 @@ class ClientPostController extends Controller
|
||||
],
|
||||
];
|
||||
|
||||
return Inertia::render('Client/Posts/Index', compact('filters', 'posts', 'categories', 'tags'));
|
||||
$routeUrl = route('client.post.index');
|
||||
$path = ltrim(parse_url($routeUrl, PHP_URL_PATH), '/');
|
||||
|
||||
$page = Page::where('path', '=', $path)->with('section.pages.section', 'section.mainSection')->first();
|
||||
|
||||
if (isset($page->section)) {
|
||||
$breadcrumbs = [
|
||||
'mainSection' => new ClientBreadcrumbSection($page->section->mainSection),
|
||||
'subSection' => new ClientBreadcrumbSubSection($page->section),
|
||||
'page' => new ClientBreadcrumbPage($page),
|
||||
];
|
||||
} else {
|
||||
$breadcrumbs = null;
|
||||
}
|
||||
|
||||
return Inertia::render('Client/Posts/Index', compact('filters', 'posts', 'categories', 'tags', 'breadcrumbs'));
|
||||
}
|
||||
|
||||
public function show(Request $request, $slug)
|
||||
{
|
||||
$post = new PostResource(Post::where('slug', $slug)->firstOrFail());
|
||||
return Inertia::render('Client/Posts/Show', compact('post'));
|
||||
$post = new PostResource(Post::where('slug', $slug)->where('publish_at', '<', Carbon::now())->firstOrFail());
|
||||
$routeUrl = route('client.post.index');
|
||||
$path = ltrim(parse_url($routeUrl, PHP_URL_PATH), '/');
|
||||
|
||||
$page = Page::where('path', '=', $path)->with('section.pages.section', 'section.mainSection')->first();
|
||||
|
||||
if (isset($page->section)) {
|
||||
$breadcrumbs = [
|
||||
'mainSection' => new ClientBreadcrumbSection($page->section->mainSection),
|
||||
'subSection' => new ClientBreadcrumbSubSection($page->section),
|
||||
'page' => new ClientBreadcrumbPage($page),
|
||||
];
|
||||
} else {
|
||||
$subSectionPages = null;
|
||||
$breadcrumbs = null;
|
||||
}
|
||||
return Inertia::render('Client/Posts/Show', compact('post', 'breadcrumbs'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Resources\ClientPageReferenceListResource;
|
||||
use App\Models\PageReferenceList;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ClientWidgetPageReferenceListController extends Controller
|
||||
{
|
||||
public function show(string $slug)
|
||||
{
|
||||
return new ClientPageReferenceListResource(PageReferenceList::query()->where('slug', $slug)->first());
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,8 @@ use App\Models\MainSection;
|
||||
use App\Models\MainSlider;
|
||||
use App\Models\Post;
|
||||
use App\Services\Filament\Icon\ArrayToCollectionService;
|
||||
use App\Services\Vicon\EducationalProgram\EducationalProgramService;
|
||||
use Carbon\Carbon;
|
||||
use DateTime;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
@@ -63,6 +65,7 @@ class MainController extends Controller
|
||||
$posts = PostThumbnailResource::collection(Post::query()
|
||||
->select('title', 'slug', 'authors', 'preview_text', 'category_id', 'preview', 'search_data', 'created_at')
|
||||
->with('category')
|
||||
->where('publish_at', '<', Carbon::now())
|
||||
->where('status', '=', PostStatus::PUBLISHED)
|
||||
->orderBy('publish_at', 'desc')->limit(3)
|
||||
->get());
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Str;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class VkAuthController extends Controller
|
||||
{
|
||||
|
||||
}
|
||||
@@ -2,8 +2,16 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Jobs\CreateVkPost;
|
||||
use App\Services\VK\VkAuthService;
|
||||
use App\Services\VK\VkService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Inertia\Inertia;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use VK\Client\VKApiClient;
|
||||
use VK\OAuth\Scopes\VKOAuthUserScope;
|
||||
use VK\OAuth\VKOAuth;
|
||||
@@ -16,33 +24,43 @@ class VkPostController extends Controller
|
||||
|
||||
private VkService $vkService;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->vkService = new VkService(new VKApiClient());
|
||||
$this->wall_token = env('WALL_ACCESS_VK_TOKEN');
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$oauth = new VKOAuth();
|
||||
$client_id = 52468445;
|
||||
$redirect_uri = 'https://crawdad-fresh-bream.ngrok-free.app/';
|
||||
$display = VKOAuthDisplay::PAGE;
|
||||
$scope = array(VKOAuthUserScope::WALL, VKOAuthUserScope::PHOTOS);
|
||||
$state = 'dJZ3N05uZc9jpcEgxD6y';
|
||||
$groups_ids = array(227826614);
|
||||
|
||||
$browser_url = $oauth->getAuthorizeUrl(VKOAuthResponseType::TOKEN, $client_id, $redirect_uri, $display, $scope, $state, $groups_ids);
|
||||
return redirect($browser_url);
|
||||
|
||||
}
|
||||
|
||||
public function wall()
|
||||
{
|
||||
return $this->vkService->createAlbum('Тестовый альбом');
|
||||
dd($this->vkService->getPostById(39));
|
||||
}
|
||||
|
||||
|
||||
public function getImages()
|
||||
{
|
||||
// Укажите путь к директории
|
||||
$directory = 'public/images';
|
||||
|
||||
// Получаем все файлы из директории
|
||||
$files = Storage::files($directory);
|
||||
|
||||
|
||||
// Фильтруем только изображения (например, jpg, png)
|
||||
$images = array_filter($files, function ($file) {
|
||||
return in_array(pathinfo($file, PATHINFO_EXTENSION), ['webp', 'jpeg', 'png', 'gif']);
|
||||
});
|
||||
|
||||
// Формируем полный URL для каждого изображения
|
||||
$imageUrls = array_map(function ($file) {
|
||||
return url(Storage::url($file)); // Добавляем домен
|
||||
}, $images);
|
||||
|
||||
return $imageUrls; // Возвращаем массив с полными URL изображений
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ class Kernel extends HttpKernel
|
||||
*/
|
||||
protected $middleware = [
|
||||
// \App\Http\Middleware\TrustHosts::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\Illuminate\Http\Middleware\HandleCors::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ClientPageReferenceListResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return parent::toArray($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ClientPageReferenceResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return parent::toArray($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Enums\LevelEducational;
|
||||
use App\Models\DirectionStudy;
|
||||
use App\Services\Vicon\DirectionStudy\DirectionStudyService;
|
||||
use App\Services\VK\VkService;
|
||||
use Carbon\Carbon;
|
||||
use Filament\Notifications\Notification;
|
||||
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\Log;
|
||||
use Illuminate\Support\Str;
|
||||
use VK\Client\VKApiClient;
|
||||
|
||||
class CreateVkPost implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct(
|
||||
readonly private string $title,
|
||||
readonly private string $text,
|
||||
readonly private array $images = [],
|
||||
readonly private int $post_id,
|
||||
readonly private int $publish_date,
|
||||
|
||||
)
|
||||
{}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
try {
|
||||
$vkService = new VkService();
|
||||
$vk_post = $vkService->createPost($this->title, $this->text, $this->images, $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(),
|
||||
]
|
||||
);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Ошибка при создании поста: ' . $e->getMessage());
|
||||
throw $e; // Перебрасываем исключение для повторной попытки
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Enums\LevelEducational;
|
||||
use App\Models\DirectionStudy;
|
||||
use App\Services\Vicon\DirectionStudy\DirectionStudyService;
|
||||
use App\Services\VK\VkService;
|
||||
use Carbon\Carbon;
|
||||
use Filament\Notifications\Notification;
|
||||
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\Log;
|
||||
use Illuminate\Support\Str;
|
||||
use VK\Client\VKApiClient;
|
||||
|
||||
class UpdateVkPost implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct(
|
||||
readonly private string $title,
|
||||
readonly private string $text,
|
||||
readonly private array $images = [],
|
||||
readonly private int $post_id,
|
||||
readonly private int $publish_date,
|
||||
)
|
||||
{}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
try {
|
||||
$postRelation = DB::table('posts_vk_posts')->select()->where('post_id', $this->post_id)->first();
|
||||
$vkService = new VkService();
|
||||
$vkService->updatePost($postRelation->vk_post_id, $this->title, $this->text, $this->images, $this->publish_date);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Ошибка при создании поста: ' . $e->getMessage());
|
||||
throw $e; // Перебрасываем исключение для повторной попытки
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -76,6 +76,9 @@ class AcceptInvitation extends SimplePage
|
||||
'email' => $this->invitationModel->email,
|
||||
]);
|
||||
|
||||
$user->assignRole(config('filament-shield.invited_user.name', 'invited_user'));
|
||||
|
||||
|
||||
AcceptedInvitation::create([
|
||||
'sender_id' => $this->invitationModel->user_id,
|
||||
'receiver_id' => $user->id,
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class PageReferenceList extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = false;
|
||||
|
||||
protected $casts = [
|
||||
'content' => 'array',
|
||||
];
|
||||
}
|
||||
+1
-2
@@ -15,13 +15,12 @@ class Post extends Model
|
||||
|
||||
protected $guarded = false;
|
||||
|
||||
|
||||
|
||||
public function category() : BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Category::class);
|
||||
}
|
||||
|
||||
|
||||
public function seo()
|
||||
{
|
||||
return $this->morphOne(Seo::class, 'seoable');
|
||||
|
||||
+3
-1
@@ -106,7 +106,9 @@ class User extends Authenticatable implements FilamentUser
|
||||
case "admin":
|
||||
return $this->hasRole(Utils::getSuperAdminName());
|
||||
case "dashboard":
|
||||
return $this->hasRole(config('filament-shield.dashboard_user.name', 'dashboard_user')) || $this->hasRole(Utils::getSuperAdminName());
|
||||
return $this->hasRole(config('filament-shield.dashboard_user.name', 'dashboard_user'))
|
||||
|| $this->hasRole(Utils::getSuperAdminName())
|
||||
|| $this->hasRole(config('filament-shield.invited_user.name', 'invited_user'));
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\PageReferenceList;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class PageReferenceListPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return $user->can('view_any_page::reference::list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*/
|
||||
public function view(User $user, PageReferenceList $pageReferenceList): bool
|
||||
{
|
||||
return $user->can('view_page::reference::list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*/
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return $user->can('create_page::reference::list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*/
|
||||
public function update(User $user, PageReferenceList $pageReferenceList): bool
|
||||
{
|
||||
return $user->can('update_page::reference::list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*/
|
||||
public function delete(User $user, PageReferenceList $pageReferenceList): bool
|
||||
{
|
||||
return $user->can('delete_page::reference::list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can bulk delete.
|
||||
*/
|
||||
public function deleteAny(User $user): bool
|
||||
{
|
||||
return $user->can('delete_any_page::reference::list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete.
|
||||
*/
|
||||
public function forceDelete(User $user, PageReferenceList $pageReferenceList): bool
|
||||
{
|
||||
return $user->can('force_delete_page::reference::list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently bulk delete.
|
||||
*/
|
||||
public function forceDeleteAny(User $user): bool
|
||||
{
|
||||
return $user->can('force_delete_any_page::reference::list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore.
|
||||
*/
|
||||
public function restore(User $user, PageReferenceList $pageReferenceList): bool
|
||||
{
|
||||
return $user->can('restore_page::reference::list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can bulk restore.
|
||||
*/
|
||||
public function restoreAny(User $user): bool
|
||||
{
|
||||
return $user->can('restore_any_page::reference::list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can replicate.
|
||||
*/
|
||||
public function replicate(User $user, PageReferenceList $pageReferenceList): bool
|
||||
{
|
||||
return $user->can('replicate_page::reference::list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can reorder.
|
||||
*/
|
||||
public function reorder(User $user): bool
|
||||
{
|
||||
return $user->can('reorder_page::reference::list');
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ class RolePolicy
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return $user->can('view_any_role');
|
||||
return $user->can('view_any_shield::role');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -23,7 +23,7 @@ class RolePolicy
|
||||
*/
|
||||
public function view(User $user, Role $role): bool
|
||||
{
|
||||
return $user->can('view_role');
|
||||
return $user->can('view_shield::role');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,7 +31,7 @@ class RolePolicy
|
||||
*/
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return $user->can('create_role');
|
||||
return $user->can('create_shield::role');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,7 +39,7 @@ class RolePolicy
|
||||
*/
|
||||
public function update(User $user, Role $role): bool
|
||||
{
|
||||
return $user->can('update_role');
|
||||
return $user->can('update_shield::role');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,7 +47,7 @@ class RolePolicy
|
||||
*/
|
||||
public function delete(User $user, Role $role): bool
|
||||
{
|
||||
return $user->can('delete_role');
|
||||
return $user->can('delete_shield::role');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,7 +55,7 @@ class RolePolicy
|
||||
*/
|
||||
public function deleteAny(User $user): bool
|
||||
{
|
||||
return $user->can('delete_any_role');
|
||||
return $user->can('delete_any_shield::role');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,36 +2,140 @@
|
||||
|
||||
namespace App\Services\VK\Album;
|
||||
|
||||
use App\Services\VK\VkAuthService;
|
||||
use CURLFile;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use VK\Client\VKApiClient;
|
||||
|
||||
class VkAlbumService
|
||||
{
|
||||
private VKApiClient $vk;
|
||||
private VkAuthService $vkAuthService;
|
||||
|
||||
private string $wallToken;
|
||||
private string $serviceToken;
|
||||
private string $publicId;
|
||||
private string $publicDomain;
|
||||
|
||||
public function __construct(VKApiClient $vk) {
|
||||
$this->vk = $vk;
|
||||
$this->wallToken = env('WALL_ACCESS_VK_TOKEN');
|
||||
$this->vkAuthService = new VkAuthService();
|
||||
$this->serviceToken = env('SERVICE_ACCESS_VK_KEY');
|
||||
$this->publicId = env('PUBLIC_ID');
|
||||
$this->publicDomain = env('PUBLIC_DOMAIN');
|
||||
}
|
||||
|
||||
public function getServerForUploadImages()
|
||||
public function getServerForUploadImages($album_id, $group_id)
|
||||
{
|
||||
return $this->vk->photos()->getUploadServer($this->wallToken, array(
|
||||
''
|
||||
));
|
||||
return $this->vk->photos()->getUploadServer(
|
||||
$this->vkAuthService->getToken()->access_token,
|
||||
array(
|
||||
'album_id' => $album_id,
|
||||
'group_id' => $group_id,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function uploadImagesToUploadServer($uploadUrl, $images)
|
||||
{
|
||||
// Массив для хранения локальных путей к загруженным изображениям
|
||||
$localFiles = [];
|
||||
|
||||
// Загрузка изображений из URL
|
||||
foreach ($images as $imageUrl) {
|
||||
$localFile = tempnam(sys_get_temp_dir(), 'img_') . '.webp';
|
||||
file_put_contents($localFile, file_get_contents($imageUrl));
|
||||
$localFiles[] = $localFile;
|
||||
}
|
||||
|
||||
// Подготовка данных для отправки
|
||||
$postFields = [];
|
||||
foreach ($localFiles as $index => $localFile) {
|
||||
// Добавляем файл в массив
|
||||
$postFields['file' . ($index + 1)] = new CURLFile($localFile);
|
||||
}
|
||||
|
||||
// Инициализация cURL
|
||||
$ch = curl_init();
|
||||
|
||||
// Установка параметров cURL
|
||||
curl_setopt($ch, CURLOPT_URL, $uploadUrl);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
|
||||
|
||||
// Выполнение запроса
|
||||
$response = curl_exec($ch);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
// Проверка на ошибки
|
||||
if (curl_errno($ch)) {
|
||||
return 'Ошибка cURL: ' . curl_error($ch);
|
||||
}
|
||||
|
||||
// Закрытие cURL
|
||||
|
||||
// Обработка ответа
|
||||
$responseData = json_decode($response, true);
|
||||
|
||||
|
||||
|
||||
// Удаление временных файлов
|
||||
foreach ($localFiles as $localFile) {
|
||||
unlink($localFile);
|
||||
}
|
||||
|
||||
return $responseData;
|
||||
}
|
||||
|
||||
public function saveImagesToUploadServer($albumId, $server, $photosList, $hash)
|
||||
{
|
||||
// URL для запроса
|
||||
$url = 'https://api.vk.com/method/photos.save';
|
||||
|
||||
// Подготовка данных для отправки
|
||||
$postFields = [
|
||||
'album_id' => $albumId,
|
||||
'server' => $server,
|
||||
'group_id' => env('PUBLIC_ID'),
|
||||
'photos_list' => $photosList, // Преобразуем массив в JSON-строку
|
||||
'hash' => $hash,
|
||||
'access_token' => $this->vkAuthService->getToken()->access_token,
|
||||
'v' => '5.131', // Версия API
|
||||
];
|
||||
|
||||
// Инициализация cURL
|
||||
$ch = curl_init();
|
||||
|
||||
// Установка параметров cURL
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
|
||||
|
||||
// Выполнение запроса
|
||||
$response = curl_exec($ch);
|
||||
|
||||
// Проверка на ошибки
|
||||
if (curl_errno($ch)) {
|
||||
return 'Ошибка cURL: ' . curl_error($ch);
|
||||
}
|
||||
|
||||
// Закрытие cURL
|
||||
curl_close($ch);
|
||||
|
||||
// Обработка ответа
|
||||
$responseData = json_decode($response, true);
|
||||
|
||||
return $responseData;
|
||||
}
|
||||
public function createAlbum(string $title)
|
||||
{
|
||||
try {
|
||||
return $this->vk->photos()->createAlbum($this->wallToken, array(
|
||||
return $this->vk->photos()->createAlbum($this->vkAuthService->getToken()->access_token, array(
|
||||
'title' => $title,
|
||||
'group_id' => $this->publicId,
|
||||
'privacy' => 0,
|
||||
@@ -46,4 +150,20 @@ class VkAlbumService
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteAlbum(int $album_id, int $group_id)
|
||||
{
|
||||
try {
|
||||
return $this->vk->photos()->deleteAlbum($this->vkAuthService->getToken()->access_token, array(
|
||||
'album_id' => $album_id,
|
||||
'group_id' => $group_id,
|
||||
));
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Ошибка при удалении альбома: ' . $e->getMessage());
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Не удалось удалить альбом: ' . $e->getMessage(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\VK;
|
||||
|
||||
use App\Services\VK\Album\VkAlbumService;
|
||||
use App\Services\VK\Wall\VkWallService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use VK\Client\VKApiClient;
|
||||
|
||||
class VkAuthService
|
||||
{
|
||||
|
||||
public function getToken()
|
||||
{
|
||||
try {
|
||||
// Получаем последний токен
|
||||
$token = DB::table('vk_tokens')->latest()->first();
|
||||
|
||||
// Проверяем, существует ли токен и является ли он валидным
|
||||
if ($token && !$this->isTokenValid($token)) {
|
||||
// Если токен не валиден, обновляем его
|
||||
return $this->refresh();
|
||||
}
|
||||
return $token;
|
||||
} catch (\Exception $e) {
|
||||
// Обработка ошибок, например, логирование
|
||||
Log::error('Ошибка при получении токена: ' . $e->getMessage());
|
||||
return null; // Или выбросьте исключение, если это необходимо
|
||||
}
|
||||
}
|
||||
|
||||
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', // Укажите необходимые права доступа
|
||||
'code_challenge' => $code_challenge, // Добавьте код, если используете PKCE
|
||||
'code_challenge_method' => 's256',
|
||||
]);
|
||||
|
||||
return redirect($url);
|
||||
}
|
||||
|
||||
public function handleProviderCallback(Request $request)
|
||||
{
|
||||
$this->validateState($request);
|
||||
$codeVerifier = session('vk_code_verifier');
|
||||
|
||||
$tokenData = $this->exchangeCodeForTokens($request, $codeVerifier);
|
||||
|
||||
|
||||
if (isset($tokenData->error)) {
|
||||
return response()->json(['error' => $tokenData->error_description], 400);
|
||||
}
|
||||
|
||||
return $this->storeTokenData($tokenData, $request);
|
||||
}
|
||||
|
||||
public function refresh()
|
||||
{
|
||||
$token = DB::table('vk_tokens')->latest()->first();
|
||||
$newTokenData = $this->refreshToken($token->refresh_token, bin2hex(random_bytes(16)), $token->device_id);
|
||||
return $this->storeRefreshTokenData($newTokenData['data']);
|
||||
}
|
||||
|
||||
public function logout()
|
||||
{
|
||||
session()->forget('vk_state');
|
||||
session()->forget('vk_code_verifier');
|
||||
|
||||
return redirect('/'); // Перенаправление на главную страницу
|
||||
}
|
||||
|
||||
private function exchangeCodeForTokens(Request $request, $codeVerifier)
|
||||
{
|
||||
return Http::asForm()->post('https://id.vk.com/oauth2/auth', [
|
||||
'grant_type' => 'authorization_code',
|
||||
'code_verifier' => $codeVerifier,
|
||||
'redirect_uri' => env('VK_REDIRECT_URI_AFTER_AUTH'),
|
||||
'code' => $request->code,
|
||||
'client_id' => env('VK_APP_ID'),
|
||||
'device_id' => $request->device_id,
|
||||
'state' => $request->state,
|
||||
'scope' => 'photos wall',
|
||||
])->object();
|
||||
}
|
||||
|
||||
private function refreshToken($refresh_token, $state, $device_id)
|
||||
{
|
||||
$response = Http::asForm()->post('https://id.vk.com/oauth2/auth', [
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refresh_token,
|
||||
'client_id' => env('VK_APP_ID'),
|
||||
'device_id' => $device_id,
|
||||
'state' => $state,
|
||||
'scope' => 'photos wall',
|
||||
]);
|
||||
|
||||
if ($response->failed()) {
|
||||
// Обработка ошибок
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => $response->json(), // Возвращаем детали ошибки
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => $response->object(), // Успешный ответ
|
||||
];
|
||||
}
|
||||
|
||||
private function storeTokenData($tokenData, Request $request)
|
||||
{
|
||||
try {
|
||||
DB::table('vk_tokens')->updateOrInsert(
|
||||
['user_id' => $tokenData->user_id],
|
||||
[
|
||||
'user_id' => $tokenData->user_id,
|
||||
'access_token' => $tokenData->access_token,
|
||||
'refresh_token' => $tokenData->refresh_token,
|
||||
'id_token' => $tokenData->id_token,
|
||||
'state' => $tokenData->state,
|
||||
'scope' => $tokenData->scope,
|
||||
'device_id' => $request->device_id,
|
||||
'token_expire' => Carbon::createFromTimestamp(Carbon::now()->timestamp + $tokenData->expires_in),
|
||||
'updated_at' => now(),
|
||||
]
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Ошибка при обновлении или вставке токена: ' . $e->getMessage());
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Произошла ошибка при обновлении или создания токена.',
|
||||
'error_message' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
|
||||
return redirect('/'); // Перенаправление после успешной авторизации
|
||||
}
|
||||
|
||||
private function storeRefreshTokenData($tokenData)
|
||||
{
|
||||
try {
|
||||
// Обновляем запись и получаем количество затронутых строк
|
||||
$updatedRows = DB::table('vk_tokens')->where('user_id', $tokenData->user_id)->update(
|
||||
[
|
||||
'access_token' => $tokenData->access_token,
|
||||
'refresh_token' => $tokenData->refresh_token,
|
||||
'state' => $tokenData->state,
|
||||
'scope' => $tokenData->scope,
|
||||
'token_expire' => Carbon::createFromTimestamp(Carbon::now()->timestamp + $tokenData->expires_in),
|
||||
'updated_at' => now(),
|
||||
]
|
||||
);
|
||||
|
||||
// Если обновление прошло успешно, получаем обновленную запись
|
||||
if ($updatedRows > 0) {
|
||||
return DB::table('vk_tokens')->where('user_id', $tokenData->user_id)->first();
|
||||
}
|
||||
|
||||
// Если запись не найдена, можно вернуть null или выбросить исключение
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Запись не найдена для обновления.',
|
||||
], 404);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Ошибка при обновлении токена: ' . $e->getMessage());
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Произошла ошибка при обновлении токена.',
|
||||
'error_message' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
private function generateCodeVerifier($length = 128)
|
||||
{
|
||||
return bin2hex(random_bytes($length / 2));
|
||||
}
|
||||
|
||||
private function generateCodeChallenge($code_verifier)
|
||||
{
|
||||
return rtrim(strtr(base64_encode(hash('sha256', $code_verifier, true)), '+/', '-_'), '=');
|
||||
}
|
||||
|
||||
private function validateState(Request $request)
|
||||
{
|
||||
if ($request->input('state') !== session('vk_state')) {
|
||||
abort(403, 'Invalid state');
|
||||
}
|
||||
}
|
||||
|
||||
private function isTokenValid($token)
|
||||
{
|
||||
if (Carbon::now() > $token->token_expire) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -10,9 +10,12 @@ class VkService
|
||||
{
|
||||
protected VkWallService $wallService;
|
||||
protected VkAlbumService $albumService;
|
||||
public function __construct(VKApiClient $vk) {
|
||||
protected int $public_id;
|
||||
public function __construct() {
|
||||
$vk = new VKApiClient();
|
||||
$this->wallService = new VkWallService($vk);
|
||||
$this->albumService = new VkAlbumService($vk);
|
||||
$this->public_id = env('PUBLIC_ID');
|
||||
}
|
||||
|
||||
public function getPosts(int $count = 10)
|
||||
@@ -20,14 +23,70 @@ class VkService
|
||||
return $this->wallService->getPosts($count);
|
||||
}
|
||||
|
||||
public function createPost(string $message, int $from_group = 1)
|
||||
public function getPostById(int $id)
|
||||
{
|
||||
return $this->wallService->createPost($message, $from_group);
|
||||
return $this->wallService->getPostById($id);
|
||||
}
|
||||
|
||||
public function createAlbum(string $title)
|
||||
public function createPost(string $title, string $message, array $images = [], int $publish_date = null)
|
||||
{
|
||||
return $this->albumService->createAlbum($title);
|
||||
$from_group = 1;
|
||||
$album_attachment = '';
|
||||
if ($images !== []) {
|
||||
$album = $this->createAlbum($title, $images);
|
||||
$album_attachment = $this->createAlbumAttachmentParam($album['id']);
|
||||
}
|
||||
|
||||
return $this->wallService->createPost($message, $from_group, $album_attachment, $publish_date);
|
||||
}
|
||||
|
||||
public function updatePost(int $id, string $title, string $message, array $images = [], int $publish_date = null)
|
||||
{
|
||||
$from_group = 1;
|
||||
$vk_post = $this->wallService->getPostById($id);
|
||||
$album_attachment = '';
|
||||
if ($vk_post['attachments']) {
|
||||
if ($this->getAlbumAttachment($vk_post['attachments'])) {
|
||||
$album = $this->getAlbumAttachment($vk_post['attachments']);
|
||||
$this->albumService->deleteAlbum($album['album']['id'], $this->public_id);
|
||||
}
|
||||
}
|
||||
if ($images !== []) {
|
||||
$album = $this->createAlbum($title, $images);
|
||||
$album_attachment = $this->createAlbumAttachmentParam($album['id']);
|
||||
}
|
||||
|
||||
return $this->wallService->updatePost($id, $message, $from_group, $album_attachment, $publish_date);
|
||||
}
|
||||
|
||||
public function createAlbum(string $title, $images)
|
||||
{
|
||||
$album = $this->albumService->createAlbum($title);
|
||||
$uploadServer = $this->albumService->getServerForUploadImages($album['id'], env('PUBLIC_ID'));
|
||||
foreach (array_chunk($images, 4) as $images_slice) {
|
||||
$images_data = $this->albumService->uploadImagesToUploadServer($uploadServer['upload_url'], $images_slice);
|
||||
$this->albumService->saveImagesToUploadServer(
|
||||
$images_data['aid'],
|
||||
$images_data['server'],
|
||||
$images_data['photos_list'],
|
||||
$images_data['hash']
|
||||
);
|
||||
}
|
||||
return $album;
|
||||
}
|
||||
|
||||
private function createAlbumAttachmentParam(int $attachmentId)
|
||||
{
|
||||
return $this->wallService->generateAttachmentsParams('album', $attachmentId);
|
||||
}
|
||||
|
||||
private function getAlbumAttachment(array $attachments)
|
||||
{
|
||||
$data = collect($attachments);
|
||||
$filteredAttachment = $data->filter(function($attachment) {
|
||||
return $attachment['type'] === 'album';
|
||||
});
|
||||
return (isset($filteredAttachment[0]) ? $filteredAttachment[0] : null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
namespace App\Services\VK\Wall;
|
||||
|
||||
use App\Services\VK\VkAuthService;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use VK\Client\VKApiClient;
|
||||
|
||||
@@ -19,6 +23,8 @@ class VkWallService
|
||||
$this->serviceToken = env('SERVICE_ACCESS_VK_KEY');
|
||||
$this->publicId = env('PUBLIC_ID');
|
||||
$this->publicDomain = env('PUBLIC_DOMAIN');
|
||||
$this->vkAuthService = new VkAuthService();
|
||||
|
||||
}
|
||||
|
||||
public function getPosts(int $count)
|
||||
@@ -30,15 +36,40 @@ class VkWallService
|
||||
));
|
||||
}
|
||||
|
||||
public function createPost(string $message, int $from_group, string $attachments = '')
|
||||
public function getPostById(int $id)
|
||||
{
|
||||
$post = $this->vk->wall()->getById($this->serviceToken, array(
|
||||
'posts' => '-'. $this->publicId . '_' . $id,
|
||||
));
|
||||
return $post[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function createPost(string $message, int $from_group, string $attachments = '', int $publish_date)
|
||||
{
|
||||
$params = [
|
||||
'owner_id' => '-' . $this->publicId,
|
||||
'from_group' => $from_group,
|
||||
'message' => $message,
|
||||
'attachments' => $attachments,
|
||||
'access_token' => $this->wallToken,
|
||||
'publish_date' => $publish_date,
|
||||
'v' => '5.131',
|
||||
];
|
||||
|
||||
try {
|
||||
return $this->vk->wall()->post($this->wallToken, array(
|
||||
'owner_id' => '-' . $this->publicId,
|
||||
'from_group' => $from_group,
|
||||
'message' => $message,
|
||||
'attachments' => $attachments
|
||||
));
|
||||
$response = Http::asForm()->post('https://api.vk.com/method/wall.post', $params);
|
||||
|
||||
if ($response->successful() && isset($response['response'])) {
|
||||
return [
|
||||
'success' => true,
|
||||
'post_id' => $response['response']['post_id'],
|
||||
];
|
||||
} else {
|
||||
throw new \Exception('Ошибка API: ' . json_encode($response->json()));
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Ошибка при создании поста: ' . $e->getMessage());
|
||||
return [
|
||||
@@ -47,4 +78,58 @@ class VkWallService
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
public function updatePost(int $post_id, string $message = '', int $from_group = 1, string $attachments = '', int $publish_date)
|
||||
{
|
||||
if (empty($message) && empty($attachments)) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Необходимо указать либо сообщение, либо вложения.',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
$params = [
|
||||
'owner_id' => '-' . $this->publicId,
|
||||
'post_id' => $post_id,
|
||||
'message' => $message,
|
||||
'attachments' => $attachments,
|
||||
'access_token' => $this->wallToken,
|
||||
'v' => '5.131',
|
||||
];
|
||||
|
||||
|
||||
|
||||
|
||||
try {
|
||||
return $this->vk->wall()->edit(
|
||||
$this->vkAuthService->getToken()->access_token,
|
||||
array(
|
||||
'owner_id' => '-' . $this->publicId,
|
||||
'post_id' => $post_id,
|
||||
'message' => $message,
|
||||
'attachments' => $attachments,
|
||||
'publish_date' => $publish_date,
|
||||
),
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Ошибка при обновлении новости SDK: ' . $e->getMessage());
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Не удалось обновить новость SDK: ' . $e->getMessage(),
|
||||
];
|
||||
}
|
||||
}
|
||||
public function generateAttachmentsParams(string $attachmentType, int $attachmentId)
|
||||
{
|
||||
$pubic_id = env('PUBLIC_ID');
|
||||
switch ($attachmentType) {
|
||||
case 'album': {
|
||||
return "album-{$pubic_id}_{$attachmentId}";
|
||||
}
|
||||
case 'doc': {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user