diff --git a/config/bootstrap.php b/config/bootstrap.php
index 739122d..6da31ba 100644
--- a/config/bootstrap.php
+++ b/config/bootstrap.php
@@ -173,6 +173,14 @@ Mailer::setConfig(Configure::consume('Email'));
Log::setConfig(Configure::consume('Log'));
Security::setSalt(Configure::consume('Security.salt'));
+Configure::write('Session', [
+ 'defaults' => 'php',
+ 'ini' => [
+ 'session.cookie_httponly' => true,
+ 'session.cookie_secure' => true,
+ ]
+]);
+
/*
* Setup detectors for mobile and tablet.
*/
diff --git a/config/routes.php b/config/routes.php
index ac1ab26..32712cd 100644
--- a/config/routes.php
+++ b/config/routes.php
@@ -49,6 +49,7 @@ $routes->scope('/', function (RouteBuilder $builder) {
// Register scoped middleware for in scopes.
$builder->registerMiddleware('csrf', new CsrfProtectionMiddleware([
'httponly' => true,
+ 'secure' => true,
]));
/*
* Apply a middleware to the current route scope.
diff --git a/src/Command/SummaryCommand.php b/src/Command/SummaryCommand.php
index cf5debf..f7622a1 100644
--- a/src/Command/SummaryCommand.php
+++ b/src/Command/SummaryCommand.php
@@ -80,7 +80,14 @@ class SummaryCommand extends Command
fwrite($file_input, $message);
$this->io->out($message);
$logsUsers = $this->_fetchLogsForUsers($userID, $days);
- $modifiedUsers = $this->_formatLogsForTable($logsUsers);
+ $userByIDs = Hash::combine($userForOrg, '{n}.id', '{n}');
+ $logsUserMetaFields = $this->_fetchLogsForUserMetaFields($userID, $days);
+ $logsUserMetaFields = $this->_formatUserMetafieldLogs($logsUserMetaFields, $userByIDs);
+ $logsUsersCombined = array_merge($logsUsers, $logsUserMetaFields);
+ usort($logsUsersCombined, function($a, $b) {
+ return $a['created'] < $b['created'] ? -1 : 1;
+ });
+ $modifiedUsers = $this->_formatLogsForTable($logsUsersCombined);
foreach ($modifiedUsers as $row) {
fputcsv($file_input, $row);
}
@@ -167,6 +174,45 @@ class SummaryCommand extends Command
]);
}
+ protected function _fetchLogsForUserMetaFields(array $userIDs = [], int $days=7): array
+ {
+ if (empty($userIDs)) {
+ return [];
+ }
+ $logs = $this->_fetchLogs([
+ 'contain' => ['Users'],
+ 'conditions' => [
+ 'model' => 'MetaFields',
+ 'request_action IN' => ['add', 'edit', 'delete'],
+ 'AuditLogs.created >=' => FrozenTime::now()->subDays($days),
+ ]
+ ]);
+ $metaFieldLogs = array_filter($logs, function ($log) use ($userIDs) {
+ return !empty($log['changed']['scope']) && $log['changed']['scope'] === 'user' && in_array($log['changed']['parent_id'], $userIDs);
+ });
+ $metaFieldDeletionLogs = array_filter($logs, function ($log) use ($userIDs) {
+ return $log['request_action'] === 'delete';
+ });
+ foreach ($metaFieldDeletionLogs as $i => $log) {
+ $latestAssociatedLog = $this->_fetchLogs([
+ 'contain' => ['Users'],
+ 'conditions' => [
+ 'model' => 'MetaFields',
+ 'request_action IN' => ['add'],
+ 'model_id' => $log['model_id'],
+ ],
+ 'order' => ['AuditLogs.created' => 'DESC'],
+ 'limit' => 1,
+ ]);
+ if (!empty($latestAssociatedLog)) {
+ $metaFieldDeletionLogs[$i]['changed']['orig_value'] = $latestAssociatedLog[0]['changed']['value'];
+ $metaFieldDeletionLogs[$i]['changed']['value'] = '';
+ }
+ }
+ $allLogs = array_merge($metaFieldLogs, $metaFieldDeletionLogs);
+ return $allLogs;
+ }
+
protected function _fetchLogsForOrgs(array $orgIDs = [], int $days = 7): array
{
if (empty($orgIDs)) {
@@ -201,18 +247,42 @@ class SummaryCommand extends Command
protected function _fetchLogs(array $options=[]): array
{
- $logs = $this->AuditLogs->find()
+ $query = $this->AuditLogs->find()
->contain($options['contain'])
- ->where($options['conditions'])
+ ->where($options['conditions']);
+ if (!empty($options['order'])) {
+ $query = $query->order($options['order']);
+ }
+ if (!empty($options['limit'])) {
+ $query = $query
+ ->limit($options['limit'])
+ ->page(1);
+ }
+ $logs = $query
->enableHydration(false)
->all()->toList();
return array_map(function ($log) {
$log['changed'] = is_resource($log['changed']) ? stream_get_contents($log['changed']) : $log['changed'];
- $log['changed'] = json_decode($log['changed']);
+ $log['changed'] = json_decode($log['changed'], true);
return $log;
}, $logs);
}
+ protected function _formatUserMetafieldLogs($logEntries, $userByIDs): array
+ {
+ return array_map(function($log) use ($userByIDs) {
+ $log['model'] = 'Users';
+ $log['request_action'] = 'edit';
+ $log['changed'] = [
+ $log['model_title'] => [
+ $log['changed']['orig_value'] ?? '',
+ $log['changed']['value']
+ ]
+ ];
+ return $log;
+ }, $logEntries);
+ }
+
protected function _formatLogsForTable($logEntries): array
{
$header = ['Model', 'Action', 'Editor user', 'Log ID', 'Datetime', 'Change'];
diff --git a/src/Controller/Component/CRUDComponent.php b/src/Controller/Component/CRUDComponent.php
index 9891b20..a1ecba1 100644
--- a/src/Controller/Component/CRUDComponent.php
+++ b/src/Controller/Component/CRUDComponent.php
@@ -96,17 +96,18 @@ class CRUDComponent extends Component
$query->order($sort . ' ' . $direction);
}
}
- if ($this->metaFieldsSupported() && !$this->Controller->ParamHandler->isRest()) {
+ if ($this->metaFieldsSupported()) {
$query = $this->includeRequestedMetaFields($query);
}
if (!$this->Controller->ParamHandler->isRest()) {
$this->setRequestedEntryAmount();
+ } else if (!empty($this->request->getQuery('limit'))) {
+ $this->Controller->paginate['limit'] = PHP_INT_MAX; // Make sure to download the entire filtered table
}
$data = $this->Controller->paginate($query, $this->Controller->paginate ?? []);
$totalCount = $this->Controller->getRequest()->getAttribute('paging')[$this->TableAlias]['count'];
if ($this->Controller->ParamHandler->isRest()) {
- $data = $this->Controller->paginate($query, $this->Controller->paginate ?? []);
if (isset($options['hidden'])) {
$data->each(function($value, $key) use ($options) {
$hidden = is_array($options['hidden']) ? $options['hidden'] : [$options['hidden']];
@@ -795,6 +796,9 @@ class CRUDComponent extends Component
$user = $this->Controller->ACL->getUser();
$tableSettings = IndexSetting::getTableSetting($user, $this->Table);
if (!empty($tableSettings['number_of_element'])) {
+ if ($tableSettings['number_of_element'] === 'all') {
+ $tableSettings['number_of_element'] = 10000; // Even with all, sure not to return too much data
+ }
$this->Controller->paginate['limit'] = intval($tableSettings['number_of_element']);
}
}
diff --git a/src/Controller/Component/NavigationComponent.php b/src/Controller/Component/NavigationComponent.php
index 3c606e8..452d575 100644
--- a/src/Controller/Component/NavigationComponent.php
+++ b/src/Controller/Component/NavigationComponent.php
@@ -37,6 +37,7 @@ class NavigationComponent extends Component
'Instance' => 'server',
'Tags' => 'tags',
'API' => 'code',
+ 'EnumerationCollections' => 'list',
];
public function initialize(array $config): void
@@ -163,6 +164,7 @@ class NavigationComponent extends Component
'LocalTools',
'UserSettings',
'MailingLists',
+ 'EnumerationCollections',
];
foreach ($CRUDControllers as $controller) {
$bcf->setDefaultCRUDForModel($controller);
diff --git a/src/VERSION.json b/src/VERSION.json
index 0b24643..423dd7e 100644
--- a/src/VERSION.json
+++ b/src/VERSION.json
@@ -1,4 +1,4 @@
{
- "version": "1.14",
+ "version": "1.15",
"application": "Cerebrate"
}
diff --git a/templates/element/genericElements/ListTopBar/group_table_action/numberOfElement.php b/templates/element/genericElements/ListTopBar/group_table_action/numberOfElement.php
index 6b69c50..e3913d1 100644
--- a/templates/element/genericElements/ListTopBar/group_table_action/numberOfElement.php
+++ b/templates/element/genericElements/ListTopBar/group_table_action/numberOfElement.php
@@ -10,6 +10,7 @@ $numberOfElementSelectSeed = 'seed-' . mt_rand();
+