From 7037c3b0433416351ae9bb02151e4f787c313a91 Mon Sep 17 00:00:00 2001 From: Benn Oshrin Date: Tue, 25 Jan 2022 20:25:03 -0500 Subject: [PATCH] Initial implementation of EmailAddress (CFM-14) and Identifier (CFM-15) --- app/config/schema/schema.json | 28 ++- app/resources/locales/en_US/controller.po | 6 + app/resources/locales/en_US/defaultType.po | 75 +++++++ app/resources/locales/en_US/field.po | 18 ++ app/src/Command/TransmogrifyCommand.php | 31 ++- .../Component/RegistryAuthComponent.php | 2 +- .../Controller/EmailAddressesController.php | 64 ++++++ app/src/Controller/IdentifiersController.php | 64 ++++++ app/src/Model/Entity/EmailAddress.php | 42 ++++ app/src/Model/Entity/Identifier.php | 4 +- app/src/Model/Table/CoSettingsTable.php | 21 +- app/src/Model/Table/EmailAddressesTable.php | 187 ++++++++++++++++ app/src/Model/Table/IdentifiersTable.php | 199 ++++++++++++++++++ app/src/Model/Table/NamesTable.php | 2 +- app/src/Model/Table/PeopleTable.php | 4 + app/src/Model/Table/TypesTable.php | 17 +- app/templates/CoSettings/fields.inc | 4 + app/templates/Cos/columns.inc | 2 +- app/templates/EmailAddresses/columns.inc | 35 +++ app/templates/EmailAddresses/fields.inc | 38 ++++ app/templates/Identifiers/columns.inc | 35 +++ app/templates/Identifiers/fields.inc | 37 ++++ app/templates/People/fields.inc | 22 ++ app/templates/Types/columns.inc | 3 +- 24 files changed, 920 insertions(+), 20 deletions(-) create mode 100644 app/src/Controller/EmailAddressesController.php create mode 100644 app/src/Controller/IdentifiersController.php create mode 100644 app/src/Model/Entity/EmailAddress.php create mode 100644 app/src/Model/Table/EmailAddressesTable.php create mode 100644 app/src/Model/Table/IdentifiersTable.php create mode 100644 app/templates/EmailAddresses/columns.inc create mode 100644 app/templates/EmailAddresses/fields.inc create mode 100644 app/templates/Identifiers/columns.inc create mode 100644 app/templates/Identifiers/fields.inc diff --git a/app/config/schema/schema.json b/app/config/schema/schema.json index 96b97e7bf..c730bf39d 100644 --- a/app/config/schema/schema.json +++ b/app/config/schema/schema.json @@ -62,6 +62,8 @@ "id": {}, "co_id": {}, "address_required_fields": { "type": "string", "size": 160 }, + "email_address_default_type_id": { "type": "integer", "foreignkey": { "table": "types", "column": "id" } }, + "identifier_default_type_id": { "type": "integer", "foreignkey": { "table": "types", "column": "id" } }, "name_default_type_id": { "type": "integer", "foreignkey": { "table": "types", "column": "id" } }, "name_permitted_fields": { "type": "string", "size": 160 }, "name_required_fields": { "type": "string", "size": 160 } @@ -74,7 +76,9 @@ "typeIsDefault will make queries using these columns, but rarely and won't usually have enough rows to need the index" ], "columns": [ "name_default_type_id" ] - } + }, + "co_settings_i3": { "columns": [ "email_address_default_type_id" ] }, + "co_settings_i4": { "columns": [ "identifier_default_type_id" ] } } }, @@ -176,14 +180,13 @@ "display_name": { "type": "string", "size": 256 } }, "indexes": { - "names_i1": { "columns": [ "type_id"] } + "names_i1": { "columns": [ "type_id" ] } }, "mvea": [ "person", "external_identity" ], "sourced": true }, "identifiers": { - "XXX": [ "add index for co_provision_target_id+co_person_id" ], "columns": { "id": {}, "identifier": { "type": "string", "size": 512 }, @@ -194,7 +197,24 @@ "indexes": { "identifiers_i1": { "columns": [ "identifier", "type_id", "person_id" ] }, "identifiers_i2": { "columns": [ "identifier", "type_id", "external_identity_id" ] }, - "identifiers_i3": { "columns": [ "type_id"] } + "identifiers_i3": { "columns": [ "type_id" ] } + }, + "mvea": [ "person", "external_identity" ], + "sourced": true + }, + + "email_addresses": { + "columns": { + "id": {}, + "mail": { "type": "string", "size": 256 }, + "description": {}, + "type_id": {}, + "verified": { "type": "boolean" } + }, + "indexes": { + "email_addresses_i1": { "columns": [ "mail", "type_id", "person_id" ] }, + "email_addresses_i2": { "columns": [ "mail", "type_id", "external_identity_id" ] }, + "email_addresses_i3": { "columns": [ "type_id" ] } }, "mvea": [ "person", "external_identity" ], "sourced": true diff --git a/app/resources/locales/en_US/controller.po b/app/resources/locales/en_US/controller.po index e085388fd..ee178b23f 100644 --- a/app/resources/locales/en_US/controller.po +++ b/app/resources/locales/en_US/controller.po @@ -39,9 +39,15 @@ msgstr "{0,plural,=1{COU} other{COUs}}" msgid "Dashboards" msgstr "{0,plural,=1{Dashboard} other{Dashboards}}" +msgid "EmailAddresses" +msgstr "{0,plural,=1{Email Address} other{Email Addresses}}" + msgid "ExternalIdentities" msgstr "{0,plural,=1{External Identity} other{External Identities}}" +msgid "Identifiers" +msgstr "{0,plural,=1{Identifier} other{Identifiers}}" + msgid "Names" msgstr "{0,plural,=1{Name} other{Names}}" diff --git a/app/resources/locales/en_US/defaultType.po b/app/resources/locales/en_US/defaultType.po index ca0cf9afe..e143f504e 100644 --- a/app/resources/locales/en_US/defaultType.po +++ b/app/resources/locales/en_US/defaultType.po @@ -24,6 +24,81 @@ # Labels for default types when a new CO is created +msgid "EmailAddresses.delivery" +msgstr "Delivery" + +msgid "EmailAddresses.forwarding" +msgstr "Forwarding" + +msgid "EmailAddresses.list" +msgstr "Mailing List" + +msgid "EmailAddresses.official" +msgstr "Official" + +msgid "EmailAddresses.personal" +msgstr "Personal" + +msgid "EmailAddresses.preferred" +msgstr "Preferred" + +msgid "EmailAddresses.recovery" +msgstr "Recovery" + +msgid "Identifiers.badge" +msgstr "Badge" + +msgid "Identifiers.enterprise" +msgstr "Enterprise" + +msgid "Identifiers.eppn" +msgstr "ePPN" + +msgid "Identifiers.eptid" +msgstr "ePTID" + +msgid "Identifiers.epuid" +msgstr "ePUID" + +msgid "Identifiers.gid" +msgstr "GID" + +msgid "Identifiers.mail" +msgstr "Mail" + +msgid "Identifiers.national" +msgstr "National" + +msgid "Identifiers.network" +msgstr "Network" + +msgid "Identifiers.oidcsub" +msgstr "OIDC Sub" + +msgid "Identifiers.openid" +msgstr "OpenID" + +msgid "Identifiers.orcid" +msgstr "ORCiD" + +msgid "Identifiers.provisioningtarget" +msgstr "Provisioning Target" + +msgid "Identifiers.reference" +msgstr "Match Reference" + +msgid "Identifiers.pairwiseid" +msgstr "SAML Pairwise" + +msgid "Identifiers.subjectid" +msgstr "SAML Subject" + +msgid "Identifiers.sorid" +msgstr "System of Record" + +msgid "Identifiers.uid" +msgstr "UID" + msgid "Names.alternate" msgstr "Alternate" diff --git a/app/resources/locales/en_US/field.po b/app/resources/locales/en_US/field.po index 2a1b8207c..c0d99963d 100644 --- a/app/resources/locales/en_US/field.po +++ b/app/resources/locales/en_US/field.po @@ -38,6 +38,12 @@ msgstr "Attribute" msgid "CoSettings.address_required_fields" msgstr "Address Required Fields" +msgid "CoSettings.email_address_default_type_id" +msgstr "Default Email Address Type" + +msgid "CoSettings.identifier_default_type_id" +msgstr "Default Identifier Type" + msgid "CoSettings.name_default_type_id" msgstr "Default Name Type" @@ -75,12 +81,21 @@ msgstr "Honorific" msgid "honorific.desc" msgstr "(Dr, Hon, etc)" +msgid "identifier" +msgstr "Identifier" + msgid "full_name" msgstr "Full Name" msgid "language" msgstr "Language" +msgid "login" +msgstr "Login" + +msgid "mail" +msgstr "Email Address" + msgid "middle" msgstr "Middle" @@ -152,3 +167,6 @@ msgstr "Database Value" msgid "Types.value.desc" msgstr "Database value for this type, characters must be alphanumeric, dot, or dash" + +msgid "verified" +msgstr "Verified" \ No newline at end of file diff --git a/app/src/Command/TransmogrifyCommand.php b/app/src/Command/TransmogrifyCommand.php index 13ad7c83d..b03bf4717 100644 --- a/app/src/Command/TransmogrifyCommand.php +++ b/app/src/Command/TransmogrifyCommand.php @@ -93,7 +93,10 @@ class TransmogrifyCommand extends Command { 'elect_strategy_primary_name' => null, 'co_dashboard_id' => null, 'co_theme_id' => null, - 'global_search_limit' => null + 'global_search_limit' => null, + 'person_picker_email_type' => null, + 'person_picker_identifier_type' => null, + 'person_picker_display_types' => null ] ], 'api_users' => [ @@ -158,6 +161,20 @@ class TransmogrifyCommand extends Command { 'co_provisioning_target_id' => null, 'organization_id' => null ] + ], + 'email_addresses' => [ + 'source' => 'cm_email_addresses', + 'displayField' => 'id', + 'booleans' => [ 'verified' ], + 'fieldMap' => [ + 'co_person_id' => 'person_id', + 'org_identity_id' => 'external_identity_id', + 'type_id' => '&map_email_type', + 'type' => null, +// XXX temporary until tables are migrated + 'co_department_id' => null, + 'organization_id' => null + ] ] ]; @@ -498,6 +515,18 @@ protected function mapFields(string $table, array &$row) { } } + /** + * Map an email type string to a foreign key. + * + * @since COmanage Registry v5.0.0 + * @param array $row Row of table data (ignored) + * @return int type_id + */ + + protected function map_email_type(array $row) { + return $this->map_type($row, 'EmailAddresses.type', $this->findCoId($row)); + } + /** * Map an Extended Type attribute name for model name changes. * diff --git a/app/src/Controller/Component/RegistryAuthComponent.php b/app/src/Controller/Component/RegistryAuthComponent.php index 0d873194c..06b37a163 100644 --- a/app/src/Controller/Component/RegistryAuthComponent.php +++ b/app/src/Controller/Component/RegistryAuthComponent.php @@ -273,7 +273,7 @@ public function calculatePermissionsForView(string $action, ?int $id=null): arra * @return string The authenticated user identifier or false if no authenticated user */ - public function getAuthenticatedUser(): string { + public function getAuthenticatedUser(): ?string { return $this->authenticatedUser; } diff --git a/app/src/Controller/EmailAddressesController.php b/app/src/Controller/EmailAddressesController.php new file mode 100644 index 000000000..703bf4009 --- /dev/null +++ b/app/src/Controller/EmailAddressesController.php @@ -0,0 +1,64 @@ + [ + 'EmailAddresses.mail' => 'asc' + ] + ]; + + /** + * Callback run prior to the request render. + * + * @since COmanage Registry v5.0.0 + * @param EventInterface $event Cake Event + * @return \Cake\Http\Response HTTP Response + */ + + public function beforeRender(\Cake\Event\EventInterface $event) { + if(!$this->request->is('restful')) { +// XXX maybe $CoSettings should be available via AppController, like $this->getCOID()? + $CoSettings = TableRegistry::getTableLocator()->get('CoSettings'); + + $settings = $CoSettings->find()->where(['co_id' => $this->getCOID()])->firstOrFail(); + +// XXX move this into MVEAController or a trait + $this->set('vv_default_type', $settings->email_address_default_type_id); + } + + return parent::beforeRender($event); + } +} \ No newline at end of file diff --git a/app/src/Controller/IdentifiersController.php b/app/src/Controller/IdentifiersController.php new file mode 100644 index 000000000..cfdd8302b --- /dev/null +++ b/app/src/Controller/IdentifiersController.php @@ -0,0 +1,64 @@ + [ + 'Identifiers.identifier' => 'asc' + ] + ]; + + /** + * Callback run prior to the request render. + * + * @since COmanage Registry v5.0.0 + * @param EventInterface $event Cake Event + * @return \Cake\Http\Response HTTP Response + */ + + public function beforeRender(\Cake\Event\EventInterface $event) { + if(!$this->request->is('restful')) { +// XXX maybe $CoSettings should be available via AppController, like $this->getCOID()? + $CoSettings = TableRegistry::getTableLocator()->get('CoSettings'); + + $settings = $CoSettings->find()->where(['co_id' => $this->getCOID()])->firstOrFail(); + +// XXX move this into MVEAController or a trait + $this->set('vv_default_type', $settings->identifier_default_type_id); + } + + return parent::beforeRender($event); + } +} \ No newline at end of file diff --git a/app/src/Model/Entity/EmailAddress.php b/app/src/Model/Entity/EmailAddress.php new file mode 100644 index 000000000..4a3911f2c --- /dev/null +++ b/app/src/Model/Entity/EmailAddress.php @@ -0,0 +1,42 @@ + true, + 'id' => false, + 'slug' => false, + ]; +} \ No newline at end of file diff --git a/app/src/Model/Entity/Identifier.php b/app/src/Model/Entity/Identifier.php index 0ce1203b3..e2da65b54 100644 --- a/app/src/Model/Entity/Identifier.php +++ b/app/src/Model/Entity/Identifier.php @@ -1,6 +1,6 @@ true, 'id' => false, diff --git a/app/src/Model/Table/CoSettingsTable.php b/app/src/Model/Table/CoSettingsTable.php index 3036769ae..632c13667 100644 --- a/app/src/Model/Table/CoSettingsTable.php +++ b/app/src/Model/Table/CoSettingsTable.php @@ -72,10 +72,19 @@ public function initialize(array $config): void { // Define associations $this->belongsTo('Cos'); - $this->belongsTo('Types') - ->setForeignKey('name_default_type_id') + $this->belongsTo('EmailAddressDefaultTypes') + ->setClassName('Types') + ->setForeignKey('email_address_default_type_id') // Property is set so ruleValidateCO can find it. We don't use the // _id suffix to match Cake's default pattern. + ->setProperty('email_address_default_type'); + $this->belongsTo('IdentifierDefaultTypes') + ->setClassName('Types') + ->setForeignKey('identifier_default_type_id') + ->setProperty('identifier_default_type'); + $this->belongsTo('NameDefaultTypes') + ->setClassName('Types') + ->setForeignKey('name_default_type_id') ->setProperty('name_default_type'); $this->setDisplayField('co_id'); @@ -90,6 +99,14 @@ public function initialize(array $config): void { 'type' => 'enum', 'class' => 'RequiredAddressFieldsEnum' ], + 'emailAddressDefaultTypes' => [ + 'type' => 'type', + 'attribute' => 'EmailAddresses.type' + ], + 'identifierDefaultTypes' => [ + 'type' => 'type', + 'attribute' => 'Identifiers.type' + ], 'nameDefaultTypes' => [ 'type' => 'type', 'attribute' => 'Names.type' diff --git a/app/src/Model/Table/EmailAddressesTable.php b/app/src/Model/Table/EmailAddressesTable.php new file mode 100644 index 000000000..34110f34b --- /dev/null +++ b/app/src/Model/Table/EmailAddressesTable.php @@ -0,0 +1,187 @@ + [ + 'delivery', + 'forwarding', + 'list', + 'official', + 'personal', + 'preferred', + 'recovery' + ] + ]; + + /** + * Perform Cake Model initialization. + * + * @since COmanage Registry v5.0.0 + * @param array $config Configuration options passed to constructor + */ + + public function initialize(array $config): void { + // Timestamp behavior handles created/modified updates + $this->addBehavior('Changelog'); + $this->addBehavior('Log'); + $this->addBehavior('Timestamp'); + + // Identifiers are not configuration + $this->setIsConfigurationTable(false); + + // Define associations + $this->belongsTo('People'); + $this->belongsTo('ExternalIdentity'); + $this->belongsTo('Types'); + + $this->setDisplayField('mail'); + +// XXX note primary link is external_identity_id when set... + $this->setPrimaryLink('person_id'); + $this->setAllowLookupPrimaryLink(['primary']); + $this->setRequiresCO(true); + + $this->setAutoViewVars([ + 'types' => [ + 'type' => 'type', + 'attribute' => 'EmailAddresses.type' + ] + ]); + + $this->setPermissions([ + // Actions that operate over an entity (ie: require an $id) + 'entity' => [ + 'delete' => ['platformAdmin', 'coAdmin'], + 'edit' => ['platformAdmin', 'coAdmin'], + 'primary' => ['platformAdmin', 'coAdmin'], + 'view' => ['platformAdmin', 'coAdmin'] + ], + // Actions that operate over a table (ie: do not require an $id) + 'table' => [ + 'add' => ['platformAdmin', 'coAdmin'], + 'index' => ['platformAdmin', 'coAdmin'] + ] + ]); + } + + /** + * Set validation rules. + * + * @since COmanage Registry v5.0.0 + * @param Validator $validator Validator + * @return Validator Validator + * @throws InvalidArgumentException + * @throws RecordNotFoundException + */ + + public function validationDefault(Validator $validator): Validator { + // One of Person ID or External Identity ID is required + $validator->add( + 'person_id', + 'content', + [ 'rule' => 'isInteger' ] + ); + $validator->notEmptyString('person_id', null, function($context) { + return empty($context['data']['external_identity_id']); + }); + + $validator->add( + 'external_identity_id', + 'content', + [ 'rule' => 'isInteger' ] + ); + $validator->notEmptyString('external_identity_id', null, function($context) { + return empty($context['data']['person_id']); + }); + + $validator->add( + 'mail', + 'length', + [ 'rule' => [ 'maxLength', 256 ] ] + ); + $validator->add( + 'mail', + 'content', + [ 'rule' => [ 'email' ] ] + ); + $validator->notEmptyString('mail'); + + $validator->add( + 'type_id', + 'content', + [ 'rule' => 'isInteger' ] + ); + $validator->notEmptyString('type_id'); + + $validator->add( + 'verified', + 'content', + [ 'rule' => [ 'boolean' ] ] + ); + $validator->allowEmptyString('verified'); + + $validator->add( + 'description', + 'content', + [ 'rule' => [ 'maxLength', 128 ] ] + ); + $validator->add( + 'description', + 'content', + [ 'rule' => [ 'validateInput' ], + 'provider' => 'table' ] + ); + $validator->allowEmptyString('description'); + + $validator->add( + 'source_email_address_id', + 'content', + [ 'rule' => 'isInteger' ] + ); + $validator->allowEmptyString('source_email_address_id'); + + return $validator; + } +} \ No newline at end of file diff --git a/app/src/Model/Table/IdentifiersTable.php b/app/src/Model/Table/IdentifiersTable.php new file mode 100644 index 000000000..b52c86ff4 --- /dev/null +++ b/app/src/Model/Table/IdentifiersTable.php @@ -0,0 +1,199 @@ + [ + 'badge', + 'enterprise', + 'eppn', + 'eptid', + 'epuid', + 'gid', + 'mail', + 'national', + 'network', + 'oidcsub', + 'openid', + 'orcid', + 'provisioningtarget', + 'reference', + 'pairwiseid', + 'subjectid', + 'sorid', + 'uid' + ] + ]; + + /** + * Perform Cake Model initialization. + * + * @since COmanage Registry v5.0.0 + * @param array $config Configuration options passed to constructor + */ + + public function initialize(array $config): void { + // Timestamp behavior handles created/modified updates + $this->addBehavior('Changelog'); + $this->addBehavior('Log'); + $this->addBehavior('Timestamp'); + + // Identifiers are not configuration + $this->setIsConfigurationTable(false); + + // Define associations + $this->belongsTo('People'); + $this->belongsTo('ExternalIdentity'); + $this->belongsTo('Types'); + + $this->setDisplayField('identifier'); + +// XXX note primary link is external_identity_id when set... + $this->setPrimaryLink('person_id'); + $this->setAllowLookupPrimaryLink(['primary']); + $this->setRequiresCO(true); + + $this->setAutoViewVars([ + 'types' => [ + 'type' => 'type', + 'attribute' => 'Identifiers.type' + ], + 'statuses' => [ + 'type' => 'enum', + 'class' => 'TemplateableStatusEnum' + ] + ]); + + $this->setPermissions([ + // Actions that operate over an entity (ie: require an $id) + 'entity' => [ + 'delete' => ['platformAdmin', 'coAdmin'], + 'edit' => ['platformAdmin', 'coAdmin'], + 'primary' => ['platformAdmin', 'coAdmin'], + 'view' => ['platformAdmin', 'coAdmin'] + ], + // Actions that operate over a table (ie: do not require an $id) + 'table' => [ + 'add' => ['platformAdmin', 'coAdmin'], + 'index' => ['platformAdmin', 'coAdmin'] + ] + ]); + } + + /** + * Set validation rules. + * + * @since COmanage Registry v5.0.0 + * @param Validator $validator Validator + * @return Validator Validator + * @throws InvalidArgumentException + * @throws RecordNotFoundException + */ + + public function validationDefault(Validator $validator): Validator { + // One of Person ID or External Identity ID is required + $validator->add( + 'person_id', + 'content', + [ 'rule' => 'isInteger' ] + ); + $validator->notEmptyString('person_id', null, function($context) { + return empty($context['data']['external_identity_id']); + }); + + $validator->add( + 'external_identity_id', + 'content', + [ 'rule' => 'isInteger' ] + ); + $validator->notEmptyString('external_identity_id', null, function($context) { + return empty($context['data']['person_id']); + }); + + $validator->add( + 'identifier', + 'length', + [ 'rule' => [ 'maxLength', 512 ] ] + ); + $validator->add( + 'identifier', + 'content', + // Identifier must have at least one non-space character in order to avoid + // errors (eg: with provisioning ldap) + [ 'rule' => [ 'notBlank' ] ] + ); + $validator->notEmptyString('identifier'); + + $validator->add( + 'type_id', + 'content', + [ 'rule' => 'isInteger' ] + ); + $validator->notEmptyString('type_id'); + + $validator->add( + 'login', + 'content', + [ 'rule' => [ 'boolean' ] ] + ); + $validator->allowEmptyString('login'); + + $validator->add( + 'status', + 'content', + [ 'rule' => [ 'inList', SuspendableStatusEnum::getConstValues() ] ] + ); + $validator->notEmptyString('status'); + + $validator->add( + 'source_identifier_id', + 'content', + [ 'rule' => 'isInteger' ] + ); + $validator->allowEmptyString('source_identifier_id'); + + return $validator; + } +} \ No newline at end of file diff --git a/app/src/Model/Table/NamesTable.php b/app/src/Model/Table/NamesTable.php index 43a8fa0e9..72006cdb6 100644 --- a/app/src/Model/Table/NamesTable.php +++ b/app/src/Model/Table/NamesTable.php @@ -256,7 +256,7 @@ public function validationDefault(Validator $validator): Validator { $permittedFields = $settings->name_permitted_fields_array(); $requiredFields = $settings->name_required_fields_array(); - // One of CO Person ID or Org Identity ID is required + // One of Person ID or External Identity ID is required $validator->add( 'person_id', 'content', diff --git a/app/src/Model/Table/PeopleTable.php b/app/src/Model/Table/PeopleTable.php index 504f6b752..9e5d55900 100644 --- a/app/src/Model/Table/PeopleTable.php +++ b/app/src/Model/Table/PeopleTable.php @@ -69,6 +69,10 @@ public function initialize(array $config): void { ->setConditions(['PrimaryName.primary_name' => true]); $this->hasMany('Names') ->setDependent(true); + $this->hasMany('EmailAddresses') + ->setDependent(true); + $this->hasMany('Identifiers') + ->setDependent(true); // XXX can we change this to Name? $this->setDisplayField('id'); diff --git a/app/src/Model/Table/TypesTable.php b/app/src/Model/Table/TypesTable.php index 83f027f91..c7c8acf6b 100644 --- a/app/src/Model/Table/TypesTable.php +++ b/app/src/Model/Table/TypesTable.php @@ -53,15 +53,15 @@ class TypesTable extends Table { protected $testVar = "123"; protected $supportedAttributes = [ -// 'Address.type', -// 'Department.type', -// 'PersonRole.affiliation', -// 'EmailAddress.type', -// 'Identifier.type', +// 'Addresses.type', +// 'Departments.type', +// 'PersonRoles.affiliation', + 'EmailAddresses.type', + 'Identifiers.type', 'Names.type', -// 'Organization.type', -// 'TelephoneNumber.type', -// 'Url.type' +// 'Organizations.type', +// 'TelephoneNumbers.type', +// 'Urls.type' ]; /** @@ -84,6 +84,7 @@ public function initialize(array $config): void { $this->belongsTo('Cos'); $this->hasMany('CoSettings') ->setForeignKey('name_default_type_id'); + $this->hasMany('EmailAddresses'); $this->hasMany('Identifiers'); $this->hasMany('Names'); // XXX add other MVEA models diff --git a/app/templates/CoSettings/fields.inc b/app/templates/CoSettings/fields.inc index 97a970d71..3241ad571 100644 --- a/app/templates/CoSettings/fields.inc +++ b/app/templates/CoSettings/fields.inc @@ -30,6 +30,10 @@ if($vv_action == 'edit') { print $this->Field->control('address_required_fields', ['suppressBlank' => true]); + print $this->Field->control('email_address_default_type_id'); + + print $this->Field->control('identifier_default_type_id'); + print $this->Field->control('name_default_type_id'); print $this->Field->control('name_permitted_fields', ['suppressBlank' => true]); diff --git a/app/templates/Cos/columns.inc b/app/templates/Cos/columns.inc index eaf1efa1b..a7ff2a79e 100644 --- a/app/templates/Cos/columns.inc +++ b/app/templates/Cos/columns.inc @@ -41,7 +41,7 @@ $indexColumns = [ $indexActions = [ [ 'action' => 'duplicate', - 'class' => 'duplicate', + 'class' => '', 'icon' => 'content_copy' ] ]; diff --git a/app/templates/EmailAddresses/columns.inc b/app/templates/EmailAddresses/columns.inc new file mode 100644 index 000000000..93ca3b009 --- /dev/null +++ b/app/templates/EmailAddresses/columns.inc @@ -0,0 +1,35 @@ + [ + 'type' => 'link' + ], + 'type_id' => [ + 'type' => 'fk' + ] +]; diff --git a/app/templates/EmailAddresses/fields.inc b/app/templates/EmailAddresses/fields.inc new file mode 100644 index 000000000..d5790a145 --- /dev/null +++ b/app/templates/EmailAddresses/fields.inc @@ -0,0 +1,38 @@ +Field->control('mail'); + + print $this->Field->control('type_id', ['default' => $vv_default_type]); + + print $this->Field->control('description'); + +// XXX CFM-129 need to implement verification + print $this->Field->control('verified', ['readonly' => true]); +} diff --git a/app/templates/Identifiers/columns.inc b/app/templates/Identifiers/columns.inc new file mode 100644 index 000000000..1d1bac086 --- /dev/null +++ b/app/templates/Identifiers/columns.inc @@ -0,0 +1,35 @@ + [ + 'type' => 'link' + ], + 'type_id' => [ + 'type' => 'fk' + ] +]; diff --git a/app/templates/Identifiers/fields.inc b/app/templates/Identifiers/fields.inc new file mode 100644 index 000000000..f60acc2d5 --- /dev/null +++ b/app/templates/Identifiers/fields.inc @@ -0,0 +1,37 @@ +Field->control('identifier'); + + print $this->Field->control('type_id', ['default' => $vv_default_type]); + + print $this->Field->control('login'); + + print $this->Field->control('status', ['empty' => false]); +} diff --git a/app/templates/People/fields.inc b/app/templates/People/fields.inc index ca4415911..ba55ea479 100644 --- a/app/templates/People/fields.inc +++ b/app/templates/People/fields.inc @@ -64,5 +64,27 @@ if($vv_action == 'add') { ['class' => 'linkbutton'] ); + print $this->Html->link( + __d('controller', 'EmailAddresses', [99]), + [ 'controller' => 'email_addresses', + 'action' => 'index', + '?' => [ + 'person_id' => $vv_obj->id + ] + ], + ['class' => 'linkbutton'] + ); + + print $this->Html->link( + __d('controller', 'Identifiers', [99]), + [ 'controller' => 'identifiers', + 'action' => 'index', + '?' => [ + 'person_id' => $vv_obj->id + ] + ], + ['class' => 'linkbutton'] + ); + // XXX add other MVEAs here } \ No newline at end of file diff --git a/app/templates/Types/columns.inc b/app/templates/Types/columns.inc index 4950f82f1..b0aeca57e 100644 --- a/app/templates/Types/columns.inc +++ b/app/templates/Types/columns.inc @@ -47,6 +47,7 @@ $topLinks = [ 'label' => __d('operation', 'Types.restore'), 'link' => [ 'action' => 'restore' - ] + ], + 'class' => '' ] ]; \ No newline at end of file