From 95e80ab87b26eb9c440992e3e4b5cd4687cfaf9e Mon Sep 17 00:00:00 2001 From: Kavalar Date: Thu, 12 Sep 2024 16:01:04 +0300 Subject: [PATCH] module manager --- app/admin_themes/custom/manifest.json | 1 + kernel/AdminController.php | 2 +- kernel/Module.php | 9 ++++ kernel/admin_themes/default/manifest.json | 1 + kernel/admin_themes/simple/manifest.json | 1 + kernel/controllers/ModuleController.php | 50 ++++++++++++++++++ .../admin_themes/AdminThemesModule.php | 14 +++++ .../controllers/AdminThemeController.php | 8 ++- kernel/modules/admin_themes/manifest.json | 8 +++ kernel/modules/admin_themes/views/index.php | 2 +- kernel/modules/menu/MenuModule.php | 14 +++++ kernel/modules/menu/manifest.json | 8 +++ kernel/modules/post/PostModule.php | 14 +++++ kernel/modules/post/manifest.json | 8 +++ kernel/modules/user/UserModule.php | 15 ++++++ kernel/modules/user/manifest.json | 8 +++ kernel/routs/admin.php | 13 +++++ kernel/services/ModuleService.php | 39 ++++++++++++++ kernel/views/module/index.php | 41 ++++++++++++++ resources/tmp/themes/custom.zip | Bin 365076 -> 367538 bytes .../tmp/themes/custom/meta/manifest.json | 1 + 21 files changed, 254 insertions(+), 3 deletions(-) create mode 100644 kernel/Module.php create mode 100644 kernel/controllers/ModuleController.php create mode 100644 kernel/modules/admin_themes/AdminThemesModule.php create mode 100644 kernel/modules/admin_themes/manifest.json create mode 100644 kernel/modules/menu/MenuModule.php create mode 100644 kernel/modules/menu/manifest.json create mode 100644 kernel/modules/post/PostModule.php create mode 100644 kernel/modules/post/manifest.json create mode 100644 kernel/modules/user/UserModule.php create mode 100644 kernel/modules/user/manifest.json create mode 100644 kernel/services/ModuleService.php create mode 100644 kernel/views/module/index.php diff --git a/app/admin_themes/custom/manifest.json b/app/admin_themes/custom/manifest.json index 5fcce5d..ab256cb 100644 --- a/app/admin_themes/custom/manifest.json +++ b/app/admin_themes/custom/manifest.json @@ -1,6 +1,7 @@ { "name": "Custom", "version": "0.1", + "author": "Kavalar", "slug": "custom", "description": "Custom admin theme", "preview": "nrnv2024_640x360.jpg", diff --git a/kernel/AdminController.php b/kernel/AdminController.php index 712c5e7..33918e7 100644 --- a/kernel/AdminController.php +++ b/kernel/AdminController.php @@ -10,7 +10,7 @@ class AdminController extends Controller { protected AdminThemeService $adminThemeService; - protected function init() + protected function init(): void { $this->adminThemeService = new AdminThemeService(); $active_theme = $this->adminThemeService->getActiveAdminThemeInfo(); diff --git a/kernel/Module.php b/kernel/Module.php new file mode 100644 index 0000000..cd094e7 --- /dev/null +++ b/kernel/Module.php @@ -0,0 +1,9 @@ +cgView->viewPath = KERNEL_DIR . "/views/module/"; + + $this->moduleService = new ModuleService(); + } + + public function actionIndex(): void + { + $admin_theme_paths = Option::where("key", "module_paths")->first(); + $dirs = []; + if ($admin_theme_paths){ + $path = json_decode($admin_theme_paths->value); + foreach ($path->paths as $p){ + $dirs[] = getConst($p); + } + } + + $modules_info = []; + foreach ($dirs as $dir){ + $i = 1; + foreach (new DirectoryIterator($dir) as $fileInfo) { + $info = []; + if($fileInfo->isDot()) continue; + $info['id'] = $i; + $modules_info[] = array_merge($info, $this->moduleService->getModuleInfo($fileInfo->getPathname())); + $i++; + } + } + + $this->cgView->render("index.php", ['modules_info' => $modules_info, 'moduleService' => $this->moduleService]); + } + +} \ No newline at end of file diff --git a/kernel/modules/admin_themes/AdminThemesModule.php b/kernel/modules/admin_themes/AdminThemesModule.php new file mode 100644 index 0000000..f95f56e --- /dev/null +++ b/kernel/modules/admin_themes/AdminThemesModule.php @@ -0,0 +1,14 @@ + "Превью", "name" => "Название", "version" => "Версия", "description" => "Описание"]; + $meta['columns'] = [ + "preview" => "Превью", + "name" => "Название", + "author" => "Автор", + "version" => "Версия", + "description" => "Описание" + ]; $meta['params'] = ["class" => "table table-bordered"]; $meta['perPage'] = 10; $meta['baseUrl'] = "/admin/settings/admin-themes"; diff --git a/kernel/modules/admin_themes/manifest.json b/kernel/modules/admin_themes/manifest.json new file mode 100644 index 0000000..b792723 --- /dev/null +++ b/kernel/modules/admin_themes/manifest.json @@ -0,0 +1,8 @@ +{ + "name": "Admin themes", + "version": "0.1", + "author": "ITGuild", + "slug": "admin_themes", + "description": "Admin themes module", + "module_class": "AdminThemesModule" +} \ No newline at end of file diff --git a/kernel/modules/admin_themes/views/index.php b/kernel/modules/admin_themes/views/index.php index ab4dc4d..8ae87ff 100644 --- a/kernel/modules/admin_themes/views/index.php +++ b/kernel/modules/admin_themes/views/index.php @@ -15,7 +15,7 @@ $table->columns([ $table->addAction(function ($row, $url){ $path = $row['path']; $active_admin_theme = Option::where("key", "active_admin_theme")->first(); - $btn = "Активировать";; + $btn = "Активировать"; if ($path === $active_admin_theme->value){ $btn = "Активна"; } diff --git a/kernel/modules/menu/MenuModule.php b/kernel/modules/menu/MenuModule.php new file mode 100644 index 0000000..0f138e1 --- /dev/null +++ b/kernel/modules/menu/MenuModule.php @@ -0,0 +1,14 @@ +group(["prefix" => "admin"], function (RouteCollector $router){ + App::$collector->group(["prefix" => "module"], function (RouteCollector $router){ + App::$collector->get('/', [\kernel\controllers\ModuleController::class, 'actionIndex']); + }); App::$collector->group(["prefix" => "post"], function (RouteCollector $router){ App::$collector->get('/', [\kernel\modules\post\controllers\PostController::class, 'actionIndex']); App::$collector->get('/page/{page_number}', [\kernel\modules\post\controllers\PostController::class, 'actionIndex']); @@ -17,6 +20,16 @@ App::$collector->group(["prefix" => "admin"], function (RouteCollector $router){ App::$collector->any("/edit/{id}", [\kernel\modules\post\controllers\PostController::class, 'actionEdit']); App::$collector->get('/delete/{id}', [\kernel\modules\post\controllers\PostController::class, 'actionDelete']); }); + App::$collector->group(["prefix" => "user"], callback: function (RouteCollector $router){ + App::$collector->get('/', [\kernel\modules\user\controllers\UserController::class, 'actionIndex']); + App::$collector->get('/page/{page_number}', [\kernel\modules\user\controllers\UserController::class, 'actionIndex']); + App::$collector->get('/create', [\kernel\modules\user\controllers\UserController::class, 'actionCreate']); + App::$collector->post("/", [\kernel\modules\user\controllers\UserController::class, 'actionAdd']); + App::$collector->get('/{id}', [\kernel\modules\user\controllers\UserController::class, 'actionView']); + App::$collector->any('/update/{id}', [\kernel\modules\user\controllers\UserController::class, 'actionUpdate']); + App::$collector->any("/edit/{id}", [\kernel\modules\user\controllers\UserController::class, 'actionEdit']); + App::$collector->get('/delete/{id}', [\kernel\modules\user\controllers\UserController::class, 'actionDelete']); + }); App::$collector->group(["prefix" => "settings"], function (RouteCollector $router){ App::$collector->group(["prefix" => "menu"], function (RouteCollector $router){ App::$collector->get('/', [\kernel\modules\menu\controllers\MenuController::class, 'actionIndex']); diff --git a/kernel/services/ModuleService.php b/kernel/services/ModuleService.php new file mode 100644 index 0000000..1255c65 --- /dev/null +++ b/kernel/services/ModuleService.php @@ -0,0 +1,39 @@ +first(); + if ($active_modules){ + $path = json_decode($active_modules->value); + foreach ($path->modules as $p){ + if ($p === $slug){ + return true; + } + } + } + + return false; + } + +} \ No newline at end of file diff --git a/kernel/views/module/index.php b/kernel/views/module/index.php new file mode 100644 index 0000000..0239174 --- /dev/null +++ b/kernel/views/module/index.php @@ -0,0 +1,41 @@ + "Название", + "author" => "Автор", + "version" => "Версия", + "description" => "Описание" +]; +$meta['params'] = ["class" => "table table-bordered"]; +$meta['perPage'] = 10; +$meta['baseUrl'] = "/admin/module"; +$meta['currentPage'] = 1; +$meta['total'] = count($modules_info); + +$info_to_table['meta'] = $meta; +$info_to_table['data'] = $modules_info; + +$table = new \Itguild\Tables\ListJsonTable(json_encode($info_to_table, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); + +$table->addAction(function ($row, $url) use ($moduleService){ + $slug = $row['slug']; + if ($moduleService->isActive($slug)){ + $label = "Деактивировать"; + $btn_type = "warning"; + } + else { + $label = "Активировать"; + $btn_type = "primary"; + } + $btn = "$label"; + + return $btn; +}); + +$table->create(); +$table->render(); diff --git a/resources/tmp/themes/custom.zip b/resources/tmp/themes/custom.zip index da5f01403571d3b7499afd1931690792079b0ee4..c5e1281e35fde34a63df9db78bb7b00b4192d64d 100644 GIT binary patch delta 11161 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 delta 8634 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 OXMH)&Iu>0Da{mYTeGc*f diff --git a/resources/tmp/themes/custom/meta/manifest.json b/resources/tmp/themes/custom/meta/manifest.json index 5fcce5d..ab256cb 100644 --- a/resources/tmp/themes/custom/meta/manifest.json +++ b/resources/tmp/themes/custom/meta/manifest.json @@ -1,6 +1,7 @@ { "name": "Custom", "version": "0.1", + "author": "Kavalar", "slug": "custom", "description": "Custom admin theme", "preview": "nrnv2024_640x360.jpg",