diff --git a/app/config/schema/schema.json b/app/config/schema/schema.json index 015d5528c..59f572f25 100644 --- a/app/config/schema/schema.json +++ b/app/config/schema/schema.json @@ -78,6 +78,7 @@ "default_email_address_type_id": { "type": "integer", "foreignkey": { "table": "types", "column": "id" } }, "default_identifier_type_id": { "type": "integer", "foreignkey": { "table": "types", "column": "id" } }, "default_name_type_id": { "type": "integer", "foreignkey": { "table": "types", "column": "id" } }, + "default_pronoun_type_id": { "type": "integer", "foreignkey": { "table": "types", "column": "id" } }, "default_telephone_number_type_id": { "type": "integer", "foreignkey": { "table": "types", "column": "id" } }, "default_url_type_id": { "type": "integer", "foreignkey": { "table": "types", "column": "id" } }, "permitted_fields_name": { "type": "string", "size": 160 }, @@ -99,8 +100,9 @@ "co_settings_i3": { "columns": [ "default_email_address_type_id" ] }, "co_settings_i4": { "columns": [ "default_identifier_type_id" ] }, "co_settings_i5": { "columns": [ "default_address_type_id" ] }, - "co_settings_i6": { "columns": [ "default_telephone_number_type_id" ] }, - "co_settings_i7": { "columns": [ "default_url_type_id" ] } + "co_settings_i6": { "columns": [ "default_pronoun_type_id" ] }, + "co_settings_i7": { "columns": [ "default_telephone_number_type_id" ] }, + "co_settings_i8": { "columns": [ "default_url_type_id" ] } } }, @@ -392,6 +394,20 @@ "sourced": true }, + "pronouns": { + "columns": { + "id": {}, + "pronouns": { "type": "string", "size": 64 }, + "language": {}, + "type_id": {} + }, + "indexes": { + "pronouns_i1": { "columns": [ "type_id" ] } + }, + "mvea": [ "person", "external_identity" ], + "sourced": true + }, + "telephone_numbers": { "columns": { "id": {}, diff --git a/app/resources/locales/en_US/command.po b/app/resources/locales/en_US/command.po index 0f85dc84e..65969df57 100644 --- a/app/resources/locales/en_US/command.po +++ b/app/resources/locales/en_US/command.po @@ -25,7 +25,7 @@ # Command Line text msgid "db.noop" -msgstr "SQL NOT EXECUTED" +msgstr "== SQL NOT EXECUTED ==" msgid "db.ok" msgstr "Database schema update successful" diff --git a/app/resources/locales/en_US/controller.po b/app/resources/locales/en_US/controller.po index 48d41f678..e613cad43 100644 --- a/app/resources/locales/en_US/controller.po +++ b/app/resources/locales/en_US/controller.po @@ -84,6 +84,9 @@ msgstr "{0,plural,=1{Person} other{People}}" msgid "PersonRoles" msgstr "{0,plural,=1{Person Role} other{Person Roles}}" +msgid "Pronouns" +msgstr "{0,plural,=1{Pronoun Preference} other{Pronouns}}" + msgid "TelephoneNumbers" msgstr "{0,plural,=1{Telephone Number} other{Telephone Numbers}}" diff --git a/app/resources/locales/en_US/defaultType.po b/app/resources/locales/en_US/defaultType.po index eec6e4abf..a2634dd47 100644 --- a/app/resources/locales/en_US/defaultType.po +++ b/app/resources/locales/en_US/defaultType.po @@ -150,6 +150,9 @@ msgstr "Staff" msgid "PersonRoles.student" msgstr "Student" +msgid "Pronouns.default" +msgstr "Default" + msgid "Urls.official" msgstr "Official" diff --git a/app/resources/locales/en_US/error.po b/app/resources/locales/en_US/error.po index bbd916b16..af75b2577 100644 --- a/app/resources/locales/en_US/error.po +++ b/app/resources/locales/en_US/error.po @@ -191,11 +191,14 @@ msgid "save" msgstr "Save Failed ({0})" msgid "schema.column" -msgstr "No type defined for table {0} column {1}" +msgstr "No type defined for table \"{0}\" column \"{1}\"" msgid "schema.parse" msgstr "Failed to parse file {0}" +msgid "setup.co.comanage" +msgstr "Failed to setup COmanage CO" + msgid "Types.inuse" msgstr "Type {0} is in use and cannot be deleted" diff --git a/app/resources/locales/en_US/field.po b/app/resources/locales/en_US/field.po index 336d42e27..07110a128 100644 --- a/app/resources/locales/en_US/field.po +++ b/app/resources/locales/en_US/field.po @@ -68,6 +68,9 @@ msgstr "Default Identifier Type" msgid "CoSettings.default_name_type_id" msgstr "Default Name Type" +msgid "CoSettings.default_pronoun_type_id" +msgstr "Default Pronoun Type" + msgid "CoSettings.default_telephone_number_type_id" msgstr "Default Telephone Number Type" @@ -260,6 +263,9 @@ msgstr "Primary Name" msgid "privileged" msgstr "Privileged" +msgid "pronouns" +msgstr "Preferred Pronouns" + msgid "ApiUsers.privileged.desc" msgstr "A privileged API user has full access to the CO. Unprivileged API users may be granted specific permissions where supported." diff --git a/app/src/Command/DatabaseCommand.php b/app/src/Command/DatabaseCommand.php index 32ad6ea73..b2a8ea109 100644 --- a/app/src/Command/DatabaseCommand.php +++ b/app/src/Command/DatabaseCommand.php @@ -294,7 +294,7 @@ public function execute(Arguments $args, ConsoleIo $io) { } if(!$doSQL) { - $io->out(__d('registry', 'db.noop')); + $io->out(__d('command', 'db.noop')); } else { $io->out(__d('command', 'db.ok')); } diff --git a/app/src/Command/TransmogrifyCommand.php b/app/src/Command/TransmogrifyCommand.php index d89dced23..2995f0141 100644 --- a/app/src/Command/TransmogrifyCommand.php +++ b/app/src/Command/TransmogrifyCommand.php @@ -57,6 +57,7 @@ class TransmogrifyCommand extends Command { 'types' => [ 'source' => 'cm_co_extended_types', 'displayField' => 'display_name', + 'postTable' => 'insertPronounTypes', 'fieldMap' => [ 'attribute' => '&map_extended_type', 'name' => 'value', @@ -792,6 +793,23 @@ protected function insertDefaultSettings() { } } + /** + * Insert default Pronoun types. + * + * @since COmanage Registry v5.0.0 + */ + + protected function insertPronounTypes() { + // Since the Pronoun MVEA didn't exist in v4, we'll need to create the + // default types for all COs. + + $Types = TableRegistry::getTableLocator()->get('Types'); + + foreach(array_keys($this->cache['cos']['id']) as $coId) { + $Types->addDefault($coId, 'Pronouns.type'); + } + } + /** * Map fields that have been renamed from Registry Classic to Registry PE. * diff --git a/app/src/Controller/PronounsController.php b/app/src/Controller/PronounsController.php new file mode 100644 index 000000000..0d516eabb --- /dev/null +++ b/app/src/Controller/PronounsController.php @@ -0,0 +1,42 @@ + [ + 'Pronouns.pronouns' => 'asc' + ] + ]; +} \ No newline at end of file diff --git a/app/src/Model/Entity/Pronoun.php b/app/src/Model/Entity/Pronoun.php new file mode 100644 index 000000000..e2825a8b4 --- /dev/null +++ b/app/src/Model/Entity/Pronoun.php @@ -0,0 +1,44 @@ + true, + 'id' => false, + 'slug' => false, + ]; +} \ No newline at end of file diff --git a/app/src/Model/Table/CoSettingsTable.php b/app/src/Model/Table/CoSettingsTable.php index 6102b7a7c..81ed851ec 100644 --- a/app/src/Model/Table/CoSettingsTable.php +++ b/app/src/Model/Table/CoSettingsTable.php @@ -91,6 +91,10 @@ public function initialize(array $config): void { ->setClassName('Types') ->setForeignKey('default_name_type_id') ->setProperty('default_name_type'); + $this->belongsTo('DefaultPronounTypes') + ->setClassName('Types') + ->setForeignKey('default_pronoun_type_id') + ->setProperty('default_pronoun_type'); $this->belongsTo('DefaultTelephoneNumberTypes') ->setClassName('Types') ->setForeignKey('default_telephone_number_type_id') @@ -124,6 +128,10 @@ public function initialize(array $config): void { 'type' => 'type', 'attribute' => 'Names.type' ], + 'defaultPronounTypes' => [ + 'type' => 'type', + 'attribute' => 'Pronouns.type' + ], 'defaultTelephoneNumberTypes' => [ 'type' => 'type', 'attribute' => 'TelephoneNumbers.type' @@ -185,6 +193,7 @@ public function addDefaults(int $coId): int { 'default_email_address_type_id' => null, 'default_identifier_type_id' => null, 'default_name_type_id' => null, + 'default_pronoun_type_id' => null, 'default_telephone_number_type_id' => null, 'default_url_type_id' => null, 'permitted_fields_name' => PermittedNameFieldsEnum::HGMFS, @@ -294,6 +303,11 @@ public function validationDefault(Validator $validator): Validator { ]); $validator->allowEmptyString('default_name_type_id'); + $validator->add('default_pronoun_type_id', [ + 'content' => ['rule' => 'isInteger'] + ]); + $validator->allowEmptyString('default_pronoun_type_id'); + $validator->add('default_telephone_number_type_id', [ 'content' => ['rule' => 'isInteger'] ]); diff --git a/app/src/Model/Table/ExternalIdentitiesTable.php b/app/src/Model/Table/ExternalIdentitiesTable.php index 16315f4b8..455c19c76 100644 --- a/app/src/Model/Table/ExternalIdentitiesTable.php +++ b/app/src/Model/Table/ExternalIdentitiesTable.php @@ -82,6 +82,8 @@ public function initialize(array $config): void { ->setDependent(true); $this->hasMany('Identifiers') ->setDependent(true); + $this->hasMany('Pronouns') + ->setDependent(true); $this->hasMany('TelephoneNumbers') ->setDependent(true); $this->hasMany('Urls') diff --git a/app/src/Model/Table/PeopleTable.php b/app/src/Model/Table/PeopleTable.php index e8fd6b365..07582a198 100644 --- a/app/src/Model/Table/PeopleTable.php +++ b/app/src/Model/Table/PeopleTable.php @@ -90,6 +90,8 @@ public function initialize(array $config): void { ->setDependent(true); $this->hasMany('PersonRoles') ->setDependent(true); + $this->hasMany('Pronouns') + ->setDependent(true); $this->hasMany('TelephoneNumbers') ->setDependent(true); $this->hasMany('Urls') diff --git a/app/src/Model/Table/PronounsTable.php b/app/src/Model/Table/PronounsTable.php new file mode 100644 index 000000000..631d1c1da --- /dev/null +++ b/app/src/Model/Table/PronounsTable.php @@ -0,0 +1,158 @@ + [ + 'default' + ] + ]; + + /** + * 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'); + + // Pronouns are not configuration + $this->setIsConfigurationTable(false); + + // Define associations + $this->belongsTo('People'); + $this->belongsTo('ExternalIdentities'); + $this->belongsTo('Types'); + + $this->setDisplayField('pronouns'); + + $this->setPrimaryLink(['external_identity_id', 'person_id']); + $this->setRequiresCO(true); + + $this->setAutoViewVars([ + 'languages' => [ + 'type' => 'enum', + 'class' => 'LanguageEnum' + ], + 'types' => [ + 'type' => 'type', + 'attribute' => 'Pronouns.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'] + ] + ]); + } + + /** + * Callback after model save. + * + * @since COmanage Registry v5.0.0 + * @param EventInterface $event Event + * @param EntityInterface $entity Entity (ie: Co) + * @param ArrayObject $options Save options + * @return bool True on success + */ + + public function localAfterSave(\Cake\Event\EventInterface $event, \Cake\Datasource\EntityInterface $entity, \ArrayObject $options): bool { + $this->recordHistory($entity); + + return true; + } + + /** + * 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 { + $schema = $this->getSchema(); + + $this->registerPrimaryKeyValidation($validator, $this->getPrimaryLinks()); + + $this->registerStringValidation($validator, $schema, 'pronouns', true); + + $validator->add('type_id', [ + 'content' => ['rule' => 'isInteger'] + ]); + $validator->notEmptyString('type_id'); + + $validator->add('language', [ + 'content' => ['rule' => ['inList', LanguageEnum::getConstValues()]] + ]); + $validator->allowEmptyString('language'); + + $validator->add('source_pronoun_id', [ + 'content' => ['rule' => 'isInteger'] + ]); + $validator->allowEmptyString('source_pronoun_id'); + + return $validator; + } +} \ No newline at end of file diff --git a/app/src/Model/Table/TypesTable.php b/app/src/Model/Table/TypesTable.php index 0caa24963..6ec5d8bcc 100644 --- a/app/src/Model/Table/TypesTable.php +++ b/app/src/Model/Table/TypesTable.php @@ -61,6 +61,7 @@ class TypesTable extends Table { 'Identifiers.type', 'Names.type', // 'Organizations.type', + 'Pronouns.type', 'TelephoneNumbers.type', 'Urls.type' ]; @@ -89,6 +90,7 @@ public function initialize(array $config): void { $this->hasMany('EmailAddresses'); $this->hasMany('Identifiers'); $this->hasMany('Names'); + $this->hasMany('Pronouns'); $this->hasMany('TelephoneNumbers'); $this->hasMany('Urls'); // XXX add other MVEA models diff --git a/app/templates/CoSettings/fields.inc b/app/templates/CoSettings/fields.inc index a7dc234fc..cd8002a31 100644 --- a/app/templates/CoSettings/fields.inc +++ b/app/templates/CoSettings/fields.inc @@ -42,6 +42,8 @@ if($vv_action == 'edit') { print $this->Field->control('required_fields_name', ['suppressBlank' => true]); + print $this->Field->control('default_pronoun_type_id'); + print $this->Field->control('default_telephone_number_type_id'); print $this->Field->control('permitted_fields_telephone_number', ['suppressBlank' => true]); diff --git a/app/templates/ExternalIdentities/fields.inc b/app/templates/ExternalIdentities/fields.inc index 04fa8c917..43c4632d0 100644 --- a/app/templates/ExternalIdentities/fields.inc +++ b/app/templates/ExternalIdentities/fields.inc @@ -128,19 +128,19 @@ print $this->Html->link( [ 'controller' => 'urls', 'action' => 'index', '?' => [ - 'person_id' => $vv_obj->id + 'external_identity_id' => $vv_obj->id ] ], ['class' => 'linkbutton'] ); print $this->Html->link( - __d('controller', 'ExternalIdentities', [99]), - [ 'controller' => 'external-identities', - 'action' => 'index', + __d('controller', 'Pronouns', [99]), + [ 'controller' => 'pronouns', + 'action' => 'index', '?' => [ 'external_identity_id' => $vv_obj->id ] ], ['class' => 'linkbutton'] -); \ No newline at end of file +); diff --git a/app/templates/People/fields.inc b/app/templates/People/fields.inc index 3b81e76f6..9c864588a 100644 --- a/app/templates/People/fields.inc +++ b/app/templates/People/fields.inc @@ -148,6 +148,17 @@ if($vv_action == 'add') { ['class' => 'linkbutton'] ); + print $this->Html->link( + __d('controller', 'Pronouns', [99]), + [ 'controller' => 'pronouns', + 'action' => 'index', + '?' => [ + 'person_id' => $vv_obj->id + ] + ], + ['class' => 'linkbutton'] + ); + print $this->Html->link( __d('controller', 'ExternalIdentities', [99]), [ 'controller' => 'external-identities', diff --git a/app/templates/Pronouns/columns.inc b/app/templates/Pronouns/columns.inc new file mode 100644 index 000000000..92e6e3ddc --- /dev/null +++ b/app/templates/Pronouns/columns.inc @@ -0,0 +1,44 @@ + [ + 'type' => 'link' + ], + 'type_id' => [ + 'type' => 'fk' + ], + 'language' => [ + 'type' => 'enum', + 'class' => 'LanguageEnum' + ] +]; + +$bulkActions = [ + // TODO: develop bulk actions. For now, use a placeholder. + 'delete' => true +]; \ No newline at end of file diff --git a/app/templates/Pronouns/fields.inc b/app/templates/Pronouns/fields.inc new file mode 100644 index 000000000..26d64e1a4 --- /dev/null +++ b/app/templates/Pronouns/fields.inc @@ -0,0 +1,35 @@ +Field->control('pronouns'); + + print $this->Field->control('type_id', ['default' => $vv_default_type]); + + print $this->Field->control('language'); +}