From 77aba91c86f633f3c9bac7a070a2edf9b0992ff2 Mon Sep 17 00:00:00 2001 From: Rhilip Date: Wed, 17 Jul 2019 16:08:43 +0800 Subject: [PATCH] feat(Category): Add Categories Manage Pane --- CHANGELOG.md | 10 +- apps/controllers/ManageController.php | 63 ++++++++ .../form/Manage/Categories/EditForm.php | 112 ++++++++++++++ .../form/Manage/Categories/RemoveForm.php | 65 ++++++++ apps/public/static/css/main.css | 4 + apps/public/static/js/manage_categories.js | 30 ++++ apps/views/manage/categories.php | 144 ++++++++++++++++++ migration/ridpt.sql | 29 +++- 8 files changed, 451 insertions(+), 6 deletions(-) create mode 100644 apps/controllers/ManageController.php create mode 100644 apps/models/form/Manage/Categories/EditForm.php create mode 100644 apps/models/form/Manage/Categories/RemoveForm.php create mode 100644 apps/public/static/js/manage_categories.js create mode 100644 apps/views/manage/categories.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d777e0..5f72beb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,20 +13,22 @@ - **Database:** Fix table `links` miss - **Form:** Miss use flag since namespace change - **Form:** Link\EditForm Update diff +- **Requests:** Fix fullUrl() may add unnecessary `?` ### Perf - **Tracker:** Use brpoplpush to get announce data from redis ### Refactor - **View:** Rename folder `error` to `action` +- **action_success:** Simple The Action Template ### Style - **Auth:** Sort Auth Form - **printIn:** Add datetime tag - -## [0.1.4-alpha] - 2019-06-28 + +## [v0.1.4-alpha] - 2019-06-28 ### Chore - **User:** Make User component as Part of App but not framework @@ -260,8 +262,8 @@ Structure of Table `users_session_log` Change ## v0.1.0-alpha - 2019-01-30 -[Unreleased]: https://github.com/Rhilip/ridpt/compare/0.1.4-alpha...HEAD -[0.1.4-alpha]: https://github.com/Rhilip/ridpt/compare/v0.1.3-alpha...0.1.4-alpha +[Unreleased]: https://github.com/Rhilip/ridpt/compare/v0.1.4-alpha...HEAD +[v0.1.4-alpha]: https://github.com/Rhilip/ridpt/compare/v0.1.3-alpha...v0.1.4-alpha [v0.1.3-alpha]: https://github.com/Rhilip/ridpt/compare/v0.1.2-alpha...v0.1.3-alpha [v0.1.2-alpha]: https://github.com/Rhilip/ridpt/compare/v0.1.1-alpha...v0.1.2-alpha [v0.1.1-alpha]: https://github.com/Rhilip/ridpt/compare/v0.1.0-alpha...v0.1.1-alpha diff --git a/apps/controllers/ManageController.php b/apps/controllers/ManageController.php new file mode 100644 index 0000000..c0f146a --- /dev/null +++ b/apps/controllers/ManageController.php @@ -0,0 +1,63 @@ +request->isPost()) { + if (app()->request->post('action') == 'cat_edit') { + $edit_form = new Categories\EditForm(); + $edit_form->setData(app()->request->post()); + $success = $edit_form->validate(); + if ($success) { + $edit_form->flush(); + return $this->render('action/action_success'); + } else { + return $this->render('action/action_fail', ['msg' => $edit_form->getError()]); + } + } elseif (app()->request->post('action') == 'cat_delete') { + $delete_form = new Categories\RemoveForm(); + $delete_form->setData(app()->request->post()); + $success = $delete_form->validate(); + if ($success) { + $delete_form->flush(); + return $this->render('action/action_success'); + } else { + return $this->render('action/action_fail', ['msg' => $delete_form->getError()]); + } + } + } + + $parent_id = app()->request->get('parent_id', 0); + $parent_category = []; + if ($parent_id !== 0) { + $parent_category = app()->pdo->createCommand('SELECT * FROM `torrents_categories` WHERE `id` = :id')->bindParams([ + 'id' => $parent_id + ])->queryOne(); + } + + $categories = app()->pdo->createCommand('SELECT * FROM `torrents_categories` WHERE `parent_id` = :pid ORDER BY `sort_index`,`id`')->bindParams([ + 'pid' => $parent_id + ])->queryAll(); + + foreach ($categories as &$category) { + $child_count = app()->pdo->createCommand('SELECT COUNT(`id`) FROM `torrents_categories` WHERE `parent_id` = :pid')->bindParams([ + 'pid' => $category['id'] + ])->queryScalar(); + $category['child_count'] = $child_count; + } + + return $this->render('manage/categories', ['parent_id' => $parent_id, 'parent_category' => $parent_category, 'categories' => $categories]); + } +} diff --git a/apps/models/form/Manage/Categories/EditForm.php b/apps/models/form/Manage/Categories/EditForm.php new file mode 100644 index 0000000..04cbdcc --- /dev/null +++ b/apps/models/form/Manage/Categories/EditForm.php @@ -0,0 +1,112 @@ + 'Required | Integer', + 'cat_parent_id' => 'Required | Integer', + 'cat_name' => 'Required | AlphaNumHyphen', + 'cat_enabled' => 'Integer', + 'cat_sort_index' => 'Integer', + 'cat_image' => [ + ['Regex', ['pattern' => '/^[a-z0-9_.\/]*$/']] + ], + 'cat_class_name' => [ + ['Regex', ['pattern' => '/^[a-z][a-z0-9_\-]*?$/']] + ], + ]; + } + + public static function callbackRules() + { + return ['checkCategoryData']; + } + + protected function checkCategoryData() + { + $this->cat_new_data = [ + 'parent_id' => (int)$this->cat_parent_id, + 'name' => $this->cat_name, 'enabled' => $this->cat_enabled, + 'sort_index' => (int)$this->cat_sort_index, + 'image' => $this->cat_image, 'class_name' => $this->cat_class_name + ]; + + // Generate New Full Path Key + $parent_cat_fpath = app()->pdo->createCommand('SELECT `full_path` FROM `torrents_categories` WHERE `id` = :pid')->bindParams([ + 'pid' => $this->cat_parent_id + ])->queryScalar(); + if ($parent_cat_fpath === false) { + $full_path = $this->cat_name; + } else { + $full_path = $parent_cat_fpath . ' - ' . $this->cat_name; + } + $this->cat_new_data['full_path'] = $full_path; + $flag_check_full_path = true; + + if ((int)$this->cat_id !== 0) { // Check if old links should be update + $this->cat_old_data = app()->pdo->createCommand('SELECT * FROM `torrents_categories` WHERE id = :id')->bindParams([ + 'id' => $this->cat_id + ])->queryOne(); + if ($this->cat_old_data === false) { + $this->buildCallbackFailMsg('Category:exist', 'the link data not found in our database'); + return; + } + $this->cat_new_data['id'] = (int)$this->cat_id; + + // Diff old and new data. + $this->cat_data_diff = array_diff_assoc($this->cat_new_data, $this->cat_old_data); + if (count($this->cat_data_diff) === 0) { + $this->buildCallbackFailMsg('Category:update', 'No data update'); + return; + } + if (!isset($this->cat_data_diff['full_path'])) $flag_check_full_path = false; // It means full path key not update, We shouldn't check anymore. + } + + if ($flag_check_full_path) { // Check if full path key is duplicate or not. + $check_full_path = app()->pdo->createCommand('SELECT COUNT(`id`) FROM `torrents_categories` WHERE `full_path` = :fpath')->bindParams([ + 'fpath' => $full_path + ])->queryScalar(); + if ($check_full_path > 0) { + $this->buildCallbackFailMsg('Category:duplicate', 'This Path is already exist.'); + return; + } + } + } + + public function flush() + { + if ((int)$this->cat_id !== 0) { // to edit exist cat + app()->pdo->update('torrents_categories', $this->cat_data_diff, [['id', '=', $this->cat_id]])->execute(); + // TODO Add site log + } else { // to new a cat + app()->pdo->insert('torrents_categories', $this->cat_new_data)->execute(); + // TODO Add site log + } + // TODO flush Redis Cache + } +} diff --git a/apps/models/form/Manage/Categories/RemoveForm.php b/apps/models/form/Manage/Categories/RemoveForm.php new file mode 100644 index 0000000..91307d5 --- /dev/null +++ b/apps/models/form/Manage/Categories/RemoveForm.php @@ -0,0 +1,65 @@ + 'Required | Integer', + ]; + } + + public static function callbackRules() + { + return ['getExistCategoryData', 'checkChildNode']; + } + + protected function getExistCategoryData() + { + $this->category_data = app()->pdo->createCommand('SELECT * FROM `torrents_categories` WHERE id = :id')->bindParams([ + 'id' => $this->cat_id + ])->queryScalar(); + if ($this->category_data === false) { + $this->buildCallbackFailMsg('Categories:exist', 'This category isn\'t exist in our site.'); + } + } + + protected function checkChildNode() + { + $child_chount = app()->pdo->createCommand('SELECT COUNT(`id`) FROM `torrents_categories` WHERE `parent_id` = :pid')->bindParams([ + 'pid' => $this->cat_id + ])->queryScalar(); + if ($child_chount !== 0) { + $this->buildCallbackFailMsg('Categories;child', 'This category has sub category exist, Please clean subcategory first.'); + } + } + + public function flush() + { + // FIXME Move Category's torrent from this to it's parent + app()->pdo->createCommand('UPDATE `torrents` SET `category` = :new WHERE `category` = :old ')->bindParams([ + 'new' => $this->category_data['parent_id'], 'old' => $this->category_data['id'] + ])->execute(); + + // Delete it~ + app()->pdo->createCommand('DELETE FROM `torrents_categories` WHERE id = :id')->bindParams([ + 'id' => $this->cat_id + ])->execute(); + // TODO flush Redis cache + } +} diff --git a/apps/public/static/css/main.css b/apps/public/static/css/main.css index d5adbde..00b5068 100644 --- a/apps/public/static/css/main.css +++ b/apps/public/static/css/main.css @@ -71,6 +71,9 @@ body{background-color:#f6f6f6} #footer_menu a{color:#C3C0B9} #footer_menu a:hover{color:#E84807} +.modal-content form{padding:0 10px} +.switch>label{font-weight:700} + /*-----------------------------------------------------------------------------------*/ /* 3. Page of '/auth' /*-----------------------------------------------------------------------------------*/ @@ -114,3 +117,4 @@ body{background-color:#f6f6f6} #torrent_structure li div.dictionary span.icon{color:#909;padding:2px} #torrent_structure li div.list span.icon{color:#009;padding:2px} #torrent_structure li span.title{font-weight:bold} + diff --git a/apps/public/static/js/manage_categories.js b/apps/public/static/js/manage_categories.js new file mode 100644 index 0000000..f1cc4b6 --- /dev/null +++ b/apps/public/static/js/manage_categories.js @@ -0,0 +1,30 @@ +jQuery(document).ready(function () { + let edit_form = $('#cat_edit_form'); + let remove_form = $('#cat_remove_form'); + + $('.cat-edit').click(function () { + let that = $(this); + + $('#cat_modal').modal(); + + // Get category data from and Fill data to form + let tr = $('#cat_manager_table tr[data-id=' + that.data('id') + ']'); + for (let datum in tr.data()) { + let input = edit_form.find('[name="cat_' + datum + '"]'); + if (datum === 'enabled') { + input.prop('checked',tr.data(datum) ? 'checked' : ''); + } else { + input.val(tr.data(datum)); + } + } + }); + + $('.cat-remove').click(function () { + let that = $(this); + if (confirm('Confirm to remove this Category ?')) { + remove_form.find('input[name=cat_id]').val(that.data('id')); + remove_form.submit(); + } + }); + +}); diff --git a/apps/views/manage/categories.php b/apps/views/manage/categories.php new file mode 100644 index 0000000..7e9e5ff --- /dev/null +++ b/apps/views/manage/categories.php @@ -0,0 +1,144 @@ + + +layout('layout/base') ?> + +start('title') ?>Manage Categoriesend(); ?> + +start('container') ?> +
+
+

