From 4c1c8b948c7f27b715c93340732d5fa86a06a0d7 Mon Sep 17 00:00:00 2001 From: scott_earnest Date: Thu, 28 Oct 2021 17:24:37 -0600 Subject: [PATCH 01/18] FE2-37: FOIA CFO custom module files. --- .../modules/custom/foia_cfo/foia_cfo.info.yml | 5 + .../custom/foia_cfo/foia_cfo.routing.yml | 6 + .../foia_cfo/src/Controller/CFOController.php | 162 ++++++++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 docroot/modules/custom/foia_cfo/foia_cfo.info.yml create mode 100644 docroot/modules/custom/foia_cfo/foia_cfo.routing.yml create mode 100644 docroot/modules/custom/foia_cfo/src/Controller/CFOController.php diff --git a/docroot/modules/custom/foia_cfo/foia_cfo.info.yml b/docroot/modules/custom/foia_cfo/foia_cfo.info.yml new file mode 100644 index 000000000..04f3671e2 --- /dev/null +++ b/docroot/modules/custom/foia_cfo/foia_cfo.info.yml @@ -0,0 +1,5 @@ +name: 'FOIA CFO Council' +type: module +description: 'Support for Chief FOIA Officers Council.' +core_version_requirement: ^8 || ^9 +package: 'FOIA' diff --git a/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml b/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml new file mode 100644 index 000000000..155bab9a0 --- /dev/null +++ b/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml @@ -0,0 +1,6 @@ +foia_cfo.council: + path: 'api/cfo/council' + defaults: { _controller: '\Drupal\foia_cfo\Controller\CFOController::getCouncil' } + methods: [GET] + requirements: + _access: 'TRUE' diff --git a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php new file mode 100644 index 000000000..93c2cf1bf --- /dev/null +++ b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php @@ -0,0 +1,162 @@ +node_storage = \Drupal::entityTypeManager()->getStorage('node'); + } + + /** + * Callback for `my-api/get.json` API method. + */ + public function getCouncil(Request $request) { + + // Initialize the response. + $response = []; + + // Load the view for the CFO API and execute the "council" display. + $view = Views::getView('cfo_council_api'); + $view->setDisplay('council'); + $view->execute(); + + // Should only be one result. + foreach ($view->result as $resultRow) { + + // Title and body of the Council node. + $response['title'] = $resultRow->_entity->label(); + if ($resultRow->_entity->get('body')) { + $response['body'] = $resultRow->_entity->get('body')->getValue()[0]['value']; + } + + /** @var \Drupal\Core\Field\EntityReferenceFieldItemList $committees */ + $committees = $resultRow->_entity->get('field_council_committees'); + + if (!empty($committees)) { + + // Store committees as array elements. + $response['committees'] = []; + + foreach ($committees as $committee) { + /** @var \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $committee */ + $nid = $committee->getValue()['target_id']; + $committee_node = $this->node_storage->load($nid); + $response['committees'][] = [ + 'committee_title' => $committee_node->label(), + 'committee_body' => $committee_node->body->view('default')[0]['#text'], + ]; + } + } + + } + + // Set the display for the meetings. + $view_meetings = Views::getView('cfo_council_api'); + $view_meetings->setDisplay('meetings'); + $view_meetings->execute(); + + // Store meetings as array elements. + $response['meetings'] = []; + + foreach ($view_meetings->result as $resultRow) { + + // Initialize this meeting. + $meeting = []; + + $meeting['meeting_title'] = $resultRow->_entity->label(); + if (!empty($resultRow->_entity->body->view('default')[0]['#text'])) { + $meeting['meeting_body'] = $resultRow->_entity->body->view('default')[0]['#text']; + } + + if (!empty($resultRow->_entity->get('field_meeting_agenda'))) { + /** @var \Drupal\entity_reference_revisions\EntityReferenceRevisionsFieldItemList $agenda */ + $agenda = $resultRow->_entity->get('field_meeting_agenda'); + } + + if ($resultRow->_entity->field_meeting_materials->count()) { + $meeting['meeting_materials'] = self::linkOrFileFormatter($resultRow->_entity->field_meeting_materials); + } + + if ($resultRow->_entity->field_meeting_documents->count()) { + $meeting['meeting_documents'] = self::linkOrFileFormatter($resultRow->_entity->field_meeting_documents); + } + + $response['meetings'][] = $meeting; + + } + + // Return the response array converted to json response. + return new JsonResponse($response); + + } + + /** + * Formats "Link or File" paragraph types. + * + * @param \Drupal\entity_reference_revisions\EntityReferenceRevisionsFieldItemList $field + * The field. + * + * @return array + * Lables and links to either the url or the file. + */ + private function linkOrFileFormatter(EntityReferenceRevisionsFieldItemList $field) { + + // Initialize return array. + $return = []; + + foreach ($field->referencedEntities() as $item) { + + $return_item = []; + $return_item['item_title'] = $item->get('field_link_label')->getValue()[0]['value']; + if (!empty($item->get('field_link_link')->getValue()[0]['uri'])) { + $return_item['item_link'] = $item->get('field_link_link')->getValue()[0]['uri']; + } + elseif (!empty($item->get('field_link_file')->getValue()[0]['target_id'])) { + $fid = $item->get('field_link_file')->getValue()[0]['target_id']; + $file = File::load($fid); + $return_item['item_link'] = $file->createFileUrl(); + } + + $return[] = $return_item; + + } + + return $return; + + } + +} From e067ecfa83ae2304aec17dbe6da7a06a9dc078fc Mon Sep 17 00:00:00 2001 From: scott_earnest Date: Thu, 28 Oct 2021 07:48:19 -0600 Subject: [PATCH 02/18] FE2-34: Timefield module files from composer and drupal config. --- composer.json | 1 + composer.lock | 51 ++++++++++++++++++++++++++++++- config/default/core.extension.yml | 1 + 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b991cb2a9..af3630f50 100644 --- a/composer.json +++ b/composer.json @@ -67,6 +67,7 @@ "drupal/shield": "^1.0.0", "drupal/simplesamlphp_auth": "3.x-dev@dev", "drupal/swiftmailer": "^2.0", + "drupal/time_field": "^2.0", "drupal/upgrade_status": "^3.11", "drupal/view_unpublished": "^1.0@alpha", "drupal/views_bulk_operations": "^3.6", diff --git a/composer.lock b/composer.lock index cf2ccd5d9..4ffe2ed24 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b9a96d7711e4d323d295497b1c88a9bb", + "content-hash": "4c9c802faf2052c79778b92abe7cbe11", "packages": [ { "name": "acquia/blt", @@ -10602,6 +10602,55 @@ "source": "https://git.drupalcode.org/project/swiftmailer" } }, + { + "name": "drupal/time_field", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://git.drupalcode.org/project/time_field.git", + "reference": "2.0.0" + }, + "dist": { + "type": "zip", + "url": "https://ftp.drupal.org/files/projects/time_field-2.0.0.zip", + "reference": "2.0.0", + "shasum": "7385d8ca94dcdaf725e6a3f72ef348db5232d022" + }, + "require": { + "drupal/core": "^8 || ^9" + }, + "type": "drupal-module", + "extra": { + "drupal": { + "version": "2.0.0", + "datestamp": "1626688764", + "security-coverage": { + "status": "covered", + "message": "Covered by Drupal's security advisory policy" + } + } + }, + "notification-url": "https://packages.drupal.org/8/downloads", + "license": [ + "GPL-2.0+" + ], + "authors": [ + { + "name": "BramDriesen", + "homepage": "https://www.drupal.org/user/3383264" + }, + { + "name": "lostkoder", + "homepage": "https://www.drupal.org/user/3545132" + } + ], + "description": "Provides 'Time Field' and 'Time Range Field'.", + "homepage": "https://www.drupal.org/project/time_field", + "support": { + "source": "http://git.drupal.org/project/time_field.git", + "issues": "https://www.drupal.org/project/issues/time_field" + } + }, { "name": "drupal/token", "version": "1.9.0", diff --git a/config/default/core.extension.yml b/config/default/core.extension.yml index c7bc58ffa..e81299f8e 100644 --- a/config/default/core.extension.yml +++ b/config/default/core.extension.yml @@ -131,6 +131,7 @@ module: taxonomy: 0 telephone: 0 text: 0 + time_field: 0 token: 0 toolbar: 0 typed_data: 0 From c5ff9c9c171cd450616b2bd48c60ab801af05b8b Mon Sep 17 00:00:00 2001 From: scott_earnest Date: Thu, 28 Oct 2021 07:51:37 -0600 Subject: [PATCH 03/18] FE2-34: New text format for rich text with media. --- .../editor.editor.rich_text_with_media.yml | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 config/default/editor.editor.rich_text_with_media.yml diff --git a/config/default/editor.editor.rich_text_with_media.yml b/config/default/editor.editor.rich_text_with_media.yml new file mode 100644 index 000000000..87a869133 --- /dev/null +++ b/config/default/editor.editor.rich_text_with_media.yml @@ -0,0 +1,68 @@ +uuid: 67f79eed-0bb4-48b1-873b-1d93e0909a0a +langcode: en +status: true +dependencies: + config: + - filter.format.rich_text_with_media + module: + - ckeditor +format: rich_text_with_media +editor: ckeditor +settings: + toolbar: + rows: + - + - + name: Formatting + items: + - Bold + - Italic + - Underline + - Strike + - Superscript + - Subscript + - RemoveFormat + - + name: Links + items: + - DrupalLink + - DrupalUnlink + - + name: Lists + items: + - BulletedList + - NumberedList + - + name: Formatting + items: + - Format + - JustifyLeft + - JustifyCenter + - JustifyRight + - JustifyBlock + - Blockquote + - Table + - + name: Media + items: + - DrupalImage + - DrupalMediaLibrary + - + name: Tools + items: + - Source + - Undo + - Redo + plugins: + language: + language_list: un + stylescombo: + styles: '' +image_upload: + status: true + scheme: public + directory: inline-images + max_size: '' + max_dimensions: + width: null + height: null From 9271b09df9a7442629844e57caf395fd64e9415e Mon Sep 17 00:00:00 2001 From: scott_earnest Date: Thu, 28 Oct 2021 07:53:23 -0600 Subject: [PATCH 04/18] FE2-34: New paragraph types to support CFO council content types. --- ..._display.paragraph.agenda_item.default.yml | 43 +++++++++++++++++ ...display.paragraph.link_or_file.default.yml | 43 +++++++++++++++++ ..._display.paragraph.agenda_item.default.yml | 41 ++++++++++++++++ ...display.paragraph.link_or_file.default.yml | 47 +++++++++++++++++++ ...nda_item.field_agenda_item_description.yml | 26 ++++++++++ ...aph.agenda_item.field_agenda_item_time.yml | 27 +++++++++++ ...ph.agenda_item.field_agenda_item_title.yml | 26 ++++++++++ ...paragraph.link_or_file.field_link_file.yml | 33 +++++++++++++ ...aragraph.link_or_file.field_link_label.yml | 26 ++++++++++ ...paragraph.link_or_file.field_link_link.yml | 29 ++++++++++++ ...aragraph.field_agenda_item_description.yml | 23 +++++++++ ...orage.paragraph.field_agenda_item_time.yml | 23 +++++++++ ...rage.paragraph.field_agenda_item_title.yml | 25 ++++++++++ ...ield.storage.paragraph.field_link_file.yml | 27 +++++++++++ ...eld.storage.paragraph.field_link_label.yml | 25 ++++++++++ ...ield.storage.paragraph.field_link_link.yml | 23 +++++++++ ...paragraphs.paragraphs_type.agenda_item.yml | 10 ++++ ...aragraphs.paragraphs_type.link_or_file.yml | 10 ++++ 18 files changed, 507 insertions(+) create mode 100644 config/default/core.entity_form_display.paragraph.agenda_item.default.yml create mode 100644 config/default/core.entity_form_display.paragraph.link_or_file.default.yml create mode 100644 config/default/core.entity_view_display.paragraph.agenda_item.default.yml create mode 100644 config/default/core.entity_view_display.paragraph.link_or_file.default.yml create mode 100644 config/default/field.field.paragraph.agenda_item.field_agenda_item_description.yml create mode 100644 config/default/field.field.paragraph.agenda_item.field_agenda_item_time.yml create mode 100644 config/default/field.field.paragraph.agenda_item.field_agenda_item_title.yml create mode 100644 config/default/field.field.paragraph.link_or_file.field_link_file.yml create mode 100644 config/default/field.field.paragraph.link_or_file.field_link_label.yml create mode 100644 config/default/field.field.paragraph.link_or_file.field_link_link.yml create mode 100644 config/default/field.storage.paragraph.field_agenda_item_description.yml create mode 100644 config/default/field.storage.paragraph.field_agenda_item_time.yml create mode 100644 config/default/field.storage.paragraph.field_agenda_item_title.yml create mode 100644 config/default/field.storage.paragraph.field_link_file.yml create mode 100644 config/default/field.storage.paragraph.field_link_label.yml create mode 100644 config/default/field.storage.paragraph.field_link_link.yml create mode 100644 config/default/paragraphs.paragraphs_type.agenda_item.yml create mode 100644 config/default/paragraphs.paragraphs_type.link_or_file.yml diff --git a/config/default/core.entity_form_display.paragraph.agenda_item.default.yml b/config/default/core.entity_form_display.paragraph.agenda_item.default.yml new file mode 100644 index 000000000..006f94ee5 --- /dev/null +++ b/config/default/core.entity_form_display.paragraph.agenda_item.default.yml @@ -0,0 +1,43 @@ +uuid: f20fc1bb-ff78-4efc-8448-4c72618167b1 +langcode: en +status: true +dependencies: + config: + - field.field.paragraph.agenda_item.field_agenda_item_description + - field.field.paragraph.agenda_item.field_agenda_item_time + - field.field.paragraph.agenda_item.field_agenda_item_title + - paragraphs.paragraphs_type.agenda_item + module: + - time_field +id: paragraph.agenda_item.default +targetEntityType: paragraph +bundle: agenda_item +mode: default +content: + field_agenda_item_description: + weight: 2 + settings: + rows: 5 + placeholder: '' + third_party_settings: { } + type: string_textarea + region: content + field_agenda_item_time: + weight: 0 + settings: + enabled: false + step: 5 + third_party_settings: { } + type: time_widget + region: content + field_agenda_item_title: + weight: 1 + settings: + size: 60 + placeholder: '' + third_party_settings: { } + type: string_textfield + region: content +hidden: + created: true + status: true diff --git a/config/default/core.entity_form_display.paragraph.link_or_file.default.yml b/config/default/core.entity_form_display.paragraph.link_or_file.default.yml new file mode 100644 index 000000000..5fb95f9dc --- /dev/null +++ b/config/default/core.entity_form_display.paragraph.link_or_file.default.yml @@ -0,0 +1,43 @@ +uuid: 10c53275-16e5-4763-8066-545ad15fd20e +langcode: en +status: true +dependencies: + config: + - field.field.paragraph.link_or_file.field_link_file + - field.field.paragraph.link_or_file.field_link_label + - field.field.paragraph.link_or_file.field_link_link + - paragraphs.paragraphs_type.link_or_file + module: + - file + - link +id: paragraph.link_or_file.default +targetEntityType: paragraph +bundle: link_or_file +mode: default +content: + field_link_file: + weight: 3 + settings: + progress_indicator: throbber + third_party_settings: { } + type: file_generic + region: content + field_link_label: + weight: 1 + settings: + size: 60 + placeholder: '' + third_party_settings: { } + type: string_textfield + region: content + field_link_link: + weight: 2 + settings: + placeholder_url: '' + placeholder_title: '' + third_party_settings: { } + type: link_default + region: content +hidden: + created: true + status: true diff --git a/config/default/core.entity_view_display.paragraph.agenda_item.default.yml b/config/default/core.entity_view_display.paragraph.agenda_item.default.yml new file mode 100644 index 000000000..c5fb3ca44 --- /dev/null +++ b/config/default/core.entity_view_display.paragraph.agenda_item.default.yml @@ -0,0 +1,41 @@ +uuid: b9062477-3eea-49c2-a675-ea69ad36c562 +langcode: en +status: true +dependencies: + config: + - field.field.paragraph.agenda_item.field_agenda_item_description + - field.field.paragraph.agenda_item.field_agenda_item_time + - field.field.paragraph.agenda_item.field_agenda_item_title + - paragraphs.paragraphs_type.agenda_item + module: + - time_field +id: paragraph.agenda_item.default +targetEntityType: paragraph +bundle: agenda_item +mode: default +content: + field_agenda_item_description: + weight: 2 + label: above + settings: { } + third_party_settings: { } + type: basic_string + region: content + field_agenda_item_time: + weight: 3 + label: above + settings: + time_format: 'h:i a' + third_party_settings: { } + type: time_formatter + region: content + field_agenda_item_title: + weight: 1 + label: above + settings: + link_to_entity: false + third_party_settings: { } + type: string + region: content +hidden: + search_api_excerpt: true diff --git a/config/default/core.entity_view_display.paragraph.link_or_file.default.yml b/config/default/core.entity_view_display.paragraph.link_or_file.default.yml new file mode 100644 index 000000000..937e87e9a --- /dev/null +++ b/config/default/core.entity_view_display.paragraph.link_or_file.default.yml @@ -0,0 +1,47 @@ +uuid: 71fb1647-938c-4ebd-9b2c-b0ce8e821a03 +langcode: en +status: true +dependencies: + config: + - field.field.paragraph.link_or_file.field_link_file + - field.field.paragraph.link_or_file.field_link_label + - field.field.paragraph.link_or_file.field_link_link + - paragraphs.paragraphs_type.link_or_file + module: + - file + - link +id: paragraph.link_or_file.default +targetEntityType: paragraph +bundle: link_or_file +mode: default +content: + field_link_file: + weight: 3 + label: above + settings: + use_description_as_link_text: true + third_party_settings: { } + type: file_default + region: content + field_link_label: + weight: 1 + label: above + settings: + link_to_entity: false + third_party_settings: { } + type: string + region: content + field_link_link: + weight: 2 + label: above + settings: + trim_length: 80 + url_only: false + url_plain: false + rel: '' + target: '' + third_party_settings: { } + type: link + region: content +hidden: + search_api_excerpt: true diff --git a/config/default/field.field.paragraph.agenda_item.field_agenda_item_description.yml b/config/default/field.field.paragraph.agenda_item.field_agenda_item_description.yml new file mode 100644 index 000000000..e7a3f85d1 --- /dev/null +++ b/config/default/field.field.paragraph.agenda_item.field_agenda_item_description.yml @@ -0,0 +1,26 @@ +uuid: 77696b40-a5ff-449b-99fa-81b573f05779 +langcode: en +status: true +dependencies: + config: + - field.storage.paragraph.field_agenda_item_description + - paragraphs.paragraphs_type.agenda_item + module: + - foia_autocalc +third_party_settings: + foia_autocalc: + autocalc_settings: + description: '' + autocalc_config: '' +id: paragraph.agenda_item.field_agenda_item_description +field_name: field_agenda_item_description +entity_type: paragraph +bundle: agenda_item +label: Description +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: string_long diff --git a/config/default/field.field.paragraph.agenda_item.field_agenda_item_time.yml b/config/default/field.field.paragraph.agenda_item.field_agenda_item_time.yml new file mode 100644 index 000000000..f65facc61 --- /dev/null +++ b/config/default/field.field.paragraph.agenda_item.field_agenda_item_time.yml @@ -0,0 +1,27 @@ +uuid: 4597991c-53e5-40e2-8c93-a769c06553f3 +langcode: en +status: true +dependencies: + config: + - field.storage.paragraph.field_agenda_item_time + - paragraphs.paragraphs_type.agenda_item + module: + - foia_autocalc + - time_field +third_party_settings: + foia_autocalc: + autocalc_settings: + description: '' + autocalc_config: '' +id: paragraph.agenda_item.field_agenda_item_time +field_name: field_agenda_item_time +entity_type: paragraph +bundle: agenda_item +label: Time +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: time diff --git a/config/default/field.field.paragraph.agenda_item.field_agenda_item_title.yml b/config/default/field.field.paragraph.agenda_item.field_agenda_item_title.yml new file mode 100644 index 000000000..baceb9f09 --- /dev/null +++ b/config/default/field.field.paragraph.agenda_item.field_agenda_item_title.yml @@ -0,0 +1,26 @@ +uuid: 8f56f4de-17f8-4418-972b-bdda044e0cf3 +langcode: en +status: true +dependencies: + config: + - field.storage.paragraph.field_agenda_item_title + - paragraphs.paragraphs_type.agenda_item + module: + - foia_autocalc +third_party_settings: + foia_autocalc: + autocalc_settings: + description: '' + autocalc_config: '' +id: paragraph.agenda_item.field_agenda_item_title +field_name: field_agenda_item_title +entity_type: paragraph +bundle: agenda_item +label: Title +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: string diff --git a/config/default/field.field.paragraph.link_or_file.field_link_file.yml b/config/default/field.field.paragraph.link_or_file.field_link_file.yml new file mode 100644 index 000000000..772ddc014 --- /dev/null +++ b/config/default/field.field.paragraph.link_or_file.field_link_file.yml @@ -0,0 +1,33 @@ +uuid: 4cc4754e-901f-4699-85a7-d1d1149a1eda +langcode: en +status: true +dependencies: + config: + - field.storage.paragraph.field_link_file + - paragraphs.paragraphs_type.link_or_file + module: + - file + - foia_autocalc +third_party_settings: + foia_autocalc: + autocalc_settings: + description: '' + autocalc_config: '' +id: paragraph.link_or_file.field_link_file +field_name: field_link_file +entity_type: paragraph +bundle: link_or_file +label: File +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + file_directory: cfo + file_extensions: 'txt pdf' + max_filesize: '' + description_field: false + handler: 'default:file' + handler_settings: { } +field_type: file diff --git a/config/default/field.field.paragraph.link_or_file.field_link_label.yml b/config/default/field.field.paragraph.link_or_file.field_link_label.yml new file mode 100644 index 000000000..dfea72d64 --- /dev/null +++ b/config/default/field.field.paragraph.link_or_file.field_link_label.yml @@ -0,0 +1,26 @@ +uuid: 35562acf-e08c-4122-915d-bbb43e83ba64 +langcode: en +status: true +dependencies: + config: + - field.storage.paragraph.field_link_label + - paragraphs.paragraphs_type.link_or_file + module: + - foia_autocalc +third_party_settings: + foia_autocalc: + autocalc_settings: + description: '' + autocalc_config: '' +id: paragraph.link_or_file.field_link_label +field_name: field_link_label +entity_type: paragraph +bundle: link_or_file +label: Label +description: "Using the fields below, enter either:\r\n
    \r\n
  • a link/URL to an existing piece of content or other external webpage.
  • \r\n
  • upload a file using the \"Choose File\" browser
  • \r\n
" +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: string diff --git a/config/default/field.field.paragraph.link_or_file.field_link_link.yml b/config/default/field.field.paragraph.link_or_file.field_link_link.yml new file mode 100644 index 000000000..4472efed4 --- /dev/null +++ b/config/default/field.field.paragraph.link_or_file.field_link_link.yml @@ -0,0 +1,29 @@ +uuid: 3b80edac-cb9f-4006-9985-a143b051b3fe +langcode: en +status: true +dependencies: + config: + - field.storage.paragraph.field_link_link + - paragraphs.paragraphs_type.link_or_file + module: + - foia_autocalc + - link +third_party_settings: + foia_autocalc: + autocalc_settings: + description: '' + autocalc_config: '' +id: paragraph.link_or_file.field_link_link +field_name: field_link_link +entity_type: paragraph +bundle: link_or_file +label: Link +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + link_type: 17 + title: 0 +field_type: link diff --git a/config/default/field.storage.paragraph.field_agenda_item_description.yml b/config/default/field.storage.paragraph.field_agenda_item_description.yml new file mode 100644 index 000000000..03a9192b2 --- /dev/null +++ b/config/default/field.storage.paragraph.field_agenda_item_description.yml @@ -0,0 +1,23 @@ +uuid: 5e4de79d-94a4-4bb2-b1ac-203c2c76a147 +langcode: en +status: true +dependencies: + module: + - field_permissions + - paragraphs +third_party_settings: + field_permissions: + permission_type: public +id: paragraph.field_agenda_item_description +field_name: field_agenda_item_description +entity_type: paragraph +type: string_long +settings: + case_sensitive: false +module: core +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/default/field.storage.paragraph.field_agenda_item_time.yml b/config/default/field.storage.paragraph.field_agenda_item_time.yml new file mode 100644 index 000000000..624735de7 --- /dev/null +++ b/config/default/field.storage.paragraph.field_agenda_item_time.yml @@ -0,0 +1,23 @@ +uuid: a304778c-1297-4330-a941-4cca48a7567e +langcode: en +status: true +dependencies: + module: + - field_permissions + - paragraphs + - time_field +third_party_settings: + field_permissions: + permission_type: public +id: paragraph.field_agenda_item_time +field_name: field_agenda_item_time +entity_type: paragraph +type: time +settings: { } +module: time_field +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/default/field.storage.paragraph.field_agenda_item_title.yml b/config/default/field.storage.paragraph.field_agenda_item_title.yml new file mode 100644 index 000000000..4a2bbc7e1 --- /dev/null +++ b/config/default/field.storage.paragraph.field_agenda_item_title.yml @@ -0,0 +1,25 @@ +uuid: 26820085-f53a-438e-87f7-01b70c888f24 +langcode: en +status: true +dependencies: + module: + - field_permissions + - paragraphs +third_party_settings: + field_permissions: + permission_type: public +id: paragraph.field_agenda_item_title +field_name: field_agenda_item_title +entity_type: paragraph +type: string +settings: + max_length: 255 + is_ascii: false + case_sensitive: false +module: core +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/default/field.storage.paragraph.field_link_file.yml b/config/default/field.storage.paragraph.field_link_file.yml new file mode 100644 index 000000000..c2476ef63 --- /dev/null +++ b/config/default/field.storage.paragraph.field_link_file.yml @@ -0,0 +1,27 @@ +uuid: 924ae49f-2982-4c69-a3cd-2dc1ac818161 +langcode: en +status: true +dependencies: + module: + - field_permissions + - file + - paragraphs +third_party_settings: + field_permissions: + permission_type: public +id: paragraph.field_link_file +field_name: field_link_file +entity_type: paragraph +type: file +settings: + display_field: false + display_default: false + uri_scheme: public + target_type: file +module: file +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/default/field.storage.paragraph.field_link_label.yml b/config/default/field.storage.paragraph.field_link_label.yml new file mode 100644 index 000000000..1be3d905e --- /dev/null +++ b/config/default/field.storage.paragraph.field_link_label.yml @@ -0,0 +1,25 @@ +uuid: 1a00952c-ca68-4109-b973-d8825b88eb85 +langcode: en +status: true +dependencies: + module: + - field_permissions + - paragraphs +third_party_settings: + field_permissions: + permission_type: public +id: paragraph.field_link_label +field_name: field_link_label +entity_type: paragraph +type: string +settings: + max_length: 100 + is_ascii: false + case_sensitive: false +module: core +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/default/field.storage.paragraph.field_link_link.yml b/config/default/field.storage.paragraph.field_link_link.yml new file mode 100644 index 000000000..d8d6ac647 --- /dev/null +++ b/config/default/field.storage.paragraph.field_link_link.yml @@ -0,0 +1,23 @@ +uuid: 97b2fbc9-33a7-44be-a34d-ce21dc4cb87b +langcode: en +status: true +dependencies: + module: + - field_permissions + - link + - paragraphs +third_party_settings: + field_permissions: + permission_type: public +id: paragraph.field_link_link +field_name: field_link_link +entity_type: paragraph +type: link +settings: { } +module: link +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/default/paragraphs.paragraphs_type.agenda_item.yml b/config/default/paragraphs.paragraphs_type.agenda_item.yml new file mode 100644 index 000000000..56937e8ec --- /dev/null +++ b/config/default/paragraphs.paragraphs_type.agenda_item.yml @@ -0,0 +1,10 @@ +uuid: 3a77dd7b-2f60-4f10-8114-904e3cfbf320 +langcode: en +status: true +dependencies: { } +id: agenda_item +label: 'Agenda Item' +icon_uuid: null +icon_default: null +description: 'Agenda Items make up a meeting and consist of a time, title and description.' +behavior_plugins: { } diff --git a/config/default/paragraphs.paragraphs_type.link_or_file.yml b/config/default/paragraphs.paragraphs_type.link_or_file.yml new file mode 100644 index 000000000..2058583f6 --- /dev/null +++ b/config/default/paragraphs.paragraphs_type.link_or_file.yml @@ -0,0 +1,10 @@ +uuid: c160b95c-65c1-4a3d-b9f4-5f825f83ae94 +langcode: en +status: true +dependencies: { } +id: link_or_file +label: 'Link or File' +icon_uuid: null +icon_default: null +description: 'A link field that will let you enter a URL or upload a file.' +behavior_plugins: { } From bad5f4a33a84b5bc67bab03105db62f09a45f5b7 Mon Sep 17 00:00:00 2001 From: scott_earnest Date: Thu, 28 Oct 2021 07:59:01 -0600 Subject: [PATCH 05/18] FE2-34: Config for CFO Meeting content type. --- ...ield_override.node.cfo_meeting.promote.yml | 22 +++ ..._form_display.node.cfo_meeting.default.yml | 142 ++++++++++++++++++ ..._view_display.node.cfo_meeting.default.yml | 76 ++++++++++ ...y_view_display.node.cfo_meeting.teaser.yml | 46 ++++++ .../field.field.node.cfo_meeting.body.yml | 23 +++ ....node.cfo_meeting.field_meeting_agenda.yml | 127 ++++++++++++++++ ...ld.node.cfo_meeting.field_meeting_date.yml | 27 ++++ ...de.cfo_meeting.field_meeting_documents.yml | 124 +++++++++++++++ ...node.cfo_meeting.field_meeting_heading.yml | 27 ++++ ...de.cfo_meeting.field_meeting_materials.yml | 124 +++++++++++++++ ...ield.storage.node.field_meeting_agenda.yml | 25 +++ .../field.storage.node.field_meeting_date.yml | 24 +++ ...d.storage.node.field_meeting_documents.yml | 25 +++ ...eld.storage.node.field_meeting_heading.yml | 23 +++ ...d.storage.node.field_meeting_materials.yml | 25 +++ config/default/node.type.cfo_meeting.yml | 20 +++ ...er_add_role_action.cfo_meeting_creator.yml | 14 ++ ...r_add_role_action.cfo_meeting_reviewer.yml | 14 ++ ...remove_role_action.cfo_meeting_creator.yml | 14 ++ ...emove_role_action.cfo_meeting_reviewer.yml | 14 ++ .../default/user.role.cfo_meeting_creator.yml | 26 ++++ .../user.role.cfo_meeting_reviewer.yml | 20 +++ 22 files changed, 982 insertions(+) create mode 100644 config/default/core.base_field_override.node.cfo_meeting.promote.yml create mode 100644 config/default/core.entity_form_display.node.cfo_meeting.default.yml create mode 100644 config/default/core.entity_view_display.node.cfo_meeting.default.yml create mode 100644 config/default/core.entity_view_display.node.cfo_meeting.teaser.yml create mode 100644 config/default/field.field.node.cfo_meeting.body.yml create mode 100644 config/default/field.field.node.cfo_meeting.field_meeting_agenda.yml create mode 100644 config/default/field.field.node.cfo_meeting.field_meeting_date.yml create mode 100644 config/default/field.field.node.cfo_meeting.field_meeting_documents.yml create mode 100644 config/default/field.field.node.cfo_meeting.field_meeting_heading.yml create mode 100644 config/default/field.field.node.cfo_meeting.field_meeting_materials.yml create mode 100644 config/default/field.storage.node.field_meeting_agenda.yml create mode 100644 config/default/field.storage.node.field_meeting_date.yml create mode 100644 config/default/field.storage.node.field_meeting_documents.yml create mode 100644 config/default/field.storage.node.field_meeting_heading.yml create mode 100644 config/default/field.storage.node.field_meeting_materials.yml create mode 100644 config/default/node.type.cfo_meeting.yml create mode 100644 config/default/system.action.user_add_role_action.cfo_meeting_creator.yml create mode 100644 config/default/system.action.user_add_role_action.cfo_meeting_reviewer.yml create mode 100644 config/default/system.action.user_remove_role_action.cfo_meeting_creator.yml create mode 100644 config/default/system.action.user_remove_role_action.cfo_meeting_reviewer.yml create mode 100644 config/default/user.role.cfo_meeting_creator.yml create mode 100644 config/default/user.role.cfo_meeting_reviewer.yml diff --git a/config/default/core.base_field_override.node.cfo_meeting.promote.yml b/config/default/core.base_field_override.node.cfo_meeting.promote.yml new file mode 100644 index 000000000..c5b929400 --- /dev/null +++ b/config/default/core.base_field_override.node.cfo_meeting.promote.yml @@ -0,0 +1,22 @@ +uuid: 2f6b0192-8395-470a-8456-8fa1efb33777 +langcode: en +status: true +dependencies: + config: + - node.type.cfo_meeting +id: node.cfo_meeting.promote +field_name: promote +entity_type: node +bundle: cfo_meeting +label: 'Promoted to front page' +description: '' +required: false +translatable: true +default_value: + - + value: 0 +default_value_callback: '' +settings: + on_label: 'On' + off_label: 'Off' +field_type: boolean diff --git a/config/default/core.entity_form_display.node.cfo_meeting.default.yml b/config/default/core.entity_form_display.node.cfo_meeting.default.yml new file mode 100644 index 000000000..a450ff2a9 --- /dev/null +++ b/config/default/core.entity_form_display.node.cfo_meeting.default.yml @@ -0,0 +1,142 @@ +uuid: 56670ce0-ace9-4b9a-94bd-a8205d75ee6f +langcode: en +status: true +dependencies: + config: + - field.field.node.cfo_meeting.body + - field.field.node.cfo_meeting.field_meeting_agenda + - field.field.node.cfo_meeting.field_meeting_date + - field.field.node.cfo_meeting.field_meeting_documents + - field.field.node.cfo_meeting.field_meeting_heading + - field.field.node.cfo_meeting.field_meeting_materials + - node.type.cfo_meeting + - workflows.workflow.editorial + module: + - content_moderation + - datetime + - paragraphs + - path + - text +id: node.cfo_meeting.default +targetEntityType: node +bundle: cfo_meeting +mode: default +content: + body: + type: text_textarea_with_summary + weight: 2 + settings: + rows: 9 + summary_rows: 3 + placeholder: '' + show_summary: false + third_party_settings: { } + region: content + created: + type: datetime_timestamp + weight: 8 + region: content + settings: { } + third_party_settings: { } + field_meeting_agenda: + type: entity_reference_paragraphs + weight: 4 + settings: + title: Paragraph + title_plural: Paragraphs + edit_mode: open + add_mode: dropdown + form_display_mode: default + default_paragraph_type: '' + third_party_settings: { } + region: content + field_meeting_date: + weight: 1 + settings: { } + third_party_settings: { } + type: datetime_default + region: content + field_meeting_documents: + type: entity_reference_paragraphs + weight: 6 + region: content + settings: + title: Paragraph + title_plural: Paragraphs + edit_mode: open + add_mode: dropdown + form_display_mode: default + default_paragraph_type: '' + third_party_settings: { } + field_meeting_heading: + weight: 3 + settings: + rows: 5 + placeholder: '' + third_party_settings: { } + type: text_textarea + region: content + field_meeting_materials: + type: entity_reference_paragraphs + weight: 5 + settings: + title: Paragraph + title_plural: Paragraphs + edit_mode: open + add_mode: dropdown + form_display_mode: default + default_paragraph_type: '' + third_party_settings: { } + region: content + moderation_state: + type: moderation_state_default + weight: 12 + settings: { } + region: content + third_party_settings: { } + path: + type: path + weight: 11 + region: content + settings: { } + third_party_settings: { } + promote: + type: boolean_checkbox + settings: + display_label: true + weight: 9 + region: content + third_party_settings: { } + status: + type: boolean_checkbox + settings: + display_label: true + weight: 13 + region: content + third_party_settings: { } + sticky: + type: boolean_checkbox + settings: + display_label: true + weight: 10 + region: content + third_party_settings: { } + title: + type: string_textfield + weight: 0 + region: content + settings: + size: 60 + placeholder: '' + third_party_settings: { } + uid: + type: entity_reference_autocomplete + weight: 7 + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + match_limit: 10 + region: content + third_party_settings: { } +hidden: { } diff --git a/config/default/core.entity_view_display.node.cfo_meeting.default.yml b/config/default/core.entity_view_display.node.cfo_meeting.default.yml new file mode 100644 index 000000000..cd1cfe8e3 --- /dev/null +++ b/config/default/core.entity_view_display.node.cfo_meeting.default.yml @@ -0,0 +1,76 @@ +uuid: f0a5ea2b-bfd5-4e6d-a0ff-402e6ac4adc2 +langcode: en +status: true +dependencies: + config: + - field.field.node.cfo_meeting.body + - field.field.node.cfo_meeting.field_meeting_agenda + - field.field.node.cfo_meeting.field_meeting_date + - field.field.node.cfo_meeting.field_meeting_documents + - field.field.node.cfo_meeting.field_meeting_heading + - field.field.node.cfo_meeting.field_meeting_materials + - node.type.cfo_meeting + module: + - datetime + - entity_reference_revisions + - text + - user +id: node.cfo_meeting.default +targetEntityType: node +bundle: cfo_meeting +mode: default +content: + body: + label: hidden + type: text_default + weight: 101 + settings: { } + third_party_settings: { } + region: content + content_moderation_control: + weight: -20 + settings: { } + third_party_settings: { } + region: content + field_meeting_agenda: + type: entity_reference_revisions_entity_view + weight: 104 + label: above + settings: + view_mode: default + link: '' + third_party_settings: { } + region: content + field_meeting_date: + weight: 102 + label: above + settings: + format_type: medium + timezone_override: '' + third_party_settings: { } + type: datetime_default + region: content + field_meeting_heading: + weight: 105 + label: above + settings: { } + third_party_settings: { } + type: text_default + region: content + field_meeting_materials: + type: entity_reference_revisions_entity_view + weight: 103 + label: above + settings: + view_mode: default + link: '' + third_party_settings: { } + region: content + links: + weight: 100 + settings: { } + third_party_settings: { } + region: content +hidden: + field_meeting_documents: true + search_api_excerpt: true diff --git a/config/default/core.entity_view_display.node.cfo_meeting.teaser.yml b/config/default/core.entity_view_display.node.cfo_meeting.teaser.yml new file mode 100644 index 000000000..f6f34c68a --- /dev/null +++ b/config/default/core.entity_view_display.node.cfo_meeting.teaser.yml @@ -0,0 +1,46 @@ +uuid: 778779ad-8ea0-4168-b2da-835664eb34f5 +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.node.teaser + - field.field.node.cfo_meeting.body + - field.field.node.cfo_meeting.field_meeting_agenda + - field.field.node.cfo_meeting.field_meeting_date + - field.field.node.cfo_meeting.field_meeting_documents + - field.field.node.cfo_meeting.field_meeting_heading + - field.field.node.cfo_meeting.field_meeting_materials + - node.type.cfo_meeting + module: + - text + - user +id: node.cfo_meeting.teaser +targetEntityType: node +bundle: cfo_meeting +mode: teaser +content: + body: + label: hidden + type: text_summary_or_trimmed + weight: 101 + settings: + trim_length: 600 + third_party_settings: { } + region: content + content_moderation_control: + weight: -20 + settings: { } + third_party_settings: { } + region: content + links: + weight: 100 + settings: { } + third_party_settings: { } + region: content +hidden: + field_meeting_agenda: true + field_meeting_date: true + field_meeting_documents: true + field_meeting_heading: true + field_meeting_materials: true + search_api_excerpt: true diff --git a/config/default/field.field.node.cfo_meeting.body.yml b/config/default/field.field.node.cfo_meeting.body.yml new file mode 100644 index 000000000..a4e590070 --- /dev/null +++ b/config/default/field.field.node.cfo_meeting.body.yml @@ -0,0 +1,23 @@ +uuid: a1fc5bd1-3821-46b9-949c-9849d9f11138 +langcode: en +status: true +dependencies: + config: + - field.storage.node.body + - node.type.cfo_meeting + module: + - text +id: node.cfo_meeting.body +field_name: body +entity_type: node +bundle: cfo_meeting +label: Body +description: '' +required: false +translatable: true +default_value: { } +default_value_callback: '' +settings: + display_summary: true + required_summary: false +field_type: text_with_summary diff --git a/config/default/field.field.node.cfo_meeting.field_meeting_agenda.yml b/config/default/field.field.node.cfo_meeting.field_meeting_agenda.yml new file mode 100644 index 000000000..1121ee5d9 --- /dev/null +++ b/config/default/field.field.node.cfo_meeting.field_meeting_agenda.yml @@ -0,0 +1,127 @@ +uuid: d28648c5-dbfa-4eb9-a13c-546718263767 +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_meeting_agenda + - node.type.cfo_meeting + - paragraphs.paragraphs_type.agenda_item + module: + - entity_reference_revisions + - foia_autocalc +third_party_settings: + foia_autocalc: + autocalc_settings: + description: '' + autocalc_config: '' +id: node.cfo_meeting.field_meeting_agenda +field_name: field_meeting_agenda +entity_type: node +bundle: cfo_meeting +label: Agenda +description: 'Add agenda items to this meeting.' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:paragraph' + handler_settings: + negate: 0 + target_bundles: + agenda_item: agenda_item + target_bundles_drag_drop: + admin_app_via: + weight: 32 + enabled: false + admin_app_vib: + weight: 33 + enabled: false + admin_app_vic1: + weight: 34 + enabled: false + admin_app_vic2: + weight: 35 + enabled: false + admin_app_vic3: + weight: 36 + enabled: false + admin_app_vic3_oth_details: + weight: 37 + enabled: false + admin_app_vic4: + weight: 38 + enabled: false + agenda_item: + enabled: true + weight: 39 + fees_x: + weight: 40 + enabled: false + foia_pers_costs_ix: + weight: 41 + enabled: false + foia_req_va: + weight: 42 + enabled: false + foia_req_vb1: + weight: 43 + enabled: false + foia_req_vb2: + weight: 44 + enabled: false + foia_req_vb2_other_details: + weight: 45 + enabled: false + foia_req_vb3: + weight: 46 + enabled: false + foia_xii_backlogged: + weight: 47 + enabled: false + foia_xii_received_proc: + weight: 48 + enabled: false + foia_xiia: + weight: 49 + enabled: false + foia_xiib: + weight: 50 + enabled: false + link_or_file: + weight: 51 + enabled: false + oldest_days: + weight: 52 + enabled: false + pending_requests_viid: + weight: 53 + enabled: false + proc_req_viic: + weight: 54 + enabled: false + processed_requests_vii: + weight: 55 + enabled: false + quarterly_component_data: + weight: 56 + enabled: false + req_viiia: + weight: 57 + enabled: false + req_viiib: + weight: 58 + enabled: false + statute: + weight: 59 + enabled: false + statute_agency_details: + weight: 60 + enabled: false + sub_xia: + weight: 61 + enabled: false + sub_xib: + weight: 62 + enabled: false +field_type: entity_reference_revisions diff --git a/config/default/field.field.node.cfo_meeting.field_meeting_date.yml b/config/default/field.field.node.cfo_meeting.field_meeting_date.yml new file mode 100644 index 000000000..6d5c58521 --- /dev/null +++ b/config/default/field.field.node.cfo_meeting.field_meeting_date.yml @@ -0,0 +1,27 @@ +uuid: b7792db1-e698-43eb-958c-639899cc9ed7 +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_meeting_date + - node.type.cfo_meeting + module: + - datetime + - foia_autocalc +third_party_settings: + foia_autocalc: + autocalc_settings: + description: '' + autocalc_config: '' +id: node.cfo_meeting.field_meeting_date +field_name: field_meeting_date +entity_type: node +bundle: cfo_meeting +label: 'Meeting Date' +description: 'Enter the required meeting date. This will control the sort order of all meetings on the council page.' +required: true +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: datetime diff --git a/config/default/field.field.node.cfo_meeting.field_meeting_documents.yml b/config/default/field.field.node.cfo_meeting.field_meeting_documents.yml new file mode 100644 index 000000000..68d3f7017 --- /dev/null +++ b/config/default/field.field.node.cfo_meeting.field_meeting_documents.yml @@ -0,0 +1,124 @@ +uuid: 30c99b4f-018d-4384-9c3b-cbb202edb2a2 +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_meeting_documents + - node.type.cfo_meeting + - paragraphs.paragraphs_type.link_or_file + module: + - entity_reference_revisions + - foia_autocalc +third_party_settings: + foia_autocalc: + autocalc_settings: + description: '' + autocalc_config: '' +id: node.cfo_meeting.field_meeting_documents +field_name: field_meeting_documents +entity_type: node +bundle: cfo_meeting +label: 'Working Documents' +description: 'Enter links for the working documents. You may enter in a URL for the link or upload a file. Drag the crosshairs to re-order these links.' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:paragraph' + handler_settings: + negate: 0 + target_bundles: + link_or_file: link_or_file + target_bundles_drag_drop: + admin_app_via: + weight: 31 + enabled: false + admin_app_vib: + weight: 32 + enabled: false + admin_app_vic1: + weight: 33 + enabled: false + admin_app_vic2: + weight: 34 + enabled: false + admin_app_vic3: + weight: 35 + enabled: false + admin_app_vic3_oth_details: + weight: 36 + enabled: false + admin_app_vic4: + weight: 37 + enabled: false + fees_x: + weight: 38 + enabled: false + foia_pers_costs_ix: + weight: 39 + enabled: false + foia_req_va: + weight: 40 + enabled: false + foia_req_vb1: + weight: 41 + enabled: false + foia_req_vb2: + weight: 42 + enabled: false + foia_req_vb2_other_details: + weight: 43 + enabled: false + foia_req_vb3: + weight: 44 + enabled: false + foia_xii_backlogged: + weight: 45 + enabled: false + foia_xii_received_proc: + weight: 46 + enabled: false + foia_xiia: + weight: 47 + enabled: false + foia_xiib: + weight: 48 + enabled: false + link_or_file: + enabled: true + weight: 49 + oldest_days: + weight: 50 + enabled: false + pending_requests_viid: + weight: 51 + enabled: false + proc_req_viic: + weight: 52 + enabled: false + processed_requests_vii: + weight: 53 + enabled: false + quarterly_component_data: + weight: 54 + enabled: false + req_viiia: + weight: 55 + enabled: false + req_viiib: + weight: 56 + enabled: false + statute: + weight: 57 + enabled: false + statute_agency_details: + weight: 58 + enabled: false + sub_xia: + weight: 59 + enabled: false + sub_xib: + weight: 60 + enabled: false +field_type: entity_reference_revisions diff --git a/config/default/field.field.node.cfo_meeting.field_meeting_heading.yml b/config/default/field.field.node.cfo_meeting.field_meeting_heading.yml new file mode 100644 index 000000000..fb1975a8c --- /dev/null +++ b/config/default/field.field.node.cfo_meeting.field_meeting_heading.yml @@ -0,0 +1,27 @@ +uuid: ec493fe4-e3fc-450c-93f5-93e8514f2ac2 +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_meeting_heading + - node.type.cfo_meeting + module: + - foia_autocalc + - text +third_party_settings: + foia_autocalc: + autocalc_settings: + description: '' + autocalc_config: '' +id: node.cfo_meeting.field_meeting_heading +field_name: field_meeting_heading +entity_type: node +bundle: cfo_meeting +label: Heading +description: 'The heading will appear at the top of the agenda page for this meeting.' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: text_long diff --git a/config/default/field.field.node.cfo_meeting.field_meeting_materials.yml b/config/default/field.field.node.cfo_meeting.field_meeting_materials.yml new file mode 100644 index 000000000..ae3e25ae8 --- /dev/null +++ b/config/default/field.field.node.cfo_meeting.field_meeting_materials.yml @@ -0,0 +1,124 @@ +uuid: 307b48a9-97d3-4b52-b12d-47849fbf5009 +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_meeting_materials + - node.type.cfo_meeting + - paragraphs.paragraphs_type.link_or_file + module: + - entity_reference_revisions + - foia_autocalc +third_party_settings: + foia_autocalc: + autocalc_settings: + description: '' + autocalc_config: '' +id: node.cfo_meeting.field_meeting_materials +field_name: field_meeting_materials +entity_type: node +bundle: cfo_meeting +label: 'Meeting Materials' +description: 'Enter links for the meeting materials. You may enter in a URL for the link or upload a file. Drag the crosshairs to re-order these links.' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:paragraph' + handler_settings: + negate: 0 + target_bundles: + link_or_file: link_or_file + target_bundles_drag_drop: + admin_app_via: + weight: 31 + enabled: false + admin_app_vib: + weight: 32 + enabled: false + admin_app_vic1: + weight: 33 + enabled: false + admin_app_vic2: + weight: 34 + enabled: false + admin_app_vic3: + weight: 35 + enabled: false + admin_app_vic3_oth_details: + weight: 36 + enabled: false + admin_app_vic4: + weight: 37 + enabled: false + fees_x: + weight: 38 + enabled: false + foia_pers_costs_ix: + weight: 39 + enabled: false + foia_req_va: + weight: 40 + enabled: false + foia_req_vb1: + weight: 41 + enabled: false + foia_req_vb2: + weight: 42 + enabled: false + foia_req_vb2_other_details: + weight: 43 + enabled: false + foia_req_vb3: + weight: 44 + enabled: false + foia_xii_backlogged: + weight: 45 + enabled: false + foia_xii_received_proc: + weight: 46 + enabled: false + foia_xiia: + weight: 47 + enabled: false + foia_xiib: + weight: 48 + enabled: false + link_or_file: + enabled: true + weight: 49 + oldest_days: + weight: 50 + enabled: false + pending_requests_viid: + weight: 51 + enabled: false + proc_req_viic: + weight: 52 + enabled: false + processed_requests_vii: + weight: 53 + enabled: false + quarterly_component_data: + weight: 54 + enabled: false + req_viiia: + weight: 55 + enabled: false + req_viiib: + weight: 56 + enabled: false + statute: + weight: 57 + enabled: false + statute_agency_details: + weight: 58 + enabled: false + sub_xia: + weight: 59 + enabled: false + sub_xib: + weight: 60 + enabled: false +field_type: entity_reference_revisions diff --git a/config/default/field.storage.node.field_meeting_agenda.yml b/config/default/field.storage.node.field_meeting_agenda.yml new file mode 100644 index 000000000..ab19f3cde --- /dev/null +++ b/config/default/field.storage.node.field_meeting_agenda.yml @@ -0,0 +1,25 @@ +uuid: e828b8f6-6dae-4af5-8819-e0a1781c3c12 +langcode: en +status: true +dependencies: + module: + - entity_reference_revisions + - field_permissions + - node + - paragraphs +third_party_settings: + field_permissions: + permission_type: public +id: node.field_meeting_agenda +field_name: field_meeting_agenda +entity_type: node +type: entity_reference_revisions +settings: + target_type: paragraph +module: entity_reference_revisions +locked: false +cardinality: -1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/default/field.storage.node.field_meeting_date.yml b/config/default/field.storage.node.field_meeting_date.yml new file mode 100644 index 000000000..827b622a6 --- /dev/null +++ b/config/default/field.storage.node.field_meeting_date.yml @@ -0,0 +1,24 @@ +uuid: 7ec7cbd9-b930-4eff-ae05-7ce84c098cfa +langcode: en +status: true +dependencies: + module: + - datetime + - field_permissions + - node +third_party_settings: + field_permissions: + permission_type: public +id: node.field_meeting_date +field_name: field_meeting_date +entity_type: node +type: datetime +settings: + datetime_type: datetime +module: datetime +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/default/field.storage.node.field_meeting_documents.yml b/config/default/field.storage.node.field_meeting_documents.yml new file mode 100644 index 000000000..892b81cba --- /dev/null +++ b/config/default/field.storage.node.field_meeting_documents.yml @@ -0,0 +1,25 @@ +uuid: d9b213bb-1ce1-46b6-9119-91defcca0df3 +langcode: en +status: true +dependencies: + module: + - entity_reference_revisions + - field_permissions + - node + - paragraphs +third_party_settings: + field_permissions: + permission_type: public +id: node.field_meeting_documents +field_name: field_meeting_documents +entity_type: node +type: entity_reference_revisions +settings: + target_type: paragraph +module: entity_reference_revisions +locked: false +cardinality: -1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/default/field.storage.node.field_meeting_heading.yml b/config/default/field.storage.node.field_meeting_heading.yml new file mode 100644 index 000000000..e7ee24a0e --- /dev/null +++ b/config/default/field.storage.node.field_meeting_heading.yml @@ -0,0 +1,23 @@ +uuid: 173a644b-c350-498c-b8c9-718337d24f2b +langcode: en +status: true +dependencies: + module: + - field_permissions + - node + - text +third_party_settings: + field_permissions: + permission_type: public +id: node.field_meeting_heading +field_name: field_meeting_heading +entity_type: node +type: text_long +settings: { } +module: text +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/default/field.storage.node.field_meeting_materials.yml b/config/default/field.storage.node.field_meeting_materials.yml new file mode 100644 index 000000000..624833c95 --- /dev/null +++ b/config/default/field.storage.node.field_meeting_materials.yml @@ -0,0 +1,25 @@ +uuid: cea7dd6f-7a52-4a2e-b1e2-bb63777f9391 +langcode: en +status: true +dependencies: + module: + - entity_reference_revisions + - field_permissions + - node + - paragraphs +third_party_settings: + field_permissions: + permission_type: public +id: node.field_meeting_materials +field_name: field_meeting_materials +entity_type: node +type: entity_reference_revisions +settings: + target_type: paragraph +module: entity_reference_revisions +locked: false +cardinality: -1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/default/node.type.cfo_meeting.yml b/config/default/node.type.cfo_meeting.yml new file mode 100644 index 000000000..bdc6c175c --- /dev/null +++ b/config/default/node.type.cfo_meeting.yml @@ -0,0 +1,20 @@ +uuid: 706c582b-cb0c-499c-b92c-0d88f747417f +langcode: en +status: true +dependencies: + module: + - lightning_workflow + - menu_ui +third_party_settings: + menu_ui: + available_menus: { } + parent: '' + lightning_workflow: + workflow: editorial +name: 'CFO Meeting' +type: cfo_meeting +description: 'Meetings for the Chief FOIA Officers Council. Contains the date, body, heading, agenda, and links to meeting related documents and information.' +help: '' +new_revision: true +preview_mode: 1 +display_submitted: false diff --git a/config/default/system.action.user_add_role_action.cfo_meeting_creator.yml b/config/default/system.action.user_add_role_action.cfo_meeting_creator.yml new file mode 100644 index 000000000..9464edf0f --- /dev/null +++ b/config/default/system.action.user_add_role_action.cfo_meeting_creator.yml @@ -0,0 +1,14 @@ +uuid: 966a4ec7-4bc9-4535-bce9-b55ca18d7718 +langcode: en +status: true +dependencies: + config: + - user.role.cfo_meeting_creator + module: + - user +id: user_add_role_action.cfo_meeting_creator +label: 'Add the CFO Meeting creator role to the selected user(s)' +type: user +plugin: user_add_role_action +configuration: + rid: cfo_meeting_creator diff --git a/config/default/system.action.user_add_role_action.cfo_meeting_reviewer.yml b/config/default/system.action.user_add_role_action.cfo_meeting_reviewer.yml new file mode 100644 index 000000000..923ee757b --- /dev/null +++ b/config/default/system.action.user_add_role_action.cfo_meeting_reviewer.yml @@ -0,0 +1,14 @@ +uuid: 255458f4-c7cb-4a25-8cc5-3a294b663ede +langcode: en +status: true +dependencies: + config: + - user.role.cfo_meeting_reviewer + module: + - user +id: user_add_role_action.cfo_meeting_reviewer +label: 'Add the CFO Meeting reviewer role to the selected user(s)' +type: user +plugin: user_add_role_action +configuration: + rid: cfo_meeting_reviewer diff --git a/config/default/system.action.user_remove_role_action.cfo_meeting_creator.yml b/config/default/system.action.user_remove_role_action.cfo_meeting_creator.yml new file mode 100644 index 000000000..9bf586e19 --- /dev/null +++ b/config/default/system.action.user_remove_role_action.cfo_meeting_creator.yml @@ -0,0 +1,14 @@ +uuid: 985bd7a4-5312-4fc5-aa78-5e9e9485e2c8 +langcode: en +status: true +dependencies: + config: + - user.role.cfo_meeting_creator + module: + - user +id: user_remove_role_action.cfo_meeting_creator +label: 'Remove the CFO Meeting creator role from the selected user(s)' +type: user +plugin: user_remove_role_action +configuration: + rid: cfo_meeting_creator diff --git a/config/default/system.action.user_remove_role_action.cfo_meeting_reviewer.yml b/config/default/system.action.user_remove_role_action.cfo_meeting_reviewer.yml new file mode 100644 index 000000000..289022eb3 --- /dev/null +++ b/config/default/system.action.user_remove_role_action.cfo_meeting_reviewer.yml @@ -0,0 +1,14 @@ +uuid: 1900340d-5a98-4928-918a-11f3a06d03b3 +langcode: en +status: true +dependencies: + config: + - user.role.cfo_meeting_reviewer + module: + - user +id: user_remove_role_action.cfo_meeting_reviewer +label: 'Remove the CFO Meeting reviewer role from the selected user(s)' +type: user +plugin: user_remove_role_action +configuration: + rid: cfo_meeting_reviewer diff --git a/config/default/user.role.cfo_meeting_creator.yml b/config/default/user.role.cfo_meeting_creator.yml new file mode 100644 index 000000000..1ab9bcc85 --- /dev/null +++ b/config/default/user.role.cfo_meeting_creator.yml @@ -0,0 +1,26 @@ +uuid: 6af9c031-22a4-4d8c-ae4d-b5cdcd9c5519 +langcode: en +status: true +dependencies: { } +id: cfo_meeting_creator +label: 'CFO Meeting creator' +weight: 15 +is_admin: false +permissions: + - 'access image_browser entity browser pages' + - 'access media_browser entity browser pages' + - 'access panels in-place editing' + - 'administer panelizer node cfo_meeting content' + - 'administer panelizer node cfo_meeting layout' + - 'change layouts in place editing' + - 'create cfo_meeting content' + - 'create url aliases' + - 'edit own cfo_meeting content' + - 'use draft_draft transition' + - 'use draft_needs_review transition' + - 'use needs_review_needs_review transition' + - 'use text format rich_text' + - 'view any unpublished content' + - 'view cfo_meeting revisions' + - 'view latest version' + - 'view own unpublished content' diff --git a/config/default/user.role.cfo_meeting_reviewer.yml b/config/default/user.role.cfo_meeting_reviewer.yml new file mode 100644 index 000000000..b445b360e --- /dev/null +++ b/config/default/user.role.cfo_meeting_reviewer.yml @@ -0,0 +1,20 @@ +uuid: 3e1ab9d3-ff68-4e46-abd0-bd450e5f4942 +langcode: en +status: true +dependencies: { } +id: cfo_meeting_reviewer +label: 'CFO Meeting reviewer' +weight: 16 +is_admin: false +permissions: + - 'access content overview' + - 'delete any cfo_meeting content' + - 'edit any cfo_meeting content' + - 'use draft_published transition' + - 'use needs_review_draft transition' + - 'use needs_review_published transition' + - 'use published_archived transition' + - 'use published_published transition' + - 'view any unpublished content' + - 'view latest version' + - 'view moderation states' From 5385f83e16f4f770df9239179de7700becbd4f2c Mon Sep 17 00:00:00 2001 From: scott_earnest Date: Thu, 28 Oct 2021 07:59:31 -0600 Subject: [PATCH 06/18] FE2-34: Config for CFO Committee content type. --- ...ld_override.node.cfo_committee.promote.yml | 22 +++++ ...orm_display.node.cfo_committee.default.yml | 85 +++++++++++++++++++ ...iew_display.node.cfo_committee.default.yml | 34 ++++++++ ...view_display.node.cfo_committee.teaser.yml | 36 ++++++++ .../field.field.node.cfo_committee.body.yml | 29 +++++++ ...e.cfo_council.field_council_committees.yml | 35 ++++++++ ....storage.node.field_council_committees.yml | 23 +++++ config/default/node.type.cfo_committee.yml | 21 +++++ ..._add_role_action.cfo_committee_creator.yml | 14 +++ ...add_role_action.cfo_committee_reviewer.yml | 14 +++ ...move_role_action.cfo_committee_creator.yml | 14 +++ ...ove_role_action.cfo_committee_reviewer.yml | 14 +++ .../user.role.cfo_committee_creator.yml | 26 ++++++ .../user.role.cfo_committee_reviewer.yml | 20 +++++ 14 files changed, 387 insertions(+) create mode 100644 config/default/core.base_field_override.node.cfo_committee.promote.yml create mode 100644 config/default/core.entity_form_display.node.cfo_committee.default.yml create mode 100644 config/default/core.entity_view_display.node.cfo_committee.default.yml create mode 100644 config/default/core.entity_view_display.node.cfo_committee.teaser.yml create mode 100644 config/default/field.field.node.cfo_committee.body.yml create mode 100644 config/default/field.field.node.cfo_council.field_council_committees.yml create mode 100644 config/default/field.storage.node.field_council_committees.yml create mode 100644 config/default/node.type.cfo_committee.yml create mode 100644 config/default/system.action.user_add_role_action.cfo_committee_creator.yml create mode 100644 config/default/system.action.user_add_role_action.cfo_committee_reviewer.yml create mode 100644 config/default/system.action.user_remove_role_action.cfo_committee_creator.yml create mode 100644 config/default/system.action.user_remove_role_action.cfo_committee_reviewer.yml create mode 100644 config/default/user.role.cfo_committee_creator.yml create mode 100644 config/default/user.role.cfo_committee_reviewer.yml diff --git a/config/default/core.base_field_override.node.cfo_committee.promote.yml b/config/default/core.base_field_override.node.cfo_committee.promote.yml new file mode 100644 index 000000000..1c5984b00 --- /dev/null +++ b/config/default/core.base_field_override.node.cfo_committee.promote.yml @@ -0,0 +1,22 @@ +uuid: 981b7330-b500-482f-bb96-21782d55c7df +langcode: en +status: true +dependencies: + config: + - node.type.cfo_committee +id: node.cfo_committee.promote +field_name: promote +entity_type: node +bundle: cfo_committee +label: 'Promoted to front page' +description: '' +required: false +translatable: true +default_value: + - + value: 0 +default_value_callback: '' +settings: + on_label: 'On' + off_label: 'Off' +field_type: boolean diff --git a/config/default/core.entity_form_display.node.cfo_committee.default.yml b/config/default/core.entity_form_display.node.cfo_committee.default.yml new file mode 100644 index 000000000..d10948f08 --- /dev/null +++ b/config/default/core.entity_form_display.node.cfo_committee.default.yml @@ -0,0 +1,85 @@ +uuid: cc2bb812-ee19-47b0-b4e9-81a363c4a07c +langcode: en +status: true +dependencies: + config: + - field.field.node.cfo_committee.body + - node.type.cfo_committee + - workflows.workflow.editorial + module: + - content_moderation + - path + - text +id: node.cfo_committee.default +targetEntityType: node +bundle: cfo_committee +mode: default +content: + body: + type: text_textarea_with_summary + weight: 121 + settings: + rows: 9 + summary_rows: 3 + placeholder: '' + show_summary: false + third_party_settings: { } + region: content + created: + type: datetime_timestamp + weight: 10 + region: content + settings: { } + third_party_settings: { } + moderation_state: + type: moderation_state_default + weight: 100 + settings: { } + region: content + third_party_settings: { } + path: + type: path + weight: 30 + region: content + settings: { } + third_party_settings: { } + promote: + type: boolean_checkbox + settings: + display_label: true + weight: 15 + region: content + third_party_settings: { } + status: + type: boolean_checkbox + settings: + display_label: true + weight: 120 + region: content + third_party_settings: { } + sticky: + type: boolean_checkbox + settings: + display_label: true + weight: 16 + region: content + third_party_settings: { } + title: + type: string_textfield + weight: -5 + region: content + settings: + size: 60 + placeholder: '' + third_party_settings: { } + uid: + type: entity_reference_autocomplete + weight: 5 + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + match_limit: 10 + region: content + third_party_settings: { } +hidden: { } diff --git a/config/default/core.entity_view_display.node.cfo_committee.default.yml b/config/default/core.entity_view_display.node.cfo_committee.default.yml new file mode 100644 index 000000000..f708c84ff --- /dev/null +++ b/config/default/core.entity_view_display.node.cfo_committee.default.yml @@ -0,0 +1,34 @@ +uuid: ea6f80b4-735c-47ab-a192-cb15c84509e9 +langcode: en +status: true +dependencies: + config: + - field.field.node.cfo_committee.body + - node.type.cfo_committee + module: + - text + - user +id: node.cfo_committee.default +targetEntityType: node +bundle: cfo_committee +mode: default +content: + body: + label: hidden + type: text_default + weight: 101 + settings: { } + third_party_settings: { } + region: content + content_moderation_control: + weight: -20 + settings: { } + third_party_settings: { } + region: content + links: + weight: 100 + settings: { } + third_party_settings: { } + region: content +hidden: + search_api_excerpt: true diff --git a/config/default/core.entity_view_display.node.cfo_committee.teaser.yml b/config/default/core.entity_view_display.node.cfo_committee.teaser.yml new file mode 100644 index 000000000..b1b83c0be --- /dev/null +++ b/config/default/core.entity_view_display.node.cfo_committee.teaser.yml @@ -0,0 +1,36 @@ +uuid: 9c0dc38e-5380-4765-aec1-2f5c48912ac5 +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.node.teaser + - field.field.node.cfo_committee.body + - node.type.cfo_committee + module: + - text + - user +id: node.cfo_committee.teaser +targetEntityType: node +bundle: cfo_committee +mode: teaser +content: + body: + label: hidden + type: text_summary_or_trimmed + weight: 101 + settings: + trim_length: 600 + third_party_settings: { } + region: content + content_moderation_control: + weight: -20 + settings: { } + third_party_settings: { } + region: content + links: + weight: 100 + settings: { } + third_party_settings: { } + region: content +hidden: + search_api_excerpt: true diff --git a/config/default/field.field.node.cfo_committee.body.yml b/config/default/field.field.node.cfo_committee.body.yml new file mode 100644 index 000000000..31cfdeab9 --- /dev/null +++ b/config/default/field.field.node.cfo_committee.body.yml @@ -0,0 +1,29 @@ +uuid: 1fa6272f-487a-41ae-9ae6-c77be9989927 +langcode: en +status: true +dependencies: + config: + - field.storage.node.body + - node.type.cfo_committee + module: + - foia_autocalc + - text +third_party_settings: + foia_autocalc: + autocalc_settings: + description: '' + autocalc_config: '' +id: node.cfo_committee.body +field_name: body +entity_type: node +bundle: cfo_committee +label: Body +description: '' +required: false +translatable: true +default_value: { } +default_value_callback: '' +settings: + display_summary: true + required_summary: false +field_type: text_with_summary diff --git a/config/default/field.field.node.cfo_council.field_council_committees.yml b/config/default/field.field.node.cfo_council.field_council_committees.yml new file mode 100644 index 000000000..7d95ef551 --- /dev/null +++ b/config/default/field.field.node.cfo_council.field_council_committees.yml @@ -0,0 +1,35 @@ +uuid: 436d3455-c52d-4770-8e9b-22af7ef3bd4b +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_council_committees + - node.type.cfo_committee + - node.type.cfo_council + module: + - foia_autocalc +third_party_settings: + foia_autocalc: + autocalc_settings: + description: '' + autocalc_config: '' +id: node.cfo_council.field_council_committees +field_name: field_council_committees +entity_type: node +bundle: cfo_council +label: Committees +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:node' + handler_settings: + target_bundles: + cfo_committee: cfo_committee + sort: + field: _none + auto_create: false + auto_create_bundle: '' +field_type: entity_reference diff --git a/config/default/field.storage.node.field_council_committees.yml b/config/default/field.storage.node.field_council_committees.yml new file mode 100644 index 000000000..30e95c7da --- /dev/null +++ b/config/default/field.storage.node.field_council_committees.yml @@ -0,0 +1,23 @@ +uuid: 7ce9db4d-000d-480b-aff9-bc8c3189dff7 +langcode: en +status: true +dependencies: + module: + - field_permissions + - node +third_party_settings: + field_permissions: + permission_type: public +id: node.field_council_committees +field_name: field_council_committees +entity_type: node +type: entity_reference +settings: + target_type: node +module: core +locked: false +cardinality: -1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/default/node.type.cfo_committee.yml b/config/default/node.type.cfo_committee.yml new file mode 100644 index 000000000..a9f496a47 --- /dev/null +++ b/config/default/node.type.cfo_committee.yml @@ -0,0 +1,21 @@ +uuid: 07aaf791-e099-477b-89cc-e5ffc94a34c6 +langcode: en +status: true +dependencies: + module: + - lightning_workflow + - menu_ui +third_party_settings: + menu_ui: + available_menus: + - main + parent: 'main:' + lightning_workflow: + workflow: editorial +name: 'CFO Committee' +type: cfo_committee +description: 'Committees of the Chief FOIA Officers Council. Includes title and WYSIWYG description fields.' +help: '' +new_revision: true +preview_mode: 1 +display_submitted: false diff --git a/config/default/system.action.user_add_role_action.cfo_committee_creator.yml b/config/default/system.action.user_add_role_action.cfo_committee_creator.yml new file mode 100644 index 000000000..0fe09cb6f --- /dev/null +++ b/config/default/system.action.user_add_role_action.cfo_committee_creator.yml @@ -0,0 +1,14 @@ +uuid: afd47e77-3668-40d7-b184-addf1cfb80a3 +langcode: en +status: true +dependencies: + config: + - user.role.cfo_committee_creator + module: + - user +id: user_add_role_action.cfo_committee_creator +label: 'Add the CFO Committee creator role to the selected user(s)' +type: user +plugin: user_add_role_action +configuration: + rid: cfo_committee_creator diff --git a/config/default/system.action.user_add_role_action.cfo_committee_reviewer.yml b/config/default/system.action.user_add_role_action.cfo_committee_reviewer.yml new file mode 100644 index 000000000..1ecd3d8d4 --- /dev/null +++ b/config/default/system.action.user_add_role_action.cfo_committee_reviewer.yml @@ -0,0 +1,14 @@ +uuid: d8745c13-a6eb-4366-bd68-2404cec40240 +langcode: en +status: true +dependencies: + config: + - user.role.cfo_committee_reviewer + module: + - user +id: user_add_role_action.cfo_committee_reviewer +label: 'Add the CFO Committee reviewer role to the selected user(s)' +type: user +plugin: user_add_role_action +configuration: + rid: cfo_committee_reviewer diff --git a/config/default/system.action.user_remove_role_action.cfo_committee_creator.yml b/config/default/system.action.user_remove_role_action.cfo_committee_creator.yml new file mode 100644 index 000000000..e96237ae5 --- /dev/null +++ b/config/default/system.action.user_remove_role_action.cfo_committee_creator.yml @@ -0,0 +1,14 @@ +uuid: a3ae1fc5-7889-4e93-a576-578f0b7530de +langcode: en +status: true +dependencies: + config: + - user.role.cfo_committee_creator + module: + - user +id: user_remove_role_action.cfo_committee_creator +label: 'Remove the CFO Committee creator role from the selected user(s)' +type: user +plugin: user_remove_role_action +configuration: + rid: cfo_committee_creator diff --git a/config/default/system.action.user_remove_role_action.cfo_committee_reviewer.yml b/config/default/system.action.user_remove_role_action.cfo_committee_reviewer.yml new file mode 100644 index 000000000..a3d19777d --- /dev/null +++ b/config/default/system.action.user_remove_role_action.cfo_committee_reviewer.yml @@ -0,0 +1,14 @@ +uuid: 850219d8-ea60-49d8-9651-1b21febd5764 +langcode: en +status: true +dependencies: + config: + - user.role.cfo_committee_reviewer + module: + - user +id: user_remove_role_action.cfo_committee_reviewer +label: 'Remove the CFO Committee reviewer role from the selected user(s)' +type: user +plugin: user_remove_role_action +configuration: + rid: cfo_committee_reviewer diff --git a/config/default/user.role.cfo_committee_creator.yml b/config/default/user.role.cfo_committee_creator.yml new file mode 100644 index 000000000..622e50c4d --- /dev/null +++ b/config/default/user.role.cfo_committee_creator.yml @@ -0,0 +1,26 @@ +uuid: 6269385c-89bd-40ca-b9dc-f7bc4bd0013c +langcode: en +status: true +dependencies: { } +id: cfo_committee_creator +label: 'CFO Committee creator' +weight: 17 +is_admin: false +permissions: + - 'access image_browser entity browser pages' + - 'access media_browser entity browser pages' + - 'access panels in-place editing' + - 'administer panelizer node cfo_committee content' + - 'administer panelizer node cfo_committee layout' + - 'change layouts in place editing' + - 'create cfo_committee content' + - 'create url aliases' + - 'edit own cfo_committee content' + - 'use draft_draft transition' + - 'use draft_needs_review transition' + - 'use needs_review_needs_review transition' + - 'use text format rich_text' + - 'view any unpublished content' + - 'view cfo_committee revisions' + - 'view latest version' + - 'view own unpublished content' diff --git a/config/default/user.role.cfo_committee_reviewer.yml b/config/default/user.role.cfo_committee_reviewer.yml new file mode 100644 index 000000000..9e53b8349 --- /dev/null +++ b/config/default/user.role.cfo_committee_reviewer.yml @@ -0,0 +1,20 @@ +uuid: 0bd16333-b7ea-4403-b19b-6e68da45a084 +langcode: en +status: true +dependencies: { } +id: cfo_committee_reviewer +label: 'CFO Committee reviewer' +weight: 18 +is_admin: false +permissions: + - 'access content overview' + - 'delete any cfo_committee content' + - 'edit any cfo_committee content' + - 'use draft_published transition' + - 'use needs_review_draft transition' + - 'use needs_review_published transition' + - 'use published_archived transition' + - 'use published_published transition' + - 'view any unpublished content' + - 'view latest version' + - 'view moderation states' From d7bb1ce8f0c877fe48f23925e54ebf445b7f74f0 Mon Sep 17 00:00:00 2001 From: scott_earnest Date: Thu, 28 Oct 2021 07:59:55 -0600 Subject: [PATCH 07/18] FE2-34: Config for CFO Council content type. --- ...ield_override.node.cfo_council.promote.yml | 22 + ..._form_display.node.cfo_council.default.yml | 96 ++ ..._view_display.node.cfo_council.default.yml | 43 + ...y_view_display.node.cfo_council.teaser.yml | 38 + .../field.field.node.cfo_council.body.yml | 29 + config/default/node.type.cfo_council.yml | 21 + ...er_add_role_action.cfo_council_creator.yml | 14 + ...r_add_role_action.cfo_council_reviewer.yml | 14 + ...remove_role_action.cfo_council_creator.yml | 14 + ...emove_role_action.cfo_council_reviewer.yml | 14 + .../default/user.role.cfo_council_creator.yml | 26 + .../user.role.cfo_council_reviewer.yml | 20 + config/default/views.view.cfo_council.yml | 238 +++++ .../default/views.view.cfo_council_admin.yml | 873 ++++++++++++++++++ 14 files changed, 1462 insertions(+) create mode 100644 config/default/core.base_field_override.node.cfo_council.promote.yml create mode 100644 config/default/core.entity_form_display.node.cfo_council.default.yml create mode 100644 config/default/core.entity_view_display.node.cfo_council.default.yml create mode 100644 config/default/core.entity_view_display.node.cfo_council.teaser.yml create mode 100644 config/default/field.field.node.cfo_council.body.yml create mode 100644 config/default/node.type.cfo_council.yml create mode 100644 config/default/system.action.user_add_role_action.cfo_council_creator.yml create mode 100644 config/default/system.action.user_add_role_action.cfo_council_reviewer.yml create mode 100644 config/default/system.action.user_remove_role_action.cfo_council_creator.yml create mode 100644 config/default/system.action.user_remove_role_action.cfo_council_reviewer.yml create mode 100644 config/default/user.role.cfo_council_creator.yml create mode 100644 config/default/user.role.cfo_council_reviewer.yml create mode 100644 config/default/views.view.cfo_council.yml create mode 100644 config/default/views.view.cfo_council_admin.yml diff --git a/config/default/core.base_field_override.node.cfo_council.promote.yml b/config/default/core.base_field_override.node.cfo_council.promote.yml new file mode 100644 index 000000000..1a6e00311 --- /dev/null +++ b/config/default/core.base_field_override.node.cfo_council.promote.yml @@ -0,0 +1,22 @@ +uuid: 1fd07756-def5-47fc-8104-a569f528dbd6 +langcode: en +status: true +dependencies: + config: + - node.type.cfo_council +id: node.cfo_council.promote +field_name: promote +entity_type: node +bundle: cfo_council +label: 'Promoted to front page' +description: '' +required: false +translatable: true +default_value: + - + value: 0 +default_value_callback: '' +settings: + on_label: 'On' + off_label: 'Off' +field_type: boolean diff --git a/config/default/core.entity_form_display.node.cfo_council.default.yml b/config/default/core.entity_form_display.node.cfo_council.default.yml new file mode 100644 index 000000000..596eada22 --- /dev/null +++ b/config/default/core.entity_form_display.node.cfo_council.default.yml @@ -0,0 +1,96 @@ +uuid: 59d17392-3da3-4f20-97eb-801864478f37 +langcode: en +status: true +dependencies: + config: + - field.field.node.cfo_council.body + - field.field.node.cfo_council.field_council_committees + - node.type.cfo_council + - workflows.workflow.editorial + module: + - content_moderation + - path + - text +id: node.cfo_council.default +targetEntityType: node +bundle: cfo_council +mode: default +content: + body: + type: text_textarea_with_summary + weight: 1 + settings: + rows: 9 + summary_rows: 3 + placeholder: '' + show_summary: false + third_party_settings: { } + region: content + created: + type: datetime_timestamp + weight: 4 + region: content + settings: { } + third_party_settings: { } + field_council_committees: + weight: 2 + settings: + match_operator: CONTAINS + match_limit: 10 + size: 60 + placeholder: '' + third_party_settings: { } + type: entity_reference_autocomplete + region: content + moderation_state: + type: moderation_state_default + weight: 8 + settings: { } + region: content + third_party_settings: { } + path: + type: path + weight: 7 + region: content + settings: { } + third_party_settings: { } + promote: + type: boolean_checkbox + settings: + display_label: true + weight: 5 + region: content + third_party_settings: { } + status: + type: boolean_checkbox + settings: + display_label: true + weight: 9 + region: content + third_party_settings: { } + sticky: + type: boolean_checkbox + settings: + display_label: true + weight: 6 + region: content + third_party_settings: { } + title: + type: string_textfield + weight: 0 + region: content + settings: + size: 60 + placeholder: '' + third_party_settings: { } + uid: + type: entity_reference_autocomplete + weight: 3 + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + match_limit: 10 + region: content + third_party_settings: { } +hidden: { } diff --git a/config/default/core.entity_view_display.node.cfo_council.default.yml b/config/default/core.entity_view_display.node.cfo_council.default.yml new file mode 100644 index 000000000..17fa6bb9b --- /dev/null +++ b/config/default/core.entity_view_display.node.cfo_council.default.yml @@ -0,0 +1,43 @@ +uuid: 89defc83-c75a-4ad6-a0c5-221cc32b9ac4 +langcode: en +status: true +dependencies: + config: + - field.field.node.cfo_council.body + - field.field.node.cfo_council.field_council_committees + - node.type.cfo_council + module: + - text + - user +id: node.cfo_council.default +targetEntityType: node +bundle: cfo_council +mode: default +content: + body: + label: hidden + type: text_default + weight: 101 + settings: { } + third_party_settings: { } + region: content + content_moderation_control: + weight: -20 + settings: { } + third_party_settings: { } + region: content + field_council_committees: + weight: 102 + label: above + settings: + link: true + third_party_settings: { } + type: entity_reference_label + region: content + links: + weight: 100 + settings: { } + third_party_settings: { } + region: content +hidden: + search_api_excerpt: true diff --git a/config/default/core.entity_view_display.node.cfo_council.teaser.yml b/config/default/core.entity_view_display.node.cfo_council.teaser.yml new file mode 100644 index 000000000..523bc6fd6 --- /dev/null +++ b/config/default/core.entity_view_display.node.cfo_council.teaser.yml @@ -0,0 +1,38 @@ +uuid: 1f742005-aa95-4efc-be71-8d063ffcc233 +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.node.teaser + - field.field.node.cfo_council.body + - field.field.node.cfo_council.field_council_committees + - node.type.cfo_council + module: + - text + - user +id: node.cfo_council.teaser +targetEntityType: node +bundle: cfo_council +mode: teaser +content: + body: + label: hidden + type: text_summary_or_trimmed + weight: 101 + settings: + trim_length: 600 + third_party_settings: { } + region: content + content_moderation_control: + weight: -20 + settings: { } + third_party_settings: { } + region: content + links: + weight: 100 + settings: { } + third_party_settings: { } + region: content +hidden: + field_council_committees: true + search_api_excerpt: true diff --git a/config/default/field.field.node.cfo_council.body.yml b/config/default/field.field.node.cfo_council.body.yml new file mode 100644 index 000000000..994cbaacd --- /dev/null +++ b/config/default/field.field.node.cfo_council.body.yml @@ -0,0 +1,29 @@ +uuid: 9f6c2631-bddd-4b51-884d-a5f686ba50c1 +langcode: en +status: true +dependencies: + config: + - field.storage.node.body + - node.type.cfo_council + module: + - foia_autocalc + - text +third_party_settings: + foia_autocalc: + autocalc_settings: + description: '' + autocalc_config: '' +id: node.cfo_council.body +field_name: body +entity_type: node +bundle: cfo_council +label: Body +description: '' +required: false +translatable: true +default_value: { } +default_value_callback: '' +settings: + display_summary: true + required_summary: false +field_type: text_with_summary diff --git a/config/default/node.type.cfo_council.yml b/config/default/node.type.cfo_council.yml new file mode 100644 index 000000000..b11493b55 --- /dev/null +++ b/config/default/node.type.cfo_council.yml @@ -0,0 +1,21 @@ +uuid: 752582a9-d6b7-44ec-a225-9418d8abbb6f +langcode: en +status: true +dependencies: + module: + - lightning_workflow + - menu_ui +third_party_settings: + menu_ui: + available_menus: + - main + parent: 'main:' + lightning_workflow: + workflow: editorial +name: 'CFO Council' +type: cfo_council +description: 'The main page for the Chief FOIA Officers Council. Assign committees to the council. Meetings will be automatically attached.' +help: '' +new_revision: true +preview_mode: 1 +display_submitted: false diff --git a/config/default/system.action.user_add_role_action.cfo_council_creator.yml b/config/default/system.action.user_add_role_action.cfo_council_creator.yml new file mode 100644 index 000000000..83a89049d --- /dev/null +++ b/config/default/system.action.user_add_role_action.cfo_council_creator.yml @@ -0,0 +1,14 @@ +uuid: ff720bce-3fcf-4665-9039-c62a17b18931 +langcode: en +status: true +dependencies: + config: + - user.role.cfo_council_creator + module: + - user +id: user_add_role_action.cfo_council_creator +label: 'Add the CFO Council creator role to the selected user(s)' +type: user +plugin: user_add_role_action +configuration: + rid: cfo_council_creator diff --git a/config/default/system.action.user_add_role_action.cfo_council_reviewer.yml b/config/default/system.action.user_add_role_action.cfo_council_reviewer.yml new file mode 100644 index 000000000..92a9f6848 --- /dev/null +++ b/config/default/system.action.user_add_role_action.cfo_council_reviewer.yml @@ -0,0 +1,14 @@ +uuid: 0c953364-2af4-45dc-8fc4-604415f84977 +langcode: en +status: true +dependencies: + config: + - user.role.cfo_council_reviewer + module: + - user +id: user_add_role_action.cfo_council_reviewer +label: 'Add the CFO Council reviewer role to the selected user(s)' +type: user +plugin: user_add_role_action +configuration: + rid: cfo_council_reviewer diff --git a/config/default/system.action.user_remove_role_action.cfo_council_creator.yml b/config/default/system.action.user_remove_role_action.cfo_council_creator.yml new file mode 100644 index 000000000..3e6732de0 --- /dev/null +++ b/config/default/system.action.user_remove_role_action.cfo_council_creator.yml @@ -0,0 +1,14 @@ +uuid: 1d77543c-b265-44a5-9966-a381d882ed13 +langcode: en +status: true +dependencies: + config: + - user.role.cfo_council_creator + module: + - user +id: user_remove_role_action.cfo_council_creator +label: 'Remove the CFO Council creator role from the selected user(s)' +type: user +plugin: user_remove_role_action +configuration: + rid: cfo_council_creator diff --git a/config/default/system.action.user_remove_role_action.cfo_council_reviewer.yml b/config/default/system.action.user_remove_role_action.cfo_council_reviewer.yml new file mode 100644 index 000000000..a989afdab --- /dev/null +++ b/config/default/system.action.user_remove_role_action.cfo_council_reviewer.yml @@ -0,0 +1,14 @@ +uuid: 98b74db4-30c8-4790-b857-f3cba03d5879 +langcode: en +status: true +dependencies: + config: + - user.role.cfo_council_reviewer + module: + - user +id: user_remove_role_action.cfo_council_reviewer +label: 'Remove the CFO Council reviewer role from the selected user(s)' +type: user +plugin: user_remove_role_action +configuration: + rid: cfo_council_reviewer diff --git a/config/default/user.role.cfo_council_creator.yml b/config/default/user.role.cfo_council_creator.yml new file mode 100644 index 000000000..8e0dc95fd --- /dev/null +++ b/config/default/user.role.cfo_council_creator.yml @@ -0,0 +1,26 @@ +uuid: aad6b39a-88f9-42ec-b31b-b12558418036 +langcode: en +status: true +dependencies: { } +id: cfo_council_creator +label: 'CFO Council creator' +weight: 19 +is_admin: false +permissions: + - 'access image_browser entity browser pages' + - 'access media_browser entity browser pages' + - 'access panels in-place editing' + - 'administer panelizer node cfo_council content' + - 'administer panelizer node cfo_council layout' + - 'change layouts in place editing' + - 'create cfo_council content' + - 'create url aliases' + - 'edit own cfo_council content' + - 'use draft_draft transition' + - 'use draft_needs_review transition' + - 'use needs_review_needs_review transition' + - 'use text format rich_text' + - 'view any unpublished content' + - 'view cfo_council revisions' + - 'view latest version' + - 'view own unpublished content' diff --git a/config/default/user.role.cfo_council_reviewer.yml b/config/default/user.role.cfo_council_reviewer.yml new file mode 100644 index 000000000..dcf22fd6c --- /dev/null +++ b/config/default/user.role.cfo_council_reviewer.yml @@ -0,0 +1,20 @@ +uuid: 5417c1aa-dd79-430f-84da-de8b119d2d38 +langcode: en +status: true +dependencies: { } +id: cfo_council_reviewer +label: 'CFO Council reviewer' +weight: 20 +is_admin: false +permissions: + - 'access content overview' + - 'delete any cfo_council content' + - 'edit any cfo_council content' + - 'use draft_published transition' + - 'use needs_review_draft transition' + - 'use needs_review_published transition' + - 'use published_archived transition' + - 'use published_published transition' + - 'view any unpublished content' + - 'view latest version' + - 'view moderation states' diff --git a/config/default/views.view.cfo_council.yml b/config/default/views.view.cfo_council.yml new file mode 100644 index 000000000..ba2ba174b --- /dev/null +++ b/config/default/views.view.cfo_council.yml @@ -0,0 +1,238 @@ +uuid: 4d1d2559-2df9-437b-9c88-1f07fc2ed888 +langcode: en +status: true +dependencies: + config: + - node.type.cfo_council + module: + - node + - rest + - serialization + - user +id: cfo_council +label: 'CFO Council' +module: views +description: '' +tag: '' +base_table: node_field_data +base_field: nid +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: perm + options: + perm: 'access content' + cache: + type: tag + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + replica: false + query_comment: '' + query_tags: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: mini + options: + items_per_page: 10 + offset: 0 + id: 0 + total_pages: null + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + tags: + previous: ‹‹ + next: ›› + style: + type: serializer + row: + type: fields + options: + inline: { } + separator: '' + hide_empty: false + default_field_elements: true + fields: + title: + id: title + table: node_field_data + field: title + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: false + ellipsis: false + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: node + entity_field: title + plugin_id: field + filters: + status: + value: '1' + table: node_field_data + field: status + plugin_id: boolean + entity_type: node + entity_field: status + id: status + expose: + operator: '' + operator_limit_selection: false + operator_list: { } + group: 1 + type: + id: type + table: node_field_data + field: type + value: + cfo_council: cfo_council + entity_type: node + entity_field: type + plugin_id: bundle + expose: + operator_limit_selection: false + operator_list: { } + sorts: + created: + id: created + table: node_field_data + field: created + order: ASC + entity_type: node + entity_field: created + plugin_id: date + relationship: none + group_type: group + admin_label: '' + exposed: false + expose: + label: '' + granularity: second + header: { } + footer: { } + empty: { } + relationships: { } + arguments: { } + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - request_format + - url.query_args + - 'user.node_grants:view' + - user.permissions + tags: { } + rest_export_1: + display_plugin: rest_export + id: rest_export_1 + display_title: 'REST export' + position: 1 + display_options: + display_extenders: { } + path: api/json/cfo-council + pager: + type: some + options: + items_per_page: 1 + offset: 0 + style: + type: serializer + options: + grouping: { } + uses_fields: false + formats: { } + row: + type: data_field + options: + field_options: + title: + alias: '' + raw_output: false + auth: + - basic_auth + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - request_format + - 'user.node_grants:view' + - user.permissions + tags: { } diff --git a/config/default/views.view.cfo_council_admin.yml b/config/default/views.view.cfo_council_admin.yml new file mode 100644 index 000000000..f48530fe0 --- /dev/null +++ b/config/default/views.view.cfo_council_admin.yml @@ -0,0 +1,873 @@ +uuid: 772dcbbe-e145-4263-aa0d-e34c7623e19f +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_council_committees + - node.type.cfo_council + - node.type.cfo_meeting + - user.role.authenticated + module: + - datetime + - node + - user +id: cfo_council_admin +label: 'CFO Council Admin' +module: views +description: '' +tag: '' +base_table: node_field_data +base_field: nid +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: role + options: + role: + authenticated: authenticated + cache: + type: tag + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + replica: false + query_comment: '' + query_tags: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: some + options: + items_per_page: 1 + offset: 0 + style: + type: default + options: + grouping: { } + row_class: '' + default_row_class: true + row: + type: fields + fields: + title: + id: title + table: node_field_data + field: title + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: true + path: '/node/{{ nid }}/edit?destination=/admin/content/cfo-council' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: false + ellipsis: false + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: h2 + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: node + entity_field: title + plugin_id: field + changed: + id: changed + table: node_field_revision + field: changed + relationship: none + group_type: group + admin_label: '' + label: Changed + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: timestamp + settings: + date_format: short + custom_date_format: '' + timezone: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: node + entity_field: changed + plugin_id: field + field_council_committees: + id: field_council_committees + table: node__field_council_committees + field: field_council_committees + relationship: none + group_type: group + admin_label: '' + label: Committees + exclude: false + alter: + alter_text: false + text: '' + make_link: true + path: '/node/{{ field_council_committees__target_id }}/edit?destination=/admin/content/cfo-council' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: h3 + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: target_id + type: entity_reference_label + settings: + link: false + group_column: target_id + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: ul + separator: ', ' + field_api_classes: false + plugin_id: field + filters: + type: + id: type + table: node_field_data + field: type + relationship: none + group_type: group + admin_label: '' + operator: in + value: + cfo_council: cfo_council + group: 1 + exposed: false + expose: + operator_id: '' + label: '' + description: '' + use_operator: false + operator: '' + operator_limit_selection: false + operator_list: { } + identifier: '' + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + reduce: false + argument: null + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: node + entity_field: type + plugin_id: bundle + sorts: + created: + id: created + table: node_field_data + field: created + relationship: none + group_type: group + admin_label: '' + order: ASC + exposed: false + expose: + label: '' + granularity: second + entity_type: node + entity_field: created + plugin_id: date + title: 'CFO Council' + header: { } + footer: { } + empty: { } + relationships: { } + arguments: { } + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - 'user.node_grants:view' + - user.roles + tags: + - 'config:field.storage.node.field_council_committees' + attachment_1: + display_plugin: attachment + id: attachment_1 + display_title: Meetings + position: 2 + display_options: + display_extenders: { } + title: 'CFO Meetings' + defaults: + title: false + style: false + row: false + fields: false + filters: false + filter_groups: false + sorts: false + relationships: false + header: false + style: + type: html_list + options: + grouping: { } + row_class: '' + default_row_class: true + type: ul + wrapper_class: item-list + class: '' + row: + type: fields + options: { } + fields: + edit_node: + id: edit_node + table: node + field: edit_node + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: edit + output_url_as_text: true + absolute: false + entity_type: node + plugin_id: entity_link_edit + title: + id: title + table: node_field_data + field: title + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: true + path: '{{ edit_node }}?destination=/admin/content/cfo-council' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: false + ellipsis: false + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: node + entity_field: title + plugin_id: field + filters: + type: + id: type + table: node_field_data + field: type + relationship: none + group_type: group + admin_label: '' + operator: in + value: + cfo_meeting: cfo_meeting + group: 1 + exposed: false + expose: + operator_id: '' + label: '' + description: '' + use_operator: false + operator: '' + operator_limit_selection: false + operator_list: { } + identifier: '' + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + reduce: false + argument: null + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: node + entity_field: type + plugin_id: bundle + filter_groups: + operator: AND + groups: + 1: AND + sorts: + field_meeting_date_value: + id: field_meeting_date_value + table: node__field_meeting_date + field: field_meeting_date_value + relationship: none + group_type: group + admin_label: '' + order: DESC + exposed: false + expose: + label: '' + granularity: second + plugin_id: datetime + relationships: { } + displays: + page_1: page_1 + attachment_position: after + pager: + type: none + options: + offset: 0 + header: + area: + id: area + table: views + field: area + relationship: none + group_type: group + admin_label: '' + empty: false + tokenize: false + content: + value: '

Meetings

' + format: rich_text + plugin_id: text + display_description: '' + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - 'user.node_grants:view' + - user.roles + tags: { } + page_1: + display_plugin: page + id: page_1 + display_title: Admin + position: 1 + display_options: + display_extenders: { } + path: admin/content/cfo-council + menu: + type: tab + title: 'CFO Council' + description: '' + expanded: false + parent: '' + weight: 10 + context: '0' + menu_name: main + display_description: '' + fields: + edit_node: + id: edit_node + table: node + field: edit_node + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: edit + output_url_as_text: true + absolute: false + entity_type: node + plugin_id: entity_link_edit + title: + id: title + table: node_field_data + field: title + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: true + path: '{{ edit_node }}?destination=/admin/content/cfo-council' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: false + ellipsis: false + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: h2 + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: node + entity_field: title + plugin_id: field + changed: + id: changed + table: node_field_revision + field: changed + relationship: none + group_type: group + admin_label: '' + label: 'Last Modified' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: timestamp + settings: + date_format: long_12h + custom_date_format: '' + timezone: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: node + entity_field: changed + plugin_id: field + field_council_committees: + id: field_council_committees + table: node__field_council_committees + field: field_council_committees + relationship: none + group_type: group + admin_label: '' + label: Committees + exclude: false + alter: + alter_text: false + text: '' + make_link: true + path: '/node/{{ field_council_committees__target_id }}/edit?destination=/admin/content/cfo-council' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: h3 + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: target_id + type: entity_reference_label + settings: + link: false + group_column: target_id + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: ul + separator: ', ' + field_api_classes: false + plugin_id: field + defaults: + fields: false + header: false + header: + area: + id: area + table: views + field: area + relationship: none + group_type: group + admin_label: '' + empty: false + tokenize: false + content: + value: "click here to add a committee\r\n  |  \r\nclick here to add a meeting" + format: rich_text + plugin_id: text + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - 'user.node_grants:view' + - user.roles + tags: + - 'config:field.storage.node.field_council_committees' From 46ae7ac1a4bc4a8b1ce6608c0ba3a4f16ff1f40b Mon Sep 17 00:00:00 2001 From: scott_earnest Date: Thu, 28 Oct 2021 08:05:09 -0600 Subject: [PATCH 08/18] FE2-34: Additional supporting config for CFO Council. --- config/default/autosave_form.settings.yml | 3 + .../filter.format.rich_text_with_media.yml | 95 +++++++++++++++++++ config/default/search_api.index.content.yml | 3 + config/default/user.role.layout_manager.yml | 3 + config/default/views.view.search.yml | 3 + .../default/workflows.workflow.editorial.yml | 10 +- 6 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 config/default/filter.format.rich_text_with_media.yml diff --git a/config/default/autosave_form.settings.yml b/config/default/autosave_form.settings.yml index 1f90346c6..f901f8e26 100644 --- a/config/default/autosave_form.settings.yml +++ b/config/default/autosave_form.settings.yml @@ -14,6 +14,9 @@ allowed_content_entity_types: bundles: annual_foia_report_data: annual_foia_report_data quarterly_foia_report_data: quarterly_foia_report_data + cfo_meeting: cfo_meeting + cfo_committee: cfo_committee + cfo_council: cfo_council paragraph: bundles: admin_app_via: admin_app_via diff --git a/config/default/filter.format.rich_text_with_media.yml b/config/default/filter.format.rich_text_with_media.yml new file mode 100644 index 000000000..4444690f7 --- /dev/null +++ b/config/default/filter.format.rich_text_with_media.yml @@ -0,0 +1,95 @@ +uuid: 5453cbca-9c2c-46c2-9e26-72c81c459386 +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.media.embedded + - core.entity_view_mode.media.full + module: + - editor + - entity_embed + - media +_core: + default_config_hash: xNqrUFmyyyy8JFxTT_Zd1CLPZ3fyIR8wqQkEfPrYj9o +name: 'Rich Text with Media' +format: rich_text_with_media +weight: 1 +filters: + filter_align: + id: filter_align + provider: filter + status: true + weight: -49 + settings: { } + filter_caption: + id: filter_caption + provider: filter + status: true + weight: -48 + settings: { } + filter_htmlcorrector: + id: filter_htmlcorrector + provider: filter + status: true + weight: -47 + settings: { } + editor_file_reference: + id: editor_file_reference + provider: editor + status: true + weight: -46 + settings: { } + entity_embed: + id: entity_embed + provider: entity_embed + status: true + weight: -41 + settings: { } + filter_html: + id: filter_html + provider: filter + status: true + weight: -50 + settings: + allowed_html: '


    1.  '
      +      filter_html_help: true
      +      filter_html_nofollow: false
      +  filter_autop:
      +    id: filter_autop
      +    provider: filter
      +    status: false
      +    weight: -44
      +    settings: {  }
      +  filter_html_escape:
      +    id: filter_html_escape
      +    provider: filter
      +    status: false
      +    weight: -45
      +    settings: {  }
      +  filter_html_image_secure:
      +    id: filter_html_image_secure
      +    provider: filter
      +    status: true
      +    weight: -42
      +    settings: {  }
      +  filter_url:
      +    id: filter_url
      +    provider: filter
      +    status: false
      +    weight: -43
      +    settings:
      +      filter_url_length: 72
      +  media_embed:
      +    id: media_embed
      +    provider: media
      +    status: true
      +    weight: -40
      +    settings:
      +      default_view_mode: default
      +      allowed_media_types:
      +        audio_file: audio_file
      +        document: document
      +      allowed_view_modes:
      +        default: default
      +        embedded: embedded
      +        full: full
      diff --git a/config/default/search_api.index.content.yml b/config/default/search_api.index.content.yml
      index 7260dbb39..e640bbf9b 100644
      --- a/config/default/search_api.index.content.yml
      +++ b/config/default/search_api.index.content.yml
      @@ -41,6 +41,9 @@ field_settings:
               'entity:node':
                 agency_component: default
                 annual_foia_report_data: default
      +          cfo_committee: default
      +          cfo_council: default
      +          cfo_meeting: default
                 landing_page: full
                 page: default
                 quarterly_foia_report_data: default
      diff --git a/config/default/user.role.layout_manager.yml b/config/default/user.role.layout_manager.yml
      index f797bba9e..07d87258a 100644
      --- a/config/default/user.role.layout_manager.yml
      +++ b/config/default/user.role.layout_manager.yml
      @@ -13,6 +13,9 @@ permissions:
         - 'administer panelizer'
         - 'administer panelizer node agency_component defaults'
         - 'administer panelizer node annual_foia_report_data defaults'
      +  - 'administer panelizer node cfo_committee defaults'
      +  - 'administer panelizer node cfo_council defaults'
      +  - 'administer panelizer node cfo_meeting defaults'
         - 'administer panelizer node landing_page defaults'
         - 'administer panelizer node page defaults'
         - 'administer panelizer node quarterly_foia_report_data defaults'
      diff --git a/config/default/views.view.search.yml b/config/default/views.view.search.yml
      index 1d75177e6..9c42c30dd 100644
      --- a/config/default/views.view.search.yml
      +++ b/config/default/views.view.search.yml
      @@ -81,6 +81,9 @@ display:
                   'entity:node':
                     agency_component: default
                     annual_foia_report_data: default
      +              cfo_committee: default
      +              cfo_council: default
      +              cfo_meeting: default
                     landing_page: teaser
                     page: teaser
                     quarterly_foia_report_data: default
      diff --git a/config/default/workflows.workflow.editorial.yml b/config/default/workflows.workflow.editorial.yml
      index 63a41ba62..b4a2e0ab2 100644
      --- a/config/default/workflows.workflow.editorial.yml
      +++ b/config/default/workflows.workflow.editorial.yml
      @@ -2,6 +2,10 @@ uuid: ae37d41d-2453-474e-8dc6-c12c179c6b02
       langcode: en
       status: true
       dependencies:
      +  config:
      +    - node.type.cfo_committee
      +    - node.type.cfo_council
      +    - node.type.cfo_meeting
         module:
           - content_moderation
       _core:
      @@ -54,5 +58,9 @@ type_settings:
             from:
               - draft
               - published
      -  entity_types: {  }
      +  entity_types:
      +    node:
      +      - cfo_committee
      +      - cfo_council
      +      - cfo_meeting
         default_moderation_state: draft
      
      From 60a5e6386331f7f6554956ed1a2c93099026a5d7 Mon Sep 17 00:00:00 2001
      From: scott_earnest 
      Date: Thu, 28 Oct 2021 17:24:37 -0600
      Subject: [PATCH 09/18] FE2-37: FOIA CFO custom module files.
      
      ---
       .../modules/custom/foia_cfo/foia_cfo.info.yml |   5 +
       .../custom/foia_cfo/foia_cfo.routing.yml      |   6 +
       .../foia_cfo/src/Controller/CFOController.php | 162 ++++++++++++++++++
       3 files changed, 173 insertions(+)
       create mode 100644 docroot/modules/custom/foia_cfo/foia_cfo.info.yml
       create mode 100644 docroot/modules/custom/foia_cfo/foia_cfo.routing.yml
       create mode 100644 docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      
      diff --git a/docroot/modules/custom/foia_cfo/foia_cfo.info.yml b/docroot/modules/custom/foia_cfo/foia_cfo.info.yml
      new file mode 100644
      index 000000000..04f3671e2
      --- /dev/null
      +++ b/docroot/modules/custom/foia_cfo/foia_cfo.info.yml
      @@ -0,0 +1,5 @@
      +name: 'FOIA CFO Council'
      +type: module
      +description: 'Support for Chief FOIA Officers Council.'
      +core_version_requirement: ^8 || ^9
      +package: 'FOIA'
      diff --git a/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml b/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml
      new file mode 100644
      index 000000000..155bab9a0
      --- /dev/null
      +++ b/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml
      @@ -0,0 +1,6 @@
      +foia_cfo.council:
      +  path: 'api/cfo/council'
      +  defaults: { _controller: '\Drupal\foia_cfo\Controller\CFOController::getCouncil' }
      +  methods:  [GET]
      +  requirements:
      +    _access: 'TRUE'
      diff --git a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      new file mode 100644
      index 000000000..93c2cf1bf
      --- /dev/null
      +++ b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      @@ -0,0 +1,162 @@
      +node_storage = \Drupal::entityTypeManager()->getStorage('node');
      +  }
      +
      +  /**
      +   * Callback for `my-api/get.json` API method.
      +   */
      +  public function getCouncil(Request $request) {
      +
      +    // Initialize the response.
      +    $response = [];
      +
      +    // Load the view for the CFO API and execute the "council" display.
      +    $view = Views::getView('cfo_council_api');
      +    $view->setDisplay('council');
      +    $view->execute();
      +
      +    // Should only be one result.
      +    foreach ($view->result as $resultRow) {
      +
      +      // Title and body of the Council node.
      +      $response['title'] = $resultRow->_entity->label();
      +      if ($resultRow->_entity->get('body')) {
      +        $response['body'] = $resultRow->_entity->get('body')->getValue()[0]['value'];
      +      }
      +
      +      /** @var \Drupal\Core\Field\EntityReferenceFieldItemList $committees */
      +      $committees = $resultRow->_entity->get('field_council_committees');
      +
      +      if (!empty($committees)) {
      +
      +        // Store committees as array elements.
      +        $response['committees'] = [];
      +
      +        foreach ($committees as $committee) {
      +          /** @var \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $committee */
      +          $nid = $committee->getValue()['target_id'];
      +          $committee_node = $this->node_storage->load($nid);
      +          $response['committees'][] = [
      +            'committee_title' => $committee_node->label(),
      +            'committee_body' => $committee_node->body->view('default')[0]['#text'],
      +          ];
      +        }
      +      }
      +
      +    }
      +
      +    // Set the display for the meetings.
      +    $view_meetings = Views::getView('cfo_council_api');
      +    $view_meetings->setDisplay('meetings');
      +    $view_meetings->execute();
      +
      +    // Store meetings as array elements.
      +    $response['meetings'] = [];
      +
      +    foreach ($view_meetings->result as $resultRow) {
      +
      +      // Initialize this meeting.
      +      $meeting = [];
      +
      +      $meeting['meeting_title'] = $resultRow->_entity->label();
      +      if (!empty($resultRow->_entity->body->view('default')[0]['#text'])) {
      +        $meeting['meeting_body'] = $resultRow->_entity->body->view('default')[0]['#text'];
      +      }
      +
      +      if (!empty($resultRow->_entity->get('field_meeting_agenda'))) {
      +        /** @var \Drupal\entity_reference_revisions\EntityReferenceRevisionsFieldItemList $agenda */
      +        $agenda = $resultRow->_entity->get('field_meeting_agenda');
      +      }
      +
      +      if ($resultRow->_entity->field_meeting_materials->count()) {
      +        $meeting['meeting_materials'] = self::linkOrFileFormatter($resultRow->_entity->field_meeting_materials);
      +      }
      +
      +      if ($resultRow->_entity->field_meeting_documents->count()) {
      +        $meeting['meeting_documents'] = self::linkOrFileFormatter($resultRow->_entity->field_meeting_documents);
      +      }
      +
      +      $response['meetings'][] = $meeting;
      +
      +    }
      +
      +    // Return the response array converted to json response.
      +    return new JsonResponse($response);
      +
      +  }
      +
      +  /**
      +   * Formats "Link or File" paragraph types.
      +   *
      +   * @param \Drupal\entity_reference_revisions\EntityReferenceRevisionsFieldItemList $field
      +   *   The field.
      +   *
      +   * @return array
      +   *   Lables and links to either the url or the file.
      +   */
      +  private function linkOrFileFormatter(EntityReferenceRevisionsFieldItemList $field) {
      +
      +    // Initialize return array.
      +    $return = [];
      +
      +    foreach ($field->referencedEntities() as $item) {
      +
      +      $return_item = [];
      +      $return_item['item_title'] = $item->get('field_link_label')->getValue()[0]['value'];
      +      if (!empty($item->get('field_link_link')->getValue()[0]['uri'])) {
      +        $return_item['item_link'] = $item->get('field_link_link')->getValue()[0]['uri'];
      +      }
      +      elseif (!empty($item->get('field_link_file')->getValue()[0]['target_id'])) {
      +        $fid = $item->get('field_link_file')->getValue()[0]['target_id'];
      +        $file = File::load($fid);
      +        $return_item['item_link'] = $file->createFileUrl();
      +      }
      +
      +      $return[] = $return_item;
      +
      +    }
      +
      +    return $return;
      +
      +  }
      +
      +}
      
      From e6cc182f8f13a0adf5ee26b6054c17d6dbd8a497 Mon Sep 17 00:00:00 2001
      From: scott_earnest 
      Date: Fri, 29 Oct 2021 14:44:44 -0600
      Subject: [PATCH 10/18] FE2-37: Caching and other updates to JSON Controller.
      
      ---
       .../foia_cfo/src/Controller/CFOController.php | 201 +++++++++++++-----
       1 file changed, 145 insertions(+), 56 deletions(-)
      
      diff --git a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      index 93c2cf1bf..c2bba713c 100644
      --- a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      +++ b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      @@ -1,18 +1,19 @@
       node_storage = \Drupal::entityTypeManager()->getStorage('node');
      +    $this->nodeStorage = \Drupal::entityTypeManager()->getStorage('node');
         }
       
         /**
      -   * Callback for `my-api/get.json` API method.
      +   * Callback for `api/cfo/council` API method.
          */
      -  public function getCouncil(Request $request) {
      +  public function getCouncil(): CacheableJsonResponse {
       
           // Initialize the response.
           $response = [];
       
      -    // Load the view for the CFO API and execute the "council" display.
      -    $view = Views::getView('cfo_council_api');
      -    $view->setDisplay('council');
      -    $view->execute();
      +    // Array to hold cache dependent node id's.
      +    $cache_nids = [];
      +
      +    // Load the council node.  Load the oldest one, there should be just one.
      +    $council_query = \Drupal::entityQuery('node')
      +      ->condition('type', 'cfo_council')
      +      ->condition('status', 1)
      +      ->sort('created')
      +      ->range(0, 1)
      +      ->accessCheck(FALSE)
      +      ->execute();
       
           // Should only be one result.
      -    foreach ($view->result as $resultRow) {
      +    if (!empty($council_query)) {
      +
      +      // Grab the node id of the council node.
      +      $council_nid = array_shift($council_query);
      +
      +      // Add the node id of the council page.
      +      $cache_nids[] = 'node:' . $council_nid;
      +
      +      // Load the council node.
      +      $council_node = $this->nodeStorage->load($council_nid);
       
             // Title and body of the Council node.
      -      $response['title'] = $resultRow->_entity->label();
      -      if ($resultRow->_entity->get('body')) {
      -        $response['body'] = $resultRow->_entity->get('body')->getValue()[0]['value'];
      +      $response['title'] = $council_node->label();
      +
      +      if ($council_node->get('body')) {
      +        $body = self::absolutePathFormatter($council_node->get('body')->getValue()[0]['value']);
      +        $response['body'] = $body;
             }
       
             /** @var \Drupal\Core\Field\EntityReferenceFieldItemList $committees */
      -      $committees = $resultRow->_entity->get('field_council_committees');
      +      $committees = $council_node->get('field_council_committees');
       
             if (!empty($committees)) {
       
               // Store committees as array elements.
               $response['committees'] = [];
       
      +        // Loop through the committees and add title and body to the feed.
               foreach ($committees as $committee) {
                 /** @var \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $committee */
                 $nid = $committee->getValue()['target_id'];
      -          $committee_node = $this->node_storage->load($nid);
      +          // Add the node id of the committee page.
      +          $cache_nids[] = 'node:' . $nid;
      +          $committee_node = $this->nodeStorage->load($nid);
      +          $committee_body = self::absolutePathFormatter($committee_node->body->getValue()[0]['value']);
                 $response['committees'][] = [
                   'committee_title' => $committee_node->label(),
      -            'committee_body' => $committee_node->body->view('default')[0]['#text'],
      +            'committee_body' => $committee_body,
                 ];
               }
             }
       
           }
       
      -    // Set the display for the meetings.
      -    $view_meetings = Views::getView('cfo_council_api');
      -    $view_meetings->setDisplay('meetings');
      -    $view_meetings->execute();
      +    // Query for all CFO meetings.
      +    $meetings_query = \Drupal::entityQuery('node')
      +      ->condition('type', 'cfo_meeting')
      +      ->condition('status', 1)
      +      ->sort('field_meeting_date', 'DESC')
      +      ->accessCheck(FALSE)
      +      ->execute();
       
      -    // Store meetings as array elements.
      -    $response['meetings'] = [];
      +    if (!empty($meetings_query)) {
       
      -    foreach ($view_meetings->result as $resultRow) {
      +      // Store meetings as array elements.
      +      $response['meetings'] = [];
       
      -      // Initialize this meeting.
      -      $meeting = [];
      +      // Loop through all meetings.
      +      foreach ($meetings_query as $meeting_nid) {
       
      -      $meeting['meeting_title'] = $resultRow->_entity->label();
      -      if (!empty($resultRow->_entity->body->view('default')[0]['#text'])) {
      -        $meeting['meeting_body'] = $resultRow->_entity->body->view('default')[0]['#text'];
      -      }
      +        // Initialize this meeting.
      +        $meeting = [];
       
      -      if (!empty($resultRow->_entity->get('field_meeting_agenda'))) {
      -        /** @var \Drupal\entity_reference_revisions\EntityReferenceRevisionsFieldItemList $agenda */
      -        $agenda = $resultRow->_entity->get('field_meeting_agenda');
      -      }
      +        // Add the node id of the meeting.
      +        $cache_nids[] = 'node:' . $meeting_nid;
       
      -      if ($resultRow->_entity->field_meeting_materials->count()) {
      -        $meeting['meeting_materials'] = self::linkOrFileFormatter($resultRow->_entity->field_meeting_materials);
      -      }
      +        // Load the meeting node.
      +        $meeting_node = $this->nodeStorage->load($meeting_nid);
       
      -      if ($resultRow->_entity->field_meeting_documents->count()) {
      -        $meeting['meeting_documents'] = self::linkOrFileFormatter($resultRow->_entity->field_meeting_documents);
      -      }
      +        // Add title and body for the meeting.
      +        $meeting['meeting_title'] = $meeting_node->label();
      +        if (!empty($meeting_node->body->getValue()[0]['value'])) {
      +          $meeting_body = self::absolutePathFormatter($meeting_node->body->getValue()[0]['value']);
      +          $meeting['meeting_body'] = $meeting_body;
      +        }
      +
      +        // Add link to the Agenda if there is one.
      +        if (!empty($meeting_node->get('field_meeting_agenda'))) {
      +          /** @var \Drupal\entity_reference_revisions\EntityReferenceRevisionsFieldItemList $agenda */
      +          $agenda = $meeting_node->get('field_meeting_agenda');
      +        }
      +
      +        // Meeting materials.
      +        if ($meeting_node->field_meeting_materials->count()) {
      +          $meeting['meeting_materials'] = self::linkOrFileFormatter($meeting_node->field_meeting_materials);
      +        }
       
      -      $response['meetings'][] = $meeting;
      +        // Meeting documents.
      +        if ($meeting_node->field_meeting_documents->count()) {
      +          $meeting['meeting_documents'] = self::linkOrFileFormatter($meeting_node->field_meeting_documents);
      +        }
      +
      +        // Add this meeting to the return meeting array.
      +        $response['meetings'][] = $meeting;
      +
      +      }
       
           }
       
      -    // Return the response array converted to json response.
      -    return new JsonResponse($response);
      +    $cacheMeta = (new CacheableMetadata())
      +      ->setCacheTags($cache_nids)
      +      ->setCacheMaxAge(Cache::PERMANENT);
      +
      +    // Set the JSON response to the agents array.
      +    $json_response = new CacheableJsonResponse($response);
      +
      +    // Add in the cache dependencies.
      +    $json_response->addCacheableDependency($cacheMeta);
      +
      +    // Return JSON Response.
      +    return $json_response;
      +
      +  }
      +
      +  /**
      +   * Adds the absolute path to src and href paramater values.
      +   *
      +   * @param string $input
      +   *   Input string (html).
      +   *
      +   * @return string
      +   *   Input string with absolute paths to src and href.
      +   */
      +  private function absolutePathFormatter(string $input): string {
      +
      +    // Grab the "base href" with http.
      +    $host = \Drupal::request()->getSchemeAndHttpHost();
      +
      +    // Replacements array - look for href and src with relative paths.
      +    $replacements = [
      +      'href="/' => 'href="' . $host . '/',
      +      'src="/' => 'src="' . $host . '/',
      +    ];
      +
      +    // Add absolute references to relative paths.
      +    return str_replace(array_keys($replacements), array_values($replacements), $input);
       
         }
       
      @@ -131,30 +204,46 @@ public function getCouncil(Request $request) {
          *   The field.
          *
          * @return array
      -   *   Lables and links to either the url or the file.
      +   *   Labels and links to either the url or the file.
          */
      -  private function linkOrFileFormatter(EntityReferenceRevisionsFieldItemList $field) {
      +  private function linkOrFileFormatter(EntityReferenceRevisionsFieldItemList $field): array {
       
           // Initialize return array.
           $return = [];
       
      +    // Loop over the referenced paragraph entities.
           foreach ($field->referencedEntities() as $item) {
       
      +      // Initialize this item.
             $return_item = [];
      -      $return_item['item_title'] = $item->get('field_link_label')->getValue()[0]['value'];
      +
      +      // Set the item label.
      +      $return_item['item_title'] = $item->get('field_link_label')
      +        ->getValue()[0]['value'];
      +
      +      // Set the item link - this will be a URL or File.
             if (!empty($item->get('field_link_link')->getValue()[0]['uri'])) {
      -        $return_item['item_link'] = $item->get('field_link_link')->getValue()[0]['uri'];
      +        $link = $item->get('field_link_link')
      +          ->first()
      +          ->getUrl()
      +          ->setAbsolute(TRUE)
      +          ->toString(TRUE)
      +          ->getGeneratedUrl();
      +        $return_item['item_link'] = $link;
             }
      -      elseif (!empty($item->get('field_link_file')->getValue()[0]['target_id'])) {
      +      elseif (!empty($item->get('field_link_file')
      +        ->getValue()[0]['target_id'])) {
               $fid = $item->get('field_link_file')->getValue()[0]['target_id'];
               $file = File::load($fid);
      -        $return_item['item_link'] = $file->createFileUrl();
      +        $return_item['item_link'] = $file->createFileUrl(FALSE);
             }
       
      +      // Add this item to the return array.
             $return[] = $return_item;
       
           }
       
      +    // Returns array of items with labels and links.
           return $return;
       
         }
      
      From 6f5f7dfdfc51ffee8c010739fd15fc42357ce8b1 Mon Sep 17 00:00:00 2001
      From: scott_earnest 
      Date: Fri, 29 Oct 2021 15:16:43 -0600
      Subject: [PATCH 11/18] FE2-37: Config for cfo view and display.
      
      ---
       ...iew_display.node.cfo_committee.default.yml |  21 +-
       config/default/core.extension.yml             |   1 +
       config/default/views.view.cfo_council.yml     | 238 ------------------
       .../default/views.view.cfo_council_admin.yml  |  75 +++++-
       4 files changed, 82 insertions(+), 253 deletions(-)
       delete mode 100644 config/default/views.view.cfo_council.yml
      
      diff --git a/config/default/core.entity_view_display.node.cfo_committee.default.yml b/config/default/core.entity_view_display.node.cfo_committee.default.yml
      index f708c84ff..604095332 100644
      --- a/config/default/core.entity_view_display.node.cfo_committee.default.yml
      +++ b/config/default/core.entity_view_display.node.cfo_committee.default.yml
      @@ -6,8 +6,15 @@ dependencies:
           - field.field.node.cfo_committee.body
           - node.type.cfo_committee
         module:
      +    - panelizer
           - text
           - user
      +third_party_settings:
      +  panelizer:
      +    enable: false
      +    custom: false
      +    allow: false
      +    default: default
       id: node.cfo_committee.default
       targetEntityType: node
       bundle: cfo_committee
      @@ -16,19 +23,11 @@ content:
         body:
           label: hidden
           type: text_default
      -    weight: 101
      -    settings: {  }
      -    third_party_settings: {  }
      -    region: content
      -  content_moderation_control:
      -    weight: -20
      -    settings: {  }
      -    third_party_settings: {  }
      -    region: content
      -  links:
      -    weight: 100
      +    weight: 0
           settings: {  }
           third_party_settings: {  }
           region: content
       hidden:
      +  content_moderation_control: true
      +  links: true
         search_api_excerpt: true
      diff --git a/config/default/core.extension.yml b/config/default/core.extension.yml
      index e81299f8e..209608e86 100644
      --- a/config/default/core.extension.yml
      +++ b/config/default/core.extension.yml
      @@ -43,6 +43,7 @@ module:
         foia_annual_data_report: 0
         foia_api: 0
         foia_autocalc: 0
      +  foia_cfo: 0
         foia_export_xml: 0
         foia_file: 0
         foia_personnel: 0
      diff --git a/config/default/views.view.cfo_council.yml b/config/default/views.view.cfo_council.yml
      deleted file mode 100644
      index ba2ba174b..000000000
      --- a/config/default/views.view.cfo_council.yml
      +++ /dev/null
      @@ -1,238 +0,0 @@
      -uuid: 4d1d2559-2df9-437b-9c88-1f07fc2ed888
      -langcode: en
      -status: true
      -dependencies:
      -  config:
      -    - node.type.cfo_council
      -  module:
      -    - node
      -    - rest
      -    - serialization
      -    - user
      -id: cfo_council
      -label: 'CFO Council'
      -module: views
      -description: ''
      -tag: ''
      -base_table: node_field_data
      -base_field: nid
      -display:
      -  default:
      -    display_plugin: default
      -    id: default
      -    display_title: Master
      -    position: 0
      -    display_options:
      -      access:
      -        type: perm
      -        options:
      -          perm: 'access content'
      -      cache:
      -        type: tag
      -        options: {  }
      -      query:
      -        type: views_query
      -        options:
      -          disable_sql_rewrite: false
      -          distinct: false
      -          replica: false
      -          query_comment: ''
      -          query_tags: {  }
      -      exposed_form:
      -        type: basic
      -        options:
      -          submit_button: Apply
      -          reset_button: false
      -          reset_button_label: Reset
      -          exposed_sorts_label: 'Sort by'
      -          expose_sort_order: true
      -          sort_asc_label: Asc
      -          sort_desc_label: Desc
      -      pager:
      -        type: mini
      -        options:
      -          items_per_page: 10
      -          offset: 0
      -          id: 0
      -          total_pages: null
      -          expose:
      -            items_per_page: false
      -            items_per_page_label: 'Items per page'
      -            items_per_page_options: '5, 10, 25, 50'
      -            items_per_page_options_all: false
      -            items_per_page_options_all_label: '- All -'
      -            offset: false
      -            offset_label: Offset
      -          tags:
      -            previous: ‹‹
      -            next: ››
      -      style:
      -        type: serializer
      -      row:
      -        type: fields
      -        options:
      -          inline: {  }
      -          separator: ''
      -          hide_empty: false
      -          default_field_elements: true
      -      fields:
      -        title:
      -          id: title
      -          table: node_field_data
      -          field: title
      -          relationship: none
      -          group_type: group
      -          admin_label: ''
      -          label: ''
      -          exclude: false
      -          alter:
      -            alter_text: false
      -            text: ''
      -            make_link: false
      -            path: ''
      -            absolute: false
      -            external: false
      -            replace_spaces: false
      -            path_case: none
      -            trim_whitespace: false
      -            alt: ''
      -            rel: ''
      -            link_class: ''
      -            prefix: ''
      -            suffix: ''
      -            target: ''
      -            nl2br: false
      -            max_length: 0
      -            word_boundary: false
      -            ellipsis: false
      -            more_link: false
      -            more_link_text: ''
      -            more_link_path: ''
      -            strip_tags: false
      -            trim: false
      -            preserve_tags: ''
      -            html: false
      -          element_type: ''
      -          element_class: ''
      -          element_label_type: ''
      -          element_label_class: ''
      -          element_label_colon: false
      -          element_wrapper_type: ''
      -          element_wrapper_class: ''
      -          element_default_classes: true
      -          empty: ''
      -          hide_empty: false
      -          empty_zero: false
      -          hide_alter_empty: true
      -          click_sort_column: value
      -          type: string
      -          settings:
      -            link_to_entity: false
      -          group_column: value
      -          group_columns: {  }
      -          group_rows: true
      -          delta_limit: 0
      -          delta_offset: 0
      -          delta_reversed: false
      -          delta_first_last: false
      -          multi_type: separator
      -          separator: ', '
      -          field_api_classes: false
      -          entity_type: node
      -          entity_field: title
      -          plugin_id: field
      -      filters:
      -        status:
      -          value: '1'
      -          table: node_field_data
      -          field: status
      -          plugin_id: boolean
      -          entity_type: node
      -          entity_field: status
      -          id: status
      -          expose:
      -            operator: ''
      -            operator_limit_selection: false
      -            operator_list: {  }
      -          group: 1
      -        type:
      -          id: type
      -          table: node_field_data
      -          field: type
      -          value:
      -            cfo_council: cfo_council
      -          entity_type: node
      -          entity_field: type
      -          plugin_id: bundle
      -          expose:
      -            operator_limit_selection: false
      -            operator_list: {  }
      -      sorts:
      -        created:
      -          id: created
      -          table: node_field_data
      -          field: created
      -          order: ASC
      -          entity_type: node
      -          entity_field: created
      -          plugin_id: date
      -          relationship: none
      -          group_type: group
      -          admin_label: ''
      -          exposed: false
      -          expose:
      -            label: ''
      -          granularity: second
      -      header: {  }
      -      footer: {  }
      -      empty: {  }
      -      relationships: {  }
      -      arguments: {  }
      -      display_extenders: {  }
      -    cache_metadata:
      -      max-age: -1
      -      contexts:
      -        - 'languages:language_content'
      -        - 'languages:language_interface'
      -        - request_format
      -        - url.query_args
      -        - 'user.node_grants:view'
      -        - user.permissions
      -      tags: {  }
      -  rest_export_1:
      -    display_plugin: rest_export
      -    id: rest_export_1
      -    display_title: 'REST export'
      -    position: 1
      -    display_options:
      -      display_extenders: {  }
      -      path: api/json/cfo-council
      -      pager:
      -        type: some
      -        options:
      -          items_per_page: 1
      -          offset: 0
      -      style:
      -        type: serializer
      -        options:
      -          grouping: {  }
      -          uses_fields: false
      -          formats: {  }
      -      row:
      -        type: data_field
      -        options:
      -          field_options:
      -            title:
      -              alias: ''
      -              raw_output: false
      -      auth:
      -        - basic_auth
      -    cache_metadata:
      -      max-age: -1
      -      contexts:
      -        - 'languages:language_content'
      -        - 'languages:language_interface'
      -        - request_format
      -        - 'user.node_grants:view'
      -        - user.permissions
      -      tags: {  }
      diff --git a/config/default/views.view.cfo_council_admin.yml b/config/default/views.view.cfo_council_admin.yml
      index f48530fe0..c99ad6a00 100644
      --- a/config/default/views.view.cfo_council_admin.yml
      +++ b/config/default/views.view.cfo_council_admin.yml
      @@ -14,7 +14,7 @@ dependencies:
       id: cfo_council_admin
       label: 'CFO Council Admin'
       module: views
      -description: ''
      +description: 'CFO Council administrative dashboard.'
       tag: ''
       base_table: node_field_data
       base_field: nid
      @@ -420,6 +420,73 @@ display:
                 absolute: false
                 entity_type: node
                 plugin_id: entity_link_edit
      +        status:
      +          id: status
      +          table: node_field_data
      +          field: status
      +          relationship: none
      +          group_type: group
      +          admin_label: ''
      +          label: ''
      +          exclude: true
      +          alter:
      +            alter_text: false
      +            text: ''
      +            make_link: false
      +            path: ''
      +            absolute: false
      +            external: false
      +            replace_spaces: false
      +            path_case: none
      +            trim_whitespace: false
      +            alt: ''
      +            rel: ''
      +            link_class: ''
      +            prefix: ''
      +            suffix: ''
      +            target: ''
      +            nl2br: false
      +            max_length: 0
      +            word_boundary: true
      +            ellipsis: true
      +            more_link: false
      +            more_link_text: ''
      +            more_link_path: ''
      +            strip_tags: false
      +            trim: false
      +            preserve_tags: ''
      +            html: false
      +          element_type: ''
      +          element_class: ''
      +          element_label_type: ''
      +          element_label_class: ''
      +          element_label_colon: false
      +          element_wrapper_type: ''
      +          element_wrapper_class: ''
      +          element_default_classes: true
      +          empty: ''
      +          hide_empty: false
      +          empty_zero: false
      +          hide_alter_empty: true
      +          click_sort_column: value
      +          type: boolean
      +          settings:
      +            format: custom
      +            format_custom_true: ''
      +            format_custom_false: (UNPUBLISHED)
      +          group_column: value
      +          group_columns: {  }
      +          group_rows: true
      +          delta_limit: 0
      +          delta_offset: 0
      +          delta_reversed: false
      +          delta_first_last: false
      +          multi_type: separator
      +          separator: ', '
      +          field_api_classes: false
      +          entity_type: node
      +          entity_field: status
      +          plugin_id: field
               title:
                 id: title
                 table: node_field_data
      @@ -430,8 +497,8 @@ display:
                 label: ''
                 exclude: false
                 alter:
      -            alter_text: false
      -            text: ''
      +            alter_text: true
      +            text: '{{ title }} {{ status }}'
                   make_link: true
                   path: '{{ edit_node }}?destination=/admin/content/cfo-council'
                   absolute: false
      @@ -859,7 +926,7 @@ display:
                 empty: false
                 tokenize: false
                 content:
      -            value: "click here to add a committee\r\n  |  \r\nclick here to add a meeting"
      +            value: "click here to add a committee\r\n  |  \r\nclick here to add a meeting\r\n  |  \r\ncouncil json"
                   format: rich_text
                 plugin_id: text
           cache_metadata:
      
      From 35b22f879e6068748339400bc8529505ee1e7ab4 Mon Sep 17 00:00:00 2001
      From: scott_earnest 
      Date: Mon, 1 Nov 2021 10:19:48 -0600
      Subject: [PATCH 12/18] FE2-37: Updates to JSON caching.
      
      ---
       .../foia_cfo/src/Controller/CFOController.php | 81 ++++++++++++-------
       1 file changed, 53 insertions(+), 28 deletions(-)
      
      diff --git a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      index 0b6c7098b..5e8a688ed 100644
      --- a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      +++ b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      @@ -11,6 +11,8 @@
       use Drupal\Core\Cache\CacheableJsonResponse;
       use Drupal\Core\Cache\CacheableMetadata;
       use Drupal\Core\Controller\ControllerBase;
      +use Drupal\Core\Render\BubbleableMetadata;
      +use Drupal\Core\Render\RenderContext;
       use Drupal\file\Entity\File;
       use Drupal\entity_reference_revisions\EntityReferenceRevisionsFieldItemList;
       
      @@ -47,20 +49,22 @@ public function getCouncil(): CacheableJsonResponse {
           // Array to hold cache dependent node id's.
           $cache_nids = [];
       
      -    // Load the council node.  Load the oldest one, there should be just one.
      -    $council_query = \Drupal::entityQuery('node')
      -      ->condition('type', 'cfo_council')
      -      ->condition('status', 1)
      -      ->sort('created')
      -      ->range(0, 1)
      -      ->accessCheck(FALSE)
      -      ->execute();
      +    // Wrap Query in render context.
      +    $context = new RenderContext();
      +    $council_nids = \Drupal::service('renderer')->executeInRenderContext($context, function () {
      +      $council_query = \Drupal::entityQuery('node')
      +        ->condition('type', 'cfo_council')
      +        ->condition('status', 1)
      +        ->sort('created')
      +        ->range(0, 1);
      +      return $council_query->execute();
      +    });
       
           // Should only be one result.
      -    if (!empty($council_query)) {
      +    if (!empty($council_nids)) {
       
             // Grab the node id of the council node.
      -      $council_nid = array_shift($council_query);
      +      $council_nid = array_shift($council_nids);
       
             // Add the node id of the council page.
             $cache_nids[] = 'node:' . $council_nid;
      @@ -91,31 +95,35 @@ public function getCouncil(): CacheableJsonResponse {
                 // Add the node id of the committee page.
                 $cache_nids[] = 'node:' . $nid;
                 $committee_node = $this->nodeStorage->load($nid);
      -          $committee_body = self::absolutePathFormatter($committee_node->body->getValue()[0]['value']);
      -          $response['committees'][] = [
      -            'committee_title' => $committee_node->label(),
      -            'committee_body' => $committee_body,
      -          ];
      +          $committee = ['committee_title' => $committee_node->label()];
      +          if (!empty($committee_node->body->getValue())) {
      +            $committee_body = self::absolutePathFormatter($committee_node->body->getValue()[0]['value']);
      +            $committee['committee_body'] = $committee_body;
      +          }
      +          $response['committees'][] = $committee;
               }
             }
       
           }
       
      -    // Query for all CFO meetings.
      -    $meetings_query = \Drupal::entityQuery('node')
      -      ->condition('type', 'cfo_meeting')
      -      ->condition('status', 1)
      -      ->sort('field_meeting_date', 'DESC')
      -      ->accessCheck(FALSE)
      -      ->execute();
      +    // Wrap Query in render context.
      +    $context_meetings = new RenderContext();
      +    $meetings_nids = \Drupal::service('renderer')->executeInRenderContext($context_meetings, function () {
      +      // Query for all CFO meetings.
      +      $meetings_query = \Drupal::entityQuery('node')
      +        ->condition('type', 'cfo_meeting')
      +        ->condition('status', 1)
      +        ->sort('field_meeting_date', 'DESC');
      +      return $meetings_query->execute();
      +    });
       
      -    if (!empty($meetings_query)) {
      +    if (!empty($meetings_nids)) {
       
             // Store meetings as array elements.
             $response['meetings'] = [];
       
             // Loop through all meetings.
      -      foreach ($meetings_query as $meeting_nid) {
      +      foreach ($meetings_nids as $meeting_nid) {
       
               // Initialize this meeting.
               $meeting = [];
      @@ -156,6 +164,7 @@ public function getCouncil(): CacheableJsonResponse {
       
           }
       
      +    // Set up the Cache Meta.
           $cacheMeta = (new CacheableMetadata())
             ->setCacheTags($cache_nids)
             ->setCacheMaxAge(Cache::PERMANENT);
      @@ -166,13 +175,25 @@ public function getCouncil(): CacheableJsonResponse {
           // Add in the cache dependencies.
           $json_response->addCacheableDependency($cacheMeta);
       
      +    // Handle any bubbled cacheability metadata.
      +    if (!$context->isEmpty()) {
      +      $bubbleable_metadata = $context->pop();
      +      BubbleableMetadata::createFromObject($council_nids)
      +        ->merge($bubbleable_metadata);
      +    }
      +    if (!$context_meetings->isEmpty()) {
      +      $bubbleable_metadata = $context_meetings->pop();
      +      BubbleableMetadata::createFromObject($meetings_nids)
      +        ->merge($bubbleable_metadata);
      +    }
      +
           // Return JSON Response.
           return $json_response;
       
         }
       
         /**
      -   * Adds the absolute path to src and href paramater values.
      +   * Adds the absolute path to src and href parameter values.
          *
          * @param string $input
          *   Input string (html).
      @@ -217,8 +238,10 @@ private function linkOrFileFormatter(EntityReferenceRevisionsFieldItemList $fiel
             $return_item = [];
       
             // Set the item label.
      -      $return_item['item_title'] = $item->get('field_link_label')
      -        ->getValue()[0]['value'];
      +      if (!empty($item->get('field_link_label')->getValue())) {
      +        $return_item['item_title'] = $item->get('field_link_label')
      +          ->getValue()[0]['value'];
      +      }
       
             // Set the item link - this will be a URL or File.
             if (!empty($item->get('field_link_link')->getValue()[0]['uri'])) {
      @@ -238,7 +261,9 @@ private function linkOrFileFormatter(EntityReferenceRevisionsFieldItemList $fiel
             }
       
             // Add this item to the return array.
      -      $return[] = $return_item;
      +      if (!empty($return_item)) {
      +        $return[] = $return_item;
      +      }
       
           }
       
      
      From b5e19c9ca890d8f5c70d3293ba45f4546eb76f82 Mon Sep 17 00:00:00 2001
      From: scott_earnest 
      Date: Mon, 1 Nov 2021 11:54:15 -0600
      Subject: [PATCH 13/18] FE2-37: List of committees JSON.
      
      ---
       .../custom/foia_cfo/foia_cfo.routing.yml      |  6 ++
       .../foia_cfo/src/Controller/CFOController.php | 91 +++++++++++++++++--
       2 files changed, 91 insertions(+), 6 deletions(-)
      
      diff --git a/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml b/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml
      index 155bab9a0..54ca3ac38 100644
      --- a/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml
      +++ b/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml
      @@ -4,3 +4,9 @@ foia_cfo.council:
         methods:  [GET]
         requirements:
           _access: 'TRUE'
      +foia_cfo.committees:
      +  path: 'api/cfo/committees'
      +  defaults: { _controller: '\Drupal\foia_cfo\Controller\CFOController::getCommittees' }
      +  methods:  [GET]
      +  requirements:
      +    _access: 'TRUE'
      diff --git a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      index 5e8a688ed..050b0cfac 100644
      --- a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      +++ b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      @@ -39,7 +39,13 @@ public function __construct() {
         }
       
         /**
      -   * Callback for `api/cfo/council` API method.
      +   * Callback for `api/cfo/council` API method returns JSON Response.
      +   *
      +   * Includes all elements for the council page including attached committees
      +   * and details of all CFO Meetings.
      +   *
      +   * @return \Drupal\Core\Cache\CacheableJsonResponse
      +   *   JSON for the CFO council page.
          */
         public function getCouncil(): CacheableJsonResponse {
       
      @@ -76,7 +82,7 @@ public function getCouncil(): CacheableJsonResponse {
             $response['title'] = $council_node->label();
       
             if ($council_node->get('body')) {
      -        $body = self::absolutePathFormatter($council_node->get('body')->getValue()[0]['value']);
      +        $body = static::absolutePathFormatter($council_node->get('body')->getValue()[0]['value']);
               $response['body'] = $body;
             }
       
      @@ -97,7 +103,7 @@ public function getCouncil(): CacheableJsonResponse {
                 $committee_node = $this->nodeStorage->load($nid);
                 $committee = ['committee_title' => $committee_node->label()];
                 if (!empty($committee_node->body->getValue())) {
      -            $committee_body = self::absolutePathFormatter($committee_node->body->getValue()[0]['value']);
      +            $committee_body = static::absolutePathFormatter($committee_node->body->getValue()[0]['value']);
                   $committee['committee_body'] = $committee_body;
                 }
                 $response['committees'][] = $committee;
      @@ -137,7 +143,7 @@ public function getCouncil(): CacheableJsonResponse {
               // Add title and body for the meeting.
               $meeting['meeting_title'] = $meeting_node->label();
               if (!empty($meeting_node->body->getValue()[0]['value'])) {
      -          $meeting_body = self::absolutePathFormatter($meeting_node->body->getValue()[0]['value']);
      +          $meeting_body = static::absolutePathFormatter($meeting_node->body->getValue()[0]['value']);
                 $meeting['meeting_body'] = $meeting_body;
               }
       
      @@ -149,12 +155,12 @@ public function getCouncil(): CacheableJsonResponse {
       
               // Meeting materials.
               if ($meeting_node->field_meeting_materials->count()) {
      -          $meeting['meeting_materials'] = self::linkOrFileFormatter($meeting_node->field_meeting_materials);
      +          $meeting['meeting_materials'] = static::linkOrFileFormatter($meeting_node->field_meeting_materials);
               }
       
               // Meeting documents.
               if ($meeting_node->field_meeting_documents->count()) {
      -          $meeting['meeting_documents'] = self::linkOrFileFormatter($meeting_node->field_meeting_documents);
      +          $meeting['meeting_documents'] = static::linkOrFileFormatter($meeting_node->field_meeting_documents);
               }
       
               // Add this meeting to the return meeting array.
      @@ -192,6 +198,79 @@ public function getCouncil(): CacheableJsonResponse {
       
         }
       
      +  /**
      +   * Callback for `api/cfo/committees` API method returns JSON Response.
      +   *
      +   * Returns array of node ids, committee name, and a few other details.
      +   * The node id's can then be passed to the committee detail callback
      +   * for full details of the committee.
      +   *
      +   * @return \Drupal\Core\Cache\CacheableJsonResponse
      +   *   JSON for the committees list.
      +   */
      +  public function getCommittees(): CacheableJsonResponse {
      +
      +    // Initialize the response.
      +    $response = [];
      +
      +    // Array to hold cache dependent node id's.
      +    $cache_nids = [];
      +
      +    // Wrap Query in render context.
      +    $context = new RenderContext();
      +    $committee_nids = \Drupal::service('renderer')->executeInRenderContext($context, function () {
      +      $committee_query = \Drupal::entityQuery('node')
      +        ->condition('type', 'cfo_committee')
      +        ->condition('status', 1)
      +        ->sort('created');
      +      return $committee_query->execute();
      +    });
      +
      +    if (!empty($committee_nids)) {
      +
      +      // Loop through all committees.
      +      foreach ($committee_nids as $committee_nid) {
      +
      +        // Add the node id of the committee.
      +        $cache_nids[] = 'node:' . $committee_nid;
      +
      +        // Load the committee node.
      +        if ($committee_node = $this->nodeStorage->load($committee_nid)) {
      +          $committee = [
      +            'committee_nid' => $committee_nid,
      +            'committee_title' => $committee_node->label(),
      +            'committee_updated' => $committee_node->changed->value,
      +          ];
      +          $response[] = $committee;
      +        }
      +
      +      }
      +
      +    }
      +
      +    // Set up the Cache Meta.
      +    $cacheMeta = (new CacheableMetadata())
      +      ->setCacheTags($cache_nids)
      +      ->setCacheMaxAge(Cache::PERMANENT);
      +
      +    // Set the JSON response to the agents array.
      +    $json_response = new CacheableJsonResponse($response);
      +
      +    // Add in the cache dependencies.
      +    $json_response->addCacheableDependency($cacheMeta);
      +
      +    // Handle any bubbled cacheability metadata.
      +    if (!$context->isEmpty()) {
      +      $bubbleable_metadata = $context->pop();
      +      BubbleableMetadata::createFromObject($committee_nids)
      +        ->merge($bubbleable_metadata);
      +    }
      +
      +    // Return JSON Response.
      +    return $json_response;
      +
      +  }
      +
         /**
          * Adds the absolute path to src and href parameter values.
          *
      
      From ace9b157cf2bfd79a310188ecc33c07afd54528b Mon Sep 17 00:00:00 2001
      From: scott_earnest 
      Date: Mon, 1 Nov 2021 13:32:50 -0600
      Subject: [PATCH 14/18] FE2-37: Committee detail JSON.
      
      ---
       .../custom/foia_cfo/foia_cfo.routing.yml      | 10 ++++
       .../foia_cfo/src/Controller/CFOController.php | 59 ++++++++++++++++++-
       2 files changed, 67 insertions(+), 2 deletions(-)
      
      diff --git a/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml b/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml
      index 54ca3ac38..e17b22f34 100644
      --- a/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml
      +++ b/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml
      @@ -10,3 +10,13 @@ foia_cfo.committees:
         methods:  [GET]
         requirements:
           _access: 'TRUE'
      +foia_cfo.committee:
      +  path: 'api/cfo/committee/{committee}'
      +  defaults: { _controller: '\Drupal\foia_cfo\Controller\CFOController::getCommittee' }
      +  methods:  [GET]
      +  requirements:
      +    _access: 'TRUE'
      +  options:
      +    parameters:
      +      committee:
      +        type: entity:node
      diff --git a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      index 050b0cfac..d431c3c79 100644
      --- a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      +++ b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      @@ -15,6 +15,7 @@
       use Drupal\Core\Render\RenderContext;
       use Drupal\file\Entity\File;
       use Drupal\entity_reference_revisions\EntityReferenceRevisionsFieldItemList;
      +use Drupal\node\Entity\Node;
       
       /**
        * Controller routines for foia_cfo routes.
      @@ -175,7 +176,7 @@ public function getCouncil(): CacheableJsonResponse {
             ->setCacheTags($cache_nids)
             ->setCacheMaxAge(Cache::PERMANENT);
       
      -    // Set the JSON response to the agents array.
      +    // Set the JSON response from our response of council data.
           $json_response = new CacheableJsonResponse($response);
       
           // Add in the cache dependencies.
      @@ -253,7 +254,7 @@ public function getCommittees(): CacheableJsonResponse {
             ->setCacheTags($cache_nids)
             ->setCacheMaxAge(Cache::PERMANENT);
       
      -    // Set the JSON response to the agents array.
      +    // Set the JSON response to the response of committees.
           $json_response = new CacheableJsonResponse($response);
       
           // Add in the cache dependencies.
      @@ -271,6 +272,60 @@ public function getCommittees(): CacheableJsonResponse {
       
         }
       
      +  /**
      +   * Callback for `api/cfo/committee/{node}` API method returns JSON Response.
      +   *
      +   * Returns full details for a committee based on node id passed.
      +   *
      +   * @param \Drupal\node\Entity\Node $committee
      +   *   Node object of the committee passed as argument through routing.
      +   *
      +   * @return \Drupal\Core\Cache\CacheableJsonResponse|false
      +   *   Returns json object or false if the node did not load.
      +   */
      +  public function getCommittee(Node $committee) {
      +
      +    if (!empty($committee) && $committee->isPublished()) {
      +
      +      // Array to hold cache dependent node id's (just this one).
      +      $cache_nids = ['node:' . $committee->id()];
      +
      +      // Initialize the response with basic info.
      +      $response = [
      +        'committee_title' => $committee->label(),
      +        'committee_updated' => $committee->changed->value,
      +      ];
      +
      +      // Add body HTML if any - use absolute links.
      +      if ($committee->hasField('body') && !empty($committee->get('body'))) {
      +        $response['committee_body'] = static::absolutePathFormatter($committee->get('body')->getValue()[0]['value']);
      +      }
      +
      +      // Set up the Cache Meta.
      +      $cacheMeta = (new CacheableMetadata())
      +        ->setCacheTags($cache_nids)
      +        ->setCacheMaxAge(Cache::PERMANENT);
      +
      +      // Set the JSON response to the response of committee data.
      +      $json_response = new CacheableJsonResponse($response);
      +
      +      // Add in the cache dependencies.
      +      $json_response->addCacheableDependency($cacheMeta);
      +
      +      // Return JSON Response.
      +      return $json_response;
      +
      +    }
      +
      +    else {
      +
      +      // Not a valid committee or not published.
      +      return FALSE;
      +
      +    }
      +
      +  }
      +
         /**
          * Adds the absolute path to src and href parameter values.
          *
      
      From 4229118800a1b9a4b2d263ae98f19a8fee54e869 Mon Sep 17 00:00:00 2001
      From: scott_earnest 
      Date: Mon, 1 Nov 2021 15:48:34 -0600
      Subject: [PATCH 15/18] FE2-37: Splitting out formatting functions in to
       service.
      
      ---
       .../custom/foia_cfo/foia_cfo.routing.yml      |  16 ++
       .../custom/foia_cfo/foia_cfo.services.yml     |   7 +
       .../foia_cfo/src/Controller/CFOController.php | 223 +++++++++++++-----
       .../foia_cfo/src/Services/CFOService.php      | 100 ++++++++
       4 files changed, 285 insertions(+), 61 deletions(-)
       create mode 100644 docroot/modules/custom/foia_cfo/foia_cfo.services.yml
       create mode 100644 docroot/modules/custom/foia_cfo/src/Services/CFOService.php
      
      diff --git a/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml b/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml
      index e17b22f34..223b50b39 100644
      --- a/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml
      +++ b/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml
      @@ -20,3 +20,19 @@ foia_cfo.committee:
           parameters:
             committee:
               type: entity:node
      +foia_cfo.meetings:
      +  path: 'api/cfo/meetings'
      +  defaults: { _controller: '\Drupal\foia_cfo\Controller\CFOController::getMeetings' }
      +  methods:  [GET]
      +  requirements:
      +    _access: 'TRUE'
      +foia_cfo.meeting:
      +  path: 'api/cfo/meeting/{meeting}'
      +  defaults: { _controller: '\Drupal\foia_cfo\Controller\CFOController::getMeeting' }
      +  methods:  [GET]
      +  requirements:
      +    _access: 'TRUE'
      +  options:
      +    parameters:
      +      meeting:
      +        type: entity:node
      diff --git a/docroot/modules/custom/foia_cfo/foia_cfo.services.yml b/docroot/modules/custom/foia_cfo/foia_cfo.services.yml
      new file mode 100644
      index 000000000..9d9a85ad8
      --- /dev/null
      +++ b/docroot/modules/custom/foia_cfo/foia_cfo.services.yml
      @@ -0,0 +1,7 @@
      +services:
      +  logger.channel.foia_cfo:
      +    parent: logger.channel_base
      +    arguments: ['foia_cfo']
      +  foia_cfo.default:
      +    class: Drupal\foia_cfo\Services\CFOService
      +    arguments: []
      diff --git a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      index d431c3c79..26013eea0 100644
      --- a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      +++ b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      @@ -13,9 +13,9 @@
       use Drupal\Core\Controller\ControllerBase;
       use Drupal\Core\Render\BubbleableMetadata;
       use Drupal\Core\Render\RenderContext;
      -use Drupal\file\Entity\File;
      -use Drupal\entity_reference_revisions\EntityReferenceRevisionsFieldItemList;
       use Drupal\node\Entity\Node;
      +use Drupal\time_field\Time;
      +
       
       /**
        * Controller routines for foia_cfo routes.
      @@ -83,7 +83,7 @@ public function getCouncil(): CacheableJsonResponse {
             $response['title'] = $council_node->label();
       
             if ($council_node->get('body')) {
      -        $body = static::absolutePathFormatter($council_node->get('body')->getValue()[0]['value']);
      +        $body = \Drupal::service('foia_cfo.default')->absolutePathFormatter($council_node->get('body')->getValue()[0]['value']);
               $response['body'] = $body;
             }
       
      @@ -104,7 +104,7 @@ public function getCouncil(): CacheableJsonResponse {
                 $committee_node = $this->nodeStorage->load($nid);
                 $committee = ['committee_title' => $committee_node->label()];
                 if (!empty($committee_node->body->getValue())) {
      -            $committee_body = static::absolutePathFormatter($committee_node->body->getValue()[0]['value']);
      +            $committee_body = \Drupal::service('foia_cfo.default')->absolutePathFormatter($committee_node->body->getValue()[0]['value']);
                   $committee['committee_body'] = $committee_body;
                 }
                 $response['committees'][] = $committee;
      @@ -144,7 +144,7 @@ public function getCouncil(): CacheableJsonResponse {
               // Add title and body for the meeting.
               $meeting['meeting_title'] = $meeting_node->label();
               if (!empty($meeting_node->body->getValue()[0]['value'])) {
      -          $meeting_body = static::absolutePathFormatter($meeting_node->body->getValue()[0]['value']);
      +          $meeting_body = \Drupal::service('foia_cfo.default')->absolutePathFormatter($meeting_node->body->getValue()[0]['value']);
                 $meeting['meeting_body'] = $meeting_body;
               }
       
      @@ -156,12 +156,13 @@ public function getCouncil(): CacheableJsonResponse {
       
               // Meeting materials.
               if ($meeting_node->field_meeting_materials->count()) {
      -          $meeting['meeting_materials'] = static::linkOrFileFormatter($meeting_node->field_meeting_materials);
      +          // Use the Service to get info for an annual data report form.
      +          $meeting['meeting_materials'] = \Drupal::service('foia_cfo.default')->linkOrFileFormatter($meeting_node->field_meeting_materials);
               }
       
               // Meeting documents.
               if ($meeting_node->field_meeting_documents->count()) {
      -          $meeting['meeting_documents'] = static::linkOrFileFormatter($meeting_node->field_meeting_documents);
      +          $meeting['meeting_documents'] = \Drupal::service('foia_cfo.default')->linkOrFileFormatter($meeting_node->field_meeting_documents);
               }
       
               // Add this meeting to the return meeting array.
      @@ -273,9 +274,9 @@ public function getCommittees(): CacheableJsonResponse {
         }
       
         /**
      -   * Callback for `api/cfo/committee/{node}` API method returns JSON Response.
      +   * Callback for `api/cfo/committee/{committee}` API method.
          *
      -   * Returns full details for a committee based on node id passed.
      +   * Returns JSON Response full details for a committee based on node id passed.
          *
          * @param \Drupal\node\Entity\Node $committee
          *   Node object of the committee passed as argument through routing.
      @@ -298,7 +299,7 @@ public function getCommittee(Node $committee) {
       
             // Add body HTML if any - use absolute links.
             if ($committee->hasField('body') && !empty($committee->get('body'))) {
      -        $response['committee_body'] = static::absolutePathFormatter($committee->get('body')->getValue()[0]['value']);
      +        $response['committee_body'] = \Drupal::service('foia_cfo.default')->absolutePathFormatter($committee->get('body')->getValue()[0]['value']);
             }
       
             // Set up the Cache Meta.
      @@ -327,82 +328,182 @@ public function getCommittee(Node $committee) {
         }
       
         /**
      -   * Adds the absolute path to src and href parameter values.
      +   * Callback for `api/cfo/meetings` API method returns JSON Response.
          *
      -   * @param string $input
      -   *   Input string (html).
      +   * Returns array of node ids, meeting name, and a few other details.
      +   * The node id's can then be passed to the meeting detail callback
      +   * for full details of the meeting.
          *
      -   * @return string
      -   *   Input string with absolute paths to src and href.
      +   * @return \Drupal\Core\Cache\CacheableJsonResponse
      +   *   JSON for the meetings list.
          */
      -  private function absolutePathFormatter(string $input): string {
      +  public function getMeetings(): CacheableJsonResponse {
      +
      +    // Initialize the response.
      +    $response = [];
      +
      +    // Array to hold cache dependent node id's.
      +    $cache_nids = [];
      +
      +    // Wrap Query in render context.
      +    $context = new RenderContext();
      +    $meeting_nids = \Drupal::service('renderer')->executeInRenderContext($context, function () {
      +      $meeting_query = \Drupal::entityQuery('node')
      +        ->condition('type', 'cfo_meeting')
      +        ->condition('status', 1)
      +        ->sort('created');
      +      return $meeting_query->execute();
      +    });
      +
      +    if (!empty($meeting_nids)) {
      +
      +      // Loop through all meetings.
      +      foreach ($meeting_nids as $meeting_nid) {
      +
      +        // Add the node id of the meeting.
      +        $cache_nids[] = 'node:' . $meeting_nid;
      +
      +        // Load the meeting node.
      +        if ($meeting_node = $this->nodeStorage->load($meeting_nid)) {
      +          $meeting = [
      +            'meeting_nid' => $meeting_nid,
      +            'meeting_title' => $meeting_node->label(),
      +            'meeting_updated' => $meeting_node->changed->value,
      +          ];
      +          $response[] = $meeting;
      +        }
      +
      +      }
      +
      +    }
      +
      +    // Set up the Cache Meta.
      +    $cacheMeta = (new CacheableMetadata())
      +      ->setCacheTags($cache_nids)
      +      ->setCacheMaxAge(Cache::PERMANENT);
       
      -    // Grab the "base href" with http.
      -    $host = \Drupal::request()->getSchemeAndHttpHost();
      +    // Set the JSON response to the response of meetings.
      +    $json_response = new CacheableJsonResponse($response);
       
      -    // Replacements array - look for href and src with relative paths.
      -    $replacements = [
      -      'href="/' => 'href="' . $host . '/',
      -      'src="/' => 'src="' . $host . '/',
      -    ];
      +    // Add in the cache dependencies.
      +    $json_response->addCacheableDependency($cacheMeta);
       
      -    // Add absolute references to relative paths.
      -    return str_replace(array_keys($replacements), array_values($replacements), $input);
      +    // Handle any bubbled cacheability metadata.
      +    if (!$context->isEmpty()) {
      +      $bubbleable_metadata = $context->pop();
      +      BubbleableMetadata::createFromObject($meeting_nids)
      +        ->merge($bubbleable_metadata);
      +    }
      +
      +    // Return JSON Response.
      +    return $json_response;
       
         }
       
         /**
      -   * Formats "Link or File" paragraph types.
      +   * Callback for `api/cfo/meeting/{meeting}` API method.
      +   *
      +   * Returns JSON Response full details for a meeting based on node id passed.
          *
      -   * @param \Drupal\entity_reference_revisions\EntityReferenceRevisionsFieldItemList $field
      -   *   The field.
      +   * @param \Drupal\node\Entity\Node $meeting
      +   *   Node object of the meeting passed as argument through routing.
          *
      -   * @return array
      -   *   Labels and links to either the url or the file.
      +   * @return \Drupal\Core\Cache\CacheableJsonResponse|false
      +   *   Returns json object or false if the node did not load.
          */
      -  private function linkOrFileFormatter(EntityReferenceRevisionsFieldItemList $field): array {
      +  public function getMeeting(Node $meeting) {
       
      -    // Initialize return array.
      -    $return = [];
      +    if (!empty($meeting) && $meeting->isPublished()) {
       
      -    // Loop over the referenced paragraph entities.
      -    foreach ($field->referencedEntities() as $item) {
      +      // Array to hold cache dependent node id's (just this one).
      +      $cache_nids = ['node:' . $meeting->id()];
       
      -      // Initialize this item.
      -      $return_item = [];
      +      // Initialize the response with basic info.
      +      $response = [
      +        'meeting_title' => $meeting->label(),
      +        'meeting_updated' => $meeting->changed->value,
      +      ];
       
      -      // Set the item label.
      -      if (!empty($item->get('field_link_label')->getValue())) {
      -        $return_item['item_title'] = $item->get('field_link_label')
      -          ->getValue()[0]['value'];
      +      // Add body HTML if any - use absolute links.
      +      if ($meeting->hasField('body') && !empty($meeting->get('body'))) {
      +        $response['meeting_body'] = \Drupal::service('foia_cfo.default')->absolutePathFormatter($meeting->get('body')->getValue()[0]['value']);
             }
       
      -      // Set the item link - this will be a URL or File.
      -      if (!empty($item->get('field_link_link')->getValue()[0]['uri'])) {
      -        $link = $item->get('field_link_link')
      -          ->first()
      -          ->getUrl()
      -          ->setAbsolute(TRUE)
      -          ->toString(TRUE)
      -          ->getGeneratedUrl();
      -        $return_item['item_link'] = $link;
      -      }
      -      elseif (!empty($item->get('field_link_file')
      -        ->getValue()[0]['target_id'])) {
      -        $fid = $item->get('field_link_file')->getValue()[0]['target_id'];
      -        $file = File::load($fid);
      -        $return_item['item_link'] = $file->createFileUrl(FALSE);
      +      // Heading.
      +      if ($meeting->hasField('field_meeting_heading') && !empty($meeting->get('field_meeting_heading'))) {
      +        $response['meeting_heading'] = \Drupal::service('foia_cfo.default')->absolutePathFormatter($meeting->get('field_meeting_heading')->getValue()[0]['value']);
             }
       
      -      // Add this item to the return array.
      -      if (!empty($return_item)) {
      -        $return[] = $return_item;
      +      // Agenda.
      +      if ($meeting->hasField('field_meeting_agenda') && !empty($meeting->get('field_meeting_agenda'))) {
      +
      +        // Initialize agenda - to hold agenda items.
      +        $agenda = [];
      +
      +        // Loop over the referenced paragraph entities.
      +        foreach ($meeting->get('field_meeting_agenda')->referencedEntities() as $item) {
      +
      +          // Initialize this agenda item.
      +          $agenda_item = [];
      +
      +          // Agenda Time.
      +          if (!empty($item->get('field_agenda_item_time'))) {
      +            if (!empty($item->get('field_agenda_item_time')->getValue()[0]['value'])) {
      +              $time_object = Time::createFromTimestamp($item->get('field_agenda_item_time')->getValue()[0]['value']);
      +              $agenda_item['agenda_time'] = $time_object->format();
      +            }
      +          }
      +
      +          // Agenda Title.
      +          if (!empty($item->get('field_agenda_item_title'))) {
      +            if (!empty($item->get('field_agenda_item_title')->getValue()[0]['value'])) {
      +              $agenda_item['agenda_title'] = $item->get('field_agenda_item_title')->getValue()[0]['value'];
      +            }
      +          }
      +
      +          // Agenda Description.
      +          if (!empty($item->get('field_agenda_item_description'))) {
      +            if (!empty($item->get('field_agenda_item_description')->getValue()[0]['value'])) {
      +              $agenda_item['agenda_description'] = $item->get('field_agenda_item_description')->getValue()[0]['value'];
      +            }
      +          }
      +
      +          // Add agenda item to agenda array.
      +          if (!empty($agenda_item)) {
      +            $agenda[] = $agenda_item;
      +          }
      +
      +        }
      +
      +        // Add agenda to the meeting array.
      +        if (!empty($agenda)) {
      +          $response['meeting_agenda'] = $agenda;
      +        }
      +
             }
       
      +      // Set up the Cache Meta.
      +      $cacheMeta = (new CacheableMetadata())
      +        ->setCacheTags($cache_nids)
      +        ->setCacheMaxAge(Cache::PERMANENT);
      +
      +      // Set the JSON response to the response of meeting data.
      +      $json_response = new CacheableJsonResponse($response);
      +
      +      // Add in the cache dependencies.
      +      $json_response->addCacheableDependency($cacheMeta);
      +
      +      // Return JSON Response.
      +      return $json_response;
      +
           }
       
      -    // Returns array of items with labels and links.
      -    return $return;
      +    else {
      +
      +      // Not a valid meeting or not published.
      +      return FALSE;
      +
      +    }
       
         }
       
      diff --git a/docroot/modules/custom/foia_cfo/src/Services/CFOService.php b/docroot/modules/custom/foia_cfo/src/Services/CFOService.php
      new file mode 100644
      index 000000000..176df3e9d
      --- /dev/null
      +++ b/docroot/modules/custom/foia_cfo/src/Services/CFOService.php
      @@ -0,0 +1,100 @@
      +referencedEntities() as $item) {
      +
      +      // Initialize this item.
      +      $return_item = [];
      +
      +      // Set the item label.
      +      if (!empty($item->get('field_link_label')->getValue())) {
      +        $return_item['item_title'] = $item->get('field_link_label')
      +          ->getValue()[0]['value'];
      +      }
      +
      +      // Set the item link - this will be a URL or File.
      +      if (!empty($item->get('field_link_link')->getValue()[0]['uri'])) {
      +        $link = $item->get('field_link_link')
      +          ->first()
      +          ->getUrl()
      +          ->setAbsolute(TRUE)
      +          ->toString(TRUE)
      +          ->getGeneratedUrl();
      +        $return_item['item_link'] = $link;
      +      }
      +      elseif (!empty($item->get('field_link_file')
      +        ->getValue()[0]['target_id'])) {
      +        $fid = $item->get('field_link_file')->getValue()[0]['target_id'];
      +        $file = File::load($fid);
      +        $return_item['item_link'] = $file->createFileUrl(FALSE);
      +      }
      +
      +      // Add this item to the return array.
      +      if (!empty($return_item)) {
      +        $return[] = $return_item;
      +      }
      +
      +    }
      +
      +    // Returns array of items with labels and links.
      +    return $return;
      +
      +  }
      +
      +  /**
      +   * Adds the absolute path to src and href parameter values.
      +   *
      +   * @param string $input
      +   *   Input string (html).
      +   *
      +   * @return string
      +   *   Input string with absolute paths to src and href.
      +   */
      +  public function absolutePathFormatter(string $input): string {
      +
      +    // Grab the "base href" with http.
      +    $host = \Drupal::request()->getSchemeAndHttpHost();
      +
      +    // Replacements array - look for href and src with relative paths.
      +    $replacements = [
      +      'href="/' => 'href="' . $host . '/',
      +      'src="/' => 'src="' . $host . '/',
      +    ];
      +
      +    // Add absolute references to relative paths.
      +    return str_replace(array_keys($replacements), array_values($replacements), $input);
      +
      +  }
      +
      +}
      
      From 88045657250102f4ef89d284787fc65581caf4bf Mon Sep 17 00:00:00 2001
      From: scott_earnest 
      Date: Mon, 1 Nov 2021 15:59:03 -0600
      Subject: [PATCH 16/18] FE2-37: Splitting out meetings functions to its own
       controller.
      
      ---
       .../custom/foia_cfo/foia_cfo.routing.yml      |   4 +-
       .../foia_cfo/src/Controller/CFOController.php | 182 --------------
       .../src/Controller/CFOMeetingsController.php  | 230 ++++++++++++++++++
       3 files changed, 232 insertions(+), 184 deletions(-)
       create mode 100644 docroot/modules/custom/foia_cfo/src/Controller/CFOMeetingsController.php
      
      diff --git a/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml b/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml
      index 223b50b39..3ebe7e59a 100644
      --- a/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml
      +++ b/docroot/modules/custom/foia_cfo/foia_cfo.routing.yml
      @@ -22,13 +22,13 @@ foia_cfo.committee:
               type: entity:node
       foia_cfo.meetings:
         path: 'api/cfo/meetings'
      -  defaults: { _controller: '\Drupal\foia_cfo\Controller\CFOController::getMeetings' }
      +  defaults: { _controller: '\Drupal\foia_cfo\Controller\CFOMeetingsController::getMeetings' }
         methods:  [GET]
         requirements:
           _access: 'TRUE'
       foia_cfo.meeting:
         path: 'api/cfo/meeting/{meeting}'
      -  defaults: { _controller: '\Drupal\foia_cfo\Controller\CFOController::getMeeting' }
      +  defaults: { _controller: '\Drupal\foia_cfo\Controller\CFOMeetingsController::getMeeting' }
         methods:  [GET]
         requirements:
           _access: 'TRUE'
      diff --git a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      index 26013eea0..336b33d29 100644
      --- a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      +++ b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      @@ -14,8 +14,6 @@
       use Drupal\Core\Render\BubbleableMetadata;
       use Drupal\Core\Render\RenderContext;
       use Drupal\node\Entity\Node;
      -use Drupal\time_field\Time;
      -
       
       /**
        * Controller routines for foia_cfo routes.
      @@ -327,184 +325,4 @@ public function getCommittee(Node $committee) {
       
         }
       
      -  /**
      -   * Callback for `api/cfo/meetings` API method returns JSON Response.
      -   *
      -   * Returns array of node ids, meeting name, and a few other details.
      -   * The node id's can then be passed to the meeting detail callback
      -   * for full details of the meeting.
      -   *
      -   * @return \Drupal\Core\Cache\CacheableJsonResponse
      -   *   JSON for the meetings list.
      -   */
      -  public function getMeetings(): CacheableJsonResponse {
      -
      -    // Initialize the response.
      -    $response = [];
      -
      -    // Array to hold cache dependent node id's.
      -    $cache_nids = [];
      -
      -    // Wrap Query in render context.
      -    $context = new RenderContext();
      -    $meeting_nids = \Drupal::service('renderer')->executeInRenderContext($context, function () {
      -      $meeting_query = \Drupal::entityQuery('node')
      -        ->condition('type', 'cfo_meeting')
      -        ->condition('status', 1)
      -        ->sort('created');
      -      return $meeting_query->execute();
      -    });
      -
      -    if (!empty($meeting_nids)) {
      -
      -      // Loop through all meetings.
      -      foreach ($meeting_nids as $meeting_nid) {
      -
      -        // Add the node id of the meeting.
      -        $cache_nids[] = 'node:' . $meeting_nid;
      -
      -        // Load the meeting node.
      -        if ($meeting_node = $this->nodeStorage->load($meeting_nid)) {
      -          $meeting = [
      -            'meeting_nid' => $meeting_nid,
      -            'meeting_title' => $meeting_node->label(),
      -            'meeting_updated' => $meeting_node->changed->value,
      -          ];
      -          $response[] = $meeting;
      -        }
      -
      -      }
      -
      -    }
      -
      -    // Set up the Cache Meta.
      -    $cacheMeta = (new CacheableMetadata())
      -      ->setCacheTags($cache_nids)
      -      ->setCacheMaxAge(Cache::PERMANENT);
      -
      -    // Set the JSON response to the response of meetings.
      -    $json_response = new CacheableJsonResponse($response);
      -
      -    // Add in the cache dependencies.
      -    $json_response->addCacheableDependency($cacheMeta);
      -
      -    // Handle any bubbled cacheability metadata.
      -    if (!$context->isEmpty()) {
      -      $bubbleable_metadata = $context->pop();
      -      BubbleableMetadata::createFromObject($meeting_nids)
      -        ->merge($bubbleable_metadata);
      -    }
      -
      -    // Return JSON Response.
      -    return $json_response;
      -
      -  }
      -
      -  /**
      -   * Callback for `api/cfo/meeting/{meeting}` API method.
      -   *
      -   * Returns JSON Response full details for a meeting based on node id passed.
      -   *
      -   * @param \Drupal\node\Entity\Node $meeting
      -   *   Node object of the meeting passed as argument through routing.
      -   *
      -   * @return \Drupal\Core\Cache\CacheableJsonResponse|false
      -   *   Returns json object or false if the node did not load.
      -   */
      -  public function getMeeting(Node $meeting) {
      -
      -    if (!empty($meeting) && $meeting->isPublished()) {
      -
      -      // Array to hold cache dependent node id's (just this one).
      -      $cache_nids = ['node:' . $meeting->id()];
      -
      -      // Initialize the response with basic info.
      -      $response = [
      -        'meeting_title' => $meeting->label(),
      -        'meeting_updated' => $meeting->changed->value,
      -      ];
      -
      -      // Add body HTML if any - use absolute links.
      -      if ($meeting->hasField('body') && !empty($meeting->get('body'))) {
      -        $response['meeting_body'] = \Drupal::service('foia_cfo.default')->absolutePathFormatter($meeting->get('body')->getValue()[0]['value']);
      -      }
      -
      -      // Heading.
      -      if ($meeting->hasField('field_meeting_heading') && !empty($meeting->get('field_meeting_heading'))) {
      -        $response['meeting_heading'] = \Drupal::service('foia_cfo.default')->absolutePathFormatter($meeting->get('field_meeting_heading')->getValue()[0]['value']);
      -      }
      -
      -      // Agenda.
      -      if ($meeting->hasField('field_meeting_agenda') && !empty($meeting->get('field_meeting_agenda'))) {
      -
      -        // Initialize agenda - to hold agenda items.
      -        $agenda = [];
      -
      -        // Loop over the referenced paragraph entities.
      -        foreach ($meeting->get('field_meeting_agenda')->referencedEntities() as $item) {
      -
      -          // Initialize this agenda item.
      -          $agenda_item = [];
      -
      -          // Agenda Time.
      -          if (!empty($item->get('field_agenda_item_time'))) {
      -            if (!empty($item->get('field_agenda_item_time')->getValue()[0]['value'])) {
      -              $time_object = Time::createFromTimestamp($item->get('field_agenda_item_time')->getValue()[0]['value']);
      -              $agenda_item['agenda_time'] = $time_object->format();
      -            }
      -          }
      -
      -          // Agenda Title.
      -          if (!empty($item->get('field_agenda_item_title'))) {
      -            if (!empty($item->get('field_agenda_item_title')->getValue()[0]['value'])) {
      -              $agenda_item['agenda_title'] = $item->get('field_agenda_item_title')->getValue()[0]['value'];
      -            }
      -          }
      -
      -          // Agenda Description.
      -          if (!empty($item->get('field_agenda_item_description'))) {
      -            if (!empty($item->get('field_agenda_item_description')->getValue()[0]['value'])) {
      -              $agenda_item['agenda_description'] = $item->get('field_agenda_item_description')->getValue()[0]['value'];
      -            }
      -          }
      -
      -          // Add agenda item to agenda array.
      -          if (!empty($agenda_item)) {
      -            $agenda[] = $agenda_item;
      -          }
      -
      -        }
      -
      -        // Add agenda to the meeting array.
      -        if (!empty($agenda)) {
      -          $response['meeting_agenda'] = $agenda;
      -        }
      -
      -      }
      -
      -      // Set up the Cache Meta.
      -      $cacheMeta = (new CacheableMetadata())
      -        ->setCacheTags($cache_nids)
      -        ->setCacheMaxAge(Cache::PERMANENT);
      -
      -      // Set the JSON response to the response of meeting data.
      -      $json_response = new CacheableJsonResponse($response);
      -
      -      // Add in the cache dependencies.
      -      $json_response->addCacheableDependency($cacheMeta);
      -
      -      // Return JSON Response.
      -      return $json_response;
      -
      -    }
      -
      -    else {
      -
      -      // Not a valid meeting or not published.
      -      return FALSE;
      -
      -    }
      -
      -  }
      -
       }
      diff --git a/docroot/modules/custom/foia_cfo/src/Controller/CFOMeetingsController.php b/docroot/modules/custom/foia_cfo/src/Controller/CFOMeetingsController.php
      new file mode 100644
      index 000000000..8b84692cc
      --- /dev/null
      +++ b/docroot/modules/custom/foia_cfo/src/Controller/CFOMeetingsController.php
      @@ -0,0 +1,230 @@
      +nodeStorage = \Drupal::entityTypeManager()->getStorage('node');
      +  }
      +
      +  /**
      +   * Callback for `api/cfo/meetings` API method returns JSON Response.
      +   *
      +   * Returns array of node ids, meeting name, and a few other details.
      +   * The node id's can then be passed to the meeting detail callback
      +   * for full details of the meeting.
      +   *
      +   * @return \Drupal\Core\Cache\CacheableJsonResponse
      +   *   JSON for the meetings list.
      +   */
      +  public function getMeetings(): CacheableJsonResponse {
      +
      +    // Initialize the response.
      +    $response = [];
      +
      +    // Array to hold cache dependent node id's.
      +    $cache_nids = [];
      +
      +    // Wrap Query in render context.
      +    $context = new RenderContext();
      +    $meeting_nids = \Drupal::service('renderer')->executeInRenderContext($context, function () {
      +      $meeting_query = \Drupal::entityQuery('node')
      +        ->condition('type', 'cfo_meeting')
      +        ->condition('status', 1)
      +        ->sort('created');
      +      return $meeting_query->execute();
      +    });
      +
      +    if (!empty($meeting_nids)) {
      +
      +      // Loop through all meetings.
      +      foreach ($meeting_nids as $meeting_nid) {
      +
      +        // Add the node id of the meeting.
      +        $cache_nids[] = 'node:' . $meeting_nid;
      +
      +        // Load the meeting node.
      +        if ($meeting_node = $this->nodeStorage->load($meeting_nid)) {
      +          $meeting = [
      +            'meeting_nid' => $meeting_nid,
      +            'meeting_title' => $meeting_node->label(),
      +            'meeting_updated' => $meeting_node->changed->value,
      +          ];
      +          $response[] = $meeting;
      +        }
      +
      +      }
      +
      +    }
      +
      +    // Set up the Cache Meta.
      +    $cacheMeta = (new CacheableMetadata())
      +      ->setCacheTags($cache_nids)
      +      ->setCacheMaxAge(Cache::PERMANENT);
      +
      +    // Set the JSON response to the response of meetings.
      +    $json_response = new CacheableJsonResponse($response);
      +
      +    // Add in the cache dependencies.
      +    $json_response->addCacheableDependency($cacheMeta);
      +
      +    // Handle any bubbled cacheability metadata.
      +    if (!$context->isEmpty()) {
      +      $bubbleable_metadata = $context->pop();
      +      BubbleableMetadata::createFromObject($meeting_nids)
      +        ->merge($bubbleable_metadata);
      +    }
      +
      +    // Return JSON Response.
      +    return $json_response;
      +
      +  }
      +
      +  /**
      +   * Callback for `api/cfo/meeting/{meeting}` API method.
      +   *
      +   * Returns JSON Response full details for a meeting based on node id passed.
      +   *
      +   * @param \Drupal\node\Entity\Node $meeting
      +   *   Node object of the meeting passed as argument through routing.
      +   *
      +   * @return \Drupal\Core\Cache\CacheableJsonResponse|false
      +   *   Returns json object or false if the node did not load.
      +   */
      +  public function getMeeting(Node $meeting) {
      +
      +    if (!empty($meeting) && $meeting->isPublished()) {
      +
      +      // Array to hold cache dependent node id's (just this one).
      +      $cache_nids = ['node:' . $meeting->id()];
      +
      +      // Initialize the response with basic info.
      +      $response = [
      +        'meeting_title' => $meeting->label(),
      +        'meeting_updated' => $meeting->changed->value,
      +      ];
      +
      +      // Add body HTML if any - use absolute links.
      +      if (
      +        $meeting->hasField('body')
      +        && !empty($meeting->get('body'))
      +        && !empty($meeting->get('body')->getValue()[0]['value'])
      +      ) {
      +        $response['meeting_body'] = \Drupal::service('foia_cfo.default')->absolutePathFormatter($meeting->get('body')->getValue()[0]['value']);
      +      }
      +
      +      // Heading.
      +      if (
      +        $meeting->hasField('field_meeting_heading')
      +        && !empty($meeting->get('field_meeting_heading'))
      +        && !empty($meeting->get('field_meeting_heading')->getValue()[0]['value'])
      +      ) {
      +        $response['meeting_heading'] = \Drupal::service('foia_cfo.default')->absolutePathFormatter($meeting->get('field_meeting_heading')->getValue()[0]['value']);
      +      }
      +
      +      // Agenda.
      +      if ($meeting->hasField('field_meeting_agenda') && !empty($meeting->get('field_meeting_agenda'))) {
      +
      +        // Initialize agenda - to hold agenda items.
      +        $agenda = [];
      +
      +        // Loop over the referenced paragraph entities.
      +        foreach ($meeting->get('field_meeting_agenda')->referencedEntities() as $item) {
      +
      +          // Initialize this agenda item.
      +          $agenda_item = [];
      +
      +          // Agenda Time.
      +          if (!empty($item->get('field_agenda_item_time'))) {
      +            if (!empty($item->get('field_agenda_item_time')->getValue()[0]['value'])) {
      +              $time_object = Time::createFromTimestamp($item->get('field_agenda_item_time')->getValue()[0]['value']);
      +              $agenda_item['agenda_time'] = $time_object->format();
      +            }
      +          }
      +
      +          // Agenda Title.
      +          if (!empty($item->get('field_agenda_item_title'))) {
      +            if (!empty($item->get('field_agenda_item_title')->getValue()[0]['value'])) {
      +              $agenda_item['agenda_title'] = $item->get('field_agenda_item_title')->getValue()[0]['value'];
      +            }
      +          }
      +
      +          // Agenda Description.
      +          if (!empty($item->get('field_agenda_item_description'))) {
      +            if (!empty($item->get('field_agenda_item_description')->getValue()[0]['value'])) {
      +              $agenda_item['agenda_description'] = $item->get('field_agenda_item_description')->getValue()[0]['value'];
      +            }
      +          }
      +
      +          // Add agenda item to agenda array.
      +          if (!empty($agenda_item)) {
      +            $agenda[] = $agenda_item;
      +          }
      +
      +        }
      +
      +        // Add agenda to the meeting array.
      +        if (!empty($agenda)) {
      +          $response['meeting_agenda'] = $agenda;
      +        }
      +
      +      }
      +
      +      // Set up the Cache Meta.
      +      $cacheMeta = (new CacheableMetadata())
      +        ->setCacheTags($cache_nids)
      +        ->setCacheMaxAge(Cache::PERMANENT);
      +
      +      // Set the JSON response to the response of meeting data.
      +      $json_response = new CacheableJsonResponse($response);
      +
      +      // Add in the cache dependencies.
      +      $json_response->addCacheableDependency($cacheMeta);
      +
      +      // Return JSON Response.
      +      return $json_response;
      +
      +    }
      +
      +    else {
      +
      +      // Not a valid meeting or not published.
      +      return FALSE;
      +
      +    }
      +
      +  }
      +
      +}
      
      From d91ccccddf6df40d8c0795cdb7a1631791151f16 Mon Sep 17 00:00:00 2001
      From: scott_earnest 
      Date: Mon, 1 Nov 2021 17:11:50 -0600
      Subject: [PATCH 17/18] FE2-37: Misc checks and formatting.
      
      ---
       .../foia_cfo/src/Controller/CFOController.php   | 17 ++++++++++++-----
       .../src/Controller/CFOMeetingsController.php    |  6 +++---
       2 files changed, 15 insertions(+), 8 deletions(-)
      
      diff --git a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      index 336b33d29..48963d13c 100644
      --- a/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      +++ b/docroot/modules/custom/foia_cfo/src/Controller/CFOController.php
      @@ -80,7 +80,10 @@ public function getCouncil(): CacheableJsonResponse {
             // Title and body of the Council node.
             $response['title'] = $council_node->label();
       
      -      if ($council_node->get('body')) {
      +      if (
      +        !empty($council_node->get('body'))
      +        && !empty($council_node->get('body')->getValue()[0]['value'])
      +      ) {
               $body = \Drupal::service('foia_cfo.default')->absolutePathFormatter($council_node->get('body')->getValue()[0]['value']);
               $response['body'] = $body;
             }
      @@ -279,10 +282,10 @@ public function getCommittees(): CacheableJsonResponse {
          * @param \Drupal\node\Entity\Node $committee
          *   Node object of the committee passed as argument through routing.
          *
      -   * @return \Drupal\Core\Cache\CacheableJsonResponse|false
      +   * @return \Drupal\Core\Cache\CacheableJsonResponse
          *   Returns json object or false if the node did not load.
          */
      -  public function getCommittee(Node $committee) {
      +  public function getCommittee(Node $committee): CacheableJsonResponse {
       
           if (!empty($committee) && $committee->isPublished()) {
       
      @@ -296,7 +299,11 @@ public function getCommittee(Node $committee) {
             ];
       
             // Add body HTML if any - use absolute links.
      -      if ($committee->hasField('body') && !empty($committee->get('body'))) {
      +      if (
      +        $committee->hasField('body')
      +        && !empty($committee->get('body'))
      +        && !empty($committee->get('body')->getValue()[0]['value'])
      +      ) {
               $response['committee_body'] = \Drupal::service('foia_cfo.default')->absolutePathFormatter($committee->get('body')->getValue()[0]['value']);
             }
       
      @@ -319,7 +326,7 @@ public function getCommittee(Node $committee) {
           else {
       
             // Not a valid committee or not published.
      -      return FALSE;
      +      return new CacheableJsonResponse([]);
       
           }
       
      diff --git a/docroot/modules/custom/foia_cfo/src/Controller/CFOMeetingsController.php b/docroot/modules/custom/foia_cfo/src/Controller/CFOMeetingsController.php
      index 8b84692cc..0bf50a3ee 100644
      --- a/docroot/modules/custom/foia_cfo/src/Controller/CFOMeetingsController.php
      +++ b/docroot/modules/custom/foia_cfo/src/Controller/CFOMeetingsController.php
      @@ -120,10 +120,10 @@ public function getMeetings(): CacheableJsonResponse {
          * @param \Drupal\node\Entity\Node $meeting
          *   Node object of the meeting passed as argument through routing.
          *
      -   * @return \Drupal\Core\Cache\CacheableJsonResponse|false
      +   * @return \Drupal\Core\Cache\CacheableJsonResponse
          *   Returns json object or false if the node did not load.
          */
      -  public function getMeeting(Node $meeting) {
      +  public function getMeeting(Node $meeting): CacheableJsonResponse {
       
           if (!empty($meeting) && $meeting->isPublished()) {
       
      @@ -221,7 +221,7 @@ public function getMeeting(Node $meeting) {
           else {
       
             // Not a valid meeting or not published.
      -      return FALSE;
      +      return new CacheableJsonResponse([]);
       
           }
       
      
      From 61cfecbeb4e65ecf3584918783f1c3cb4627ecf7 Mon Sep 17 00:00:00 2001
      From: scott_earnest 
      Date: Mon, 1 Nov 2021 17:21:16 -0600
      Subject: [PATCH 18/18] FE2-37: Config for CFO admin dashboard.
      
      ---
       .../default/views.view.cfo_council_admin.yml  | 453 +++++++++++++++++-
       1 file changed, 446 insertions(+), 7 deletions(-)
      
      diff --git a/config/default/views.view.cfo_council_admin.yml b/config/default/views.view.cfo_council_admin.yml
      index c99ad6a00..9ae9294cc 100644
      --- a/config/default/views.view.cfo_council_admin.yml
      +++ b/config/default/views.view.cfo_council_admin.yml
      @@ -4,6 +4,7 @@ status: true
       dependencies:
         config:
           - field.storage.node.field_council_committees
      +    - node.type.cfo_committee
           - node.type.cfo_council
           - node.type.cfo_meeting
           - user.role.authenticated
      @@ -336,11 +337,385 @@ display:
               - user.roles
             tags:
               - 'config:field.storage.node.field_council_committees'
      -  attachment_1:
      +  committees:
           display_plugin: attachment
      -    id: attachment_1
      -    display_title: Meetings
      +    id: committees
      +    display_title: Committees
           position: 2
      +    display_options:
      +      display_extenders: {  }
      +      title: 'CFO Committees'
      +      defaults:
      +        title: false
      +        style: false
      +        row: false
      +        fields: false
      +        filters: false
      +        filter_groups: false
      +        sorts: false
      +        relationships: false
      +        header: false
      +      style:
      +        type: html_list
      +        options:
      +          grouping: {  }
      +          row_class: ''
      +          default_row_class: true
      +          type: ul
      +          wrapper_class: item-list
      +          class: ''
      +      row:
      +        type: fields
      +        options: {  }
      +      fields:
      +        edit_node:
      +          id: edit_node
      +          table: node
      +          field: edit_node
      +          relationship: none
      +          group_type: group
      +          admin_label: ''
      +          label: ''
      +          exclude: true
      +          alter:
      +            alter_text: false
      +            text: ''
      +            make_link: false
      +            path: ''
      +            absolute: false
      +            external: false
      +            replace_spaces: false
      +            path_case: none
      +            trim_whitespace: false
      +            alt: ''
      +            rel: ''
      +            link_class: ''
      +            prefix: ''
      +            suffix: ''
      +            target: ''
      +            nl2br: false
      +            max_length: 0
      +            word_boundary: true
      +            ellipsis: true
      +            more_link: false
      +            more_link_text: ''
      +            more_link_path: ''
      +            strip_tags: false
      +            trim: false
      +            preserve_tags: ''
      +            html: false
      +          element_type: ''
      +          element_class: ''
      +          element_label_type: ''
      +          element_label_class: ''
      +          element_label_colon: false
      +          element_wrapper_type: ''
      +          element_wrapper_class: ''
      +          element_default_classes: true
      +          empty: ''
      +          hide_empty: false
      +          empty_zero: false
      +          hide_alter_empty: true
      +          text: edit
      +          output_url_as_text: true
      +          absolute: false
      +          entity_type: node
      +          plugin_id: entity_link_edit
      +        status:
      +          id: status
      +          table: node_field_data
      +          field: status
      +          relationship: none
      +          group_type: group
      +          admin_label: ''
      +          label: ''
      +          exclude: true
      +          alter:
      +            alter_text: false
      +            text: ''
      +            make_link: false
      +            path: ''
      +            absolute: false
      +            external: false
      +            replace_spaces: false
      +            path_case: none
      +            trim_whitespace: false
      +            alt: ''
      +            rel: ''
      +            link_class: ''
      +            prefix: ''
      +            suffix: ''
      +            target: ''
      +            nl2br: false
      +            max_length: 0
      +            word_boundary: true
      +            ellipsis: true
      +            more_link: false
      +            more_link_text: ''
      +            more_link_path: ''
      +            strip_tags: false
      +            trim: false
      +            preserve_tags: ''
      +            html: false
      +          element_type: ''
      +          element_class: ''
      +          element_label_type: ''
      +          element_label_class: ''
      +          element_label_colon: false
      +          element_wrapper_type: ''
      +          element_wrapper_class: ''
      +          element_default_classes: true
      +          empty: ''
      +          hide_empty: false
      +          empty_zero: false
      +          hide_alter_empty: true
      +          click_sort_column: value
      +          type: boolean
      +          settings:
      +            format: custom
      +            format_custom_true: ''
      +            format_custom_false: (UNPUBLISHED)
      +          group_column: value
      +          group_columns: {  }
      +          group_rows: true
      +          delta_limit: 0
      +          delta_offset: 0
      +          delta_reversed: false
      +          delta_first_last: false
      +          multi_type: separator
      +          separator: ', '
      +          field_api_classes: false
      +          entity_type: node
      +          entity_field: status
      +          plugin_id: field
      +        nid:
      +          id: nid
      +          table: node_field_data
      +          field: nid
      +          relationship: none
      +          group_type: group
      +          admin_label: ''
      +          label: ''
      +          exclude: true
      +          alter:
      +            alter_text: true
      +            text: '   (json)'
      +            make_link: true
      +            path: '/api/cfo/committee/{{ nid }}'
      +            absolute: false
      +            external: false
      +            replace_spaces: false
      +            path_case: none
      +            trim_whitespace: false
      +            alt: ''
      +            rel: ''
      +            link_class: ''
      +            prefix: ''
      +            suffix: ''
      +            target: ''
      +            nl2br: false
      +            max_length: 0
      +            word_boundary: true
      +            ellipsis: true
      +            more_link: false
      +            more_link_text: ''
      +            more_link_path: ''
      +            strip_tags: false
      +            trim: false
      +            preserve_tags: ''
      +            html: false
      +          element_type: ''
      +          element_class: ''
      +          element_label_type: ''
      +          element_label_class: ''
      +          element_label_colon: false
      +          element_wrapper_type: ''
      +          element_wrapper_class: ''
      +          element_default_classes: true
      +          empty: ''
      +          hide_empty: false
      +          empty_zero: false
      +          hide_alter_empty: true
      +          click_sort_column: value
      +          type: number_unformatted
      +          settings: {  }
      +          group_column: value
      +          group_columns: {  }
      +          group_rows: true
      +          delta_limit: 0
      +          delta_offset: 0
      +          delta_reversed: false
      +          delta_first_last: false
      +          multi_type: separator
      +          separator: ', '
      +          field_api_classes: false
      +          entity_type: node
      +          entity_field: nid
      +          plugin_id: field
      +        title:
      +          id: title
      +          table: node_field_data
      +          field: title
      +          relationship: none
      +          group_type: group
      +          admin_label: ''
      +          label: ''
      +          exclude: false
      +          alter:
      +            alter_text: true
      +            text: '{{ title }} {{ status }} {{ nid }}'
      +            make_link: true
      +            path: '{{ edit_node }}?destination=/admin/content/cfo-council'
      +            absolute: false
      +            external: false
      +            replace_spaces: false
      +            path_case: none
      +            trim_whitespace: false
      +            alt: ''
      +            rel: ''
      +            link_class: ''
      +            prefix: ''
      +            suffix: ''
      +            target: ''
      +            nl2br: false
      +            max_length: 0
      +            word_boundary: false
      +            ellipsis: false
      +            more_link: false
      +            more_link_text: ''
      +            more_link_path: ''
      +            strip_tags: false
      +            trim: false
      +            preserve_tags: ''
      +            html: false
      +          element_type: ''
      +          element_class: ''
      +          element_label_type: ''
      +          element_label_class: ''
      +          element_label_colon: false
      +          element_wrapper_type: ''
      +          element_wrapper_class: ''
      +          element_default_classes: true
      +          empty: ''
      +          hide_empty: false
      +          empty_zero: false
      +          hide_alter_empty: true
      +          click_sort_column: value
      +          type: string
      +          settings:
      +            link_to_entity: false
      +          group_column: value
      +          group_columns: {  }
      +          group_rows: true
      +          delta_limit: 0
      +          delta_offset: 0
      +          delta_reversed: false
      +          delta_first_last: false
      +          multi_type: separator
      +          separator: ', '
      +          field_api_classes: false
      +          entity_type: node
      +          entity_field: title
      +          plugin_id: field
      +      filters:
      +        type:
      +          id: type
      +          table: node_field_data
      +          field: type
      +          relationship: none
      +          group_type: group
      +          admin_label: ''
      +          operator: in
      +          value:
      +            cfo_committee: cfo_committee
      +          group: 1
      +          exposed: false
      +          expose:
      +            operator_id: ''
      +            label: ''
      +            description: ''
      +            use_operator: false
      +            operator: ''
      +            operator_limit_selection: false
      +            operator_list: {  }
      +            identifier: ''
      +            required: false
      +            remember: false
      +            multiple: false
      +            remember_roles:
      +              authenticated: authenticated
      +            reduce: false
      +            argument: null
      +          is_grouped: false
      +          group_info:
      +            label: ''
      +            description: ''
      +            identifier: ''
      +            optional: true
      +            widget: select
      +            multiple: false
      +            remember: false
      +            default_group: All
      +            default_group_multiple: {  }
      +            group_items: {  }
      +          entity_type: node
      +          entity_field: type
      +          plugin_id: bundle
      +      filter_groups:
      +        operator: AND
      +        groups:
      +          1: AND
      +      sorts:
      +        title:
      +          id: title
      +          table: node_field_data
      +          field: title
      +          relationship: none
      +          group_type: group
      +          admin_label: ''
      +          order: ASC
      +          exposed: false
      +          expose:
      +            label: ''
      +          entity_type: node
      +          entity_field: title
      +          plugin_id: standard
      +      relationships: {  }
      +      displays:
      +        page_1: page_1
      +      attachment_position: after
      +      pager:
      +        type: none
      +        options:
      +          offset: 0
      +      header:
      +        area:
      +          id: area
      +          table: views
      +          field: area
      +          relationship: none
      +          group_type: group
      +          admin_label: ''
      +          empty: false
      +          tokenize: false
      +          content:
      +            value: '

      Committees (full list)

      ' + format: rich_text + plugin_id: text + display_description: '' + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - 'user.node_grants:view' + - user.roles + tags: { } + meetings: + display_plugin: attachment + id: meetings + display_title: Meetings + position: 3 display_options: display_extenders: { } title: 'CFO Meetings' @@ -487,6 +862,70 @@ display: entity_type: node entity_field: status plugin_id: field + nid: + id: nid + table: node_field_data + field: nid + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: true + text: '  (json)' + make_link: true + path: '/api/cfo/meeting/{{ nid }}' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: number_unformatted + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: node + entity_field: nid + plugin_id: field title: id: title table: node_field_data @@ -498,7 +937,7 @@ display: exclude: false alter: alter_text: true - text: '{{ title }} {{ status }}' + text: '{{ title }} {{ status }} {{ nid }}' make_link: true path: '{{ edit_node }}?destination=/admin/content/cfo-council' absolute: false @@ -856,12 +1295,12 @@ display: relationship: none group_type: group admin_label: '' - label: Committees + label: 'Committees (assigned to the Council)' exclude: false alter: alter_text: false text: '' - make_link: true + make_link: false path: '/node/{{ field_council_committees__target_id }}/edit?destination=/admin/content/cfo-council' absolute: false external: false @@ -926,7 +1365,7 @@ display: empty: false tokenize: false content: - value: "click here to add a committee\r\n  |  \r\nclick here to add a meeting\r\n  |  \r\ncouncil json" + value: "[ ADD CONTENT:   \r\nclick here to add a committee\r\n  |  \r\nclick here to add a meeting\r\n]    \r\n[ JSON FEEDS:   \r\ncouncil page\r\n  |  \r\ncommittees list\r\n  |  \r\nmeetings list\r\n]" format: rich_text plugin_id: text cache_metadata: