From 39fdb8ec0d351da7992cb95c61c8c91c7108c7a5 Mon Sep 17 00:00:00 2001 From: Sami Mokaddem Date: Fri, 8 Oct 2021 10:27:40 +0200 Subject: [PATCH] new: [user-settings] Added user settings feature --- .../20211005163854_UserSettings.php | 63 +++++++++++++ src/Controller/Component/CRUDComponent.php | 2 + .../Component/Navigation/UserSettings.php | 50 ++++++++++ src/Controller/Component/Navigation/Users.php | 35 +++++++ .../Component/NavigationComponent.php | 2 + src/Controller/UserSettingsController.php | 93 +++++++++++++++++++ src/Controller/UsersController.php | 2 +- src/Model/Entity/UserSetting.php | 9 ++ src/Model/Table/UserSettingsTable.php | 29 ++++++ src/Model/Table/UsersTable.php | 7 ++ templates/UserSettings/add.php | 37 ++++++++ templates/UserSettings/index.php | 74 +++++++++++++++ templates/Users/index.php | 7 ++ templates/Users/view.php | 5 + .../Form/Fields/dropdownField.php | 3 + .../element/layouts/header/header-profile.php | 2 +- 16 files changed, 418 insertions(+), 2 deletions(-) create mode 100644 config/Migrations/20211005163854_UserSettings.php create mode 100644 src/Controller/Component/Navigation/UserSettings.php create mode 100644 src/Controller/Component/Navigation/Users.php create mode 100644 src/Controller/UserSettingsController.php create mode 100644 src/Model/Entity/UserSetting.php create mode 100644 src/Model/Table/UserSettingsTable.php create mode 100644 templates/UserSettings/add.php create mode 100644 templates/UserSettings/index.php diff --git a/config/Migrations/20211005163854_UserSettings.php b/config/Migrations/20211005163854_UserSettings.php new file mode 100644 index 0000000..2049680 --- /dev/null +++ b/config/Migrations/20211005163854_UserSettings.php @@ -0,0 +1,63 @@ +table('user_settings', [ + 'signed' => false, + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table + ->addColumn('id', 'integer', [ + 'autoIncrement' => true, + 'limit' => 10, + 'signed' => false, + ]) + ->addPrimaryKey('id') + ->addColumn('name', 'string', [ + 'default' => null, + 'null' => false, + 'limit' => 255, + 'comment' => 'The name of the user setting', + ]) + ->addColumn('value', 'text', [ + 'default' => null, + 'null' => true, + 'limit' => MysqlAdapter::TEXT_LONG, + 'comment' => 'The value of the user setting', + ]) + ->addColumn('user_id', 'integer', [ + 'default' => null, + 'null' => true, + 'signed' => false, + 'length' => 10, + ]) + ->addColumn('created', 'datetime', [ + 'default' => null, + 'null' => false, + ]) + ->addColumn('modified', 'datetime', [ + 'default' => null, + 'null' => false, + ]); + + $table->addForeignKey('user_id', 'users', 'id', ['delete'=> 'CASCADE', 'update'=> 'CASCADE']); + + $table->addIndex('name') + ->addIndex('user_id') + ->addIndex('created') + ->addIndex('modified'); + + $table->create(); + } +} diff --git a/src/Controller/Component/CRUDComponent.php b/src/Controller/Component/CRUDComponent.php index 827ac1c..585eeba 100644 --- a/src/Controller/Component/CRUDComponent.php +++ b/src/Controller/Component/CRUDComponent.php @@ -196,6 +196,7 @@ class CRUDComponent extends Component } } } + $this->Controller->entity = $data; $this->Controller->set('entity', $data); } @@ -317,6 +318,7 @@ class CRUDComponent extends Component } } } + $this->Controller->entity = $data; $this->Controller->set('entity', $data); } diff --git a/src/Controller/Component/Navigation/UserSettings.php b/src/Controller/Component/Navigation/UserSettings.php new file mode 100644 index 0000000..84efa25 --- /dev/null +++ b/src/Controller/Component/Navigation/UserSettings.php @@ -0,0 +1,50 @@ +bcf; + $request = $this->request; + $this->bcf->addLink('UserSettings', 'index', 'Users', 'view', function ($config) use ($bcf, $request) { + if (!empty($request->getQuery('Users_id'))) { + $user_id = h($request->getQuery('Users_id')); + $linkData = [ + 'label' => __('View user ({0})', h($user_id)), + 'url' => sprintf('/users/view/%s', h($user_id)) + ]; + return $linkData; + } + return null; + }); + $this->bcf->addLink('UserSettings', 'index', 'Users', 'edit', function ($config) use ($bcf, $request) { + if (!empty($request->getQuery('Users_id'))) { + $user_id = h($request->getQuery('Users_id')); + $linkData = [ + 'label' => __('Edit user ({0})', h($user_id)), + 'url' => sprintf('/users/edit/%s', h($user_id)) + ]; + return $linkData; + } + return null; + }); + if (!empty($request->getQuery('Users_id'))) { + $this->bcf->addSelfLink('UserSettings', 'index'); + } + if ($this->request->getParam('controller') == 'UserSettings' && $this->request->getParam('action') == 'index') { + if (!empty($this->request->getQuery('Users_id'))) { + $user_id = $this->request->getQuery('Users_id'); + $this->bcf->addParent('UserSettings', 'index', 'Users', 'view', [ + 'textGetter' => [ + 'path' => 'username', + 'varname' => 'settingsForUser', + ], + 'url' => "/users/view/{$user_id}" + ]); + } + } + } +} diff --git a/src/Controller/Component/Navigation/Users.php b/src/Controller/Component/Navigation/Users.php new file mode 100644 index 0000000..ea76f15 --- /dev/null +++ b/src/Controller/Component/Navigation/Users.php @@ -0,0 +1,35 @@ +bcf; + $request = $this->request; + $this->bcf->addLink('Users', 'view', 'UserSettings', 'index', function ($config) use ($bcf, $request) { + if (!empty($this->passedData[0])) { + $user_id = $this->passedData[0]; + $linkData = [ + 'label' => __('User Setting ({0})', h($user_id)), + 'url' => sprintf('/user-settings/index?Users.id=%s', h($user_id)) + ]; + return $linkData; + } + return []; + }); + $this->bcf->addLink('Users', 'edit', 'UserSettings', 'index', function ($config) use ($bcf, $request) { + if (!empty($this->passedData[0])) { + $user_id = $this->passedData[0]; + $linkData = [ + 'label' => __('User Setting ({0})', h($user_id)), + 'url' => sprintf('/user-settings/index?Users.id=%s', h($user_id)) + ]; + return $linkData; + } + return []; + }); + } +} diff --git a/src/Controller/Component/NavigationComponent.php b/src/Controller/Component/NavigationComponent.php index 3fcde32..b18a34b 100644 --- a/src/Controller/Component/NavigationComponent.php +++ b/src/Controller/Component/NavigationComponent.php @@ -27,6 +27,7 @@ class NavigationComponent extends Component 'Broods' => 'network-wired', 'Roles' => 'id-badge', 'Users' => 'users', + 'UserSettings' => 'user-cog', 'Inbox' => 'inbox', 'Outbox' => 'inbox', 'MetaTemplates' => 'object-group', @@ -128,6 +129,7 @@ class NavigationComponent extends Component 'Users', 'Tags', 'LocalTools', + 'UserSettings', ]; foreach ($CRUDControllers as $controller) { $bcf->setDefaultCRUDForModel($controller); diff --git a/src/Controller/UserSettingsController.php b/src/Controller/UserSettingsController.php new file mode 100644 index 0000000..3853633 --- /dev/null +++ b/src/Controller/UserSettingsController.php @@ -0,0 +1,93 @@ + true], ['value' => true]]; + public $filterFields = ['name', 'value', 'Users.id']; + public $containFields = ['Users']; + + public function index() + { + $conditions = []; + $this->CRUD->index([ + 'conditions' => [], + 'contain' => $this->containFields, + 'filters' => $this->filterFields, + 'quickFilters' => $this->quickFilterFields, + ]); + $responsePayload = $this->CRUD->getResponsePayload(); + if (!empty($responsePayload)) { + return $responsePayload; + } + if (!empty($this->request->getQuery('Users_id'))) { + $settingsForUser = $this->UserSettings->Users->find()->where([ + 'id' => $this->request->getQuery('Users_id') + ])->first(); + $this->set('settingsForUser', $settingsForUser); + } + } + + public function add($user_id = false) + { + $this->CRUD->add([ + 'redirect' => ['action' => 'index', $user_id], + 'beforeSave' => function($data) use ($user_id) { + $data['user_id'] = $user_id; + return $data; + } + ]); + $responsePayload = $this->CRUD->getResponsePayload(); + if (!empty($responsePayload)) { + return $responsePayload; + } + $dropdownData = [ + 'user' => $this->UserSettings->Users->find('list', [ + 'sort' => ['username' => 'asc'] + ]), + ]; + $this->set(compact('dropdownData')); + $this->set('user_id', $user_id); + } + + public function edit($id) + { + $entity = $this->UserSettings->find()->where([ + 'id' => $id + ])->first(); + $entity = $this->CRUD->edit($id, [ + 'redirect' => ['action' => 'index', $entity->user_id] + ]); + $responsePayload = $this->CRUD->getResponsePayload(); + if (!empty($responsePayload)) { + return $responsePayload; + } + $dropdownData = [ + 'user' => $this->UserSettings->Users->find('list', [ + 'sort' => ['username' => 'asc'] + ]), + ]; + $this->set(compact('dropdownData')); + $this->set('user_id', $this->entity->user_id); + $this->render('add'); + } + + public function delete($id) + { + $this->CRUD->delete($id); + $responsePayload = $this->CRUD->getResponsePayload(); + if (!empty($responsePayload)) { + return $responsePayload; + } + } + +} \ No newline at end of file diff --git a/src/Controller/UsersController.php b/src/Controller/UsersController.php index f3059b2..4b13df6 100644 --- a/src/Controller/UsersController.php +++ b/src/Controller/UsersController.php @@ -11,7 +11,7 @@ class UsersController extends AppController { public $filterFields = ['Individuals.uuid', 'username', 'Individuals.email', 'Individuals.first_name', 'Individuals.last_name']; public $quickFilterFields = ['Individuals.uuid', ['username' => true], ['Individuals.first_name' => true], ['Individuals.last_name' => true], 'Individuals.email']; - public $containFields = ['Individuals', 'Roles']; + public $containFields = ['Individuals', 'Roles', 'UserSettings']; public function index() { diff --git a/src/Model/Entity/UserSetting.php b/src/Model/Entity/UserSetting.php new file mode 100644 index 0000000..e5d12f3 --- /dev/null +++ b/src/Model/Entity/UserSetting.php @@ -0,0 +1,9 @@ +addBehavior('Timestamp'); + $this->belongsTo( + 'Users' + ); + $this->setDisplayField('name'); + } + + public function validationDefault(Validator $validator): Validator + { + $validator + ->requirePresence(['name', 'user_id'], 'create') + ->notEmptyString('name', __('Please fill this field')) + ->notEmptyString('user_id', __('Please supply the user id to which this setting belongs to')); + return $validator; + } +} diff --git a/src/Model/Table/UsersTable.php b/src/Model/Table/UsersTable.php index 585295d..f3c7097 100644 --- a/src/Model/Table/UsersTable.php +++ b/src/Model/Table/UsersTable.php @@ -34,6 +34,13 @@ class UsersTable extends AppTable 'cascadeCallbacks' => false ] ); + $this->hasMany( + 'UserSettings', + [ + 'dependent' => true, + 'cascadeCallbacks' => true + ] + ); $this->setDisplayField('username'); } diff --git a/templates/UserSettings/add.php b/templates/UserSettings/add.php new file mode 100644 index 0000000..38a14c8 --- /dev/null +++ b/templates/UserSettings/add.php @@ -0,0 +1,37 @@ +element('genericElements/Form/genericForm', [ + 'data' => [ + 'description' => __('User settings are used to register setting tied to user profile.'), + 'model' => 'UserSettings', + 'fields' => [ + [ + 'field' => 'user_id', + 'type' => 'dropdown', + 'label' => __('User'), + 'options' => $dropdownData['user'], + 'value' => !empty($user_id) ? $user_id : '', + 'disabled' => !empty($user_id), + ], + [ + 'field' => 'name', + 'label' => __('Setting Name'), + ], + [ + 'field' => 'value', + 'label' => __('Setting Value'), + 'type' => 'codemirror', + 'codemirror' => [ + 'height' => '10rem', + 'mode' => [ + 'name' => 'text', + ], + ] + ], + ], + 'submit' => [ + 'action' => $this->request->getParam('action') + ] + ] + ]); +?> + diff --git a/templates/UserSettings/index.php b/templates/UserSettings/index.php new file mode 100644 index 0000000..5740047 --- /dev/null +++ b/templates/UserSettings/index.php @@ -0,0 +1,74 @@ +username); +} + +echo $this->element('genericElements/IndexTable/index_table', [ + 'data' => [ + 'data' => $data, + 'top_bar' => [ + 'children' => [ + [ + 'type' => 'simple', + 'children' => [ + 'data' => [ + 'type' => 'simple', + 'text' => __('Add Setting'), + 'class' => 'btn btn-primary', + 'popover_url' => sprintf('/userSettings/add/%s', h($this->request->getQuery('Users_id'))) + ] + ] + ], + [ + 'type' => 'search', + 'button' => __('Filter'), + 'placeholder' => __('Enter value to search'), + 'data' => '', + 'searchKey' => 'value' + ] + ] + ], + 'fields' => [ + [ + 'name' => '#', + 'sort' => 'id', + 'data_path' => 'id', + ], + [ + 'name' => __('User'), + 'sort' => 'user.username', + 'data_path' => 'user.username', + 'url' => '/users/view/{{0}}', + 'url_vars' => ['user.id'] + ], + [ + 'name' => __('Setting Name'), + 'sort' => 'name', + 'data_path' => 'name', + ], + [ + 'name' => __('Setting Value'), + 'sort' => 'value', + 'data_path' => 'value', + 'class' => 'font-monospace' + ], + ], + 'title' => $title, + 'description' => __('The list of user settings in this Cerebrate instance. All users can have setting tied to their user profile.'), + 'actions' => [ + [ + 'open_modal' => '/userSettings/edit/[onclick_params_data_path]', + 'modal_params_data_path' => 'id', + 'icon' => 'edit' + ], + [ + 'open_modal' => '/userSettings/delete/[onclick_params_data_path]', + 'modal_params_data_path' => 'id', + 'icon' => 'trash' + ], + ] + ] +]); +echo ''; +?> diff --git a/templates/Users/index.php b/templates/Users/index.php index 9da12ba..64561a1 100644 --- a/templates/Users/index.php +++ b/templates/Users/index.php @@ -75,6 +75,13 @@ echo $this->element('genericElements/IndexTable/index_table', [ 'url' => '/roles/view/{{0}}', 'url_vars' => ['role.id'] ], + [ + 'name' => __('# User Settings'), + 'element' => 'count_summary', + 'data_path' => 'user_settings', + 'url' => '/user-settings/index?Users.id={{url_data}}', + 'url_data_path' => 'id' + ], ], 'title' => __('User index'), 'description' => __('The list of enrolled users in this Cerebrate instance. All of the users have or at one point had access to the system.'), diff --git a/templates/Users/view.php b/templates/Users/view.php index d26bffb..760ead4 100644 --- a/templates/Users/view.php +++ b/templates/Users/view.php @@ -51,6 +51,11 @@ echo $this->element( 'url' => '/EncryptionKeys/index?Users.id={{0}}', 'url_params' => ['id'], 'title' => __('Encryption keys') + ], + [ + 'url' => '/UserSettings/index?Users.id={{0}}', + 'url_params' => ['id'], + 'title' => __('User settings') ] ] ] diff --git a/templates/element/genericElements/Form/Fields/dropdownField.php b/templates/element/genericElements/Form/Fields/dropdownField.php index b5c64b6..46b4c81 100644 --- a/templates/element/genericElements/Form/Fields/dropdownField.php +++ b/templates/element/genericElements/Form/Fields/dropdownField.php @@ -2,6 +2,9 @@ $controlParams = [ 'options' => $fieldData['options'], 'empty' => $fieldData['empty'] ?? false, + 'value' => $fieldData['value'] ?? [], + 'multiple' => $fieldData['multiple'] ?? false, + 'disabled' => $fieldData['disabled'] ?? false, 'class' => ($fieldData['class'] ?? '') . ' formDropdown form-select' ]; echo $this->FormFieldMassage->prepareFormElement($this->Form, $controlParams, $fieldData); diff --git a/templates/element/layouts/header/header-profile.php b/templates/element/layouts/header/header-profile.php index 4cfd43b..27c5b8d 100644 --- a/templates/element/layouts/header/header-profile.php +++ b/templates/element/layouts/header/header-profile.php @@ -19,7 +19,7 @@ use Cake\Routing\Router; - +