Theme module and them to igfs add

This commit is contained in:
Билай Станислав 2025-01-19 21:23:53 +03:00
parent dac4db96af
commit 50c6ca98d8
12 changed files with 315 additions and 17 deletions

View File

@ -42,7 +42,6 @@ class App
public function load(): static
{
$this->moduleService = new ModuleService();
// $this->themeService = new ThemeService();
App::$collector = new CgRouteCollector();
$this->setRouting();
@ -57,10 +56,6 @@ class App
foreach ($modules_routs as $rout){
include "$rout";
}
// $activeTheme = getConst($this->themeService->getActiveTheme());
// if (!empty($activeTheme)){
// include $activeTheme . "/" . $this->themeService->getThemeRout($activeTheme);
// }
$themeService = new ThemeService();
$activeTheme = getConst($themeService->getActiveTheme());

View File

@ -3,6 +3,7 @@
"version": "0.1",
"author": "ItGuild",
"slug": "default",
"type": "admin_theme",
"description": "Default admin theme",
"preview": "preview.png",
"resource": "/resources/admin_themes/default",

View File

@ -0,0 +1,73 @@
<?php
namespace kernel\console\controllers;
use kernel\console\ConsoleController;
use kernel\helpers\Files;
use kernel\helpers\Manifest;
use kernel\models\Option;
use kernel\services\AdminThemeService;
use kernel\services\ThemeService;
use ZipArchive;
class ThemeController extends ConsoleController
{
/**
* @throws \Exception
*/
public function actionInstallTheme(): void
{
if (!isset($this->argv['path'])) {
throw new \Exception('Missing theme path "--path" specified');
}
if (file_exists(ROOT_DIR . $this->argv['path'])) {
$themeService = new ThemeService();
if ($themeService->install($this->argv['path'])) {
$this->out->r("Тема сайта установлена", 'green');
} else {
$this->out->r("Ошибка установки темы сайта", 'red');
}
} else {
$this->out->r("Тема сайта не найдена", 'red');
}
}
/**
* @throws \Exception
*/
public function actionUninstallTheme(): void
{
if (!isset($this->argv['path'])) {
throw new \Exception('Missing theme path "--path" specified');
}
if (file_exists(ROOT_DIR . $this->argv['path'])) {
$themeService = new ThemeService();
$themeService->uninstall($this->argv['path']);
$this->out->r("Тема сайта удалена", 'green');
} else {
$this->out->r("Тема сайта не найдена", 'red');
}
}
/**
* @throws \Exception
*/
public function actionPackTheme(): void
{
if (!isset($this->argv['path'])) {
throw new \Exception('Missing theme path "--path" specified');
}
if (file_exists(ROOT_DIR . $this->argv['path'])) {
$themeService = new ThemeService();
$themeService->pack($this->argv['path']);
$this->out->r("Тема сайта заархивирована", 'green');
} else {
$this->out->r("Тема сайта не найдена", 'red');
}
}
}

View File

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

View File

@ -17,6 +17,7 @@ use kernel\services\AdminThemeService;
use kernel\services\KernelService;
use kernel\services\ModuleService;
use kernel\services\ModuleShopService;
use kernel\services\ThemeService;
use PHPMailer\PHPMailer\Exception;
class ModuleShopClientController extends AdminController
@ -60,6 +61,7 @@ class ModuleShopClientController extends AdminController
'per_page' => $per_page,
'kernelService' => new KernelService(),
'adminThemeService' => new AdminThemeService(),
'themeService' => new ThemeService(),
]);
} else {
$this->cgView->render("module_shop_error_connection.php");
@ -295,4 +297,56 @@ class ModuleShopClientController extends AdminController
$this->redirect('/admin/module_shop_client', 302);
}
#[NoReturn] public function actionThemeInstall(): void
{
$request = new Request();
$id = $request->get("id");
$themeInfo = RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/install/' . $id);
$themeInfo = json_decode($themeInfo->getBody()->getContents(), true);
Files::uploadByUrl($_ENV['MODULE_SHOP_URL'] . $themeInfo['path_to_archive'], RESOURCES_DIR . "/tmp/themes");
if ($this->themeService->install('/resources/tmp/themes/' . basename($themeInfo['path_to_archive']))) {
Flash::setMessage("success", "Тема сайта успешно установлена.");
} else {
Session::start();
Session::set("error", implode(";", $this->themeService->getErrors()));
}
$this->redirect('/admin/module_shop_client', 302);
}
#[NoReturn] public function actionThemeUpdate(): void
{
$request = new Request();
$slug = $request->get("slug");
$modules_info = RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/gb_slug');
$modules_info = json_decode($modules_info->getBody()->getContents(), true);
foreach ($modules_info as $module) {
if ($module['slug'] === $slug) {
$path = $module['path_to_archive'];
}
}
if (isset($path)) {
Files::uploadByUrl($_ENV['MODULE_SHOP_URL'] . $path, RESOURCES_DIR . "/tmp/themes");
$this->themeService->update('/resources/tmp/themes/' . basename($path));
Flash::setMessage("success", "Тема сайта успешно обновлена.");
} else {
Flash::setMessage("error", "Ошибка обновления темы сайта.");
}
$this->redirect('/admin/module_shop_client', 302);
}
#[NoReturn] public function actionThemeDelete(): void
{
$request = new Request();
$slug = $request->get("slug");
$themeInfo = $this->themeService->getThemeInfoBySlug($slug);
$this->themeService->uninstall($themeInfo['path']);
Flash::setMessage("success", "Тема сайта успешно удалена.");
$this->redirect('/admin/module_shop_client', 302);
}
}

