diff --git a/app/availableplugins/ApiConnector/src/Model/Entity/ApiSource.php b/app/availableplugins/ApiConnector/src/Model/Entity/ApiSource.php
index b05cd80ae..890e06c4c 100644
--- a/app/availableplugins/ApiConnector/src/Model/Entity/ApiSource.php
+++ b/app/availableplugins/ApiConnector/src/Model/Entity/ApiSource.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class ApiSource extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/availableplugins/ApiConnector/src/Model/Entity/ApiSourceEndpoint.php b/app/availableplugins/ApiConnector/src/Model/Entity/ApiSourceEndpoint.php
index da833c35f..8df2cab59 100644
--- a/app/availableplugins/ApiConnector/src/Model/Entity/ApiSourceEndpoint.php
+++ b/app/availableplugins/ApiConnector/src/Model/Entity/ApiSourceEndpoint.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class ApiSourceEndpoint extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/availableplugins/ApiConnector/src/Model/Entity/ApiSourceRecord.php b/app/availableplugins/ApiConnector/src/Model/Entity/ApiSourceRecord.php
index d6ab1e064..be2180e98 100644
--- a/app/availableplugins/ApiConnector/src/Model/Entity/ApiSourceRecord.php
+++ b/app/availableplugins/ApiConnector/src/Model/Entity/ApiSourceRecord.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class ApiSourceRecord extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/availableplugins/FileConnector/src/Model/Entity/FileProvisioner.php b/app/availableplugins/FileConnector/src/Model/Entity/FileProvisioner.php
index 7499334f2..123cced99 100644
--- a/app/availableplugins/FileConnector/src/Model/Entity/FileProvisioner.php
+++ b/app/availableplugins/FileConnector/src/Model/Entity/FileProvisioner.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class FileProvisioner extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/availableplugins/FileConnector/src/Model/Entity/FileSource.php b/app/availableplugins/FileConnector/src/Model/Entity/FileSource.php
index 662131667..912109c1b 100644
--- a/app/availableplugins/FileConnector/src/Model/Entity/FileSource.php
+++ b/app/availableplugins/FileConnector/src/Model/Entity/FileSource.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class FileSource extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/availableplugins/PasswordAuthenticator/src/Model/Entity/Password.php b/app/availableplugins/PasswordAuthenticator/src/Model/Entity/Password.php
index db6c589df..94ef05513 100644
--- a/app/availableplugins/PasswordAuthenticator/src/Model/Entity/Password.php
+++ b/app/availableplugins/PasswordAuthenticator/src/Model/Entity/Password.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class Password extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/availableplugins/PasswordAuthenticator/src/Model/Entity/PasswordAuthenticator.php b/app/availableplugins/PasswordAuthenticator/src/Model/Entity/PasswordAuthenticator.php
index 773237765..abc2cdd74 100644
--- a/app/availableplugins/PasswordAuthenticator/src/Model/Entity/PasswordAuthenticator.php
+++ b/app/availableplugins/PasswordAuthenticator/src/Model/Entity/PasswordAuthenticator.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class PasswordAuthenticator extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/availableplugins/PipelineToolkit/src/Model/Entity/IdentifierMapper.php b/app/availableplugins/PipelineToolkit/src/Model/Entity/IdentifierMapper.php
index e9687f174..0d76ebfba 100644
--- a/app/availableplugins/PipelineToolkit/src/Model/Entity/IdentifierMapper.php
+++ b/app/availableplugins/PipelineToolkit/src/Model/Entity/IdentifierMapper.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class IdentifierMapper extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/availableplugins/PipelineToolkit/src/Model/Entity/LoginIdentifierType.php b/app/availableplugins/PipelineToolkit/src/Model/Entity/LoginIdentifierType.php
index 6d5092b2b..c356c1926 100644
--- a/app/availableplugins/PipelineToolkit/src/Model/Entity/LoginIdentifierType.php
+++ b/app/availableplugins/PipelineToolkit/src/Model/Entity/LoginIdentifierType.php
@@ -34,6 +34,8 @@
// use \App\Model\Entity\ExternalIdentityRole;
class LoginIdentifierType extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/availableplugins/PipelineToolkit/src/Model/Entity/PersonRoleMapper.php b/app/availableplugins/PipelineToolkit/src/Model/Entity/PersonRoleMapper.php
index eb42d7458..f47bc355b 100644
--- a/app/availableplugins/PipelineToolkit/src/Model/Entity/PersonRoleMapper.php
+++ b/app/availableplugins/PipelineToolkit/src/Model/Entity/PersonRoleMapper.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class PersonRoleMapper extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/availableplugins/PipelineToolkit/src/Model/Entity/PersonRoleMapping.php b/app/availableplugins/PipelineToolkit/src/Model/Entity/PersonRoleMapping.php
index 4e6b33e59..1a68d5468 100644
--- a/app/availableplugins/PipelineToolkit/src/Model/Entity/PersonRoleMapping.php
+++ b/app/availableplugins/PipelineToolkit/src/Model/Entity/PersonRoleMapping.php
@@ -34,6 +34,8 @@
use \App\Model\Entity\ExternalIdentityRole;
class PersonRoleMapping extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/availableplugins/SqlConnector/src/Model/Entity/SqlProvisioner.php b/app/availableplugins/SqlConnector/src/Model/Entity/SqlProvisioner.php
index 78e20c05c..92667dd1a 100644
--- a/app/availableplugins/SqlConnector/src/Model/Entity/SqlProvisioner.php
+++ b/app/availableplugins/SqlConnector/src/Model/Entity/SqlProvisioner.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class SqlProvisioner extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/availableplugins/SqlConnector/src/Model/Entity/SqlSource.php b/app/availableplugins/SqlConnector/src/Model/Entity/SqlSource.php
index 1015f2f08..c2ad280e9 100644
--- a/app/availableplugins/SqlConnector/src/Model/Entity/SqlSource.php
+++ b/app/availableplugins/SqlConnector/src/Model/Entity/SqlSource.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class SqlSource extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreApi/src/Model/Entity/MatchCallback.php b/app/plugins/CoreApi/src/Model/Entity/MatchCallback.php
index fd21c1b6c..07979e05d 100644
--- a/app/plugins/CoreApi/src/Model/Entity/MatchCallback.php
+++ b/app/plugins/CoreApi/src/Model/Entity/MatchCallback.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class MatchCallback extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreAssigner/src/Model/Entity/FormatAssigner.php b/app/plugins/CoreAssigner/src/Model/Entity/FormatAssigner.php
index c15bbe0bd..a90cdd12f 100644
--- a/app/plugins/CoreAssigner/src/Model/Entity/FormatAssigner.php
+++ b/app/plugins/CoreAssigner/src/Model/Entity/FormatAssigner.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class FormatAssigner extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreAssigner/src/Model/Entity/FormatAssignerSequence.php b/app/plugins/CoreAssigner/src/Model/Entity/FormatAssignerSequence.php
index a20808d83..67684a398 100644
--- a/app/plugins/CoreAssigner/src/Model/Entity/FormatAssignerSequence.php
+++ b/app/plugins/CoreAssigner/src/Model/Entity/FormatAssignerSequence.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class FormatAssignerSequence extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreAssigner/src/Model/Entity/SqlAssigner.php b/app/plugins/CoreAssigner/src/Model/Entity/SqlAssigner.php
index 582ac9cf0..ca375cecd 100644
--- a/app/plugins/CoreAssigner/src/Model/Entity/SqlAssigner.php
+++ b/app/plugins/CoreAssigner/src/Model/Entity/SqlAssigner.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class SqlAssigner extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreEnroller/src/Model/Entity/EnrollmentAttribute.php b/app/plugins/CoreEnroller/src/Model/Entity/EnrollmentAttribute.php
index 8801194e5..ddb4baec2 100644
--- a/app/plugins/CoreEnroller/src/Model/Entity/EnrollmentAttribute.php
+++ b/app/plugins/CoreEnroller/src/Model/Entity/EnrollmentAttribute.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class EnrollmentAttribute extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreEnroller/src/Model/Entity/PetitionAcceptance.php b/app/plugins/CoreEnroller/src/Model/Entity/PetitionAcceptance.php
index 7705a1ad8..559cf30b8 100644
--- a/app/plugins/CoreEnroller/src/Model/Entity/PetitionAcceptance.php
+++ b/app/plugins/CoreEnroller/src/Model/Entity/PetitionAcceptance.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class PetitionAcceptance extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreEnroller/src/Model/Entity/PetitionApproval.php b/app/plugins/CoreEnroller/src/Model/Entity/PetitionApproval.php
index 541f0b2c8..c57a8670d 100644
--- a/app/plugins/CoreEnroller/src/Model/Entity/PetitionApproval.php
+++ b/app/plugins/CoreEnroller/src/Model/Entity/PetitionApproval.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class PetitionApproval extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreEnroller/src/Model/Entity/PetitionAttribute.php b/app/plugins/CoreEnroller/src/Model/Entity/PetitionAttribute.php
index 2829228e7..108651f0a 100644
--- a/app/plugins/CoreEnroller/src/Model/Entity/PetitionAttribute.php
+++ b/app/plugins/CoreEnroller/src/Model/Entity/PetitionAttribute.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class PetitionAttribute extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreEnroller/src/Model/Entity/PetitionBasicAttributeSet.php b/app/plugins/CoreEnroller/src/Model/Entity/PetitionBasicAttributeSet.php
index 2408e0a42..bee6d19f9 100644
--- a/app/plugins/CoreEnroller/src/Model/Entity/PetitionBasicAttributeSet.php
+++ b/app/plugins/CoreEnroller/src/Model/Entity/PetitionBasicAttributeSet.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class PetitionBasicAttributeSet extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreEnroller/src/Model/Entity/PetitionIdentifier.php b/app/plugins/CoreEnroller/src/Model/Entity/PetitionIdentifier.php
index c10403990..1f9f36014 100644
--- a/app/plugins/CoreEnroller/src/Model/Entity/PetitionIdentifier.php
+++ b/app/plugins/CoreEnroller/src/Model/Entity/PetitionIdentifier.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class PetitionIdentifier extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreEnroller/src/Model/Entity/PetitionVerification.php b/app/plugins/CoreEnroller/src/Model/Entity/PetitionVerification.php
index 75e8f6ec7..f36f6f978 100644
--- a/app/plugins/CoreEnroller/src/Model/Entity/PetitionVerification.php
+++ b/app/plugins/CoreEnroller/src/Model/Entity/PetitionVerification.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class PetitionVerification extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreServer/src/Model/Entity/HttpServer.php b/app/plugins/CoreServer/src/Model/Entity/HttpServer.php
index b40dba1a4..6e01e8462 100644
--- a/app/plugins/CoreServer/src/Model/Entity/HttpServer.php
+++ b/app/plugins/CoreServer/src/Model/Entity/HttpServer.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class HttpServer extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreServer/src/Model/Entity/MatchServer.php b/app/plugins/CoreServer/src/Model/Entity/MatchServer.php
index b80202698..8b01f27fc 100644
--- a/app/plugins/CoreServer/src/Model/Entity/MatchServer.php
+++ b/app/plugins/CoreServer/src/Model/Entity/MatchServer.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class MatchServer extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreServer/src/Model/Entity/MatchServerAttribute.php b/app/plugins/CoreServer/src/Model/Entity/MatchServerAttribute.php
index 3f4be8a52..07eb8102e 100644
--- a/app/plugins/CoreServer/src/Model/Entity/MatchServerAttribute.php
+++ b/app/plugins/CoreServer/src/Model/Entity/MatchServerAttribute.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class MatchServerAttribute extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreServer/src/Model/Entity/Oauth2Server.php b/app/plugins/CoreServer/src/Model/Entity/Oauth2Server.php
index 3881ee0c6..b4d0521ec 100644
--- a/app/plugins/CoreServer/src/Model/Entity/Oauth2Server.php
+++ b/app/plugins/CoreServer/src/Model/Entity/Oauth2Server.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class Oauth2Server extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreServer/src/Model/Entity/SmtpServer.php b/app/plugins/CoreServer/src/Model/Entity/SmtpServer.php
index 4dd82c18d..ecb779c3b 100644
--- a/app/plugins/CoreServer/src/Model/Entity/SmtpServer.php
+++ b/app/plugins/CoreServer/src/Model/Entity/SmtpServer.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class SmtpServer extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/plugins/CoreServer/src/Model/Entity/SqlServer.php b/app/plugins/CoreServer/src/Model/Entity/SqlServer.php
index 081f28e03..8f0c811ca 100644
--- a/app/plugins/CoreServer/src/Model/Entity/SqlServer.php
+++ b/app/plugins/CoreServer/src/Model/Entity/SqlServer.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class SqlServer extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
diff --git a/app/resources/locales/en_US/field.po b/app/resources/locales/en_US/field.po
index b3270a15e..4385417e4 100644
--- a/app/resources/locales/en_US/field.po
+++ b/app/resources/locales/en_US/field.po
@@ -53,6 +53,18 @@ msgstr "Area Code"
msgid "attribute"
msgstr "Attribute"
+msgid "changelog.actor_identifier"
+msgstr "Actor Identifier"
+
+msgid "changelog.deleted"
+msgstr "Deleted"
+
+msgid "changelog.parent"
+msgstr "Parent Record ID"
+
+msgid "changelog.revision"
+msgstr "Revision"
+
msgid "code"
msgstr "Code"
diff --git a/app/resources/locales/en_US/information.po b/app/resources/locales/en_US/information.po
index ba84190c5..503bda478 100644
--- a/app/resources/locales/en_US/information.po
+++ b/app/resources/locales/en_US/information.po
@@ -30,6 +30,15 @@ msgstr "API Users created in the COmanage CO are given full privileges to all Re
msgid "api.key"
msgstr "This newly generated API Key cannot be recovered. If it is lost a new key must be generated."
+msgid "changelog"
+msgstr "Change Log"
+
+msgid "changelog.archived"
+msgstr "This is an archive record"
+
+msgid "changelog.deleted"
+msgstr "This record has been deleted"
+
msgid "cos.none"
msgstr "You are not an active member in any collaboration. If your request for enrollment is still being processed, you will not be able to login until it is approved. Please contact an administrator for assistance."
diff --git a/app/resources/locales/en_US/operation.po b/app/resources/locales/en_US/operation.po
index fb2402a55..bfd24d042 100644
--- a/app/resources/locales/en_US/operation.po
+++ b/app/resources/locales/en_US/operation.po
@@ -123,6 +123,9 @@ msgstr "Bulk add"
msgid "cancel"
msgstr "Cancel"
+msgid "changelog.view"
+msgstr "View Change Log"
+
msgid "clear"
msgstr "Clear"
diff --git a/app/src/Command/ResetMfaCommand.php b/app/src/Command/ResetMfaCommand.php
index c12ec3ee3..814d2dc98 100644
--- a/app/src/Command/ResetMfaCommand.php
+++ b/app/src/Command/ResetMfaCommand.php
@@ -57,7 +57,7 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption
}*/
/**
- * Execute the Database Command.
+ * Execute the Reset MFA Command.
*
* @since COmanage Registry v5.2.0
* @param Arguments $args Command Arguments
diff --git a/app/src/Controller/ApiV2Controller.php b/app/src/Controller/ApiV2Controller.php
index e47d5ca76..e5ca9f109 100644
--- a/app/src/Controller/ApiV2Controller.php
+++ b/app/src/Controller/ApiV2Controller.php
@@ -390,12 +390,18 @@ public function view($id = null) {
$table = $this->getCurrentTable();
// $tableName = models
$tableName = $table->getTable();
+ $request = $this->getRequest();
if(empty($id)) {
throw new InvalidArgumentException(__d('error', 'notprov', ['id']));
}
- $obj = $table->findById($id)->firstOrFail();
+ // We allow archived records to be retrieved via the API, but only if
+ // explicitly requested
+
+ $archived = $request->getQuery('archived') === 'yes';
+
+ $obj = $table->findById($id)->applyOptions(['archived' => $archived])->firstOrFail();
$this->set($tableName, [$obj]);
diff --git a/app/src/Controller/AppController.php b/app/src/Controller/AppController.php
index 6f8b31988..b4549e98a 100644
--- a/app/src/Controller/AppController.php
+++ b/app/src/Controller/AppController.php
@@ -293,6 +293,9 @@ public function getCurrentTable(): \Cake\ORM\Table
protected function primaryLinkOnGet(string $potentialPrimaryLink): Object|bool
{
+ /** @var string $modelsName */
+ $modelsName = $this->getName();
+
// If this action allows unkeyed, asserted primary link IDs, check the query
// string (e.g.: 'add' or 'index' allow matchgrid_id to be passed in)
$actionParam = $this->request->getParam('action');
@@ -311,7 +314,10 @@ protected function primaryLinkOnGet(string $potentialPrimaryLink): Object|bool
return false;
}
- return $this->getCurrentTable()->findPrimaryLink($param);
+ // For a GET with a param (ie: a record id) we allow archived records to be
+ // retrieved via ChangelogBehavior. Note because $param must be an integer
+ // we don't need to check it further.
+ return $this->$modelsName->findPrimaryLink(id: $param, archived: true);
}
/**
diff --git a/app/src/Controller/Component/RegistryAuthComponent.php b/app/src/Controller/Component/RegistryAuthComponent.php
index aa39db4b9..d8c3f8d74 100644
--- a/app/src/Controller/Component/RegistryAuthComponent.php
+++ b/app/src/Controller/Component/RegistryAuthComponent.php
@@ -400,10 +400,12 @@ protected function calculatePermissions(?int $id=null): array {
// Pull the record so we can interrogate it
- // XXX Get the record along with the contains
+ // Get the record along with the contains
// We use findById() rather than get() so we can apply subsequent
- // query modifications via traits
- $query = $table->findById($id);
+ // query modifications via traits. We set archived to true so we can
+ // retrieve archived records via ChangelogBehavior.
+ $query = $table->findById($id)
+ ->applyOptions(['archived' => true]);
// QueryModificationTrait
$getActionMethod = "get{$reqAction}Contains";
@@ -1060,7 +1062,8 @@ public function isSelf(?int $coId, ?int $id): bool {
if ($request->getParam('action') == 'view' && $id !== null) {
$modelTable = TableRegistry::getTableLocator()->get($controllerName);
- $modelEntity = $modelTable->get($id);
+ // We need to allow archived gets for viewing archived records
+ $modelEntity = $modelTable->get($id, ['archived' => true]);
// Associated Models, e.g. MVEAs
$primaryLinks = $modelTable->getPrimaryLinks();
diff --git a/app/src/Lib/Traits/EntityMetaTrait.php b/app/src/Lib/Traits/EntityMetaTrait.php
index 6545dd924..3398a7439 100644
--- a/app/src/Lib/Traits/EntityMetaTrait.php
+++ b/app/src/Lib/Traits/EntityMetaTrait.php
@@ -89,6 +89,37 @@ public function isProbablyThisArray(array $data): bool {
return $match;
}
+ /**
+ * Determine if this entity is Read Only.
+ *
+ * @since COmanage Registry v5.0.0
+ * @return boolean True if the entity is read only, false otherwise
+ */
+
+ public function isReadOnly(): bool {
+ // This function implements common logic for determining if an entity is read only.
+ // To implement entity specific tests, see the documentation at
+ // XXX insert link to wiki
+
+ // If we're incorporated into an MVEA entity, isMVEReadOnly will check for
+ // pipelined attributes (which are read only).
+
+ if(method_exists($this, 'isMVEReadOnly') && $this->isMVEReadOnly()) {
+ return true;
+ }
+
+ // Frozen attributes are treated as read snly
+ if($this->frozen) {
+ return true;
+ }
+
+ // Records flagged as deleted or with a non-null changelog attribute are read only
+ $parentfk = $this->changelogAttributeName();
+
+ return (isset($this->deleted) && $this->deleted)
+ || !empty($this->$parentfk);
+ }
+
/**
* Determine the source attribute foreign key (eg: source_name_id) for this entity.
*
@@ -97,6 +128,9 @@ public function isProbablyThisArray(array $data): bool {
*/
public function sourceAttributeName() {
+ // There is a similar function in EntityMetaTrait because sometimes we have a Table
+ // context and sometimes we have an Entity context.
+
// The class name is something like `\App\Model\Entity\TelephoneNumber', but we
// want telephone_number (lowercased).
$entityName = Inflector::underscore(substr(strrchr(get_class($this), '\\'),1));
diff --git a/app/src/Lib/Traits/ReadOnlyEntityTrait.php b/app/src/Lib/Traits/ReadOnlyEntityTrait.php
deleted file mode 100644
index 0673af91f..000000000
--- a/app/src/Lib/Traits/ReadOnlyEntityTrait.php
+++ /dev/null
@@ -1,63 +0,0 @@
-isMVEReadOnly()) {
- return true;
- }
-
- // Frozen attributes are treated as Read Only
- if($this->frozen) {
- return true;
- }
-
- // Records flagged as deleted or with a parent foreign key are read only
-
- // The class name is something like `\App\Model\Entity\PersonRole', but we just
- // want person_role (lowercased).
- $entityName = \Cake\Utility\Inflector::underscore(substr(strrchr(get_class($this), '\\'),1));
- $parentfk = $entityName . "_id";
-
- return (isset($entity->deleted) && $entity->deleted)
- || !empty($entity->$parentfk);
- }
-}
diff --git a/app/src/Lib/Traits/TableMetaTrait.php b/app/src/Lib/Traits/TableMetaTrait.php
index 495c3044e..bc8d341d6 100644
--- a/app/src/Lib/Traits/TableMetaTrait.php
+++ b/app/src/Lib/Traits/TableMetaTrait.php
@@ -287,6 +287,9 @@ public function setTableType(string $tableType) {
*/
public function sourceForeignKey(): string {
+ // There is a similar function in EntityMetaTrait because sometimes we have a Table
+ // context and sometimes we have an Entity context.
+
return "source_" . Inflector::underscore(StringUtilities::tableToEntityName($this)) . "_id";
}
}
diff --git a/app/src/Model/Behavior/ChangelogBehavior.php b/app/src/Model/Behavior/ChangelogBehavior.php
index 5c83d9dbd..bb5c019d2 100644
--- a/app/src/Model/Behavior/ChangelogBehavior.php
+++ b/app/src/Model/Behavior/ChangelogBehavior.php
@@ -55,7 +55,15 @@ public function beforeDelete(Event $event, $entity, \ArrayObject $options) {
}
$subject = $event->getSubject();
+ $table = $subject->getTable();
$alias = $subject->getAlias();
+ $parentfk = Inflector::singularize($table) . "_id";
+
+ // Before we do anything else, make sure we're not trying to update an archive record
+ if($entity->deleted || !empty($entity->$parentfk)) {
+ LogBehavior::serror($alias, 'Attempt to delete archived record ' . $entity->id . ' has been declined');
+ throw new \RuntimeException(__d('error', 'edit.readonly'));
+ }
LogBehavior::strace($alias, 'Changelog converting delete to update');
@@ -96,7 +104,7 @@ public function beforeDelete(Event $event, $entity, \ArrayObject $options) {
public function beforeFind(Event $event, Query $query, \ArrayObject $options, bool $primary): void {
if(isset($options['archived']) && $options['archived']) {
- // Archived records requested (including possiblf expunge), so just return
+ // Archived records requested (including possibly expunge), so just return
$event->setResult(true);
return;
}
@@ -108,9 +116,6 @@ public function beforeFind(Event $event, Query $query, \ArrayObject $options, bo
LogBehavior::strace($alias, 'Changelog altering find conditions');
- // XXX add support for archived, revision, etc
- // XXX if specific id is requested, do not modify query
-
// Take into account all joined associations
if(!empty($query->clause('join'))) {
foreach($query->clause('join') as $mdl => $opts) {
@@ -142,10 +147,6 @@ public function beforeFind(Event $event, Query $query, \ArrayObject $options, bo
*/
public function beforeSave(Event $event, EntityInterface $entity, \ArrayObject $options): void {
- // XXX prevent updates to deleted and archived records
- // Cake Book suggests doing this with Application Rules... can we define those in the Behavior?
- // or perhaps in beforeMarshal? https://book.cakephp.org/3.0/en/orm/saving-data.html#modifying-request-data-before-building-entities
-
if(isset($options['archive']) && !$options['archive']) {
// Archiving disabled for this request, don't do anything
return;
@@ -155,6 +156,12 @@ public function beforeSave(Event $event, EntityInterface $entity, \ArrayObject $
$table = $subject->getTable();
$alias = $subject->getAlias();
$parentfk = Inflector::singularize($table) . "_id";
+
+ // Before we do anything else, make sure we're not trying to update an archive record
+ if($entity->deleted || !empty($entity->$parentfk)) {
+ LogBehavior::serror($alias, 'Attempt to edit archived record ' . $entity->id . ' has been declined');
+ throw new \RuntimeException(__d('error', 'edit.readonly'));
+ }
$actor = '';
@@ -206,13 +213,26 @@ public function beforeSave(Event $event, EntityInterface $entity, \ArrayObject $
// Cake 3+ doesn't have callbacks=false, so we use the archive flag so we
// don't recurse indefinitely. We also skip validation in case (eg) validation
// rules changed since the original record was created.
- $subject->saveOrFail($archive, [
- 'checkRules' => false,
- 'archive' => false,
- // We don't want to save associated models by default since
- // it will rekey them to the new archive copy.
- 'associated' => false
- ]);
+
+ $archiveOptions = [
+ 'checkRules' => false,
+ 'archive' => false
+ ];
+
+ // Are we relinking associated models to the archive copy?
+
+ $relinkToArchive = isset($options['relinkToArchive']) && $options['relinkToArchive'];
+
+ if(!$relinkToArchive) {
+ // We don't want to save associated models by default since
+ // it will rekey them to the new archive copy.
+
+ $archiveOptions['associated'] = false;
+ } else {
+ // This means relink to archive is simple to implement
+ }
+
+ $subject->saveOrFail($archive, $archiveOptions);
return;
}
diff --git a/app/src/Model/Behavior/LogBehavior.php b/app/src/Model/Behavior/LogBehavior.php
index 99df65398..c0c324056 100644
--- a/app/src/Model/Behavior/LogBehavior.php
+++ b/app/src/Model/Behavior/LogBehavior.php
@@ -60,6 +60,12 @@ public function trace(string $msg) {
}
+ public static function serror(string $name, string $msg) {
+ $label = getmypid() . "/" . $name . ": ";
+
+ Log::error($label . $msg);
+ }
+
public static function strace(string $name, string $msg) {
$label = getmypid() . "/" . $name . ": ";
diff --git a/app/src/Model/Entity/AdHocAttribute.php b/app/src/Model/Entity/AdHocAttribute.php
index 0b0bf6dd7..5886b06e8 100644
--- a/app/src/Model/Entity/AdHocAttribute.php
+++ b/app/src/Model/Entity/AdHocAttribute.php
@@ -33,7 +33,6 @@
class AdHocAttribute extends Entity {
use \App\Lib\Traits\EntityMetaTrait;
- use \App\Lib\Traits\ReadOnlyEntityTrait;
use \App\Lib\Traits\MVETrait;
protected array $_accessible = [
diff --git a/app/src/Model/Entity/Address.php b/app/src/Model/Entity/Address.php
index 7ede4ce63..09bbd9f6d 100644
--- a/app/src/Model/Entity/Address.php
+++ b/app/src/Model/Entity/Address.php
@@ -33,7 +33,6 @@
class Address extends Entity {
use \App\Lib\Traits\EntityMetaTrait;
- use \App\Lib\Traits\ReadOnlyEntityTrait;
use \App\Lib\Traits\MVETrait;
protected array $_accessible = [
diff --git a/app/src/Model/Entity/Api.php b/app/src/Model/Entity/Api.php
index a91a1f4e0..7a0d5b99e 100644
--- a/app/src/Model/Entity/Api.php
+++ b/app/src/Model/Entity/Api.php
@@ -32,7 +32,7 @@
use Cake\ORM\Entity;
class Api extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/ApiUser.php b/app/src/Model/Entity/ApiUser.php
index bf12db32a..91628df84 100644
--- a/app/src/Model/Entity/ApiUser.php
+++ b/app/src/Model/Entity/ApiUser.php
@@ -33,7 +33,7 @@
use Cake\ORM\Entity;
class ApiUser extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/ApplicationState.php b/app/src/Model/Entity/ApplicationState.php
index 396224c5a..e6aa921fc 100644
--- a/app/src/Model/Entity/ApplicationState.php
+++ b/app/src/Model/Entity/ApplicationState.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class ApplicationState extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
protected array $_accessible = [
'*' => true,
'id' => false,
diff --git a/app/src/Model/Entity/Authenticator.php b/app/src/Model/Entity/Authenticator.php
index 277ef252c..5fa6b2cc7 100644
--- a/app/src/Model/Entity/Authenticator.php
+++ b/app/src/Model/Entity/Authenticator.php
@@ -32,7 +32,7 @@
use Cake\ORM\Entity;
class Authenticator extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/AuthenticatorStatus.php b/app/src/Model/Entity/AuthenticatorStatus.php
index 7486da1ee..914af3925 100644
--- a/app/src/Model/Entity/AuthenticatorStatus.php
+++ b/app/src/Model/Entity/AuthenticatorStatus.php
@@ -32,7 +32,7 @@
use Cake\ORM\Entity;
class AuthenticatorStatus extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/Co.php b/app/src/Model/Entity/Co.php
index 3514df96c..4be4d9723 100644
--- a/app/src/Model/Entity/Co.php
+++ b/app/src/Model/Entity/Co.php
@@ -34,6 +34,10 @@
use \App\Lib\Enum\SuspendableStatusEnum;
class Co extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait {
+ isReadOnly as traitIsReadOnly;
+ }
+
protected array $_accessible = [
'*' => true,
'id' => false,
@@ -73,6 +77,6 @@ public function isCOmanageCO(): bool {
public function isReadOnly(): bool {
// The COmanage CO is read only
- return $this->isCOmanageCO();
+ return $this->isCOmanageCO() || $this->traitIsReadOnly();
}
}
\ No newline at end of file
diff --git a/app/src/Model/Entity/CoSetting.php b/app/src/Model/Entity/CoSetting.php
index f15cddbb1..4bff82c66 100644
--- a/app/src/Model/Entity/CoSetting.php
+++ b/app/src/Model/Entity/CoSetting.php
@@ -35,7 +35,7 @@
// collection of settings for a given CO, but it's easier not to fight
// Cake's inflection.
class CoSetting extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/Cou.php b/app/src/Model/Entity/Cou.php
index cc6b0e535..2fb346906 100644
--- a/app/src/Model/Entity/Cou.php
+++ b/app/src/Model/Entity/Cou.php
@@ -32,7 +32,7 @@
use Cake\ORM\Entity;
class Cou extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/Dashboard.php b/app/src/Model/Entity/Dashboard.php
index 1365b3fb3..5c2757416 100644
--- a/app/src/Model/Entity/Dashboard.php
+++ b/app/src/Model/Entity/Dashboard.php
@@ -32,7 +32,7 @@
use Cake\ORM\Entity;
class Dashboard extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/EmailAddress.php b/app/src/Model/Entity/EmailAddress.php
index 0185cc179..eba4c4e2b 100644
--- a/app/src/Model/Entity/EmailAddress.php
+++ b/app/src/Model/Entity/EmailAddress.php
@@ -33,7 +33,6 @@
class EmailAddress extends Entity {
use \App\Lib\Traits\EntityMetaTrait;
- use \App\Lib\Traits\ReadOnlyEntityTrait;
use \App\Lib\Traits\MVETrait;
protected array $_accessible = [
diff --git a/app/src/Model/Entity/EnrollmentFlow.php b/app/src/Model/Entity/EnrollmentFlow.php
index 148310b3e..883d1b696 100644
--- a/app/src/Model/Entity/EnrollmentFlow.php
+++ b/app/src/Model/Entity/EnrollmentFlow.php
@@ -33,7 +33,6 @@
class EnrollmentFlow extends Entity {
use \App\Lib\Traits\EntityMetaTrait;
- use \App\Lib\Traits\ReadOnlyEntityTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/EnrollmentFlowStep.php b/app/src/Model/Entity/EnrollmentFlowStep.php
index a87570a98..9dab91aa8 100644
--- a/app/src/Model/Entity/EnrollmentFlowStep.php
+++ b/app/src/Model/Entity/EnrollmentFlowStep.php
@@ -33,7 +33,6 @@
class EnrollmentFlowStep extends Entity {
use \App\Lib\Traits\EntityMetaTrait;
- use \App\Lib\Traits\ReadOnlyEntityTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/ExtIdentitySourceRecord.php b/app/src/Model/Entity/ExtIdentitySourceRecord.php
index 098a10efa..ddd4ade07 100644
--- a/app/src/Model/Entity/ExtIdentitySourceRecord.php
+++ b/app/src/Model/Entity/ExtIdentitySourceRecord.php
@@ -35,7 +35,6 @@
// exceeds Cake's 61 character limit
class ExtIdentitySourceRecord extends Entity {
use \App\Lib\Traits\EntityMetaTrait;
- use \App\Lib\Traits\ReadOnlyEntityTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/ExternalIdentity.php b/app/src/Model/Entity/ExternalIdentity.php
index bd2cd4baf..f717b06ad 100644
--- a/app/src/Model/Entity/ExternalIdentity.php
+++ b/app/src/Model/Entity/ExternalIdentity.php
@@ -32,7 +32,7 @@
use Cake\ORM\Entity;
class ExternalIdentity extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/ExternalIdentityRole.php b/app/src/Model/Entity/ExternalIdentityRole.php
index 63193ea20..a4e7706c2 100644
--- a/app/src/Model/Entity/ExternalIdentityRole.php
+++ b/app/src/Model/Entity/ExternalIdentityRole.php
@@ -32,7 +32,7 @@
use Cake\ORM\Entity;
class ExternalIdentityRole extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/ExternalIdentitySource.php b/app/src/Model/Entity/ExternalIdentitySource.php
index 7bc510b72..80656d6cd 100644
--- a/app/src/Model/Entity/ExternalIdentitySource.php
+++ b/app/src/Model/Entity/ExternalIdentitySource.php
@@ -32,7 +32,7 @@
use Cake\ORM\Entity;
class ExternalIdentitySource extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/Flange.php b/app/src/Model/Entity/Flange.php
index 4e480bc75..972de96f5 100644
--- a/app/src/Model/Entity/Flange.php
+++ b/app/src/Model/Entity/Flange.php
@@ -32,7 +32,7 @@
use Cake\ORM\Entity;
class Flange extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/Group.php b/app/src/Model/Entity/Group.php
index b1950b0b6..ec33f0eda 100644
--- a/app/src/Model/Entity/Group.php
+++ b/app/src/Model/Entity/Group.php
@@ -33,6 +33,10 @@
use \App\Lib\Enum\GroupTypeEnum;
class Group extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait {
+ isReadOnly as traitIsReadOnly;
+ }
+
protected array $_accessible = [
'*' => true,
'id' => false,
@@ -83,6 +87,20 @@ public function isOwners(): bool {
return $this->group_type == GroupTypeEnum::Owners;
}
+ /**
+ * Determine if this entity is Read Only.
+ *
+ * @since COmanage Registry v5.0.0
+ * @param Entity $entity Cake Entity
+ * @return boolean true if the entity is read only, false otherwise
+ */
+
+ public function isReadOnly(): bool {
+ // Automatic groups are read-only
+
+ return $this->isAutomatic() || $this->traitIsReadOnly();
+ }
+
/**
* Determine if this entity is a system group.
*
@@ -101,20 +119,6 @@ public function isSystem(): bool {
]);
}
- /**
- * Determine if this entity is Read Only.
- *
- * @since COmanage Registry v5.0.0
- * @param Entity $entity Cake Entity
- * @return boolean true if the entity is read only, false otherwise
- */
-
- public function isReadOnly(): bool {
- // Automatic groups are read-only
-
- return $this->isAutomatic();
- }
-
/**
* Determine if this is not an automatic group.
*
diff --git a/app/src/Model/Entity/GroupMember.php b/app/src/Model/Entity/GroupMember.php
index eb9a4bf92..65b4d7c8e 100644
--- a/app/src/Model/Entity/GroupMember.php
+++ b/app/src/Model/Entity/GroupMember.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class GroupMember extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
protected array $_accessible = [
'*' => true,
'id' => false,
diff --git a/app/src/Model/Entity/GroupNesting.php b/app/src/Model/Entity/GroupNesting.php
index 1f78b9a8a..43e1a94cc 100644
--- a/app/src/Model/Entity/GroupNesting.php
+++ b/app/src/Model/Entity/GroupNesting.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class GroupNesting extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
protected array $_accessible = [
'*' => true,
'id' => false,
diff --git a/app/src/Model/Entity/HistoryRecord.php b/app/src/Model/Entity/HistoryRecord.php
index e91d7ed76..b60ba647c 100644
--- a/app/src/Model/Entity/HistoryRecord.php
+++ b/app/src/Model/Entity/HistoryRecord.php
@@ -32,11 +32,25 @@
use Cake\ORM\Entity;
class HistoryRecord extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
'id' => false,
'slug' => false,
];
+
+ /**
+ * Determine if this entity is Read Only.
+ *
+ * @since COmanage Registry v5.2.0
+ * @param Entity $entity Cake Entity
+ * @return boolean true if the entity is read only, false otherwise
+ */
+
+ public function isReadOnly(): bool {
+ // History records can't be altered once created
+
+ return true;
+ }
}
\ No newline at end of file
diff --git a/app/src/Model/Entity/Identifier.php b/app/src/Model/Entity/Identifier.php
index 4a8128563..048c077dc 100644
--- a/app/src/Model/Entity/Identifier.php
+++ b/app/src/Model/Entity/Identifier.php
@@ -33,7 +33,6 @@
class Identifier extends Entity {
use \App\Lib\Traits\EntityMetaTrait;
- use \App\Lib\Traits\ReadOnlyEntityTrait;
use \App\Lib\Traits\MVETrait;
protected array $_accessible = [
diff --git a/app/src/Model/Entity/IdentifierAssignment.php b/app/src/Model/Entity/IdentifierAssignment.php
index 35db54f9e..a186eca4c 100644
--- a/app/src/Model/Entity/IdentifierAssignment.php
+++ b/app/src/Model/Entity/IdentifierAssignment.php
@@ -32,7 +32,7 @@
use Cake\ORM\Entity;
class IdentifierAssignment extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/Job.php b/app/src/Model/Entity/Job.php
index 1b74fed24..617b352ab 100644
--- a/app/src/Model/Entity/Job.php
+++ b/app/src/Model/Entity/Job.php
@@ -33,6 +33,8 @@
use \App\Lib\Enum\JobStatusEnum;
class Job extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
protected array $_accessible = [
'*' => true,
'id' => false,
diff --git a/app/src/Model/Entity/JobHistoryRecord.php b/app/src/Model/Entity/JobHistoryRecord.php
index 9fab7a9f8..d96626687 100644
--- a/app/src/Model/Entity/JobHistoryRecord.php
+++ b/app/src/Model/Entity/JobHistoryRecord.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class JobHistoryRecord extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
protected array $_accessible = [
'*' => true,
'id' => false,
diff --git a/app/src/Model/Entity/MessageTemplate.php b/app/src/Model/Entity/MessageTemplate.php
index e2eb1825b..9a0c62903 100644
--- a/app/src/Model/Entity/MessageTemplate.php
+++ b/app/src/Model/Entity/MessageTemplate.php
@@ -34,7 +34,7 @@
use Cake\Routing\Router;
class MessageTemplate extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/MostlyStaticPage.php b/app/src/Model/Entity/MostlyStaticPage.php
index 353846c0f..7f7c586ca 100644
--- a/app/src/Model/Entity/MostlyStaticPage.php
+++ b/app/src/Model/Entity/MostlyStaticPage.php
@@ -32,7 +32,7 @@
use Cake\ORM\Entity;
class MostlyStaticPage extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/Name.php b/app/src/Model/Entity/Name.php
index 70fe676a5..edc2475ac 100644
--- a/app/src/Model/Entity/Name.php
+++ b/app/src/Model/Entity/Name.php
@@ -33,7 +33,6 @@
class Name extends Entity {
use \App\Lib\Traits\EntityMetaTrait;
- use \App\Lib\Traits\ReadOnlyEntityTrait;
use \App\Lib\Traits\MVETrait;
protected array $_accessible = [
diff --git a/app/src/Model/Entity/Notification.php b/app/src/Model/Entity/Notification.php
index d2e42dc9c..5e95a6a02 100644
--- a/app/src/Model/Entity/Notification.php
+++ b/app/src/Model/Entity/Notification.php
@@ -33,6 +33,8 @@
use \App\Lib\Enum\NotificationStatusEnum;
class Notification extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
protected array $_accessible = [
'*' => true,
'id' => false,
diff --git a/app/src/Model/Entity/Person.php b/app/src/Model/Entity/Person.php
index 46b1f42c1..23c67a9a5 100644
--- a/app/src/Model/Entity/Person.php
+++ b/app/src/Model/Entity/Person.php
@@ -33,7 +33,7 @@
use \App\Lib\Enum\StatusEnum;
class Person extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/PersonRole.php b/app/src/Model/Entity/PersonRole.php
index bae395c4d..dfbd76688 100644
--- a/app/src/Model/Entity/PersonRole.php
+++ b/app/src/Model/Entity/PersonRole.php
@@ -33,7 +33,7 @@
use \App\Lib\Enum\StatusEnum;
class PersonRole extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
@@ -69,4 +69,16 @@ public function isValid(): bool {
&& (!$this->valid_from || $this->valid_from->isPast())
&& (!$this->valid_through || $this->valid_through->isFuture());
}
+
+ /**
+ * Determine the source attribute foreign key (eg: source_name_id) for this entity.
+ *
+ * @since COmanage Registry v5.2.0
+ * @return string Source Attribute column name
+ */
+
+ public function sourceAttributeName(): string {
+ // PersonRoles doesn't follow the standard pattern
+ return "source_external_identity_role_id";
+ }
}
\ No newline at end of file
diff --git a/app/src/Model/Entity/Petition.php b/app/src/Model/Entity/Petition.php
index 7395ada80..be71b59e6 100644
--- a/app/src/Model/Entity/Petition.php
+++ b/app/src/Model/Entity/Petition.php
@@ -34,7 +34,7 @@
use \App\Lib\Enum\PetitionStatusEnum;
class Petition extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait {
+ use \App\Lib\Traits\EntityMetaTrait {
isReadOnly as traitIsReadOnly;
}
diff --git a/app/src/Model/Entity/PetitionHistoryRecord.php b/app/src/Model/Entity/PetitionHistoryRecord.php
index 7e30ea221..51c3e75cc 100644
--- a/app/src/Model/Entity/PetitionHistoryRecord.php
+++ b/app/src/Model/Entity/PetitionHistoryRecord.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class PetitionHistoryRecord extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
protected array $_accessible = [
'*' => true,
'id' => false,
diff --git a/app/src/Model/Entity/PetitionStepResult.php b/app/src/Model/Entity/PetitionStepResult.php
index 55ce62b9b..3872fcaa0 100644
--- a/app/src/Model/Entity/PetitionStepResult.php
+++ b/app/src/Model/Entity/PetitionStepResult.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class PetitionStepResult extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
protected array $_accessible = [
'*' => true,
'id' => false,
diff --git a/app/src/Model/Entity/Pipeline.php b/app/src/Model/Entity/Pipeline.php
index f1c73d267..71831343d 100644
--- a/app/src/Model/Entity/Pipeline.php
+++ b/app/src/Model/Entity/Pipeline.php
@@ -32,7 +32,7 @@
use Cake\ORM\Entity;
class Pipeline extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/Plugin.php b/app/src/Model/Entity/Plugin.php
index fd0deac65..9c7a8b063 100644
--- a/app/src/Model/Entity/Plugin.php
+++ b/app/src/Model/Entity/Plugin.php
@@ -33,6 +33,8 @@
use \App\Lib\Enum\SuspendableStatusEnum;
class Plugin extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
protected array $_accessible = [
'*' => true,
'id' => false,
diff --git a/app/src/Model/Entity/Pronoun.php b/app/src/Model/Entity/Pronoun.php
index 866f4e4ef..c70c2bf69 100644
--- a/app/src/Model/Entity/Pronoun.php
+++ b/app/src/Model/Entity/Pronoun.php
@@ -34,7 +34,6 @@
// Strictly speaking, this should probably be "Pronouns", but it's easier not to fight inflection
class Pronoun extends Entity {
use \App\Lib\Traits\EntityMetaTrait;
- use \App\Lib\Traits\ReadOnlyEntityTrait;
use \App\Lib\Traits\MVETrait;
protected array $_accessible = [
diff --git a/app/src/Model/Entity/ProvisioningHistoryRecord.php b/app/src/Model/Entity/ProvisioningHistoryRecord.php
index fec2cae16..db85b44de 100644
--- a/app/src/Model/Entity/ProvisioningHistoryRecord.php
+++ b/app/src/Model/Entity/ProvisioningHistoryRecord.php
@@ -32,6 +32,8 @@
use Cake\ORM\Entity;
class ProvisioningHistoryRecord extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
protected array $_accessible = [
'*' => true,
'id' => false,
diff --git a/app/src/Model/Entity/ProvisioningTarget.php b/app/src/Model/Entity/ProvisioningTarget.php
index dc654a002..ccd484ad9 100644
--- a/app/src/Model/Entity/ProvisioningTarget.php
+++ b/app/src/Model/Entity/ProvisioningTarget.php
@@ -33,7 +33,7 @@
use \App\Lib\Enum\ProvisionerModeEnum;
class ProvisioningTarget extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/Server.php b/app/src/Model/Entity/Server.php
index d7d1867a9..9f94981ad 100644
--- a/app/src/Model/Entity/Server.php
+++ b/app/src/Model/Entity/Server.php
@@ -32,7 +32,7 @@
use Cake\ORM\Entity;
class Server extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/TelephoneNumber.php b/app/src/Model/Entity/TelephoneNumber.php
index 61c82429c..4b00184f4 100644
--- a/app/src/Model/Entity/TelephoneNumber.php
+++ b/app/src/Model/Entity/TelephoneNumber.php
@@ -33,7 +33,6 @@
class TelephoneNumber extends Entity {
use \App\Lib\Traits\EntityMetaTrait;
- use \App\Lib\Traits\ReadOnlyEntityTrait;
use \App\Lib\Traits\MVETrait;
protected array $_accessible = [
diff --git a/app/src/Model/Entity/TrafficDetour.php b/app/src/Model/Entity/TrafficDetour.php
index 068434d4f..a13b5efcb 100644
--- a/app/src/Model/Entity/TrafficDetour.php
+++ b/app/src/Model/Entity/TrafficDetour.php
@@ -32,7 +32,7 @@
use Cake\ORM\Entity;
class TrafficDetour extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/Type.php b/app/src/Model/Entity/Type.php
index 4c14825a2..77a732059 100644
--- a/app/src/Model/Entity/Type.php
+++ b/app/src/Model/Entity/Type.php
@@ -32,7 +32,7 @@
use Cake\ORM\Entity;
class Type extends Entity {
- use \App\Lib\Traits\ReadOnlyEntityTrait;
+ use \App\Lib\Traits\EntityMetaTrait;
protected array $_accessible = [
'*' => true,
diff --git a/app/src/Model/Entity/Url.php b/app/src/Model/Entity/Url.php
index f990ba436..e4613b07d 100644
--- a/app/src/Model/Entity/Url.php
+++ b/app/src/Model/Entity/Url.php
@@ -33,7 +33,6 @@
class Url extends Entity {
use \App\Lib\Traits\EntityMetaTrait;
- use \App\Lib\Traits\ReadOnlyEntityTrait;
use \App\Lib\Traits\MVETrait;
protected array $_accessible = [
diff --git a/app/src/Model/Entity/Verification.php b/app/src/Model/Entity/Verification.php
index 252369ceb..7ab825f06 100644
--- a/app/src/Model/Entity/Verification.php
+++ b/app/src/Model/Entity/Verification.php
@@ -33,6 +33,8 @@
use App\Lib\Enum\VerificationMethodEnum;
class Verification extends Entity {
+ use \App\Lib\Traits\EntityMetaTrait;
+
protected array $_accessible = [
'*' => true,
'id' => false,
diff --git a/app/templates/Standard/add-edit-view.php b/app/templates/Standard/add-edit-view.php
index 24ad18887..1e2a8dbad 100644
--- a/app/templates/Standard/add-edit-view.php
+++ b/app/templates/Standard/add-edit-view.php
@@ -91,6 +91,16 @@
= $title ?>
+ changelogAttributeName();
+
+ if($vv_obj->deleted) {
+ print __d('information', 'changelog.deleted');
+ } elseif(!empty($vv_obj->$clfield)) {
+ print __d('information', 'changelog.archived');
+ }
+ ?>
Form->end();
-
/** MVEA Canvas output **/
if($vv_action != 'add' && !empty($mveas)) {
// Pass along the $mveas and any $addMenuLinks defined in templates/.../fields-nav.inc config.
@@ -228,4 +237,7 @@
]);
}
-// XXX insert changelog metadata (+nav? or maybe we should have a dedicate index view that shows all records in revision order?)
+if($vv_action != 'add') {
+ // Insert changelog
+ print $this->element('changelog');
+}
\ No newline at end of file
diff --git a/app/templates/element/changelog.php b/app/templates/element/changelog.php
new file mode 100644
index 000000000..63987cede
--- /dev/null
+++ b/app/templates/element/changelog.php
@@ -0,0 +1,108 @@
+changelogAttributeName();
+$parentLink = null;
+
+if(!empty($vv_obj->$clAttr)) {
+ $parentLink = $this->Html->link(
+ $vv_obj->$clAttr,
+ ['action' => 'edit', $vv_obj->$clAttr]
+ );
+}
+
+// We'll render an index of all archived records if we are the current active record,
+// or just the current metadata if we are an archived record
+?>
+
+= __d('information', 'changelog') ?>
+
+
+
+
+
+ = __d('field', 'id') ?> |
+ = __d('field', 'changelog.revision') ?> |
+ = __d('field', 'modified') ?> |
+ = __d('field', 'changelog.actor_identifier') ?> |
+
+
+
+ =
+ // In general it's confusing to have a link back to the record currently being displayed,
+ // so just echo the ID without making it a link
+ $vv_obj->id
+ ?> |
+ = $vv_obj->revision ?> |
+ = $vv_obj->modified ?> |
+ = $vv_obj->actor_identifier ?> |
+
+
+
+ =
+ $this->Html->link(
+ $archive->id,
+ ['action' => 'view', $archive->id]
+ )
+ ?> |
+ = $archive->revision ?> |
+ = $archive->modified ?> |
+ = $archive->actor_identifier ?> |
+
+
+
+
+
+
+
+
+ = __d('field', 'changelog.deleted') ?> |
+ = __d('enumeration', 'YesBooleanEnum.'.($vv_obj->deleted ? '1' : '0')) ?> |
+
+
+ = __d('field', 'changelog.revision') ?> |
+ = $vv_obj->revision; ?> |
+
+
+ = __d('field', 'modified') ?> |
+ = $vv_obj->modified ?> |
+
+
+ = __d('field', 'changelog.actor_identifier') ?> |
+ = $vv_obj->actor_identifier ?> |
+
+
+ = __d('field', 'changelog.parent') ?> |
+ = $parentLink ?> |
+
+
+
+
\ No newline at end of file