diff --git a/.gitignore b/.gitignore index cdb86ef..f84928d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ composer.lock config/app_local.php +config/Migrations/schema-dump-default.lock logs tmp vendor +webroot/theme/node_modules +.vscode docker/run/ diff --git a/composer.json b/composer.json index 42a49b2..bc562a0 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ "admad/cakephp-social-auth": "^1.1", "cakephp/authentication": "^2.0", "cakephp/authorization": "^2.0", - "cakephp/cakephp": "^4.0", + "cakephp/cakephp": "^4.3", "cakephp/migrations": "^3.0", "cakephp/plugin-installer": "^1.2", "erusev/parsedown": "^1.7", diff --git a/config/Migrations/20211123152707_user_org.php b/config/Migrations/20211123152707_user_org.php new file mode 100644 index 0000000..f615c98 --- /dev/null +++ b/config/Migrations/20211123152707_user_org.php @@ -0,0 +1,43 @@ +hasTable('users'); + if (!$exists) { + $alignments = $this->table('users') + ->addColumn('organisation_id', 'integer', [ + 'default' => null, + 'null' => true, + 'signed' => false, + 'length' => 10 + ]) + ->addIndex('org_id') + ->update(); + } + $q1 = $this->getQueryBuilder(); + $org_id = $q1->select(['min(id)'])->from('organisations')->execute()->fetchAll()[0][0]; + if (!empty($org_id)) { + $q2 = $this->getQueryBuilder(); + $q2->update('users') + ->set('organisation_id', $org_id) + ->where(['organisation_id IS NULL']) + ->execute(); + } + } +} diff --git a/src/Controller/AppController.php b/src/Controller/AppController.php index 9b44ec4..cdd85e2 100644 --- a/src/Controller/AppController.php +++ b/src/Controller/AppController.php @@ -102,7 +102,7 @@ class AppController extends Controller $this->ACL->setPublicInterfaces(); if (!empty($this->request->getAttribute('identity'))) { $user = $this->Users->get($this->request->getAttribute('identity')->getIdentifier(), [ - 'contain' => ['Roles', 'Individuals' => 'Organisations', 'UserSettings'] + 'contain' => ['Roles', 'Individuals' => 'Organisations', 'UserSettings', 'Organisations'] ]); if (!empty($user['disabled'])) { $this->Authentication->logout(); @@ -113,8 +113,10 @@ class AppController extends Controller $this->ACL->setUser($user); $this->request->getSession()->write('authUser', $user); $this->isAdmin = $user['role']['perm_admin']; - $this->set('menu', $this->ACL->getMenu()); - $this->set('loggedUser', $this->ACL->getUser()); + if (!$this->ParamHandler->isRest()) { + $this->set('menu', $this->ACL->getMenu()); + $this->set('loggedUser', $this->ACL->getUser()); + } } else if ($this->ParamHandler->isRest()) { throw new MethodNotAllowedException(__('Invalid user credentials.')); } @@ -153,12 +155,11 @@ class AppController extends Controller if (!empty($authKey)) { $this->loadModel('Users'); $user = $this->Users->get($authKey['user_id']); - $user = $logModel->userInfo(); $logModel->insert([ - 'action' => 'login', + 'request_action' => 'login', 'model' => 'Users', 'model_id' => $user['id'], - 'model_title' => $user['name'], + 'model_title' => $user['username'], 'change' => [] ]); if (!empty($user)) { @@ -167,7 +168,7 @@ class AppController extends Controller } else { $user = $logModel->userInfo(); $logModel->insert([ - 'action' => 'login', + 'request_action' => 'login', 'model' => 'Users', 'model_id' => $user['id'], 'model_title' => $user['name'], diff --git a/src/Controller/AuditLogsController.php b/src/Controller/AuditLogsController.php index 58a2133..9717416 100644 --- a/src/Controller/AuditLogsController.php +++ b/src/Controller/AuditLogsController.php @@ -11,8 +11,8 @@ use Cake\Core\Configure; class AuditLogsController extends AppController { - public $filterFields = ['model_id', 'model', 'action', 'user_id', 'title']; - public $quickFilterFields = ['model', 'action', 'title']; + public $filterFields = ['model_id', 'model', 'request_action', 'user_id', 'title']; + public $quickFilterFields = ['model', 'request_action', 'title']; public $containFields = ['Users']; public function index() diff --git a/src/Controller/AuthKeysController.php b/src/Controller/AuthKeysController.php index 5f75b4a..9e8ac03 100644 --- a/src/Controller/AuthKeysController.php +++ b/src/Controller/AuthKeysController.php @@ -16,15 +16,25 @@ class AuthKeysController extends AppController { public $filterFields = ['Users.username', 'authkey', 'comment', 'Users.id']; public $quickFilterFields = ['authkey', ['comment' => true]]; - public $containFields = ['Users']; + public $containFields = ['Users' => ['fields' => ['id', 'username']]]; public function index() { + $currentUser = $this->ACL->getUser(); + $conditions = []; + if (empty($currentUser['role']['perm_admin'])) { + $conditions['Users.organisation_id'] = $currentUser['organisation_id']; + if (empty($currentUser['role']['perm_org_admin'])) { + $conditions['Users.id'] = $currentUser['id']; + } + } $this->CRUD->index([ 'filters' => $this->filterFields, 'quickFilters' => $this->quickFilterFields, 'contain' => $this->containFields, - 'exclude_fields' => ['authkey'] + 'exclude_fields' => ['authkey'], + 'conditions' => $conditions, + 'hidden' => [] ]); $responsePayload = $this->CRUD->getResponsePayload(); if (!empty($responsePayload)) { @@ -35,7 +45,15 @@ class AuthKeysController extends AppController public function delete($id) { - $this->CRUD->delete($id); + $currentUser = $this->ACL->getUser(); + $conditions = []; + if (empty($currentUser['role']['perm_admin'])) { + $conditions['Users.organisation_id'] = $currentUser['organisation_id']; + if (empty($currentUser['role']['perm_org_admin'])) { + $conditions['Users.id'] = $currentUser['id']; + } + } + $this->CRUD->delete($id, ['conditions' => $conditions, 'contain' => 'Users']); $responsePayload = $this->CRUD->getResponsePayload(); if (!empty($responsePayload)) { return $responsePayload; diff --git a/src/Controller/Component/ACLComponent.php b/src/Controller/Component/ACLComponent.php index 5feae97..cd38752 100644 --- a/src/Controller/Component/ACLComponent.php +++ b/src/Controller/Component/ACLComponent.php @@ -145,24 +145,24 @@ class ACLComponent extends Component 'view' => ['*'] ], 'SharingGroups' => [ - 'add' => ['perm_admin'], - 'addOrg' => ['perm_admin'], - 'delete' => ['perm_admin'], - 'edit' => ['perm_admin'], + 'add' => ['perm_org_admin'], + 'addOrg' => ['perm_org_admin'], + 'delete' => ['perm_org_admin'], + 'edit' => ['perm_org_admin'], 'index' => ['*'], 'listOrgs' => ['*'], - 'removeOrg' => ['perm_admin'], + 'removeOrg' => ['perm_org_admin'], 'view' => ['*'] ], 'Users' => [ - 'add' => ['perm_admin'], - 'delete' => ['perm_admin'], + 'add' => ['perm_org_admin'], + 'delete' => ['perm_org_admin'], 'edit' => ['*'], - 'index' => ['perm_admin'], + 'index' => ['perm_org_admin'], 'login' => ['*'], 'logout' => ['*'], 'register' => ['*'], - 'toggle' => ['perm_admin'], + 'toggle' => ['perm_org_admin'], 'view' => ['*'] ] ); @@ -290,6 +290,12 @@ class ACLComponent extends Component if ($allConditionsMet) { return true; } + } else { + foreach ($this->aclList[$controller][$action] as $permission) { + if ($this->user['role'][$permission]) { + return true; + } + } } } return false; diff --git a/src/Controller/Component/CRUDComponent.php b/src/Controller/Component/CRUDComponent.php index 45df6d5..4ebabff 100644 --- a/src/Controller/Component/CRUDComponent.php +++ b/src/Controller/Component/CRUDComponent.php @@ -50,6 +50,9 @@ class CRUDComponent extends Component } $query = $this->setFilters($params, $query, $options); $query = $this->setQuickFilters($params, $query, empty($options['quickFilters']) ? [] : $options['quickFilters']); + if (!empty($options['conditions'])) { + $query->where($options['conditions']); + } if (!empty($options['contain'])) { $query->contain($options['contain']); } @@ -284,7 +287,14 @@ class CRUDComponent extends Component $params['contain'][] = 'Tags'; $this->setAllTags(); } - $data = $this->Table->get($id, isset($params['get']) ? $params['get'] : $params); + $data = $this->Table->find()->where(['id' => $id]); + if (!empty($params['conditions'])) { + $data->where($params['conditions']); + } + $data = $data->first(); + if (empty($data)) { + throw new NotFoundException(__('Invalid {0}.', $this->ObjectAlias)); + } $data = $this->getMetaFields($id, $data); if (!empty($params['fields'])) { $this->Controller->set('fields', $params['fields']); @@ -414,11 +424,21 @@ class CRUDComponent extends Component $this->Controller->set('entity', $data); } - public function delete($id=false): void + public function delete($id=false, $params=[]): void { if ($this->request->is('get')) { if(!empty($id)) { - $data = $this->Table->get($id); + $data = $this->Table->find()->where([$this->Table->getAlias() . '.id' => $id]); + if (!empty($params['conditions'])) { + $data->where($params['conditions']); + } + if (!empty($params['contain'])) { + $data->contain($params['contain']); + } + $data = $data->first(); + if (empty($data)) { + throw new NotFoundException(__('Invalid {0}.', $this->ObjectAlias)); + } $this->Controller->set('id', $data['id']); $this->Controller->set('data', $data); $this->Controller->set('bulkEnabled', false); @@ -430,9 +450,20 @@ class CRUDComponent extends Component $isBulk = count($ids) > 1; $bulkSuccesses = 0; foreach ($ids as $id) { - $data = $this->Table->get($id); - $success = $this->Table->delete($data); - $success = true; + $data = $this->Table->find()->where([$this->Table->getAlias() . '.id' => $id]); + if (!empty($params['conditions'])) { + $data->where($params['conditions']); + } + if (!empty($params['contain'])) { + $data->contain($params['contain']); + } + $data = $data->first(); + if (!empty($data)) { + $success = $this->Table->delete($data); + $success = true; + } else { + $success = false; + } if ($success) { $bulkSuccesses++; } diff --git a/src/Controller/EncryptionKeysController.php b/src/Controller/EncryptionKeysController.php index 65183cb..78bec89 100644 --- a/src/Controller/EncryptionKeysController.php +++ b/src/Controller/EncryptionKeysController.php @@ -49,7 +49,31 @@ class EncryptionKeysController extends AppController public function add() { - $this->CRUD->add(['redirect' => $this->referer()]); + $orgConditions = []; + $currentUser = $this->ACL->getUser(); + $params = ['redirect' => $this->referer()]; + if (empty($currentUser['role']['perm_admin'])) { + $params['beforeSave'] = function($entity) { + if ($entity['owner_model'] === 'organisation') { + $entity['owner_id'] = $currentUser['organisation_id']; + } else { + if ($currentUser['role']['perm_org_admin']) { + $validIndividuals = $this->Organisations->Alignments->find('list', [ + 'fields' => ['distinct(individual_id)'], + 'conditions' => ['organisation_id' => $currentUser['organisation_id']] + ]); + if (!in_array($entity['owner_id'], $validIndividuals)) { + throw new MethodNotAllowedException(__('Selected individual cannot be linked by the current user.')); + } + } else { + if ($entity['owner_id'] !== $currentUser['id']) { + throw new MethodNotAllowedException(__('Selected individual cannot be linked by the current user.')); + } + } + } + }; + } + $this->CRUD->add($params); $responsePayload = $this->CRUD->getResponsePayload(); if (!empty($responsePayload)) { return $responsePayload; @@ -58,7 +82,8 @@ class EncryptionKeysController extends AppController $this->loadModel('Individuals'); $dropdownData = [ 'organisation' => $this->Organisations->find('list', [ - 'sort' => ['name' => 'asc'] + 'sort' => ['name' => 'asc'], + 'conditions' => $orgConditions ]), 'individual' => $this->Individuals->find('list', [ 'sort' => ['email' => 'asc'] @@ -70,12 +95,19 @@ class EncryptionKeysController extends AppController public function edit($id = false) { + $conditions = []; + $currentUser = $this->ACL->getUser(); $params = [ 'fields' => [ 'type', 'encryption_key', 'revoked' ], 'redirect' => $this->referer() ]; + if (empty($currentUser['role']['perm_admin'])) { + if (empty($currentUser['role']['perm_org_admin'])) { + + } + } $this->CRUD->edit($id, $params); $responsePayload = $this->CRUD->getResponsePayload(); if (!empty($responsePayload)) { diff --git a/src/Controller/SharingGroupsController.php b/src/Controller/SharingGroupsController.php index c8f8f79..4e98df8 100644 --- a/src/Controller/SharingGroupsController.php +++ b/src/Controller/SharingGroupsController.php @@ -16,10 +16,16 @@ class SharingGroupsController extends AppController public function index() { + $currentUser = $this->ACL->getUser(); + $conditions = []; + if (empty($currentUser['role']['perm_admin'])) { + $conditions['SharingGroups.organisation_id'] = $currentUser['organisation_id']; + } $this->CRUD->index([ 'contain' => $this->containFields, 'filters' => $this->filterFields, - 'quickFilters' => $this->quickFilterFields + 'quickFilters' => $this->quickFilterFields, + 'conditions' => $conditions ]); $responsePayload = $this->CRUD->getResponsePayload(); if (!empty($responsePayload)) { @@ -60,7 +66,12 @@ class SharingGroupsController extends AppController public function edit($id = false) { - $this->CRUD->edit($id); + $params = []; + $currentUser = $this->ACL->getUser(); + if (empty($currentUser['role']['perm_admin'])) { + $params['conditions'] = ['organisation_id' => $currentUser['organisation_id']]; + } + $this->CRUD->edit($id, $params); $responsePayload = $this->CRUD->getResponsePayload(); if (!empty($responsePayload)) { return $responsePayload; @@ -206,11 +217,11 @@ class SharingGroupsController extends AppController $organisations = []; if (!empty($user['role']['perm_admin'])) { $organisations = $this->SharingGroups->Organisations->find('list')->order(['name' => 'ASC'])->toArray(); - } else if (!empty($user['individual']['organisations'])) { + } else { $organisations = $this->SharingGroups->Organisations->find('list', [ 'sort' => ['name' => 'asc'], 'conditions' => [ - 'id IN' => array_values(\Cake\Utility\Hash::extract($user, 'individual.organisations.{n}.id')) + 'id' => $user['organisation_id'] ] ]); } diff --git a/src/Controller/UsersController.php b/src/Controller/UsersController.php index 012655e..0f81751 100644 --- a/src/Controller/UsersController.php +++ b/src/Controller/UsersController.php @@ -11,16 +11,22 @@ use Cake\Core\Configure; class UsersController extends AppController { - public $filterFields = ['Individuals.uuid', 'username', 'Individuals.email', 'Individuals.first_name', 'Individuals.last_name']; + public $filterFields = ['Individuals.uuid', 'username', 'Individuals.email', 'Individuals.first_name', 'Individuals.last_name', 'Organisations.name']; public $quickFilterFields = ['Individuals.uuid', ['username' => true], ['Individuals.first_name' => true], ['Individuals.last_name' => true], 'Individuals.email']; - public $containFields = ['Individuals', 'Roles', 'UserSettings']; + public $containFields = ['Individuals', 'Roles', 'UserSettings', 'Organisations']; public function index() { + $currentUser = $this->ACL->getUser(); + $conditions = []; + if (empty($currentUser['role']['perm_admin'])) { + $conditions['organisation_id'] = $currentUser['organisation_id']; + } $this->CRUD->index([ 'contain' => $this->containFields, 'filters' => $this->filterFields, 'quickFilters' => $this->quickFilterFields, + 'conditions' => $conditions ]); $responsePayload = $this->CRUD->getResponsePayload(); if (!empty($responsePayload)) { @@ -31,8 +37,12 @@ class UsersController extends AppController public function add() { + $currentUser = $this->ACL->getUser(); $this->CRUD->add([ - 'beforeSave' => function($data) { + 'beforeSave' => function($data) use ($currentUser) { + if (!$currentUser['role']['perm_admin']) { + $data['organisation_id'] = $currentUser['organisation_id']; + } $this->Users->enrollUserRouter($data); return $data; } @@ -41,12 +51,28 @@ class UsersController extends AppController if (!empty($responsePayload)) { return $responsePayload; } + /* + $alignments = $this->Users->Individuals->Alignments->find('list', [ + //'keyField' => 'id', + 'valueField' => 'organisation_id', + 'groupField' => 'individual_id' + ])->toArray(); + $alignments = array_map(function($value) { return array_values($value); }, $alignments); + */ + $org_conditions = []; + if (empty($currentUser['role']['perm_admin'])) { + $org_conditions = ['id' => $currentUser['organisation_id']]; + } $dropdownData = [ 'role' => $this->Users->Roles->find('list', [ 'sort' => ['name' => 'asc'] ]), 'individual' => $this->Users->Individuals->find('list', [ 'sort' => ['email' => 'asc'] + ]), + 'organisation' => $this->Users->Organisations->find('list', [ + 'sort' => ['name' => 'asc'], + 'conditions' => $org_conditions ]) ]; $this->set(compact('dropdownData')); @@ -59,7 +85,7 @@ class UsersController extends AppController $id = $this->ACL->getUser()['id']; } $this->CRUD->view($id, [ - 'contain' => ['Individuals' => ['Alignments' => 'Organisations'], 'Roles'] + 'contain' => ['Individuals' => ['Alignments' => 'Organisations'], 'Roles', 'Organisations'] ]); $responsePayload = $this->CRUD->getResponsePayload(); if (!empty($responsePayload)) { @@ -70,9 +96,11 @@ class UsersController extends AppController public function edit($id = false) { - if (empty($id) || empty($this->ACL->getUser()['role']['perm_admin'])) { - $id = $this->ACL->getUser()['id']; + $currentUser = $this->ACL->getUser(); + if (empty($id) || (empty($currentUser['role']['perm_org_admin']) && empty($currentUser['role']['perm_site_admin']))) { + $id = $currentUser['id']; } + $params = [ 'get' => [ 'fields' => [ @@ -88,6 +116,7 @@ class UsersController extends AppController ]; if (!empty($this->ACL->getUser()['role']['perm_admin'])) { $params['fields'][] = 'role_id'; + $params['fields'][] = 'organisation_id'; } $this->CRUD->edit($id, $params); $responsePayload = $this->CRUD->getResponsePayload(); @@ -100,6 +129,9 @@ class UsersController extends AppController ]), 'individual' => $this->Users->Individuals->find('list', [ 'sort' => ['email' => 'asc'] + ]), + 'organisation' => $this->Users->Organisations->find('list', [ + 'sort' => ['name' => 'asc'] ]) ]; $this->set(compact('dropdownData')); diff --git a/src/Model/Behavior/AuditLogBehavior.php b/src/Model/Behavior/AuditLogBehavior.php index f7ef3df..26d354c 100644 --- a/src/Model/Behavior/AuditLogBehavior.php +++ b/src/Model/Behavior/AuditLogBehavior.php @@ -129,14 +129,13 @@ class AuditLogBehavior extends Behavior $modelTitle = $entity[$modelTitleField]; } - $logEntity = $this->auditLogs()->newEntity([ + $this->auditLogs()->insert([ 'request_action' => $entity->getConstant('ACTION_DELETE'), 'model' => $entity->getSource(), 'model_id' => $this->old->id, 'model_title' => $modelTitle, 'change' => $this->changedFields($entity) ]); - $logEntity->save(); } /** diff --git a/src/Model/Behavior/AuthKeycloakBehavior.php b/src/Model/Behavior/AuthKeycloakBehavior.php index d42a8c9..4b46a87 100644 --- a/src/Model/Behavior/AuthKeycloakBehavior.php +++ b/src/Model/Behavior/AuthKeycloakBehavior.php @@ -98,7 +98,7 @@ class AuthKeycloakBehavior extends Behavior { $individual = $this->_table->Individuals->find()->where( ['id' => $data['individual_id']] - )->contain(['Organisations'])->first(); + )->first(); $roleConditions = [ 'id' => $data['role_id'] ]; @@ -106,10 +106,9 @@ class AuthKeycloakBehavior extends Behavior $roleConditions['name'] = Configure::read('keycloak.default_role_name'); } $role = $this->_table->Roles->find()->where($roleConditions)->first(); - $orgs = []; - foreach ($individual['organisations'] as $org) { - $orgs[] = $org['uuid']; - } + $org = $this->_table->Organisations->find()->where([ + ['id' => $data['organisation_id']] + ]); $token = $this->getAdminAccessToken(); $keyCloakUser = [ 'firstName' => $individual['first_name'], @@ -118,7 +117,7 @@ class AuthKeycloakBehavior extends Behavior 'email' => $individual['email'], 'attributes' => [ 'role_name' => empty($role['name']) ? Configure::read('keycloak.default_role_name') : $role['name'], - 'org_uuid' => empty($orgs[0]) ? '' : $orgs[0] + 'org_uuid' => $orgs['uuid'] ] ]; $keycloakConfig = Configure::read('keycloak'); diff --git a/src/Model/Table/UsersTable.php b/src/Model/Table/UsersTable.php index 3a98b00..cb189aa 100644 --- a/src/Model/Table/UsersTable.php +++ b/src/Model/Table/UsersTable.php @@ -36,6 +36,13 @@ class UsersTable extends AppTable 'cascadeCallbacks' => false ] ); + $this->belongsTo( + 'Organisations', + [ + 'dependent' => false, + 'cascadeCallbacks' => false + ] + ); $this->hasMany( 'UserSettings', [ diff --git a/templates/AuditLogs/index.php b/templates/AuditLogs/index.php index 46ec90b..a121e4f 100644 --- a/templates/AuditLogs/index.php +++ b/templates/AuditLogs/index.php @@ -45,8 +45,8 @@ echo $this->element('genericElements/IndexTable/index_table', [ ], [ 'name' => __('Action'), - 'sort' => 'action', - 'data_path' => 'action', + 'sort' => 'request_action', + 'data_path' => 'request_action', ], [ 'name' => __('Change'), diff --git a/templates/Organisations/index.php b/templates/Organisations/index.php index 0448c77..4b34aab 100644 --- a/templates/Organisations/index.php +++ b/templates/Organisations/index.php @@ -94,12 +94,14 @@ echo $this->element('genericElements/IndexTable/index_table', [ [ 'open_modal' => '/organisations/edit/[onclick_params_data_path]', 'modal_params_data_path' => 'id', - 'icon' => 'edit' + 'icon' => 'edit', + 'requirement' => $loggedUser['role']['perm_admin'] ], [ 'open_modal' => '/organisations/delete/[onclick_params_data_path]', 'modal_params_data_path' => 'id', - 'icon' => 'trash' + 'icon' => 'trash', + 'requirement' => $loggedUser['role']['perm_admin'] ], ] ] diff --git a/templates/Roles/index.php b/templates/Roles/index.php index 2fc4c03..204d1d9 100644 --- a/templates/Roles/index.php +++ b/templates/Roles/index.php @@ -78,12 +78,14 @@ echo $this->element('genericElements/IndexTable/index_table', [ [ 'open_modal' => '/roles/edit/[onclick_params_data_path]', 'modal_params_data_path' => 'id', - 'icon' => 'edit' + 'icon' => 'edit', + 'requirement' => !empty($loggedUser['role']['perm_site_admin']) ], [ 'open_modal' => '/roles/delete/[onclick_params_data_path]', 'modal_params_data_path' => 'id', - 'icon' => 'trash' + 'icon' => 'trash', + 'requirement' => !empty($loggedUser['role']['perm_site_admin']) ], ] ] diff --git a/templates/SharingGroups/index.php b/templates/SharingGroups/index.php index 6076c6c..2aae744 100644 --- a/templates/SharingGroups/index.php +++ b/templates/SharingGroups/index.php @@ -35,6 +35,11 @@ echo $this->element('genericElements/IndexTable/index_table', [ 'class' => 'short', 'data_path' => 'name', ], + [ + 'name' => __('Owner'), + 'class' => 'short', + 'data_path' => 'organisation.name' + ], [ 'name' => __('UUID'), 'sort' => 'uuid', diff --git a/templates/Users/add.php b/templates/Users/add.php index 99bf366..f215277 100644 --- a/templates/Users/add.php +++ b/templates/Users/add.php @@ -14,6 +14,12 @@ 'field' => 'username', 'autocomplete' => 'off' ], + [ + 'field' => 'organisation_id', + 'type' => 'dropdown', + 'label' => __('Associated organisation'), + 'options' => $dropdownData['organisation'] + ], [ 'field' => 'password', 'label' => __('Password'), diff --git a/templates/Users/index.php b/templates/Users/index.php index 64561a1..1ff36bf 100644 --- a/templates/Users/index.php +++ b/templates/Users/index.php @@ -51,6 +51,13 @@ echo $this->element('genericElements/IndexTable/index_table', [ 'sort' => 'username', 'data_path' => 'username', ], + [ + 'name' => __('Organisation'), + 'sort' => 'organisation.name', + 'data_path' => 'organisation.name', + 'url' => '/organisations/view/{{0}}', + 'url_vars' => ['organisation.id'] + ], [ 'name' => __('Email'), 'sort' => 'individual.email', diff --git a/templates/Users/view.php b/templates/Users/view.php index 760ead4..26c3c25 100644 --- a/templates/Users/view.php +++ b/templates/Users/view.php @@ -21,6 +21,14 @@ echo $this->element( 'path' => 'individual.email' ], [ + 'type' => 'generic', + 'key' => __('Organisation'), + 'path' => 'organisation.name', + 'url' => '/organisations/view/{{0}}', + 'url_vars' => 'organisation.id' + ], + [ + 'type' => 'generic', 'key' => __('Role'), 'path' => 'role.name', 'url' => '/roles/view/{{0}}', diff --git a/templates/element/layouts/header/header-profile.php b/templates/element/layouts/header/header-profile.php index a35e041..1f148d6 100644 --- a/templates/element/layouts/header/header-profile.php +++ b/templates/element/layouts/header/header-profile.php @@ -8,10 +8,10 @@ use Cake\Routing\Router;
\ No newline at end of file + diff --git a/webroot/css/login.css b/webroot/css/login.css index f308579..7cfb32d 100644 --- a/webroot/css/login.css +++ b/webroot/css/login.css @@ -30,7 +30,7 @@ body { transform: rotate(100deg); -webkit-transform-origin: center; transform-origin: center; - left: 42%; + left: calc(50% - 120px); top: 30%; }