Compare commits

...

15 Commits

132 changed files with 473 additions and 94 deletions
View File
+1
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",
+6 -2
View File
@@ -36,7 +36,9 @@ class FileUpload
$newFileName = md5(time() . $this->fileName) . '.' . $this->fileExtension; $newFileName = md5(time() . $this->fileName) . '.' . $this->fileExtension;
if (in_array($this->fileExtension, $this->allowedFileExtensions)) { if (in_array($this->fileExtension, $this->allowedFileExtensions)) {
$this->uploadDir = $uploadDir . mb_substr($newFileName, 0, 2) . '/' . mb_substr($newFileName, 2, 2) . '/'; $this->uploadDir = $uploadDir . mb_substr($newFileName, 0, 2) . '/' . mb_substr($newFileName, 2, 2) . '/';
mkdir(ROOT_DIR . $this->uploadDir, 0777, true); $oldMask = umask(0);
mkdir(ROOT_DIR . $this->uploadDir, 0775, true);
umask($oldMask);
$uploadFileDir = ROOT_DIR . $this->uploadDir; $uploadFileDir = ROOT_DIR . $this->uploadDir;
$this->destPath = $uploadFileDir . $newFileName; $this->destPath = $uploadFileDir . $newFileName;
$this->uploadFile = $this->uploadDir . $newFileName; $this->uploadFile = $this->uploadDir . $newFileName;
@@ -49,7 +51,9 @@ class FileUpload
} else { } else {
if (in_array($this->fileExtension, $this->allowedFileExtensions)) { if (in_array($this->fileExtension, $this->allowedFileExtensions)) {
$this->uploadDir = $uploadDir; $this->uploadDir = $uploadDir;
mkdir(ROOT_DIR . $this->uploadDir, 0777, true); $oldMask = umask(0);
mkdir(ROOT_DIR . $this->uploadDir, 0775, true);
umask($oldMask);
$uploadFileDir = ROOT_DIR . $this->uploadDir; $uploadFileDir = ROOT_DIR . $this->uploadDir;
$this->destPath = $uploadFileDir . $this->fileName; $this->destPath = $uploadFileDir . $this->fileName;
$this->uploadFile = $this->uploadDir . $this->fileName; $this->uploadFile = $this->uploadDir . $this->fileName;
+4 -4
View File
@@ -6,9 +6,9 @@ class PrimaryBtn
{ {
protected string $btn = ''; protected string $btn = '';
public function __construct(string $title, string $url) public function __construct(string $title, string $url, $width)
{ {
$this->btn = "<a class='btn btn-primary' href='$url' style='margin: 3px; width: 150px;' >$title</a>"; $this->btn = "<a class='btn btn-primary' href='$url' style='margin: 3px; width: '$width >$title</a>";
} }
public function fetch(): string public function fetch(): string
@@ -16,9 +16,9 @@ class PrimaryBtn
return $this->btn; return $this->btn;
} }
public static function create(string $title, string $url): PrimaryBtn public static function create(string $title, string $url, $width = '150px'): PrimaryBtn
{ {
return new self($title, $url); return new self($title, $url, $width);
} }
} }
+3 -1
View File
@@ -94,7 +94,9 @@ class RestController
$model = $this->model->where('id', $id)->first(); $model = $this->model->where('id', $id)->first();
foreach ($model->getFillable() as $item){ foreach ($model->getFillable() as $item){
$model->{$item} = $data[$item] ?? null; if (!empty($data[$item])){
$model->{$item} = $data[$item] ?? null;
}
} }
$model->save(); $model->save();
+2 -2
View File
@@ -26,8 +26,8 @@
<div class="wrapper d-flex align-items-stretch"> <div class="wrapper d-flex align-items-stretch">
<nav id="sidebar"> <nav id="sidebar">
<div class="p-4 pt-5"> <div class="p-4 pt-5">
<a href="#" class="img logo rounded-circle mb-5" <a href="<?= '/admin/user/view/' . \kernel\modules\user\service\UserService::getAuthUser()->id ?>" class="img logo rounded-circle mb-5"
style="background-image: url(/resources/admin_theme/images/logo.jpg);"></a> style="background-image: url(<?= \kernel\modules\user\service\UserService::getAuthUserPhoto() ?? '/resources/images/noPhoto.png' ?>);"></a>
<p> <p>
<?= \kernel\modules\user\service\UserService::getAuthUsername() ?> <?= \kernel\modules\user\service\UserService::getAuthUsername() ?>
</p> </p>
@@ -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 . "/"; } else {
$zip->extractTo($tmpThemeDirFull); $this->out->r("Ошибка установки темы админ-панели", 'red');
$zip->close(); }
$this->out->r('Архив распакован', 'green');
} else { } else {
$this->out->r('Message: Ошибка чтения архива', 'red'); $this->out->r("Тема админ-панели не найдена", 'red');
}
if (file_exists($tmpThemeDirFull . "meta/manifest.json")){
$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']); $adminThemeService = new AdminThemeService();
$active_admin_theme = Option::where("key", "active_admin_theme")->first(); $adminThemeService->uninstall($this->argv['path']);
if ($active_admin_theme->value === ROOT_DIR . $this->argv['path']) {
$this->out->r("Меняем тему на базовую", 'green');
$adminThemeService = new AdminThemeService();
$adminThemeService->setActiveAdminTheme(KERNEL_ADMIN_THEMES_DIR . '/default');
$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');
}
}
} }
+4
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){
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace kernel\filters;
use itguild\forms\builders\SelectBuilder;
use Itguild\Tables\Filter\Filter;
use kernel\helpers\Debug;
class BootstrapSelectFilter extends Filter
{
public function fetch(): string
{
$select = SelectBuilder::build($this->name, [
'class' => 'form-control',
'options' => $this->param,
'value' => $this->value,
]);
return "<td>" . $select->create()->fetch() . "</td>";
}
}
@@ -0,0 +1,23 @@
<?php
namespace kernel\filters;
use itguild\forms\builders\SelectBuilder;
use Itguild\Tables\Filter\Filter;
use kernel\helpers\Debug;
class BootstrapSelectFilterWithPrompt extends Filter
{
public function fetch(): string
{
$select = SelectBuilder::build($this->name, [
'class' => 'form-control',
'options' => $this->param,
'value' => $this->value,
'prompt' => "Не выбрано"
]);
return "<td>" . $select->create()->fetch() . "</td>";
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace kernel\filters;
use itguild\forms\builders\TextInputBuilder;
use Itguild\Tables\Filter\Filter;
class BootstrapTextFilter extends Filter
{
public function fetch()
{
$textInput = TextInputBuilder::build($this->name, [
'value' => $this->value,
'class' => "form-control"
]);
return "<td>" . $textInput->create()->fetch() . "</td>";
}
}
+5 -2
View File
@@ -19,12 +19,15 @@ $table = new ListEloquentTable(new EloquentDataProvider(Menu::class, [
'baseUrl' => "/admin/settings/menu", 'baseUrl' => "/admin/settings/menu",
])); ]));
$table->columns([ $table->columns([
'parent_id' => (function ($data) { 'parent_id' => function ($data) {
if ($data == 0) return null; if ($data == 0) return null;
return Menu::find($data)->label; return Menu::find($data)->label;
}), },
'icon_file' => function ($data) { 'icon_file' => function ($data) {
return $data ? "<img src='$data' width='150px'>" : ""; return $data ? "<img src='$data' width='150px'>" : "";
},
'status' => function ($data) {
return Menu::getStatus()[$data];
} }
]); ]);
$table->beforePrint(function () { $table->beforePrint(function () {
@@ -10,14 +10,12 @@ use kernel\Flash;
use kernel\helpers\Debug; use kernel\helpers\Debug;
use kernel\helpers\Files; use kernel\helpers\Files;
use kernel\helpers\RESTClient; use kernel\helpers\RESTClient;
use kernel\helpers\SMTP; use kernel\modules\module_shop_client\services\ModuleShopClientService;
use kernel\Mailing;
use kernel\Request; use kernel\Request;
use kernel\services\AdminThemeService; use kernel\services\AdminThemeService;
use kernel\services\KernelService; use kernel\services\KernelService;
use kernel\services\ModuleService; use kernel\services\ModuleService;
use kernel\services\ModuleShopService; use kernel\services\ModuleShopService;
use kernel\services\TokenService;
use PHPMailer\PHPMailer\Exception; use PHPMailer\PHPMailer\Exception;
class ModuleShopClientController extends AdminController class ModuleShopClientController extends AdminController
@@ -26,6 +24,7 @@ class ModuleShopClientController extends AdminController
protected Client $client; protected Client $client;
protected ModuleService $moduleService; protected ModuleService $moduleService;
protected KernelService $kernelService; protected KernelService $kernelService;
protected ModuleShopClientService $moduleShopClientService;
protected function init(): void protected function init(): void
{ {
@@ -35,6 +34,7 @@ class ModuleShopClientController extends AdminController
$this->client = new Client(); $this->client = new Client();
$this->moduleService = new ModuleService(); $this->moduleService = new ModuleService();
$this->kernelService = new KernelService(); $this->kernelService = new KernelService();
$this->moduleShopClientService = new ModuleShopClientService();
} }
/** /**
@@ -42,7 +42,6 @@ class ModuleShopClientController extends AdminController
*/ */
public function actionIndex(int $page_number = 1): void public function actionIndex(int $page_number = 1): void
{ {
if ($this->moduleService->issetModuleShopToken()) { if ($this->moduleService->issetModuleShopToken()) {
if ($this->moduleService->isServerAvailable()) { if ($this->moduleService->isServerAvailable()) {
@@ -157,6 +156,48 @@ class ModuleShopClientController extends AdminController
$this->redirect('/admin/module_shop_client', 302); $this->redirect('/admin/module_shop_client', 302);
} }
public function actionSearch(int $page_number = 1): void
{
$request = new Request();
$filters = $request->get();
if ($this->moduleService->issetModuleShopToken()) {
if ($this->moduleService->isServerAvailable()) {
$modules_info = [];
$per_page = 8;
$modules = RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/gb_slug');
$modules = json_decode($modules->getBody()->getContents(), true);
foreach ($modules as $module) {
foreach ($filters as $key => $value) {
if ($value === '') continue;
if ($module[$key] !== $value) {
break;
}
$modules_info[] = $module;
}
}
$module_count = count($modules_info);
$modules_info = array_slice($modules_info, $per_page * ($page_number - 1), $per_page);
$this->cgView->render("index.php", [
'modules_info' => $modules_info,
'moduleService' => $this->moduleService,
'page_number' => $page_number,
'module_count' => $module_count,
'per_page' => $per_page,
'kernelService' => new KernelService(),
'adminThemeService' => new AdminThemeService(),
'filterValues' => $filters
]);
} else {
$this->cgView->render("module_shop_error_connection.php");
}
} else {
$this->cgView->render("login_at_module_shop.php");
}
}
/** /**
* @throws Exception * @throws Exception
*/ */
@@ -15,6 +15,7 @@ App::$collector->group(["prefix" => "admin"], function (RouteCollector $router){
App::$collector->get('/view/{id}', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionView']); App::$collector->get('/view/{id}', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionView']);
App::$collector->get('/delete', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionDelete']); App::$collector->get('/delete', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionDelete']);
App::$collector->get('/update', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionUpdate']); App::$collector->get('/update', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionUpdate']);
App::$collector->get('/search', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionSearch']);
App::$collector->post('/auth', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionAuth']); App::$collector->post('/auth', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionAuth']);
App::$collector->post('/code_check', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionCodeCheck']); App::$collector->post('/code_check', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionCodeCheck']);
App::$collector->group(["prefix" => "kernel"], function (RouteCollector $router) { App::$collector->group(["prefix" => "kernel"], function (RouteCollector $router) {
@@ -0,0 +1,22 @@
<?php
namespace kernel\modules\module_shop_client\services;
use kernel\helpers\RESTClient;
class ModuleShopClientService
{
// public function getModulesInfo(string $url, int $perPage, int $pageNumber): \Psr\Http\Message\ResponseInterface
// {
// $modules_info = RESTClient::request($url);
// $modules_info = json_decode($modules_info->getBody()->getContents(), true);
// return array_slice($modules_info, $perPage * ($pageNumber - 1), $perPage);
// }
//
// public function getModulesInfoWithFilters(string $url, int $perPage, int $pageNumber): \Psr\Http\Message\ResponseInterface
// {
// $modules_info = RESTClient::request($url);
// $modules_info = json_decode($modules_info->getBody()->getContents(), true);
// return array_slice($modules_info, $perPage * ($pageNumber - 1), $perPage);
// }
}
@@ -7,16 +7,17 @@
* @var \kernel\services\ModuleService $moduleService * @var \kernel\services\ModuleService $moduleService
* @var \kernel\services\KernelService $kernelService * @var \kernel\services\KernelService $kernelService
* @var \kernel\services\AdminThemeService $adminThemeService * @var \kernel\services\AdminThemeService $adminThemeService
* @var array $filterValues
*/ */
use Itguild\Tables\ListJsonTable; use Itguild\Tables\ListJsonTable;
use kernel\widgets\ActionButtonWidget; use kernel\widgets\ActionButtonWidget;
$meta = []; $meta = [];
$meta['columns'] = [ $meta['columns'] = [
"name" => "Название", "name" => "Название",
"author" => "Автор", "author" => "Автор",
"version" => "Версия", "version" => "Версия",
"type" => "Тип",
"description" => "Описание", "description" => "Описание",
"installations" => "Установки", "installations" => "Установки",
"views" => "Просмотры" "views" => "Просмотры"
@@ -38,8 +39,21 @@ $table->addAction(function ($row, $url) use ($moduleService) {
return \kernel\widgets\IconBtn\IconBtnViewWidget::create(['url' => $url])->run(); return \kernel\widgets\IconBtn\IconBtnViewWidget::create(['url' => $url])->run();
}); });
$table->addAction(function ($row, $url) use ($moduleService){ $table->columns([
if ($row['slug'] !== 'kernel') { 'type' => [
'filter' => [
'class' => \kernel\filters\BootstrapSelectFilterWithPrompt::class,
'param' => [
'kernel' => 'kernel',
'entity' => 'entity',
],
'value' => $filterValues['type'] ?? ''
],
]
]);
$table->addAction(function ($row, $url) use ($moduleService) {
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'];
@@ -50,16 +64,19 @@ $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) {
$slug = $row['slug']; if ($row['type'] === 'entity' || $row['type'] === 'additional_property') {
if ($moduleService->isInstall($slug)) { $slug = $row['slug'];
if (!$moduleService->isLastVersion($slug)) { if ($moduleService->isInstall($slug)) {
$url = "$url/update/?slug=" . $slug; if (!$moduleService->isLastVersion($slug)) {
$url = "$url/update/?slug=" . $slug;
return \kernel\widgets\IconBtn\IconBtnUpdateWidget::create(['url' => $url])->run(); return \kernel\widgets\IconBtn\IconBtnUpdateWidget::create(['url' => $url])->run();
}
} }
} }
@@ -67,8 +84,7 @@ $table->addAction(function ($row, $url) use ($moduleService) {
}); });
$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/";
@@ -80,9 +96,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/";
@@ -95,6 +110,10 @@ $table->addAction(function ($row, $url) use ($adminThemeService) {
return false; return false;
}); });
$table->afterPrint(function () {
return \kernel\IGTabel\btn\PrimaryBtn::create('Сбросить все фильтры', '/admin/module_shop_client')->fetch();
});
\kernel\widgets\ModuleTabsWidget::create()->run(); \kernel\widgets\ModuleTabsWidget::create()->run();
$table->create(); $table->create();
+41 -15
View File
@@ -15,13 +15,19 @@ use kernel\widgets\IconBtn\IconBtnDeleteWidget;
use kernel\widgets\IconBtn\IconBtnEditWidget; use kernel\widgets\IconBtn\IconBtnEditWidget;
use kernel\widgets\IconBtn\IconBtnViewWidget; use kernel\widgets\IconBtn\IconBtnViewWidget;
$get = (new \kernel\Request())->get();
$table = new ListEloquentTable(new EloquentDataProvider(Post::class, [ $table = new ListEloquentTable(new EloquentDataProvider(Post::class, [
'currentPage' => $page_number, 'currentPage' => $page_number,
'perPage' => 3, 'perPage' => 3,
'params' => ["class" => "table table-bordered", "border" => "2"], 'params' => ["class" => "table table-bordered", "border" => "2"],
'baseUrl' => "/admin/post" 'baseUrl' => "/admin/post",
'searchPrefix' => "",
'searchParams' => $get,
])); ]));
//\kernel\helpers\Debug::dd((new \kernel\Request())->get());
$view->setTitle("Список постов"); $view->setTitle("Список постов");
$view->setMeta([ $view->setMeta([
'description' => 'Список постов системы' 'description' => 'Список постов системы'
@@ -36,36 +42,56 @@ foreach ($additionals as $additional) {
}); });
} }
//\kernel\helpers\Debug::dd($request);
$table->columns([ $table->columns([
'created_at' => function ($data) { 'title' => [
if (!$data){ 'filter' => [
return null; 'class' => \kernel\filters\BootstrapTextFilter::class,
} 'value' => $get['title'] ?? ''
]
return (new DateTimeImmutable($data))->format("d-m-Y"); ],
}, 'content' => [
'filter' => [
'class' => \kernel\filters\BootstrapTextFilter::class,
'value' => $get['content'] ?? ''
]
],
'created_at' => [
'format' => 'date:d-m-Y',
],
'updated_at' => function ($data) { 'updated_at' => function ($data) {
if (!$data){ if (!$data) {
return null; return null;
} }
return (new DateTimeImmutable($data))->format("d-m-Y"); return (new DateTimeImmutable($data))->format("d-m-Y");
}, },
'user_id' => (function ($data) { 'user_id' => [
return User::find($data)->username; 'value' => function ($data) {
}) return User::find($data)->username;
},
'filter' => [
'class' => \kernel\filters\BootstrapSelectFilterWithPrompt::class,
'param' => \kernel\modules\user\service\UserService::createUsernameArr(),
'value' => $get['user_id'] ?? '',
'prompt' => 'dsds'
],
'prompt' => 'dsds'
]
]); ]);
$table->beforePrint(function () { $table->beforePrint(function () {
return IconBtnCreateWidget::create(['url' => '/admin/post/create'])->run(); return IconBtnCreateWidget::create(['url' => '/admin/post/create'])->run();
}); });
$table->addAction(function($row) { $table->addAction(function ($row) {
return IconBtnViewWidget::create(['url' => '/admin/post/view/' . $row['id']])->run(); return IconBtnViewWidget::create(['url' => '/admin/post/view/' . $row['id']])->run();
}); });
$table->addAction(function($row) { $table->addAction(function ($row) {
return IconBtnEditWidget::create(['url' => '/admin/post/update/' . $row['id']])->run(); return IconBtnEditWidget::create(['url' => '/admin/post/update/' . $row['id']])->run();
}); });
$table->addAction(function($row) { $table->addAction(function ($row) {
return IconBtnDeleteWidget::create(['url' => '/admin/post/delete/' . $row['id']])->run(); return IconBtnDeleteWidget::create(['url' => '/admin/post/delete/' . $row['id']])->run();
}); });
$table->create(); $table->create();
@@ -6,6 +6,8 @@ use Exception;
use JetBrains\PhpStorm\NoReturn; use JetBrains\PhpStorm\NoReturn;
use kernel\AdminController; use kernel\AdminController;
use kernel\EntityRelation; use kernel\EntityRelation;
use kernel\FileUpload;
use kernel\helpers\Debug;
use kernel\modules\user\models\forms\CreateUserForm; use kernel\modules\user\models\forms\CreateUserForm;
use kernel\modules\user\models\User; use kernel\modules\user\models\User;
use kernel\modules\user\service\UserService; use kernel\modules\user\service\UserService;
@@ -35,10 +37,17 @@ class UserController extends AdminController
{ {
$userForm = new CreateUserForm(); $userForm = new CreateUserForm();
$userForm->load($_REQUEST); $userForm->load($_REQUEST);
if (isset($_FILES['user_photo']) && $_FILES['user_photo']['error'] === UPLOAD_ERR_OK) {
$file = new FileUpload($_FILES['user_photo'], ['jpg', 'jpeg', 'png']);
$file->upload();
$userForm->setItem('user_photo', $file->getUploadFile());
}
if ($userForm->validate()){ if ($userForm->validate()){
$user = $this->userService->create($userForm); $user = $this->userService->create($userForm);
$entityRelation = new EntityRelation(); $entityRelation = new EntityRelation();
$entityRelation->saveEntityRelation(entity: "user", model: $user, request: new Request()); $entityRelation->saveEntityRelation(entity: "user", model: $user, request: new Request());
@@ -98,6 +107,13 @@ class UserController extends AdminController
$userForm = new CreateUserForm(); $userForm = new CreateUserForm();
$userService = new UserService(); $userService = new UserService();
$userForm->load($_REQUEST); $userForm->load($_REQUEST);
if (isset($_FILES['user_photo']) && $_FILES['user_photo']['error'] === UPLOAD_ERR_OK) {
$file = new FileUpload($_FILES['user_photo'], ['jpg', 'jpeg', 'png']);
$file->upload();
$userForm->setItem('user_photo', $file->getUploadFile());
}
if ($userForm->validateForUpdate()){ if ($userForm->validateForUpdate()){
$user = $userService->update($userForm, $user); $user = $userService->update($userForm, $user);
@@ -20,6 +20,7 @@ return new class extends Migration
$table->string('username', 255)->nullable(false); $table->string('username', 255)->nullable(false);
$table->string('email', 255); $table->string('email', 255);
$table->string('password_hash', 255); $table->string('password_hash', 255);
$table->string('user_photo', 255)->nullable();
$table->integer('role')->default(1); $table->integer('role')->default(1);
$table->string('access_token', 255)->nullable(true); $table->string('access_token', 255)->nullable(true);
$table->dateTime('access_token_expires_at')->nullable(true); $table->dateTime('access_token_expires_at')->nullable(true);
+3 -1
View File
@@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Model;
* @property string $username * @property string $username
* @property string $email * @property string $email
* @property string $password_hash * @property string $password_hash
* @property string $user_photo
* @property string $access_token * @property string $access_token
* @property string $access_token_expires_at * @property string $access_token_expires_at
* @method static find($id) * @method static find($id)
@@ -17,7 +18,7 @@ class User extends Model {
const ADMIN_USER_ROLE = 9; const ADMIN_USER_ROLE = 9;
protected $table = 'user'; protected $table = 'user';
protected $fillable = ['username', 'email', 'password_hash', 'role', 'access_token', 'access_token_expires_at']; protected $fillable = ['username', 'email', 'password_hash', 'user_photo', 'role', 'access_token', 'access_token_expires_at'];
protected array $dates = ['deleted at']; protected array $dates = ['deleted at'];
public static function labels(): array public static function labels(): array
@@ -25,6 +26,7 @@ class User extends Model {
return [ return [
'username' => 'Логин', 'username' => 'Логин',
'email' => 'Email', 'email' => 'Email',
'user_photo' => 'Фото профиля',
'created_at' => 'Создан', 'created_at' => 'Создан',
'updated_at' => 'Обновлен', 'updated_at' => 'Обновлен',
]; ];
@@ -12,7 +12,8 @@ class CreateUserForm extends FormModel
return [ return [
'username' => 'required|min-str-len:5|max-str-len:30', 'username' => 'required|min-str-len:5|max-str-len:30',
'password' => 'required|min-str-len:5|max-str-len:30', 'password' => 'required|min-str-len:5|max-str-len:30',
'email' => 'required|email' 'email' => 'required|email',
'user_photo' => ''
]; ];
} }
@@ -21,7 +22,9 @@ class CreateUserForm extends FormModel
return [ return [
'username' => 'required|min-str-len:5|max-str-len:30', 'username' => 'required|min-str-len:5|max-str-len:30',
'password' => '', 'password' => '',
'email' => 'required|email' 'email' => 'required|email',
'user_photo' => ''
]; ];
} }
@@ -15,6 +15,7 @@ class UserService
$model->username = $form_model->getItem('username'); $model->username = $form_model->getItem('username');
$model->email = $form_model->getItem('email'); $model->email = $form_model->getItem('email');
$model->password_hash = password_hash($form_model->getItem('password'), PASSWORD_DEFAULT); $model->password_hash = password_hash($form_model->getItem('password'), PASSWORD_DEFAULT);
$model->user_photo = $form_model->getItem('user_photo');
if ($model->save()){ if ($model->save()){
return $model; return $model;
} }
@@ -29,6 +30,7 @@ class UserService
if ($form_model->getItem('password')) { if ($form_model->getItem('password')) {
$user->password_hash = password_hash($form_model->getItem('password'), PASSWORD_DEFAULT); $user->password_hash = password_hash($form_model->getItem('password'), PASSWORD_DEFAULT);
} }
$user->user_photo = $form_model->getItem('user_photo');
if ($user->save()){ if ($user->save()){
return $user; return $user;
} }
@@ -80,6 +82,28 @@ class UserService
return ''; return '';
} }
public static function getAuthUserId(): string
{
$user = self::getAuthUser();
if ($user){
return $user->id;
}
return '';
}
public static function getAuthUserPhoto(): string|null
{
$user = self::getAuthUser();
if ($user){
if ($user->user_photo) {
return $user->user_photo;
}
}
return null;
}
public function getByAccessToken(string $token) public function getByAccessToken(string $token)
{ {
return $this->getByField("access_token", $token); return $this->getByField("access_token", $token);
+10
View File
@@ -32,6 +32,16 @@ $form->field(class: \itguild\forms\inputs\TextInput::class, name: "email", param
->setLabel("Email") ->setLabel("Email")
->render(); ->render();
if (!empty($model->user_photo)){
echo "<div><img src='$model->user_photo' width='200px'></div>";
}
$form->field(class: \itguild\forms\inputs\File::class, name: "user_photo", params: [
'class' => "form-control",
'value' => $model->user_photo ?? ''
])
->setLabel("Фото профиля")
->render();
$entityRelations = new \kernel\EntityRelation(); $entityRelations = new \kernel\EntityRelation();
if (!isset($model)) { if (!isset($model)) {
$model = new User(); $model = new User();
+9 -3
View File
@@ -17,13 +17,15 @@ use kernel\widgets\IconBtn\IconBtnDeleteWidget;
use kernel\widgets\IconBtn\IconBtnEditWidget; use kernel\widgets\IconBtn\IconBtnEditWidget;
use kernel\widgets\IconBtn\IconBtnViewWidget; use kernel\widgets\IconBtn\IconBtnViewWidget;
$get = (new \kernel\Request())->get();
$table = new ListEloquentTable(new EloquentDataProvider(User::class, [ $table = new ListEloquentTable(new EloquentDataProvider(User::class, [
'currentPage' => $page_number, 'currentPage' => $page_number,
'perPage' => 3, 'perPage' => 3,
'params' => ["class" => "table table-bordered", "border" => "2"], 'params' => ["class" => "table table-bordered", "border" => "2"],
'baseUrl' => "/admin/user", 'baseUrl' => "/admin/user",
'filters' => ['email'], 'searchPrefix' => "",
])); 'searchParams' => $get,]));
$entityRelation = new \kernel\EntityRelation(); $entityRelation = new \kernel\EntityRelation();
$additionals = $entityRelation->getEntityRelationsBySlug("user"); $additionals = $entityRelation->getEntityRelationsBySlug("user");
@@ -37,9 +39,13 @@ foreach ($additionals as $additional) {
$table->columns([ $table->columns([
'username' => [ 'username' => [
"filter" => [ "filter" => [
'class' => \Itguild\Tables\Filter\InputTextFilter::class 'class' => \kernel\filters\BootstrapTextFilter::class,
'value' => $get['username'] ?? null,
] ]
], ],
'user_photo' => function ($data) {
return $data ? "<img src='$data' width='150px'>" : "";
},
'created_at' => function ($data) { 'created_at' => function ($data) {
if (!$data){ if (!$data){
return null; return null;
+3
View File
@@ -35,6 +35,9 @@ foreach ($additionals as $key => $additional) {
} }
$table->rows([ $table->rows([
'user_photo' => function ($data) {
return $data ? "<img src='$data' width='300px'>" : "";
},
'created_at' => function ($data) { 'created_at' => function ($data) {
if (!$data){ if (!$data){
return null; return null;
+107 -4
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']);
}
}
} }
+20 -4
View File
@@ -308,7 +308,12 @@ class ModuleService
$manifest = Manifest::getWithVars($manifestJson); $manifest = Manifest::getWithVars($manifestJson);
$fileHelper = new Files(); $fileHelper = new Files();
$fileHelper->copy_folder($tmpModuleDirFull . 'app', $manifest['app_module_path']); if (isset($manifest['app_module_path'])) {
$fileHelper->copy_folder($tmpModuleDirFull . 'app', $manifest['app_module_path']);
} else {
$fileHelper->copy_folder($tmpModuleDirFull . 'app', APP_DIR . '/modules/' . $manifest['slug']);
}
if (isset($manifest['kernel_module_path'])) { if (isset($manifest['kernel_module_path'])) {
$fileHelper->copy_folder($tmpModuleDirFull . 'kernel', $manifest['kernel_module_path']); $fileHelper->copy_folder($tmpModuleDirFull . 'kernel', $manifest['kernel_module_path']);
} else { } else {
@@ -316,6 +321,7 @@ class ModuleService
} }
$fileHelper->recursiveRemoveDir($tmpModuleDirFull); $fileHelper->recursiveRemoveDir($tmpModuleDirFull);
unlink(ROOT_DIR . $path);
return true; return true;
} }
@@ -356,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');
} }
@@ -392,8 +402,12 @@ class ModuleService
$manifest = Manifest::getWithVars($manifestJson); $manifest = Manifest::getWithVars($manifestJson);
$fileHelper = new Files(); $fileHelper = new Files();
if (isset($manifest['app_module_path'])) {
$fileHelper->copy_folder($tmpModuleDirFull . 'app/manifest.json', $manifest['app_module_path'] . '/manifest.json');
} else {
$fileHelper->copy_folder($tmpModuleDirFull . 'app/manifest.json', APP_DIR . '/modules/' . $manifest['slug'] . '/manifest.json');
}
$fileHelper->copy_folder($tmpModuleDirFull . 'app/manifest.json', $manifest['app_module_path'] . '/manifest.json');
if (isset($manifest['kernel_module_path'])) { if (isset($manifest['kernel_module_path'])) {
$fileHelper->copy_folder($tmpModuleDirFull . 'kernel', $manifest['kernel_module_path']); $fileHelper->copy_folder($tmpModuleDirFull . 'kernel', $manifest['kernel_module_path']);
} else { } else {
@@ -401,6 +415,8 @@ class ModuleService
} }
$fileHelper->recursiveRemoveDir($tmpModuleDirFull); $fileHelper->recursiveRemoveDir($tmpModuleDirFull);
unlink(ROOT_DIR . $path);
return true; return true;
} }
+10
View File
@@ -51,6 +51,16 @@ $table = new \Itguild\Tables\ListJsonTable(json_encode(
] ]
)); ));
// Пример фильтра
$table->columns([
'title' => [
'filter' => [
'class' => \Itguild\Tables\Filter\InputTextFilter::class,
'value' => $get['title'] ?? ''
]
],
]
$table->beforePrint(function () { $table->beforePrint(function () {
return IconBtnCreateWidget::create(['url' => '/admin/{slug}/create'])->run(); return IconBtnCreateWidget::create(['url' => '/admin/{slug}/create'])->run();
}); });
Vendored Regular → Executable
View File
View File
View File
View File
View File
View File
Regular → Executable
View File
Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Vendored Regular → Executable
View File
Vendored Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
Vendored Regular → Executable
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File

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