diff --git a/web/profiles/custom/yalesites_profile/config/sync/block_content.type.tags.yml b/web/profiles/custom/yalesites_profile/config/sync/block_content.type.tags.yml new file mode 100644 index 000000000..39956d646 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/config/sync/block_content.type.tags.yml @@ -0,0 +1,33 @@ +uuid: a69bdfdd-d7d2-4c53-b531-54531018f15d +langcode: en +status: true +dependencies: + module: + - entity_redirect +third_party_settings: + entity_redirect: + redirect: + add: + active: 0 + destination: default + url: '' + external: '' + edit: + active: 0 + destination: default + url: '' + external: '' + delete: + active: 0 + destination: default + url: '' + external: '' + anonymous: + active: 0 + destination: default + url: '' + external: '' +id: tags +label: Tags +revision: 1 +description: 'Block to display tag information about a Resource ' diff --git a/web/profiles/custom/yalesites_profile/config/sync/core.entity_form_display.block_content.tags.default.yml b/web/profiles/custom/yalesites_profile/config/sync/core.entity_form_display.block_content.tags.default.yml new file mode 100644 index 000000000..f78b98243 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/config/sync/core.entity_form_display.block_content.tags.default.yml @@ -0,0 +1,45 @@ +uuid: aec9487e-e4cf-4057-b324-99a12f9215f5 +langcode: en +status: true +dependencies: + config: + - block_content.type.tags + - field.field.block_content.tags.field_selected_resource + module: + - hide_revision_field +id: block_content.tags.default +targetEntityType: block_content +bundle: tags +mode: default +content: + field_selected_resource: + type: entity_reference_autocomplete + weight: 82 + region: content + settings: + match_operator: CONTAINS + match_limit: 10 + size: 60 + placeholder: '' + third_party_settings: { } + info: + type: string_textfield + weight: -5 + region: content + settings: + size: 60 + placeholder: '' + third_party_settings: { } + revision_log: + type: hide_revision_field_log_widget + weight: 80 + region: content + settings: + rows: 5 + placeholder: '' + show: true + default: '' + permission_based: false + allow_user_settings: true + third_party_settings: { } +hidden: { } diff --git a/web/profiles/custom/yalesites_profile/config/sync/core.entity_form_display.node.page.default.yml b/web/profiles/custom/yalesites_profile/config/sync/core.entity_form_display.node.page.default.yml index a6d418b66..4c2f23203 100644 --- a/web/profiles/custom/yalesites_profile/config/sync/core.entity_form_display.node.page.default.yml +++ b/web/profiles/custom/yalesites_profile/config/sync/core.entity_form_display.node.page.default.yml @@ -3,6 +3,7 @@ langcode: en status: true dependencies: config: + - field.field.node.page.field_audience - field.field.node.page.field_category - field.field.node.page.field_external_source - field.field.node.page.field_login_required @@ -11,6 +12,7 @@ dependencies: - field.field.node.page.field_teaser_media - field.field.node.page.field_teaser_text - field.field.node.page.field_teaser_title + - field.field.node.page.field_type - field.field.node.page.layout_builder__layout - node.type.page module: @@ -34,7 +36,7 @@ third_party_settings: label: Teaser region: content parent_name: '' - weight: 3 + weight: 6 format_type: fieldset format_settings: classes: '' @@ -48,7 +50,7 @@ third_party_settings: label: 'Publishing Settings' region: content parent_name: '' - weight: 8 + weight: 11 format_type: details_sidebar format_settings: classes: '' @@ -64,7 +66,7 @@ third_party_settings: label: 'External Link' region: content parent_name: '' - weight: 10 + weight: 13 format_type: details_sidebar format_settings: classes: '' @@ -79,6 +81,12 @@ targetEntityType: node bundle: page mode: default content: + field_audience: + type: chosen_select + weight: 4 + region: content + settings: { } + third_party_settings: { } field_category: type: chosen_select weight: 1 @@ -102,7 +110,7 @@ content: third_party_settings: { } field_metatags: type: metatag_firehose - weight: 7 + weight: 10 region: content settings: sidebar: true @@ -144,27 +152,33 @@ content: size: 60 placeholder: '' third_party_settings: { } + field_type: + type: chosen_select + weight: 5 + region: content + settings: { } + third_party_settings: { } moderation_state: type: workflow_buttons - weight: 5 + weight: 8 region: content settings: show_current_state: false third_party_settings: { } path: type: path - weight: 4 + weight: 7 region: content settings: { } third_party_settings: { } simple_sitemap: - weight: 11 + weight: 14 region: content settings: { } third_party_settings: { } status: type: boolean_checkbox - weight: 9 + weight: 12 region: content settings: display_label: true @@ -178,7 +192,7 @@ content: placeholder: '' third_party_settings: { } url_redirects: - weight: 6 + weight: 9 region: content settings: { } third_party_settings: { } diff --git a/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.block_content.tags.default.yml b/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.block_content.tags.default.yml new file mode 100644 index 000000000..e900a362b --- /dev/null +++ b/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.block_content.tags.default.yml @@ -0,0 +1,22 @@ +uuid: 3fd5878c-5140-4749-8fed-56048696b0d2 +langcode: en +status: true +dependencies: + config: + - block_content.type.tags + - field.field.block_content.tags.field_selected_resource +id: block_content.tags.default +targetEntityType: block_content +bundle: tags +mode: default +content: + field_selected_resource: + type: entity_reference_label + label: above + settings: + link: true + third_party_settings: { } + weight: 1 + region: content +hidden: + search_api_excerpt: true diff --git a/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.card.yml b/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.card.yml index 61045d25a..ad414c51b 100644 --- a/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.card.yml +++ b/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.card.yml @@ -4,6 +4,7 @@ status: true dependencies: config: - core.entity_view_mode.node.card + - field.field.node.page.field_audience - field.field.node.page.field_category - field.field.node.page.field_external_source - field.field.node.page.field_login_required @@ -12,6 +13,7 @@ dependencies: - field.field.node.page.field_teaser_media - field.field.node.page.field_teaser_text - field.field.node.page.field_teaser_title + - field.field.node.page.field_type - field.field.node.page.layout_builder__layout - node.type.page module: @@ -86,8 +88,10 @@ content: weight: 1 region: content hidden: + field_audience: true field_login_required: true field_metatags: true + field_type: true layout_builder__layout: true links: true search_api_excerpt: true diff --git a/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.condensed.yml b/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.condensed.yml index eb1cb82ce..51e336e30 100644 --- a/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.condensed.yml +++ b/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.condensed.yml @@ -4,6 +4,7 @@ status: true dependencies: config: - core.entity_view_mode.node.condensed + - field.field.node.page.field_audience - field.field.node.page.field_category - field.field.node.page.field_external_source - field.field.node.page.field_login_required @@ -12,6 +13,7 @@ dependencies: - field.field.node.page.field_teaser_media - field.field.node.page.field_teaser_text - field.field.node.page.field_teaser_title + - field.field.node.page.field_type - field.field.node.page.layout_builder__layout - node.type.page module: @@ -81,6 +83,7 @@ content: weight: 2 region: content hidden: + field_audience: true field_category: true field_login_required: true field_metatags: true @@ -88,6 +91,7 @@ hidden: field_teaser_media: true field_teaser_text: true field_teaser_title: true + field_type: true layout_builder__layout: true links: true search_api_excerpt: true diff --git a/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.default.yml b/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.default.yml index af82f6c56..1016c666e 100644 --- a/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.default.yml +++ b/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.default.yml @@ -3,6 +3,7 @@ langcode: en status: true dependencies: config: + - field.field.node.page.field_audience - field.field.node.page.field_category - field.field.node.page.field_external_source - field.field.node.page.field_login_required @@ -11,6 +12,7 @@ dependencies: - field.field.node.page.field_teaser_media - field.field.node.page.field_teaser_text - field.field.node.page.field_teaser_title + - field.field.node.page.field_type - field.field.node.page.layout_builder__layout - node.type.page module: @@ -41,6 +43,38 @@ third_party_settings: entity: layout_builder.entity weight: 0 additional: { } + 3a023761-75c3-4330-8d61-62826da7868a: + uuid: 3a023761-75c3-4330-8d61-62826da7868a + region: content + configuration: + id: 'field_block:node:page:field_audience' + label_display: '0' + context_mapping: + entity: layout_builder.entity + formatter: + type: entity_reference_label + label: above + settings: + link: true + third_party_settings: { } + weight: 2 + additional: { } + ec2bce73-9bae-46cb-9ee3-becb7dd5fa65: + uuid: ec2bce73-9bae-46cb-9ee3-becb7dd5fa65 + region: content + configuration: + id: 'field_block:node:page:field_type' + label_display: '0' + context_mapping: + entity: layout_builder.entity + formatter: + type: entity_reference_label + label: above + settings: + link: true + third_party_settings: { } + weight: 3 + additional: { } third_party_settings: layout_builder_lock: lock: @@ -99,6 +133,11 @@ third_party_settings: - layout_onecol - ys_layout_two_column allowlisted_blocks: + layout_onecol: + all_regions: + 'Lists (Views)': + - 'views_block:popular_resources-block_1' + - 'views_block:resource_tags-block_1' ys_layout_banner: all_regions: 'Inline blocks': @@ -174,7 +213,6 @@ third_party_settings: - Devel - Forms - Help - - 'Lists (Views)' - Menus - System - Webform @@ -224,6 +262,14 @@ content: third_party_settings: { } weight: -20 region: content + field_audience: + type: entity_reference_label + label: above + settings: + link: true + third_party_settings: { } + weight: 3 + region: content field_external_source: type: link label: above @@ -236,6 +282,14 @@ content: third_party_settings: { } weight: 1 region: content + field_type: + type: entity_reference_label + label: above + settings: + link: true + third_party_settings: { } + weight: 4 + region: content hidden: field_category: true field_login_required: true diff --git a/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.list_item.yml b/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.list_item.yml index d9a85409d..e87a0df3f 100644 --- a/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.list_item.yml +++ b/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.list_item.yml @@ -4,6 +4,7 @@ status: true dependencies: config: - core.entity_view_mode.node.list_item + - field.field.node.page.field_audience - field.field.node.page.field_category - field.field.node.page.field_external_source - field.field.node.page.field_login_required @@ -12,6 +13,7 @@ dependencies: - field.field.node.page.field_teaser_media - field.field.node.page.field_teaser_text - field.field.node.page.field_teaser_title + - field.field.node.page.field_type - field.field.node.page.layout_builder__layout - node.type.page module: @@ -86,8 +88,10 @@ content: weight: 1 region: content hidden: + field_audience: true field_login_required: true field_metatags: true + field_type: true layout_builder__layout: true links: true search_api_excerpt: true diff --git a/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.search_result.yml b/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.search_result.yml index e4148b32b..bdc826329 100644 --- a/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.search_result.yml +++ b/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.search_result.yml @@ -4,6 +4,7 @@ status: true dependencies: config: - core.entity_view_mode.node.search_result + - field.field.node.page.field_audience - field.field.node.page.field_category - field.field.node.page.field_external_source - field.field.node.page.field_login_required @@ -12,6 +13,7 @@ dependencies: - field.field.node.page.field_teaser_media - field.field.node.page.field_teaser_text - field.field.node.page.field_teaser_title + - field.field.node.page.field_type - field.field.node.page.layout_builder__layout - node.type.page module: @@ -53,12 +55,14 @@ content: weight: 0 region: content hidden: + field_audience: true field_category: true field_login_required: true field_metatags: true field_tags: true field_teaser_media: true field_teaser_title: true + field_type: true layout_builder__layout: true links: true workflow_buttons: true diff --git a/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.teaser.yml b/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.teaser.yml index 01b3f67a0..2c49a3368 100644 --- a/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.teaser.yml +++ b/web/profiles/custom/yalesites_profile/config/sync/core.entity_view_display.node.page.teaser.yml @@ -4,6 +4,7 @@ status: true dependencies: config: - core.entity_view_mode.node.teaser + - field.field.node.page.field_audience - field.field.node.page.field_category - field.field.node.page.field_external_source - field.field.node.page.field_login_required @@ -12,6 +13,7 @@ dependencies: - field.field.node.page.field_teaser_media - field.field.node.page.field_teaser_text - field.field.node.page.field_teaser_title + - field.field.node.page.field_type - field.field.node.page.layout_builder__layout - node.type.page module: @@ -32,6 +34,7 @@ content: weight: 0 region: content hidden: + field_audience: true field_category: true field_external_source: true field_login_required: true @@ -40,6 +43,7 @@ hidden: field_teaser_media: true field_teaser_text: true field_teaser_title: true + field_type: true layout_builder__layout: true search_api_excerpt: true workflow_buttons: true diff --git a/web/profiles/custom/yalesites_profile/config/sync/field.field.block_content.tags.field_selected_resource.yml b/web/profiles/custom/yalesites_profile/config/sync/field.field.block_content.tags.field_selected_resource.yml new file mode 100644 index 000000000..eafb292bd --- /dev/null +++ b/web/profiles/custom/yalesites_profile/config/sync/field.field.block_content.tags.field_selected_resource.yml @@ -0,0 +1,29 @@ +uuid: c855643b-6959-4864-9b52-9b21b0c92057 +langcode: en +status: true +dependencies: + config: + - block_content.type.tags + - field.storage.block_content.field_selected_resource + - node.type.page +id: block_content.tags.field_selected_resource +field_name: field_selected_resource +entity_type: block_content +bundle: tags +label: 'Selected Resource' +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:node' + handler_settings: + target_bundles: + page: page + sort: + field: _none + direction: ASC + auto_create: false + auto_create_bundle: '' +field_type: entity_reference diff --git a/web/profiles/custom/yalesites_profile/config/sync/field.field.node.page.field_audience.yml b/web/profiles/custom/yalesites_profile/config/sync/field.field.node.page.field_audience.yml new file mode 100644 index 000000000..6e4fc764a --- /dev/null +++ b/web/profiles/custom/yalesites_profile/config/sync/field.field.node.page.field_audience.yml @@ -0,0 +1,29 @@ +uuid: 6f46825e-4502-4eaa-af86-ba12ce501b42 +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_audience + - node.type.page + - taxonomy.vocabulary.page_audience +id: node.page.field_audience +field_name: field_audience +entity_type: node +bundle: page +label: Audience +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:taxonomy_term' + handler_settings: + target_bundles: + page_audience: page_audience + sort: + field: name + direction: asc + auto_create: false + auto_create_bundle: '' +field_type: entity_reference diff --git a/web/profiles/custom/yalesites_profile/config/sync/field.field.node.page.field_type.yml b/web/profiles/custom/yalesites_profile/config/sync/field.field.node.page.field_type.yml new file mode 100644 index 000000000..eddebde66 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/config/sync/field.field.node.page.field_type.yml @@ -0,0 +1,29 @@ +uuid: ecdb95bd-3c25-4264-9c11-666a5625eeec +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_type + - node.type.page + - taxonomy.vocabulary.type +id: node.page.field_type +field_name: field_type +entity_type: node +bundle: page +label: Type +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:taxonomy_term' + handler_settings: + target_bundles: + type: type + sort: + field: name + direction: asc + auto_create: false + auto_create_bundle: '' +field_type: entity_reference diff --git a/web/profiles/custom/yalesites_profile/config/sync/field.storage.block_content.field_selected_resource.yml b/web/profiles/custom/yalesites_profile/config/sync/field.storage.block_content.field_selected_resource.yml new file mode 100644 index 000000000..045fe2fa4 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/config/sync/field.storage.block_content.field_selected_resource.yml @@ -0,0 +1,20 @@ +uuid: 92bf4bef-ac8e-403a-9671-b65131a12c07 +langcode: en +status: true +dependencies: + module: + - block_content + - node +id: block_content.field_selected_resource +field_name: field_selected_resource +entity_type: block_content +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/web/profiles/custom/yalesites_profile/config/sync/field.storage.node.field_audience.yml b/web/profiles/custom/yalesites_profile/config/sync/field.storage.node.field_audience.yml new file mode 100644 index 000000000..2abb03e9b --- /dev/null +++ b/web/profiles/custom/yalesites_profile/config/sync/field.storage.node.field_audience.yml @@ -0,0 +1,20 @@ +uuid: b09e18f3-1d21-4619-b9dd-6c613f16b218 +langcode: en +status: true +dependencies: + module: + - node + - taxonomy +id: node.field_audience +field_name: field_audience +entity_type: node +type: entity_reference +settings: + target_type: taxonomy_term +module: core +locked: false +cardinality: -1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/web/profiles/custom/yalesites_profile/config/sync/field.storage.node.field_type.yml b/web/profiles/custom/yalesites_profile/config/sync/field.storage.node.field_type.yml new file mode 100644 index 000000000..40a7390f5 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/config/sync/field.storage.node.field_type.yml @@ -0,0 +1,20 @@ +uuid: ee9e4acf-7973-43e8-96cb-be14e17bd904 +langcode: en +status: true +dependencies: + module: + - node + - taxonomy +id: node.field_type +field_name: field_type +entity_type: node +type: entity_reference +settings: + target_type: taxonomy_term +module: core +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/web/profiles/custom/yalesites_profile/config/sync/layout_builder_browser.layout_builder_browser_block.resource_tags.yml b/web/profiles/custom/yalesites_profile/config/sync/layout_builder_browser.layout_builder_browser_block.resource_tags.yml new file mode 100644 index 000000000..567b4ebfc --- /dev/null +++ b/web/profiles/custom/yalesites_profile/config/sync/layout_builder_browser.layout_builder_browser_block.resource_tags.yml @@ -0,0 +1,11 @@ +uuid: b90cf842-ff4d-46b4-9e70-45468575d2bb +langcode: en +status: true +dependencies: { } +id: resource_tags +block_id: 'views_block:resource_tags-block_1' +category: advanced +label: 'Resource Tags' +image_path: '' +image_alt: '' +weight: -100 diff --git a/web/profiles/custom/yalesites_profile/config/sync/taxonomy.vocabulary.page_audience.yml b/web/profiles/custom/yalesites_profile/config/sync/taxonomy.vocabulary.page_audience.yml new file mode 100644 index 000000000..80daffd91 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/config/sync/taxonomy.vocabulary.page_audience.yml @@ -0,0 +1,33 @@ +uuid: 7122ff07-0996-419b-be63-e5b6f9b7c6c4 +langcode: en +status: true +dependencies: + module: + - entity_redirect +third_party_settings: + entity_redirect: + redirect: + anonymous: + active: false + destination: default + url: '' + external: '' + add: + active: false + destination: default + url: '' + external: '' + edit: + active: false + destination: default + url: '' + external: '' + delete: + active: false + destination: default + url: '' + external: '' +name: 'Page Audience' +vid: page_audience +description: '' +weight: 0 diff --git a/web/profiles/custom/yalesites_profile/config/sync/taxonomy.vocabulary.type.yml b/web/profiles/custom/yalesites_profile/config/sync/taxonomy.vocabulary.type.yml new file mode 100644 index 000000000..0dedcd1c4 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/config/sync/taxonomy.vocabulary.type.yml @@ -0,0 +1,33 @@ +uuid: c7830d5c-4dd7-42d0-a9cc-e598f956d610 +langcode: en +status: true +dependencies: + module: + - entity_redirect +third_party_settings: + entity_redirect: + redirect: + anonymous: + active: false + destination: default + url: '' + external: '' + add: + active: false + destination: default + url: '' + external: '' + edit: + active: false + destination: default + url: '' + external: '' + delete: + active: false + destination: default + url: '' + external: '' +name: Type +vid: type +description: '' +weight: 0 diff --git a/web/profiles/custom/yalesites_profile/config/sync/views.view.resource_tags.yml b/web/profiles/custom/yalesites_profile/config/sync/views.view.resource_tags.yml new file mode 100644 index 000000000..887b27860 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/config/sync/views.view.resource_tags.yml @@ -0,0 +1,496 @@ +uuid: b5846236-b779-4af6-91ca-3d9dcf899268 +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_audience + - field.storage.node.field_category + - field.storage.node.field_tags + - field.storage.node.field_type + - node.type.page + - taxonomy.vocabulary.tags + content: + - 'taxonomy_term:tags:9233793b-ab3c-445f-9caf-a14f090e971e' + module: + - node + - taxonomy + - user +id: resource_tags +label: 'Resource Tags' +module: views +description: '' +tag: '' +base_table: node_field_data +base_field: nid +display: + default: + id: default + display_title: Default + display_plugin: default + position: 0 + display_options: + title: Tags + fields: + field_audience: + id: field_audience + table: node__field_audience + field: field_audience + relationship: none + group_type: group + admin_label: '' + plugin_id: field + label: Audience + 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: 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: true + group_column: target_id + 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 + field_type: + id: field_type + table: node__field_type + field: field_type + relationship: none + group_type: group + admin_label: '' + plugin_id: field + label: Type + 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: 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: true + group_column: target_id + 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 + field_category: + id: field_category + table: node__field_category + field: field_category + relationship: none + group_type: group + admin_label: '' + plugin_id: field + label: Category + 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: 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: true + group_column: target_id + 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 + field_tags: + id: field_tags + table: node__field_tags + field: field_tags + relationship: none + group_type: group + admin_label: '' + plugin_id: field + label: Tags + 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: 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: true + group_column: target_id + 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 + pager: + type: some + options: + offset: 0 + items_per_page: 1 + 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 + access: + type: perm + options: + perm: 'access content' + cache: + type: tag + options: { } + empty: { } + sorts: + created: + id: created + table: node_field_data + field: created + relationship: none + group_type: group + admin_label: '' + entity_type: node + entity_field: created + plugin_id: date + order: DESC + expose: + label: '' + field_identifier: '' + exposed: false + granularity: second + arguments: + nid: + id: nid + table: node_field_data + field: nid + relationship: none + group_type: group + admin_label: '' + entity_type: node + entity_field: nid + plugin_id: node_nid + default_action: default + exception: + value: all + title_enable: false + title: All + title_enable: false + title: '' + default_argument_type: node + default_argument_options: { } + default_argument_skip_url: false + summary_options: + base_path: '' + count: true + override: false + items_per_page: 25 + summary: + sort_order: asc + number_of_records: 0 + format: default_summary + specify_validation: false + validate: + type: none + fail: 'not found' + validate_options: { } + break_phrase: false + not: false + filters: + status: + id: status + table: node_field_data + field: status + entity_type: node + entity_field: status + plugin_id: boolean + value: '1' + group: 1 + expose: + operator: '' + type: + id: type + table: node_field_data + field: type + entity_type: node + entity_field: type + plugin_id: bundle + value: + page: page + field_tags_target_id: + id: field_tags_target_id + table: node__field_tags + field: field_tags_target_id + relationship: none + group_type: group + admin_label: '' + plugin_id: taxonomy_index_tid + operator: or + value: + - 34 + 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 + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + reduce_duplicates: false + vid: tags + type: textfield + hierarchy: false + limit: true + error_message: true + style: + type: default + options: + grouping: { } + row_class: '' + default_row_class: true + row: + type: fields + options: + default_field_elements: true + inline: + field_audience: field_audience + field_type: field_type + field_category: field_category + field_tags: field_tags + separator: '' + hide_empty: false + query: + type: views_query + options: + query_comment: '' + disable_sql_rewrite: false + distinct: false + replica: false + query_tags: { } + relationships: { } + header: { } + footer: { } + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - user + - 'user.node_grants:view' + - user.permissions + tags: + - 'config:field.storage.node.field_audience' + - 'config:field.storage.node.field_category' + - 'config:field.storage.node.field_tags' + - 'config:field.storage.node.field_type' + block_1: + id: block_1 + display_title: Block + display_plugin: block + position: 1 + display_options: + display_extenders: + metatag_display_extender: + metatags: { } + tokenize: false + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - user + - 'user.node_grants:view' + - user.permissions + tags: + - 'config:field.storage.node.field_audience' + - 'config:field.storage.node.field_category' + - 'config:field.storage.node.field_tags' + - 'config:field.storage.node.field_type' diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/config/install/migrate_plus.migration.campus_group_events.yml b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/config/install/migrate_plus.migration.campus_group_events.yml new file mode 100644 index 000000000..5717d19ad --- /dev/null +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/config/install/migrate_plus.migration.campus_group_events.yml @@ -0,0 +1,196 @@ +uuid: 84aabb96-aabf-421e-a890-c69341363ab9 +langcode: en +status: true +dependencies: { } +id: campus_group_events +class: null +field_plugin_method: null +cck_plugin_method: null +migration_tags: null +migration_group: null +label: 'Campus Group Events' +source: + plugin: campus_group_url + data_fetcher_plugin: http + data_parser_plugin: simple_xml + track_changes: true + urls: 'test.xml' + item_selector: /rss/channel/item + constants: + migration_user_name: event_import + fields: + - + name: event_id + label: 'Event ID' + selector: eventId + - + name: event_title + label: 'Event title' + selector: title + - + name: event_description + label: 'Description' + selector: fullDescription + - + name: event_teaser + label: 'Teaser' + selector: description + - + name: event_image_url + label: 'Event image URL' + selector: eventPhotoFullUrl + - + name: event_url + label: 'Event URL' + selector: eventLink + - + name: event_ics_url + label: Event ICS URL + selector: iCalLink + - + name: event_start_date + label: 'Event Start Date' + selector: eventStartDateTime + - + name: event_end_date + label: 'Event End Date' + selector: eventEndDateTime + - + name: event_tags + label: 'Event Tags' + selector: groupAcronym + - + name: event_category + label: 'Event Category' + selector: category + - + name: event_type + label: 'Event Type' + selector: eventType + - + name: ticket_cost + label: 'Ticket cost' + selector: eventLink + - + name: event_status + label: 'Event status' + selector: locationType + - + name: event_start_datetime + label: 'Event Start Date time' + selector: eventStartDateTime + - + name: event_end_datetime + label: 'Event End Date time' + selector: eventEndDateTime + - + name: event_topics + label: Event Topics + selector: eventTopics + - + name: event_group + label: Event Group + selector: group + ids: + event_id: + # This would be an int, but it is too long for the DB + type: string + +process: + title: event_title + field_event_description/value: event_description + field_event_description/format: + plugin: default_value + default_value: basic_html + field_teaser_text/value: event_teaser + field_teaser_text/format: + plugin: default_value + default_value: heading_html + field_localist_event_url/uri: event_url + field_localist_event_image_url/uri: event_image_url + field_localist_ics_url/uri: event_ics_url + field_event_cta/uri: event_url + field_event_date/value: + plugin: format_date + source: event_start_date + from_format: 'Y-m-d\TH:i:s.0000000P' + to_format: 'U' + field_event_date/end_value: + plugin: format_date + source: event_end_date + from_format: 'Y-m-d\TH:i:s.0000000P' + to_format: 'U' + field_event_cta/title: + plugin: default_value + default_value: "More details" + field_tags: + plugin: entity_generate + entity_type: taxonomy_term + value_key: name + bundle_key: vid + bundle: tags + source: event_tags + field_localist_event_type: + plugin: entity_generate + entity_type: taxonomy_term + value_key: name + bundle_key: vid + bundle: localist_event_type + source: event_type + field_category: + plugin: entity_generate + entity_type: taxonomy_term + value_key: name + bundle_key: vid + bundle: event_category + source: event_category + field_localist_group: + plugin: entity_generate + entity_type: taxonomy_term + value_key: name + bundle_key: vid + bundle: event_groups + source: event_group + field_event_status: + plugin: entity_generate + entity_type: taxonomy_term + value_key: name + bundle_key: vid + bundle: event_status + source: event_status + field_event_topics: + - + plugin: explode + source: event_topics + delimiter: ',' + - + plugin: callback + callable: trim + - + plugin: entity_generate + entity_type: taxonomy_term + bundle: event_topics + bundle_key: vid + value_key: name + ignore_case: true + field_ticket_cost: ticket_cost + uid: + plugin: entity_generate + source: constants/migration_user_name + value_key: name + entity_type: user + default_value: + mail: event_import@yalesites.edu +destination: + plugin: 'entity:node' + default_bundle: event + overwrite_properties: + - title + - field_localist_id + - field_event_description + - field_event_room + - field_localist_event_url + - field_localist_event_image_url + - field_localist_event_image_alt + - field_localist_ics_url +migration_dependencies: { } diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/src/CampusGroupManager.php b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/src/CampusGroupManager.php new file mode 100644 index 000000000..9bb4185ad --- /dev/null +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/src/CampusGroupManager.php @@ -0,0 +1,387 @@ +localistConfig = $config_factory->get('ys_localist.settings'); + $this->endpointBase = $this->localistConfig->get('localist_endpoint'); + $this->httpClient = $http_client; + $this->entityTypeManager = $entity_type_manager; + $this->migrationManager = $migration_manager; + $this->moduleHandler = $module_handler; + $this->time = $time; + $this->messenger = $messenger; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('config.factory'), + $container->get('http_client'), + $container->get('entity_type.manager'), + $container->get('plugin.manager.migration'), + $container->get('module_handler'), + $container->get('datetime.time'), + $container->get('messenger'), + ); + } + + /** + * Gets the endpoint URLs for migration. + * + * @param string $endpointType + * The endpoint to fetch. + * + * @return array + * An array of endpoint URLs with dynamic parameters. + */ + public function getEndpointUrls($endpointType) { + $endpointsWithParams = []; + + switch ($endpointType) { + case 'events': + // Group ID is required. + $groupId = $this->getGroupTaxonomyEntity(); + + if ($groupId) { + $eventsURL = "$this->endpointBase/api/2/events"; + + // Gets the latest version from the API by changing the URL each time. + $version = time(); + + // Localist supports only getting 365 days from today. + $endDate = date('Y-m-d', strtotime("+364 days")); + + $endpointsWithParams[] = "$eventsURL?end=$endDate&group_id=$groupId&v=$version&pp=100"; + } + + break; + + case 'places': + $placesURL = "$this->endpointBase/api/2/places?pp=100"; + $endpointsWithParams = $this->getMultiPageUrls($placesURL); + + break; + + case 'filters': + $endpointsWithParams[] = "$this->endpointBase/api/2/events/filters"; + + break; + + case 'groups': + $groupsURL = "$this->endpointBase/api/2/groups?pp=100"; + $endpointsWithParams = $this->getMultiPageUrls($groupsURL); + + break; + + case 'photos': + $endpointsWithParams[] = "$this->endpointBase/api/2/photos"; + + break; + + case 'tickets': + $endpointsWithParams[] = "$this->endpointBase/api/2/events"; + + break; + + default: + $endpointsWithParams = []; + break; + } + return $endpointsWithParams; + } + + /** + * Gets the total number of pages from a Localist API endpoint. + * + * @param string $url + * The endpoint to fetch. + * + * @return array + * Endpoint URLs with pages attached. + */ + private function getMultiPageUrls($url) { + $endpointUrls = []; + $response = $this->httpClient->get($url); + $data = json_decode($response->getBody(), TRUE); + + $i = 1; + while ($i <= $data['page']['total']) { + $endpointUrls[] = "$url&page=$i"; + $i++; + } + + return $endpointUrls; + } + + /** + * Gets an entity object for the selected group taxonomy term. + * + * @return array + * Endpoint URLs with pages attached. + */ + private function getGroupTaxonomyEntity() { + $groupId = NULL; + $groupTermId = $this->localistConfig->get('localist_group'); + if ($groupTermId) { + $term = $this->entityTypeManager->getStorage('taxonomy_term')->load($groupTermId); + $groupId = ($term) ? $term->field_localist_group_id->value : NULL; + } + + return $groupId; + } + + /** + * Runs all Localist migrations. + * + * @return array + * Array of status of all migrations run. + */ + public function runAllMigrations() { + if ($this->getEndpointUrls('events')) { + foreach (self::LOCALIST_MIGRATIONS as $migration) { + $this->runMigration($migration); + $messageData[$migration] = [ + 'imported' => $this->getMigrationStatus($migration), + ]; + } + return $messageData; + } + else { + $this->messenger()->addError('Localist endpoint not configured correctly. No events imported.'); + } + + } + + /** + * Runs specific migration. + * + * @param string $migration + * The migration ID. + */ + public function runMigration($migration) { + // Loop over the list of the migrations and check if they require + // execution. + // Prevent non-existent migrations from breaking cron. + $migrationInstance = $this->migrationManager->createInstance($migration); + if ($migrationInstance) { + // Check if the migration status is IDLE, if not, make it so. + $status = $migrationInstance->getStatus(); + if ($status !== MigrationInterface::STATUS_IDLE) { + $migrationInstance->setStatus(MigrationInterface::STATUS_IDLE); + } + + /* + * @todo Possibly implement the following flags, if needed. + * Runs migration with the --update flag. + * $migration_update = $migration->getIdMap(); + * $migration_update->prepareUpdate(); + * Runs migration with the --sync flag. + * The problem here is if editor adds layout builder, this will wipe those + * changes out before recreating. So, this not be a good idea. + * $migrationInstance->set('syncSource', TRUE); + */ + + $message = new MigrateMessage(); + $executable = new MigrateExecutable($migrationInstance, $message); + $executable->import(); + + /* If using migrate_plus module, update the migrate_last_imported value + * for the migration. + */ + + if ($this->moduleHandler->moduleExists('migrate_plus')) { + $migrate_last_imported_store = $this->keyValue('migrate_last_imported'); + $migrate_last_imported_store->set($migrationInstance->id(), round($this->time->getCurrentMicroTime() * 1000)); + } + } + } + + /** + * Gets the migration status such as number of items imported. + * + * @return int + * For now, just the number of items imported. + */ + public function getMigrationStatus($migration_id) { + $migration = $this->migrationManager->createInstance($migration_id); + $map = $migration->getIdMap(); + $imported = $map->importedCount(); + return $imported; + } + + /** + * Checks the group endpoint to make sure we are receiving a JSON feed. + */ + public function checkGroupsEndpoint() { + $returnVal = FALSE; + if ($endpoint = $this->localistConfig->get('localist_endpoint')) { + $endpointUrl = $endpoint . "/api/2/groups"; + try { + $response = $this->httpClient->get($endpointUrl); + $returnVal = str_contains($response->getHeader("Content-Type")[0], 'json') ? TRUE : FALSE; + } + catch (\Throwable $th) { + + } + + } + + return $returnVal; + + } + + /** + * When Localist is first installed, remove the old terms for experiences. + */ + public function removeOldExperiences() { + $termsToRemove = [ + 'In-person', + 'Online', + 'Hybrid', + ]; + + foreach ($termsToRemove as $term) { + $terms = $this->entityTypeManager + ->getStorage('taxonomy_term') + ->loadByProperties(['name' => $term, 'vid' => 'event_type']); + if ($terms) { + foreach ($terms as $term) { + $term->delete(); + } + } + } + } + + /** + * Returns ticket info for a given event ID. + */ + public function getTicketInfo($eventId) { + $ticketData = []; + $response = NULL; + $ticketEndpoint = $this->getEndpointUrls('tickets'); + $version = time(); + $url = "$ticketEndpoint[0]/$eventId/tickets?v=$version"; + try { + $response = $this->httpClient->get($url); + } + catch (\Throwable $th) { + } + + if ($response) { + $data = json_decode($response->getBody()->getContents(), TRUE); + foreach ($data['tickets'] as $ticket) { + $ticketData[] = [ + 'name' => $ticket['ticket']['name'], + 'desc' => $ticket['ticket']['description'], + 'id' => $ticket['ticket']['id'], + 'price' => $ticket['ticket']['price'], + ]; + } + } + return $ticketData; + } + +} diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/src/Form/CampusGroupSettings.php b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/src/Form/CampusGroupSettings.php new file mode 100644 index 000000000..725c75e99 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/src/Form/CampusGroupSettings.php @@ -0,0 +1,109 @@ +config('ys_campus_group.settings'); + + $form['enable_campus_group_sync'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Enable Campus Group sync'), + '#description' => $this->t('Once enabled, Campus Group data will sync events for the selected group roughly every hour.'), + '#default_value' => $config->get('enable_campus_group_sync') ?: FALSE, + ]; + + $form['campus_group_endpoint'] = [ + '#type' => 'url', + '#required' => TRUE, + '#title' => $this->t('Campus Group endpoint base URL'), + '#description' => $this->t('Ex: https://yaleconnect.yale.edu'), + '#default_value' => $config->get('campus_group_endpoint') ?: 'https://yaleconnect.yale.edu', + ]; + $form['campus_group_future_days'] = [ + '#type' => 'textfield', + '#required' => TRUE, + '#title' => $this->t('Future number of days'), + '#default_value' => $config->get('campus_group_future_days') ?: 120, + '#description' => $this->t('Enter the number of future days'), + ]; + $form['campus_group_groupids'] = [ + '#type' => 'textfield', + '#required' => TRUE, + '#title' => $this->t('Group ids'), + '#default_value' => $config->get('campus_group_groupids'), + '#description' => $this->t('Enter the group ids comman seperated'), + ]; + $form['campus_group_header'] = [ + '#type' => 'details', + '#title' => $this->t('API Header Info'), + '#open' => TRUE, + ]; + $form['campus_group_header']['campus_group_api_useragent'] = [ + '#type' => 'textfield', + '#required' => TRUE, + '#title' => $this->t('API User Agent'), + '#default_value' => $config->get('campus_group_api_useragent'), + '#description' => $this->t('Enter the user agent used in api.'), + ]; + $form['campus_group_header']['campus_group_api_secret'] = [ + '#type' => 'textarea', + '#required' => TRUE, + '#title' => $this->t('API Secret'), + '#default_value' => $config->get('campus_group_api_secret'), + '#description' => $this->t('Enter the API Secret'), + ]; + $form['campus_group_header']['campus_group_api_cookie'] = [ + '#type' => 'textarea', + '#required' => TRUE, + '#title' => $this->t('API Cookie'), + '#default_value' => $config->get('campus_group_api_cookie'), + '#description' => $this->t('Enter the API cookie'), + ]; + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + + $this->configFactory->getEditable('ys_campus_group.settings') + // Set the submitted configuration setting. + ->set('enable_campus_group_sync', $form_state->getValue('enable_campus_group_sync')) + ->set('campus_group_endpoint', rtrim($form_state->getValue('campus_group_endpoint'), "/")) + ->set('campus_group_future_days', $form_state->getValue('campus_group_future_days')) + ->set('campus_group_groupids', $form_state->getValue('campus_group_groupids')) + ->set('campus_group_api_useragent', $form_state->getValue('campus_group_api_useragent')) + ->set('campus_group_api_secret', $form_state->getValue('campus_group_api_secret')) + ->set('campus_group_api_cookie', $form_state->getValue('campus_group_api_cookie')) + ->save(); + + parent::submitForm($form, $form_state); + } + +} diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/src/MetaFieldsManager.php b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/src/MetaFieldsManager.php new file mode 100644 index 000000000..5b2cfa4dc --- /dev/null +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/src/MetaFieldsManager.php @@ -0,0 +1,299 @@ +dateFormatter = $date_formatter; + $this->entityTypeManager = $entity_type_manager; + $this->localistManager = $localist_manager; + $this->calendarLink = new CalendarLinkTwigExtension(); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $container->get('date.formatter'), + $container->get('entity_type.manager'), + $container->get('ys_localist.manager'), + ); + } + + /** + * Calculates if an event is set to all day. + * + * Code copied from contrib module smart_date/src/SmartDateTrait.php because + * with version 3.6 of smart_date and PHP 8.1, calling static traits + * in this way is deprecated. Patches to fix failed to apply. + */ + private function isAllDay($start_ts, $end_ts, $timezone = NULL) { + if ($timezone) { + if ($timezone instanceof \DateTimeZone) { + // If provided as an object, convert to a string. + $timezone = $timezone->getName(); + } + // Apply a specific timezone provided. + $default_tz = date_default_timezone_get(); + date_default_timezone_set($timezone); + } + // Format timestamps to predictable format for comparison. + $temp_start = date('H:i', $start_ts); + $temp_end = date('H:i', $end_ts); + if ($timezone) { + // Revert to previous timezone. + date_default_timezone_set($default_tz); + } + if ($temp_start == '00:00' && $temp_end == '23:59') { + return TRUE; + } + return FALSE; + } + + /** + * Returns filter values for a given filter field. + * + * @param \Drupal\node\NodeInterface $node + * The node object. + * @param string $filterField + * The field machine name. + * + * @return array + * An array of filter names and URL to visit the taxonomy term view page. + */ + private function getFilterValues($node, $filterField) { + $filterValues = []; + if ($node->$filterField) { + $values = $node->$filterField->getValue(); + if ($values) { + foreach ($values as $value) { + /** @var \Drupal\taxonomy\Entity\Term $typeInfo */ + $typeInfo = $this->entityTypeManager->getStorage('taxonomy_term')->load($value['target_id']); + $name = $url = ""; + if ($typeInfo) { + $name = $typeInfo->getName(); + $url = $typeInfo->toUrl()->toString(); + } + $filterValues[] = [ + 'name' => $name, + 'url' => $url, + ]; + } + } + } + return $filterValues; + } + + /** + * Gets event all fields. + */ + public function getEventData($node) { + if (!($node instanceof NodeInterface)) { + return []; + } + + // Event basic fields. + $localistId = $node->field_localist_id->first() ? $node->field_localist_id->first()->getValue()['value'] : NULL; + $experience = $this->getFilterValues($node, 'field_localist_event_experience'); + $eventTypes = $this->getFilterValues($node, 'field_localist_event_type'); + $eventAudience = $this->getFilterValues($node, 'field_event_audience'); + $eventTopics = $this->getFilterValues($node, 'field_event_topics'); + $ticketLink = $node->field_ticket_registration_url->first() ? $node->field_ticket_registration_url->first()->getValue()['uri'] : NULL; + $ticketCost = $node->field_ticket_cost->first() ? $node->field_ticket_cost->first()->getValue()['value'] : NULL; + $costButtonText = $ticketCost ? 'Buy Tickets' : 'Register'; + $description = $node->field_event_description->first() ? $node->field_event_description->first()->getValue()['value'] : NULL; + $externalEventWebsiteUrl = ($node->field_event_cta->first()) ? Url::fromUri($node->field_event_cta->first()->getValue()['uri'])->toString() : NULL; + $externalEventWebsiteTitle = ($node->field_event_cta->first()) ? $node->field_event_cta->first()->getValue()['title'] : NULL; + $localistImageUrl = ($node->field_localist_event_image_url->first()) ? Url::fromUri($node->field_localist_event_image_url->first()->getValue()['uri'])->toString() : NULL; + $localistImageAlt = $node->field_localist_event_image_alt->first() ? $node->field_localist_event_image_alt->first()->getValue()['value'] : NULL; + $hasRegister = $node->field_localist_register_enabled->first() ? (bool) $node->field_localist_register_enabled->first()->getValue()['value'] : FALSE; + $localistUrl = ($node->field_localist_event_url->first()) ? Url::fromUri($node->field_localist_event_url->first()->getValue()['uri'])->toString() : NULL; + $streamUrl = ($node->field_stream_url->first()) ? Url::fromUri($node->field_stream_url->first()->getValue()['uri'])->toString() : NULL; + $streamEmbedCode = $node->field_stream_embed_code->first() ? $node->field_stream_embed_code->first()->getValue()['value'] : NULL; + + // Localist register ticket changes. + $localistRegisterTickets = $hasRegister ? $this->localistManager->getTicketInfo($localistId) : NULL; + if ($localistRegisterTickets) { + $costButtonText = 'Register'; + foreach ($localistRegisterTickets as $ticketInfo) { + if ($ticketInfo['price'] > 0) { + $costButtonText = 'Buy Tickets'; + } + $ticketCost[] = $ticketInfo['name'] . ": $" . $ticketInfo['price']; + } + $ticketLink = $localistUrl . "#tickets=1"; + } + else { + $hasRegister = FALSE; + } + + // Dates. + $dates = []; + if ($dates = $node->field_event_date->getValue()) { + foreach ($dates as $key => $date) { + $dates[$key]['formatted_start_date'] = $this->dateFormatter->format($date['value'], 'event_date_only'); + $dates[$key]['formatted_start_time'] = $this->dateFormatter->format($date['value'], 'event_time_only'); + $dates[$key]['formatted_end_date'] = $this->dateFormatter->format($date['end_value'], 'event_date_only'); + $dates[$key]['formatted_end_time'] = $this->dateFormatter->format($date['end_value'], 'event_time_only'); + $dates[$key]['original_start'] = $date['value']; + $dates[$key]['original_end'] = $date['end_value']; + $dates[$key]['is_all_day'] = $this->isAllDay($date['value'], $date['end_value']); + // Remove older dates. + if ($date['end_value'] < time()) { + unset($dates[$key]); + } + } + // Sort dates - first date is next upcoming date. + asort($dates); + } + + // Teaser responsive image. + $teaserMediaRender = []; + $teaserMediaId = ($node->field_teaser_media->first()) ? $node->field_teaser_media->getValue()[0]['target_id'] : NULL; + if ($teaserMediaId) { + /** @var Drupal\media\Entity\Media $teaserMedia */ + if ($teaserMedia = $this->entityTypeManager->getStorage('media')->load($teaserMediaId)) { + /** @var Drupal\file\FileStorage $fileEntity */ + $fileEntity = $this->entityTypeManager->getStorage('file'); + $teaserImageFileUri = $fileEntity->load($teaserMedia->field_media_image->target_id)->getFileUri(); + + $teaserMediaRender = [ + '#type' => 'responsive_image', + '#responsive_image_style_id' => 'card_featured_3_2', + '#uri' => $teaserImageFileUri, + '#attributes' => [ + 'alt' => $teaserMedia->get('field_media_image')->first()->get('alt')->getValue(), + ], + ]; + } + } + + // Place info. + $place = []; + if ($placeRef = $node->field_event_place->first()) { + /** @var \Drupal\taxonomy\Entity\Term $placeInfo */ + $placeInfo = $this->entityTypeManager->getStorage('taxonomy_term')->load($placeRef->getValue()['target_id']); + if ($placeInfo) { + $place = [ + 'name' => $placeInfo->getName(), + 'address' => $placeInfo->field_address->address_line1 ?? NULL, + 'city' => $placeInfo->field_address->locality ?? NULL, + 'state' => $placeInfo->field_address->administrative_area ?? NULL, + 'postal_code' => $placeInfo->field_address->postal_code ?? NULL, + 'country_code' => $placeInfo->field_address->country_code ?? NULL, + 'latitude' => $placeInfo->field_latitude->first() ? $placeInfo->field_latitude->first()->getValue()['value'] : NULL, + 'longitude' => $placeInfo->field_longitude->first() ? $placeInfo->field_longitude->first()->getValue()['value'] : NULL, + ]; + } + } + + /* + * ICS URL. + * + * If a Localist ICU url exists, use it. If not, calculate from Drupal date. + */ + $icsUrl = $node->field_localist_ics_url->first() ? $node->field_localist_ics_url->first()->getValue()['uri'] : NULL; + if (!$icsUrl && $dates) { + // Dates might not be 0-based. + $firstDate = reset($dates); + $tz = new \DateTimeZone('America/New_York'); + $date = new \DateTime(); + $start = $date->createFromFormat('U', $firstDate['value'], $tz); + $end = $date->createFromFormat('U', $firstDate['end_value'], $tz); + + /* Note one additional argument at the end of this function can create an + * address in the ICS file. + * @see calendar_link/src/Twig/CalendarLinkTwigExtension.php + */ + $icsUrl = $this->calendarLink->calendarLink( + 'ics', + $node->getTitle(), + $start, + $end, + $firstDate['is_all_day'], + $node->toUrl()->setAbsolute()->toString() + ); + } + + return [ + 'title' => $node->getTitle(), + 'dates' => $dates, + 'ics' => $icsUrl, + 'canonical_url' => $node->toUrl()->setAbsolute()->toString(), + 'experience' => $experience, + 'ticket_url' => $ticketLink, + 'ticket_cost' => $ticketCost, + 'description' => $description, + 'external_website_url' => $externalEventWebsiteUrl, + 'external_website_title' => $externalEventWebsiteTitle, + 'localist_image_url' => $localistImageUrl, + 'localist_image_alt' => $localistImageAlt, + 'teaser_media' => $teaserMediaRender, + 'place_info' => $place, + 'event_types' => $eventTypes, + 'event_audience' => $eventAudience, + 'event_topics' => $eventTopics, + 'has_register' => $hasRegister, + 'cost_button_text' => $costButtonText, + 'localist_url' => $localistUrl, + 'stream_url' => $streamUrl, + 'stream_embed_code' => $streamEmbedCode, + ]; + } + +} diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/src/Plugin/migrate/source/CampusGroupUrl.php b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/src/Plugin/migrate/source/CampusGroupUrl.php new file mode 100644 index 000000000..a7dc7995a --- /dev/null +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/src/Plugin/migrate/source/CampusGroupUrl.php @@ -0,0 +1,41 @@ +getEditable('ys_campus_group.settings'); + $url = $config->get('campus_group_endpoint'); + $groups = $config->get('campus_group_groupids'); + $token = $config->get('campus_group_api_secret'); + $cookie = $config->get('campus_group_api_cookie'); + $agent = $config->get('campus_group_api_useragent'); + $days = $config->get('campus_group_future_days'); + + if (empty($headers)) { + $headers['User-Agent'] = $agent; + $headers['X-CG-API-Secret'] = $token; + $headers['Set-Cookie'] = $cookie; + } + + $configuration['headers'] = $headers; + $configuration['urls'] = $url . '?future_day_range=' . $days . '&group_ids=' . $groups; + // Run the parent constructor. + parent::__construct($configuration, $plugin_id, $plugin_definition, $migration); + } + +} diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/ys_campus_group.info.yml b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/ys_campus_group.info.yml new file mode 100644 index 000000000..b829ce139 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/ys_campus_group.info.yml @@ -0,0 +1,9 @@ +name: 'YS Campus Group' +type: module +description: 'Provides integration with the Campus Group Event Feeds' +package: YaleSites +core_version_requirement: ^10 +dependencies: + - drupal:migrate + - migrate_plus:migrate_plus + - migrate_tools:migrate_tools diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/ys_campus_group.links.menu.yml b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/ys_campus_group.links.menu.yml new file mode 100644 index 000000000..20e1fc623 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/ys_campus_group.links.menu.yml @@ -0,0 +1,6 @@ +ys_campus_group.settings: + title: 'Campus Group settings' + description: 'Configure Campus Group sync settings' + route_name: ys_campus_group.settings + parent: ys_core.admin_yalesites + weight: 0 diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/ys_campus_group.module b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/ys_campus_group.module new file mode 100644 index 000000000..dd09701d5 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/ys_campus_group.module @@ -0,0 +1,29 @@ +get('enable_campus_group_sync')) { + + $state = \Drupal::state(); + + $next_execution_time = $state->get("campus_group_migrations", 0); + $current_time = \Drupal::time()->getRequestTime(); + if ($current_time > $next_execution_time) { + $state->set("campus_group_migrations", $current_time + 3600); + $process = new Process('drush mrs campus_group_events'); + $process->run(); + $process = new Process('drush mim campus_group_events'); + $process->run(); + } + } +} diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/ys_campus_group.permissions.yml b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/ys_campus_group.permissions.yml new file mode 100644 index 000000000..189c66eb6 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/ys_campus_group.permissions.yml @@ -0,0 +1,4 @@ +# Permission to manage YaleSites Campus Group. +yalesites manage campus_group: + title: 'Manage YaleSites Campus Group' + description: 'Set and change YaleSites Campus Group settings.' diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/ys_campus_group.routing.yml b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/ys_campus_group.routing.yml new file mode 100644 index 000000000..5af8079d2 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_campus_group/ys_campus_group.routing.yml @@ -0,0 +1,7 @@ +ys_campus_group.settings: + path: '/admin/yalesites/campus_group' + defaults: + _form: '\Drupal\ys_campus_group\Form\CampusGroupSettings' + _title: 'Campus Group Settings' + requirements: + _permission: 'yalesites manage campus_group'