chg: [mailinglist] Improved feature
Previously, emails were stored as json encoded string. To add more flexibility and prevent inconsistencies (such as propagating email changes to the mailing list), it has been moved to a table.pull/93/head
parent
fe9fbe2e99
commit
4ef6738053
|
@ -112,11 +112,43 @@ class MailingLists extends AbstractMigration
|
|||
'null' => true,
|
||||
'signed' => false,
|
||||
'length' => 10,
|
||||
]);
|
||||
])
|
||||
->addColumn('include_primary_email', 'boolean', [
|
||||
'default' => 1,
|
||||
'null' => false,
|
||||
'comment' => 'Should the primary email address by included in the mailing list'
|
||||
])
|
||||
->addForeignKey('mailing_list_id', 'mailing_lists', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE'])
|
||||
->addForeignKey('individual_id', 'individuals', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE']);
|
||||
|
||||
$mailinglists_individuals->addIndex(['mailing_list_id', 'individual_id'], ['unique' => true]);
|
||||
|
||||
$mailinglists_individuals->create();
|
||||
|
||||
|
||||
$mailinglists_metafields = $this->table('mailing_lists_meta_fields', [
|
||||
'signed' => false,
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
]);
|
||||
|
||||
$mailinglists_metafields
|
||||
->addColumn('mailing_list_id', 'integer', [
|
||||
'default' => null,
|
||||
'null' => true,
|
||||
'signed' => false,
|
||||
'length' => 10,
|
||||
])
|
||||
->addColumn('meta_field_id', 'integer', [
|
||||
'default' => null,
|
||||
'null' => true,
|
||||
'signed' => false,
|
||||
'length' => 10,
|
||||
])
|
||||
->addPrimaryKey(['mailing_list_id', 'meta_field_id'])
|
||||
->addForeignKey('mailing_list_id', 'mailing_lists', 'id', ['delete'=> 'CASCADE', 'update'=> 'CASCADE'])
|
||||
->addForeignKey('meta_field_id', 'meta_fields', 'id', ['delete'=> 'CASCADE', 'update'=> 'CASCADE']);
|
||||
|
||||
$mailinglists_metafields->create();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "Cerebrate Individuals extended",
|
||||
"namespace": "cerebrate",
|
||||
"description": "Template to extend fields of individuals",
|
||||
"version": 1,
|
||||
"scope": "individual",
|
||||
"uuid": "3bc374c8-3cdd-4900-823e-cc9100ad5179",
|
||||
"source": "Cerebrate",
|
||||
"metaFields": [
|
||||
{
|
||||
"field": "alternate_email",
|
||||
"type": "text",
|
||||
"multiple": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -676,16 +676,7 @@ class CRUDComponent extends Component
|
|||
$this->Controller->set('quickFilter', empty($quickFilterFields) ? [] : $quickFilterFields);
|
||||
if (!empty($params['quickFilter']) && !empty($quickFilterFields)) {
|
||||
$this->Controller->set('quickFilterValue', $params['quickFilter']);
|
||||
foreach ($quickFilterFields as $filterField) {
|
||||
$likeCondition = false;
|
||||
if (is_array($filterField)) {
|
||||
$likeCondition = reset($filterField);
|
||||
$filterFieldName = array_key_first($filterField);
|
||||
$queryConditions[$filterFieldName . ' LIKE'] = '%' . $params['quickFilter'] .'%';
|
||||
} else {
|
||||
$queryConditions[$filterField] = $params['quickFilter'];
|
||||
}
|
||||
}
|
||||
$queryConditions = $this->genQuickFilterConditions($params, $query, $quickFilterFields);
|
||||
$query->where(['OR' => $queryConditions]);
|
||||
} else {
|
||||
$this->Controller->set('quickFilterValue', '');
|
||||
|
@ -693,6 +684,28 @@ class CRUDComponent extends Component
|
|||
return $query;
|
||||
}
|
||||
|
||||
public function genQuickFilterConditions(array $params, \Cake\ORM\Query $query, array $quickFilterFields): array
|
||||
{
|
||||
$queryConditions = [];
|
||||
foreach ($quickFilterFields as $filterField) {
|
||||
$likeCondition = false;
|
||||
if (is_array($filterField)) {
|
||||
reset($filterField);
|
||||
$filterFieldName = array_key_first($filterField);
|
||||
if (!empty($filterField[$filterFieldName])) {
|
||||
$queryConditions[$filterFieldName . ' LIKE'] = '%' . $params['quickFilter'] . '%';
|
||||
} else {
|
||||
$queryConditions[$filterField] = $params['quickFilter'];
|
||||
}
|
||||
}
|
||||
$query->where(['OR' => $queryConditions]);
|
||||
} else {
|
||||
$queryConditions[$filterField] = $params['quickFilter'];
|
||||
}
|
||||
}
|
||||
return $queryConditions;
|
||||
}
|
||||
|
||||
protected function setFilters($params, \Cake\ORM\Query $query, array $options): \Cake\ORM\Query
|
||||
{
|
||||
$filteringLabel = !empty($params['filteringLabel']) ? $params['filteringLabel'] : '';
|
||||
|
|
|
@ -26,15 +26,15 @@ class ParamHandlerComponent extends Component
|
|||
$queryString = str_replace('.', '_', $filter);
|
||||
$queryString = str_replace(' ', '_', $queryString);
|
||||
if ($this->request->getQuery($queryString) !== null) {
|
||||
$parsedParams[$filter] = $this->request->getQuery($queryString);
|
||||
$parsedParams[$filter] = trim($this->request->getQuery($queryString));
|
||||
continue;
|
||||
}
|
||||
if (($this->request->getQuery($filter)) !== null) {
|
||||
$parsedParams[$filter] = $this->request->getQuery($filter);
|
||||
$parsedParams[$filter] = trim($this->request->getQuery($filter));
|
||||
continue;
|
||||
}
|
||||
if (($this->request->is('post') || $this->request->is('put')) && $this->request->getData($filter) !== null) {
|
||||
$parsedParams[$filter] = $this->request->getData($filter);
|
||||
$parsedParams[$filter] = trim($this->request->getData($filter));
|
||||
}
|
||||
}
|
||||
return $parsedParams;
|
||||
|
|
|
@ -6,13 +6,15 @@ use Cake\Utility\Inflector;
|
|||
use Cake\Utility\Hash;
|
||||
use Cake\Utility\Text;
|
||||
use \Cake\Database\Expression\QueryExpression;
|
||||
use Cake\Error\Debugger;
|
||||
use Cake\ORM\Query;
|
||||
use Cake\ORM\Entity;
|
||||
use Exception;
|
||||
|
||||
class MailingListsController extends AppController
|
||||
{
|
||||
public $filterFields = ['MailingLists.uuid', 'MailingLists.name', 'description', 'releasability'];
|
||||
public $quickFilterFields = ['MailingLists.uuid', ['MailingLists.name' => true], ['description' => true], ['releasability' => true]];
|
||||
public $containFields = ['Users', 'Individuals'];
|
||||
public $containFields = ['Users', 'Individuals', 'MetaFields'];
|
||||
|
||||
public function index()
|
||||
{
|
||||
|
@ -72,45 +74,151 @@ class MailingListsController extends AppController
|
|||
|
||||
public function listIndividuals($mailinglist_id)
|
||||
{
|
||||
$individuals = $this->MailingLists->get($mailinglist_id, [
|
||||
'contain' => 'Individuals'
|
||||
])->individuals;
|
||||
$params = $this->ParamHandler->harvestParams(['quickFilter']);
|
||||
if (!empty($params['quickFilter'])) {
|
||||
// foreach ($sharingGroup['sharing_group_orgs'] as $k => $org) {
|
||||
// if (strpos($org['name'], $params['quickFilter']) === false) {
|
||||
// unset($sharingGroup['sharing_group_orgs'][$k]);
|
||||
// }
|
||||
// }
|
||||
// $sharingGroup['sharing_group_orgs'] = array_values($sharingGroup['sharing_group_orgs']);
|
||||
$quickFilter = [
|
||||
'uuid',
|
||||
['first_name' => true],
|
||||
['last_name' => true],
|
||||
];
|
||||
$quickFilterUI = array_merge($quickFilter, [
|
||||
['Registered emails' => true],
|
||||
]);
|
||||
$filters = ['uuid', 'first_name', 'last_name', 'quickFilter'];
|
||||
$queryParams = $this->ParamHandler->harvestParams($filters);
|
||||
$activeFilters = $queryParams['quickFilter'] ?? [];
|
||||
|
||||
$mailingList = $this->MailingLists->find()
|
||||
->where(['MailingLists.id' => $mailinglist_id])
|
||||
->contain('MetaFields')
|
||||
->first();
|
||||
|
||||
$matchingMetaFieldParentIDs = [];
|
||||
// Collect individuals having a matching meta_field
|
||||
foreach ($mailingList->meta_fields as $metaField) {
|
||||
if (
|
||||
empty($queryParams['quickFilter']) ||
|
||||
(
|
||||
str_contains($metaField->field, 'email') &&
|
||||
str_contains($metaField->value, $queryParams['quickFilter'])
|
||||
)
|
||||
) {
|
||||
$matchingMetaFieldParentIDs[$metaField->parent_id] = true;
|
||||
}
|
||||
}
|
||||
$matchingMetaFieldParentIDs = array_keys($matchingMetaFieldParentIDs);
|
||||
$mailingList = $this->MailingLists->loadInto($mailingList, [
|
||||
'Individuals' => function (Query $q) use ($queryParams, $quickFilter, $matchingMetaFieldParentIDs) {
|
||||
$conditions = [];
|
||||
if (!empty($queryParams)) {
|
||||
$conditions = $this->CRUD->genQuickFilterConditions($queryParams, $q, $quickFilter);
|
||||
}
|
||||
if (!empty($matchingMetaFieldParentIDs)) {
|
||||
$conditions[] = function (QueryExpression $exp) use ($matchingMetaFieldParentIDs) {
|
||||
return $exp->in('Individuals.id', $matchingMetaFieldParentIDs);
|
||||
};
|
||||
}
|
||||
if (!empty($queryParams['quickFilter'])) {
|
||||
$conditions[] = [
|
||||
'MailingListsIndividuals.include_primary_email' => true,
|
||||
'Individuals.email LIKE' => "%{$queryParams['quickFilter']}%"
|
||||
];
|
||||
}
|
||||
$q->where([
|
||||
'OR' => $conditions
|
||||
]);
|
||||
return $q;
|
||||
}
|
||||
]);
|
||||
$mailingList->injectRegisteredEmailsIntoIndividuals();
|
||||
if ($this->ParamHandler->isRest()) {
|
||||
return $this->RestResponse->viewData($individuals, 'json');
|
||||
return $this->RestResponse->viewData($mailingList->individuals, 'json');
|
||||
}
|
||||
$individuals = $this->CustomPagination->paginate($mailingList->individuals);
|
||||
$this->set('mailing_list_id', $mailinglist_id);
|
||||
$this->set('quickFilter', $quickFilterUI);
|
||||
$this->set('activeFilters', $activeFilters);
|
||||
$this->set('quickFilterValue', $queryParams['quickFilter'] ?? '');
|
||||
$this->set('individuals', $individuals);
|
||||
}
|
||||
|
||||
public function addIndividual($mailinglist_id)
|
||||
{
|
||||
$mailingList = $this->MailingLists->get($mailinglist_id, [
|
||||
'contain' => 'Individuals'
|
||||
'contain' => ['Individuals', 'MetaFields']
|
||||
]);
|
||||
$conditions = [];
|
||||
$linkedIndividualsIDs = Hash::extract($mailingList, 'individuals.{n}.id');
|
||||
$conditions = [
|
||||
'id NOT IN' => $linkedIndividualsIDs
|
||||
];
|
||||
$dropdownData = [
|
||||
'individuals' => $this->MailingLists->Individuals->getTarget()->find('list', [
|
||||
'sort' => ['name' => 'asc'],
|
||||
'conditions' => $conditions
|
||||
])
|
||||
'individuals' => $this->MailingLists->Individuals->getTarget()->find()
|
||||
->order(['first_name' => 'asc'])
|
||||
->where($conditions)
|
||||
->all()
|
||||
->combine('id', 'full_name')
|
||||
->toArray()
|
||||
];
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
$memberIDs = $this->request->getData()['individuals'];
|
||||
$chosen_emails = $this->request->getData()['chosen_emails'];
|
||||
if (!empty($chosen_emails)) {
|
||||
$chosen_emails = json_decode($chosen_emails, true);
|
||||
$chosen_emails = !is_null($chosen_emails) ? $chosen_emails : [];
|
||||
} else {
|
||||
$chosen_emails = [];
|
||||
}
|
||||
$members = $this->MailingLists->Individuals->getTarget()->find()->where([
|
||||
'id IN' => $memberIDs
|
||||
])->all()->toArray();
|
||||
$success = (bool)$this->MailingLists->Individuals->link($mailingList, $members);
|
||||
$memberToLink = [];
|
||||
$memberToUpdate = [];
|
||||
foreach ($members as $i => $member) {
|
||||
$includePrimary = in_array('primary', $chosen_emails[$member->id]);
|
||||
$chosen_emails[$member->id] = array_filter($chosen_emails[$member->id], function($entry) {
|
||||
return $entry != 'primary';
|
||||
});
|
||||
$members[$i]->_joinData = new Entity(['include_primary_email' => $includePrimary]);
|
||||
if (in_array($member->id, $linkedIndividualsIDs)) { // individual already in the list
|
||||
// $memberToUpdate[] = $members[$i];
|
||||
} else { // new individual to add to the list
|
||||
$memberToLink[] = $members[$i];
|
||||
}
|
||||
}
|
||||
|
||||
// save new individuals
|
||||
if (!empty($memberToLink)) {
|
||||
$success = (bool)$this->MailingLists->Individuals->link($mailingList, $memberToLink);
|
||||
if ($success && !empty($chosen_emails[$member->id])) { // Include any remaining emails from the metaFields
|
||||
$emailsFromMetaFields = $this->MailingLists->MetaFields->find()->where([
|
||||
'id IN' => $chosen_emails[$member->id]
|
||||
])->all()->toArray();
|
||||
$success = (bool)$this->MailingLists->MetaFields->link($mailingList, $emailsFromMetaFields);
|
||||
}
|
||||
}
|
||||
|
||||
// update existing individuals
|
||||
if (!empty($memberToUpdate)) {
|
||||
$memberToUpdateIDs = Hash::extract($memberToUpdate, '{n}.id');
|
||||
$metaFieldsToRemove = array_filter($mailingList->meta_fields, function($metaField) use ($memberToUpdateIDs) {
|
||||
return in_array($metaField->parent_id, $memberToUpdateIDs);
|
||||
});
|
||||
|
||||
// Trying to update `include_primary`...
|
||||
// $success = (bool)$this->MailingLists->Individuals->unlink($mailingList, $memberToUpdate, ['atomic' => false]);
|
||||
// $success = $success && (bool)$this->MailingLists->Individuals->link($mailingList, $memberToUpdate);
|
||||
|
||||
// Remove and add relevant meta fields
|
||||
// $success = (bool)$this->MailingLists->MetaFields->unlink($mailingList, $metaFieldsToRemove, ['atomic' => false]);
|
||||
// if ($success && !empty($chosen_emails[$member->id])) { // Include any remaining emails from the metaFields
|
||||
// $emailsFromMetaFields = $this->MailingLists->MetaFields->find()->where([
|
||||
// 'id IN' => $chosen_emails[$member->id]
|
||||
// ])->all()->toArray();
|
||||
// $success = (bool)$this->MailingLists->MetaFields->link($mailingList, $emailsFromMetaFields);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
if ($success) {
|
||||
$message = __n('%s individual added to the mailing list.', '%s Individuals added to the mailing list.', count($members), count($members));
|
||||
$message = __n('{0} individual added to the mailing list.', '{0} Individuals added to the mailing list.', count($members), count($members));
|
||||
$mailingList = $this->MailingLists->get($mailingList->id);
|
||||
} else {
|
||||
$message = __n('The individual could not be added to the mailing list.', 'The Individuals could not be added to the mailing list.', count($members));
|
||||
|
@ -129,7 +237,7 @@ class MailingListsController extends AppController
|
|||
public function removeIndividual($mailinglist_id, $individual_id=null)
|
||||
{
|
||||
$mailingList = $this->MailingLists->get($mailinglist_id, [
|
||||
'contain' => 'Individuals'
|
||||
'contain' => ['Individuals', 'MetaFields']
|
||||
]);
|
||||
$individual = [];
|
||||
if (!is_null($individual_id)) {
|
||||
|
@ -138,13 +246,20 @@ class MailingListsController extends AppController
|
|||
if ($this->request->is('post') || $this->request->is('delete')) {
|
||||
$success = false;
|
||||
if (!is_null($individual_id)) {
|
||||
$individual = $this->MailingLists->Individuals->get($individual_id);
|
||||
$success = (bool)$this->MailingLists->Individuals->unlink($mailingList, [$individual]);
|
||||
$individualToRemove = $this->MailingLists->Individuals->get($individual_id);
|
||||
$metaFieldsToRemove = $this->MailingLists->MetaFields->find()->where([
|
||||
'id IN' => Hash::extract($mailingList, 'meta_fields.{n}.id'),
|
||||
'parent_id' => $individual_id,
|
||||
])->all()->toArray();
|
||||
$success = (bool)$this->MailingLists->Individuals->unlink($mailingList, [$individualToRemove]);
|
||||
if ($success && !empty($metaFieldsToRemove)) {
|
||||
$success = (bool)$this->MailingLists->MetaFields->unlink($mailingList, $metaFieldsToRemove);
|
||||
}
|
||||
if ($success) {
|
||||
$message = __('Individual removed from the mailing list.');
|
||||
$message = __('{0} removed from the mailing list.', $individualToRemove->full_name);
|
||||
$mailingList = $this->MailingLists->get($mailingList->id);
|
||||
} else {
|
||||
$message = __n('Individual could not be removed from the mailing list.');
|
||||
$message = __n('{0} could not be removed from the mailing list.', $individual->full_name);
|
||||
}
|
||||
$this->CRUD->setResponseForController('remove_individuals', $success, $message, $mailingList, $mailingList->getErrors());
|
||||
} else {
|
||||
|
@ -155,22 +270,27 @@ class MailingListsController extends AppController
|
|||
if (empty($params['ids'])) {
|
||||
throw new NotFoundException(__('Invalid {0}.', Inflector::singularize($this->MailingLists->Individuals->getAlias())));
|
||||
}
|
||||
$individuals = $this->MailingLists->Individuals->find()->where([
|
||||
$individualsToRemove = $this->MailingLists->Individuals->find()->where([
|
||||
'id IN' => array_map('intval', $params['ids'])
|
||||
])->all()->toArray();
|
||||
$metaFieldsToRemove = $this->MailingLists->MetaFields->find()->where([
|
||||
'id IN' => Hash::extract($mailingList, 'meta_fields.{n}.id'),
|
||||
'parent_id IN' => Hash::extract($mailingList, 'meta_fields.{n}.id')
|
||||
])->all()->toArray();
|
||||
dd($metaFieldsToRemove);
|
||||
$unlinkSuccesses = 0;
|
||||
foreach ($individuals as $individual) {
|
||||
$success = (bool)$this->MailingLists->Individuals->unlink($mailingList, [$individual]);
|
||||
foreach ($individualsToRemove as $individualToRemove) {
|
||||
$success = (bool)$this->MailingLists->Individuals->unlink($mailingList, [$individualToRemove]);
|
||||
$results[] = $success;
|
||||
if ($success) {
|
||||
$unlinkSuccesses++;
|
||||
}
|
||||
}
|
||||
$mailingList = $this->MailingLists->get($mailingList->id);
|
||||
$success = $unlinkSuccesses == count($individuals);
|
||||
$success = $unlinkSuccesses == count($individualsToRemove);
|
||||
$message = __(
|
||||
'{0} {1} have been removed.',
|
||||
$unlinkSuccesses == count($individuals) ? __('All') : sprintf('%s / %s', $unlinkSuccesses, count($individuals)),
|
||||
$unlinkSuccesses == count($individualsToRemove) ? __('All') : sprintf('%s / %s', $unlinkSuccesses, count($individualsToRemove)),
|
||||
Inflector::singularize($this->MailingLists->Individuals->getAlias())
|
||||
);
|
||||
$this->CRUD->setResponseForController('remove_individuals', $success, $message, $mailingList, []);
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Model\Entity;
|
||||
|
||||
use App\Model\Entity\AppModel;
|
||||
use Cake\ORM\Entity;
|
||||
|
||||
class MailingList extends AppModel
|
||||
{
|
||||
|
@ -18,4 +17,35 @@ class MailingList extends AppModel
|
|||
'uuid' => true,
|
||||
'user_id' => true,
|
||||
];
|
||||
|
||||
private $metaFieldsByParentId = [];
|
||||
|
||||
public function injectRegisteredEmailsIntoIndividuals()
|
||||
{
|
||||
if (empty($this->individuals)) {
|
||||
return;
|
||||
}
|
||||
if (!empty($this->meta_fields)) {
|
||||
foreach ($this->meta_fields as $meta_field) {
|
||||
$this->metaFieldsByParentId[$meta_field->parent_id][] = $meta_field;
|
||||
}
|
||||
}
|
||||
foreach ($this->individuals as $i => $individual) {
|
||||
$this->individuals[$i]->mailinglist_emails = $this->collectEmailsForMailingList($individual);
|
||||
}
|
||||
}
|
||||
|
||||
protected function collectEmailsForMailingList($individual)
|
||||
{
|
||||
$emails = [];
|
||||
if (!empty($individual['_joinData']) && !empty($individual['_joinData']['include_primary_email'])) {
|
||||
$emails[] = $individual->email;
|
||||
}
|
||||
if (!empty($this->metaFieldsByParentId[$individual->id])) {
|
||||
foreach ($this->metaFieldsByParentId[$individual->id] as $metaField) {
|
||||
$emails[] = $metaField->value;
|
||||
}
|
||||
}
|
||||
return $emails;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,15 @@ class IndividualsTable extends AppTable
|
|||
$this->belongsToMany('Organisations', [
|
||||
'through' => 'Alignments',
|
||||
]);
|
||||
|
||||
$this->hasMany('MetaFields')
|
||||
->setForeignKey('parent_id')
|
||||
->setBindingKey('id')
|
||||
->setConditions([
|
||||
'MetaFields.scope' => 'individual'
|
||||
])
|
||||
->setDependent(true);
|
||||
|
||||
$this->belongsToMany('MailingLists');
|
||||
$this->setDisplayField('email');
|
||||
}
|
||||
|
|
|
@ -18,19 +18,12 @@ class MailingListsTable extends AppTable
|
|||
$this->belongsTo(
|
||||
'Users'
|
||||
);
|
||||
// $this->belongsToMany(
|
||||
// 'Individuals',
|
||||
// [
|
||||
// 'className' => 'Individuals',
|
||||
// 'foreignKey' => 'individual_id',
|
||||
// 'joinTable' => 'sgo',
|
||||
// 'targetForeignKey' => 'organisation_id'
|
||||
// ]
|
||||
// );
|
||||
|
||||
$this->belongsToMany('Individuals', [
|
||||
'joinTable' => 'mailing_lists_individuals',
|
||||
]);
|
||||
// Change to HasMany?
|
||||
$this->belongsToMany('MetaFields');
|
||||
|
||||
$this->setDisplayField('name');
|
||||
}
|
||||
|
|
|
@ -15,6 +15,12 @@ class MetaFieldsTable extends AppTable
|
|||
$this->setDisplayField('field');
|
||||
$this->belongsTo('MetaTemplates');
|
||||
$this->belongsTo('MetaTemplateFields');
|
||||
$this->belongsTo('Individuals')
|
||||
->setForeignKey('parent_id')
|
||||
->setBindingKey('id')
|
||||
->setConditions([
|
||||
'scope' => 'individual'
|
||||
]);
|
||||
}
|
||||
|
||||
public function validationDefault(Validator $validator): Validator
|
||||
|
|
|
@ -1,24 +1,121 @@
|
|||
<?php
|
||||
echo $this->element('genericElements/Form/genericForm', [
|
||||
'data' => [
|
||||
'title' => __('Add members to mailing list {0} [{1}]', h($mailingList->name), h($mailingList->id)),
|
||||
// 'description' => __('Mailing list are email distribution lists containing individuals.'),
|
||||
'model' => 'MailingLists',
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'individuals',
|
||||
'type' => 'dropdown',
|
||||
'multiple' => true,
|
||||
'select2' => true,
|
||||
'label' => __('Members'),
|
||||
'class' => 'select2-input',
|
||||
'options' => $dropdownData['individuals']
|
||||
],
|
||||
echo $this->element('genericElements/Form/genericForm', [
|
||||
'data' => [
|
||||
'title' => __('Add members to `{0}` [{1}]', h($mailingList->name), h($mailingList->id)),
|
||||
'model' => 'MailingLists',
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'individuals',
|
||||
'type' => 'dropdown',
|
||||
'multiple' => true,
|
||||
'select2' => true,
|
||||
'label' => __('Members'),
|
||||
'class' => 'select2-input',
|
||||
'options' => $dropdownData['individuals']
|
||||
],
|
||||
'submit' => [
|
||||
'action' => $this->request->getParam('action')
|
||||
[
|
||||
'field' => 'chosen_emails',
|
||||
'type' => 'text',
|
||||
'templates' => ['inputContainer' => '<div class="row mb-3 d-none">{{content}}</div>'],
|
||||
],
|
||||
'<div class="alternate-emails-container panel d-none"></div>'
|
||||
],
|
||||
]);
|
||||
'submit' => [
|
||||
'action' => $this->request->getParam('action')
|
||||
],
|
||||
],
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
let individuals = {}
|
||||
$('#individuals-field').on('select2:select select2:unselect', function(e) {
|
||||
const selected = e.params.data;
|
||||
fetchIndividual(selected.id).then(() => {
|
||||
udpateAvailableEmails($(e.target).select2('data'));
|
||||
})
|
||||
});
|
||||
|
||||
function udpateAvailableEmails(selected) {
|
||||
const $container = $('.alternate-emails-container')
|
||||
$container.empty()
|
||||
$container.toggleClass('d-none', selected.length == 0)
|
||||
selected.forEach(selectData => {
|
||||
const individual = individuals[selectData.id]
|
||||
let formContainers = [genForContainer(`primary-${individual.id}`, individual.email, '<?= __('primary email') ?>', true, true)]
|
||||
if (individual.alternate_emails !== undefined) {
|
||||
individual.alternate_emails.forEach(alternateEmail => {
|
||||
formContainers.push(
|
||||
genForContainer(alternateEmail.id, alternateEmail.value, `${alternateEmail.metaTemplate.namespace} :: ${alternateEmail.metaTemplate.name}`, false)
|
||||
)
|
||||
})
|
||||
}
|
||||
const $individualFullName = $('<div/>').addClass('fw-light fs-5 mt-2').text(individual.full_name)
|
||||
const $individualContainer = $('<div/>').addClass('individual-container').data('individualid', individual.id)
|
||||
.append($individualFullName).append(formContainers)
|
||||
$container.append($individualContainer)
|
||||
registerChangeListener()
|
||||
injectSelectedEmailsIntoForm()
|
||||
});
|
||||
}
|
||||
|
||||
function genForContainer(id, email, email_source, is_primary = true, checked = false) {
|
||||
const $formContainer = $('<div/>').addClass('form-check ms-2')
|
||||
$formContainer.append(
|
||||
$('<input/>').addClass('form-check-input').attr('type', 'checkbox').attr('id', `individual-${id}`)
|
||||
.attr('value', is_primary ? 'primary' : id).prop('checked', checked),
|
||||
$('<label/>').addClass('form-check-label').attr('for', `individual-${id}`).append(
|
||||
$('<span/>').text(email),
|
||||
$('<span/>').addClass('fw-light fs-8 align-middle ms-2').text(`${email_source}`)
|
||||
)
|
||||
)
|
||||
return $formContainer
|
||||
}
|
||||
|
||||
function registerChangeListener() {
|
||||
$('.alternate-emails-container .individual-container input')
|
||||
.off('change.udpate')
|
||||
.on('change.udpate', injectSelectedEmailsIntoForm)
|
||||
}
|
||||
|
||||
function injectSelectedEmailsIntoForm() {
|
||||
const selectedEmails = getSelectedEmails()
|
||||
$('#chosen_emails-field').val(JSON.stringify(selectedEmails))
|
||||
}
|
||||
|
||||
function getSelectedEmails() {
|
||||
selectedEmails = {}
|
||||
$('.alternate-emails-container .individual-container').each(function() {
|
||||
const $individualContainer = $(this)
|
||||
const individualId = $individualContainer.data('individualid')
|
||||
selectedEmails[individualId] = []
|
||||
const $inputs = $individualContainer.find('input:checked').each(function() {
|
||||
selectedEmails[individualId].push($(this).val())
|
||||
})
|
||||
})
|
||||
return selectedEmails
|
||||
}
|
||||
|
||||
function fetchIndividual(id) {
|
||||
const urlGet = `/individuals/view/${id}`
|
||||
const options = {
|
||||
statusNode: $('.alternate-emails-container')
|
||||
}
|
||||
if (individuals[id] !== undefined) {
|
||||
return Promise.resolve(individuals[id])
|
||||
}
|
||||
return AJAXApi.quickFetchJSON(urlGet, options)
|
||||
.then(individual => {
|
||||
individuals[individual.id] = individual
|
||||
})
|
||||
.catch((e) => {
|
||||
UI.toast({
|
||||
variant: 'danger',
|
||||
text: '<?= __('Could not fetch individual') ?>'
|
||||
})
|
||||
})
|
||||
}
|
||||
})()
|
||||
</script>
|
|
@ -2,7 +2,7 @@
|
|||
echo $this->element('genericElements/IndexTable/index_table', [
|
||||
'data' => [
|
||||
'data' => $individuals,
|
||||
'skip_pagination' => 1,
|
||||
// 'skip_pagination' => 1,
|
||||
'top_bar' => [
|
||||
'children' => [
|
||||
[
|
||||
|
@ -33,11 +33,12 @@ echo $this->element('genericElements/IndexTable/index_table', [
|
|||
],
|
||||
[
|
||||
'type' => 'search',
|
||||
'button' => __('Filter'),
|
||||
'button' => __('Search'),
|
||||
'placeholder' => __('Enter value to search'),
|
||||
'data' => '',
|
||||
'searchKey' => 'value'
|
||||
]
|
||||
'searchKey' => 'value',
|
||||
'additionalUrlParams' => h($mailing_list_id)
|
||||
],
|
||||
]
|
||||
],
|
||||
'fields' => [
|
||||
|
@ -45,18 +46,25 @@ echo $this->element('genericElements/IndexTable/index_table', [
|
|||
'name' => '#',
|
||||
'sort' => 'id',
|
||||
'data_path' => 'id',
|
||||
'url' => '/individuals/view/{{0}}',
|
||||
'url_vars' => ['id'],
|
||||
],
|
||||
[
|
||||
'name' => __('First name'),
|
||||
'data_path' => 'first_name',
|
||||
'url' => '/individuals/view/{{0}}',
|
||||
'url_vars' => ['id'],
|
||||
],
|
||||
[
|
||||
'name' => __('Last name'),
|
||||
'data_path' => 'last_name',
|
||||
'url' => '/individuals/view/{{0}}',
|
||||
'url_vars' => ['id'],
|
||||
],
|
||||
[
|
||||
'name' => __('Email'),
|
||||
'data_path' => 'email',
|
||||
'name' => __('Registered Email'),
|
||||
'data_path' => 'mailinglist_emails',
|
||||
'element' => 'list',
|
||||
],
|
||||
[
|
||||
'name' => __('UUID'),
|
||||
|
@ -65,11 +73,6 @@ echo $this->element('genericElements/IndexTable/index_table', [
|
|||
]
|
||||
],
|
||||
'actions' => [
|
||||
[
|
||||
'url' => '/individuals/view',
|
||||
'url_params_data_paths' => ['id'],
|
||||
'icon' => 'eye'
|
||||
],
|
||||
[
|
||||
'open_modal' => '/mailingLists/removeIndividual/' . h($mailing_list_id) . '/[onclick_params_data_path]',
|
||||
'modal_params_data_path' => 'id',
|
||||
|
|
|
@ -45,7 +45,8 @@ echo $this->element(
|
|||
[
|
||||
'url' => '/mailingLists/listIndividuals/{{0}}',
|
||||
'url_params' => ['id'],
|
||||
'title' => __('Individuals')
|
||||
'title' => __('Individuals'),
|
||||
'collapsed' => 'show',
|
||||
]
|
||||
]
|
||||
]
|
||||
|
|
|
@ -84,7 +84,6 @@ echo $this->element('genericElements/IndexTable/index_table', [
|
|||
],
|
||||
'title' => __('ContactDB Organisation Index'),
|
||||
'description' => __('A list of organisations known by your Cerebrate instance. This list can get populated either directly, by adding new organisations or by fetching them from trusted remote sources.'),
|
||||
'pull' => 'right',
|
||||
'actions' => [
|
||||
[
|
||||
'url' => '/organisations/view',
|
||||
|
|
|
@ -92,9 +92,6 @@ echo $this->Breadcrumbs->render(
|
|||
|
||||
<?php if (!empty($breadcrumbLinks) || !empty($breadcrumbAction)) : ?>
|
||||
<div class="breadcrumb-link-container position-absolute end-0 d-flex">
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($breadcrumbLinks)) : ?>
|
||||
<div class="header-breadcrumb-children d-none d-md-flex btn-group">
|
||||
<?= $breadcrumbLinks ?>
|
||||
<?php if (!empty($breadcrumbAction)) : ?>
|
||||
|
@ -106,8 +103,5 @@ echo $this->Breadcrumbs->render(
|
|||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($breadcrumbLinks) || !empty($breadcrumbAction)) : ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
Loading…
Reference in New Issue