Compare commits
1 Commits
4dc6060fb3
...
0.2.1
Author | SHA1 | Date | |
---|---|---|---|
417ce35fc8 |
@@ -7,7 +7,6 @@
|
|||||||
**/storage/framework/sessions/*
|
**/storage/framework/sessions/*
|
||||||
**/storage/framework/views/*
|
**/storage/framework/views/*
|
||||||
**/storage/framework/testing/*
|
**/storage/framework/testing/*
|
||||||
**/storage/translation_service/*
|
|
||||||
**/storage/logs/*
|
**/storage/logs/*
|
||||||
**/vendor/
|
**/vendor/
|
||||||
**/node_modules/
|
**/node_modules/
|
||||||
|
@@ -1,33 +1,15 @@
|
|||||||
APP_NAME="My Projects Website"
|
APP_NAME=Laravel
|
||||||
APP_ENV=local
|
APP_ENV=local
|
||||||
APP_KEY=
|
APP_KEY=
|
||||||
APP_DEBUG=true
|
APP_DEBUG=true
|
||||||
APP_TIMEZONE=UTC
|
APP_TIMEZONE=UTC
|
||||||
APP_URL=http://localhost
|
APP_URL=http://localhost
|
||||||
|
|
||||||
APP_CAPTCHA=false
|
|
||||||
CAPTCHA_API_DOMAIN=http://your-domain-captcha-or-IP:8081
|
CAPTCHA_API_DOMAIN=http://your-domain-captcha-or-IP:8081
|
||||||
CAPTCHA_PRIVATE_TOKEN=
|
CAPTCHA_PRIVATE_TOKEN=
|
||||||
CAPTCHA_STATIC_PATH=http://your-domain-captcha-or-IP:8081/captcha
|
CAPTCHA_STATIC_PATH=http://your-domain-captcha-or-IP:8081/captcha
|
||||||
CAPTCHA_PUBLIC_TOKEN=
|
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
|
APP_FORCE_HTTPS=false
|
||||||
|
|
||||||
APP_DEFAULT_LOCALE=ru
|
APP_DEFAULT_LOCALE=ru
|
||||||
@@ -76,7 +58,7 @@ REDIS_HOST=app-redis
|
|||||||
REDIS_PASSWORD=null
|
REDIS_PASSWORD=null
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|
||||||
MAIL_MAILER=smtp
|
MAIL_MAILER=log
|
||||||
MAIL_HOST=127.0.0.1
|
MAIL_HOST=127.0.0.1
|
||||||
MAIL_PORT=2525
|
MAIL_PORT=2525
|
||||||
MAIL_USERNAME=null
|
MAIL_USERNAME=null
|
||||||
|
@@ -1,50 +0,0 @@
|
|||||||
<?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());
|
|
||||||
}
|
|
||||||
}
|
|
@@ -3,14 +3,12 @@
|
|||||||
namespace App\Dto\Service\Admin\Project\About;
|
namespace App\Dto\Service\Admin\Project\About;
|
||||||
|
|
||||||
use App\Dto\Service\Dto;
|
use App\Dto\Service\Dto;
|
||||||
use App\Dto\Service\Storage\Storages;
|
|
||||||
|
|
||||||
final readonly class StoreUpdate extends Dto
|
final readonly class StoreUpdate extends Dto
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private string $title,
|
private string $title,
|
||||||
private string $description,
|
private string $description,
|
||||||
private Storages $storages,
|
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public function getTitle(): string
|
public function getTitle(): string
|
||||||
@@ -22,9 +20,4 @@ final readonly class StoreUpdate extends Dto
|
|||||||
{
|
{
|
||||||
return $this->description;
|
return $this->description;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getStorages(): Storages
|
|
||||||
{
|
|
||||||
return $this->storages;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,6 @@ final readonly class Content
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
private int $languageId,
|
private int $languageId,
|
||||||
private string $title,
|
private string $title,
|
||||||
private bool $isTranslateAutomatically = false,
|
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public function getLanguageId(): int
|
public function getLanguageId(): int
|
||||||
@@ -19,9 +18,4 @@ final readonly class Content
|
|||||||
{
|
{
|
||||||
return $this->title;
|
return $this->title;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isTranslateAutomatically(): bool
|
|
||||||
{
|
|
||||||
return $this->isTranslateAutomatically;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -2,16 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Dto\Service\Admin\Project\DocumentationContent;
|
namespace App\Dto\Service\Admin\Project\DocumentationContent;
|
||||||
|
|
||||||
use App\Dto\Service\Storage\Storages;
|
|
||||||
|
|
||||||
final readonly class Content
|
final readonly class Content
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private int $languageId,
|
private int $languageId,
|
||||||
private string $title,
|
private string $title,
|
||||||
private string $content,
|
private string $content,
|
||||||
private Storages $storages,
|
|
||||||
private bool $isTranslateAutomatically = false,
|
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public function getLanguageId(): int
|
public function getLanguageId(): int
|
||||||
@@ -28,14 +24,4 @@ final readonly class Content
|
|||||||
{
|
{
|
||||||
return $this->content;
|
return $this->content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getStorages(): Storages
|
|
||||||
{
|
|
||||||
return $this->storages;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isTranslateAutomatically(): bool
|
|
||||||
{
|
|
||||||
return $this->isTranslateAutomatically;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,29 +0,0 @@
|
|||||||
<?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;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,18 +0,0 @@
|
|||||||
<?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;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
<?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;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,30 +0,0 @@
|
|||||||
<?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;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,25 +0,0 @@
|
|||||||
<?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);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,18 +0,0 @@
|
|||||||
<?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;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,28 +0,0 @@
|
|||||||
<?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;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,37 +0,0 @@
|
|||||||
<?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] ?? [];
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,29 +0,0 @@
|
|||||||
<?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;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -2,25 +2,16 @@
|
|||||||
|
|
||||||
namespace App\Enums;
|
namespace App\Enums;
|
||||||
|
|
||||||
use App\Models\DocumentationCategoryContent;
|
|
||||||
use App\Models\DocumentationContent;
|
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\ProjectContent;
|
|
||||||
|
|
||||||
enum Morph: int
|
enum Morph: int
|
||||||
{
|
{
|
||||||
case Project = 1;
|
case Project = 1;
|
||||||
case DocumentationContent = 2;
|
|
||||||
case ProjectContent = 3;
|
|
||||||
case DocumentationCategoryContent = 4;
|
|
||||||
|
|
||||||
public function getPathModel(): string
|
public function getPathModel(): string
|
||||||
{
|
{
|
||||||
return match ($this) {
|
return match ($this) {
|
||||||
self::Project => Project::class,
|
self::Project => Project::class,
|
||||||
self::DocumentationContent => DocumentationContent::class,
|
|
||||||
self::ProjectContent => ProjectContent::class,
|
|
||||||
self::DocumentationCategoryContent => DocumentationCategoryContent::class,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,9 +21,6 @@ enum Permission: string
|
|||||||
self::AdminPanel => [
|
self::AdminPanel => [
|
||||||
'view' => __('permissions.Administrative panel allowed'),
|
'view' => __('permissions.Administrative panel allowed'),
|
||||||
],
|
],
|
||||||
self::Project => array_merge($this->getBasePermissions(), [
|
|
||||||
'Setting up automatic translation' => __('permissions.Setting up automatic translation'),
|
|
||||||
]),
|
|
||||||
self::ProjectContent => [
|
self::ProjectContent => [
|
||||||
'view' => __('permissions.Allowed to watch'),
|
'view' => __('permissions.Allowed to watch'),
|
||||||
'create' => __('permissions.Allowed to create'),
|
'create' => __('permissions.Allowed to create'),
|
||||||
|
@@ -1,9 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Enums\ProjectTranslationServiceHashes;
|
|
||||||
|
|
||||||
enum Status: int
|
|
||||||
{
|
|
||||||
case Waiting = 0;
|
|
||||||
case Success = 10;
|
|
||||||
}
|
|
@@ -9,13 +9,11 @@ use App\Contracts\StorageType\Video;
|
|||||||
enum StorageType: int implements Image, Video, Audio
|
enum StorageType: int implements Image, Video, Audio
|
||||||
{
|
{
|
||||||
case Logo = 1;
|
case Logo = 1;
|
||||||
case ContentImages = 2;
|
|
||||||
|
|
||||||
public function getTitle(): string
|
public function getTitle(): string
|
||||||
{
|
{
|
||||||
return match ($this) {
|
return match ($this) {
|
||||||
self::Logo => __('validation.attributes.logo'),
|
self::Logo => __('validation.attributes.logo'),
|
||||||
self::ContentImages => __('validation.attributes.content_images'),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,7 +21,6 @@ enum StorageType: int implements Image, Video, Audio
|
|||||||
{
|
{
|
||||||
return match ($this) {
|
return match ($this) {
|
||||||
self::Logo => ['jpeg', 'jpg', 'png'],
|
self::Logo => ['jpeg', 'jpg', 'png'],
|
||||||
self::ContentImages => ['jpeg', 'jpg', 'png'],
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,21 +28,20 @@ enum StorageType: int implements Image, Video, Audio
|
|||||||
{
|
{
|
||||||
return match ($this) {
|
return match ($this) {
|
||||||
self::Logo => true,
|
self::Logo => true,
|
||||||
self::ContentImages => true,
|
|
||||||
default => false
|
default => false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isVideo(): bool
|
public function isVideo(): bool
|
||||||
{
|
{
|
||||||
return match ($this) {
|
return match ($this->name) {
|
||||||
default => false
|
default => false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isAudio(): bool
|
public function isAudio(): bool
|
||||||
{
|
{
|
||||||
return match ($this) {
|
return match ($this->name) {
|
||||||
default => false
|
default => false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,18 +0,0 @@
|
|||||||
<?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;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,8 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Exceptions\Services\Translate;
|
|
||||||
|
|
||||||
final class CompletedException extends \Exception
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
@@ -1,41 +0,0 @@
|
|||||||
<?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,9 +19,7 @@ final class AuthController extends Controller
|
|||||||
|
|
||||||
public function login(): View
|
public function login(): View
|
||||||
{
|
{
|
||||||
return view('login', [
|
return view('login');
|
||||||
'captcha' => config('app.captcha', false),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function authorization(AuthorizationRequest $request): RedirectResponse
|
public function authorization(AuthorizationRequest $request): RedirectResponse
|
||||||
|
@@ -19,7 +19,6 @@ final class FeedbackController extends Controller
|
|||||||
return view('site.feedback.index', [
|
return view('site.feedback.index', [
|
||||||
'project' => $request->get('project'),
|
'project' => $request->get('project'),
|
||||||
'websiteTranslations' => $request->get('websiteTranslations'),
|
'websiteTranslations' => $request->get('websiteTranslations'),
|
||||||
'captcha' => config('app.captcha', false),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,19 +4,10 @@ namespace App\Http\Requests\Admin\Projects\About;
|
|||||||
|
|
||||||
use App\Contracts\FormRequestDto;
|
use App\Contracts\FormRequestDto;
|
||||||
use App\Dto\Service\Admin\Project\About\StoreUpdate;
|
use App\Dto\Service\Admin\Project\About\StoreUpdate;
|
||||||
use App\Dto\Service\Storage\Storages;
|
|
||||||
use App\Enums\StorageType;
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
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.
|
* Get the validation rules that apply to the request.
|
||||||
*/
|
*/
|
||||||
@@ -25,7 +16,6 @@ final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
|||||||
return [
|
return [
|
||||||
'title' => ['required', 'string', 'max:255',],
|
'title' => ['required', 'string', 'max:255',],
|
||||||
'description' => ['nullable', 'string',],
|
'description' => ['nullable', 'string',],
|
||||||
'storage.content_images.*.file' => ['numeric', 'min:1'],
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,18 +24,6 @@ final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
|||||||
return new StoreUpdate(
|
return new StoreUpdate(
|
||||||
title: $this->input('title'),
|
title: $this->input('title'),
|
||||||
description: $this->input('description'),
|
description: $this->input('description'),
|
||||||
storages: $this->storages(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function storages(): Storages
|
|
||||||
{
|
|
||||||
$storages = new Storages();
|
|
||||||
|
|
||||||
$content = $this->input('storage', []);
|
|
||||||
$images = $content['content_images'] ?? [];
|
|
||||||
$storages->addMany($images, StorageType::ContentImages);
|
|
||||||
|
|
||||||
return $storages;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -21,7 +21,6 @@ final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
|||||||
'sort' => ['required', 'integer', 'min:-1000', 'max:1000'],
|
'sort' => ['required', 'integer', 'min:-1000', 'max:1000'],
|
||||||
'parent_id' => ['nullable', 'integer', 'exists:documentation_categories,id'],
|
'parent_id' => ['nullable', 'integer', 'exists:documentation_categories,id'],
|
||||||
'content.*.title' => ['required', 'string', 'max:255'],
|
'content.*.title' => ['required', 'string', 'max:255'],
|
||||||
'translate-automatically.*' => ['nullable', 'boolean'],
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +47,6 @@ final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
|||||||
$contents->addContent(new Content(
|
$contents->addContent(new Content(
|
||||||
languageId: (int) $languageId,
|
languageId: (int) $languageId,
|
||||||
title: $content['title'],
|
title: $content['title'],
|
||||||
isTranslateAutomatically: (bool) $this->input('translate-automatically.' . $languageId, false),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
return $contents;
|
return $contents;
|
||||||
|
@@ -6,19 +6,10 @@ use App\Contracts\FormRequestDto;
|
|||||||
use App\Dto\Service\Admin\Project\Documentation\StoreUpdate;
|
use App\Dto\Service\Admin\Project\Documentation\StoreUpdate;
|
||||||
use App\Dto\Service\Admin\Project\DocumentationContent\Content;
|
use App\Dto\Service\Admin\Project\DocumentationContent\Content;
|
||||||
use App\Dto\Service\Admin\Project\DocumentationContent\Contents;
|
use App\Dto\Service\Admin\Project\DocumentationContent\Contents;
|
||||||
use App\Dto\Service\Storage\Storages;
|
|
||||||
use App\Enums\StorageType;
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
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.
|
* Get the validation rules that apply to the request.
|
||||||
*/
|
*/
|
||||||
@@ -31,8 +22,6 @@ final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
|||||||
'category_id' => ['nullable', 'integer', 'exists:documentation_categories,id'],
|
'category_id' => ['nullable', 'integer', 'exists:documentation_categories,id'],
|
||||||
'content.*.title' => ['required', 'string', 'max:255'],
|
'content.*.title' => ['required', 'string', 'max:255'],
|
||||||
'content.*.content' => ['nullable', 'string'],
|
'content.*.content' => ['nullable', 'string'],
|
||||||
'content.*.content_images.*.file' => ['numeric', 'min:1'],
|
|
||||||
'translate-automatically.*' => ['nullable', 'boolean'],
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,20 +49,8 @@ final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
|||||||
languageId: (int) $languageId,
|
languageId: (int) $languageId,
|
||||||
title: $content['title'],
|
title: $content['title'],
|
||||||
content: $content['content'] ?? '',
|
content: $content['content'] ?? '',
|
||||||
storages: $this->contentStorages($content),
|
|
||||||
isTranslateAutomatically: (bool) $this->input('translate-automatically.' . $languageId, false),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
return $contents;
|
return $contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function contentStorages(array $content): Storages
|
|
||||||
{
|
|
||||||
$storages = new Storages();
|
|
||||||
|
|
||||||
$images = $content['content_images'] ?? [];
|
|
||||||
$storages->addMany($images, StorageType::ContentImages);
|
|
||||||
|
|
||||||
return $storages;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,56 +0,0 @@
|
|||||||
<?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'],
|
|
||||||
'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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -13,17 +13,12 @@ final class AuthorizationRequest extends FormRequest implements FormRequestDto
|
|||||||
*/
|
*/
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
$rules = [
|
return [
|
||||||
'email' => ['required', 'email', 'max:255'],
|
'email' => ['required', 'email', 'max:255'],
|
||||||
'password' => ['required', 'min:3'],
|
'password' => ['required', 'min:3'],
|
||||||
|
'captcha-verified' => ['captcha'],
|
||||||
'remember' => ['nullable', 'boolean'],
|
'remember' => ['nullable', 'boolean'],
|
||||||
];
|
];
|
||||||
|
|
||||||
if (config('app.captcha', false)) {
|
|
||||||
$rules['captcha-verified'] = ['captcha'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $rules;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDto(): Authorization
|
public function getDto(): Authorization
|
||||||
|
@@ -32,17 +32,12 @@ final class SendRequest extends FormRequest implements FormRequestDto
|
|||||||
*/
|
*/
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
$rules = [
|
return [
|
||||||
'name' => ['nullable', 'string', 'max:255'],
|
'name' => ['nullable', 'string', 'max:255'],
|
||||||
'email' => ['nullable', 'string', 'max:255', 'email'],
|
'email' => ['nullable', 'string', 'max:255', 'email'],
|
||||||
'message' => ['required', 'string', 'max:5000'],
|
'message' => ['required', 'string', 'max:5000'],
|
||||||
|
'captcha-verified' => ['captcha'],
|
||||||
];
|
];
|
||||||
|
|
||||||
if (config('app.captcha', false)) {
|
|
||||||
$rules['captcha-verified'] = ['captcha'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $rules;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDto(): Send
|
public function getDto(): Send
|
||||||
|
@@ -6,9 +6,7 @@ use App\Contracts\FormRequestDto;
|
|||||||
use App\Dto\Service\Storage\Upload;
|
use App\Dto\Service\Storage\Upload;
|
||||||
use App\Enums\Morph;
|
use App\Enums\Morph;
|
||||||
use App\Enums\StorageType;
|
use App\Enums\StorageType;
|
||||||
use Illuminate\Contracts\Validation\Validator;
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Http\Exceptions\HttpResponseException;
|
|
||||||
use Illuminate\Validation\Rules\Enum;
|
use Illuminate\Validation\Rules\Enum;
|
||||||
|
|
||||||
final class ImageRequest extends FormRequest implements FormRequestDto
|
final class ImageRequest extends FormRequest implements FormRequestDto
|
||||||
@@ -39,20 +37,4 @@ final class ImageRequest extends FormRequest implements FormRequestDto
|
|||||||
morph: Morph::from((int) $this->input('morph')),
|
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,58 +0,0 @@
|
|||||||
<?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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,58 +0,0 @@
|
|||||||
<?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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -2,15 +2,13 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
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\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
final class DocumentationContent extends Model implements StorageContract
|
final class DocumentationContent extends Model
|
||||||
{
|
{
|
||||||
use HasFactory, SoftDeletes, StorageTrait;
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
protected $table = 'documentation_content';
|
protected $table = 'documentation_content';
|
||||||
|
|
||||||
|
@@ -2,15 +2,13 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
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\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
final class ProjectContent extends Model implements StorageContract
|
final class ProjectContent extends Model
|
||||||
{
|
{
|
||||||
use HasFactory, SoftDeletes, StorageTrait;
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
protected $table = 'project_content';
|
protected $table = 'project_content';
|
||||||
|
|
||||||
|
@@ -7,7 +7,6 @@ use App\Models\Scopes\SortScope;
|
|||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Database\Eloquent\Attributes\ScopedBy;
|
use Illuminate\Database\Eloquent\Attributes\ScopedBy;
|
||||||
|
|
||||||
@@ -71,9 +70,4 @@ final class ProjectLanguage extends Model
|
|||||||
},
|
},
|
||||||
)->shouldCache();
|
)->shouldCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function serviceTranslate(): HasOne
|
|
||||||
{
|
|
||||||
return $this->hasOne(ProjectTranslationService::class, 'language_id', 'id');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,24 +0,0 @@
|
|||||||
<?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',
|
|
||||||
];
|
|
||||||
}
|
|
@@ -1,51 +0,0 @@
|
|||||||
<?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,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,60 +0,0 @@
|
|||||||
<?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 [
|
|
||||||
//
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
<?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;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -26,13 +26,4 @@ final readonly class ProjectContentPolicy extends Policy
|
|||||||
{
|
{
|
||||||
return $user->hasPermission('project-content.update');
|
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,11 +32,6 @@ final readonly class ProjectPolicy extends Policy
|
|||||||
return $user->hasPermission('project.delete');
|
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
|
public function upload(User $user): bool
|
||||||
{
|
{
|
||||||
if ($user->hasPermission('project.create') || $user->hasPermission('project.update')) {
|
if ($user->hasPermission('project.create') || $user->hasPermission('project.update')) {
|
||||||
|
@@ -3,10 +3,8 @@
|
|||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
use App\Enums\Morph;
|
use App\Enums\Morph;
|
||||||
use App\Services\ProjectFeedback\ProjectFeedbackCommandHandler;
|
|
||||||
use App\Services\Search\CreateSearchInstanceCommand;
|
use App\Services\Search\CreateSearchInstanceCommand;
|
||||||
use App\Services\Search\Search;
|
use App\Services\Search\Search;
|
||||||
use App\Services\Site\FeedbackService;
|
|
||||||
use App\Services\Storage\Image\ResizeCommandHandler;
|
use App\Services\Storage\Image\ResizeCommandHandler;
|
||||||
use App\Services\Storage\ImageService;
|
use App\Services\Storage\ImageService;
|
||||||
use App\Services\Storage\StorageCommandHandler;
|
use App\Services\Storage\StorageCommandHandler;
|
||||||
@@ -33,15 +31,7 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
});
|
});
|
||||||
|
|
||||||
$this->app->bind(StorageCommandHandler::class, function () {
|
$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) {
|
$this->app->bind(ImageService::class, function (Application $app) {
|
||||||
|
@@ -11,6 +11,7 @@ use App\Services\Search\CreateSearchInstanceCommand;
|
|||||||
use App\Dto\Builder\DocumentationCategory as DocumentationCategoryBuilderDto;
|
use App\Dto\Builder\DocumentationCategory as DocumentationCategoryBuilderDto;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
final readonly class DocumentationCategoryRepository
|
final readonly class DocumentationCategoryRepository
|
||||||
@@ -62,7 +63,7 @@ final readonly class DocumentationCategoryRepository
|
|||||||
->exists();
|
->exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getForSelect(DocumentationVersion $version, ?ProjectLanguage $defaultLanguage, ?DocumentationCategory $exceptCategory = null, array $withExcepts = []): array
|
public function getForSelect(?ProjectLanguage $defaultLanguage, ?DocumentationCategory $exceptCategory = null, array $withExcepts = []): array
|
||||||
{
|
{
|
||||||
$with = [
|
$with = [
|
||||||
'content' => function (HasOne $hasOne) use ($defaultLanguage) {
|
'content' => function (HasOne $hasOne) use ($defaultLanguage) {
|
||||||
@@ -72,7 +73,7 @@ final readonly class DocumentationCategoryRepository
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
$categories = $version->categories()
|
$categories = DocumentationCategory::query()
|
||||||
->with($with)
|
->with($with)
|
||||||
->when($exceptCategory, function (Builder $query, DocumentationCategory $exceptCategory) {
|
->when($exceptCategory, function (Builder $query, DocumentationCategory $exceptCategory) {
|
||||||
$query->whereNotIn(
|
$query->whereNotIn(
|
||||||
|
@@ -1,38 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Repositories;
|
|
||||||
|
|
||||||
use App\Contracts\Search;
|
|
||||||
use App\Enums\Morph;
|
|
||||||
use App\Models\ProjectTranslationServiceHash;
|
|
||||||
use App\Services\Search\CreateSearchInstanceCommand;
|
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
|
||||||
|
|
||||||
final readonly class ProjectTranslationServiceHashRepository
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private CreateSearchInstanceCommand $createSearchInstanceCommand,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
public function getHashes(Morph $morph, int $morphId, ?array $languages = null, ?array $fields = null): Search
|
|
||||||
{
|
|
||||||
$query = ProjectTranslationServiceHash::query()
|
|
||||||
->where('morph_type', $morph)
|
|
||||||
->where('morph_id', $morphId)
|
|
||||||
->whereIn('language_id', $languages)
|
|
||||||
->when($languages, function (Builder $query) use ($languages) {
|
|
||||||
$query->whereIn('language_id', $languages);
|
|
||||||
})
|
|
||||||
->when($fields, function (Builder $query) use ($fields) {
|
|
||||||
$query->whereIn('field', $fields);
|
|
||||||
});
|
|
||||||
|
|
||||||
return $this->createSearchInstanceCommand->execute($query);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHashesByIds(array $ids): Search
|
|
||||||
{
|
|
||||||
$query = ProjectTranslationServiceHash::query()->whereIn('id', $ids);
|
|
||||||
return $this->createSearchInstanceCommand->execute($query);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,35 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Repositories;
|
|
||||||
|
|
||||||
use App\Models\ProjectTranslationService;
|
|
||||||
use App\Services\Search\CreateSearchInstanceCommand;
|
|
||||||
use App\Services\Search\Search;
|
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
|
||||||
|
|
||||||
final readonly class ProjectTranslationServiceRepository
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private CreateSearchInstanceCommand $createSearchInstanceCommand,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
public function getLanguagesBySourceLanguage(int $sourceLanguage, ?array $excludeLanguages = null): Search
|
|
||||||
{
|
|
||||||
$query = ProjectTranslationService::query()
|
|
||||||
->select('language_id', 'code')
|
|
||||||
->where('source_language_id', $sourceLanguage)
|
|
||||||
->when($excludeLanguages, function (Builder $query) use ($excludeLanguages) {
|
|
||||||
$query->whereNotIn('language_id', $excludeLanguages);
|
|
||||||
});
|
|
||||||
|
|
||||||
return $this->createSearchInstanceCommand->execute($query);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLanguageCodeByLanguageId(int $languageId): ?string
|
|
||||||
{
|
|
||||||
return ProjectTranslationService::query()
|
|
||||||
->select('code')
|
|
||||||
->where('language_id', $languageId)
|
|
||||||
->first()?->code ?? null;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -4,7 +4,6 @@ namespace App\Services\Admin\Project;
|
|||||||
|
|
||||||
use App\Contracts\ServiceResultError;
|
use App\Contracts\ServiceResultError;
|
||||||
use App\Dto\Service\Admin\Project\About\StoreUpdate;
|
use App\Dto\Service\Admin\Project\About\StoreUpdate;
|
||||||
use App\Enums\Morph;
|
|
||||||
use App\Models\ProjectContent;
|
use App\Models\ProjectContent;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Repositories\ProjectContentRepository;
|
use App\Repositories\ProjectContentRepository;
|
||||||
@@ -14,7 +13,6 @@ use App\ServiceResults\ServiceResultArray;
|
|||||||
use App\ServiceResults\StoreUpdateResult;
|
use App\ServiceResults\StoreUpdateResult;
|
||||||
use App\Services\ProjectContent\ProjectContentCommandHandler;
|
use App\Services\ProjectContent\ProjectContentCommandHandler;
|
||||||
use App\Services\Service;
|
use App\Services\Service;
|
||||||
use App\Services\Storage\StorageService;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
final class AboutService extends Service
|
final class AboutService extends Service
|
||||||
@@ -24,7 +22,6 @@ final class AboutService extends Service
|
|||||||
private readonly ProjectLanguageRepository $projectLanguageRepository,
|
private readonly ProjectLanguageRepository $projectLanguageRepository,
|
||||||
private readonly ProjectContentRepository $projectContentRepository,
|
private readonly ProjectContentRepository $projectContentRepository,
|
||||||
private readonly ProjectContentCommandHandler $projectContentCommandHandler,
|
private readonly ProjectContentCommandHandler $projectContentCommandHandler,
|
||||||
private readonly StorageService $storageService,
|
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public function languages(int $projectId, User $user): ServiceResultError | ServiceResultArray
|
public function languages(int $projectId, User $user): ServiceResultError | ServiceResultArray
|
||||||
@@ -91,19 +88,11 @@ final class AboutService extends Service
|
|||||||
if ($user->cannot('create', ProjectContent::class)) {
|
if ($user->cannot('create', ProjectContent::class)) {
|
||||||
return $this->errFobidden(__('Access is denied'));
|
return $this->errFobidden(__('Access is denied'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$storages = $this->storageService->getStoragesAndValidate($data->getStorages(), Morph::ProjectContent);
|
|
||||||
if (!$storages->isSuccess()) {
|
|
||||||
return $storages;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$aboutProject = DB::transaction(function () use ($data, $projectId, $languageId, $storages) {
|
$aboutProject = DB::transaction(function () use ($data, $projectId, $languageId) {
|
||||||
$dataAboutProject = $this->getDataAboutProject($data);
|
$dataAboutProject = $this->getDataAboutProject($data);
|
||||||
|
|
||||||
$aboutProject = $this->projectContentCommandHandler->handleStore($projectId, $languageId, $dataAboutProject);
|
return $this->projectContentCommandHandler->handleStore($projectId, $languageId, $dataAboutProject);
|
||||||
$this->storageService->saveAndDelete($aboutProject, $storages);
|
|
||||||
return $aboutProject;
|
|
||||||
});
|
});
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
report($e);
|
report($e);
|
||||||
@@ -119,19 +108,11 @@ final class AboutService extends Service
|
|||||||
return $this->errFobidden(__('Access is denied'));
|
return $this->errFobidden(__('Access is denied'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$storages = $this->storageService->getStoragesAndValidate($data->getStorages(), Morph::ProjectContent);
|
|
||||||
if (!$storages->isSuccess()) {
|
|
||||||
return $storages;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$aboutProject = DB::transaction(function () use ($data, $content, $storages) {
|
$aboutProject = DB::transaction(function () use ($data, $content) {
|
||||||
$dataAboutProject = $this->getDataAboutProject($data);
|
$dataAboutProject = $this->getDataAboutProject($data);
|
||||||
|
|
||||||
$aboutProject = $this->projectContentCommandHandler->handleUpdate($content, $dataAboutProject);
|
return $this->projectContentCommandHandler->handleUpdate($content, $dataAboutProject);
|
||||||
$this->storageService->saveAndDelete($aboutProject, $storages);
|
|
||||||
|
|
||||||
return $aboutProject;
|
|
||||||
});
|
});
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
report($e);
|
report($e);
|
||||||
|
@@ -5,11 +5,8 @@ namespace App\Services\Admin\Project;
|
|||||||
use App\Dto\QuerySettingsDto;
|
use App\Dto\QuerySettingsDto;
|
||||||
use App\Dto\Builder\DocumentationCategory as DocumentationCategoryBuilderDto;
|
use App\Dto\Builder\DocumentationCategory as DocumentationCategoryBuilderDto;
|
||||||
use App\Dto\Service\Admin\Project\DocumentationCategory\StoreUpdate;
|
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 App\Exceptions\Services\DocumentationCategory\ParentException;
|
use App\Exceptions\Services\DocumentationCategory\ParentException;
|
||||||
use App\Exceptions\Services\ServiceException;
|
use App\Exceptions\Services\ServiceException;
|
||||||
use App\Jobs\Translate\ProcessProjectDocumentationCategoryContent;
|
|
||||||
use App\Models\DocumentationCategory;
|
use App\Models\DocumentationCategory;
|
||||||
use App\Models\DocumentationCategoryContent;
|
use App\Models\DocumentationCategoryContent;
|
||||||
use App\Models\ProjectLanguage;
|
use App\Models\ProjectLanguage;
|
||||||
@@ -92,8 +89,7 @@ final class DocumentationCategoryService extends Service
|
|||||||
'version' => $version,
|
'version' => $version,
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'category' => new DocumentationCategory(),
|
'category' => new DocumentationCategory(),
|
||||||
'categories' => $this->documentationCategoryRepository->getForSelect($version, $defaultLanguage),
|
'categories' => $this->documentationCategoryRepository->getForSelect($defaultLanguage),
|
||||||
'serviceTranslationEnable' => config('translation_service.enable', false),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,8 +119,7 @@ final class DocumentationCategoryService extends Service
|
|||||||
'version' => $version,
|
'version' => $version,
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'category' => $category,
|
'category' => $category,
|
||||||
'categories' => $this->documentationCategoryRepository->getForSelect($version, $defaultLanguage, $category, $withCategories),
|
'categories' => $this->documentationCategoryRepository->getForSelect($defaultLanguage, $category, $withCategories),
|
||||||
'serviceTranslationEnable' => config('translation_service.enable', false),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,10 +151,6 @@ final class DocumentationCategoryService extends Service
|
|||||||
|
|
||||||
return $category;
|
return $category;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (\config('translation_service.enable', false)) {
|
|
||||||
$this->translateContent($category, $data->getContents());
|
|
||||||
}
|
|
||||||
} catch (ServiceException $e) {
|
} catch (ServiceException $e) {
|
||||||
return $e->getServiceResultError();
|
return $e->getServiceResultError();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
@@ -210,10 +201,6 @@ final class DocumentationCategoryService extends Service
|
|||||||
|
|
||||||
return $category;
|
return $category;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (\config('translation_service.enable', false)) {
|
|
||||||
$this->translateContent($category, $data->getContents());
|
|
||||||
}
|
|
||||||
} catch (ServiceException $e) {
|
} catch (ServiceException $e) {
|
||||||
return $e->getServiceResultError();
|
return $e->getServiceResultError();
|
||||||
} catch (ParentException $e) {
|
} catch (ParentException $e) {
|
||||||
@@ -267,27 +254,4 @@ final class DocumentationCategoryService extends Service
|
|||||||
'parent_id' => $data->getParentId(),
|
'parent_id' => $data->getParentId(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function translateContent(DocumentationCategory $category, Contents $contents): void
|
|
||||||
{
|
|
||||||
$translateExceptLanguages = [];
|
|
||||||
|
|
||||||
$translateLanguages = [];
|
|
||||||
foreach ($contents->getContents() as $content) {
|
|
||||||
/** @var Content $content */
|
|
||||||
$translateExceptLanguages[] = $content->getLanguageId();
|
|
||||||
if ($content->isTranslateAutomatically()) {
|
|
||||||
$translateLanguages[] = $content->getLanguageId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($translateLanguages)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$translateContentIds = $category->contents()->select('id')
|
|
||||||
->whereIn('language_id', $translateLanguages)
|
|
||||||
->get()->pluck('id')->toArray();
|
|
||||||
ProcessProjectDocumentationCategoryContent::dispatch($category->id, $translateContentIds, $translateExceptLanguages);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -5,16 +5,13 @@ namespace App\Services\Admin\Project;
|
|||||||
use App\Dto\Builder\Documentation as DocumentationBuilderDto;
|
use App\Dto\Builder\Documentation as DocumentationBuilderDto;
|
||||||
use App\Dto\QuerySettingsDto;
|
use App\Dto\QuerySettingsDto;
|
||||||
use App\Dto\Service\Admin\Project\Documentation\StoreUpdate;
|
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\Exceptions\Services\DocumentationContent\StorageCommandException;
|
|
||||||
use App\Jobs\Translate\ProcessProjectDocumentationContent;
|
|
||||||
use App\Models\Documentation;
|
use App\Models\Documentation;
|
||||||
use App\Models\ProjectLanguage;
|
use App\Models\ProjectLanguage;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Repositories\DocumentationCategoryRepository;
|
use App\Repositories\DocumentationCategoryRepository;
|
||||||
use App\Repositories\DocumentationRepository;
|
use App\Repositories\DocumentationRepository;
|
||||||
use App\Repositories\DocumentationVersionRepository;
|
use App\Repositories\DocumentationVersionRepository;
|
||||||
|
use App\Repositories\ProjectRepository;
|
||||||
use App\ServiceResults\ServiceResultArray;
|
use App\ServiceResults\ServiceResultArray;
|
||||||
use App\ServiceResults\ServiceResultError;
|
use App\ServiceResults\ServiceResultError;
|
||||||
use App\ServiceResults\ServiceResultSuccess;
|
use App\ServiceResults\ServiceResultSuccess;
|
||||||
@@ -92,8 +89,7 @@ final class DocumentationService extends Service
|
|||||||
'version' => $version,
|
'version' => $version,
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'documentation' => new Documentation(),
|
'documentation' => new Documentation(),
|
||||||
'categories' => $this->documentationCategoryRepository->getForSelect($version, $defaultLanguage),
|
'categories' => $this->documentationCategoryRepository->getForSelect($defaultLanguage),
|
||||||
'serviceTranslationEnable' => config('translation_service.enable', false),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,8 +119,7 @@ final class DocumentationService extends Service
|
|||||||
'version' => $version,
|
'version' => $version,
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'documentation' => $documentation,
|
'documentation' => $documentation,
|
||||||
'categories' => $this->documentationCategoryRepository->getForSelect($version, $defaultLanguage, null, $withCategories),
|
'categories' => $this->documentationCategoryRepository->getForSelect($defaultLanguage, null, $withCategories),
|
||||||
'serviceTranslationEnable' => config('translation_service.enable', false),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,12 +150,6 @@ final class DocumentationService extends Service
|
|||||||
|
|
||||||
return $documentation;
|
return $documentation;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (\config('translation_service.enable', false)) {
|
|
||||||
$this->translateContent($documentation, $data->getContents());
|
|
||||||
}
|
|
||||||
} catch (StorageCommandException $e) {
|
|
||||||
return $e->getResultError();
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
report($e);
|
report($e);
|
||||||
return $this->errService(__('Server Error'));
|
return $this->errService(__('Server Error'));
|
||||||
@@ -201,12 +190,6 @@ final class DocumentationService extends Service
|
|||||||
|
|
||||||
return $documentation;
|
return $documentation;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (\config('translation_service.enable', false)) {
|
|
||||||
$this->translateContent($documentation, $data->getContents());
|
|
||||||
}
|
|
||||||
} catch (StorageCommandException $e) {
|
|
||||||
return $e->getResultError();
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
report($e);
|
report($e);
|
||||||
return $this->errService(__('Server Error'));
|
return $this->errService(__('Server Error'));
|
||||||
@@ -253,27 +236,4 @@ final class DocumentationService extends Service
|
|||||||
'category_id' => $data->getCategoryId(),
|
'category_id' => $data->getCategoryId(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function translateContent(Documentation $documentation, Contents $contents): void
|
|
||||||
{
|
|
||||||
$translateExceptLanguages = [];
|
|
||||||
|
|
||||||
$translateLanguages = [];
|
|
||||||
foreach ($contents->getContents() as $content) {
|
|
||||||
/** @var Content $content */
|
|
||||||
$translateExceptLanguages[] = $content->getLanguageId();
|
|
||||||
if ($content->isTranslateAutomatically()) {
|
|
||||||
$translateLanguages[] = $content->getLanguageId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($translateLanguages)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$translateContentIds = $documentation->contents()->select('id')
|
|
||||||
->whereIn('language_id', $translateLanguages)
|
|
||||||
->get()->pluck('id')->toArray();
|
|
||||||
ProcessProjectDocumentationContent::dispatch($documentation->id, $translateContentIds, $translateExceptLanguages);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,67 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Services\Admin\Project;
|
|
||||||
|
|
||||||
use App\Dto\Service\Admin\Project\ServiceTranslate\Update;
|
|
||||||
use App\Models\User;
|
|
||||||
use App\Repositories\ProjectRepository;
|
|
||||||
use App\ServiceResults\ServiceResultArray;
|
|
||||||
use App\ServiceResults\ServiceResultError;
|
|
||||||
use App\ServiceResults\ServiceResultSuccess;
|
|
||||||
use App\Services\ProjectTranslationService\ModelSyncCommand as TranslationServiceModelSyncCommand;
|
|
||||||
use App\Services\Service;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
|
|
||||||
final class ServiceTranslateService extends Service
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private readonly ProjectRepository $projectRepository,
|
|
||||||
private readonly TranslationServiceModelSyncCommand $translationServiceModelSyncCommand,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
public function view(int $projectId, User $user): ServiceResultError | ServiceResultArray
|
|
||||||
{
|
|
||||||
$project = $this->projectRepository->getProjectById($projectId);
|
|
||||||
if (\is_null($project)) {
|
|
||||||
return $this->errNotFound(__('Not Found'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
config('translation_service.enable', false) === false
|
|
||||||
|| $user->cannot('settingUpAutomaticTranslation', $project)
|
|
||||||
) {
|
|
||||||
return $this->errFobidden(__('Access is denied'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->result([
|
|
||||||
'project' => $project,
|
|
||||||
'languages' => $project->languages()->with(['serviceTranslate'])->get(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function update(int $projectId, Update $data, User $user): ServiceResultError | ServiceResultSuccess
|
|
||||||
{
|
|
||||||
$project = $this->projectRepository->getProjectById($projectId);
|
|
||||||
if (\is_null($project)) {
|
|
||||||
return $this->errNotFound(__('Not Found'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
config('translation_service.enable', false) === false
|
|
||||||
|| $user->cannot('settingUpAutomaticTranslation', $project)
|
|
||||||
) {
|
|
||||||
return $this->errFobidden(__('Access is denied'));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
DB::transaction(function () use ($data, $project) {
|
|
||||||
$this->translationServiceModelSyncCommand->execute($project, $data->getTranslations());
|
|
||||||
});
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
report($e);
|
|
||||||
return $this->errService(__('Server Error'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->ok(__('The settings were saved successfully'));
|
|
||||||
}
|
|
||||||
}
|
|
@@ -50,7 +50,6 @@ final class ProjectService extends Service
|
|||||||
|
|
||||||
return $this->result([
|
return $this->result([
|
||||||
'projects' => $projects,
|
'projects' => $projects,
|
||||||
'serviceTranslationEnable' => config('translation_service.enable', false),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,46 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Services\Commands;
|
|
||||||
|
|
||||||
use App\Models\Storage as StorageModel;
|
|
||||||
use App\ServiceResults\ServiceResultError;
|
|
||||||
use App\ServiceResults\ServiceResultSuccess;
|
|
||||||
use App\Services\Service;
|
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
use Illuminate\Support\Facades\Storage as StorageSupport;
|
|
||||||
|
|
||||||
final class DeleteOldFilesService extends Service
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* $temporaryBeforeDate = date of deletion of temporary files
|
|
||||||
* $deletedBeforeDate = date of deletion files that were marked as deleted
|
|
||||||
*
|
|
||||||
* @param Carbon $temporaryBeforeDate
|
|
||||||
* @param Carbon $deletedBeforeDate
|
|
||||||
* @return ServiceResultError|ServiceResultSuccess
|
|
||||||
*/
|
|
||||||
public function fromStorage(Carbon $temporaryBeforeDate, Carbon $deletedBeforeDate): ServiceResultError|ServiceResultSuccess
|
|
||||||
{
|
|
||||||
$disk = config('storage.disk');
|
|
||||||
|
|
||||||
StorageModel::withTrashed()
|
|
||||||
->where(function (Builder $query) use($temporaryBeforeDate) {
|
|
||||||
$query->whereNull('morph_id')->where('updated_at', '<', $temporaryBeforeDate);
|
|
||||||
})->orWhere(function (Builder $query) use($deletedBeforeDate) {
|
|
||||||
$query->whereNotNull('deleted_at')->where('deleted_at', '<', $deletedBeforeDate);
|
|
||||||
})->chunkById(100, function ($items) use($disk) {
|
|
||||||
$deleteIds = [];
|
|
||||||
foreach ($items as $item) {
|
|
||||||
$deleteIds[] = $item->id;
|
|
||||||
|
|
||||||
if (StorageSupport::disk($disk)->exists($item->file)) {
|
|
||||||
StorageSupport::disk($disk)->delete($item->file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StorageModel::withTrashed()->whereIn('id', $deleteIds)->forceDelete();
|
|
||||||
});
|
|
||||||
|
|
||||||
return $this->ok(__('Old Files deleted.'));
|
|
||||||
}
|
|
||||||
}
|
|
@@ -4,33 +4,18 @@ namespace App\Services\DocumentationContent;
|
|||||||
|
|
||||||
use App\Dto\Service\Admin\Project\DocumentationContent\Content;
|
use App\Dto\Service\Admin\Project\DocumentationContent\Content;
|
||||||
use App\Dto\Service\Admin\Project\DocumentationContent\Contents;
|
use App\Dto\Service\Admin\Project\DocumentationContent\Contents;
|
||||||
use App\Dto\Service\DocumentationContent\StorageDto;
|
|
||||||
use App\Exceptions\Services\DocumentationContent\ContentSaveException;
|
use App\Exceptions\Services\DocumentationContent\ContentSaveException;
|
||||||
use App\Exceptions\Services\DocumentationContent\StorageCommandException;
|
|
||||||
use App\Models\Documentation;
|
use App\Models\Documentation;
|
||||||
use App\Models\DocumentationContent;
|
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
|
|
||||||
final readonly class ModelSyncCommand
|
final readonly class ModelSyncCommand
|
||||||
{
|
{
|
||||||
public function __construct(
|
|
||||||
private StorageCommand $storageCommand,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws StorageCommandException
|
|
||||||
* @throws ContentSaveException
|
|
||||||
*/
|
|
||||||
public function execute(Project $project, Documentation $documentation, Contents $contents): void
|
public function execute(Project $project, Documentation $documentation, Contents $contents): void
|
||||||
{
|
{
|
||||||
$storageDto = new StorageDto();
|
|
||||||
|
|
||||||
$languages = $project->languages;
|
$languages = $project->languages;
|
||||||
$documentationContents = $documentation->contents;
|
$documentationContents = $documentation->contents;
|
||||||
|
|
||||||
$newContents = [];
|
$newContents = [];
|
||||||
$contentsStorageCreated = [];
|
|
||||||
$contentLanguages = [];
|
|
||||||
foreach ($contents->getContents() as $content) {
|
foreach ($contents->getContents() as $content) {
|
||||||
/** @var Content $content */
|
/** @var Content $content */
|
||||||
$language = $languages->firstWhere('id', $content->getLanguageId());
|
$language = $languages->firstWhere('id', $content->getLanguageId());
|
||||||
@@ -41,29 +26,15 @@ final readonly class ModelSyncCommand
|
|||||||
$model = $documentationContents->firstWhere('language_id', $language->id);
|
$model = $documentationContents->firstWhere('language_id', $language->id);
|
||||||
$data = $this->getData($content);
|
$data = $this->getData($content);
|
||||||
if (\is_null($model)) {
|
if (\is_null($model)) {
|
||||||
$contentsStorageCreated[$content->getLanguageId()] = $content->getStorages();
|
|
||||||
$newContents[] = array_merge(['language_id' => $content->getLanguageId()], $data);
|
$newContents[] = array_merge(['language_id' => $content->getLanguageId()], $data);
|
||||||
$contentLanguages[] = $content->getLanguageId();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$storageDto->add($model, $content->getStorages());
|
|
||||||
$model->update($data);
|
$model->update($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($newContents)) {
|
if (!empty($newContents)) {
|
||||||
$documentation->contents()->createMany($newContents);
|
$documentation->contents()->createMany($newContents);
|
||||||
$contents = $documentation->contents()->whereIn('language_id', $contentLanguages)->get();
|
|
||||||
foreach ($contents as $content) {
|
|
||||||
/** @var DocumentationContent $content */
|
|
||||||
if (!isset($contentsStorageCreated[$content->language_id])) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$storageDto->add($content, $contentsStorageCreated[$content->language_id]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->storageCommand->execute($storageDto);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getData(Content $content): array
|
private function getData(Content $content): array
|
||||||
|
@@ -1,31 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Services\DocumentationContent;
|
|
||||||
|
|
||||||
use App\Dto\Service\DocumentationContent\StorageDto;
|
|
||||||
use App\Enums\Morph;
|
|
||||||
use App\Exceptions\Services\DocumentationContent\StorageCommandException;
|
|
||||||
use App\Services\Storage\StorageService;
|
|
||||||
|
|
||||||
final readonly class StorageCommand
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private StorageService $storageService,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws StorageCommandException
|
|
||||||
*/
|
|
||||||
public function execute(StorageDto $storageDto): void
|
|
||||||
{
|
|
||||||
foreach ($storageDto->getStorages() as $storage) {
|
|
||||||
$storages = $this->storageService->getStoragesAndValidate($storage['storages'], Morph::DocumentationContent, $storage['documentationContent']->id);
|
|
||||||
if (!$storages->isSuccess()) {
|
|
||||||
throw new StorageCommandException($storages, 'Error when adding a file to storage: ' . $storages->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->storageService->saveAndDelete($storage['documentationContent'], $storages);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,54 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Services\ProjectTranslationService;
|
|
||||||
|
|
||||||
use App\Models\Project;
|
|
||||||
use App\Dto\Service\Admin\Project\ServiceTranslate\Translations;
|
|
||||||
use App\Models\ProjectTranslationService;
|
|
||||||
|
|
||||||
final readonly class ModelSyncCommand
|
|
||||||
{
|
|
||||||
public function execute(Project $project, Translations $translations): void
|
|
||||||
{
|
|
||||||
$insert = [];
|
|
||||||
$delete = [];
|
|
||||||
|
|
||||||
$languages = $project->languages()->with(['serviceTranslate'])->get();
|
|
||||||
foreach ($translations->getTranslations() as $translation) {
|
|
||||||
/* @var \App\Dto\Service\Admin\Project\ServiceTranslate\Translation $translation */
|
|
||||||
$language = $languages->firstWhere('id', '=', $translation->getLanguageId());
|
|
||||||
if ($language === null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$serviceTranslate = $language->serviceTranslate;
|
|
||||||
if ($serviceTranslate === null) {
|
|
||||||
if ($translation->getCode() !== null) {
|
|
||||||
$insert[] = [
|
|
||||||
'language_id' => $translation->getLanguageId(),
|
|
||||||
'code' => $translation->getCode(),
|
|
||||||
'source_language_id' => $translation->getSourceLanguageId(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($translation->getCode() === null) {
|
|
||||||
$delete[] = [$serviceTranslate->id];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$serviceTranslate->update([
|
|
||||||
'code' => $translation->getCode(),
|
|
||||||
'source_language_id' => $translation->getSourceLanguageId(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($insert)) {
|
|
||||||
ProjectTranslationService::query()->insert($insert);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($delete)) {
|
|
||||||
ProjectTranslationService::query()->whereIn('id', $delete)->delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,18 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Services\ProjectTranslationService;
|
|
||||||
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
final readonly class NoTranslateAttributeHandler
|
|
||||||
{
|
|
||||||
public function handleAddAttribute(string $text): string
|
|
||||||
{
|
|
||||||
return Str::replace('<code', '<code translate="no"', $text);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleRemoveAttribute(string $text): string
|
|
||||||
{
|
|
||||||
return Str::replace('<code translate="no"', '<code', $text);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,40 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Services\ProjectTranslationServiceHash;
|
|
||||||
|
|
||||||
use App\Dto\Service\ProjectTranslationServiceHash\Hashes;
|
|
||||||
use App\Dto\Service\ProjectTranslationServiceHash\HashStatusWaiting;
|
|
||||||
use App\Enums\ProjectTranslationServiceHashes\Status;
|
|
||||||
use App\Repositories\ProjectTranslationServiceHashRepository;
|
|
||||||
|
|
||||||
final readonly class CompletionChecker
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private ProjectTranslationServiceHashRepository $hashRepository,
|
|
||||||
private ProjectTranslationServiceHashCommandHandler $commandHandler,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
public function execute(Hashes $hashesDto): HashStatusWaiting
|
|
||||||
{
|
|
||||||
$hashes = $this->hashRepository->getHashesByIds($hashesDto->getIds())->all();
|
|
||||||
$hashStatusWaiting = new HashStatusWaiting();
|
|
||||||
$hashSuccessIds = [];
|
|
||||||
foreach ($hashes as $hash) {
|
|
||||||
$dataHash = $hashesDto->getHash($hash->id);
|
|
||||||
if ($dataHash === null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$isWaiting = false;
|
|
||||||
if ($hash->status === Status::Waiting && $hash->hash === $dataHash['hash'] && $hash->field === $dataHash['field']) {
|
|
||||||
$isWaiting = true;
|
|
||||||
$hashSuccessIds[] = $hash->id;
|
|
||||||
}
|
|
||||||
$hashStatusWaiting->add($hash['field'], $isWaiting);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->commandHandler->handleSetStatusById($hashSuccessIds, Status::Success);
|
|
||||||
|
|
||||||
return $hashStatusWaiting;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,69 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Services\ProjectTranslationServiceHash;
|
|
||||||
|
|
||||||
use App\Dto\Service\ProjectTranslationServiceHash\Fields;
|
|
||||||
use App\Dto\Service\ProjectTranslationServiceHash\TranslateFields;
|
|
||||||
use App\Enums\Morph;
|
|
||||||
use App\Enums\ProjectTranslationServiceHashes\Status;
|
|
||||||
use App\Models\ProjectTranslationServiceHash;
|
|
||||||
use App\Repositories\ProjectTranslationServiceHashRepository;
|
|
||||||
|
|
||||||
final readonly class HashTrackerCommand
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private ProjectTranslationServiceHashRepository $hashRepository,
|
|
||||||
private ProjectTranslationServiceHashCommandHandler $commandHandler,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
public function execute(Morph $morph, int $morphId, array $languages, Fields $fields): TranslateFields
|
|
||||||
{
|
|
||||||
$hashes = $this->hashRepository->getHashes($morph, $morphId, $languages, $fields->getNames())->all();
|
|
||||||
|
|
||||||
$translateFields = new TranslateFields();
|
|
||||||
foreach ($fields->getFields() as $fieldName => $fieldValue) {
|
|
||||||
$textHash = $this->generateHashFromText((string) $fieldValue);
|
|
||||||
foreach ($languages as $language) {
|
|
||||||
$modelHash = $hashes->where('language_id', $language)->firstWhere('field', $fieldName);
|
|
||||||
if ($modelHash === null) {
|
|
||||||
$modelHash = $this->commandHandler->handleStore([
|
|
||||||
'language_id' => $language,
|
|
||||||
'morph_type' => $morph,
|
|
||||||
'morph_id' => $morphId,
|
|
||||||
'field' => $fieldName,
|
|
||||||
'hash' => $textHash,
|
|
||||||
'status' => Status::Waiting,
|
|
||||||
]);
|
|
||||||
$translateFields->add($language, $fieldName, $textHash, $modelHash->id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($modelHash->hash === $textHash && $this->isSuccess($modelHash)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$translateFields->add($language, $fieldName, $textHash, $modelHash->id);
|
|
||||||
$this->commandHandler->handleUpdate($modelHash, [
|
|
||||||
'hash' => $textHash,
|
|
||||||
'status' => Status::Waiting,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $translateFields;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function generateHashFromText(string $text): string
|
|
||||||
{
|
|
||||||
return \hash('sha256', $text);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function isSuccess(ProjectTranslationServiceHash $modelHash): bool
|
|
||||||
{
|
|
||||||
if ($modelHash->status === Status::Success) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ($modelHash->updated_at >= now()->subMinutes(10));
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,26 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Services\ProjectTranslationServiceHash;
|
|
||||||
|
|
||||||
use App\Enums\ProjectTranslationServiceHashes\Status;
|
|
||||||
use App\Models\ProjectTranslationServiceHash;
|
|
||||||
|
|
||||||
final readonly class ProjectTranslationServiceHashCommandHandler
|
|
||||||
{
|
|
||||||
public function handleStore(array $data): ProjectTranslationServiceHash
|
|
||||||
{
|
|
||||||
return ProjectTranslationServiceHash::create($data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleUpdate(ProjectTranslationServiceHash $hash, array $data): ProjectTranslationServiceHash
|
|
||||||
{
|
|
||||||
$hash->update($data);
|
|
||||||
$hash->touch();
|
|
||||||
return $hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleSetStatusById(array $ids, Status $status): void
|
|
||||||
{
|
|
||||||
ProjectTranslationServiceHash::query()->whereIn('id', $ids)->update(['status' => $status->value]);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -5,44 +5,32 @@ namespace App\Services\Site;
|
|||||||
use App\Dto\Service\Site\Feedback\Send;
|
use App\Dto\Service\Site\Feedback\Send;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Notifications\ReviewAdded;
|
|
||||||
use App\ServiceResults\ServiceResultError;
|
use App\ServiceResults\ServiceResultError;
|
||||||
use App\ServiceResults\ServiceResultSuccess;
|
use App\ServiceResults\ServiceResultSuccess;
|
||||||
use App\Services\ProjectFeedback\ProjectFeedbackCommandHandler;
|
use App\Services\ProjectFeedback\ProjectFeedbackCommandHandler;
|
||||||
use App\Services\Service;
|
use App\Services\Service;
|
||||||
use App\Services\WebsiteTranslations;
|
use App\Services\WebsiteTranslations;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Notification;
|
|
||||||
|
|
||||||
final class FeedbackService extends Service
|
final class FeedbackService extends Service
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly ProjectFeedbackCommandHandler $feedbackCommandHandler,
|
private readonly ProjectFeedbackCommandHandler $feedbackCommandHandler,
|
||||||
private readonly bool $isNotifications = false,
|
|
||||||
private readonly ?string $mailNotifications = null,
|
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public function send(Send $send, Project $project, WebsiteTranslations $websiteTranslations, ?User $user = null): ServiceResultError | ServiceResultSuccess
|
public function send(Send $send, Project $project, WebsiteTranslations $websiteTranslations, ?User $user = null): ServiceResultError | ServiceResultSuccess
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$feedback = DB::transaction(function () use ($send, $project, $user) {
|
DB::transaction(function () use ($send, $project, $user) {
|
||||||
$data = $this->getDataFeedback($send);
|
$data = $this->getDataFeedback($send);
|
||||||
$data['user_id'] = $user?->id;
|
$data['user_id'] = $user?->id;
|
||||||
return $this->feedbackCommandHandler->handleStore($project, $data);
|
$this->feedbackCommandHandler->handleStore($project, $data);
|
||||||
});
|
});
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
report($e);
|
report($e);
|
||||||
return $this->errService($websiteTranslations->translate('Server Error'));
|
return $this->errService($websiteTranslations->translate('Server Error'));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
if ($this->isNotifications) {
|
|
||||||
Notification::route('mail', $this->mailNotifications)->notify(new ReviewAdded($feedback));
|
|
||||||
}
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
report($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->ok($websiteTranslations->translate('site.Message sent successfully'));
|
return $this->ok($websiteTranslations->translate('site.Message sent successfully'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,89 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Services\Translate\Completed\Project;
|
|
||||||
|
|
||||||
use App\Dto\Service\ProjectTranslationServiceHash\Hashes;
|
|
||||||
use App\Exceptions\Services\Translate\CompletedException;
|
|
||||||
use App\Jobs\Translate\ProcessProjectDocumentationCategoryContent;
|
|
||||||
use App\Models\DocumentationCategory;
|
|
||||||
use App\Models\DocumentationCategoryContent;
|
|
||||||
use App\Repositories\DocumentationCategoryRepository;
|
|
||||||
use App\Services\ProjectTranslationService\NoTranslateAttributeHandler;
|
|
||||||
use App\Services\ProjectTranslationServiceHash\CompletionChecker;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use KorElf\TranslateLaravel\Contracts\TranslationCompletedListener;
|
|
||||||
|
|
||||||
final class DocumentationCategoryContentService implements TranslationCompletedListener
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private DocumentationCategoryRepository $categoryRepository,
|
|
||||||
private NoTranslateAttributeHandler $noTranslateAttributeHandler,
|
|
||||||
private CompletionChecker $completionChecker,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws CompletedException
|
|
||||||
*/
|
|
||||||
public function onTranslationCompleted(array $translatedText, array $data = []): void
|
|
||||||
{
|
|
||||||
if (
|
|
||||||
!isset($data['categoryId'])
|
|
||||||
|| !isset($data['languageId'])
|
|
||||||
|| !isset($data['hashes'])
|
|
||||||
) {
|
|
||||||
throw new CompletedException('Required data is missing: categoryId, languageId, or hashes.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$category = $this->categoryRepository->getCategoryById((int) $data['categoryId']);
|
|
||||||
if ($category === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$categoryContent = DB::transaction(function () use ($data, $category, $translatedText) {
|
|
||||||
$values = [];
|
|
||||||
$hashes = $this->completionChecker->execute(
|
|
||||||
$this->getHashes($data['hashes']),
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($translatedText as $translatedTextKey => $translatedTextValue) {
|
|
||||||
if ($hashes->isStatusWaiting($translatedTextKey) !== true) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$translatedTextValue = $this->noTranslateAttributeHandler->handleRemoveAttribute($translatedTextValue);
|
|
||||||
$values[$translatedTextKey] = $translatedTextValue;
|
|
||||||
}
|
|
||||||
if (\count($values) === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$categoryContent = $category->contents()->where('language_id', $data['languageId'])->first();
|
|
||||||
if ($categoryContent !== null) {
|
|
||||||
$categoryContent->update($values);
|
|
||||||
return $categoryContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
$values['language_id'] = $data['languageId'];
|
|
||||||
return $category->contents()->create($values);
|
|
||||||
});
|
|
||||||
if (\config('translation_service.enable', false) && $categoryContent !== null) {
|
|
||||||
$this->translateContent($category, $categoryContent, $data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function translateContent(DocumentationCategory $category, DocumentationCategoryContent $categoryContent, array $data): void
|
|
||||||
{
|
|
||||||
$translateExceptLanguages = $data['exceptLanguages'] ?? [];
|
|
||||||
$translateExceptLanguages[] = $data['languageId'];
|
|
||||||
ProcessProjectDocumentationCategoryContent::dispatch($category->id, [$categoryContent->id], $translateExceptLanguages);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getHashes(array $hashes): Hashes
|
|
||||||
{
|
|
||||||
$hashesDto = new Hashes();
|
|
||||||
foreach ($hashes as $field => $hash) {
|
|
||||||
$hashesDto->add((int) $hash['hashId'], $field, $hash['hash']);
|
|
||||||
}
|
|
||||||
return $hashesDto;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,90 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Services\Translate\Completed\Project;
|
|
||||||
|
|
||||||
use App\Dto\Service\ProjectTranslationServiceHash\Hashes;
|
|
||||||
use App\Exceptions\Services\Translate\CompletedException;
|
|
||||||
use App\Jobs\Translate\ProcessProjectDocumentationContent;
|
|
||||||
use App\Models\Documentation;
|
|
||||||
use App\Models\DocumentationContent;
|
|
||||||
use App\Repositories\DocumentationRepository;
|
|
||||||
use App\Services\ProjectTranslationService\NoTranslateAttributeHandler;
|
|
||||||
use App\Services\ProjectTranslationServiceHash\CompletionChecker;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use KorElf\TranslateLaravel\Contracts\TranslationCompletedListener;
|
|
||||||
|
|
||||||
final readonly class DocumentationContentService implements TranslationCompletedListener
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private DocumentationRepository $documentationRepository,
|
|
||||||
private NoTranslateAttributeHandler $noTranslateAttributeHandler,
|
|
||||||
private CompletionChecker $completionChecker,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws CompletedException
|
|
||||||
*/
|
|
||||||
public function onTranslationCompleted(array $translatedText, array $data = []): void
|
|
||||||
{
|
|
||||||
if (
|
|
||||||
!isset($data['projectDocumentId'])
|
|
||||||
|| !isset($data['languageId'])
|
|
||||||
|| !isset($data['hashes'])
|
|
||||||
) {
|
|
||||||
throw new CompletedException('Required data is missing: projectDocumentId, languageId, or hashes.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$documentation = $this->documentationRepository->getDocumentationById((int) $data['projectDocumentId']);
|
|
||||||
if ($documentation === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$documentationContent = DB::transaction(function () use ($data, $documentation, $translatedText) {
|
|
||||||
$values = [];
|
|
||||||
$hashes = $this->completionChecker->execute(
|
|
||||||
$this->getHashes($data['hashes']),
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($translatedText as $translatedTextKey => $translatedTextValue) {
|
|
||||||
if ($hashes->isStatusWaiting($translatedTextKey) !== true) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$translatedTextValue = $this->noTranslateAttributeHandler->handleRemoveAttribute($translatedTextValue);
|
|
||||||
$values[$translatedTextKey] = $translatedTextValue;
|
|
||||||
}
|
|
||||||
if (\count($values) === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$documentationContent = $documentation->contents()->where('language_id', $data['languageId'])->first();
|
|
||||||
if ($documentationContent !== null) {
|
|
||||||
$documentationContent->update($values);
|
|
||||||
return $documentationContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
$values['language_id'] = $data['languageId'];
|
|
||||||
return $documentation->contents()->create($values);
|
|
||||||
});
|
|
||||||
if (\config('translation_service.enable', false) && $documentationContent !== null) {
|
|
||||||
$this->translateContent($documentation, $documentationContent, $data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function translateContent(Documentation $documentation, DocumentationContent $documentationContent, array $data): void
|
|
||||||
{
|
|
||||||
$translateExceptLanguages = $data['exceptLanguages'] ?? [];
|
|
||||||
$translateExceptLanguages[] = $data['languageId'];
|
|
||||||
ProcessProjectDocumentationContent::dispatch($documentation->id, [$documentationContent->id], $translateExceptLanguages);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getHashes(array $hashes): Hashes
|
|
||||||
{
|
|
||||||
$hashesDto = new Hashes();
|
|
||||||
foreach ($hashes as $field => $hash) {
|
|
||||||
$hashesDto->add((int) $hash['hashId'], $field, $hash['hash']);
|
|
||||||
}
|
|
||||||
return $hashesDto;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,94 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Services\Translate\Project;
|
|
||||||
|
|
||||||
use App\Dto\Service\ProjectTranslationServiceHash\Fields;
|
|
||||||
use App\Dto\Service\ProjectTranslationServiceHash\TranslateFields;
|
|
||||||
use App\Enums\Morph;
|
|
||||||
use App\Repositories\DocumentationCategoryRepository;
|
|
||||||
use App\Repositories\ProjectTranslationServiceRepository;
|
|
||||||
use App\ServiceResults\ServiceResultError;
|
|
||||||
use App\ServiceResults\ServiceResultSuccess;
|
|
||||||
use App\Services\ProjectTranslationService\NoTranslateAttributeHandler;
|
|
||||||
use App\Services\ProjectTranslationServiceHash\HashTrackerCommand;
|
|
||||||
use App\Services\Translate\Completed\Project\DocumentationCategoryContentService as DocumentationCategoryContentServiceCompleted;
|
|
||||||
use App\Services\Service;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use KorElf\TranslateLaravel\DTO\AfterTranslateDto;
|
|
||||||
use KorElf\TranslateLaravel\Facades\Translate;
|
|
||||||
|
|
||||||
final class DocumentationCategoryContentService extends Service
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private readonly DocumentationCategoryRepository $documentationCategoryRepository,
|
|
||||||
private readonly ProjectTranslationServiceRepository $projectTranslationServiceRepository,
|
|
||||||
private readonly HashTrackerCommand $hashTrackerCommand,
|
|
||||||
private readonly NoTranslateAttributeHandler $noTranslateAttributeHandler,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public function translate(int $categoryId, array $contentIds, array $exceptLanguages): ServiceResultSuccess | ServiceResultError
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$category = $this->documentationCategoryRepository->getCategoryById($categoryId);
|
|
||||||
if ($category === null) {
|
|
||||||
return $this->errNotFound(__('Category not found'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$contents = $category->contents()
|
|
||||||
->whereIn('id', $contentIds)
|
|
||||||
->cursor();
|
|
||||||
|
|
||||||
$sourceLanguagesCode = [];
|
|
||||||
foreach ($contents as $content) {
|
|
||||||
if (!isset($sourceLanguagesCode[$content->language_id])) {
|
|
||||||
$sourceLanguagesCode[$content->language_id] = $this->projectTranslationServiceRepository->getLanguageCodeByLanguageId($content->language_id) ?? 'null';
|
|
||||||
}
|
|
||||||
$translateIntoLanguage = $this->projectTranslationServiceRepository
|
|
||||||
->getLanguagesBySourceLanguage($content->language_id, $exceptLanguages)
|
|
||||||
->all()->pluck('code', 'language_id')->toArray();
|
|
||||||
|
|
||||||
if (empty($translateIntoLanguage)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$fields = (new Fields())
|
|
||||||
->add('title', $content->title ?? '');
|
|
||||||
$translations = DB::transaction(function () use ($content, $translateIntoLanguage, $fields) {
|
|
||||||
return $this->hashTrackerCommand->execute(Morph::DocumentationCategoryContent, $content->id, \array_keys($translateIntoLanguage), $fields);
|
|
||||||
});
|
|
||||||
/** @var TranslateFields $translations */
|
|
||||||
unset($fields);
|
|
||||||
|
|
||||||
foreach ($translations->getFields() as $languageId => $fields) {
|
|
||||||
$params = new \KorElf\TranslateLaravel\DTO\RunTranslateDto();
|
|
||||||
$sourceLanguageCode = null;
|
|
||||||
if (isset($sourceLanguagesCode[$content->language_id]) && $sourceLanguagesCode[$content->language_id] !== 'null') {
|
|
||||||
$sourceLanguageCode = $sourceLanguagesCode[$content->language_id];
|
|
||||||
}
|
|
||||||
foreach ($fields as $field) {
|
|
||||||
$text = $this->noTranslateAttributeHandler->handleAddAttribute((string) $content->{$field} ?? '');
|
|
||||||
$params->addParamHtml($field, $text, $translateIntoLanguage[$languageId], $sourceLanguageCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
$afterTranslateDto = new AfterTranslateDto(DocumentationCategoryContentServiceCompleted::class, [
|
|
||||||
'categoryId' => $categoryId,
|
|
||||||
'languageId' => $languageId,
|
|
||||||
'hashes' => $translations->getHashesByLanguage($languageId),
|
|
||||||
'exceptLanguages' => $exceptLanguages,
|
|
||||||
]);
|
|
||||||
Translate::runJob($params, $afterTranslateDto);
|
|
||||||
unset($params, $afterTranslateDto);
|
|
||||||
}
|
|
||||||
|
|
||||||
unset($translations, $translateIntoLanguage);
|
|
||||||
}
|
|
||||||
unset($contents, $documentation);
|
|
||||||
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
\report($e);
|
|
||||||
return $this->errService($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->ok();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,95 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Services\Translate\Project;
|
|
||||||
|
|
||||||
use App\Dto\Service\ProjectTranslationServiceHash\Fields;
|
|
||||||
use App\Dto\Service\ProjectTranslationServiceHash\TranslateFields;
|
|
||||||
use App\Enums\Morph;
|
|
||||||
use App\Repositories\DocumentationRepository;
|
|
||||||
use App\Repositories\ProjectTranslationServiceRepository;
|
|
||||||
use App\ServiceResults\ServiceResultError;
|
|
||||||
use App\ServiceResults\ServiceResultSuccess;
|
|
||||||
use App\Services\ProjectTranslationService\NoTranslateAttributeHandler;
|
|
||||||
use App\Services\ProjectTranslationServiceHash\HashTrackerCommand;
|
|
||||||
use App\Services\Service;
|
|
||||||
use App\Services\Translate\Completed\Project\DocumentationContentService as DocumentationContentServiceCompleted;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use KorElf\TranslateLaravel\DTO\AfterTranslateDto;
|
|
||||||
use KorElf\TranslateLaravel\Facades\Translate;
|
|
||||||
|
|
||||||
final class DocumentationContentService extends Service
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private readonly DocumentationRepository $documentationRepository,
|
|
||||||
private readonly ProjectTranslationServiceRepository $projectTranslationServiceRepository,
|
|
||||||
private readonly HashTrackerCommand $hashTrackerCommand,
|
|
||||||
private readonly NoTranslateAttributeHandler $noTranslateAttributeHandler,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public function translate(int $projectDocumentId, array $contentIds, array $exceptLanguages): ServiceResultSuccess | ServiceResultError
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$documentation = $this->documentationRepository->getDocumentationById($projectDocumentId);
|
|
||||||
if ($documentation === null) {
|
|
||||||
return $this->errNotFound(__('Documentation not found'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$contents = $documentation->contents()
|
|
||||||
->whereIn('id', $contentIds)
|
|
||||||
->cursor();
|
|
||||||
|
|
||||||
$sourceLanguagesCode = [];
|
|
||||||
foreach ($contents as $content) {
|
|
||||||
if (!isset($sourceLanguagesCode[$content->language_id])) {
|
|
||||||
$sourceLanguagesCode[$content->language_id] = $this->projectTranslationServiceRepository->getLanguageCodeByLanguageId($content->language_id) ?? 'null';
|
|
||||||
}
|
|
||||||
$translateIntoLanguage = $this->projectTranslationServiceRepository
|
|
||||||
->getLanguagesBySourceLanguage($content->language_id, $exceptLanguages)
|
|
||||||
->all()->pluck('code', 'language_id')->toArray();
|
|
||||||
|
|
||||||
if (empty($translateIntoLanguage)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$fields = (new Fields())
|
|
||||||
->add('title', $content->title ?? '')
|
|
||||||
->add('content', $content->content ?? '');
|
|
||||||
$translations = DB::transaction(function () use ($content, $translateIntoLanguage, $fields) {
|
|
||||||
return $this->hashTrackerCommand->execute(Morph::DocumentationContent, $content->id, \array_keys($translateIntoLanguage), $fields);
|
|
||||||
});
|
|
||||||
/** @var TranslateFields $translations */
|
|
||||||
unset($fields);
|
|
||||||
|
|
||||||
foreach ($translations->getFields() as $languageId => $fields) {
|
|
||||||
$params = new \KorElf\TranslateLaravel\DTO\RunTranslateDto();
|
|
||||||
$sourceLanguageCode = null;
|
|
||||||
if (isset($sourceLanguagesCode[$content->language_id]) && $sourceLanguagesCode[$content->language_id] !== 'null') {
|
|
||||||
$sourceLanguageCode = $sourceLanguagesCode[$content->language_id];
|
|
||||||
}
|
|
||||||
foreach ($fields as $field) {
|
|
||||||
$text = $this->noTranslateAttributeHandler->handleAddAttribute((string) $content->{$field} ?? '');
|
|
||||||
$params->addParamHtml($field, $text, $translateIntoLanguage[$languageId], $sourceLanguageCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
$afterTranslateDto = new AfterTranslateDto(DocumentationContentServiceCompleted::class, [
|
|
||||||
'projectDocumentId' => $projectDocumentId,
|
|
||||||
'languageId' => $languageId,
|
|
||||||
'hashes' => $translations->getHashesByLanguage($languageId),
|
|
||||||
'exceptLanguages' => $exceptLanguages,
|
|
||||||
]);
|
|
||||||
Translate::runJob($params, $afterTranslateDto);
|
|
||||||
unset($params, $afterTranslateDto);
|
|
||||||
}
|
|
||||||
|
|
||||||
unset($translations, $translateIntoLanguage);
|
|
||||||
}
|
|
||||||
unset($contents, $documentation);
|
|
||||||
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
\report($e);
|
|
||||||
return $this->errService($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->ok();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace App\View\Components\Volt\Forms;
|
namespace App\View\Components\Volt\Forms;
|
||||||
|
|
||||||
use App\Dto\View\Volt\Form\WysiwygStorageUpload;
|
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
@@ -12,7 +11,6 @@ final class TextareaWysiwyg extends Form
|
|||||||
private readonly string $title,
|
private readonly string $title,
|
||||||
private readonly string $name,
|
private readonly string $name,
|
||||||
private readonly ?string $value = '',
|
private readonly ?string $value = '',
|
||||||
private readonly ?WysiwygStorageUpload $storageUpload = null,
|
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
protected function getName(): string
|
protected function getName(): string
|
||||||
@@ -30,11 +28,6 @@ final class TextareaWysiwyg extends Form
|
|||||||
return (string) old($this->getRequestName(), $this->value);
|
return (string) old($this->getRequestName(), $this->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getStorageUpload(): ?WysiwygStorageUpload
|
|
||||||
{
|
|
||||||
return $this->storageUpload;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
@@ -48,7 +41,6 @@ final class TextareaWysiwyg extends Form
|
|||||||
'name' => $this->getName(),
|
'name' => $this->getName(),
|
||||||
'requestName' => $this->getRequestName(),
|
'requestName' => $this->getRequestName(),
|
||||||
'value' => $this->getValue(),
|
'value' => $this->getValue(),
|
||||||
'storageUpload' => $this->getStorageUpload(),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,6 @@
|
|||||||
"php": "^8.3",
|
"php": "^8.3",
|
||||||
"intervention/image-laravel": "^1.2",
|
"intervention/image-laravel": "^1.2",
|
||||||
"kor-elf/captcha-rule-for-laravel": "^1.0",
|
"kor-elf/captcha-rule-for-laravel": "^1.0",
|
||||||
"kor-elf/translate-laravel": "1.3.0",
|
|
||||||
"laravel/framework": "^11.0",
|
"laravel/framework": "^11.0",
|
||||||
"laravel/tinker": "^2.9",
|
"laravel/tinker": "^2.9",
|
||||||
"staudenmeir/laravel-adjacency-list": "^1.0"
|
"staudenmeir/laravel-adjacency-list": "^1.0"
|
||||||
|
3052
app/application/composer.lock
generated
3052
app/application/composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -28,15 +28,6 @@ return [
|
|||||||
|
|
||||||
'env' => env('APP_ENV', 'production'),
|
'env' => env('APP_ENV', 'production'),
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Сaptcha
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Enables or disables captcha.
|
|
||||||
*/
|
|
||||||
'captcha' => (bool) env('APP_CAPTCHA', false),
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Application Debug Mode
|
| Application Debug Mode
|
||||||
|
@@ -1,9 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
/**
|
|
||||||
* Enable new review alerts.
|
|
||||||
*/
|
|
||||||
'mail_notifications' => (bool) env('FEEDBACK_MAIL_NOTIFICATIONS', false),
|
|
||||||
'mail_to' => env('FEEDBACK_MAIL_TO', null),
|
|
||||||
];
|
|
@@ -1,11 +0,0 @@
|
|||||||
<?php
|
|
||||||
return [
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Translate service
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Enables or disables translate service.
|
|
||||||
*/
|
|
||||||
'enable' => (bool) env('TRANSLATION_SERVICE_ENABLE', false),
|
|
||||||
];
|
|
@@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use Illuminate\Database\Migrations\Migration;
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
|
|
||||||
return new class extends Migration
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Run the migrations.
|
|
||||||
*/
|
|
||||||
public function up(): void
|
|
||||||
{
|
|
||||||
Schema::table('storage', function (Blueprint $table) {
|
|
||||||
$table->dropIndex(['morph_id']);
|
|
||||||
$table->index(['morph_id', 'updated_at']);
|
|
||||||
$table->index(['deleted_at']);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::table('storage', function (Blueprint $table) {
|
|
||||||
$table->dropIndex(['morph_id', 'updated_at']);
|
|
||||||
$table->dropIndex(['deleted_at']);
|
|
||||||
$table->index(['morph_id']);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
@@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use Illuminate\Database\Migrations\Migration;
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
|
|
||||||
return new class extends Migration
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Run the migrations.
|
|
||||||
*/
|
|
||||||
public function up(): void
|
|
||||||
{
|
|
||||||
Schema::create('project_translation_service', function (Blueprint $table) {
|
|
||||||
$table->id();
|
|
||||||
$table->unsignedBigInteger('language_id')->unique();
|
|
||||||
$table->foreign('language_id')->references('id')->on('project_languages');
|
|
||||||
$table->unsignedBigInteger('source_language_id')->nullable()->index();
|
|
||||||
$table->foreign('source_language_id')->references('id')->on('project_languages');
|
|
||||||
$table->string('code', 50);
|
|
||||||
$table->timestamps();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::dropIfExists('project_translation_service');
|
|
||||||
}
|
|
||||||
};
|
|
@@ -1,36 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use Illuminate\Database\Migrations\Migration;
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
|
|
||||||
return new class extends Migration
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Run the migrations.
|
|
||||||
*/
|
|
||||||
public function up(): void
|
|
||||||
{
|
|
||||||
Schema::create('project_translation_service_hashes', function (Blueprint $table) {
|
|
||||||
$table->id();
|
|
||||||
$table->unsignedBigInteger('language_id')->index();
|
|
||||||
$table->foreign('language_id')->references('id')->on('project_languages');
|
|
||||||
$table->unsignedInteger('morph_type');
|
|
||||||
$table->unsignedBigInteger('morph_id');
|
|
||||||
$table->string('field', 255);
|
|
||||||
$table->unsignedInteger('status')->index()->default(0);
|
|
||||||
$table->char('hash', 64);
|
|
||||||
$table->timestamps();
|
|
||||||
|
|
||||||
$table->index(['morph_type', 'morph_id']);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::dropIfExists('project_translation_service_hashes');
|
|
||||||
}
|
|
||||||
};
|
|
@@ -256,7 +256,6 @@
|
|||||||
"The link has been deleted": "The link has been deleted",
|
"The link has been deleted": "The link has been deleted",
|
||||||
"Language not found": "Language not found",
|
"Language not found": "Language not found",
|
||||||
"Project not found": "Project not found",
|
"Project not found": "Project not found",
|
||||||
"Documentation not found": "Documentation not found",
|
|
||||||
"Translations successfully updated": "Translations successfully updated",
|
"Translations successfully updated": "Translations successfully updated",
|
||||||
"allowed characters:": "allowed characters:",
|
"allowed characters:": "allowed characters:",
|
||||||
"Documentation version created successfully": "Documentation version created successfully",
|
"Documentation version created successfully": "Documentation version created successfully",
|
||||||
@@ -268,9 +267,5 @@
|
|||||||
"Documentation successfully removed": "Documentation successfully removed",
|
"Documentation successfully removed": "Documentation successfully removed",
|
||||||
"Category successfully created": "Category successfully created",
|
"Category successfully created": "Category successfully created",
|
||||||
"Category updated successfully": "Category updated successfully",
|
"Category updated successfully": "Category updated successfully",
|
||||||
"Category successfully deleted": "Category successfully deleted",
|
"Category successfully deleted": "Category successfully deleted"
|
||||||
"Old Files deleted": "Old Files deleted",
|
|
||||||
"Automatic translation": "Automatic translation",
|
|
||||||
"The settings were saved successfully": "The settings were saved successfully",
|
|
||||||
"Category not found": "Category not found"
|
|
||||||
}
|
}
|
||||||
|
@@ -16,5 +16,4 @@ return [
|
|||||||
'Documentation version' => 'Documentation version',
|
'Documentation version' => 'Documentation version',
|
||||||
'Documentation' => 'Documentation',
|
'Documentation' => 'Documentation',
|
||||||
'Categories' => 'Categories',
|
'Categories' => 'Categories',
|
||||||
'Setting up automatic translation' => 'Setting up automatic translation',
|
|
||||||
];
|
];
|
||||||
|
@@ -1,6 +0,0 @@
|
|||||||
<?php
|
|
||||||
return [
|
|
||||||
'Added a new review.' => 'Added a new review.',
|
|
||||||
'Review Added: :name' => 'Review Added: :name',
|
|
||||||
'Project :name' => 'Project :name',
|
|
||||||
];
|
|
@@ -9,8 +9,6 @@ return [
|
|||||||
'Allowed to edit' => 'Allowed to edit',
|
'Allowed to edit' => 'Allowed to edit',
|
||||||
'Allowed to delete' => 'Allowed to delete',
|
'Allowed to delete' => 'Allowed to delete',
|
||||||
|
|
||||||
'Setting up automatic translation' => 'Setting up automatic translation',
|
|
||||||
|
|
||||||
'Administrative panel allowed' => 'Administrative panel allowed',
|
'Administrative panel allowed' => 'Administrative panel allowed',
|
||||||
'AdminPanel' => 'Administrative panel allowed',
|
'AdminPanel' => 'Administrative panel allowed',
|
||||||
|
|
||||||
|
@@ -307,9 +307,5 @@ return [
|
|||||||
'content.*.title' => 'title',
|
'content.*.title' => 'title',
|
||||||
'content.*.content' => 'content',
|
'content.*.content' => 'content',
|
||||||
'category_id' => 'category',
|
'category_id' => 'category',
|
||||||
'content_images' => 'content images',
|
|
||||||
'source_language_id' => 'source language identifier',
|
|
||||||
'translate_from_language' => 'translate from language',
|
|
||||||
'translate-automatically.*' => 'translate automatically',
|
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@@ -256,7 +256,6 @@
|
|||||||
"The link has been deleted": "Ссылка удалена",
|
"The link has been deleted": "Ссылка удалена",
|
||||||
"Language not found": "Язык не найден",
|
"Language not found": "Язык не найден",
|
||||||
"Project not found": "Проект не найден",
|
"Project not found": "Проект не найден",
|
||||||
"Documentation not found": "Документация не найдена",
|
|
||||||
"Translations successfully updated": "Переводы успешно обновлены",
|
"Translations successfully updated": "Переводы успешно обновлены",
|
||||||
"allowed characters:": "разрешенные символы:",
|
"allowed characters:": "разрешенные символы:",
|
||||||
"Documentation version created successfully": "Версия документации успешно создана",
|
"Documentation version created successfully": "Версия документации успешно создана",
|
||||||
@@ -268,9 +267,5 @@
|
|||||||
"Documentation successfully removed": "Документация успешно удалена",
|
"Documentation successfully removed": "Документация успешно удалена",
|
||||||
"Category successfully created": "Категория успешно создана",
|
"Category successfully created": "Категория успешно создана",
|
||||||
"Category updated successfully": "Категория успешно обновлена",
|
"Category updated successfully": "Категория успешно обновлена",
|
||||||
"Category successfully deleted": "Категория успешно удалена",
|
"Category successfully deleted": "Категория успешно удалена"
|
||||||
"Old Files deleted": "Старые файлы удалены",
|
|
||||||
"Automatic translation": "Автоматический перевод",
|
|
||||||
"The settings were saved successfully": "Настройки успешно сохранены",
|
|
||||||
"Category not found": "Категория не найдена"
|
|
||||||
}
|
}
|
||||||
|
@@ -16,5 +16,4 @@ return [
|
|||||||
'Documentation version' => 'Версия документации',
|
'Documentation version' => 'Версия документации',
|
||||||
'Documentation' => 'Документация',
|
'Documentation' => 'Документация',
|
||||||
'Categories' => 'Категории',
|
'Categories' => 'Категории',
|
||||||
'Setting up automatic translation' => 'Настройка автоматического перевода',
|
|
||||||
];
|
];
|
||||||
|
@@ -1,6 +0,0 @@
|
|||||||
<?php
|
|
||||||
return [
|
|
||||||
'Added a new review.' => 'Добавили новый отзыв.',
|
|
||||||
'Review Added: :name' => 'Отзыв добавлен: :name',
|
|
||||||
'Project :name' => 'Проект :name',
|
|
||||||
];
|
|
@@ -9,8 +9,6 @@ return [
|
|||||||
'Allowed to edit' => 'Разрешено редактировать',
|
'Allowed to edit' => 'Разрешено редактировать',
|
||||||
'Allowed to delete' => 'Разрешено удалять',
|
'Allowed to delete' => 'Разрешено удалять',
|
||||||
|
|
||||||
'Setting up automatic translation' => 'Настройка автоматического перевода',
|
|
||||||
|
|
||||||
'Administrative panel allowed' => 'Административная панель разрешена',
|
'Administrative panel allowed' => 'Административная панель разрешена',
|
||||||
'AdminPanel' => 'Административная панель разрешена',
|
'AdminPanel' => 'Административная панель разрешена',
|
||||||
|
|
||||||
|
@@ -307,9 +307,5 @@ return [
|
|||||||
'content.*.title' => 'заголовок',
|
'content.*.title' => 'заголовок',
|
||||||
'content.*.content' => 'контент',
|
'content.*.content' => 'контент',
|
||||||
'category_id' => 'категория',
|
'category_id' => 'категория',
|
||||||
'content_images' => 'изображения контента',
|
|
||||||
'source_language_id' => 'идентификатор исходного языка',
|
|
||||||
'translate_from_language' => 'перевести с языка',
|
|
||||||
'translate-automatically.*' => 'переводить автоматически',
|
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
6
app/application/package-lock.json
generated
6
app/application/package-lock.json
generated
@@ -5,7 +5,6 @@
|
|||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fancyapps/ui": "^5.0.36",
|
|
||||||
"@popperjs/core": "^2.9.2",
|
"@popperjs/core": "^2.9.2",
|
||||||
"bootstrap": "5.0.2",
|
"bootstrap": "5.0.2",
|
||||||
"chartist": "^0.11.4",
|
"chartist": "^0.11.4",
|
||||||
@@ -398,11 +397,6 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@fancyapps/ui": {
|
|
||||||
"version": "5.0.36",
|
|
||||||
"resolved": "https://registry.npmjs.org/@fancyapps/ui/-/ui-5.0.36.tgz",
|
|
||||||
"integrity": "sha512-GMygQzp1MBTFNTT6AzpbL6pXTD6bTxwjmmpI1fe8Ozmmiseu8/g82Sudl1YhcbZmS4bJgaBOF5THDFGpXQ1fDw=="
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.5",
|
"version": "0.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
||||||
|
@@ -6,7 +6,6 @@
|
|||||||
"build": "vite build"
|
"build": "vite build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fancyapps/ui": "^5.0.36",
|
|
||||||
"@popperjs/core": "^2.9.2",
|
"@popperjs/core": "^2.9.2",
|
||||||
"bootstrap": "5.0.2",
|
"bootstrap": "5.0.2",
|
||||||
"chartist": "^0.11.4",
|
"chartist": "^0.11.4",
|
||||||
|
@@ -1,6 +0,0 @@
|
|||||||
import { Fancybox } from "@fancyapps/ui";
|
|
||||||
import "@fancyapps/ui/dist/fancybox/fancybox.css";
|
|
||||||
|
|
||||||
Fancybox.bind('a.image-open', {
|
|
||||||
//
|
|
||||||
});
|
|
@@ -18,10 +18,6 @@ import "prismjs/components/prism-nginx.js";
|
|||||||
import "prismjs/components/prism-docker.js";
|
import "prismjs/components/prism-docker.js";
|
||||||
import "prismjs/components/prism-diff.js";
|
import "prismjs/components/prism-diff.js";
|
||||||
import "prismjs/components/prism-php.js";
|
import "prismjs/components/prism-php.js";
|
||||||
import "prismjs/components/prism-yaml.js";
|
|
||||||
import "prismjs/components/prism-bash.js"
|
|
||||||
import "prismjs/components/prism-json.js"
|
|
||||||
import "prismjs/components/prism-toml.js"
|
|
||||||
|
|
||||||
|
|
||||||
import "prismjs/plugins/toolbar/prism-toolbar.css";
|
import "prismjs/plugins/toolbar/prism-toolbar.css";
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
let blockDocumentationVersion = document.querySelector('#documentation-version');
|
let blockDocumentationVersion = document.querySelector('#documentation-version');
|
||||||
if (blockDocumentationVersion) {
|
|
||||||
blockDocumentationVersion.querySelector('.documentation-version__button').addEventListener('click', (e) => {
|
blockDocumentationVersion.querySelector('.documentation-version__button').addEventListener('click', (e) => {
|
||||||
if (blockDocumentationVersion.classList.contains('active')) {
|
if (blockDocumentationVersion.classList.contains('active')) {
|
||||||
blockDocumentationVersion.classList.remove('active');
|
blockDocumentationVersion.classList.remove('active');
|
||||||
@@ -7,4 +6,3 @@ if (blockDocumentationVersion) {
|
|||||||
blockDocumentationVersion.classList.add('active');
|
blockDocumentationVersion.classList.add('active');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
@@ -29,39 +29,6 @@ body {
|
|||||||
|
|
||||||
.content {
|
.content {
|
||||||
flex: 1 0 auto;
|
flex: 1 0 auto;
|
||||||
|
|
||||||
img {
|
|
||||||
max-width: 100%;
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-open {
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
img {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@supports (--custom:property) {
|
|
||||||
[style*="--aspect-ratio"] {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
[style*="--aspect-ratio"]::before {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
padding-bottom: calc(100% / (var(--aspect-ratio)));
|
|
||||||
}
|
|
||||||
[style*="--aspect-ratio"] img {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
|||||||
@vite('resources/fancybox/app.js')
|
|
@@ -1 +0,0 @@
|
|||||||
<script src="{{ asset('/build/tinymce/tinymce.min.js') }}" referrerpolicy="origin"></script>
|
|
@@ -1,4 +0,0 @@
|
|||||||
@pushOnce('scripts')
|
|
||||||
@include('_tinymce')
|
|
||||||
@include('_prism')
|
|
||||||
@endpushonce
|
|
@@ -1,11 +1,6 @@
|
|||||||
@csrf
|
@csrf
|
||||||
<x-volt.forms.input :title="__('validation.attributes.title')" name="title" type="text" :value="$content->title" required autofocus />
|
<x-volt.forms.input :title="__('validation.attributes.title')" name="title" type="text" :value="$content->title" required autofocus />
|
||||||
<x-volt.forms.textarea-wysiwyg
|
<x-volt.forms.textarea-wysiwyg :title="__('validation.attributes.description')" name="description" :value="$content->description" />
|
||||||
:title="__('validation.attributes.description')"
|
|
||||||
name="description"
|
|
||||||
:value="$content->description"
|
|
||||||
:storageUpload="new \App\Dto\View\Volt\Form\WysiwygStorageUpload(inputName: 'storage', morph: \App\Enums\Morph::ProjectContent)"
|
|
||||||
/>
|
|
||||||
|
|
||||||
@canany(['create', 'update'], $content)
|
@canany(['create', 'update'], $content)
|
||||||
<button class="btn btn-primary" type="submit">{{ __('Save') }}</button>
|
<button class="btn btn-primary" type="submit">{{ __('Save') }}</button>
|
||||||
|
@@ -20,11 +20,6 @@
|
|||||||
@endphp
|
@endphp
|
||||||
<div class="tab-pane fade @if($index === 0) show active @endif" id="language-{{ $language->id }}" role="tabpanel" aria-labelledby="language-{{ $language->id }}-tab">
|
<div class="tab-pane fade @if($index === 0) show active @endif" id="language-{{ $language->id }}" role="tabpanel" aria-labelledby="language-{{ $language->id }}-tab">
|
||||||
<x-volt.forms.checkbox :title="__('Edit')" :name="'content-enable-' . $language->id" :user-value="($index === 0) ? 1 : 0" class="content-enable" checkbox-value="1" notCheckedValue="0"/>
|
<x-volt.forms.checkbox :title="__('Edit')" :name="'content-enable-' . $language->id" :user-value="($index === 0) ? 1 : 0" class="content-enable" checkbox-value="1" notCheckedValue="0"/>
|
||||||
@if($serviceTranslationEnable)
|
|
||||||
<x-volt.forms.checkbox :title="__('Automatic translation')" :name="'translate-automatically[' . $language->id . ']'"
|
|
||||||
:user-value="1" class="language-content" checkbox-value="1"
|
|
||||||
not-checked-value="0"/>
|
|
||||||
@endif
|
|
||||||
<x-volt.forms.input :title="__('validation.attributes.title')" :name="'content[' . $language->id . '][title]'" type="text" class="language-content" :disabled="$index !== 0" :value="$content?->title ?? ''" required />
|
<x-volt.forms.input :title="__('validation.attributes.title')" :name="'content[' . $language->id . '][title]'" type="text" class="language-content" :disabled="$index !== 0" :value="$content?->title ?? ''" required />
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
@@ -1,22 +1,15 @@
|
|||||||
@csrf
|
@csrf
|
||||||
<x-volt.forms.checkbox :title="__('validation.attributes.is_public')" name="is_public" checkboxValue="1"
|
<x-volt.forms.checkbox :title="__('validation.attributes.is_public')" name="is_public" checkboxValue="1" notCheckedValue="0" :userValue="(string) $documentation->is_public" />
|
||||||
notCheckedValue="0" :userValue="(string) $documentation->is_public"/>
|
<x-volt.forms.input :title="__('validation.attributes.slug')" allowed-characters="a-z0-9.-_" name="slug" type="text" :value="$documentation->slug" required autofocus />
|
||||||
<x-volt.forms.input :title="__('validation.attributes.slug')" allowed-characters="a-z0-9.-_" name="slug" type="text"
|
<x-volt.forms.input :title="__('validation.attributes.sort')" name="sort" type="number" :value="$documentation->sort" required />
|
||||||
:value="$documentation->slug" required autofocus/>
|
<x-volt.forms.select :title="__('validation.attributes.category_id')" name="category_id" :list="$categories" :value="(string) $documentation->category?->id">
|
||||||
<x-volt.forms.input :title="__('validation.attributes.sort')" name="sort" type="number" :value="$documentation->sort"
|
|
||||||
required/>
|
|
||||||
<x-volt.forms.select :title="__('validation.attributes.category_id')" name="category_id" :list="$categories"
|
|
||||||
:value="(string) $documentation->category?->id">
|
|
||||||
<option value=""></option>
|
<option value=""></option>
|
||||||
</x-volt.forms.select>
|
</x-volt.forms.select>
|
||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
<div class="nav nav-tabs mb-4" id="nav-language-tab" role="tablist">
|
<div class="nav nav-tabs mb-4" id="nav-language-tab" role="tablist">
|
||||||
@foreach($project->languages as $index => $language)
|
@foreach($project->languages as $index => $language)
|
||||||
<a class="nav-item nav-link @if($index === 0) active @endif" id="language-{{ $language->id }}-tab"
|
<a class="nav-item nav-link @if($index === 0) active @endif" id="language-{{ $language->id }}-tab" data-bs-toggle="tab" href="#language-{{ $language->id }}" role="tab" aria-controls="language-{{ $language->id }}" aria-selected="{{ $index ? 'false' : 'true' }}">{{ $language->title }}</a>
|
||||||
data-bs-toggle="tab" href="#language-{{ $language->id }}" role="tab"
|
|
||||||
aria-controls="language-{{ $language->id }}"
|
|
||||||
aria-selected="{{ $index ? 'false' : 'true' }}">{{ $language->title }}</a>
|
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -25,28 +18,10 @@
|
|||||||
@php
|
@php
|
||||||
$content = $documentation->contents->firstWhere('language_id', $language->id);
|
$content = $documentation->contents->firstWhere('language_id', $language->id);
|
||||||
@endphp
|
@endphp
|
||||||
<div class="tab-pane fade @if($index === 0) show active @endif" id="language-{{ $language->id }}"
|
<div class="tab-pane fade @if($index === 0) show active @endif" id="language-{{ $language->id }}" role="tabpanel" aria-labelledby="language-{{ $language->id }}-tab">
|
||||||
role="tabpanel" aria-labelledby="language-{{ $language->id }}-tab">
|
<x-volt.forms.checkbox :title="__('Edit')" :name="'content-enable-' . $language->id" :user-value="($index === 0) ? 1 : 0" class="content-enable" checkbox-value="1" notCheckedValue="0"/>
|
||||||
<x-volt.forms.checkbox :title="__('Edit')" :name="'content-enable-' . $language->id"
|
<x-volt.forms.input :title="__('validation.attributes.title')" :name="'content[' . $language->id . '][title]'" type="text" class="language-content" :disabled="$index !== 0" :value="$content?->title ?? ''" required />
|
||||||
:user-value="($index === 0) ? 1 : 0" class="content-enable" checkbox-value="1"
|
<x-volt.forms.textarea-wysiwyg :title="__('validation.attributes.content')" :name="'content[' . $language->id . '][content]'" class="language-content" :value="$content?->content" :disabled="$index !== 0" />
|
||||||
not-checked-value="0"/>
|
|
||||||
@if($serviceTranslationEnable)
|
|
||||||
<x-volt.forms.checkbox :title="__('Automatic translation')" :name="'translate-automatically[' . $language->id . ']'"
|
|
||||||
:user-value="1" class="language-content" checkbox-value="1"
|
|
||||||
not-checked-value="0"/>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
<x-volt.forms.input :title="__('validation.attributes.title')"
|
|
||||||
:name="'content[' . $language->id . '][title]'" type="text" class="language-content"
|
|
||||||
:disabled="$index !== 0" :value="$content?->title ?? ''" required/>
|
|
||||||
<x-volt.forms.textarea-wysiwyg
|
|
||||||
:title="__('validation.attributes.content')"
|
|
||||||
:storageUpload="new \App\Dto\View\Volt\Form\WysiwygStorageUpload(inputName: 'content[' . $language->id . ']', morph: \App\Enums\Morph::DocumentationContent)"
|
|
||||||
:name="'content[' . $language->id . '][content]'"
|
|
||||||
class="language-content"
|
|
||||||
:value="$content?->content"
|
|
||||||
:disabled="$index !== 0"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
|
@@ -40,15 +40,6 @@
|
|||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if($serviceTranslationEnable)
|
|
||||||
@can('settingUpAutomaticTranslation', $project)
|
|
||||||
<a href="{{ route('admin.projects.service-translate.view', $project) }}" class="btn btn-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ __('Automatic translation') }}">
|
|
||||||
<svg class="align-text-top" width="16" height="16" data-slot="icon" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m10.5 21 5.25-11.25L21 21m-9-3h7.5M3 5.621a48.474 48.474 0 0 1 6-.371m0 0c1.12 0 2.233.038 3.334.114M9 5.25V3m3.334 2.364C11.176 10.658 7.69 15.08 3 17.502m9.334-12.138c.896.061 1.785.147 2.666.257m-4.589 8.495a18.023 18.023 0 0 1-3.827-5.802"></path>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
@endcan
|
|
||||||
@endif
|
|
||||||
<a href="{{ route('admin.projects.edit', $project) }}" class="btn btn-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ __('Edit') }}">
|
<a href="{{ route('admin.projects.edit', $project) }}" class="btn btn-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ __('Edit') }}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="align-text-top" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="align-text-top" viewBox="0 0 16 16">
|
||||||
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
|
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
|
||||||
|
@@ -1,46 +0,0 @@
|
|||||||
@section('meta_title', __('admin-sections.Setting up automatic translation') . '. ' . __('admin-sections.Project') . ': ' . $project->name)
|
|
||||||
@section('h1', __('admin-sections.Setting up automatic translation') . '. ' . __('admin-sections.Project') . ': ' . $project->name)
|
|
||||||
<x-admin.layout>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12 mb-4">
|
|
||||||
<div class="card border-0 shadow components-section">
|
|
||||||
<div class="card-body">
|
|
||||||
<form method="post" action="{{ route('admin.projects.service-translate.update', ['project' => $project->id]) }}">
|
|
||||||
@csrf
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-centered table-nowrap mb-0 rounded">
|
|
||||||
<thead class="thead-light">
|
|
||||||
<tr>
|
|
||||||
<th class="border-0">{{ __('validation.attributes.lang') }}</th>
|
|
||||||
<th class="border-0">{{ __('validation.attributes.code') }}</th>
|
|
||||||
<th class="border-0">{{ __('validation.attributes.translate_from_language') }}</th>
|
|
||||||
<th class="border-0 rounded-end" style="width: 150px"></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@foreach($languages as $index => $language)
|
|
||||||
<tr>
|
|
||||||
<td>{{ $language->title }}</td>
|
|
||||||
<td>
|
|
||||||
<x-volt.forms.input title="" name="language[{{ $index }}][code]" type="text" :value="$language->serviceTranslate?->code" />
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<x-volt.forms.select title="" name="language[{{ $index }}][source_language_id]" :value="(string) $language->serviceTranslate?->source_language_id" :list="$languages->pluck('title', 'id')->toArray()">
|
|
||||||
<option value=""></option>
|
|
||||||
</x-volt.forms.select>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="hidden" value="{{ $language->id }}" name="language[{{ $index }}][id]" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-primary" type="submit">{{ __('Save') }}</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</x-admin.layout>
|
|
@@ -1,7 +1,5 @@
|
|||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
@if(!empty($title))
|
|
||||||
<label for="form-select-{{ $requestName }}">{{ $title }}</label>
|
<label for="form-select-{{ $requestName }}">{{ $title }}</label>
|
||||||
@endif
|
|
||||||
<select id="form-select-{{ $requestName }}" aria-label="{{ $title }}" class="form-select @error($requestName) is-invalid @enderror" name="{{ $name }}" {{ $attributes }}>
|
<select id="form-select-{{ $requestName }}" aria-label="{{ $title }}" class="form-select @error($requestName) is-invalid @enderror" name="{{ $name }}" {{ $attributes }}>
|
||||||
{{ $slot }}
|
{{ $slot }}
|
||||||
@foreach($list as $elementKey => $elementValue)
|
@foreach($list as $elementKey => $elementValue)
|
||||||
|
@@ -1,121 +1,27 @@
|
|||||||
@php
|
|
||||||
$tinyId = \Illuminate\Support\Str::random(7);
|
|
||||||
$tinyId = 'form-textarea-wysiwyg-' . $tinyId;
|
|
||||||
|
|
||||||
$images = [];
|
|
||||||
$files = [];
|
|
||||||
/** @var \App\Dto\View\Volt\Form\WysiwygStorageUpload | null $storageUpload */
|
|
||||||
if ($storageUpload !== null) {
|
|
||||||
$storages = old($storageUpload->getRequestInputName(), []);
|
|
||||||
$images = $storages['content_images'] ?? [];
|
|
||||||
}
|
|
||||||
@endphp
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="{{ $tinyId }}">{{ $title }}</label>
|
<label for="form-textarea-wysiwyg-{{ $requestName }}">{{ $title }}</label>
|
||||||
<textarea class="form-control {{ $attributes->get('class') }} textarea-tinymce @error($requestName) is-invalid @enderror" name="{{ $name }}" id="{{ $tinyId }}" rows="3">{{ $value }}</textarea>
|
<textarea class="form-control {{ $attributes->get('class') }} textarea-tinymce @error($requestName) is-invalid @enderror" name="{{ $name }}" id="form-textarea-wysiwyg-{{ $requestName }}" rows="3">{{ $value }}</textarea>
|
||||||
@foreach($images as $image)
|
|
||||||
@continue( empty($image['file']) )
|
|
||||||
<input type="hidden" value="{{ $image['file'] }}" name="{{ $storageUpload->getInputName() }}[content_images][][file]';">
|
|
||||||
@endforeach
|
|
||||||
@error($requestName)
|
@error($requestName)
|
||||||
<span class="invalid-feedback">{{ $message }}</span>
|
<span class="invalid-feedback">{{ $message }}</span>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
@include('admin._scripts._tinymce')
|
@pushOnce('scripts')
|
||||||
@push('scripts')
|
<script src="{{ asset('/build/tinymce/tinymce.min.js') }}" referrerpolicy="origin"></script>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
@if($storageUpload !== null)
|
|
||||||
const textarea = document.querySelector('#{{ $tinyId }}');
|
|
||||||
if (!textarea) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const storageImageType = '{{ \App\Enums\StorageType::ContentImages->value }}';
|
|
||||||
const morph = '{{ $storageUpload->getMorph()->value }}';
|
|
||||||
const storageInputName = '{{ $storageUpload->getInputName() }}';
|
|
||||||
|
|
||||||
const imageUpload = (blobInfo, progress) => new Promise((resolve, reject) => {
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
xhr.withCredentials = false;
|
|
||||||
xhr.open('POST', '{{ route('storage.image_upload_and_resize') }}');
|
|
||||||
|
|
||||||
xhr.upload.onprogress = (e) => {
|
|
||||||
progress(e.loaded / e.total * 100);
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.onload = () => {
|
|
||||||
if (xhr.status === 422) {
|
|
||||||
const json = JSON.parse(xhr.responseText);
|
|
||||||
let error = 'Error:<br><br>';
|
|
||||||
for (let key of Object.keys(json.errors)) {
|
|
||||||
error += json.errors[key] + '<br><br>';
|
|
||||||
}
|
|
||||||
reject(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xhr.status === 403) {
|
|
||||||
reject({ message: 'HTTP Error: ' + xhr.status, remove: true });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xhr.status < 200 || xhr.status >= 300) {
|
|
||||||
reject('HTTP Error: ' + xhr.status);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const json = JSON.parse(xhr.responseText);
|
|
||||||
|
|
||||||
if (!json || typeof json.url != 'string') {
|
|
||||||
reject('Invalid JSON: ' + xhr.responseText);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let input = document.createElement('input');
|
|
||||||
input.type = 'hidden';
|
|
||||||
input.name = storageInputName + '[content_images][][file]';
|
|
||||||
input.value = json.id;
|
|
||||||
|
|
||||||
textarea.after(input);
|
|
||||||
|
|
||||||
resolve(json.url);
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.onerror = () => {
|
|
||||||
reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
|
|
||||||
};
|
|
||||||
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('file', blobInfo.blob(), blobInfo.filename());
|
|
||||||
formData.append('_token', document.querySelector('meta[name="csrf-token"]').content);
|
|
||||||
formData.append('storage_type', storageImageType);
|
|
||||||
formData.append('morph', morph);
|
|
||||||
|
|
||||||
xhr.send(formData);
|
|
||||||
});
|
|
||||||
@endif
|
|
||||||
tinymce.init({
|
tinymce.init({
|
||||||
selector: '#{{ $tinyId }}',
|
selector: '.textarea-tinymce',
|
||||||
@if(in_array(app()->getLocale(), ['ru'], true))
|
@if(in_array(app()->getLocale(), ['ru'], true))
|
||||||
language: '{{ app()->getLocale() }}',
|
language: '{{ app()->getLocale() }}',
|
||||||
@endif
|
@endif
|
||||||
license_key: '{{ $tinymceLicenseKey }}',
|
license_key: '{{ $tinymceLicenseKey }}',
|
||||||
plugins: 'advlist code emoticons link lists table codesample media my-image',
|
plugins: 'advlist code emoticons link lists table codesample',
|
||||||
toolbar: 'bold italic | bullist numlist | link image emoticons media codesample',
|
toolbar: 'bold italic | bullist numlist | link emoticons codesample',
|
||||||
referrer_policy: 'origin',
|
referrer_policy: 'origin',
|
||||||
@if($storageUpload !== null)
|
|
||||||
images_upload_handler: imageUpload,
|
|
||||||
@endif
|
|
||||||
relative_urls: false,
|
|
||||||
convert_urls: false,
|
|
||||||
codesample_global_prismjs: true,
|
codesample_global_prismjs: true,
|
||||||
codesample_languages: [
|
codesample_languages: [
|
||||||
{text: 'HTML/XML', value: 'markup'},
|
{text: 'HTML/XML', value: 'markup'},
|
||||||
{text: 'JavaScript', value: 'javascript'},
|
{text: 'JavaScript', value: 'javascript'},
|
||||||
{text: 'Bash', value: 'bash'},
|
|
||||||
{text: 'SH', value: 'sh'},
|
|
||||||
{text: 'Shell', value: 'shell'},
|
|
||||||
{text: 'CSS', value: 'css'},
|
{text: 'CSS', value: 'css'},
|
||||||
{text: 'PHP', value: 'php'},
|
{text: 'PHP', value: 'php'},
|
||||||
{text: 'Ruby', value: 'ruby'},
|
{text: 'Ruby', value: 'ruby'},
|
||||||
@@ -127,13 +33,11 @@
|
|||||||
{text: 'Go', value: 'go'},
|
{text: 'Go', value: 'go'},
|
||||||
{text: 'Nginx', value: 'nginx'},
|
{text: 'Nginx', value: 'nginx'},
|
||||||
{text: 'Docker', value: 'docker'},
|
{text: 'Docker', value: 'docker'},
|
||||||
{text: 'YAML', value: 'yaml'},
|
|
||||||
{text: 'TOML', value: 'toml'},
|
|
||||||
{text: 'Json', value: 'json'},
|
|
||||||
{text: "Treeview", value: "treeview"},
|
{text: "Treeview", value: "treeview"},
|
||||||
{text: "Diff", value: "diff"},
|
{text: "Diff", value: "diff"},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@endpush
|
@include('_prism')
|
||||||
|
@endpushonce
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user