+ + Manage Category + + Manage Sub Category of + +

+
+
+
+ +
+ + + + + + + + + + + + + + + 0): ?> + + + + + + + + + + + + + + + + + + +
IdSort IndexNameImageClass NameSub CategoryEnabledAction
+ 0 ? "${category['child_count']} SubCategories" : 'No SubCategory' ?> + Edit | + Remove +
No Category Exist.
+
+
+end(); ?> + +start('body');?> + + + +end(); ?> + +start('script'); ?> + +end(); ?> diff --git a/migration/ridpt.sql b/migration/ridpt.sql index 2103df1..9f0e325 100644 --- a/migration/ridpt.sql +++ b/migration/ridpt.sql @@ -3,7 +3,7 @@ -- https://www.phpmyadmin.net/ -- -- Host: 127.0.0.1 --- Generation Time: Jun 15, 2019 at 07:53 PM +-- Generation Time: Jul 17, 2019 at 04:04 PM -- Server version: 8.0.16 -- PHP Version: 7.3.6 @@ -635,14 +635,39 @@ CREATE TABLE IF NOT EXISTS `torrents_buff` ( DROP TABLE IF EXISTS `torrents_categories`; CREATE TABLE IF NOT EXISTS `torrents_categories` ( `id` mediumint(5) UNSIGNED NOT NULL AUTO_INCREMENT, + `parent_id` mediumint(5) NOT NULL DEFAULT '0', `name` varchar(30) NOT NULL, - PRIMARY KEY (`id`) + `enabled` tinyint(1) NOT NULL DEFAULT '1', + `sort_index` smallint(5) NOT NULL DEFAULT '0', + `image` varchar(255) NOT NULL DEFAULT '', + `class_name` varchar(255) NOT NULL DEFAULT '', + `full_path` varchar(255) NOT NULL DEFAULT '', + PRIMARY KEY (`id`), + UNIQUE KEY `full_path` (`full_path`), + KEY `IN_torrentcategories_enabled_sort_index_id` (`enabled`,`sort_index`,`id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; -- -- RELATIONSHIPS FOR TABLE `torrents_categories`: -- +-- +-- Truncate table before insert `torrents_categories` +-- + +TRUNCATE TABLE `torrents_categories`; +-- +-- Dumping data for table `torrents_categories` +-- + +INSERT INTO `torrents_categories` (`id`, `parent_id`, `name`, `enabled`, `sort_index`, `image`, `class_name`, `full_path`) VALUES +(1, 0, 'Movies', 1, 0, '', '', 'Movies'), +(2, 0, 'TV', 1, 0, '', '', 'TV'), +(3, 0, 'Documentary', 1, 0, '', '', 'Documentary'), +(4, 0, 'Animation', 1, 0, '', '', 'Animation'), +(5, 0, 'Sports', 1, 0, '', '', 'Sports'), +(6, 0, 'Music', 1, 0, '', '', 'Music'); + -- -------------------------------------------------------- --