Compare commits
58 Commits
Author | SHA1 | Date | |
---|---|---|---|
d4174cf7d2
|
|||
de496eaea1
|
|||
94db6aa51d
|
|||
c33fcd1d7c
|
|||
3d4bef0e56
|
|||
19b0e68b8b
|
|||
ba74aa9977
|
|||
224240708d
|
|||
4049f9df53
|
|||
c112b225dc
|
|||
e3194cef48
|
|||
41a7343338
|
|||
90aa909b7f
|
|||
8b35a5691f
|
|||
844264fb62
|
|||
d8d17064d0
|
|||
4dc6060fb3
|
|||
58a256e1e4
|
|||
25faa3d62b
|
|||
c4817a675a
|
|||
cb2161356e
|
|||
b729d057a9
|
|||
d36507b180
|
|||
8159145e07
|
|||
4e414a952e
|
|||
3902f5d36f
|
|||
46da639055
|
|||
c84ed9f12b
|
|||
dde792b97a
|
|||
618c925dfa
|
|||
8bc4c0d8d0
|
|||
a5e3c5ed25
|
|||
22bb840705
|
|||
707762d29b
|
|||
b33362a235
|
|||
4d36821ecc
|
|||
da5201dd9a
|
|||
2910509218
|
|||
74f7b88bce
|
|||
6998424b78
|
|||
05f566c115
|
|||
c5fc106761
|
|||
d7dc80cca4
|
|||
6d3891979c
|
|||
f986e0396d
|
|||
9f6924935d
|
|||
e74456ee2f
|
|||
42701a24db
|
|||
78e6a1e396
|
|||
b6e1c50486
|
|||
3bc508b8b0
|
|||
21026cdf52
|
|||
45504791c0
|
|||
156d8a9f68
|
|||
478cbe4762
|
|||
35c2368ae2
|
|||
303af6f203
|
|||
1485180e20
|
@@ -1,5 +1,6 @@
|
||||
DOCKER_APP_PORT=8080
|
||||
DOCKER_CAPTCHA_PORT=8081
|
||||
DOCKER_CAPTCHA_WEBSOCKET_PORT=8082
|
||||
DOCKER_DB_PORT=3306
|
||||
MYSQL_ROOT_PASSWORD=root_pass
|
||||
DB_DATABASE=my-projetcs
|
||||
|
15
app/.dockerignore
Normal file
15
app/.dockerignore
Normal file
@@ -0,0 +1,15 @@
|
||||
**/.env
|
||||
**/*.env
|
||||
**/.env.example
|
||||
**/storage/app/*
|
||||
**/storage/debugbar
|
||||
**/storage/framework/cache/*
|
||||
**/storage/framework/sessions/*
|
||||
**/storage/framework/views/*
|
||||
**/storage/framework/testing/*
|
||||
**/storage/translation_service/*
|
||||
**/storage/logs/*
|
||||
**/vendor/
|
||||
**/node_modules/
|
||||
**/public/build/
|
||||
**/public/storage
|
@@ -1,17 +1,34 @@
|
||||
APP_NAME=Laravel
|
||||
APP_NAME="My Projects Website"
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_CAPTCHA=false
|
||||
CAPTCHA_API_DOMAIN=http://your-domain-captcha-or-IP:8081
|
||||
CAPTCHA_PRIVATE_TOKEN=
|
||||
CAPTCHA_STATIC_PATH=http://your-domain-captcha-or-IP:8081/captcha
|
||||
CAPTCHA_PUBLIC_TOKEN=
|
||||
|
||||
# Don't forget to configure MAIL_MAILER to send mail.
|
||||
FEEDBACK_MAIL_NOTIFICATIONS=false
|
||||
FEEDBACK_MAIL_TO=
|
||||
|
||||
TRANSLATION_SERVICE_ENABLE=false
|
||||
# yandex or log
|
||||
TRANSLATE_SERVICE=log
|
||||
TRANSLATE_YANDEX_FOLDER_ID=
|
||||
TRANSLATE_YANDEX_AUTHORIZED_KEY_PATH=/storage/translation_service/authorized_key.json
|
||||
TRANSLATE_YANDEX_LIMIT_MAX_REQUEST=20
|
||||
TRANSLATE_YANDEX_LIMIT_RATE_SECONDS=1
|
||||
TRANSLATE_YANDEX_LIMIT_MAX_SYMBOLS=9000
|
||||
|
||||
TRANSLATE_LOG_LIMIT_MAX_REQUEST=20
|
||||
TRANSLATE_LOG_LIMIT_RATE_SECONDS=1
|
||||
TRANSLATE_LOG_LIMIT_MAX_SYMBOLS=9000
|
||||
|
||||
APP_FORCE_HTTPS=false
|
||||
#UNIT_SOURCE="\"172.16.0.0/12\""
|
||||
|
||||
APP_DEFAULT_LOCALE=ru
|
||||
APP_FAKER_LOCALE=ru_RU
|
||||
@@ -59,7 +76,7 @@ REDIS_HOST=app-redis
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=log
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=127.0.0.1
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
|
1
app/application/.gitignore
vendored
1
app/application/.gitignore
vendored
@@ -8,6 +8,7 @@
|
||||
.env
|
||||
.env.backup
|
||||
.env.production
|
||||
.env.testing
|
||||
.phpunit.result.cache
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
|
@@ -0,0 +1,50 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Commands\Files;
|
||||
|
||||
use App\Services\Commands\DeleteOldFilesService;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
final class DeleteOldFilesFromStorage extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'files:delete-old-files-from-storage';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Remove temporary files or files that have been deleted from the storage table';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(DeleteOldFilesService $deleteOldFilesService): void
|
||||
{
|
||||
$temporaryBeforeDate = Carbon::now()->subDays(3);
|
||||
$deletedBeforeDate = Carbon::now()->subDays(7);
|
||||
|
||||
$result = $deleteOldFilesService->fromStorage($temporaryBeforeDate, $deletedBeforeDate);
|
||||
if ($result->isError()) {
|
||||
$this->error($result->getMessage());
|
||||
return;
|
||||
}
|
||||
$this->info($result->getMessage());
|
||||
}
|
||||
}
|
23
app/application/app/Dto/Builder/Documentation.php
Normal file
23
app/application/app/Dto/Builder/Documentation.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Builder;
|
||||
|
||||
use App\Dto\Builder\DocumentationCategory\Category;
|
||||
|
||||
final readonly class Documentation
|
||||
{
|
||||
public function __construct(
|
||||
private ?bool $isPublic = null,
|
||||
private ?Category $categoryId = null,
|
||||
) { }
|
||||
|
||||
public function isPublic(): ?bool
|
||||
{
|
||||
return $this->isPublic;
|
||||
}
|
||||
|
||||
public function getCategoryId(): ?Category
|
||||
{
|
||||
return $this->categoryId;
|
||||
}
|
||||
}
|
23
app/application/app/Dto/Builder/DocumentationCategory.php
Normal file
23
app/application/app/Dto/Builder/DocumentationCategory.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Builder;
|
||||
|
||||
use App\Dto\Builder\DocumentationCategory\Category;
|
||||
|
||||
final readonly class DocumentationCategory
|
||||
{
|
||||
public function __construct(
|
||||
private ?bool $isPublic = null,
|
||||
private ?Category $parentId = null,
|
||||
) { }
|
||||
|
||||
public function isPublic(): ?bool
|
||||
{
|
||||
return $this->isPublic;
|
||||
}
|
||||
|
||||
public function getParentId(): ?Category
|
||||
{
|
||||
return $this->parentId;
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Builder\DocumentationCategory;
|
||||
|
||||
final readonly class Category
|
||||
{
|
||||
public function __construct(
|
||||
private ?int $categoryId,
|
||||
) { }
|
||||
|
||||
public function getCategoryId(): ?int
|
||||
{
|
||||
return $this->categoryId;
|
||||
}
|
||||
|
||||
public function isCategoryNull(): bool
|
||||
{
|
||||
return $this->getCategoryId() === null;
|
||||
}
|
||||
}
|
15
app/application/app/Dto/Builder/DocumentationVersion.php
Normal file
15
app/application/app/Dto/Builder/DocumentationVersion.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Builder;
|
||||
|
||||
final readonly class DocumentationVersion
|
||||
{
|
||||
public function __construct(
|
||||
private ?bool $isPublic = null,
|
||||
) { }
|
||||
|
||||
public function isPublic(): ?bool
|
||||
{
|
||||
return $this->isPublic;
|
||||
}
|
||||
}
|
@@ -3,12 +3,15 @@
|
||||
namespace App\Dto\Service\Admin\Project\About;
|
||||
|
||||
use App\Dto\Service\Dto;
|
||||
use App\Dto\Service\Storage\Storages;
|
||||
|
||||
final readonly class StoreUpdate extends Dto
|
||||
{
|
||||
public function __construct(
|
||||
private string $title,
|
||||
private string $description,
|
||||
private Storages $storages,
|
||||
private bool $isTranslateAutomatically = false,
|
||||
) { }
|
||||
|
||||
public function getTitle(): string
|
||||
@@ -20,4 +23,14 @@ final readonly class StoreUpdate extends Dto
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function getStorages(): Storages
|
||||
{
|
||||
return $this->storages;
|
||||
}
|
||||
|
||||
public function isTranslateAutomatically(): bool
|
||||
{
|
||||
return $this->isTranslateAutomatically;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,21 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\Documentation;
|
||||
|
||||
use App\Dto\Builder\Documentation;
|
||||
use App\Dto\Service\Pages;
|
||||
|
||||
final readonly class Index extends Pages
|
||||
{
|
||||
public function __construct(
|
||||
private Documentation $documentation,
|
||||
int $page
|
||||
) {
|
||||
parent::__construct($page);
|
||||
}
|
||||
|
||||
public function getDocumentation(): Documentation
|
||||
{
|
||||
return $this->documentation;
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\Documentation;
|
||||
|
||||
use App\Dto\Service\Admin\Project\DocumentationContent\Contents;
|
||||
use App\Dto\Service\Dto;
|
||||
|
||||
final readonly class StoreUpdate extends Dto
|
||||
{
|
||||
public function __construct(
|
||||
private string $slug,
|
||||
private bool $isPublic,
|
||||
private int $sort,
|
||||
private Contents $contents,
|
||||
private ?int $categoryId,
|
||||
) { }
|
||||
|
||||
public function getSlug(): string
|
||||
{
|
||||
return $this->slug;
|
||||
}
|
||||
|
||||
public function isPublic(): bool
|
||||
{
|
||||
return $this->isPublic;
|
||||
}
|
||||
|
||||
public function getCategoryId(): ?int
|
||||
{
|
||||
return $this->categoryId;
|
||||
}
|
||||
|
||||
public function getSort(): int
|
||||
{
|
||||
return $this->sort;
|
||||
}
|
||||
|
||||
public function getContents(): Contents
|
||||
{
|
||||
return $this->contents;
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationCategory;
|
||||
|
||||
use App\Dto\Builder\DocumentationCategory;
|
||||
use App\Dto\Service\Pages;
|
||||
|
||||
final readonly class Index extends Pages
|
||||
{
|
||||
public function __construct(
|
||||
private DocumentationCategory $documentationCategory,
|
||||
int $page
|
||||
) {
|
||||
parent::__construct($page);
|
||||
}
|
||||
|
||||
public function getDocumentationCategory(): DocumentationCategory
|
||||
{
|
||||
return $this->documentationCategory;
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationCategory;
|
||||
|
||||
use App\Dto\Service\Admin\Project\DocumentationCategoryContent\Contents;
|
||||
use App\Dto\Service\Dto;
|
||||
|
||||
final readonly class StoreUpdate extends Dto
|
||||
{
|
||||
public function __construct(
|
||||
private string $slug,
|
||||
private bool $isPublic,
|
||||
private int $sort,
|
||||
private Contents $contents,
|
||||
private ?int $parentId,
|
||||
) { }
|
||||
|
||||
public function getSlug(): string
|
||||
{
|
||||
return $this->slug;
|
||||
}
|
||||
|
||||
public function isPublic(): bool
|
||||
{
|
||||
return $this->isPublic;
|
||||
}
|
||||
|
||||
public function getSort(): int
|
||||
{
|
||||
return $this->sort;
|
||||
}
|
||||
|
||||
public function getParentId(): ?int
|
||||
{
|
||||
return $this->parentId;
|
||||
}
|
||||
|
||||
public function getContents(): Contents
|
||||
{
|
||||
return $this->contents;
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationCategoryContent;
|
||||
|
||||
final readonly class Content
|
||||
{
|
||||
public function __construct(
|
||||
private int $languageId,
|
||||
private string $title,
|
||||
private bool $isTranslateAutomatically = false,
|
||||
) { }
|
||||
|
||||
public function getLanguageId(): int
|
||||
{
|
||||
return $this->languageId;
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function isTranslateAutomatically(): bool
|
||||
{
|
||||
return $this->isTranslateAutomatically;
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationCategoryContent;
|
||||
|
||||
final class Contents
|
||||
{
|
||||
private array $contents = [];
|
||||
|
||||
public function addContent(Content $content): void
|
||||
{
|
||||
$this->contents[$content->getLanguageId()] = $content;
|
||||
}
|
||||
|
||||
public function getContent(int $languageId): ?Content
|
||||
{
|
||||
return $this->contents[$languageId] ?? null;
|
||||
}
|
||||
|
||||
public function getContents(): array
|
||||
{
|
||||
return $this->contents;
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationContent;
|
||||
|
||||
use App\Dto\Service\Storage\Storages;
|
||||
|
||||
final readonly class Content
|
||||
{
|
||||
public function __construct(
|
||||
private int $languageId,
|
||||
private string $title,
|
||||
private string $content,
|
||||
private Storages $storages,
|
||||
private bool $isTranslateAutomatically = false,
|
||||
) { }
|
||||
|
||||
public function getLanguageId(): int
|
||||
{
|
||||
return $this->languageId;
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function getContent(): string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function getStorages(): Storages
|
||||
{
|
||||
return $this->storages;
|
||||
}
|
||||
|
||||
public function isTranslateAutomatically(): bool
|
||||
{
|
||||
return $this->isTranslateAutomatically;
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationContent;
|
||||
|
||||
final class Contents
|
||||
{
|
||||
private array $contents = [];
|
||||
|
||||
public function addContent(Content $content): void
|
||||
{
|
||||
$this->contents[$content->getLanguageId()] = $content;
|
||||
}
|
||||
|
||||
public function getContent(int $languageId): ?Content
|
||||
{
|
||||
return $this->contents[$languageId] ?? null;
|
||||
}
|
||||
|
||||
public function getContents(): array
|
||||
{
|
||||
return $this->contents;
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationVersion;
|
||||
|
||||
use App\Dto\Builder\DocumentationVersion;
|
||||
use App\Dto\Service\Pages;
|
||||
|
||||
final readonly class Index extends Pages
|
||||
{
|
||||
public function __construct(
|
||||
private DocumentationVersion $documentationVersionBuildDto,
|
||||
int $page
|
||||
) {
|
||||
parent::__construct($page);
|
||||
}
|
||||
|
||||
public function getDocumentationVersionBuildDto(): DocumentationVersion
|
||||
{
|
||||
return $this->documentationVersionBuildDto;
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationVersion;
|
||||
|
||||
use App\Dto\Service\Dto;
|
||||
use App\Enums\DocumentationVersionStatus;
|
||||
|
||||
final readonly class StoreUpdate extends Dto
|
||||
{
|
||||
public function __construct(
|
||||
private string $title,
|
||||
private string $slug,
|
||||
private bool $isPublic,
|
||||
private DocumentationVersionStatus $status,
|
||||
) { }
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function getSlug(): string
|
||||
{
|
||||
return $this->slug;
|
||||
}
|
||||
|
||||
public function isPublic(): bool
|
||||
{
|
||||
return $this->isPublic;
|
||||
}
|
||||
|
||||
public function getStatus(): DocumentationVersionStatus
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\ServiceTranslate;
|
||||
|
||||
use App\Dto\Service\Dto;
|
||||
|
||||
final readonly class Translation extends Dto
|
||||
{
|
||||
public function __construct(
|
||||
private int $languageId,
|
||||
private ?int $sourceLanguageId,
|
||||
private ?string $code,
|
||||
) { }
|
||||
|
||||
public function getLanguageId(): int
|
||||
{
|
||||
return $this->languageId;
|
||||
}
|
||||
|
||||
public function getSourceLanguageId(): ?int
|
||||
{
|
||||
return $this->sourceLanguageId;
|
||||
}
|
||||
|
||||
public function getCode(): ?string
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\ServiceTranslate;
|
||||
|
||||
final class Translations
|
||||
{
|
||||
private array $translations;
|
||||
|
||||
public function add(Translation $translation): void
|
||||
{
|
||||
$this->translations[] = $translation;
|
||||
}
|
||||
|
||||
public function getTranslations(): array
|
||||
{
|
||||
return $this->translations;
|
||||
}
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\ServiceTranslate;
|
||||
|
||||
use App\Dto\Service\Dto;
|
||||
|
||||
final readonly class Update extends Dto
|
||||
{
|
||||
public function __construct(
|
||||
private Translations $translations,
|
||||
) { }
|
||||
|
||||
public function getTranslations(): Translations
|
||||
{
|
||||
return $this->translations;
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\Translation;
|
||||
|
||||
use App\Enums\DocumentationVersionStatus;
|
||||
use App\Exceptions\Dto\Admin\Project\Transaction\TranslationsException;
|
||||
|
||||
final class Translations
|
||||
@@ -23,7 +24,7 @@ final class Translations
|
||||
|
||||
public static function getTranslationCodes(): array
|
||||
{
|
||||
return [
|
||||
$translations = [
|
||||
'site.Menu',
|
||||
'site.Powered by service',
|
||||
'site.About project',
|
||||
@@ -38,6 +39,17 @@ final class Translations
|
||||
'site.attributes.message',
|
||||
'site.Message sent successfully',
|
||||
'Server Error',
|
||||
'site.Documentation',
|
||||
'site.Documentation not created',
|
||||
'site.Choose version',
|
||||
'site.alert-status-not-supported',
|
||||
'site.alert-status-future',
|
||||
];
|
||||
|
||||
foreach (DocumentationVersionStatus::cases() as $status) {
|
||||
$translations[] = $status->getCodeForTranslation();
|
||||
}
|
||||
|
||||
return $translations;
|
||||
}
|
||||
}
|
||||
|
@@ -8,10 +8,16 @@ final readonly class Update extends Dto
|
||||
{
|
||||
public function __construct(
|
||||
private Translations $translations,
|
||||
private bool $isTranslateAutomatically = false,
|
||||
) { }
|
||||
|
||||
public function getTranslations(): Translations
|
||||
{
|
||||
return $this->translations;
|
||||
}
|
||||
|
||||
public function isTranslateAutomatically(): bool
|
||||
{
|
||||
return $this->isTranslateAutomatically;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,30 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\DocumentationContent;
|
||||
|
||||
use App\Dto\Service\Storage\Storages;
|
||||
use App\Models\DocumentationContent;
|
||||
|
||||
final class StorageDto
|
||||
{
|
||||
/**
|
||||
* @var array [][DocumentationContent documentationContent, Storages storages]
|
||||
*/
|
||||
private array $storages = [];
|
||||
|
||||
public function add(DocumentationContent $documentationContent, Storages $storages): void
|
||||
{
|
||||
$this->storages[] = [
|
||||
'documentationContent' => $documentationContent,
|
||||
'storages' => $storages
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array [][DocumentationContent documentationContent, Storages storages]
|
||||
*/
|
||||
public function getStorages(): array
|
||||
{
|
||||
return $this->storages;
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\ProjectTranslationServiceHash;
|
||||
|
||||
final class Fields
|
||||
{
|
||||
private array $fields = [];
|
||||
|
||||
public function add(string $name, string $value): self
|
||||
{
|
||||
$this->fields[$name] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFields(): array
|
||||
{
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
public function getNames(): array
|
||||
{
|
||||
return \array_keys($this->fields);
|
||||
}
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\ProjectTranslationServiceHash;
|
||||
|
||||
final class HashStatusWaiting
|
||||
{
|
||||
private array $hash = [];
|
||||
|
||||
public function add(string $fieldName, bool $isWaiting): void
|
||||
{
|
||||
$this->hash[$fieldName] = $isWaiting;
|
||||
}
|
||||
|
||||
public function isStatusWaiting(string $fieldName): bool
|
||||
{
|
||||
return $this->hash[$fieldName] ?? false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\ProjectTranslationServiceHash;
|
||||
|
||||
final class Hashes
|
||||
{
|
||||
private array $hashes = [];
|
||||
private array $ids = [];
|
||||
|
||||
public function add(int $hashId, string $fieldName, string $hash): void
|
||||
{
|
||||
$this->hashes[$hashId] = [
|
||||
'field' => $fieldName,
|
||||
'hash' => $hash,
|
||||
];
|
||||
$this->ids[] = $hashId;
|
||||
}
|
||||
|
||||
public function getHash(int $hashId): ?array
|
||||
{
|
||||
return $this->hashes[$hashId] ?? null;
|
||||
}
|
||||
|
||||
public function getIds(): array
|
||||
{
|
||||
return $this->ids;
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\ProjectTranslationServiceHash;
|
||||
|
||||
final class TranslateFields
|
||||
{
|
||||
private array $fields = [];
|
||||
private array $hashes = [];
|
||||
|
||||
public function add(int $languageId, string $fieldName, string $hash, int $hashId): self
|
||||
{
|
||||
if (!isset($this->fields[$languageId])) {
|
||||
$this->fields[$languageId] = [];
|
||||
}
|
||||
$this->fields[$languageId][] = $fieldName;
|
||||
|
||||
if (!isset($this->hashes[$languageId])) {
|
||||
$this->hashes[$languageId] = [];
|
||||
}
|
||||
$this->hashes[$languageId][$fieldName] = [
|
||||
'hash' => $hash,
|
||||
'hashId' => $hashId,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFields(): array
|
||||
{
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
public function getHashesByLanguage(int $languageId): array
|
||||
{
|
||||
return $this->hashes[$languageId] ?? [];
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\ProjectTranslationServiceTextHash;
|
||||
|
||||
final class Codes
|
||||
{
|
||||
private array $codes = [];
|
||||
|
||||
public function add(string $code, string $value): self
|
||||
{
|
||||
$this->codes[$code] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCodes(): array
|
||||
{
|
||||
return $this->codes;
|
||||
}
|
||||
|
||||
public function getCodeNames(): array
|
||||
{
|
||||
return \array_keys($this->codes);
|
||||
}
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\ProjectTranslationServiceTextHash;
|
||||
|
||||
final class HashStatusWaiting
|
||||
{
|
||||
private array $hash = [];
|
||||
|
||||
public function add(string $code, bool $isWaiting): void
|
||||
{
|
||||
$this->hash[$code] = $isWaiting;
|
||||
}
|
||||
|
||||
public function isStatusWaiting(string $code): bool
|
||||
{
|
||||
return $this->hash[$code] ?? false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\ProjectTranslationServiceTextHash;
|
||||
|
||||
final class Hashes
|
||||
{
|
||||
private array $hashes = [];
|
||||
private array $ids = [];
|
||||
|
||||
public function add(int $hashId, string $code, string $hash): void
|
||||
{
|
||||
$this->hashes[$hashId] = [
|
||||
'code' => $code,
|
||||
'hash' => $hash,
|
||||
];
|
||||
$this->ids[] = $hashId;
|
||||
}
|
||||
|
||||
public function getHash(int $hashId): ?array
|
||||
{
|
||||
return $this->hashes[$hashId] ?? null;
|
||||
}
|
||||
|
||||
public function getIds(): array
|
||||
{
|
||||
return $this->ids;
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\ProjectTranslationServiceTextHash;
|
||||
|
||||
final class TranslateCodes
|
||||
{
|
||||
private array $codes = [];
|
||||
private array $hashes = [];
|
||||
|
||||
public function add(int $languageId, string $code, string $hash, int $hashId): self
|
||||
{
|
||||
if (!isset($this->codes[$languageId])) {
|
||||
$this->codes[$languageId] = [];
|
||||
}
|
||||
$this->codes[$languageId][] = $code;
|
||||
|
||||
if (!isset($this->hashes[$languageId])) {
|
||||
$this->hashes[$languageId] = [];
|
||||
}
|
||||
$this->hashes[$languageId][$code] = [
|
||||
'hash' => $hash,
|
||||
'hashId' => $hashId,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCodes(): array
|
||||
{
|
||||
return $this->codes;
|
||||
}
|
||||
|
||||
public function getHashesByLanguage(int $languageId): array
|
||||
{
|
||||
return $this->hashes[$languageId] ?? [];
|
||||
}
|
||||
}
|
47
app/application/app/Dto/Service/Site/Documentation.php
Normal file
47
app/application/app/Dto/Service/Site/Documentation.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Site;
|
||||
|
||||
use App\Models\DocumentationVersion;
|
||||
use App\Models\Project;
|
||||
use App\Models\User;
|
||||
use App\Services\WebsiteTranslations;
|
||||
|
||||
final readonly class Documentation
|
||||
{
|
||||
public function __construct(
|
||||
private Project $project,
|
||||
private DocumentationVersion $version,
|
||||
private WebsiteTranslations $websiteTranslations,
|
||||
private ?User $user = null,
|
||||
) { }
|
||||
|
||||
public function getProject(): Project
|
||||
{
|
||||
return $this->project;
|
||||
}
|
||||
|
||||
public function getVersion(): DocumentationVersion
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
public function getWebsiteTranslations(): WebsiteTranslations
|
||||
{
|
||||
return $this->websiteTranslations;
|
||||
}
|
||||
|
||||
public function getUser(): ?User
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'project' => $this->getProject(),
|
||||
'version' => $this->getVersion(),
|
||||
'websiteTranslations' => $this->getWebsiteTranslations(),
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\View\Volt\Form;
|
||||
|
||||
use App\Enums\Morph;
|
||||
use App\Helpers\Helpers;
|
||||
|
||||
final readonly class WysiwygStorageUpload
|
||||
{
|
||||
public function __construct(
|
||||
private string $inputName,
|
||||
private Morph $morph,
|
||||
) { }
|
||||
|
||||
public function getInputName(): string
|
||||
{
|
||||
return $this->inputName;
|
||||
}
|
||||
|
||||
public function getRequestInputName(): string
|
||||
{
|
||||
return Helpers::formatAttributeNameToRequestName($this->getInputName());
|
||||
}
|
||||
|
||||
public function getMorph(): Morph
|
||||
{
|
||||
return $this->morph;
|
||||
}
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Illuminate\Cache\TaggedCache;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
enum CacheTag: string
|
||||
{
|
||||
case Project = 'project';
|
||||
case ProjectTranslation = 'project_translation';
|
||||
|
||||
public function getCache(): TaggedCache
|
||||
{
|
||||
return Cache::tags($this->value);
|
||||
}
|
||||
}
|
46
app/application/app/Enums/DocumentationVersionStatus.php
Normal file
46
app/application/app/Enums/DocumentationVersionStatus.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use App\Services\WebsiteTranslations;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
enum DocumentationVersionStatus: int
|
||||
{
|
||||
case NotSupported = 0;
|
||||
case Supported = 50;
|
||||
case CurrentVersion = 100;
|
||||
case FutureVersion = 150;
|
||||
|
||||
public function getTitle(?WebsiteTranslations $websiteTranslations = null): string
|
||||
{
|
||||
if (\is_null($websiteTranslations)) {
|
||||
return __($this->getCodeForTranslation());
|
||||
}
|
||||
|
||||
return $websiteTranslations->translate($this->getCodeForTranslation());
|
||||
}
|
||||
|
||||
public function getCodeForTranslation(): string
|
||||
{
|
||||
return 'version-status.' . $this->name;
|
||||
}
|
||||
|
||||
public static function toArray(): array
|
||||
{
|
||||
$items = [];
|
||||
foreach (self::cases() as $item) {
|
||||
$items[] = [
|
||||
'name' => $item->name,
|
||||
'value' => $item->value,
|
||||
'title' => $item->getTitle(),
|
||||
];
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
public static function toCollection(): Collection
|
||||
{
|
||||
return collect(self::toArray());
|
||||
}
|
||||
}
|
@@ -2,16 +2,25 @@
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use App\Models\DocumentationCategoryContent;
|
||||
use App\Models\DocumentationContent;
|
||||
use App\Models\Project;
|
||||
use App\Models\ProjectContent;
|
||||
|
||||
enum Morph: int
|
||||
{
|
||||
case Project = 1;
|
||||
case DocumentationContent = 2;
|
||||
case ProjectContent = 3;
|
||||
case DocumentationCategoryContent = 4;
|
||||
|
||||
public function getPathModel(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Project => Project::class,
|
||||
self::Project => Project::class,
|
||||
self::DocumentationContent => DocumentationContent::class,
|
||||
self::ProjectContent => ProjectContent::class,
|
||||
self::DocumentationCategoryContent => DocumentationCategoryContent::class,
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -12,6 +12,8 @@ enum Permission: string
|
||||
case ProjectLink = 'project-link';
|
||||
case ProjectTranslation = 'project-translation';
|
||||
case ProjectFeedback = 'project-feedback';
|
||||
case Documentation = 'documentation';
|
||||
case DocumentationCategory = 'documentation-category';
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
@@ -19,6 +21,9 @@ enum Permission: string
|
||||
self::AdminPanel => [
|
||||
'view' => __('permissions.Administrative panel allowed'),
|
||||
],
|
||||
self::Project => array_merge($this->getBasePermissions(), [
|
||||
'Setting up automatic translation' => __('permissions.Setting up automatic translation'),
|
||||
]),
|
||||
self::ProjectContent => [
|
||||
'view' => __('permissions.Allowed to watch'),
|
||||
'create' => __('permissions.Allowed to create'),
|
||||
|
@@ -0,0 +1,9 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Enums\ProjectTranslationServiceHashes;
|
||||
|
||||
enum Status: int
|
||||
{
|
||||
case Waiting = 0;
|
||||
case Success = 10;
|
||||
}
|
@@ -5,15 +5,18 @@ namespace App\Enums\Site;
|
||||
use App\Models\Project;
|
||||
use App\Models\ProjectLanguage;
|
||||
|
||||
enum ProjectSection
|
||||
enum ProjectSection: string
|
||||
{
|
||||
case Home;
|
||||
case Feedback;
|
||||
case FeedbackSend;
|
||||
case Home = 'home';
|
||||
case Feedback = 'feedback';
|
||||
case FeedbackSend = 'feedback.send';
|
||||
case Documentation = 'documentation';
|
||||
case DocumentationVersion = 'documentation.version';
|
||||
case DocumentationCategory = 'documentation.category';
|
||||
case DocumentationView = 'documentation.view';
|
||||
|
||||
public function url(Project $project, ?ProjectLanguage $language = null): string
|
||||
public function url(Project $project, ?ProjectLanguage $language = null, array $parameters = []): string
|
||||
{
|
||||
$parameters = [];
|
||||
$prefixProject = '';
|
||||
if ($project->http_host === null) {
|
||||
$prefixProject = 'project.';
|
||||
@@ -26,12 +29,7 @@ enum ProjectSection
|
||||
$prefixLanguage = '-language';
|
||||
}
|
||||
|
||||
$route = match ($this) {
|
||||
self::Home => \route($prefixProject . 'home' . $prefixLanguage, $parameters, false),
|
||||
|
||||
self::Feedback => \route($prefixProject . 'feedback' . $prefixLanguage, $parameters, false),
|
||||
self::FeedbackSend => \route($prefixProject . 'feedback.send' . $prefixLanguage, $parameters, false),
|
||||
};
|
||||
$route = \route($prefixProject . $this->value . $prefixLanguage, $parameters, false);
|
||||
|
||||
return $project->http_host . $route;
|
||||
}
|
||||
|
@@ -9,39 +9,43 @@ use App\Contracts\StorageType\Video;
|
||||
enum StorageType: int implements Image, Video, Audio
|
||||
{
|
||||
case Logo = 1;
|
||||
case ContentImages = 2;
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Logo => __('validation.attributes.logo'),
|
||||
self::ContentImages => __('validation.attributes.content_images'),
|
||||
};
|
||||
}
|
||||
|
||||
public function getAcceptMimes(): array
|
||||
{
|
||||
return match ($this) {
|
||||
self::Logo => ['jpeg', 'jpg', 'png'],
|
||||
self::Logo => ['jpeg', 'jpg', 'png'],
|
||||
self::ContentImages => ['jpeg', 'jpg', 'png'],
|
||||
};
|
||||
}
|
||||
|
||||
public function isImage(): bool
|
||||
{
|
||||
return match ($this) {
|
||||
self::Logo => true,
|
||||
self::Logo => true,
|
||||
self::ContentImages => true,
|
||||
default => false
|
||||
};
|
||||
}
|
||||
|
||||
public function isVideo(): bool
|
||||
{
|
||||
return match ($this->name) {
|
||||
return match ($this) {
|
||||
default => false
|
||||
};
|
||||
}
|
||||
|
||||
public function isAudio(): bool
|
||||
{
|
||||
return match ($this->name) {
|
||||
return match ($this) {
|
||||
default => false
|
||||
};
|
||||
}
|
||||
|
@@ -0,0 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Exceptions\Services\DocumentationCategory;
|
||||
|
||||
final class ParentException extends \Exception
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Exceptions\Services\DocumentationCategoryContent;
|
||||
|
||||
final class ContentSaveException extends \Exception
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Exceptions\Services\DocumentationContent;
|
||||
|
||||
final class ContentSaveException extends \Exception
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Exceptions\Services\DocumentationContent;
|
||||
|
||||
use App\ServiceResults\ServiceResultError;
|
||||
|
||||
final class StorageCommandException extends \Exception
|
||||
{
|
||||
public function __construct(private readonly ServiceResultError $resultError, string $message = "", int $code = 0, ?\Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
public function getResultError(): ServiceResultError
|
||||
{
|
||||
return $this->resultError;
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Exceptions\Services\Rule;
|
||||
|
||||
final class RoleSyncPermissionsCommandHandlerException extends \Exception
|
||||
{
|
||||
|
||||
}
|
19
app/application/app/Exceptions/Services/ServiceException.php
Normal file
19
app/application/app/Exceptions/Services/ServiceException.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Exceptions\Services;
|
||||
|
||||
use App\Contracts\ServiceResultError as ServiceResultErrorContract;
|
||||
|
||||
final class ServiceException extends \Exception
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ServiceResultErrorContract $serviceResultError
|
||||
) {
|
||||
parent::__construct($this->serviceResultError->getMessage());
|
||||
}
|
||||
|
||||
public function getServiceResultError(): ServiceResultErrorContract
|
||||
{
|
||||
return $this->serviceResultError;
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Exceptions\Services\Translate;
|
||||
|
||||
final class CompletedException extends \Exception
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,105 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Admin\Projects;
|
||||
|
||||
use App\Dto\QuerySettingsDto;
|
||||
use App\Http\Controllers\Admin\Controller;
|
||||
use App\Http\Requests\Admin\Projects\DocumentationCategories\IndexRequest;
|
||||
use App\Http\Requests\Admin\Projects\DocumentationCategories\StoreUpdateRequest;
|
||||
use App\Services\Admin\Project\DocumentationCategoryService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class DocumentationCategoriesController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly DocumentationCategoryService $documentationCategoryService,
|
||||
) { }
|
||||
|
||||
public function index(int $projectId, int $versionId, IndexRequest $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$data = $request->getDto();
|
||||
$querySettingsDto = new QuerySettingsDto(
|
||||
limit: 20,
|
||||
page: $data->getPage(),
|
||||
queryWith: []
|
||||
);
|
||||
|
||||
$result = $this->documentationCategoryService->index($projectId, $versionId, $data->getDocumentationCategory(), $querySettingsDto, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-categories/index', $result->getData());
|
||||
}
|
||||
|
||||
public function create(int $projectId, int $versionId, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationCategoryService->create($projectId, $versionId, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-categories/create', $result->getData());
|
||||
}
|
||||
|
||||
public function edit(int $projectId, int $versionId, int $id, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationCategoryService->edit($projectId, $versionId, $id, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-categories/edit', $result->getData());
|
||||
}
|
||||
|
||||
public function store(int $projectId, int $versionId, StoreUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getDto();
|
||||
$user = $request->user();
|
||||
$result = $this->documentationCategoryService->store($projectId, $versionId, $data, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.categories.edit', [
|
||||
'project' => $projectId,
|
||||
'version' => $versionId,
|
||||
'category' => $result->getModel()->id,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
|
||||
public function update(int $projectId, int $versionId, int $id, StoreUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getDto();
|
||||
$user = $request->user();
|
||||
$result = $this->documentationCategoryService->update($projectId, $versionId, $id, $data, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.categories.edit', [
|
||||
'project' => $projectId,
|
||||
'version' => $versionId,
|
||||
'category' => $result->getModel()->id,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
|
||||
public function destroy(int $projectId, int $versionId, int $id, Request $request): RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationCategoryService->destroy($projectId, $versionId, $id, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.categories.index', [
|
||||
'project' => $projectId,
|
||||
'version' => $versionId,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Admin\Projects;
|
||||
|
||||
use App\Dto\QuerySettingsDto;
|
||||
use App\Http\Controllers\Admin\Controller;
|
||||
use App\Http\Requests\Admin\Projects\DocumentVersions\IndexRequest;
|
||||
use App\Http\Requests\Admin\Projects\DocumentVersions\StoreUpdateRequest;
|
||||
use App\Services\Admin\Project\DocumentationVersionService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class DocumentationVersionController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly DocumentationVersionService $documentationVersionService,
|
||||
) { }
|
||||
|
||||
public function index(int $projectId, IndexRequest $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$data = $request->getDto();
|
||||
$querySettingsDto = new QuerySettingsDto(
|
||||
limit: 20,
|
||||
page: $data->getPage(),
|
||||
queryWith: []
|
||||
);
|
||||
|
||||
$result = $this->documentationVersionService->index($projectId, $data->getDocumentationVersionBuildDto(), $querySettingsDto, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-versions/index', $result->getData());
|
||||
}
|
||||
|
||||
public function show(int $projectId, int $id, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationVersionService->show($projectId, $id, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-versions/show', $result->getData());
|
||||
}
|
||||
|
||||
public function create(int $projectId, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationVersionService->create($projectId, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-versions/create', $result->getData());
|
||||
}
|
||||
|
||||
public function edit(int $projectId, int $id, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationVersionService->edit($projectId, $id, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-versions/edit', $result->getData());
|
||||
}
|
||||
|
||||
public function store(int $projectId, StoreUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getDto();
|
||||
$user = $request->user();
|
||||
$result = $this->documentationVersionService->store($projectId, $data, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.edit', [
|
||||
'project' => $projectId,
|
||||
'documentation_version' => $result->getModel()->id,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
|
||||
public function update(int $projectId, int $id, StoreUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getDto();
|
||||
$user = $request->user();
|
||||
$result = $this->documentationVersionService->update($projectId, $id, $data, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.edit', [
|
||||
'project' => $projectId,
|
||||
'documentation_version' => $result->getModel()->id,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
|
||||
public function destroy(int $projectId, int $id, Request $request): RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationVersionService->destroy($projectId, $id, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.index', ['project' => $projectId])->withSuccess($result->getMessage());
|
||||
}
|
||||
}
|
@@ -0,0 +1,105 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Admin\Projects;
|
||||
|
||||
use App\Dto\QuerySettingsDto;
|
||||
use App\Http\Controllers\Admin\Controller;
|
||||
use App\Http\Requests\Admin\Projects\Documentations\IndexRequest;
|
||||
use App\Http\Requests\Admin\Projects\Documentations\StoreUpdateRequest;
|
||||
use App\Services\Admin\Project\DocumentationService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class DocumentationsController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly DocumentationService $documentationService,
|
||||
) { }
|
||||
|
||||
public function index(int $projectId, int $versionId, IndexRequest $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$data = $request->getDto();
|
||||
$querySettingsDto = new QuerySettingsDto(
|
||||
limit: 20,
|
||||
page: $data->getPage(),
|
||||
queryWith: []
|
||||
);
|
||||
|
||||
$result = $this->documentationService->index($projectId, $versionId, $data->getDocumentation(), $querySettingsDto, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentations/index', $result->getData());
|
||||
}
|
||||
|
||||
public function create(int $projectId, int $versionId, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationService->create($projectId, $versionId, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentations/create', $result->getData());
|
||||
}
|
||||
|
||||
public function edit(int $projectId, int $versionId, int $id, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationService->edit($projectId, $versionId, $id, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentations/edit', $result->getData());
|
||||
}
|
||||
|
||||
public function store(int $projectId, int $versionId, StoreUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getDto();
|
||||
$user = $request->user();
|
||||
$result = $this->documentationService->store($projectId, $versionId, $data, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.documentations.edit', [
|
||||
'project' => $projectId,
|
||||
'version' => $versionId,
|
||||
'documentation' => $result->getModel()->id,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
|
||||
public function update(int $projectId, int $versionId, int $id, StoreUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getDto();
|
||||
$user = $request->user();
|
||||
$result = $this->documentationService->update($projectId, $versionId, $id, $data, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.documentations.edit', [
|
||||
'project' => $projectId,
|
||||
'version' => $versionId,
|
||||
'documentation' => $result->getModel()->id,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
|
||||
public function destroy(int $projectId, int $versionId, int $id, Request $request): RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationService->destroy($projectId, $versionId, $id, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.documentations.index', [
|
||||
'project' => $projectId,
|
||||
'version' => $versionId,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Admin\Projects;
|
||||
|
||||
use App\Http\Controllers\Admin\Controller;
|
||||
use App\Http\Requests\Admin\Projects\ServiceTranslate\UpdateRequest;
|
||||
use App\Services\Admin\Project\ServiceTranslateService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class ServiceTranslateController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ServiceTranslateService $serviceTranslateService,
|
||||
) { }
|
||||
|
||||
public function view(int $projectId, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->serviceTranslateService->view($projectId, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin.projects.service-translate.view', $result->getData());
|
||||
}
|
||||
|
||||
public function update(int $projectId, UpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getDto();
|
||||
$user = $request->user();
|
||||
$result = $this->serviceTranslateService->update($projectId, $data, $user);
|
||||
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.service-translate.view', ['project' => $projectId])->withSuccess($result->getMessage());
|
||||
}
|
||||
}
|
@@ -19,7 +19,9 @@ final class AuthController extends Controller
|
||||
|
||||
public function login(): View
|
||||
{
|
||||
return view('login');
|
||||
return view('login', [
|
||||
'captcha' => config('app.captcha', false),
|
||||
]);
|
||||
}
|
||||
|
||||
public function authorization(AuthorizationRequest $request): RedirectResponse
|
||||
|
@@ -0,0 +1,96 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Site;
|
||||
|
||||
use App\Dto\Service\Site\Documentation;
|
||||
use App\Services\Site\DocumentationService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class DocumentationController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly DocumentationService $documentationService,
|
||||
) { }
|
||||
|
||||
public function defaultVersion(Request $request): RedirectResponse | View
|
||||
{
|
||||
$project = $request->get('project');
|
||||
$websiteTranslations = $request->get('websiteTranslations');
|
||||
|
||||
$result = $this->documentationService->defaultVersion($project, $request->user());
|
||||
if ($result->isError()) {
|
||||
if ($result->getCode() === 404) {
|
||||
return view('site.projects.documentation.no-default-version', [
|
||||
'project' => $project,
|
||||
'websiteTranslations' => $websiteTranslations,
|
||||
]);
|
||||
}
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
$url = \App\Enums\Site\ProjectSection::DocumentationVersion->url($project, $websiteTranslations->getLanguage(), ['version' => $result->getVersion()->slug]);
|
||||
/**
|
||||
* 302 redirect because the documentation version can change at any time.
|
||||
*/
|
||||
return redirect($url, 302);
|
||||
}
|
||||
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$documentation = new Documentation(
|
||||
project: $request->get('project'),
|
||||
version: $request->get('version'),
|
||||
websiteTranslations: $request->get('websiteTranslations'),
|
||||
user: $request->user(),
|
||||
);
|
||||
$result = $this->documentationService->index($documentation);
|
||||
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('site.projects.documentation.index', $result->getData());
|
||||
}
|
||||
|
||||
public function category(string $slug, Request $request): View
|
||||
{
|
||||
$documentation = new Documentation(
|
||||
project: $request->get('project'),
|
||||
version: $request->get('version'),
|
||||
websiteTranslations: $request->get('websiteTranslations'),
|
||||
user: $request->user(),
|
||||
);
|
||||
$result = $this->documentationService->category($slug, $documentation);
|
||||
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
if ($result->isTranslation()) {
|
||||
return $this->viewPageWithoutTranslation($result);
|
||||
}
|
||||
|
||||
return view('site.projects.documentation.category', $result->getData());
|
||||
}
|
||||
|
||||
public function view(string $slug, Request $request): View
|
||||
{
|
||||
$documentation = new Documentation(
|
||||
project: $request->get('project'),
|
||||
version: $request->get('version'),
|
||||
websiteTranslations: $request->get('websiteTranslations'),
|
||||
user: $request->user(),
|
||||
);
|
||||
$result = $this->documentationService->view($slug, $documentation);
|
||||
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
if ($result->isTranslation()) {
|
||||
return $this->viewPageWithoutTranslation($result);
|
||||
}
|
||||
|
||||
return view('site.projects.documentation.view', $result->getData());
|
||||
}
|
||||
}
|
@@ -3,7 +3,6 @@
|
||||
namespace App\Http\Controllers\Site;
|
||||
|
||||
use App\Http\Requests\Site\Feedback\SendRequest;
|
||||
use App\Models\ProjectFeedback;
|
||||
use App\Services\Site\FeedbackService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -20,6 +19,7 @@ final class FeedbackController extends Controller
|
||||
return view('site.feedback.index', [
|
||||
'project' => $request->get('project'),
|
||||
'websiteTranslations' => $request->get('websiteTranslations'),
|
||||
'captcha' => config('app.captcha', false),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@@ -16,7 +16,6 @@ final class ProjectsController extends Controller
|
||||
{
|
||||
$user = $request->user();
|
||||
$project = $request->get('project');
|
||||
$websiteTranslations = $request->get('websiteTranslations');
|
||||
|
||||
if (\is_null($project)) {
|
||||
$with = ['storage'];
|
||||
@@ -28,7 +27,8 @@ final class ProjectsController extends Controller
|
||||
return \view('site.projects.index', $result->getData());
|
||||
}
|
||||
|
||||
$result = $this->projectService->getAboutByProject($project, $websiteTranslations, $request->user());
|
||||
$websiteTranslations = $request->get('websiteTranslations');
|
||||
$result = $this->projectService->getAboutByProject($project, $websiteTranslations, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
40
app/application/app/Http/Middleware/DocumentationVersion.php
Normal file
40
app/application/app/Http/Middleware/DocumentationVersion.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
final readonly class DocumentationVersion
|
||||
{
|
||||
public function handle(Request $request, \Closure $next): Response
|
||||
{
|
||||
$project = $request->get('project');
|
||||
$versionSlug = $request->route()?->parameter('version');
|
||||
if ($versionSlug === null || $project === null) {
|
||||
\abort(Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$seconds = 3600;
|
||||
$version = Cache::remember(self::class . $project->id . '-' . $versionSlug, $seconds, function () use ($project, $versionSlug) {
|
||||
return $project->documentationVersions()->where('slug', $versionSlug)->first() ?? false;
|
||||
});
|
||||
if ($version === false) {
|
||||
\abort(Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
unset($request->route()->parameters['version']);
|
||||
|
||||
$request->attributes->set('version', $version);
|
||||
|
||||
if (
|
||||
$version->is_public === false
|
||||
&& ( $request->user() === null || $request->user()->cannot('view', $version) )
|
||||
) {
|
||||
\abort(Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
32
app/application/app/Http/Middleware/IsProject.php
Normal file
32
app/application/app/Http/Middleware/IsProject.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Models\Project;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
final class IsProject
|
||||
{
|
||||
public function handle(Request $request, \Closure $next): Response
|
||||
{
|
||||
$project = $request->get('project');
|
||||
if (\is_null($project)) {
|
||||
\abort(Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($project instanceof Project === false) {
|
||||
\report("$project must be an instance of Project");
|
||||
\abort(Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (
|
||||
$project->is_public === false
|
||||
&& ( $request->user() === null || $request->user()->cannot('view', $project) )
|
||||
) {
|
||||
\abort(Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Services\WebsiteTranslations;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
final class IsWebsiteTranslations
|
||||
{
|
||||
public function handle(Request $request, \Closure $next): Response
|
||||
{
|
||||
$websiteTranslations = $request->get('websiteTranslations');
|
||||
if (\is_null($websiteTranslations)) {
|
||||
\abort(Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($websiteTranslations instanceof WebsiteTranslations === false) {
|
||||
\report("$websiteTranslations must be an instance of WebsiteTranslations");
|
||||
\abort(Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
@@ -2,12 +2,12 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Enums\CacheTag;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Closure;
|
||||
|
||||
class ProjectAndLanguage extends ProjectLanguage
|
||||
final class ProjectAndLanguage extends ProjectLanguage
|
||||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
@@ -17,7 +17,7 @@ class ProjectAndLanguage extends ProjectLanguage
|
||||
}
|
||||
|
||||
$seconds = 3600;
|
||||
$project = CacheTag::Project->getCache()->remember(self::class . $projectCode, $seconds, function () use ($projectCode) {
|
||||
$project = Cache::remember(self::class . $projectCode, $seconds, function () use ($projectCode) {
|
||||
return $this->projectRepository->getProjectByCode($projectCode) ?? false;
|
||||
});
|
||||
if ($project === false) {
|
||||
|
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Enums\CacheTag;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
@@ -21,7 +21,7 @@ final class ProjectDomainAndLanguage extends ProjectLanguage
|
||||
}
|
||||
|
||||
$seconds = 3600;
|
||||
$project = CacheTag::Project->getCache()->remember(self::class . $httpHost, $seconds, function () use ($httpHost) {
|
||||
$project = Cache::remember(self::class . $httpHost, $seconds, function () use ($httpHost) {
|
||||
return $this->projectRepository->getProjectByHttpHost($httpHost) ?? false;
|
||||
});
|
||||
if ($project === false) {
|
||||
|
@@ -2,13 +2,13 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Enums\CacheTag;
|
||||
use App\Models\Project;
|
||||
use App\Repositories\ProjectLanguageRepository;
|
||||
use App\Repositories\ProjectRepository;
|
||||
use App\Repositories\ProjectTranslationRepository;
|
||||
use App\Services\WebsiteTranslations;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
abstract class ProjectLanguage
|
||||
{
|
||||
@@ -21,7 +21,7 @@ abstract class ProjectLanguage
|
||||
protected function getWebsiteTranslations(Project $project, ?string $languageCode): ?WebsiteTranslations
|
||||
{
|
||||
$seconds = 3600 * 3;
|
||||
$language = CacheTag::Project->getCache()->remember(self::class . $project->id . '-' . $languageCode, $seconds, function () use ($project, $languageCode) {
|
||||
$language = Cache::remember(self::class . $project->id . '-' . $languageCode, $seconds, function () use ($project, $languageCode) {
|
||||
return $this->projectLanguageRepository->getProjectLanguageByCodeOrDefault($project, $languageCode) ?? false;
|
||||
});
|
||||
if ($language === false) {
|
||||
@@ -34,7 +34,7 @@ abstract class ProjectLanguage
|
||||
}
|
||||
|
||||
$seconds = 3600 * 24;
|
||||
$translations = CacheTag::ProjectTranslation->getCache()->remember(self::class . '-translations-' . $project->id . '-' . $language->id, $seconds, function () use ($project, $language) {
|
||||
$translations = Cache::remember(self::class . '-translations-' . $project->id . '-' . $language->id, $seconds, function () use ($project, $language) {
|
||||
return $this->projectTranslationRepository->getProjectTranslations($project->id, $language->id)->all()->pluck('text', 'code')->toArray();
|
||||
});
|
||||
|
||||
|
@@ -4,10 +4,19 @@ namespace App\Http\Requests\Admin\Projects\About;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Service\Admin\Project\About\StoreUpdate;
|
||||
use App\Dto\Service\Storage\Storages;
|
||||
use App\Enums\StorageType;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
||||
{
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'storage.content_images.*.file' => __('validation.attributes.content_images'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
@@ -16,6 +25,8 @@ final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
||||
return [
|
||||
'title' => ['required', 'string', 'max:255',],
|
||||
'description' => ['nullable', 'string',],
|
||||
'storage.content_images.*.file' => ['numeric', 'min:1'],
|
||||
'translate-automatically' => ['nullable', 'boolean'],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -24,6 +35,19 @@ final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
||||
return new StoreUpdate(
|
||||
title: $this->input('title'),
|
||||
description: $this->input('description'),
|
||||
storages: $this->storages(),
|
||||
isTranslateAutomatically: (bool) $this->input('translate-automatically', false),
|
||||
);
|
||||
}
|
||||
|
||||
private function storages(): Storages
|
||||
{
|
||||
$storages = new Storages();
|
||||
|
||||
$content = $this->input('storage', []);
|
||||
$images = $content['content_images'] ?? [];
|
||||
$storages->addMany($images, StorageType::ContentImages);
|
||||
|
||||
return $storages;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\DocumentVersions;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Builder\DocumentationVersion;
|
||||
use App\Dto\Service\Admin\Project\DocumentationVersion\Index;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
final class IndexRequest extends FormRequest implements FormRequestDto
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'page' => ['nullable', 'numeric', 'min:1']
|
||||
];
|
||||
}
|
||||
|
||||
public function getDto(): Index
|
||||
{
|
||||
return new Index(
|
||||
documentationVersionBuildDto: new DocumentationVersion(),
|
||||
page: (int) $this->input('page', 1)
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\DocumentVersions;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Service\Admin\Project\DocumentationVersion\StoreUpdate;
|
||||
use App\Enums\DocumentationVersionStatus;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
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'],
|
||||
'slug' => ['required', 'string', 'max:70', 'regex:/^[a-z0-9._-]+$/'],
|
||||
'is_public' => ['required', 'boolean'],
|
||||
'status' => ['required', new Enum(DocumentationVersionStatus::class)],
|
||||
];
|
||||
}
|
||||
|
||||
public function getDto(): StoreUpdate
|
||||
{
|
||||
return new StoreUpdate(
|
||||
title: $this->input('title'),
|
||||
slug: $this->input('slug'),
|
||||
isPublic: (bool) $this->input('is_public', false),
|
||||
status: DocumentationVersionStatus::from((int) $this->input('status')),
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\DocumentationCategories;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Builder\DocumentationCategory;
|
||||
use App\Dto\Service\Admin\Project\DocumentationCategory\Index;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
final class IndexRequest extends FormRequest implements FormRequestDto
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'page' => ['nullable', 'numeric', 'min:1']
|
||||
];
|
||||
}
|
||||
|
||||
public function getDto(): Index
|
||||
{
|
||||
return new Index(
|
||||
documentationCategory: new DocumentationCategory(),
|
||||
page: (int) $this->input('page', 1)
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\DocumentationCategories;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Service\Admin\Project\DocumentationCategory\StoreUpdate;
|
||||
use App\Dto\Service\Admin\Project\DocumentationCategoryContent\Content;
|
||||
use App\Dto\Service\Admin\Project\DocumentationCategoryContent\Contents;
|
||||
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 [
|
||||
'slug' => ['required', 'string', 'max:200', 'regex:/^[a-z0-9._-]+$/'],
|
||||
'is_public' => ['required', 'boolean'],
|
||||
'sort' => ['required', 'integer', 'min:-1000', 'max:1000'],
|
||||
'parent_id' => ['nullable', 'integer', 'exists:documentation_categories,id'],
|
||||
'content.*.title' => ['required', 'string', 'max:255'],
|
||||
'translate-automatically.*' => ['nullable', 'boolean'],
|
||||
];
|
||||
}
|
||||
|
||||
public function getDto(): StoreUpdate
|
||||
{
|
||||
$parentId = $this->input('parent_id', null);
|
||||
if (!\is_null($parentId)) {
|
||||
$parentId = (int) $parentId;
|
||||
}
|
||||
|
||||
return new StoreUpdate(
|
||||
slug: $this->input('slug'),
|
||||
isPublic: (bool) $this->input('is_public', false),
|
||||
sort: (int) $this->input('sort'),
|
||||
contents: $this->getContents(),
|
||||
parentId: $parentId,
|
||||
);
|
||||
}
|
||||
|
||||
private function getContents(): Contents
|
||||
{
|
||||
$contents = new Contents();
|
||||
foreach ($this->input('content', []) as $languageId => $content) {
|
||||
$contents->addContent(new Content(
|
||||
languageId: (int) $languageId,
|
||||
title: $content['title'],
|
||||
isTranslateAutomatically: (bool) $this->input('translate-automatically.' . $languageId, false),
|
||||
));
|
||||
}
|
||||
return $contents;
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\Documentations;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Builder\Documentation;
|
||||
use App\Dto\Service\Admin\Project\Documentation\Index;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
final class IndexRequest extends FormRequest implements FormRequestDto
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'page' => ['nullable', 'numeric', 'min:1']
|
||||
];
|
||||
}
|
||||
|
||||
public function getDto(): Index
|
||||
{
|
||||
return new Index(
|
||||
documentation: new Documentation(),
|
||||
page: (int) $this->input('page', 1)
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\Documentations;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Service\Admin\Project\Documentation\StoreUpdate;
|
||||
use App\Dto\Service\Admin\Project\DocumentationContent\Content;
|
||||
use App\Dto\Service\Admin\Project\DocumentationContent\Contents;
|
||||
use App\Dto\Service\Storage\Storages;
|
||||
use App\Enums\StorageType;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
||||
{
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'content.*.content_images.*.file' => __('validation.attributes.content_images'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'slug' => ['required', 'string', 'max:200', 'regex:/^[a-z0-9._-]+$/'],
|
||||
'is_public' => ['required', 'boolean'],
|
||||
'sort' => ['required', 'integer', 'min:-1000', 'max:1000'],
|
||||
'category_id' => ['nullable', 'integer', 'exists:documentation_categories,id'],
|
||||
'content.*.title' => ['required', 'string', 'max:255'],
|
||||
'content.*.content' => ['nullable', 'string'],
|
||||
'content.*.content_images.*.file' => ['numeric', 'min:1'],
|
||||
'translate-automatically.*' => ['nullable', 'boolean'],
|
||||
];
|
||||
}
|
||||
|
||||
public function getDto(): StoreUpdate
|
||||
{
|
||||
$categoryId = $this->input('category_id', null);
|
||||
if (!\is_null($categoryId)) {
|
||||
$categoryId = (int) $categoryId;
|
||||
}
|
||||
|
||||
return new StoreUpdate(
|
||||
slug: $this->input('slug'),
|
||||
isPublic: (bool) $this->input('is_public', false),
|
||||
sort: (int) $this->input('sort'),
|
||||
contents: $this->getContents(),
|
||||
categoryId: $categoryId,
|
||||
);
|
||||
}
|
||||
|
||||
private function getContents(): Contents
|
||||
{
|
||||
$contents = new Contents();
|
||||
foreach ($this->input('content', []) as $languageId => $content) {
|
||||
$contents->addContent(new Content(
|
||||
languageId: (int) $languageId,
|
||||
title: $content['title'],
|
||||
content: $content['content'] ?? '',
|
||||
storages: $this->contentStorages($content),
|
||||
isTranslateAutomatically: (bool) $this->input('translate-automatically.' . $languageId, false),
|
||||
));
|
||||
}
|
||||
return $contents;
|
||||
}
|
||||
|
||||
private function contentStorages(array $content): Storages
|
||||
{
|
||||
$storages = new Storages();
|
||||
|
||||
$images = $content['content_images'] ?? [];
|
||||
$storages->addMany($images, StorageType::ContentImages);
|
||||
|
||||
return $storages;
|
||||
}
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\ServiceTranslate;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Service\Admin\Project\ServiceTranslate\Translation;
|
||||
use App\Dto\Service\Admin\Project\ServiceTranslate\Translations;
|
||||
use App\Dto\Service\Admin\Project\ServiceTranslate\Update;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
final class UpdateRequest extends FormRequest implements FormRequestDto
|
||||
{
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'language.*.id' => __('validation.attributes.language_id'),
|
||||
'language.*.code' => __('validation.attributes.code'),
|
||||
'language.*.source_language_id' => __('validation.attributes.source_language_id'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'language.*.id' => ['required', 'numeric', 'min:1'],
|
||||
'language.*.code' => ['nullable', 'string', 'min:2', 'max:50', 'required_with:language.*.source_language_id'],
|
||||
'language.*.source_language_id' => ['nullable', 'numeric', 'min:1', 'different:language.*.id'],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function getDto(): Update
|
||||
{
|
||||
$translations = new Translations();
|
||||
foreach ($this->input('language', []) as $language) {
|
||||
$sourceLanguageId = $language['source_language_id'] ?? null;
|
||||
if ($sourceLanguageId) {
|
||||
$sourceLanguageId = (int) $sourceLanguageId;
|
||||
}
|
||||
|
||||
$translation = new Translation(
|
||||
languageId: (int) $language['id'],
|
||||
sourceLanguageId: $sourceLanguageId,
|
||||
code: $language['code'] ?? null,
|
||||
);
|
||||
$translations->add($translation);
|
||||
}
|
||||
|
||||
return new Update(
|
||||
translations: $translations,
|
||||
);
|
||||
}
|
||||
}
|
@@ -20,6 +20,7 @@ final class UpdateRequest extends FormRequest implements FormRequestDto
|
||||
'translations' => ['nullable', 'array'],
|
||||
'translations.*.code' => ['required', 'string', new In(Translations::getTranslationCodes())],
|
||||
'translations.*.text' => ['nullable', 'string', 'max:1000'],
|
||||
'translate-automatically' => ['nullable', 'boolean'],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -33,6 +34,9 @@ final class UpdateRequest extends FormRequest implements FormRequestDto
|
||||
);
|
||||
}
|
||||
|
||||
return new Update($translations);
|
||||
return new Update(
|
||||
translations: $translations,
|
||||
isTranslateAutomatically: (bool) $this->input('translate-automatically', false),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -13,12 +13,17 @@ final class AuthorizationRequest extends FormRequest implements FormRequestDto
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
$rules = [
|
||||
'email' => ['required', 'email', 'max:255'],
|
||||
'password' => ['required', 'min:3'],
|
||||
'captcha-verified' => ['captcha'],
|
||||
'remember' => ['nullable', 'boolean'],
|
||||
];
|
||||
|
||||
if (config('app.captcha', false)) {
|
||||
$rules['captcha-verified'] = ['captcha'];
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
public function getDto(): Authorization
|
||||
|
@@ -32,12 +32,17 @@ final class SendRequest extends FormRequest implements FormRequestDto
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
$rules = [
|
||||
'name' => ['nullable', 'string', 'max:255'],
|
||||
'email' => ['nullable', 'string', 'max:255', 'email'],
|
||||
'message' => ['required', 'string', 'max:5000'],
|
||||
'captcha-verified' => ['captcha'],
|
||||
];
|
||||
|
||||
if (config('app.captcha', false)) {
|
||||
$rules['captcha-verified'] = ['captcha'];
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
public function getDto(): Send
|
||||
|
@@ -6,7 +6,9 @@ use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Service\Storage\Upload;
|
||||
use App\Enums\Morph;
|
||||
use App\Enums\StorageType;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Http\Exceptions\HttpResponseException;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
final class ImageRequest extends FormRequest implements FormRequestDto
|
||||
@@ -37,4 +39,20 @@ final class ImageRequest extends FormRequest implements FormRequestDto
|
||||
morph: Morph::from((int) $this->input('morph')),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error messages for the defined validation rules.*
|
||||
* @return array
|
||||
*/
|
||||
protected function failedValidation(Validator $validator): array
|
||||
{
|
||||
/**
|
||||
* To always return json
|
||||
*/
|
||||
throw new HttpResponseException(response()->json([
|
||||
'errors' => $validator->errors(),
|
||||
'status' => true
|
||||
], 422));
|
||||
}
|
||||
|
||||
}
|
||||
|
58
app/application/app/Jobs/Translate/ProcessProjectContent.php
Normal file
58
app/application/app/Jobs/Translate/ProcessProjectContent.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Jobs\Translate;
|
||||
|
||||
use App\Services\Translate\Project\ProjectContentService;
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||
|
||||
final class ProcessProjectContent implements ShouldQueue, ShouldBeEncrypted
|
||||
{
|
||||
use Dispatchable, Queueable;
|
||||
|
||||
/**
|
||||
* Get the middleware the job should pass through.
|
||||
*
|
||||
* @return array<int, object>
|
||||
*/
|
||||
public function middleware(): array
|
||||
{
|
||||
return [
|
||||
(new WithoutOverlapping($this->uniqueId()))->expireAfter(180),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly int $projectId,
|
||||
private readonly array $contentIds = [],
|
||||
private readonly array $exceptLanguages = [],
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Get the unique ID for the job.
|
||||
*/
|
||||
public function uniqueId(): string
|
||||
{
|
||||
return 'project-' . $this->projectId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handle(ProjectContentService $projectContentService): void
|
||||
{
|
||||
$result = $projectContentService->translate($this->projectId, $this->contentIds, $this->exceptLanguages);
|
||||
if ($result->isError() && $result->getCode() !== 404) {
|
||||
cache()->lock($this->uniqueId())->forceRelease();
|
||||
throw new Exception($result->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Jobs\Translate;
|
||||
|
||||
use App\Services\Translate\Project\DocumentationCategoryContentService;
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||
|
||||
final class ProcessProjectDocumentationCategoryContent implements ShouldQueue, ShouldBeEncrypted
|
||||
{
|
||||
use Dispatchable, Queueable;
|
||||
|
||||
/**
|
||||
* Get the middleware the job should pass through.
|
||||
*
|
||||
* @return array<int, object>
|
||||
*/
|
||||
public function middleware(): array
|
||||
{
|
||||
return [
|
||||
(new WithoutOverlapping($this->uniqueId()))->expireAfter(180),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly int $projectDocumentCategoryId,
|
||||
private readonly array $contentIds = [],
|
||||
private readonly array $exceptLanguages = [],
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Get the unique ID for the job.
|
||||
*/
|
||||
public function uniqueId(): string
|
||||
{
|
||||
return 'documentation-category-' . $this->projectDocumentCategoryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handle(DocumentationCategoryContentService $categoryContentService): void
|
||||
{
|
||||
$result = $categoryContentService->translate($this->projectDocumentCategoryId, $this->contentIds, $this->exceptLanguages);
|
||||
if ($result->isError() && $result->getCode() !== 404) {
|
||||
cache()->lock($this->uniqueId())->forceRelease();
|
||||
throw new Exception($result->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Jobs\Translate;
|
||||
|
||||
use App\Services\Translate\Project\DocumentationContentService;
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||
|
||||
final class ProcessProjectDocumentationContent implements ShouldQueue, ShouldBeEncrypted
|
||||
{
|
||||
use Dispatchable, Queueable;
|
||||
|
||||
/**
|
||||
* Get the middleware the job should pass through.
|
||||
*
|
||||
* @return array<int, object>
|
||||
*/
|
||||
public function middleware(): array
|
||||
{
|
||||
return [
|
||||
(new WithoutOverlapping($this->uniqueId()))->expireAfter(180),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly int $projectDocumentId,
|
||||
private readonly array $contentIds = [],
|
||||
private readonly array $exceptLanguages = [],
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Get the unique ID for the job.
|
||||
*/
|
||||
public function uniqueId(): string
|
||||
{
|
||||
return 'documentation-' . $this->projectDocumentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handle(DocumentationContentService $documentationContentService): void
|
||||
{
|
||||
$result = $documentationContentService->translate($this->projectDocumentId, $this->contentIds, $this->exceptLanguages);
|
||||
if ($result->isError() && $result->getCode() !== 404) {
|
||||
cache()->lock($this->uniqueId())->forceRelease();
|
||||
throw new Exception($result->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Jobs\Translate;
|
||||
|
||||
use App\Services\Translate\Project\TranslationTextService;
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||
|
||||
final class ProcessTranslationText implements ShouldQueue, ShouldBeEncrypted
|
||||
{
|
||||
use Dispatchable, Queueable;
|
||||
|
||||
/**
|
||||
* Get the middleware the job should pass through.
|
||||
*
|
||||
* @return array<int, object>
|
||||
*/
|
||||
public function middleware(): array
|
||||
{
|
||||
return [
|
||||
(new WithoutOverlapping($this->uniqueId()))->expireAfter(180),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly int $projectId,
|
||||
private readonly int $languageId,
|
||||
private readonly array $translateTextCode = [],
|
||||
private readonly array $exceptLanguages = [],
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Get the unique ID for the job.
|
||||
*/
|
||||
public function uniqueId(): string
|
||||
{
|
||||
return 'ProcessTranslationText-' . $this->projectId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handle(TranslationTextService $translationTextService): void
|
||||
{
|
||||
$result = $translationTextService->translate($this->projectId, $this->languageId, $this->translateTextCode, $this->exceptLanguages);
|
||||
if ($result->isError() && $result->getCode() !== 404) {
|
||||
cache()->lock($this->uniqueId())->forceRelease();
|
||||
throw new Exception($result->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
69
app/application/app/Models/Documentation.php
Normal file
69
app/application/app/Models/Documentation.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Scopes\SortScope;
|
||||
use Illuminate\Database\Eloquent\Attributes\ScopedBy;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
#[ScopedBy([SortScope::class])]
|
||||
final class Documentation extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $table = 'documentation';
|
||||
|
||||
/**
|
||||
* The model's default values for attributes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attributes = [
|
||||
'sort' => 100,
|
||||
'is_public' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'slug',
|
||||
'is_public',
|
||||
'category_id',
|
||||
'sort',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'is_public' => 'boolean',
|
||||
];
|
||||
}
|
||||
|
||||
public function category(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(DocumentationCategory::class, 'category_id', 'id');
|
||||
}
|
||||
|
||||
public function contents(): HasMany
|
||||
{
|
||||
return $this->hasMany(DocumentationContent::class, 'documentation_id', 'id');
|
||||
}
|
||||
|
||||
public function content(): HasOne
|
||||
{
|
||||
return $this->hasOne(DocumentationContent::class, 'documentation_id', 'id');
|
||||
}
|
||||
}
|
75
app/application/app/Models/DocumentationCategory.php
Normal file
75
app/application/app/Models/DocumentationCategory.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Scopes\SortScope;
|
||||
use Illuminate\Database\Eloquent\Attributes\ScopedBy;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships;
|
||||
|
||||
#[ScopedBy([SortScope::class])]
|
||||
final class DocumentationCategory extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes, HasRecursiveRelationships;
|
||||
|
||||
protected $table = 'documentation_categories';
|
||||
|
||||
/**
|
||||
* The model's default values for attributes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attributes = [
|
||||
'sort' => 100,
|
||||
'is_public' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'slug',
|
||||
'sort',
|
||||
'parent_id',
|
||||
'is_public',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'is_public' => 'boolean',
|
||||
];
|
||||
}
|
||||
|
||||
public function parent(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(DocumentationCategory::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function contents(): HasMany
|
||||
{
|
||||
return $this->hasMany(DocumentationCategoryContent::class, 'category_id');
|
||||
}
|
||||
|
||||
public function content(): HasOne
|
||||
{
|
||||
return $this->hasOne(DocumentationCategoryContent::class, 'category_id');
|
||||
}
|
||||
|
||||
public function version(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(DocumentationVersion::class, 'version_id');
|
||||
}
|
||||
}
|
24
app/application/app/Models/DocumentationCategoryContent.php
Normal file
24
app/application/app/Models/DocumentationCategoryContent.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?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 DocumentationCategoryContent extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $table = 'documentation_category_content';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'language_id',
|
||||
];
|
||||
}
|
27
app/application/app/Models/DocumentationContent.php
Normal file
27
app/application/app/Models/DocumentationContent.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Contracts\Models\Storage as StorageContract;
|
||||
use App\Models\Traits\StorageTrait;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
final class DocumentationContent extends Model implements StorageContract
|
||||
{
|
||||
use HasFactory, SoftDeletes, StorageTrait;
|
||||
|
||||
protected $table = 'documentation_content';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'content',
|
||||
'language_id',
|
||||
];
|
||||
}
|
78
app/application/app/Models/DocumentationVersion.php
Normal file
78
app/application/app/Models/DocumentationVersion.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\DocumentationVersionStatus;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
final class DocumentationVersion extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $table = 'documentation_versions';
|
||||
|
||||
/**
|
||||
* The model's default values for attributes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attributes = [
|
||||
'is_public' => true,
|
||||
'status' => DocumentationVersionStatus::CurrentVersion,
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'slug',
|
||||
'is_public',
|
||||
'status',
|
||||
];
|
||||
|
||||
/**
|
||||
* The "booted" method of the model.
|
||||
*/
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::addGlobalScope('status', function (Builder $builder) {
|
||||
$builder->orderBy('status', 'desc');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'is_public' => 'boolean',
|
||||
'status' => DocumentationVersionStatus::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function project(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Project::class);
|
||||
}
|
||||
|
||||
public function documentations(): HasMany
|
||||
{
|
||||
return $this->hasMany(Documentation::class, 'version_id');
|
||||
}
|
||||
|
||||
public function categories(): HasMany
|
||||
{
|
||||
return $this->hasMany(DocumentationCategory::class, 'version_id');
|
||||
}
|
||||
}
|
@@ -62,4 +62,9 @@ final class Project extends Model implements StorageContract
|
||||
{
|
||||
return $this->hasMany(ProjectFeedback::class);
|
||||
}
|
||||
|
||||
public function documentationVersions(): HasMany
|
||||
{
|
||||
return $this->hasMany(DocumentationVersion::class);
|
||||
}
|
||||
}
|
||||
|
@@ -2,18 +2,21 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Contracts\Models\Storage as StorageContract;
|
||||
use App\Models\Traits\StorageTrait;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
final class ProjectContent extends Model
|
||||
final class ProjectContent extends Model implements StorageContract
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
use HasFactory, SoftDeletes, StorageTrait;
|
||||
|
||||
protected $table = 'project_content';
|
||||
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'description',
|
||||
'language_id',
|
||||
];
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ use App\Models\Scopes\SortScope;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Database\Eloquent\Attributes\ScopedBy;
|
||||
|
||||
@@ -70,4 +71,9 @@ final class ProjectLanguage extends Model
|
||||
},
|
||||
)->shouldCache();
|
||||
}
|
||||
|
||||
public function serviceTranslate(): HasOne
|
||||
{
|
||||
return $this->hasOne(ProjectTranslationService::class, 'language_id', 'id');
|
||||
}
|
||||
}
|
||||
|
24
app/application/app/Models/ProjectTranslationService.php
Normal file
24
app/application/app/Models/ProjectTranslationService.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
final class ProjectTranslationService extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'project_translation_service';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'code',
|
||||
'language_id',
|
||||
'source_language_id',
|
||||
];
|
||||
}
|
51
app/application/app/Models/ProjectTranslationServiceHash.php
Normal file
51
app/application/app/Models/ProjectTranslationServiceHash.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\Morph;
|
||||
use App\Enums\ProjectTranslationServiceHashes\Status;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
final class ProjectTranslationServiceHash extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'project_translation_service_hashes';
|
||||
|
||||
/**
|
||||
* The model's default values for attributes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attributes = [
|
||||
'status' => Status::Waiting,
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'language_id',
|
||||
'field',
|
||||
'status',
|
||||
'hash',
|
||||
'morph_type',
|
||||
'morph_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'status' => Status::class,
|
||||
'morph_type' => Morph::class,
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\ProjectTranslationServiceHashes\Status;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
final class ProjectTranslationServiceTextHash extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'project_translation_service_text_hashes';
|
||||
|
||||
/**
|
||||
* The model's default values for attributes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attributes = [
|
||||
'status' => Status::Waiting,
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'language_id',
|
||||
'code',
|
||||
'status',
|
||||
'hash',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'status' => Status::class,
|
||||
];
|
||||
}
|
||||
}
|
60
app/application/app/Notifications/ReviewAdded.php
Normal file
60
app/application/app/Notifications/ReviewAdded.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Enums\Site\ProjectSection;
|
||||
use App\Models\ProjectFeedback;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
final class ReviewAdded extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ProjectFeedback $feedback
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*/
|
||||
public function toMail(object $notifiable): MailMessage
|
||||
{
|
||||
$project = $this->feedback->project;
|
||||
|
||||
return (new MailMessage)
|
||||
->subject(__('notification.Review Added: :name', ['name' => $project->name]))
|
||||
->line(__('notification.Added a new review.'))
|
||||
->action(__('notification.Project :name', ['name' => $project->name]), \url(ProjectSection::Home->url($project)))
|
||||
->line( __('site.attributes.name') . ': ' . $this->feedback->name)
|
||||
->line( __('site.attributes.email') . ': ' . $this->feedback->email)
|
||||
->line(__('site.attributes.message') . ': ' . $this->feedback->message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(object $notifiable): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
34
app/application/app/Policies/DocumentationCategoryPolicy.php
Normal file
34
app/application/app/Policies/DocumentationCategoryPolicy.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\DocumentationCategory;
|
||||
use App\Models\User;
|
||||
|
||||
final readonly class DocumentationCategoryPolicy extends Policy
|
||||
{
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('documentation-category.view');
|
||||
}
|
||||
|
||||
public function view(User $user, DocumentationCategory $category): bool
|
||||
{
|
||||
return $user->hasPermission('documentation-category.view');
|
||||
}
|
||||
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('documentation-category.create');
|
||||
}
|
||||
|
||||
public function update(User $user, DocumentationCategory $category): bool
|
||||
{
|
||||
return $user->hasPermission('documentation.update');
|
||||
}
|
||||
|
||||
public function delete(User $user, DocumentationCategory $category): bool
|
||||
{
|
||||
return $user->hasPermission('documentation-category.delete');
|
||||
}
|
||||
}
|
17
app/application/app/Policies/DocumentationContentPolicy.php
Normal file
17
app/application/app/Policies/DocumentationContentPolicy.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
final readonly class DocumentationContentPolicy extends Policy
|
||||
{
|
||||
public function upload(User $user): bool
|
||||
{
|
||||
if ($user->hasPermission('documentation.create') || $user->hasPermission('documentation.update')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
34
app/application/app/Policies/DocumentationPolicy.php
Normal file
34
app/application/app/Policies/DocumentationPolicy.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Documentation;
|
||||
use App\Models\User;
|
||||
|
||||
final readonly class DocumentationPolicy extends Policy
|
||||
{
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('documentation.view');
|
||||
}
|
||||
|
||||
public function view(User $user, Documentation $documentation): bool
|
||||
{
|
||||
return $user->hasPermission('documentation.view');
|
||||
}
|
||||
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('documentation.create');
|
||||
}
|
||||
|
||||
public function update(User $user, Documentation $documentation): bool
|
||||
{
|
||||
return $user->hasPermission('documentation.update');
|
||||
}
|
||||
|
||||
public function delete(User $user, Documentation $documentation): bool
|
||||
{
|
||||
return $user->hasPermission('documentation.delete');
|
||||
}
|
||||
}
|
39
app/application/app/Policies/DocumentationVersionPolicy.php
Normal file
39
app/application/app/Policies/DocumentationVersionPolicy.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\DocumentationVersion;
|
||||
use App\Models\User;
|
||||
|
||||
final readonly class DocumentationVersionPolicy extends Policy
|
||||
{
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
// Not a mistake or typo. Shared rights with Documentation.
|
||||
return $user->hasPermission('documentation.view');
|
||||
}
|
||||
|
||||
public function view(User $user, DocumentationVersion $documentationVersion): bool
|
||||
{
|
||||
// Not a mistake or typo. Shared rights with Documentation.
|
||||
return $user->hasPermission('documentation.view');
|
||||
}
|
||||
|
||||
public function create(User $user): bool
|
||||
{
|
||||
// Not a mistake or typo. Shared rights with Documentation.
|
||||
return $user->hasPermission('documentation.create');
|
||||
}
|
||||
|
||||
public function update(User $user, DocumentationVersion $documentationVersion): bool
|
||||
{
|
||||
// Not a mistake or typo. Shared rights with Documentation.
|
||||
return $user->hasPermission('documentation.update');
|
||||
}
|
||||
|
||||
public function delete(User $user, DocumentationVersion $documentationVersion): bool
|
||||
{
|
||||
// Not a mistake or typo. Shared rights with Documentation.
|
||||
return $user->hasPermission('documentation.delete');
|
||||
}
|
||||
}
|
@@ -26,4 +26,13 @@ final readonly class ProjectContentPolicy extends Policy
|
||||
{
|
||||
return $user->hasPermission('project-content.update');
|
||||
}
|
||||
|
||||
public function upload(User $user): bool
|
||||
{
|
||||
if ($user->hasPermission('project-content.create') || $user->hasPermission('project-content.update')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -32,6 +32,11 @@ final readonly class ProjectPolicy extends Policy
|
||||
return $user->hasPermission('project.delete');
|
||||
}
|
||||
|
||||
public function settingUpAutomaticTranslation(User $user, Project $project): bool
|
||||
{
|
||||
return $user->hasPermission('project.setting-up-automatic-translation');
|
||||
}
|
||||
|
||||
public function upload(User $user): bool
|
||||
{
|
||||
if ($user->hasPermission('project.create') || $user->hasPermission('project.update')) {
|
||||
|
@@ -3,8 +3,10 @@
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Enums\Morph;
|
||||
use App\Services\ProjectFeedback\ProjectFeedbackCommandHandler;
|
||||
use App\Services\Search\CreateSearchInstanceCommand;
|
||||
use App\Services\Search\Search;
|
||||
use App\Services\Site\FeedbackService;
|
||||
use App\Services\Storage\Image\ResizeCommandHandler;
|
||||
use App\Services\Storage\ImageService;
|
||||
use App\Services\Storage\StorageCommandHandler;
|
||||
@@ -31,7 +33,15 @@ class AppServiceProvider extends ServiceProvider
|
||||
});
|
||||
|
||||
$this->app->bind(StorageCommandHandler::class, function () {
|
||||
return new StorageCommandHandler(disc: (string) config('storage.disk'));
|
||||
return new StorageCommandHandler(disc: (string) \config('storage.disk'));
|
||||
});
|
||||
|
||||
$this->app->bind(FeedbackService::class, function (Application $app) {
|
||||
return new FeedbackService(
|
||||
$app->make(ProjectFeedbackCommandHandler::class),
|
||||
(bool) \config('feedback.mail_notifications', false),
|
||||
\config('feedback.mail_to', null),
|
||||
);
|
||||
});
|
||||
|
||||
$this->app->bind(ImageService::class, function (Application $app) {
|
||||
@@ -59,6 +69,8 @@ class AppServiceProvider extends ServiceProvider
|
||||
|
||||
Route::pattern('language', '[a-z_]+');
|
||||
Route::pattern('project', '[a-z0-9_-]+');
|
||||
Route::pattern('slug', '[a-z0-9._-]+');
|
||||
Route::pattern('version', '[a-z0-9._-]+');
|
||||
|
||||
$this->configureRateLimiting();
|
||||
Gate::define('AdminPanel', [\App\Policies\AdminPanel::class, 'view']);
|
||||
|
@@ -0,0 +1,96 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Contracts\Search;
|
||||
use App\Models\DocumentationCategory;
|
||||
use App\Models\DocumentationVersion;
|
||||
use App\Models\ProjectLanguage;
|
||||
use App\Services\DocumentationCategory\BuilderCommand;
|
||||
use App\Services\Search\CreateSearchInstanceCommand;
|
||||
use App\Dto\Builder\DocumentationCategory as DocumentationCategoryBuilderDto;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
final readonly class DocumentationCategoryRepository
|
||||
{
|
||||
public function __construct(
|
||||
private CreateSearchInstanceCommand $createSearchInstanceCommand,
|
||||
private BuilderCommand $builderCommand
|
||||
) { }
|
||||
|
||||
public function getCategories(int $versionId, DocumentationCategoryBuilderDto $documentationCategoryBuilderDto, array $with = []): Search
|
||||
{
|
||||
$query = $this->builderCommand->execute(
|
||||
query: DocumentationCategory::query()->where('version_id', $versionId)->with($with),
|
||||
documentationCategoryBuilderDto: $documentationCategoryBuilderDto
|
||||
);
|
||||
|
||||
return $this->createSearchInstanceCommand->execute($query);
|
||||
}
|
||||
|
||||
public function getCategoryById(int $id): ?DocumentationCategory
|
||||
{
|
||||
return DocumentationCategory::query()->where('id', $id)->first();
|
||||
}
|
||||
|
||||
public function getCategoryBySlugWithContent(string $slug, int $versionId, ProjectLanguage $language): ?DocumentationCategory
|
||||
{
|
||||
$with = [
|
||||
'content' => function (HasOne $hasOne) use ($language) {
|
||||
$hasOne->where('language_id', $language->id);
|
||||
}
|
||||
];
|
||||
|
||||
return DocumentationCategory::query()
|
||||
->where('version_id', $versionId)
|
||||
->where('slug', $slug)
|
||||
->with($with)
|
||||
->first();
|
||||
}
|
||||
|
||||
public function isExistsSlug(int $versionId, string $slug, ?int $exceptId = null): bool
|
||||
{
|
||||
return DocumentationCategory::query()
|
||||
->where('version_id', $versionId)
|
||||
->where('slug', Str::lower($slug))
|
||||
->when($exceptId, function (Builder $query, int $exceptId) {
|
||||
$query->where('id', '!=', $exceptId);
|
||||
})
|
||||
->withTrashed()
|
||||
->exists();
|
||||
}
|
||||
|
||||
public function getForSelect(DocumentationVersion $version, ?ProjectLanguage $defaultLanguage, ?DocumentationCategory $exceptCategory = null, array $withExcepts = []): array
|
||||
{
|
||||
$with = [
|
||||
'content' => function (HasOne $hasOne) use ($defaultLanguage) {
|
||||
$hasOne->when($defaultLanguage, function (Builder $query, ProjectLanguage $defaultLanguage) {
|
||||
$query->where('language_id', $defaultLanguage->id);
|
||||
});
|
||||
}
|
||||
];
|
||||
|
||||
$categories = $version->categories()
|
||||
->with($with)
|
||||
->when($exceptCategory, function (Builder $query, DocumentationCategory $exceptCategory) {
|
||||
$query->whereNotIn(
|
||||
'id',
|
||||
$exceptCategory->descendantsAndSelf()->pluck('id')->toArray()
|
||||
);
|
||||
})
|
||||
->when($withExcepts, function (Builder $query) use ($withExcepts) {
|
||||
$query->withTrashed()->whereNull('deleted_at')->orWhereIn('id', $withExcepts);
|
||||
})->get();
|
||||
|
||||
return $categories->map(function (DocumentationCategory $documentationCategory) use ($defaultLanguage) {
|
||||
return [
|
||||
'id' => $documentationCategory->id,
|
||||
'title' => $documentationCategory->content?->title ?? $documentationCategory->slug,
|
||||
];
|
||||
})
|
||||
->pluck('title', 'id')
|
||||
->toArray();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user