commit
108b778857
|
@ -0,0 +1,283 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use Cake\Console\Command;
|
||||||
|
use Cake\Console\Arguments;
|
||||||
|
use Cake\Console\ConsoleIo;
|
||||||
|
use Cake\Console\ConsoleOptionParser;
|
||||||
|
use Cake\Filesystem\File;
|
||||||
|
use Cake\Utility\Hash;
|
||||||
|
use Cake\Core\Configure;
|
||||||
|
use Cake\Utility\Security;
|
||||||
|
|
||||||
|
class FastUserEnrolmentCommand extends Command
|
||||||
|
{
|
||||||
|
protected $modelClass = 'Alignments';
|
||||||
|
private $autoYes = false;
|
||||||
|
private $alignment_type = null;
|
||||||
|
private $individual_email_column = false;
|
||||||
|
private $organisation_name_column = false;
|
||||||
|
private $create_user = false;
|
||||||
|
private $role_id = null;
|
||||||
|
|
||||||
|
protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser
|
||||||
|
{
|
||||||
|
$parser->setDescription('Create alignements (and optionally enroll users) based on the provided CSV file.');
|
||||||
|
$parser->addArgument('path', [
|
||||||
|
'help' => 'A path to the source file that should be used to create the alignments.',
|
||||||
|
'required' => true
|
||||||
|
]);
|
||||||
|
$parser->addOption('alignment_type', [
|
||||||
|
'short' => 't',
|
||||||
|
'help' => 'The alignment type to use',
|
||||||
|
'default' => 'member',
|
||||||
|
]);
|
||||||
|
$parser->addOption('individual_email_column', [
|
||||||
|
'short' => 'i',
|
||||||
|
'help' => 'The name of the column to find the individual email address',
|
||||||
|
'default' => 'Email',
|
||||||
|
]);
|
||||||
|
$parser->addOption('organisation_name_column', [
|
||||||
|
'short' => 'o',
|
||||||
|
'help' => 'The name of the column to find the organisation name',
|
||||||
|
'default' => 'TeamName',
|
||||||
|
]);
|
||||||
|
$parser->addOption('create_user', [
|
||||||
|
'short' => 'c',
|
||||||
|
'help' => 'Should the user be created',
|
||||||
|
'boolean' => true,
|
||||||
|
'default' => false,
|
||||||
|
]);
|
||||||
|
$parser->addOption('role_id', [
|
||||||
|
'short' => 'r',
|
||||||
|
'help' => 'The role to assign to the user',
|
||||||
|
]);
|
||||||
|
$parser->addOption('yes', [
|
||||||
|
'short' => 'y',
|
||||||
|
'help' => 'Automatically assume yes to any prompts',
|
||||||
|
'default' => false,
|
||||||
|
'boolean' => true
|
||||||
|
]);
|
||||||
|
return $parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(Arguments $args, ConsoleIo $io)
|
||||||
|
{
|
||||||
|
$this->io = $io;
|
||||||
|
$path = $args->getArgument('path');
|
||||||
|
$this->alignment_type = $args->getOption('alignment_type');
|
||||||
|
$this->individual_email_column = $args->getOption('individual_email_column');
|
||||||
|
$this->organisation_name_column = $args->getOption('organisation_name_column');
|
||||||
|
$this->create_user = $args->getOption('create_user');
|
||||||
|
$this->role_id = $args->getOption('role_id');
|
||||||
|
$this->autoYes = $args->getOption('yes');
|
||||||
|
|
||||||
|
$alignmentTable = $this->modelClass;
|
||||||
|
$this->loadModel($alignmentTable);
|
||||||
|
$data = $this->getDataFromFile($path);
|
||||||
|
$updatedData = $this->updateBeforeSave($data);
|
||||||
|
$alignmentEntities = $this->marshalData($this->{$alignmentTable}, $updatedData);
|
||||||
|
$alignmentEntitiesSample = array_slice($alignmentEntities, 0, min(5, count($alignmentEntities)));
|
||||||
|
$ioTable = $this->transformEntitiesIntoTable($alignmentEntitiesSample);
|
||||||
|
|
||||||
|
if ($this->autoYes) {
|
||||||
|
$this->saveAligmentData($this->{$alignmentTable}, $alignmentEntities);
|
||||||
|
} else {
|
||||||
|
$io->helper('Table')->output($ioTable);
|
||||||
|
$selection = $io->askChoice('A sample of the data you about to be saved is provided above. Would you like to proceed?', ['Y', 'N'], 'N');
|
||||||
|
if ($selection == 'Y') {
|
||||||
|
$this->saveAligmentData($this->{$alignmentTabble}, $alignmentEntities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->create_user) {
|
||||||
|
$this->loadModel('Users');
|
||||||
|
if (is_null($this->role_id)) {
|
||||||
|
$defaultRole = $this->Users->Roles->find()->select(['id'])->where(['is_default' => true])->first();
|
||||||
|
if (empty($defaultRole)) {
|
||||||
|
$this->io->error(__('No default role available. Create a default role or provide the role ID to be assigned.'));
|
||||||
|
die(1);
|
||||||
|
}
|
||||||
|
$defaultRole = $defaultRole->toArray();
|
||||||
|
if (!empty($defaultRole['perm_admin'])) {
|
||||||
|
$selection = $io->askChoice('The default role has the `admin` permission. Confirm giving the admin permission to users to be enrolled.', ['Y', 'N'], 'N');
|
||||||
|
if ($selection != 'Y') {
|
||||||
|
die(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->role_id = $defaultRole['id'];
|
||||||
|
} else {
|
||||||
|
$role = $this->Users->Roles->find()->select(['id'])->where(['id' => $this->role_id])->first();
|
||||||
|
if (empty($role)) {
|
||||||
|
$this->io->error(__('Provided role ID does not exist'));
|
||||||
|
die(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$userEntities = $this->createEntitiesForUsers($alignmentEntities);
|
||||||
|
if ($this->autoYes) {
|
||||||
|
$this->enrolUsers($userEntities);
|
||||||
|
} else {
|
||||||
|
$userEntitiesSample = array_slice($userEntities, 0, min(5, count($userEntities)));
|
||||||
|
$ioTable = $this->transformEntitiesIntoTable($userEntitiesSample);
|
||||||
|
$io->helper('Table')->output($ioTable);
|
||||||
|
$selection = $io->askChoice('A sample of the data you about to be saved is provided above. Would you like to proceed?', ['Y', 'N'], 'N');
|
||||||
|
if ($selection == 'Y') {
|
||||||
|
$this->enrolUsers($userEntities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function saveAligmentData($alignmentTable, $entities)
|
||||||
|
{
|
||||||
|
$this->io->verbose('Saving data');
|
||||||
|
$saveResult = $alignmentTable->saveMany($entities);
|
||||||
|
if ($saveResult === false) {
|
||||||
|
$errors = [];
|
||||||
|
$errorCount = 0;
|
||||||
|
foreach ($entities as $entity) {
|
||||||
|
$errorCount += 1;
|
||||||
|
$errors[json_encode($entity->getErrors())] = true;
|
||||||
|
}
|
||||||
|
$this->io->error(__('{0} Errors while saving data', $errorCount));
|
||||||
|
$this->io->error(json_encode(array_keys($errors)));
|
||||||
|
$this->io->success(__('Saved {0} aligments', count($entities) - $errorCount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function enrolUsers($entities)
|
||||||
|
{
|
||||||
|
$this->io->verbose('Saving data');
|
||||||
|
$errors = [];
|
||||||
|
$errorCount = 0;
|
||||||
|
foreach ($entities as $entity) {
|
||||||
|
$succes = $this->Users->save($entity);
|
||||||
|
if (empty($succes)) {
|
||||||
|
$errorCount += 1;
|
||||||
|
$errors[json_encode($entity->getErrors())] = true;
|
||||||
|
} else {
|
||||||
|
if (Configure::read('keycloak.enabled')) {
|
||||||
|
$this->Users->enrollUserRouter($succes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($errors)) {
|
||||||
|
$this->io->error(__('{0} Errors while saving data', $errorCount));
|
||||||
|
$this->io->error(json_encode(array_keys($errors)));
|
||||||
|
}
|
||||||
|
$this->io->success(__('Enrolled {0} users', count($entities) - $errorCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createEntitiesForUsers($alignmentEntities)
|
||||||
|
{
|
||||||
|
$entities = [];
|
||||||
|
foreach ($alignmentEntities as $alignmentEntity) {
|
||||||
|
$entity = $this->Users->newEntity([
|
||||||
|
'individual_id' => $alignmentEntity->individual_id,
|
||||||
|
'organisation_id' => $alignmentEntity->organisation_id,
|
||||||
|
'username' => $alignmentEntity->individual_email,
|
||||||
|
'password' => Security::randomString(20),
|
||||||
|
'role_id' => $this->role_id,
|
||||||
|
]);
|
||||||
|
$entities[] = $entity;
|
||||||
|
}
|
||||||
|
return $entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function marshalData($alignmentTable, $data)
|
||||||
|
{
|
||||||
|
$entities = $alignmentTable->newEntities($data, [
|
||||||
|
'accessibleFields' => ($alignmentTable->newEmptyEntity())->getAccessibleFieldForNew()
|
||||||
|
]);
|
||||||
|
return $entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function updateBeforeSave($data)
|
||||||
|
{
|
||||||
|
$this->loadModel('Individuals');
|
||||||
|
$this->loadModel('Organisations');
|
||||||
|
$updatedData = [];
|
||||||
|
foreach ($data as $entry) {
|
||||||
|
$new = [
|
||||||
|
'individual_id' => $this->getIndividualByEmail($entry[$this->individual_email_column]),
|
||||||
|
'organisation_id' => $this->getOrganisationsByName($entry[$this->organisation_name_column]),
|
||||||
|
'type' => $this->alignment_type,
|
||||||
|
'individual_email' => $entry[$this->individual_email_column],
|
||||||
|
];
|
||||||
|
if (empty($new['organisation_id'])) {
|
||||||
|
$this->io->error("Error while parsing source data. Could not find organisation with name: " . $entry[$this->organisation_name_column]);
|
||||||
|
die(1);
|
||||||
|
}
|
||||||
|
if (empty($new['individual_id'])) {
|
||||||
|
$this->io->error("Error while parsing source data. Could not find individuals with email: " . $entry[$this->individual_email_column]);
|
||||||
|
die(1);
|
||||||
|
}
|
||||||
|
$new['individual_id'] = $new['individual_id']['id'];
|
||||||
|
$new['organisation_id'] = $new['organisation_id']['id'];
|
||||||
|
$updatedData[] = $new;
|
||||||
|
}
|
||||||
|
return $updatedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getIndividualByEmail($email)
|
||||||
|
{
|
||||||
|
return $this->Individuals->find()->where([
|
||||||
|
'email' => $email,
|
||||||
|
])->first()->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getOrganisationsByName($name)
|
||||||
|
{
|
||||||
|
return $this->Organisations->find()->where([
|
||||||
|
'name' => $name,
|
||||||
|
])->first()->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getDataFromFile($path)
|
||||||
|
{
|
||||||
|
$file = new File($path);
|
||||||
|
if ($file->exists()) {
|
||||||
|
$this->io->verbose('Reading file');
|
||||||
|
$text = $file->read();
|
||||||
|
$file->close();
|
||||||
|
if (!empty($text)) {
|
||||||
|
$rows = array_map('str_getcsv', explode(PHP_EOL, $text));
|
||||||
|
if (count($rows[0]) != count($rows[1])) {
|
||||||
|
$this->io->error('Error while parsing source data. CSV doesn\'t have the same number of columns');
|
||||||
|
die(1);
|
||||||
|
}
|
||||||
|
$csvData = [];
|
||||||
|
$headers = array_shift($rows);
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
if (count($headers) == count($row)) {
|
||||||
|
$csvData[] = array_combine($headers, $row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $csvData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function transformEntitiesIntoTable($entities, $header = [])
|
||||||
|
{
|
||||||
|
$table = [[]];
|
||||||
|
if (!empty($entities)) {
|
||||||
|
$tableHeader = empty($header) ? array_keys(Hash::flatten($entities[0]->toArray())) : $header;
|
||||||
|
$tableContent = [];
|
||||||
|
foreach ($entities as $entity) {
|
||||||
|
$row = [];
|
||||||
|
foreach ($tableHeader as $key) {
|
||||||
|
if (in_array($key, $entity->getVirtual())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$row[] = (string) $entity[$key];
|
||||||
|
}
|
||||||
|
$tableContent[] = $row;
|
||||||
|
}
|
||||||
|
$table = array_merge([$tableHeader], $tableContent);
|
||||||
|
}
|
||||||
|
return $table;
|
||||||
|
}
|
||||||
|
}
|
|
@ -87,11 +87,10 @@ class FieldSquasherCommand extends Command
|
||||||
if ($selection == 'Y') {
|
if ($selection == 'Y') {
|
||||||
$this->saveDataOnDisk($filename, $candidateResult['candidates']);
|
$this->saveDataOnDisk($filename, $candidateResult['candidates']);
|
||||||
}
|
}
|
||||||
die(1);
|
$entities = $candidateResult['candidates'];
|
||||||
|
|
||||||
$selection = $io->askChoice('A sample of the data you about to be saved is provided above. Would you like to proceed?', ['Y', 'N'], 'N');
|
$selection = $io->askChoice('A sample of the data you about to be saved is provided above. Would you like to proceed?', ['Y', 'N'], 'N');
|
||||||
if ($selection == 'Y') {
|
if ($selection == 'Y') {
|
||||||
// $this->saveData($this->{$table}, $entities);
|
$this->saveData($this->{$table}, $entities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -190,7 +190,7 @@ class ImporterCommand extends Command
|
||||||
if (is_null($metaEntity)) {
|
if (is_null($metaEntity)) {
|
||||||
$metaEntity = $this->MetaFields->newEmptyEntity();
|
$metaEntity = $this->MetaFields->newEmptyEntity();
|
||||||
$metaEntity->field = $fieldName;
|
$metaEntity->field = $fieldName;
|
||||||
$metaEntity->scope = $table->metaFields;
|
$metaEntity->scope = $table->getBehavior('MetaFields')->getScope();
|
||||||
$metaEntity->meta_template_id = $metaTemplate->id;
|
$metaEntity->meta_template_id = $metaTemplate->id;
|
||||||
if (isset($metaTemplateFieldsMapping[$fieldName])) { // a meta field template must exists
|
if (isset($metaTemplateFieldsMapping[$fieldName])) { // a meta field template must exists
|
||||||
$metaEntity->meta_template_field_id = $metaTemplateFieldsMapping[$fieldName];
|
$metaEntity->meta_template_field_id = $metaTemplateFieldsMapping[$fieldName];
|
||||||
|
@ -248,6 +248,7 @@ class ImporterCommand extends Command
|
||||||
{
|
{
|
||||||
foreach ($entity->metaFields as $i => $metaEntity) {
|
foreach ($entity->metaFields as $i => $metaEntity) {
|
||||||
$metaEntity->parent_id = $entity->id;
|
$metaEntity->parent_id = $entity->id;
|
||||||
|
$metaEntity->setNew(true);
|
||||||
if ($metaEntity->hasErrors() || is_null($metaEntity->value)) {
|
if ($metaEntity->hasErrors() || is_null($metaEntity->value)) {
|
||||||
$this->io->error(json_encode(['entity' => $metaEntity, 'errors' => $metaEntity->getErrors()], JSON_PRETTY_PRINT));
|
$this->io->error(json_encode(['entity' => $metaEntity, 'errors' => $metaEntity->getErrors()], JSON_PRETTY_PRINT));
|
||||||
unset($entity->metaFields[$i]);
|
unset($entity->metaFields[$i]);
|
||||||
|
@ -289,35 +290,35 @@ class ImporterCommand extends Command
|
||||||
$values = array_map("self::{$fieldConfig['massage']}", $values);
|
$values = array_map("self::{$fieldConfig['massage']}", $values);
|
||||||
}
|
}
|
||||||
if (isset($defaultFields[$key])) {
|
if (isset($defaultFields[$key])) {
|
||||||
$data[$key] = $values;
|
$data[$key] = array_map('trim', $values);
|
||||||
} else {
|
} else {
|
||||||
$data['metaFields'][$key] = $values;
|
$data['metaFields'][$key] = array_map('trim', $values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $this->invertArray($data);
|
return $this->invertArray($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function extractDataFromCSV($defaultFields, $config, $source)
|
private function extractDataFromCSV($defaultFields, $config, $source)
|
||||||
|
{
|
||||||
|
$csvData = $this->csvToAssociativeArray($source);
|
||||||
|
return $this->extractDataFromJSON($defaultFields, $config, $csvData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function csvToAssociativeArray($source): array
|
||||||
{
|
{
|
||||||
$rows = array_map('str_getcsv', explode(PHP_EOL, $source));
|
$rows = array_map('str_getcsv', explode(PHP_EOL, $source));
|
||||||
if (count($rows[0]) != count($rows[1])) {
|
if (count($rows[0]) != count($rows[1])) {
|
||||||
$this->io->error('Error while parsing source data. CSV doesn\'t have the same number of columns');
|
$this->io->error('Error while parsing source data. CSV doesn\'t have the same number of columns');
|
||||||
die(1);
|
die(1);
|
||||||
}
|
}
|
||||||
$header = array_shift($rows);
|
$csvData = [];
|
||||||
$data = array();
|
$headers = array_shift($rows);
|
||||||
foreach($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
$dataRow = [];
|
if (count($headers) == count($row)) {
|
||||||
foreach ($header as $i => $headerField) {
|
$csvData[] = array_combine($headers, $row);
|
||||||
if (isset($defaultFields[$headerField])) {
|
|
||||||
$dataRow[$headerField] = $row[$i];
|
|
||||||
} else {
|
|
||||||
$dataRow['metaFields'][$headerField] = $row[$i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$data[] = $dataRow;
|
|
||||||
}
|
}
|
||||||
return $data;
|
return $csvData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function lockAccess(&$entity)
|
private function lockAccess(&$entity)
|
||||||
|
@ -477,6 +478,9 @@ class ImporterCommand extends Command
|
||||||
foreach ($entities as $entity) {
|
foreach ($entities as $entity) {
|
||||||
$row = [];
|
$row = [];
|
||||||
foreach ($tableHeader as $key) {
|
foreach ($tableHeader as $key) {
|
||||||
|
if (in_array($key, $entity->getVirtual())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$subKeys = explode('.', $key);
|
$subKeys = explode('.', $key);
|
||||||
if (in_array('metaFields', $subKeys)) {
|
if (in_array('metaFields', $subKeys)) {
|
||||||
$found = false;
|
$found = false;
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use Cake\Console\Command;
|
||||||
|
use Cake\Console\Arguments;
|
||||||
|
use Cake\Console\ConsoleIo;
|
||||||
|
use Cake\Console\ConsoleOptionParser;
|
||||||
|
use Cake\Filesystem\File;
|
||||||
|
use Cake\Utility\Hash;
|
||||||
|
use Cake\Core\Configure;
|
||||||
|
|
||||||
|
class MetaTemplateCommand extends Command
|
||||||
|
{
|
||||||
|
protected $modelClass = 'MetaTemplates';
|
||||||
|
|
||||||
|
protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser
|
||||||
|
{
|
||||||
|
$parser->setDescription('Load and enable the provided meta-template');
|
||||||
|
$parser->addArgument('uuid', [
|
||||||
|
'help' => 'The UUID of the meta-template to load and enable',
|
||||||
|
'required' => true
|
||||||
|
]);
|
||||||
|
return $parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(Arguments $args, ConsoleIo $io)
|
||||||
|
{
|
||||||
|
$this->io = $io;
|
||||||
|
$template_uuid = $args->getArgument('uuid');
|
||||||
|
$metaTemplateTable = $this->modelClass;
|
||||||
|
$this->loadModel($metaTemplateTable);
|
||||||
|
$result = $this->MetaTemplates->createNewTemplate($template_uuid);
|
||||||
|
if (empty($result['success'])) {
|
||||||
|
$this->io->error(__('Could not create meta-template'));
|
||||||
|
$this->io->error(json_encode($result));
|
||||||
|
die(1);
|
||||||
|
}
|
||||||
|
$template = $this->MetaTemplates->find()->where(['uuid' => $template_uuid])->first();
|
||||||
|
if (!empty($template)) {
|
||||||
|
$template->enabled = true;
|
||||||
|
$success = $this->MetaTemplates->save($template);
|
||||||
|
if (!empty($success)) {
|
||||||
|
$this->io->success(__('Meta-template loaded and enabled'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -105,7 +105,7 @@ class AlignmentsController extends AppController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($scope === 'organisations') {
|
if ($scope === 'organisations') {
|
||||||
$individuals = $this->Individuals->find('list', ['valueField' => 'email']);
|
$individuals = $this->Individuals->find('list', ['valueField' => 'email'])->toArray();
|
||||||
$this->set('individuals', $individuals);
|
$this->set('individuals', $individuals);
|
||||||
$organisation = $this->Organisations->find()->where(['id' => $source_id])->first();
|
$organisation = $this->Organisations->find()->where(['id' => $source_id])->first();
|
||||||
if (empty($organisation)) {
|
if (empty($organisation)) {
|
||||||
|
@ -113,7 +113,7 @@ class AlignmentsController extends AppController
|
||||||
}
|
}
|
||||||
$this->set(compact('organisation'));
|
$this->set(compact('organisation'));
|
||||||
} else {
|
} else {
|
||||||
$organisations = $this->Organisations->find('list', ['valueField' => 'name']);
|
$organisations = $this->Organisations->find('list', ['valueField' => 'name'])->toArray();
|
||||||
$this->set('organisations', $organisations);
|
$this->set('organisations', $organisations);
|
||||||
$individual = $this->Individuals->find()->where(['id' => $source_id])->first();
|
$individual = $this->Individuals->find()->where(['id' => $source_id])->first();
|
||||||
if (empty($individual)) {
|
if (empty($individual)) {
|
||||||
|
|
|
@ -45,7 +45,7 @@ class BroodsController extends AppController
|
||||||
$dropdownData = [
|
$dropdownData = [
|
||||||
'organisation' => $this->Organisations->find('list', [
|
'organisation' => $this->Organisations->find('list', [
|
||||||
'sort' => ['name' => 'asc']
|
'sort' => ['name' => 'asc']
|
||||||
])
|
])->toArray()
|
||||||
];
|
];
|
||||||
$this->set(compact('dropdownData'));
|
$this->set(compact('dropdownData'));
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ class BroodsController extends AppController
|
||||||
$dropdownData = [
|
$dropdownData = [
|
||||||
'organisation' => $this->Organisations->find('list', [
|
'organisation' => $this->Organisations->find('list', [
|
||||||
'sort' => ['name' => 'asc']
|
'sort' => ['name' => 'asc']
|
||||||
])
|
])->toArray()
|
||||||
];
|
];
|
||||||
$this->set(compact('dropdownData'));
|
$this->set(compact('dropdownData'));
|
||||||
$this->render('add');
|
$this->render('add');
|
||||||
|
|
|
@ -142,6 +142,9 @@ class CRUDComponent extends Component
|
||||||
$data[$i] = $this->attachMetaTemplatesIfNeeded($row, $metaTemplates);
|
$data[$i] = $this->attachMetaTemplatesIfNeeded($row, $metaTemplates);
|
||||||
}
|
}
|
||||||
$this->Controller->set('meta_templates', $metaTemplates);
|
$this->Controller->set('meta_templates', $metaTemplates);
|
||||||
|
$this->Controller->set('meta_templates_enabled', array_filter($metaTemplates, function($template) {
|
||||||
|
return $template['enabled'];
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
if (true) { // check if stats are requested
|
if (true) { // check if stats are requested
|
||||||
$modelStatistics = [];
|
$modelStatistics = [];
|
||||||
|
|
|
@ -98,7 +98,7 @@ class AuthKeycloakBehavior extends Behavior
|
||||||
public function getUserIdByUsername(string $username)
|
public function getUserIdByUsername(string $username)
|
||||||
{
|
{
|
||||||
$response = $this->restApiRequest(
|
$response = $this->restApiRequest(
|
||||||
'%s/admin/realms/%s/users/?username=' . urlencode($username),
|
'%s/admin/realms/%s/users/?username=' . $this->urlencodeEscapeForSprintf($username),
|
||||||
[],
|
[],
|
||||||
'GET'
|
'GET'
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace App\Model\Table;
|
||||||
|
|
||||||
use App\Model\Table\AppTable;
|
use App\Model\Table\AppTable;
|
||||||
use Cake\ORM\Table;
|
use Cake\ORM\Table;
|
||||||
|
use Cake\ORM\RulesChecker;
|
||||||
use Cake\Validation\Validator;
|
use Cake\Validation\Validator;
|
||||||
|
|
||||||
class AlignmentsTable extends AppTable
|
class AlignmentsTable extends AppTable
|
||||||
|
@ -24,7 +25,16 @@ class AlignmentsTable extends AppTable
|
||||||
->notEmptyString('organisation_id')
|
->notEmptyString('organisation_id')
|
||||||
->requirePresence(['individual_id', 'organisation_id'], 'create');
|
->requirePresence(['individual_id', 'organisation_id'], 'create');
|
||||||
return $validator;
|
return $validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function buildRules(RulesChecker $rules): RulesChecker
|
||||||
|
{
|
||||||
|
$rules->add($rules->isUnique(
|
||||||
|
['individual_id', 'organisation_id', 'type'],
|
||||||
|
__('This alignment already exists.')
|
||||||
|
));
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
|
||||||
public function setAlignment($organisation_id, $individual_id, $type): void
|
public function setAlignment($organisation_id, $individual_id, $type): void
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,12 +63,15 @@ class PermissionLimitationsTable extends AppTable
|
||||||
])->count();
|
])->count();
|
||||||
}
|
}
|
||||||
if (isset($data['global'])) {
|
if (isset($data['global'])) {
|
||||||
|
$conditions = [
|
||||||
|
'scope' => 'user',
|
||||||
|
'field' => $field,
|
||||||
|
];
|
||||||
|
if (!empty($ownOrgUserIds)) {
|
||||||
|
$conditions['parent_id IN'] = array_values($ownOrgUserIds);
|
||||||
|
}
|
||||||
$limitations[$field]['organisation']['current'] = $MetaFields->find('all', [
|
$limitations[$field]['organisation']['current'] = $MetaFields->find('all', [
|
||||||
'conditions' => [
|
'conditions' => $conditions,
|
||||||
'scope' => 'user',
|
|
||||||
'field' => $field,
|
|
||||||
'parent_id IN' => array_values($ownOrgUserIds)
|
|
||||||
]
|
|
||||||
])->count();
|
])->count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"version": "1.10",
|
"version": "1.11",
|
||||||
"application": "Cerebrate"
|
"application": "Cerebrate"
|
||||||
}
|
}
|
||||||
|
|
|
@ -2008,6 +2008,12 @@ class BoostrapDropdownMenu extends BootstrapGeneric
|
||||||
}
|
}
|
||||||
|
|
||||||
$classes = ['dropdown-item'];
|
$classes = ['dropdown-item'];
|
||||||
|
if (!empty($entry['class'])) {
|
||||||
|
if (!is_array($entry['class'])) {
|
||||||
|
$entry['class'] = [$entry['class']];
|
||||||
|
}
|
||||||
|
$classes = array_merge($classes, $entry['class']);
|
||||||
|
}
|
||||||
$params = ['href' => '#'];
|
$params = ['href' => '#'];
|
||||||
|
|
||||||
if (!empty($entry['menu'])) {
|
if (!empty($entry['menu'])) {
|
||||||
|
|
|
@ -10,7 +10,8 @@ echo $this->element('genericElements/Form/genericForm', array(
|
||||||
array(
|
array(
|
||||||
'field' => ($scope === 'individuals' ? 'organisation_id' : 'individual_id'),
|
'field' => ($scope === 'individuals' ? 'organisation_id' : 'individual_id'),
|
||||||
'options' => ($scope === 'individuals' ? $organisations : $individuals),
|
'options' => ($scope === 'individuals' ? $organisations : $individuals),
|
||||||
'type' => 'select'
|
'type' => 'dropdown',
|
||||||
|
'select2' => true,
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'field' => 'type'
|
'field' => 'type'
|
||||||
|
|
|
@ -19,6 +19,9 @@ if (!empty($fieldData['label'])) {
|
||||||
if ($controlParams['options'] instanceof \Cake\ORM\Query) {
|
if ($controlParams['options'] instanceof \Cake\ORM\Query) {
|
||||||
$controlParams['options'] = $controlParams['options']->all()->toList();
|
$controlParams['options'] = $controlParams['options']->all()->toList();
|
||||||
}
|
}
|
||||||
|
if (!empty($fieldData['select2'])) {
|
||||||
|
$controlParams['class'] .= ' select2-input';
|
||||||
|
}
|
||||||
if (in_array('_custom', array_keys($controlParams['options']))) {
|
if (in_array('_custom', array_keys($controlParams['options']))) {
|
||||||
$customInputValue = $this->Form->getSourceValue($fieldData['field']);
|
$customInputValue = $this->Form->getSourceValue($fieldData['field']);
|
||||||
if (!in_array($customInputValue, $controlParams['options'])) {
|
if (!in_array($customInputValue, $controlParams['options'])) {
|
||||||
|
@ -49,6 +52,15 @@ echo $this->FormFieldMassage->prepareFormElement($this->Form, $controlParams, $f
|
||||||
$select.attr('onclick', 'toggleFreetextSelectField(this)')
|
$select.attr('onclick', 'toggleFreetextSelectField(this)')
|
||||||
$select.parent().find('input.custom-value').attr('oninput', 'updateAssociatedSelect(this)')
|
$select.parent().find('input.custom-value').attr('oninput', 'updateAssociatedSelect(this)')
|
||||||
updateAssociatedSelect($select.parent().find('input.custom-value')[0])
|
updateAssociatedSelect($select.parent().find('input.custom-value')[0])
|
||||||
|
<?php if (!empty($fieldData['select2'])) : ?>
|
||||||
|
let $container = $select.closest('.modal-dialog')
|
||||||
|
if ($container.length == 0) {
|
||||||
|
$container = $(document.body)
|
||||||
|
}
|
||||||
|
$select.select2({
|
||||||
|
dropdownParent: $container,
|
||||||
|
})
|
||||||
|
<?php endif; ?>
|
||||||
})
|
})
|
||||||
|
|
||||||
})()
|
})()
|
||||||
|
|
|
@ -19,27 +19,31 @@ $availableColumnsHtml = $this->element('/genericElements/ListTopBar/group_table_
|
||||||
$metaTemplateColumnMenu = [];
|
$metaTemplateColumnMenu = [];
|
||||||
if (!empty($meta_templates)) {
|
if (!empty($meta_templates)) {
|
||||||
$metaTemplateColumnMenu[] = ['header' => true, 'text' => __('Meta Templates'), 'icon' => 'object-group',];
|
$metaTemplateColumnMenu[] = ['header' => true, 'text' => __('Meta Templates'), 'icon' => 'object-group',];
|
||||||
foreach ($meta_templates as $meta_template) {
|
if (empty($meta_templates_enabled)) {
|
||||||
$numberActiveMetaField = !empty($tableSettings['visible_meta_column'][$meta_template->id]) ? count($tableSettings['visible_meta_column'][$meta_template->id]) : 0;
|
$metaTemplateColumnMenu[] = ['header' => false, 'text' => __('- No enabled Meta Templates found -'), 'class' => ['disabled', 'muted']];
|
||||||
$metaTemplateColumnMenu[] = [
|
} else {
|
||||||
'text' => $meta_template->name,
|
foreach ($meta_templates_enabled as $meta_template) {
|
||||||
'sup' => $meta_template->version,
|
$numberActiveMetaField = !empty($tableSettings['visible_meta_column'][$meta_template->id]) ? count($tableSettings['visible_meta_column'][$meta_template->id]) : 0;
|
||||||
'badge' => [
|
$metaTemplateColumnMenu[] = [
|
||||||
'text' => $numberActiveMetaField,
|
'text' => $meta_template->name,
|
||||||
'variant' => 'secondary',
|
'sup' => $meta_template->version,
|
||||||
'title' => __n('{0} meta-field active for this meta-template', '{0} meta-fields active for this meta-template', $numberActiveMetaField, $numberActiveMetaField),
|
'badge' => [
|
||||||
],
|
'text' => $numberActiveMetaField,
|
||||||
'keepOpen' => true,
|
'variant' => 'secondary',
|
||||||
'menu' => [
|
'title' => __n('{0} meta-field active for this meta-template', '{0} meta-fields active for this meta-template', $numberActiveMetaField, $numberActiveMetaField),
|
||||||
[
|
],
|
||||||
'html' => $this->element('/genericElements/ListTopBar/group_table_action/hiddenMetaColumns', [
|
'keepOpen' => true,
|
||||||
'tableSettings' => $tableSettings,
|
'menu' => [
|
||||||
'table_setting_id' => $data['table_setting_id'],
|
[
|
||||||
'meta_template' => $meta_template,
|
'html' => $this->element('/genericElements/ListTopBar/group_table_action/hiddenMetaColumns', [
|
||||||
])
|
'tableSettings' => $tableSettings,
|
||||||
]
|
'table_setting_id' => $data['table_setting_id'],
|
||||||
],
|
'meta_template' => $meta_template,
|
||||||
];
|
])
|
||||||
|
]
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$indexColumnMenu = array_merge(
|
$indexColumnMenu = array_merge(
|
||||||
|
|
Loading…
Reference in New Issue