Added the ability to add project information.
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\About;
|
||||
|
||||
use App\Dto\Service\Dto;
|
||||
|
||||
final readonly class StoreUpdate extends Dto
|
||||
{
|
||||
public function __construct(
|
||||
private string $title,
|
||||
private string $description,
|
||||
) { }
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
}
|
@@ -8,6 +8,7 @@ enum Permission: string
|
||||
case Role = 'role';
|
||||
case User = 'user';
|
||||
case Project = 'project';
|
||||
case ProjectContent = 'project-content';
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
@@ -15,6 +16,11 @@ enum Permission: string
|
||||
self::AdminPanel => [
|
||||
'view' => __('permissions.Administrative panel allowed'),
|
||||
],
|
||||
self::ProjectContent => [
|
||||
'view' => __('permissions.Allowed to watch'),
|
||||
'create' => __('permissions.Allowed to create'),
|
||||
'update' => __('permissions.Allowed to edit'),
|
||||
],
|
||||
default => $this->getBasePermissions()
|
||||
};
|
||||
|
||||
|
@@ -0,0 +1,54 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Admin\Projects;
|
||||
|
||||
use App\Http\Controllers\Admin\Controller;
|
||||
use App\Http\Requests\Admin\Projects\About\StoreUpdateRequest;
|
||||
use App\Services\Admin\Project\AboutService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class AboutController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AboutService $aboutService,
|
||||
) { }
|
||||
|
||||
public function languages(int $project, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->aboutService->languages($project, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/about/languages', $result->getData());
|
||||
}
|
||||
|
||||
public function edit(int $project, int $language, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->aboutService->edit($project, $language, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/about/edit', $result->getData());
|
||||
}
|
||||
|
||||
public function update(int $project, int $language, StoreUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getDto();
|
||||
$user = $request->user();
|
||||
$result = $this->aboutService->storeOrUpdate($project, $language, $data, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.about.edit', [
|
||||
'project' => $project,
|
||||
'language' => $language,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
}
|
@@ -34,6 +34,17 @@ final class ProjectsController extends Controller
|
||||
return view('admin/projects/index', $result->getData());
|
||||
}
|
||||
|
||||
public function show(int $id, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->projectService->show($id, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/show', $result->getData());
|
||||
}
|
||||
|
||||
public function create(Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
|
@@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\About;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Service\Admin\Project\About\StoreUpdate;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'title' => ['required', 'string', 'max:255',],
|
||||
'description' => ['nullable', 'string',],
|
||||
];
|
||||
}
|
||||
|
||||
public function getDto(): StoreUpdate
|
||||
{
|
||||
return new StoreUpdate(
|
||||
title: $this->input('title'),
|
||||
description: $this->input('description'),
|
||||
);
|
||||
}
|
||||
}
|
@@ -47,4 +47,9 @@ final class Project extends Model implements StorageContract
|
||||
{
|
||||
return $this->hasMany(ProjectLanguage::class);
|
||||
}
|
||||
|
||||
public function contents(): HasMany
|
||||
{
|
||||
return $this->hasMany(ProjectContent::class);
|
||||
}
|
||||
}
|
||||
|
19
app/application/app/Models/ProjectContent.php
Normal file
19
app/application/app/Models/ProjectContent.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
final class ProjectContent extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $table = 'project_content';
|
||||
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'description',
|
||||
];
|
||||
}
|
29
app/application/app/Policies/ProjectContentPolicy.php
Normal file
29
app/application/app/Policies/ProjectContentPolicy.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\ProjectContent;
|
||||
use App\Models\User;
|
||||
|
||||
final readonly class ProjectContentPolicy extends Policy
|
||||
{
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('project-content.view');
|
||||
}
|
||||
|
||||
public function view(User $user, ProjectContent $projectContent): bool
|
||||
{
|
||||
return $user->hasPermission('project-content.view');
|
||||
}
|
||||
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('project-content.create');
|
||||
}
|
||||
|
||||
public function update(User $user, ProjectContent $projectContent): bool
|
||||
{
|
||||
return $user->hasPermission('project-content.update');
|
||||
}
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\ProjectContent;
|
||||
|
||||
final class ProjectContentRepository
|
||||
{
|
||||
public function getContentByLanguageId(int $projectId, int $languageId): ?ProjectContent
|
||||
{
|
||||
return ProjectContent::query()
|
||||
->where(['project_id' => $projectId, 'language_id' => $languageId])
|
||||
->first();
|
||||
}
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\ProjectLanguage;
|
||||
|
||||
final class ProjectLanguageRepository
|
||||
{
|
||||
public function isExistsLanguageById(int $projectId, int $languageId): bool
|
||||
{
|
||||
return ProjectLanguage::query()
|
||||
->where(['id' => $languageId, 'project_id' => $projectId])
|
||||
->exists();
|
||||
}
|
||||
}
|
132
app/application/app/Services/Admin/Project/AboutService.php
Normal file
132
app/application/app/Services/Admin/Project/AboutService.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Admin\Project;
|
||||
|
||||
use App\Contracts\ServiceResultError;
|
||||
use App\Dto\Service\Admin\Project\About\StoreUpdate;
|
||||
use App\Models\ProjectContent;
|
||||
use App\Models\User;
|
||||
use App\Repositories\ProjectContentRepository;
|
||||
use App\Repositories\ProjectLanguageRepository;
|
||||
use App\Repositories\ProjectRepository;
|
||||
use App\ServiceResults\ServiceResultArray;
|
||||
use App\ServiceResults\StoreUpdateResult;
|
||||
use App\Services\ProjectContent\ProjectContentCommandHandler;
|
||||
use App\Services\Service;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
final class AboutService extends Service
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ProjectRepository $projectRepository,
|
||||
private readonly ProjectLanguageRepository $projectLanguageRepository,
|
||||
private readonly ProjectContentRepository $projectContentRepository,
|
||||
private readonly ProjectContentCommandHandler $projectContentCommandHandler,
|
||||
) { }
|
||||
|
||||
public function languages(int $projectId, User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
$project = $this->projectRepository->getProjectById($projectId);
|
||||
|
||||
if (is_null($project)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('viewAny', ProjectContent::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
return $this->result([
|
||||
'project' => $project,
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(int $projectId, int $languageId, User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
$project = $this->projectRepository->getProjectById($projectId);
|
||||
$language = $project?->languages()->firstWhere('id', $languageId);
|
||||
|
||||
if (\is_null($project) || \is_null($language)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
$content = $project->contents()->firstWhere('language_id', $languageId);
|
||||
if (\is_null($content)) {
|
||||
if ($user->cannot('create', ProjectContent::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
$content = new ProjectContent();
|
||||
$content->project_id = $project->id;
|
||||
$content->language_id = $language->id;
|
||||
} else if($user->cannot('update', $content)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
return $this->result([
|
||||
'project' => $project,
|
||||
'language' => $language,
|
||||
'content' => $content,
|
||||
]);
|
||||
}
|
||||
|
||||
public function storeOrUpdate(int $projectId, int $languageId, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
|
||||
{
|
||||
if (! $this->projectLanguageRepository->isExistsLanguageById($projectId, $languageId)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
$content = $this->projectContentRepository->getContentByLanguageId($projectId, $languageId);
|
||||
if (is_null($content)) {
|
||||
return $this->store($projectId, $languageId, $data, $user);
|
||||
}
|
||||
|
||||
return $this->update($content, $data, $user);
|
||||
}
|
||||
|
||||
private function store(int $projectId, int $languageId, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
|
||||
{
|
||||
if ($user->cannot('create', ProjectContent::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
try {
|
||||
$aboutProject = DB::transaction(function () use ($data, $projectId, $languageId) {
|
||||
$dataAboutProject = $this->getDataAboutProject($data);
|
||||
|
||||
return $this->projectContentCommandHandler->handleStore($projectId, $languageId, $dataAboutProject);
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->resultStoreUpdateModel($aboutProject, __('Project information has been successfully updated'));
|
||||
}
|
||||
|
||||
private function update(ProjectContent $content, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
|
||||
{
|
||||
if ($user->cannot('update', $content)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
try {
|
||||
$aboutProject = DB::transaction(function () use ($data, $content) {
|
||||
$dataAboutProject = $this->getDataAboutProject($data);
|
||||
|
||||
return $this->projectContentCommandHandler->handleUpdate($content, $dataAboutProject);
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->resultStoreUpdateModel($aboutProject, __('Project information has been successfully updated'));
|
||||
}
|
||||
|
||||
private function getDataAboutProject(StoreUpdate $data): array
|
||||
{
|
||||
return [
|
||||
'title' => $data->getTitle(),
|
||||
'description' => $data->getDescription(),
|
||||
];
|
||||
}
|
||||
}
|
@@ -50,6 +50,23 @@ final class ProjectService extends Service
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(int $id, User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
$project = $this->projectRepository->getProjectById($id);
|
||||
|
||||
if (is_null($project)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('view', $project)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
return $this->result([
|
||||
'project' => $project,
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
if ($user->cannot('create', Project::class)) {
|
||||
|
@@ -0,0 +1,27 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\ProjectContent;
|
||||
|
||||
use App\Models\ProjectContent;
|
||||
|
||||
final readonly class ProjectContentCommandHandler
|
||||
{
|
||||
public function handleStore(int $projectId, int $languageId, array $data): ProjectContent
|
||||
{
|
||||
$content = new ProjectContent();
|
||||
$content->project_id = $projectId;
|
||||
$content->language_id = $languageId;
|
||||
|
||||
$content->fill($data);
|
||||
$content->save();
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function handleUpdate(ProjectContent $content, array $data): ProjectContent
|
||||
{
|
||||
$content->update($data);
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
43
app/application/app/View/Components/Volt/Forms/Textarea.php
Normal file
43
app/application/app/View/Components/Volt/Forms/Textarea.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\View\Components\Volt\Forms;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class Textarea extends Form
|
||||
{
|
||||
public function __construct(
|
||||
private readonly string $title,
|
||||
private readonly string $name,
|
||||
private readonly ?string $value = '',
|
||||
) { }
|
||||
|
||||
protected function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
private function getTitle(): string
|
||||
{
|
||||
return Str::ucfirst($this->title);
|
||||
}
|
||||
|
||||
private function getValue(): string
|
||||
{
|
||||
return (string) old($this->getRequestName(), $this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function render(): View
|
||||
{
|
||||
return view('components.volt.forms.textarea', [
|
||||
'title' => $this->getTitle(),
|
||||
'name' => $this->getName(),
|
||||
'requestName' => $this->getRequestName(),
|
||||
'value' => $this->getValue(),
|
||||
]);
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\View\Components\Volt\Forms;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class TextareaWysiwyg extends Form
|
||||
{
|
||||
public function __construct(
|
||||
private readonly string $title,
|
||||
private readonly string $name,
|
||||
private readonly ?string $value = '',
|
||||
) { }
|
||||
|
||||
protected function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
private function getTitle(): string
|
||||
{
|
||||
return Str::ucfirst($this->title);
|
||||
}
|
||||
|
||||
private function getValue(): string
|
||||
{
|
||||
return (string) old($this->getRequestName(), $this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function render(): View
|
||||
{
|
||||
$tinymceLicenseKey = config('tinymce.license_key');
|
||||
|
||||
return view('components.volt.forms.textarea-wysiwyg', [
|
||||
'tinymceLicenseKey' => $tinymceLicenseKey,
|
||||
'title' => $this->getTitle(),
|
||||
'name' => $this->getName(),
|
||||
'requestName' => $this->getRequestName(),
|
||||
'value' => $this->getValue(),
|
||||
]);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user