admin theme pack

This commit is contained in:
Билай Станислав 2024-12-23 14:14:59 +03:00
parent 093b04c2c9
commit de690dfd39
111 changed files with 187 additions and 55 deletions

0
app/admin_themes/custom/layout/main.php Normal file → Executable file
View File

1
app/admin_themes/custom/manifest.json Normal file → Executable file
View File

@ -3,6 +3,7 @@
"version": "0.1", "version": "0.1",
"author": "Kavalar", "author": "Kavalar",
"slug": "custom", "slug": "custom",
"type": "admin_theme",
"description": "Custom admin theme", "description": "Custom admin theme",
"preview": "nrnv2024_640x360.jpg", "preview": "nrnv2024_640x360.jpg",
"resource": "/resources/custom", "resource": "/resources/custom",

View File

@ -18,31 +18,15 @@ class AdminThemeController extends ConsoleController
throw new \Exception('Missing admin theme path "--path" specified'); throw new \Exception('Missing admin theme path "--path" specified');
} }
$zip = new ZipArchive; if (file_exists(ROOT_DIR . $this->argv['path'])) {
$tmpThemeDir = md5(time()); $adminThemeService = new AdminThemeService();
$res = $zip->open(ROOT_DIR . $this->argv['path']); if ($adminThemeService->install($this->argv['path'])) {
if ($res === TRUE) { $this->out->r("Тема админ-панели установлена", 'green');
$tmpThemeDirFull = RESOURCES_DIR . '/tmp/ad/' . $tmpThemeDir . "/";
$zip->extractTo($tmpThemeDirFull);
$zip->close();
$this->out->r('Архив распакован', 'green');
} else { } else {
$this->out->r('Message: Ошибка чтения архива', 'red'); $this->out->r("Ошибка установки темы админ-панели", 'red');
} }
} else {
if (file_exists($tmpThemeDirFull . "meta/manifest.json")){ $this->out->r("Тема админ-панели не найдена", 'red');
$manifestJson = getConst(file_get_contents($tmpThemeDirFull . "meta/manifest.json"));
$manifest = Manifest::getWithVars($manifestJson);
$this->out->r('manifest.json инициализирован', 'green');
$fileHelper = new Files();
$fileHelper->copy_folder($tmpThemeDirFull . "meta", $manifest['theme_path']);
$fileHelper->copy_folder($tmpThemeDirFull . "resources", $manifest['resource_path']);
$this->out->r("Удаляем временные файлы", 'green');
$fileHelper->recursiveRemoveDir($tmpThemeDirFull);
$this->out->r("Тема " . $manifest['name'] . " установлена", 'green');
} }
} }
@ -53,17 +37,11 @@ class AdminThemeController extends ConsoleController
} }
if (file_exists(ROOT_DIR . $this->argv['path'])) { if (file_exists(ROOT_DIR . $this->argv['path'])) {
$themeName = basename($this->argv['path']);
$active_admin_theme = Option::where("key", "active_admin_theme")->first();
if ($active_admin_theme->value === ROOT_DIR . $this->argv['path']) {
$this->out->r("Меняем тему на базовую", 'green');
$adminThemeService = new AdminThemeService(); $adminThemeService = new AdminThemeService();
$adminThemeService->setActiveAdminTheme(KERNEL_ADMIN_THEMES_DIR . '/default'); $adminThemeService->uninstall($this->argv['path']);
$this->out->r("Тема изменена", 'green');
}
$fileHelper = new Files();
$fileHelper->recursiveRemoveDir(ROOT_DIR . $this->argv['path']);
$fileHelper->recursiveRemoveDir(RESOURCES_DIR . '/' . $themeName);
$this->out->r("Тема удалена", 'green'); $this->out->r("Тема удалена", 'green');
} else { } else {
@ -71,4 +49,22 @@ class AdminThemeController extends ConsoleController
} }
} }
/**
* @throws \Exception
*/
public function actionPackTheme(): void
{
if (!isset($this->argv['path'])) {
throw new \Exception('Missing admin theme path "--path" specified');
}
if (file_exists(ROOT_DIR . $this->argv['path'])) {
$adminThemeService = new AdminThemeService();
$adminThemeService->pack($this->argv['path']);
$this->out->r("Тема админ-панели заархивирована", 'green');
} else {
$this->out->r("Тема админ-панели не найдена", 'red');
}
}
} }

