diff --git a/sandbox.md b/sandbox.md new file mode 100644 index 00000000..294f6453 --- /dev/null +++ b/sandbox.md @@ -0,0 +1,56 @@ +# Sandbox Environment + +## Description + +The `sandbox` branch creates a long-living multidev that provides a permanently available sandbox environment that mirrors production where editors can safely practice and use the CMS without fear of messing up the live site. + +This environment can be used for guided training classes, self learning, or experimentation, etc. + +## Environment Updates + +### Code Syncing + +This environment should be a replica of the live site so it needs to be updated as part of the deployment process in order to stay in sync with the live site. + +This happens automatically thanks to a Pantheon Quicksilver script that runs on deployments to Live and triggers a GitHub action that rebases the sandbox branch with master. + +If you need to do this manually, run these commands to update this branch: + +``` +git checkout sandbox +git rebase origin/master +git push -f +``` + +If the master branch is already ahead of the Live site, you'll need to find the commit ID belonging to the Live site deployment. This can be found in the Code section of the Pantheon dashboard. (Ignore the first "CircleCI deployment" commit—it's the second commit ID you want.) Use this rebase command instead of the above one: `git rebase ` + +### Content Syncing + +The database content also needs to be periodically updated by cloning the database from Live. (Please note that this will destroy any existing "test content" previously created on the site.) + +This happens automatically thanks to a CircleCI trigger that is scheduled to run every Monday morning. This runs the "Update Sandbox Database" CircleCI workflow which executes a Terminus command to clone the Live database to Sandbox, runs `drush deploy`, reindexes Solr, and executes a Percy test that adds the sandbox alert notification to the site. + +If you need to do this manually, follow these steps: + +1. Run `lando terminus env:clone-content employees.live sandbox --db-only` +2. Run `lando terminus drush employees.sandbox deploy` +3. Reindex the Solr index(es) +4. Create and publish an informational `Sandbox Site` alert with the following text: + +```This sandbox site is a copy of employees.portland.gov and is intended to provide a safe environment for editor training classes, self learning, or experimentation, etc. Changes made here will not affect the live site and cannot be imported into the live site.``` + +## Sandbox Branch Code Changes + +This branch should only have one code change from the `master` branch: +* `sandbox.md` (This file) + +Sometimes due to certain types of code changes in master, the automated rebase that keeps this branch's code up to date with master doesn't work perfectly and this branch ends up with inadvertent additional code changes to other files besides `sandbox.md`. Sometimes these extra changes will cause Sandbox builds to fail. + +If the Sandbox PR in Github shows that there are more than one files changed, you need to do the following manual cleaup steps in VS Code to remove these extraneous code changes: + +1. Run `git checkout sandbox` +2. Run `git pull --rebase` +3. In the VS Code source control panel, click the … "More actions" icon and select Commit->Undo Last Commit +4. The source control panel will now show all of the changed files under the "Staged Changes" section. Click the — icon next to each file to unstage all changes except `sandbox.md`. This moves the changed files to the "Changes" section. +5. Click the ↺ icon to discard all of the changes in the "Changes" section. This should leave the future commit with only one staged change: `sandbox.md`. Commit the change. +6. Run `git push -f` \ No newline at end of file diff --git a/web/modules/custom/portland_groups/src/Controller/PortlandGroupContentController.php b/web/modules/custom/portland_groups/src/Controller/PortlandGroupContentController.php new file mode 100644 index 00000000..02355ad1 --- /dev/null +++ b/web/modules/custom/portland_groups/src/Controller/PortlandGroupContentController.php @@ -0,0 +1,102 @@ +entityTypeManager->getStorage('node_type'); + $page_bundles = $this->addPageBundles($group, $create_mode); + // NOTE: ksort is working here, but bundle types are still displayed out of order. + // there must be some other sorting process that occurs after this point. + ksort($page_bundles); + // we need the $build['#bundles'] array to be sorted the same as $page_bundles, but it's + // being handed to us sorted by plugin_id, which doens't map well to the bundle machine names. + // we need to build a new array based on the foreach order below. + $new_bundles = []; + foreach ($page_bundles as $plugin_id => $bundle_name) { + // Don't process Media types. They are handled by PortlanMediaController next door. + if(strpos($plugin_id, 'group_media:') === 0) { + unset($build['#bundles'][$bundle_name]); + continue; + } + if (!empty($build['#bundles'][$bundle_name])) { + $plugin = $group->getGroupType()->getContentPlugin($plugin_id); + $bundle_label = $storage_handler->load($plugin->getEntityBundle())->label(); + $bundle_id = $storage_handler->load($plugin->getEntityBundle())->id(); + $bundle_desc = \Drupal::config('node.type.' . $bundle_id)->get('description'); + $t_args = ['%node_type' => $bundle_label]; + + $new_bundles[$bundle_name] = $build['#bundles'][$bundle_name]; + $new_bundles[$bundle_name]['label'] = $bundle_label; + $new_bundles[$bundle_name]['description'] = $bundle_desc; + // build custom link text; this overrides the link text created in the GroupNodeDeriver + $new_bundles[$bundle_name]['add_link']->setText(t('Add ' . $bundle_label)); + } + } + + $build['#bundles'] = $new_bundles; + return $build; + } + + /** + * The _title_callback for the entity.group_content.create_form route. + * + * @param \Drupal\group\Entity\GroupInterface $group + * The group to create the group content in. + * @param string $plugin_id + * The group content enabler to create content with. + * + * @return string + * The page title. + */ + public function createFormTitle(GroupInterface $group, $plugin_id) { + /** @var \Drupal\group\Plugin\GroupContentEnablerInterface $plugin */ + $plugin = $group->getGroupType()->getContentPlugin($plugin_id); + $entity_type = $plugin->getEntityTypeId(); + switch ($entity_type) { + case "media": + $content_type = MediaType::load($plugin->getEntityBundle()); + break; + case "node": + $content_type = NodeType::load($plugin->getEntityBundle()); + break; + default: + $content_type = "undefined"; + } + $return = $this->t('Create @name in @group', ['@name' => $content_type->label(), '@group' => $group->label()]); + return $return; + } +} diff --git a/web/sites/default/config/field.field.group.employee.field_has_contracts.yml b/web/sites/default/config/field.field.group.employee.field_has_contracts.yml new file mode 100644 index 00000000..e094ee35 --- /dev/null +++ b/web/sites/default/config/field.field.group.employee.field_has_contracts.yml @@ -0,0 +1,23 @@ +uuid: 26523f2b-d87d-4147-8cef-aec58afcf91c +langcode: en +status: true +dependencies: + config: + - field.storage.group.field_has_contracts + - group.type.employee +id: group.employee.field_has_contracts +field_name: field_has_contracts +entity_type: group +bundle: employee +label: 'Has Contracts' +description: '' +required: false +translatable: false +default_value: + - + value: 0 +default_value_callback: '' +settings: + on_label: 'Yes' + off_label: 'No' +field_type: boolean diff --git a/web/sites/default/config/field.storage.group.field_has_contracts.yml b/web/sites/default/config/field.storage.group.field_has_contracts.yml new file mode 100644 index 00000000..15dc4669 --- /dev/null +++ b/web/sites/default/config/field.storage.group.field_has_contracts.yml @@ -0,0 +1,22 @@ +uuid: 03df5b6a-2f36-41fc-9241-7f502a0024c4 +langcode: en +status: true +dependencies: + module: + - field_permissions + - group +third_party_settings: + field_permissions: + permission_type: custom +id: group.field_has_contracts +field_name: field_has_contracts +entity_type: group +type: boolean +settings: { } +module: core +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/web/sites/default/config/group.role.employee-1ab877bcd.yml b/web/sites/default/config/group.role.employee-1ab877bcd.yml new file mode 100644 index 00000000..00be6f56 --- /dev/null +++ b/web/sites/default/config/group.role.employee-1ab877bcd.yml @@ -0,0 +1,17 @@ +uuid: b9f42175-d143-4db1-856e-43ab16a7cfd4 +langcode: en +status: true +dependencies: + config: + - group.type.employee + enforced: + config: + - user.role.content_lead +id: employee-1ab877bcd +label: 'Content Lead' +weight: -7 +internal: true +audience: outsider +group_type: employee +permissions_ui: false +permissions: { } diff --git a/web/sites/default/config/group.role.employee-3e5cf4b4d.yml b/web/sites/default/config/group.role.employee-3e5cf4b4d.yml new file mode 100644 index 00000000..b23472cb --- /dev/null +++ b/web/sites/default/config/group.role.employee-3e5cf4b4d.yml @@ -0,0 +1,17 @@ +uuid: f8a46374-5d12-4931-abe3-4ecc75459576 +langcode: en +status: true +dependencies: + config: + - group.type.employee + enforced: + config: + - user.role.311_support_agent +id: employee-3e5cf4b4d +label: '311 Support Agent' +weight: -4 +internal: true +audience: outsider +group_type: employee +permissions_ui: false +permissions: { } diff --git a/web/sites/default/config/group.role.employee-631a7fe0a.yml b/web/sites/default/config/group.role.employee-631a7fe0a.yml new file mode 100644 index 00000000..57c86c5d --- /dev/null +++ b/web/sites/default/config/group.role.employee-631a7fe0a.yml @@ -0,0 +1,17 @@ +uuid: db73e9e0-34fe-4118-8821-a6cb5e41fdd2 +langcode: en +status: true +dependencies: + config: + - group.type.employee + enforced: + config: + - user.role.311_lead +id: employee-631a7fe0a +label: '311 Lead' +weight: -3 +internal: true +audience: outsider +group_type: employee +permissions_ui: false +permissions: { } diff --git a/web/sites/default/config/group.role.employee-855450a16.yml b/web/sites/default/config/group.role.employee-855450a16.yml new file mode 100644 index 00000000..2495af86 --- /dev/null +++ b/web/sites/default/config/group.role.employee-855450a16.yml @@ -0,0 +1,17 @@ +uuid: 66fbc858-d1cc-470c-90ce-f05f0d8909f7 +langcode: en +status: true +dependencies: + config: + - group.type.employee + enforced: + config: + - user.role.publisher +id: employee-855450a16 +label: Publisher +weight: -5 +internal: true +audience: outsider +group_type: employee +permissions_ui: false +permissions: { } diff --git a/web/sites/default/config/group.role.employee-a416e6833.yml b/web/sites/default/config/group.role.employee-a416e6833.yml new file mode 100644 index 00000000..72013e95 --- /dev/null +++ b/web/sites/default/config/group.role.employee-a416e6833.yml @@ -0,0 +1,17 @@ +uuid: 8fd2b688-c9a4-4757-9e94-e095e8e710d3 +langcode: en +status: true +dependencies: + config: + - group.type.employee + enforced: + config: + - user.role.administrator +id: employee-a416e6833 +label: 'Site Administrator' +weight: -6 +internal: true +audience: outsider +group_type: employee +permissions_ui: false +permissions: { } diff --git a/web/sites/default/config/group.role.private-1ab877bcd.yml b/web/sites/default/config/group.role.private-1ab877bcd.yml new file mode 100644 index 00000000..4df0690f --- /dev/null +++ b/web/sites/default/config/group.role.private-1ab877bcd.yml @@ -0,0 +1,17 @@ +uuid: 90debd6f-0edc-4edc-a265-40f8395484b6 +langcode: en +status: true +dependencies: + config: + - group.type.private + enforced: + config: + - user.role.content_lead +id: private-1ab877bcd +label: 'Content Lead' +weight: -7 +internal: true +audience: outsider +group_type: private +permissions_ui: false +permissions: { } diff --git a/web/sites/default/config/group.role.private-3e5cf4b4d.yml b/web/sites/default/config/group.role.private-3e5cf4b4d.yml new file mode 100644 index 00000000..7afdfe1d --- /dev/null +++ b/web/sites/default/config/group.role.private-3e5cf4b4d.yml @@ -0,0 +1,17 @@ +uuid: df5977ae-1801-4cc7-96f8-c1212e556639 +langcode: en +status: true +dependencies: + config: + - group.type.private + enforced: + config: + - user.role.311_support_agent +id: private-3e5cf4b4d +label: '311 Support Agent' +weight: -4 +internal: true +audience: outsider +group_type: private +permissions_ui: false +permissions: { } diff --git a/web/sites/default/config/group.role.private-631a7fe0a.yml b/web/sites/default/config/group.role.private-631a7fe0a.yml new file mode 100644 index 00000000..d0fdd392 --- /dev/null +++ b/web/sites/default/config/group.role.private-631a7fe0a.yml @@ -0,0 +1,17 @@ +uuid: daa9595a-0fd4-4f78-a8cc-a593f0fabbea +langcode: en +status: true +dependencies: + config: + - group.type.private + enforced: + config: + - user.role.311_lead +id: private-631a7fe0a +label: '311 Lead' +weight: -3 +internal: true +audience: outsider +group_type: private +permissions_ui: false +permissions: { } diff --git a/web/sites/default/config/group.role.private-855450a16.yml b/web/sites/default/config/group.role.private-855450a16.yml new file mode 100644 index 00000000..ada57276 --- /dev/null +++ b/web/sites/default/config/group.role.private-855450a16.yml @@ -0,0 +1,17 @@ +uuid: ccd16f26-a25d-4029-9341-fe4190d08ea8 +langcode: en +status: true +dependencies: + config: + - group.type.private + enforced: + config: + - user.role.publisher +id: private-855450a16 +label: Publisher +weight: -5 +internal: true +audience: outsider +group_type: private +permissions_ui: false +permissions: { } diff --git a/web/sites/default/config/group.role.private-a416e6833.yml b/web/sites/default/config/group.role.private-a416e6833.yml new file mode 100644 index 00000000..5e2cca9b --- /dev/null +++ b/web/sites/default/config/group.role.private-a416e6833.yml @@ -0,0 +1,17 @@ +uuid: 474a1a90-c157-411d-aafd-ad18b9fd0953 +langcode: en +status: true +dependencies: + config: + - group.type.private + enforced: + config: + - user.role.administrator +id: private-a416e6833 +label: 'Site Administrator' +weight: -6 +internal: true +audience: outsider +group_type: private +permissions_ui: false +permissions: { }