master
sergeybodin 2023-07-10 10:09:09 +03:00
parent 4d275414d0
commit ab1eb62220
20 changed files with 529 additions and 52 deletions

View File

@ -5,6 +5,7 @@ namespace App\Http\Controllers\Api\Publications;
use App\Http\Controllers\Controller;
use App\Models\Pages\Page;
use App\Models\Publications\Publication;
use App\Models\Publications\PublicationType;
use App\Transformers\Publications\PublicationTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@ -26,7 +27,9 @@ class PublicationsController extends Controller {
$query = $this->model->query()->orderBy('id', 'desc');
$user = Auth::user();
if (!($user->isAdmin ?? null)) $query->where(['is_published' => true]);
if ($page = Page::byUuid($request->get('page'))->first()) $query->where(['page_id' => $page->id]);
if ($page = Page::byUuid($request->get('page'))->first()){
$query->where(['page_id' => $page->id]);
}
$paginator = $query->paginate(config('app.pagination_limit'));
return fractal($paginator, new PublicationTransformer())->respond();
}

View File

@ -24,6 +24,7 @@ class Page extends Model {
'parent_id',
'slug',
'type',
'sub_type',
'name',
'title',
'h1',

View File

@ -0,0 +1,17 @@
<?php
namespace App\Models\Pages;
class PageSubType {
public const PUBLICATION_NEWS = 'publication-news';
public const PUBLICATION_SMI = 'publication-smi';
public const PUBLICATION_PHOTOS = 'publication-photos';
public const PUBLICATION_VIDEO = 'publication-video';
public const TITLES = [
self::PUBLICATION_NEWS => 'Новость',
self::PUBLICATION_SMI => 'СМИ о нас',
self::PUBLICATION_PHOTOS => 'Фотогаллерея',
self::PUBLICATION_VIDEO => 'Видеоархив',
];
}

View File

@ -29,6 +29,7 @@ class Publication extends Model {
'type',
'name',
'excerpt',
'params',
'is_published'
];
@ -74,11 +75,14 @@ class Publication extends Model {
return $result;
}
public function getParsedTypeAttribute(): array {
return ['name' => $this->type, 'title' => PublicationType::TITLES[$this->type] ?? null];
}
public function getParsedParamsAttribute() {
return json_decode($this->params);
}
public function addSection($typeName, $ord = null): ?Model {

View File

@ -4,8 +4,14 @@ namespace App\Models\Publications;
class PublicationType {
public const NEWS = 'news';
public const SMI = 'smi';
public const PHOTOS = 'photos';
public const VIDEO = 'video';
public const TITLES = [
self::NEWS => 'Новость'
self::NEWS => 'Новость',
self::SMI => 'СМИ о нас',
self::PHOTOS => 'Фотогаллерея',
self::VIDEO => 'Видеоархив',
];
}

View File

@ -4,6 +4,9 @@ namespace App\Services\Forms\Publications;
class PublicationFormsServices {
public static array $services = [
'publications' => PublicationForms::class
'publication-news' => PublicationNewsForms::class,
'publication-smi' => PublicationSmiForms::class,
'publication-photos' => PublicationPhotosForms::class,
'publication-video' => PublicationVideoForms::class,
];
}

View File

@ -14,8 +14,8 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
class PublicationForms extends FormsService {
public array $formTitles = ['create' => 'Создание новой новости', 'update' => 'Редактирование новости'];
class PublicationNewsForms extends FormsService {
public array $formTitles = ['create' => 'Создание новой публикации', 'update' => 'Редактирование публикации'];
public function form(?string $id = null, array $data = []): array {
$model = Publication::byUuid($id)->first();
@ -43,7 +43,7 @@ class PublicationForms extends FormsService {
],
[
'name' => 'poster_id',
'title' => 'Фотография профиля',
'title' => 'Превью',
'type' => FieldType::IMAGE,
'value' => ($model->poster ?? null) ? fractal($model->poster, new AssetTransformer()) : null
]
@ -58,7 +58,7 @@ class PublicationForms extends FormsService {
$page = Page::byUuid($data['attach']['page_id'])->first();
$data['page_id'] = $page->id;
}
$data['user_id'] = Auth::user()->id;
$data['author_id'] = Auth::user()->id;
$data['slug'] = Str::slug(Str::transliterate($data['name']));
$data['type'] = PublicationType::NEWS;
if (!empty($data['poster_id'])) {
@ -72,6 +72,7 @@ class PublicationForms extends FormsService {
public function update(string $id, array $data): ?JsonResponse {
$model = Publication::byUuid($id)->firstOrFail();
$data['author_id'] = Auth::user()->id;
if (!empty($data['poster_id'])) {
$asset = Asset::query()->where(['uuid' => $data['poster_id']])->first();
$data['poster_id'] = $asset->id;

View File

@ -0,0 +1,94 @@
<?php
namespace App\Services\Forms\Publications;
use App\Models\Asset;
use App\Models\Objects\FieldType;
use App\Models\Pages\Page;
use App\Models\Publications\Publication;
use App\Models\Publications\PublicationType;
use App\Services\Forms\FormsService;
use App\Transformers\Assets\AssetTransformer;
use App\Transformers\Publications\PublicationTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
class PublicationPhotosForms
extends FormsService {
public array $formTitles = ['create' => 'Создание нового фотоальбома', 'update' => 'Редактирование фотоальбома'];
public function form(?string $id = null, array $data = []): array {
$model = Publication::byUuid($id)->first();
$groups = [
['name' => 'common', 'fields' => $this->commonGroupFields($model)]
];
return ['title' => $this->formTitle($model), 'data' => $groups];
}
public function commonGroupFields(?Publication $model): array {
$params = $model->parsedParams ?? null;
if (empty($params->assets)) {
$assets = [];
} else {
$models = Asset::query()->whereIn('uuid', $params->assets)->get();
$assets = fractal($models, new AssetTransformer());
}
$fields = [
[
'name' => 'name',
'title' => 'Название',
'type' => FieldType::STRING,
'required' => true,
'value' => $model->name ?? null
],
[
'name' => 'assets',
'title' => 'Фотографии',
'type' => FieldType::IMAGE,
'multiple' => true,
'required' => true,
'value' => $assets
],
];
return ['data' => $fields];
}
public function store(array $data): ?JsonResponse {
$page = Page::byUuid($data['attach']['page_id'])->first();
$pub = [];
$pub['page_id'] = $page->id;
$pub['author_id'] = Auth::user()->id;
$pub['type'] = PublicationType::PHOTOS;
$pub['name'] = $data['name'];
if (!empty($data['assets'])) {
$pub['params'] = json_encode([
'assets' => $data['assets']
]);
}
$model = Publication::create($pub, true);
return fractal($model, new PublicationTransformer())->respond();
}
public function update(string $id, array $data): ?JsonResponse {
$model = Publication::byUuid($id)->firstOrFail();
$pub = [];
if (!empty($data['name'])) {
$pub['name'] = $data['name'];
}
if (!empty($data['assets'])) {
$pub['params'] = json_encode([
'assets' => $data['assets']
]);
}
$model->update($pub);
return fractal($model, new PublicationTransformer())->respond();
}
}

View File

@ -0,0 +1,130 @@
<?php
namespace App\Services\Forms\Publications;
use App\Models\Asset;
use App\Models\Objects\FieldType;
use App\Models\Pages\Page;
use App\Models\Publications\Publication;
use App\Models\Publications\PublicationType;
use App\Services\Forms\FormsService;
use App\Transformers\Assets\AssetTransformer;
use App\Transformers\Publications\PublicationTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
class PublicationSmiForms
extends FormsService {
public array $formTitles = ['create' => 'Создание новой публикации в СМИ', 'update' => 'Редактирование публикации В СМИ'];
public function form(?string $id = null, array $data = []): array {
$model = Publication::byUuid($id)->first();
$groups = [
['name' => 'common', 'fields' => $this->commonGroupFields($model)]
];
return ['title' => $this->formTitle($model), 'data' => $groups];
}
public function commonGroupFields(?Publication $model): array {
$params = $model->parsedParams ?? null;
$fields = [
[
'name' => 'name',
'title' => 'Название',
'type' => FieldType::STRING,
'required' => true,
'value' => $model->name ?? null
],
[
'name' => 'excerpt',
'title' => 'Краткое описание',
'type' => FieldType::TEXT,
'required' => true,
'value' => $model->excerpt ?? null
],
[
'name' => 'poster_id',
'title' => 'Превью',
'type' => FieldType::IMAGE,
'value' => ($model->poster ?? null) ? fractal($model->poster, new AssetTransformer()) : null
],
[
'name' => 'url',
'title' => 'Ссылка на сторонний ресурс',
'type' => FieldType::STRING,
'required' => true,
'value' => $params->url ?? null
],
[
'name' => 'source',
'title' => 'Название источника',
'type' => FieldType::STRING,
'required' => true,
'value' => $params->source ?? null
],
];
return ['data' => $fields];
}
public function store(array $data): ?JsonResponse {
$page = Page::byUuid($data['attach']['page_id'])->first();
$pub = [];
$pub['page_id'] = $page->id;
$pub['author_id'] = Auth::user()->id;
$pub['type'] = PublicationType::SMI;
$pub['name'] = $data['name'];
$pub['excerpt'] = $data['excerpt'];
if (!empty($data['poster_id'])) {
$asset = Asset::query()->where(['uuid' => $data['poster_id']])->first();
$pub['poster_id'] = $asset->id;
}
$params = [];
if (!empty($data['url'])) {
$params['url'] = $data['url'];
}
if (!empty($data['source'])) {
$params['source'] = $data['source'];
}
if (count($params) > 0) {
$pub['params'] = json_encode($params);
}
$model = Publication::create($pub, true);
return fractal($model, new PublicationTransformer())->respond();
}
public function update(string $id, array $data): ?JsonResponse {
$model = Publication::byUuid($id)->firstOrFail();
$pub = [];
$pub['author_id'] = Auth::user()->id;
if (!empty($data['name'])) {
$pub['name'] = $data['name'];
}
if (!empty($data['name'])) {
$pub['name'] = $data['name'];
}
if (!empty($data['excerpt'])) {
$pub['excerpt'] = $data['excerpt'];
}
if (!empty($data['poster_id'])) {
$asset = Asset::query()->where(['uuid' => $data['poster_id']])->first();
$pub['poster_id'] = $asset->id;
}
$params = [];
if (!empty($data['url'])) {
$params['url'] = $data['url'];
}
if (!empty($data['source'])) {
$params['source'] = $data['source'];
}
if (count($params) > 0) {
$pub['params'] = json_encode($params);
}
$model->update($pub);
return fractal($model->fresh(), new PublicationTransformer())->respond();
}
}

View File

@ -0,0 +1,84 @@
<?php
namespace App\Services\Forms\Publications;
use App\Models\Asset;
use App\Models\Objects\FieldType;
use App\Models\Pages\Page;
use App\Models\Publications\Publication;
use App\Models\Publications\PublicationType;
use App\Services\Forms\FormsService;
use App\Transformers\Assets\AssetTransformer;
use App\Transformers\Publications\PublicationTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
class PublicationVideoForms
extends FormsService {
public array $formTitles = ['create' => 'Видео', 'update' => 'Видео'];
public function form(?string $id = null, array $data = []): array {
$model = Publication::byUuid($id)->first();
$groups = [
['name' => 'common', 'fields' => $this->commonGroupFields($model)]
];
return ['title' => $this->formTitle($model), 'data' => $groups];
}
public function commonGroupFields(?Publication $model): array {
$params = $model->parsedParams ?? null;
$fields = [
[
'name' => 'url',
'title' => 'Ссылка на видео',
'type' => FieldType::STRING,
'required' => true,
'value' => $params->url ?? null
],
[
'name' => 'excerpt',
'title' => 'Описание',
'type' => FieldType::TEXT,
'required' => true,
'value' => $model->excerpt ?? null
],
];
return ['data' => $fields];
}
public function store(array $data): ?JsonResponse {
$page = Page::byUuid($data['attach']['page_id'])->first();
$pub = [];
$pub['page_id'] = $page->id;
$pub['excerpt'] = $data['excerpt'];
$pub['author_id'] = Auth::user()->id;
$pub['type'] = PublicationType::VIDEO;
if (!empty($data['url'])) {
$pub['params'] = json_encode([
'url' => $data['url']
]);
}
$model = Publication::create($pub, true);
return fractal($model, new PublicationTransformer())->respond();
}
public function update(string $id, array $data): ?JsonResponse {
$pub = [];
if (!empty($data['excerpt'])) {
$pub['excerpt'] = $data['excerpt'];
}
if (!empty($data['url'])) {
$pub['params'] = json_encode([
'url' => $data['url']
]);
}
$model = Publication::byUuid($id)->firstOrFail();
$model->update($pub);
return fractal($model->fresh(), new PublicationTransformer())->respond();
}
}

View File

@ -26,6 +26,7 @@ class PageTransformer extends TransformerAbstract {
'slug' => $model->slug,
'link' => $model->link,
'type' => $model->parsedType,
'sub_type' => $model->sub_type,
'name' => $model->name,
'title' => $model->title,
'h1' => $model->h1,

View File

@ -2,8 +2,10 @@
namespace App\Transformers\Publications;
use App\Models\Asset;
use App\Models\Pages\Page;
use App\Models\Publications\Publication;
use App\Models\Publications\PublicationType;
use App\Services\PermissionsService;
use App\Transformers\Assets\AssetTransformer;
use App\Transformers\Objects\ObjectTransformer;
@ -24,18 +26,28 @@ class PublicationTransformer extends TransformerAbstract {
];
public function transform(Publication $model): array {
return [
$params = $model->parsedParams;
$result = [
'id' => $model->uuid,
'slug' => $model->slug,
'link' => $model->link,
'type' => 'publication',
'subtype' => $model->parsedType,
'params' => $params,
'name' => $model->name,
'excerpt' => $model->excerpt,
'is_published' => boolval($model->is_published),
'created_at' => $model->created_at ? $model->created_at->toIso8601String() : null,
'updated_at' => $model->updated_at ? $model->updated_at->toIso8601String() : null
];
if ($model->parsedType['name'] === PublicationType::PHOTOS && $params->assets) {
$models = Asset::query()->whereIn('uuid', $params->assets)->get();
$result['assets'] = fractal($models, new AssetTransformer());
}
return $result;
}
public function includePage(Publication $model): ?Item {
@ -47,7 +59,7 @@ class PublicationTransformer extends TransformerAbstract {
}
public function includePoster(Publication $model): ?Item {
return $model->poster ? $this->item($model->poster, new AssetTransformer()) : null;
return $model->poster ? $this->item($model->poster, new AssetTransformer()) : null;
}
public function includeAuthor(Publication $model): ?Item {

View File

@ -19,6 +19,7 @@ class CreatePagesTable extends Migration
$table->integer('parent_id')->index()->default(0);
$table->string('slug')->index()->nullable();
$table->string('type')->index()->nullable();
$table->string('sub_type')->index()->nullable();
$table->string('name')->index()->nullable();
$table->string('title')->index()->nullable();
$table->string('h1')->index()->nullable();

View File

@ -23,6 +23,7 @@ class CreatePublicationsTable extends Migration
$table->string('type')->index()->nullable();
$table->string('name')->index()->nullable();
$table->text('excerpt')->nullable();
$table->text('params')->nullable();
$table->boolean('is_published')->index()->default(0);
$table->timestamps();
$table->softDeletes();

View File

@ -1,32 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddDescriptionToPublicationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('publications', function (Blueprint $table) {
$table->addColumn('text', 'description')->after('excerpt')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('publications', function (Blueprint $table) {
$table->dropColumn('description');
});
}
}

View File

@ -10,6 +10,16 @@ class DictionariesTableSeeder extends Seeder {
'list-types' => [
'title' => 'Виды списка',
'items' => ['marked' => 'Маркированный', 'numeric' => 'Нумерованный']
],
'title-types' => [
'title' => 'Виды заголовков',
'items' => ['h2' => 'Заголовок 1', 'h3' => 'Заголовок 2', 'h4' => 'Заголовок 3']
],
'feedback-types' => [
'title' => 'Тема обращения',
'items' => [
'regulation' => 'Техническое нормирование', 'assessment' => 'Оценка пригодности', 'certification' => 'Добровольная сертификация', 'questions' => 'Вопросы нормирования и стандартизации', 'other' => 'Другие'
]
]
];

View File

@ -14,6 +14,15 @@ class FieldsTableSeeder extends Seeder {
'title' => 'Текст заголовка',
'type' => FieldType::TEXT
],
'header-type' => [
'title' => 'Тип заголовка',
'type' => FieldType::RELATION,
'required' => true,
'params' => [
'related' => DictionaryItem::class, 'transformer' => DictionaryItemTransformer::class,
'options' => ['show' => true, 'whereHas' => ['dictionary' => ['name' => 'title-types']]]
]
],
'header-required' => [
'title' => 'Текст заголовка',
'type' => FieldType::TEXT,
@ -74,7 +83,84 @@ class FieldsTableSeeder extends Seeder {
'title' => 'Ссылка на видео',
'type' => FieldType::STRING,
'required' => true
]
],
'button-title' => [
'title' => 'Текст',
'type' => FieldType::STRING,
'required' => true
],
'button-url' => [
'title' => 'Ссылка на кнопку',
'type' => FieldType::STRING,
'required' => true
],
'iframe-url' => [
'title' => 'Ссылка',
'type' => FieldType::STRING,
'required' => true
],
'contact-name' => [
'title' => 'Наименование',
'type' => FieldType::STRING,
],
'contact-legal-address' => [
'title' => 'Юридический адрес',
'type' => FieldType::STRING,
],
'contact-location-address' => [
'title' => 'Фактический адрес',
'type' => FieldType::STRING,
],
'contact-email' => [
'title' => 'Email',
'type' => FieldType::STRING,
],
'contact-phone' => [
'title' => 'Телефон',
'type' => FieldType::STRING,
],
'contact-description' => [
'title' => 'Информация',
'type' => FieldType::HTML,
],
'feddback-email-admin' => [
'title' => 'Email кому будет отправлен ответ',
'type' => FieldType::STRING,
'required' => true,
'showForm' => 'first'
],
'feedback-email-user' => [
'title' => 'Email',
'type' => FieldType::STRING,
'required' => true,
'showForm' => 'second'
],
'feedback-name' => [
'title' => 'Ваше имя',
'type' => FieldType::STRING,
'required' => true,
'showForm' => 'second'
],
'feedback-type' => [
'title' => 'Тема обращения',
'type' => FieldType::RELATION,
'required' => true,
'showForm' => 'second',
'params' => [
'related' => DictionaryItem::class, 'transformer' => DictionaryItemTransformer::class,
'options' => ['show' => true, 'whereHas' => ['dictionary' => ['name' => 'feedback-types']]]
]
],
'feedback-message' => [
'title' => 'Текст сообщения',
'type' => FieldType::TEXT,
'required' => true,
'showForm' => 'second',
],
];
public function run() {

View File

@ -11,13 +11,13 @@ class ObjectTypeFieldsTableSeeder extends Seeder {
public array $objectTypeFields = [
'page-sidebar' => [
'common' => [
'fields' => ['header', 'text', 'documents']
'fields' => ['header', 'html', 'documents']
]
],
'page-section-header' => [
'common' => [
'fields' => ['header-required']
'fields' => ['header-type', 'header-required']
]
],
'page-section-html' => [
@ -44,8 +44,27 @@ class ObjectTypeFieldsTableSeeder extends Seeder {
'common' => [
'fields' => ['video-url']
]
],
'page-section-button' => [
'common' => [
'fields' => ['button-title', 'button-url']
]
],
'page-section-iframe' => [
'common' => [
'fields' => ['iframe-url']
]
],
'page-section-contacts' => [
'common' => [
'fields' => ['contact-name', 'contact-legal-address', 'contact-location-address', 'contact-email', 'contact-phone', 'contact-description']
]
],
'page-section-feedback' => [
'common' => [
'fields' => ['feddback-email-admin', 'feedback-email-user', 'feedback-name', 'feedback-type', 'feedback-message']
]
]
];
public function run() {

View File

@ -31,6 +31,18 @@ class ObjectTypesTableSeeder extends Seeder {
],
'page-section-video' => [
'title' => 'Видео'
],
'page-section-button' => [
'title' => 'Кнопка'
],
'page-section-iframe' => [
'title' => 'Интерактивное окно'
],
'page-section-contacts' => [
'title' => 'Контактная информация'
],
'page-section-feedback' => [
'title' => 'Форма обратной связи'
]
]
],

View File

@ -3,6 +3,7 @@
namespace Database\Seeders\Pages;
use App\Models\Pages\Page;
use App\Models\Pages\PageSubType;
use App\Models\Pages\PageType;
use Illuminate\Database\Seeder;
use Illuminate\Support\Str;
@ -121,14 +122,33 @@ class PagesTableSeeder extends Seeder
],
'Пресс-центр' => [
'children' => [
'Новости' => ['type' => PageType::PUBLICATIONS],
'СМИ о нас' => ['type' => PageType::REGISTRY],
'Фотогалерея' => ['type' => PageType::PUBLICATIONS],
'Видеоархив' => ['type' => PageType::PUBLICATIONS],
'Новости' => [
'type' => PageType::PUBLICATIONS,
'sub_type' => PageSubType::PUBLICATION_NEWS
],
'СМИ о нас' => [
'type' => PageType::PUBLICATIONS,
'sub_type' => PageSubType::PUBLICATION_SMI
],
'Фотогалерея' => [
'type' => PageType::PUBLICATIONS,
'sub_type' => PageSubType::PUBLICATION_PHOTOS
],
'Видеоархив' => [
'type' => PageType::PUBLICATIONS,
'sub_type' => PageSubType::PUBLICATION_VIDEO
],
'Контакты для СМИ' => [],
]
],
'Контакты' => []
'Контакты' => [
'children' => [
'Контактные данные' => [],
'Как добраться' => [],
'Консультации' => [],
'Обратная связь' => [],
]
]
];
public function run()
@ -144,7 +164,11 @@ class PagesTableSeeder extends Seeder
{
$slug = Str::slug(Str::transliterate($name));
$page = Page::firstOrCreate(['parent_id' => $parent->id ?? 0, 'slug' => $slug]);
$page->update(['name' => $name, 'type' => $data['type'] ?? PageType::CONTENT]);
$page->update([
'name' => $name,
'type' => $data['type'] ?? PageType::CONTENT,
'sub_type' => $data['sub_type'] ?? null
]);
if ($v = collect($data)->except('children')->all()) $page->update($v);
$ord = 0;
collect($data['children'] ?? [])->each(function ($data, $name) use ($page, &$ord) {