View File

@ -35,6 +35,10 @@ App::$collector->group(["prefix" => "admin-theme"], callback: function (RouteCol
[\kernel\console\controllers\AdminThemeController::class, 'actionUninstallTheme'], [\kernel\console\controllers\AdminThemeController::class, 'actionUninstallTheme'],
additionalInfo: ['description' => 'Удалить тему админ-панели', 'params' => ['--path' => 'Путь к удаляемой теме']] additionalInfo: ['description' => 'Удалить тему админ-панели', 'params' => ['--path' => 'Путь к удаляемой теме']]
); );
App::$collector->console('pack',
[\kernel\console\controllers\AdminThemeController::class, 'actionPackTheme'],
additionalInfo: ['description' => 'Заархивировать тему админ-панели', 'params' => ['--path' => 'Путь к теме, которую нужно заархивировать']]
);
}); });
App::$collector->group(["prefix" => "secure"], callback: function (RouteCollector $router){ App::$collector->group(["prefix" => "secure"], callback: function (RouteCollector $router){

View File

@ -0,0 +1,23 @@
<?php
namespace kernel\filters;
use Itguild\Tables\Filter\Filter;
class CustomSelectFilter extends Filter
{
public function fetch()
{
$this->html = "<td><select class='form-control' name='$this->name'>";
foreach ($this->param as $value) {
if ($value === $this->value) {
$this->html .= "<option value='$value' selected>$value</option>";
} else {
$this->html .= "<option value='$value'>$value</option>";
}
}
$this->html .= "value='$this->value'</select></td>";
return $this->html;
}
}

View File

@ -42,15 +42,15 @@ $table->addAction(function ($row, $url) use ($moduleService) {
$table->columns([ $table->columns([
'type' => [ 'type' => [
'filter' => [ 'filter' => [
'class' => \Itguild\Tables\Filter\SelectFilter::class, 'class' => \kernel\filters\CustomSelectFilter::class,
'param' => ['kernel', 'entity'], 'param' => ['kernel', 'entity'],
'value' => "kernel" 'value' => "kernel"
], ],
] ]
]); ]);
$table->addAction(function ($row, $url) use ($moduleService){ $table->addAction(function ($row, $url) use ($moduleService) {
if ($row['slug'] !== 'kernel') { if ($row['type'] === 'entity' || $row['type'] === 'additional_property') {
if ($moduleService->isInstall($row['slug'])) { if ($moduleService->isInstall($row['slug'])) {
$url = "$url/delete/?slug=" . $row['slug']; $url = "$url/delete/?slug=" . $row['slug'];
@ -61,10 +61,12 @@ $table->addAction(function ($row, $url) use ($moduleService){
return \kernel\widgets\IconBtn\IconBtnInstallWidget::create(['url' => $url])->run(); return \kernel\widgets\IconBtn\IconBtnInstallWidget::create(['url' => $url])->run();
} }
} }
return null;
return false;
}); });
$table->addAction(function ($row, $url) use ($moduleService) { $table->addAction(function ($row, $url) use ($moduleService) {
if ($row['type'] === 'entity' || $row['type'] === 'additional_property') {
$slug = $row['slug']; $slug = $row['slug'];
if ($moduleService->isInstall($slug)) { if ($moduleService->isInstall($slug)) {
if (!$moduleService->isLastVersion($slug)) { if (!$moduleService->isLastVersion($slug)) {
@ -73,13 +75,13 @@ $table->addAction(function ($row, $url) use ($moduleService) {
return \kernel\widgets\IconBtn\IconBtnUpdateWidget::create(['url' => $url])->run(); return \kernel\widgets\IconBtn\IconBtnUpdateWidget::create(['url' => $url])->run();
} }
} }
}
return false; return false;
}); });
$table->addAction(function ($row, $url) use ($kernelService) { $table->addAction(function ($row, $url) use ($kernelService) {
$slug = $row['slug']; if ($row['type'] === 'kernel') {
if ($slug === 'kernel') {
if (!$kernelService->isLastVersion()) { if (!$kernelService->isLastVersion()) {
$url = "$url/kernel/update_form/"; $url = "$url/kernel/update_form/";
@ -91,9 +93,8 @@ $table->addAction(function ($row, $url) use ($kernelService) {
}); });
$table->addAction(function ($row, $url) use ($adminThemeService) { $table->addAction(function ($row, $url) use ($adminThemeService) {
$type = $row['type']; if ($row['type'] === 'admin_theme') {
$slug = $row['slug']; $slug = $row['slug'];
if ($type === 'admin_theme') {
if ($adminThemeService->isInstall($slug)) { if ($adminThemeService->isInstall($slug)) {
if (!$adminThemeService->isLastVersion($slug)) { if (!$adminThemeService->isLastVersion($slug)) {
$url = "$url/admin_theme/update/"; $url = "$url/admin_theme/update/";

View File

@ -4,12 +4,16 @@ namespace kernel\services;
use DirectoryIterator; use DirectoryIterator;
use kernel\helpers\Debug; use kernel\helpers\Debug;
use kernel\helpers\Files;
use kernel\helpers\Manifest; use kernel\helpers\Manifest;
use kernel\helpers\RESTClient; use kernel\helpers\RESTClient;
use kernel\models\Option; use kernel\models\Option;
use ZipArchive;
class AdminThemeService class AdminThemeService
{ {
protected array $errors = [];
protected Option $option; protected Option $option;
protected string $active_theme; protected string $active_theme;
protected ModuleService $moduleService; protected ModuleService $moduleService;
@ -22,6 +26,24 @@ class AdminThemeService
$this->moduleService = new ModuleService(); $this->moduleService = new ModuleService();
} }
/**
* @return array
*/
public function getErrors(): array
{
return $this->errors;
}
/**
* @param $msg
* @return void
*/
public function addError($msg): void
{
$this->errors[] = $msg;
}
public function findActiveAdminTheme(): void public function findActiveAdminTheme(): void
{ {
$model = Option::where("key", "active_admin_theme")->first(); $model = Option::where("key", "active_admin_theme")->first();
@ -50,7 +72,7 @@ class AdminThemeService
$info = []; $info = [];
$theme = getConst($theme); $theme = getConst($theme);
$info['path'] = $theme; $info['path'] = $theme;
if (file_exists($theme . "/manifest.json")){ if (file_exists($theme . "/manifest.json")) {
$manifest = file_get_contents($theme . "/manifest.json"); $manifest = file_get_contents($theme . "/manifest.json");
$manifest = Manifest::getWithVars($manifest); $manifest = Manifest::getWithVars($manifest);
$manifest['preview'] = $manifest['resource'] . "/" . $manifest['preview']; $manifest['preview'] = $manifest['resource'] . "/" . $manifest['preview'];
@ -60,6 +82,11 @@ class AdminThemeService
return $info; return $info;
} }
public function getAdminThemeInfoBySlug(string $slug)
{
// TODO
}
public function isInstall(string $slug): bool public function isInstall(string $slug): bool
{ {
$adminThemePaths = Option::where("key", "admin_theme_paths")->first(); $adminThemePaths = Option::where("key", "admin_theme_paths")->first();
@ -85,12 +112,13 @@ class AdminThemeService
public function isLastVersion(string $slug): bool public function isLastVersion(string $slug): bool
{ {
if ($this->moduleService->isServerAvailable()) { if ($this->moduleService->isServerAvailable()) {
$modules_info = RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/gb_slug'); $modulesInfo = RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/gb_slug');
$modules_info = json_decode($modules_info->getBody()->getContents(), true); $modulesInfo = json_decode($modulesInfo->getBody()->getContents(), true);
$themeInfo = $this->getAdminThemeInfo($slug); $themeInfo = $this->getAdminThemeInfo($slug);
foreach ($modules_info as $mod) { Debug::dd($themeInfo);
foreach ($modulesInfo as $mod) {
if ($mod['slug'] === $themeInfo['slug'] && $mod['version'] === $themeInfo['version']) { if ($mod['slug'] === $themeInfo['slug'] && $mod['version'] === $themeInfo['version']) {
return true; return true;
} }
@ -99,4 +127,79 @@ class AdminThemeService
return false; return false;
} }
public function pack(string $path): void
{
$themeName = basename($path);
$tmpThemeDirFull = RESOURCES_DIR . '/tmp/ad/' . $themeName . "/";
$fileHelper = new Files();
$fileHelper->copy_folder(ROOT_DIR . $path, $tmpThemeDirFull . 'meta/');
$fileHelper->copy_folder(RESOURCES_DIR . '/' . $themeName, $tmpThemeDirFull . 'resources/');
if (!is_dir(RESOURCES_DIR . '/tmp/admin_themes')) {
$old_mask = umask(0);
mkdir(RESOURCES_DIR . '/tmp/admin_themes', 0775, true);
umask($old_mask);
}
$fileHelper->pack($tmpThemeDirFull, RESOURCES_DIR . '/tmp/admin_themes/' . $themeName . '.igt');
}
public function install(string $path): bool
{
$zip = new ZipArchive;
$tmpThemeDir = md5(time());
$res = $zip->open(ROOT_DIR . $path);
if ($res === TRUE) {
$tmpThemeDirFull = RESOURCES_DIR . '/tmp/ad/' . $tmpThemeDir . "/";
$zip->extractTo($tmpThemeDirFull);
$zip->close();
} else {
$this->addError('unable to open zip archive');
return false;
}
if (!file_exists($tmpThemeDirFull . "meta/manifest.json")){
$this->addError('manifest.json not found');
return false;
}
$manifestJson = getConst(file_get_contents($tmpThemeDirFull . "meta/manifest.json"));
$manifest = Manifest::getWithVars($manifestJson);
$fileHelper = new Files();
if (isset($manifest['theme_path'])) {
$fileHelper->copy_folder($tmpThemeDirFull . "meta", $manifest['theme_path']);
} else {
$fileHelper->copy_folder($tmpThemeDirFull . "meta", APP_DIR . '/admin_themes/' . $manifest['slug']);
}
if (isset($manifest['resource_path'])) {
$fileHelper->copy_folder($tmpThemeDirFull . "resources", $manifest['resource_path']);
} else {
$fileHelper->copy_folder($tmpThemeDirFull . "resources", RESOURCES_DIR . '/' . $manifest['slug']);
}
$fileHelper->recursiveRemoveDir($tmpThemeDirFull);
unlink(ROOT_DIR . $path);
return true;
}
public function uninstall(string $path): void
{
$themeInfo = $this->getAdminThemeInfo(APP_DIR . '/admin_themes/' . basename($path));
$active_admin_theme = Option::where("key", "active_admin_theme")->first();
if ($active_admin_theme->value === ROOT_DIR . $path) {
$this->setActiveAdminTheme(KERNEL_ADMIN_THEMES_DIR . '/default');
}
$fileHelper = new Files();
if (file_exists(ROOT_DIR . $path)) {
$fileHelper->recursiveRemoveDir(ROOT_DIR . $path);
}
if (file_exists(RESOURCES_DIR . '/' . $themeInfo['slug'])) {
$fileHelper->recursiveRemoveDir(RESOURCES_DIR . '/' . $themeInfo['slug']);
}
}
} }

View File

@ -362,11 +362,15 @@ class ModuleService
if (file_exists(KERNEL_APP_MODULES_DIR . '/' . $moduleName)) { if (file_exists(KERNEL_APP_MODULES_DIR . '/' . $moduleName)) {
$fileHelper->copy_folder(KERNEL_APP_MODULES_DIR . '/' . $moduleName, $tmpModuleDirFull . 'kernel/'); $fileHelper->copy_folder(KERNEL_APP_MODULES_DIR . '/' . $moduleName, $tmpModuleDirFull . 'kernel/');
} else { } else {
mkdir($tmpModuleDirFull . 'kernel/'); $old_mask = umask(0);
mkdir($tmpModuleDirFull . 'kernel/', 0775, true);
umask($old_mask);
} }
if (!is_dir(RESOURCES_DIR . '/tmp/modules')) { if (!is_dir(RESOURCES_DIR . '/tmp/modules')) {
mkdir(RESOURCES_DIR . '/tmp/modules', 0777, true); $old_mask = umask(0);
mkdir(RESOURCES_DIR . '/tmp/modules', 0775, true);
umask($old_mask);
} }
$fileHelper->pack($tmpModuleDirFull, RESOURCES_DIR . '/tmp/modules/' . $moduleName . '.igm'); $fileHelper->pack($tmpModuleDirFull, RESOURCES_DIR . '/tmp/modules/' . $moduleName . '.igm');
} }

0
resources/custom/css/bootstrap.min.css vendored Normal file → Executable file
View File

0
resources/custom/css/bootstrap/_media.css Normal file → Executable file
View File

View File

View File

0
resources/custom/css/bootstrap/mixins/_visibility.css Normal file → Executable file
View File

View File

0
resources/custom/css/style.css Normal file → Executable file
View File

0
resources/custom/images/bg_1.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

0
resources/custom/images/logo.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

0
resources/custom/js/bootstrap.min.js vendored Normal file → Executable file
View File

0
resources/custom/js/jquery.min.js vendored Normal file → Executable file
View File

0
resources/custom/js/main.js Normal file → Executable file
View File

0
resources/custom/js/popper.js Normal file → Executable file
View File

0
resources/custom/nrnv2024_640x360.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

0
resources/custom/scss/bootstrap/_alert.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_badge.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_breadcrumb.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_button-group.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_buttons.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_card.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_carousel.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_close.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_code.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_custom-forms.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_dropdown.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_forms.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_functions.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_grid.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_images.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_input-group.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_jumbotron.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_list-group.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_media.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_mixins.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_modal.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_nav.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_navbar.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_pagination.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_popover.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_print.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_progress.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_reboot.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_root.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_spinners.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_tables.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_toasts.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_tooltip.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_transitions.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_type.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_utilities.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/_variables.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/bootstrap-grid.scss vendored Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/bootstrap-reboot.scss vendored Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/bootstrap.scss vendored Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/mixins/_alert.scss Normal file → Executable file
View File

View File

0
resources/custom/scss/bootstrap/mixins/_badge.scss Normal file → Executable file
View File

View File

View File

View File

0
resources/custom/scss/bootstrap/mixins/_buttons.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/mixins/_caret.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/mixins/_clearfix.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/mixins/_deprecate.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/mixins/_float.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/mixins/_forms.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/mixins/_gradients.scss Normal file → Executable file
View File

View File

0
resources/custom/scss/bootstrap/mixins/_grid.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/mixins/_hover.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/mixins/_image.scss Normal file → Executable file
View File

View File

0
resources/custom/scss/bootstrap/mixins/_lists.scss Normal file → Executable file
View File

View File

View File

View File

0
resources/custom/scss/bootstrap/mixins/_resize.scss Normal file → Executable file
View File

View File

0
resources/custom/scss/bootstrap/mixins/_size.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/mixins/_table-row.scss Normal file → Executable file
View File

View File

0
resources/custom/scss/bootstrap/mixins/_text-hide.scss Normal file → Executable file
View File

View File

View File

View File

0
resources/custom/scss/bootstrap/utilities/_align.scss Normal file → Executable file
View File

View File

View File

View File

View File

0
resources/custom/scss/bootstrap/utilities/_embed.scss Normal file → Executable file
View File

0
resources/custom/scss/bootstrap/utilities/_flex.scss Normal file → Executable file
View File

Some files were not shown because too many files have changed in this diff Show More