View File

@ -26,7 +26,11 @@ App::$collector->group(["prefix" => "admin"], function (RouteCollector $router){
App::$collector->get('/install', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionAdminThemeInstall']);
App::$collector->get('/update', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionAdminThemeUpdate']);
App::$collector->get('/delete', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionAdminThemeDelete']);
});
App::$collector->group(["prefix" => "theme"], function (RouteCollector $router) {
App::$collector->get('/install', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionThemeInstall']);
App::$collector->get('/update', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionThemeUpdate']);
App::$collector->get('/delete', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionThemeDelete']);
});
});
});

View File

@ -7,6 +7,7 @@
* @var \kernel\services\ModuleService $moduleService
* @var \kernel\services\KernelService $kernelService
* @var \kernel\services\AdminThemeService $adminThemeService
* @var \kernel\services\ThemeService $themeService
* @var array $filterValues
*/
@ -130,6 +131,37 @@ $table->addAction(function ($row, $url) use ($adminThemeService) {
return false;
});
$table->addAction(function ($row, $url) use ($themeService) {
if ($row['type'] === 'theme') {
$slug = $row['slug'];
if ($themeService->isInstall($slug)) {
if (!$themeService->isLastVersion($slug)) {
$url = "$url/theme/update/?slug=" . $row['slug'];
return \kernel\widgets\IconBtn\IconBtnUpdateWidget::create(['url' => $url])->run();
}
}
}
return false;
});
$table->addAction(function ($row, $url) use ($themeService) {
if ($row['type'] === 'theme') {
if ($themeService->isInstall($row['slug'])) {
$url = "$url/theme/delete/?slug=" . $row['slug'];
return \kernel\widgets\IconBtn\IconBtnDeleteWidget::create(['url' => $url])->run();
} else {
$url = "$url/theme/install/?id=" . $row['id'];
return \kernel\widgets\IconBtn\IconBtnInstallWidget::create(['url' => $url])->run();
}
}
return false;
});
$table->afterPrint(function () {
return \kernel\IGTabel\btn\PrimaryBtn::create('Сбросить все фильтры', '/admin/module_shop_client')->fetch();
});

View File

@ -16,6 +16,7 @@ class AdminThemeService
protected Option $option;
protected string $active_theme;
protected ModuleService $moduleService;
@ -151,7 +152,7 @@ class AdminThemeService
$fileHelper = new Files();
$fileHelper->copy_folder(ROOT_DIR . $path, $tmpThemeDirFull . 'meta/');
$fileHelper->copy_folder(RESOURCES_DIR . '/' . $themeName, $tmpThemeDirFull . 'resources/');
$fileHelper->copy_folder(RESOURCES_DIR . '/admin_themes/' . $themeName, $tmpThemeDirFull . 'resources/');
if (!is_dir(RESOURCES_DIR . '/tmp/admin_themes')) {
$old_mask = umask(0);
@ -193,7 +194,7 @@ class AdminThemeService
if (isset($manifest['resource_path'])) {
$fileHelper->copy_folder($tmpThemeDirFull . "resources", $manifest['resource_path']);
} else {
$fileHelper->copy_folder($tmpThemeDirFull . "resources", RESOURCES_DIR . '/' . $manifest['slug']);
$fileHelper->copy_folder($tmpThemeDirFull . "resources", RESOURCES_DIR . '/admin_themes/' . $manifest['slug']);
}
$fileHelper->recursiveRemoveDir($tmpThemeDirFull);
@ -213,8 +214,8 @@ class AdminThemeService
if (file_exists($path)) {
$fileHelper->recursiveRemoveDir($path);
}
if (file_exists(RESOURCES_DIR . '/' . $themeInfo['slug'])) {
$fileHelper->recursiveRemoveDir(RESOURCES_DIR . '/' . $themeInfo['slug']);
if (file_exists(RESOURCES_DIR . '/admin_themes/' . $themeInfo['slug'])) {
$fileHelper->recursiveRemoveDir(RESOURCES_DIR . '/admin_themes/' . $themeInfo['slug']);
}
}

View File

@ -3,6 +3,7 @@
namespace kernel\services;
use DirectoryIterator;
use kernel\helpers\Files;
use kernel\helpers\Manifest;
use kernel\helpers\RESTClient;
use kernel\models\Option;
@ -14,10 +15,14 @@ class ThemeService
protected Option $option;
protected string $active_theme = "";
protected ModuleService $moduleService;
public function __construct()
{
$this->option = new Option();
$this->findActiveTheme();
$this->moduleService = new ModuleService();
}
/**
@ -103,6 +108,123 @@ class ThemeService
return $dirs;
}
public function isInstall(string $slug): bool
{
$dirs = $this->getThemeDirs();
foreach ($dirs as $dir) {
foreach (new DirectoryIterator($dir) as $fileInfo) {
if ($fileInfo->isDot()) continue;
if ($this->getThemeInfo($fileInfo->getPathname())['slug'] === $slug) {
return true;
}
}
}
return false;
}
public function isLastVersion(string $slug): bool
{
if ($this->moduleService->isServerAvailable()) {
$modulesInfo = RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/gb_slug');
$modulesInfo = json_decode($modulesInfo->getBody()->getContents(), true);
$themeInfo = $this->getThemeInfoBySlug($slug);
foreach ($modulesInfo as $mod) {
if ($mod['slug'] === $themeInfo['slug'] && $mod['version'] === $themeInfo['version']) {
return true;
}
}
}
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 . '/themes/' . $themeName, $tmpThemeDirFull . 'resources/');
if (!is_dir(RESOURCES_DIR . '/tmp/themes')) {
$old_mask = umask(0);
mkdir(RESOURCES_DIR . '/tmp/themes', 0775, true);
umask($old_mask);
}
$fileHelper->pack($tmpThemeDirFull, RESOURCES_DIR . '/tmp/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 . '/themes/' . $manifest['slug']);
}
if (isset($manifest['resource_path'])) {
$fileHelper->copy_folder($tmpThemeDirFull . "resources", $manifest['resource_path']);
} else {
$fileHelper->copy_folder($tmpThemeDirFull . "resources", RESOURCES_DIR . '/themes/' . $manifest['slug']);
}
$fileHelper->recursiveRemoveDir($tmpThemeDirFull);
unlink(ROOT_DIR . $path);
return true;
}
public function uninstall(string $path): void
{
$themeInfo = $this->getThemeInfo(APP_DIR . '/themes/' . basename($path));
$active_theme = $this->option::where("key", "active_theme")->first();
if ($active_theme->value === ROOT_DIR . $path) {
$this->setActiveTheme(KERNEL_DIR . '/themes/default');
}
$fileHelper = new Files();
if (file_exists($path)) {
$fileHelper->recursiveRemoveDir($path);
}
if (file_exists(RESOURCES_DIR . '/themes/' . $themeInfo['slug'])) {
$fileHelper->recursiveRemoveDir(RESOURCES_DIR . '/themes/' . $themeInfo['slug']);
}
}
public function update(string $path): bool
{
if ($this->install($path)) {
return true;
}
return false;
}
public function getThemeRout(string $path)
{
if (file_exists($path . "/manifest.json")){

View File

@ -1,10 +1,11 @@
{
"name": "Default",
"slug": "default",
"version": "0.1",
"author": "ItGuild",
"preview": "preview.png",
"slug": "default",
"type": "theme",
"description": "Default theme",
"preview": "preview.png",
"resource": "/resources/themes/default",
"resource_path": "{RESOURCES}/themes/default",
"routs": "routs/default.php"

View File

@ -31,7 +31,7 @@ $assets = new \kernel\themes\default\assets\DefaultThemesAssets($resources);
<!-- Navigation-->
<nav class="navbar navbar-expand-lg navbar-light" id="mainNav">
<div class="container px-4 px-lg-5">
<a class="navbar-brand" href="/">Start Bootstrap</a>
<a class="navbar-brand" href="/">Main IT Guild Micro Framework theme</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive"
aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
Menu
@ -79,7 +79,7 @@ $assets = new \kernel\themes\default\assets\DefaultThemesAssets($resources);
</a>
</li>
</ul>
<div class="small text-center text-muted fst-italic">Copyright &copy; Твой сайт 2025</div>
<div class="small text-center text-muted fst-italic">Copyright &copy; IT Guild Micro Framework</div>
</div>
</div>
</div>

View File

@ -4,9 +4,9 @@
* @var \kernel\CgView $view
*/
$view->setTitle("Старт Bootstrap");
$view->setTitle("IT Guild Micro Framework");
$view->setMeta([
'description' => 'Дефолтная bootstrap тема'
'description' => 'Default IT Guild Micro Framework theme'
]);
?>
<!-- Page Header-->
@ -16,7 +16,7 @@ $view->setMeta([
<div class="col-md-10 col-lg-8 col-xl-7">
<div class="site-heading">
<h1>Clean Blog</h1>
<span class="subheading">A Blog Theme by Start Bootstrap</span>
<span class="subheading">A Blog Theme by IT Guild Micro Framework</span>
</div>
</div>
</div>