From 048e4c339bd1b61b3b844b6c1bffff4176bfd178 Mon Sep 17 00:00:00 2001 From: Rachael Booth Date: Thu, 30 Nov 2023 10:39:18 +0000 Subject: [PATCH] Review apps on AWS (#2062) * CLDC-2812: update app config to run from relative root * Deploy to staging on pushes to branch * Add action mailer relative root config for review envs * Temporary pipeline to deploy this branch for testing * Update aws deploy pipeline to allow different prefixes for roles and tasks * Prepare database when deploying review apps * Update app nav and sentry to take account of relative root * Update more fixed paths * Update header root link path * Rack attack path * Revert "Deploy to staging on pushes to branch" This reverts commit b05f13d474607299a4fc2407d864bff644d48a3d. * Start updating workflows * Update teardown pipeline to drop database * Ensure destroy infra step runs after drop database * Remove user_password_path because it can't be found * Don't override path helpers in navigation items helper tests * Checkout infra code to run workflow * Try separating workflow call to job * Sync with infra repo updates * Use workflow on dev * Don't trigger on push to branch * Avoid rack attack path helper issue * Update review apps teardown pipeline * Update infra repo reference to main * Fix linting * Fix /logs redirect * Fix lettings_logs_current and sales_logs_current checks in navigation items helper * Fix existing bug in schemes nav item highlighting * Use starts with rather than == in logs nav items current checks * Split off non-support schemes current nav item checks --------- Co-authored-by: Sam Seed --- .github/workflows/aws_deploy.yml | 44 +++-- .github/workflows/production_pipeline.yml | 3 +- .github/workflows/review_pipeline.yml | 170 +++--------------- .../workflows/review_teardown_pipeline.yml | 120 +++++-------- .github/workflows/staging_pipeline.yml | 3 +- app/helpers/filters_helper.rb | 2 +- app/helpers/navigation_items_helper.rb | 36 ++-- app/views/layouts/application.html.erb | 2 +- app/views/organisations/index.html.erb | 2 +- config.ru | 6 +- config/application.rb | 2 + config/environments/review.rb | 2 +- config/initializers/sentry.rb | 1 + config/routes.rb | 2 +- spec/helpers/navigation_items_helper_spec.rb | 45 +++-- 15 files changed, 161 insertions(+), 279 deletions(-) diff --git a/.github/workflows/aws_deploy.yml b/.github/workflows/aws_deploy.yml index 8fa267a69..75b63d6dd 100644 --- a/.github/workflows/aws_deploy.yml +++ b/.github/workflows/aws_deploy.yml @@ -6,7 +6,10 @@ on: aws_account_id: required: true type: string - aws_resource_prefix: + aws_role_prefix: + required: true + type: string + aws_task_prefix: required: true type: string environment: @@ -104,12 +107,12 @@ jobs: uses: aws-actions/configure-aws-credentials@v3 with: aws-region: ${{ env.aws_region }} - role-to-assume: arn:aws:iam::${{ inputs.aws_account_id }}:role/${{ inputs.aws_resource_prefix }}-deployment + role-to-assume: arn:aws:iam::${{ inputs.aws_account_id }}:role/${{ inputs.aws_role_prefix }}-deployment role-chaining: true - name: Download ad hoc task definition env: - ad_hoc_task_definition: ${{ inputs.aws_resource_prefix }}-ad-hoc + ad_hoc_task_definition: ${{ inputs.aws_task_prefix }}-ad-hoc run: | aws ecs describe-task-definition --task-definition $ad_hoc_task_definition --query taskDefinition > ad-hoc-task-definition.json @@ -126,11 +129,28 @@ jobs: with: task-definition: ${{ steps.ad-hoc-task-def.outputs.task-definition }} + - name: Setup Database + if: ${{ inputs.environment == 'review' }} + env: + ad_hoc_task_definition: ${{ inputs.aws_task_prefix }}-ad-hoc + cluster: ${{ inputs.aws_task_prefix }}-app + service: ${{ inputs.aws_task_prefix }}-app + run: | + network=$(aws ecs describe-services --cluster $cluster --services $service --query services[0].networkConfiguration) + overrides='{ "containerOverrides" : [{ "name" : "app", "command" : ["bundle", "exec", "rake", "db:prepare"]}]}' + arn=$(aws ecs run-task --cluster $cluster --task-definition $ad_hoc_task_definition --network-configuration "$network" --overrides "$overrides" --group migrations --launch-type FARGATE --query tasks[0].taskArn) + echo "Waiting for db prepare task to complete" + temp=${arn##*/} + id=${temp%*\"} + aws ecs wait tasks-stopped --cluster $cluster --tasks $id + succeeded=$(aws ecs describe-tasks --cluster $cluster --tasks $id --query "tasks[0].stopCode == 'EssentialContainerExited' && to_string(tasks[0].containers[0].exitCode) == '0'") + if [ $succeeded == true ]; then exit 0; else exit 1; fi + - name: Run migrations task env: - ad_hoc_task_definition: ${{ inputs.aws_resource_prefix }}-ad-hoc - cluster: ${{ inputs.aws_resource_prefix }}-app - service: ${{ inputs.aws_resource_prefix }}-app + ad_hoc_task_definition: ${{ inputs.aws_task_prefix }}-ad-hoc + cluster: ${{ inputs.aws_task_prefix }}-app + service: ${{ inputs.aws_task_prefix }}-app run: | network=$(aws ecs describe-services --cluster $cluster --services $service --query services[0].networkConfiguration) overrides='{ "containerOverrides" : [{ "name" : "app", "command" : ["bundle", "exec", "rake", "db:migrate"]}]}' @@ -144,7 +164,7 @@ jobs: - name: Download app service task definition env: - app_task_definition: ${{ inputs.aws_resource_prefix }}-app + app_task_definition: ${{ inputs.aws_task_prefix }}-app run: | aws ecs describe-task-definition --task-definition $app_task_definition --query taskDefinition > app-task-definition.json @@ -159,14 +179,14 @@ jobs: - name: Deploy updated application uses: aws-actions/amazon-ecs-deploy-task-definition@v1 with: - cluster: ${{ inputs.aws_resource_prefix }}-app - service: ${{ inputs.aws_resource_prefix }}-app + cluster: ${{ inputs.aws_task_prefix }}-app + service: ${{ inputs.aws_task_prefix }}-app task-definition: ${{ steps.app-task-def.outputs.task-definition }} wait-for-service-stability: true - name: Download sidekiq service task definition env: - sidekiq_task_definition: ${{ inputs.aws_resource_prefix }}-sidekiq + sidekiq_task_definition: ${{ inputs.aws_task_prefix }}-sidekiq run: | aws ecs describe-task-definition --task-definition $sidekiq_task_definition --query taskDefinition > sidekiq-task-definition.json @@ -181,7 +201,7 @@ jobs: - name: Deploy updated sidekiq uses: aws-actions/amazon-ecs-deploy-task-definition@v1 with: - cluster: ${{ inputs.aws_resource_prefix }}-app - service: ${{ inputs.aws_resource_prefix }}-sidekiq + cluster: ${{ inputs.aws_task_prefix }}-app + service: ${{ inputs.aws_task_prefix }}-sidekiq task-definition: ${{ steps.sidekiq-task-def.outputs.task-definition }} wait-for-service-stability: true diff --git a/.github/workflows/production_pipeline.yml b/.github/workflows/production_pipeline.yml index 52540e92b..cb79038ef 100644 --- a/.github/workflows/production_pipeline.yml +++ b/.github/workflows/production_pipeline.yml @@ -215,7 +215,8 @@ jobs: uses: ./.github/workflows/aws_deploy.yml with: aws_account_id: 977287343304 - aws_resource_prefix: core-prod + aws_task_prefix: core-prod + aws_role_prefix: core-prod environment: production release_tag: ${{ needs.test.outputs.releasetag }} permissions: diff --git a/.github/workflows/review_pipeline.yml b/.github/workflows/review_pipeline.yml index d5921e049..bf2d1b0dc 100644 --- a/.github/workflows/review_pipeline.yml +++ b/.github/workflows/review_pipeline.yml @@ -1,6 +1,7 @@ name: Review app pipeline -concurrency: ${{ github.workflow }}-${{ github.event.pull_request.number }} +concurrency: + group: review-${{ github.event.pull_request.number }} on: pull_request: @@ -15,160 +16,41 @@ defaults: shell: bash jobs: - postgres: - name: Provision postgres - runs-on: ubuntu-latest - environment: review - - steps: - - name: Install Cloud Foundry CLI - run: | - wget --user-agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15" -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add - - echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list - sudo apt-get update - sudo apt-get install cf8-cli - - - name: Provision postgres - env: - CF_USERNAME: ${{ secrets.CF_USERNAME }} - CF_PASSWORD: ${{ secrets.CF_PASSWORD }} - CF_API_ENDPOINT: ${{ secrets.CF_API_ENDPOINT }} - CF_SPACE: dev - CF_ORG: ${{ secrets.CF_ORG }} - run: | - cf api $CF_API_ENDPOINT - cf auth - cf target -o $CF_ORG -s $CF_SPACE - cf create-service postgres tiny-unencrypted-13 dluhc-core-review-${{ github.event.pull_request.number }}-postgres --wait - - redis: - name: Provision redis - runs-on: ubuntu-latest - environment: review - - steps: - - name: Install Cloud Foundry CLI - run: | - wget --user-agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15" -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add - - echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list - sudo apt-get update - sudo apt-get install cf8-cli - - - name: Provision redis - env: - CF_USERNAME: ${{ secrets.CF_USERNAME }} - CF_PASSWORD: ${{ secrets.CF_PASSWORD }} - CF_API_ENDPOINT: ${{ secrets.CF_API_ENDPOINT }} - CF_SPACE: dev - CF_ORG: ${{ secrets.CF_ORG }} - run: | - cf api $CF_API_ENDPOINT - cf auth - cf target -o $CF_ORG -s $CF_SPACE - cf create-service redis micro-6.x dluhc-core-review-${{ github.event.pull_request.number }}-redis --wait + infra: + name: Deploy review app infrastructure + uses: communitiesuk/submit-social-housing-lettings-and-sales-data-infrastructure/.github/workflows/create_review_app_infra.yml@main + with: + key: ${{ github.event.pull_request.number }} + app_repo_role: arn:aws:iam::815624722760:role/core-application-repo + permissions: + id-token: write + + code: + name: Deploy review app code + needs: [infra] + uses: ./.github/workflows/aws_deploy.yml + with: + aws_account_id: 837698168072 + aws_role_prefix: core-dev + aws_task_prefix: core-review-${{ github.event.pull_request.number }} + environment: review + permissions: + id-token: write - deploy: - name: Deploy review app + comment: + name: Add link to PR + needs: [code] runs-on: ubuntu-latest - environment: review - needs: [postgres, redis] permissions: issues: write pull-requests: write steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Install Cloud Foundry CLI - run: | - wget --user-agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15" -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add - - echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list - sudo apt-get update - sudo apt-get install cf8-cli - - - name: Setup review app without starting - env: - CF_USERNAME: ${{ secrets.CF_USERNAME }} - CF_PASSWORD: ${{ secrets.CF_PASSWORD }} - CF_API_ENDPOINT: ${{ secrets.CF_API_ENDPOINT }} - CF_SPACE: dev - CF_ORG: ${{ secrets.CF_ORG }} - APP_NAME: dluhc-core-review-${{ github.event.pull_request.number }} - run: | - cf api $CF_API_ENDPOINT - cf auth - cf target -o $CF_ORG -s $CF_SPACE - cf push $APP_NAME \ - --manifest ./config/cloud_foundry/review_manifest.yml \ - --no-start - - - name: Set environment variables - env: - APP_NAME: dluhc-core-review-${{ github.event.pull_request.number }} - API_USER: ${{ secrets.API_USER }} - API_KEY: ${{ secrets.API_KEY }} - GOVUK_NOTIFY_API_KEY: ${{ secrets.GOVUK_NOTIFY_API_KEY }} - RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }} - OS_DATA_KEY: ${{ secrets.OS_DATA_KEY }} - IMPORT_PAAS_INSTANCE: ${{ secrets.IMPORT_PAAS_INSTANCE }} - EXPORT_PAAS_INSTANCE: ${{ secrets.EXPORT_PAAS_INSTANCE }} - S3_CONFIG: ${{ secrets.S3_CONFIG }} - CSV_DOWNLOAD_PAAS_INSTANCE: ${{ secrets.CSV_DOWNLOAD_PAAS_INSTANCE }} - SENTRY_DSN: ${{ secrets.SENTRY_DSN }} - run: | - cf set-env $APP_NAME API_USER $API_USER - cf set-env $APP_NAME API_KEY $API_KEY - cf set-env $APP_NAME GOVUK_NOTIFY_API_KEY $GOVUK_NOTIFY_API_KEY - cf set-env $APP_NAME RAILS_MASTER_KEY $RAILS_MASTER_KEY - cf set-env $APP_NAME OS_DATA_KEY $OS_DATA_KEY - cf set-env $APP_NAME IMPORT_PAAS_INSTANCE $IMPORT_PAAS_INSTANCE - cf set-env $APP_NAME EXPORT_PAAS_INSTANCE "dluhc-core-review-export-bucket" - cf set-env $APP_NAME S3_CONFIG $S3_CONFIG - cf set-env $APP_NAME CSV_DOWNLOAD_PAAS_INSTANCE "dluhc-core-review-csv-bucket" - cf set-env $APP_NAME SENTRY_DSN $SENTRY_DSN - cf set-env $APP_NAME APP_HOST "https://dluhc-core-review-${{ github.event.pull_request.number }}.london.cloudapps.digital" - - - name: Bind postgres service - env: - APP_NAME: dluhc-core-review-${{ github.event.pull_request.number }} - SERVICE_NAME: dluhc-core-review-${{ github.event.pull_request.number }}-postgres - run: | - cf bind-service $APP_NAME $SERVICE_NAME --wait - - - name: Bind redis service - env: - APP_NAME: dluhc-core-review-${{ github.event.pull_request.number }} - SERVICE_NAME: dluhc-core-review-${{ github.event.pull_request.number }}-redis - run: | - cf bind-service $APP_NAME $SERVICE_NAME --wait - - - name: Bind logit drain service - env: - APP_NAME: dluhc-core-review-${{ github.event.pull_request.number }} - SERVICE_NAME: logit-ssl-drain - run: | - cf bind-service $APP_NAME $SERVICE_NAME --wait - - - name: Bind S3 buckets services - env: - APP_NAME: dluhc-core-review-${{ github.event.pull_request.number }} - run: | - cf bind-service $APP_NAME dluhc-core-review-csv-bucket --wait - cf bind-service $APP_NAME dluhc-core-review-export-bucket --wait - cf bind-service $APP_NAME dluhc-core-review-import-bucket --wait - - - name: Start review app - env: - APP_NAME: dluhc-core-review-${{ github.event.pull_request.number }} - run: | - cf restage $APP_NAME - - name: Comment on PR with URL uses: unsplash/comment-on-pr@v1.3.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - msg: "Created review app at https://dluhc-core-review-${{ github.event.pull_request.number }}.london.cloudapps.digital" + msg: "Created review app at https://review.submit-social-housing-data.levellingup.gov.uk/${{ github.event.pull_request.number }}" check_for_duplicate_msg: true duplicate_msg_pattern: Created review app at* diff --git a/.github/workflows/review_teardown_pipeline.yml b/.github/workflows/review_teardown_pipeline.yml index 3962243c4..4303e4063 100644 --- a/.github/workflows/review_teardown_pipeline.yml +++ b/.github/workflows/review_teardown_pipeline.yml @@ -1,92 +1,64 @@ name: Review app teardown pipeline +concurrency: + group: review-${{ github.event.pull_request.number }} + on: pull_request: types: - closed workflow_dispatch: -defaults: - run: - shell: bash +env: + app_repo_role: arn:aws:iam::815624722760:role/core-application-repo + aws_account_id: 837698168072 + aws_region: eu-west-2 + aws_role_prefix: core-dev + aws_task_prefix: core-review-${{ github.event.pull_request.number }} jobs: - app: - name: Teardown app + database: + name: Drop database runs-on: ubuntu-latest - environment: review + permissions: + id-token: write steps: - - name: Install Cloud Foundry CLI - run: | - wget --user-agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15" -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add - - echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list - sudo apt-get update - sudo apt-get install cf8-cli - - - name: Teardown app - env: - CF_USERNAME: ${{ secrets.CF_USERNAME }} - CF_PASSWORD: ${{ secrets.CF_PASSWORD }} - CF_API_ENDPOINT: ${{ secrets.CF_API_ENDPOINT }} - CF_SPACE: dev - CF_ORG: ${{ secrets.CF_ORG }} - run: | - cf api $CF_API_ENDPOINT - cf auth - cf target -o $CF_ORG -s $CF_SPACE - cf delete dluhc-core-review-${{ github.event.pull_request.number }} -f -r - - postgres: - name: Teardown postgres - runs-on: ubuntu-latest - environment: review - needs: [app] + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v3 + with: + aws-region: ${{ env.aws_region }} + role-to-assume: ${{ env.app_repo_role }} - steps: - - name: Install Cloud Foundry CLI - run: | - wget --user-agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15" -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add - - echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list - sudo apt-get update - sudo apt-get install cf8-cli + - name: Configure AWS credentials for review environment + uses: aws-actions/configure-aws-credentials@v3 + with: + aws-region: ${{ env.aws_region }} + role-to-assume: arn:aws:iam::${{ env.aws_account_id }}:role/${{ env.aws_role_prefix }}-deployment + role-chaining: true - - name: Teardown postgres + - name: Drop Database env: - CF_USERNAME: ${{ secrets.CF_USERNAME }} - CF_PASSWORD: ${{ secrets.CF_PASSWORD }} - CF_API_ENDPOINT: ${{ secrets.CF_API_ENDPOINT }} - CF_SPACE: dev - CF_ORG: ${{ secrets.CF_ORG }} - run: | - cf api $CF_API_ENDPOINT - cf auth - cf target -o $CF_ORG -s $CF_SPACE - cf delete-service dluhc-core-review-${{ github.event.pull_request.number }}-postgres --wait -f - - redis: - name: Teardown redis - runs-on: ubuntu-latest - environment: review - needs: [app] - - steps: - - name: Install Cloud Foundry CLI + ad_hoc_task_definition: ${{ env.aws_task_prefix }}-ad-hoc + cluster: ${{ env.aws_task_prefix }}-app + service: ${{ env.aws_task_prefix }}-app run: | - wget --user-agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15" -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add - - echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list - sudo apt-get update - sudo apt-get install cf8-cli + network=$(aws ecs describe-services --cluster $cluster --services $service --query services[0].networkConfiguration) + overrides='{ "containerOverrides" : [{ "name" : "app", "command" : ["bundle", "exec", "rake", "db:drop"]}]}' + arn=$(aws ecs run-task --cluster $cluster --task-definition $ad_hoc_task_definition --network-configuration "$network" --overrides "$overrides" --group migrations --launch-type FARGATE --query tasks[0].taskArn) + echo "Waiting for db prepare task to complete" + temp=${arn##*/} + id=${temp%*\"} + aws ecs wait tasks-stopped --cluster $cluster --tasks $id + succeeded=$(aws ecs describe-tasks --cluster $cluster --tasks $id --query "tasks[0].stopCode == 'EssentialContainerExited' && to_string(tasks[0].containers[0].exitCode) == '0'") + if [ $succeeded == true ]; then exit 0; else exit 1; fi - - name: Teardown redis - env: - CF_USERNAME: ${{ secrets.CF_USERNAME }} - CF_PASSWORD: ${{ secrets.CF_PASSWORD }} - CF_API_ENDPOINT: ${{ secrets.CF_API_ENDPOINT }} - CF_SPACE: dev - CF_ORG: ${{ secrets.CF_ORG }} - run: | - cf api $CF_API_ENDPOINT - cf auth - cf target -o $CF_ORG -s $CF_SPACE - cf delete-service dluhc-core-review-${{ github.event.pull_request.number }}-redis --wait -f + infra: + name: Teardown review app + needs: [database] + uses: communitiesuk/submit-social-housing-lettings-and-sales-data-infrastructure/.github/workflows/destroy_review_app_infra.yml@main + with: + key: ${{ github.event.pull_request.number }} + app_repo_role: arn:aws:iam::815624722760:role/core-application-repo + permissions: + id-token: write diff --git a/.github/workflows/staging_pipeline.yml b/.github/workflows/staging_pipeline.yml index ee9a45d40..883c5c816 100644 --- a/.github/workflows/staging_pipeline.yml +++ b/.github/workflows/staging_pipeline.yml @@ -238,7 +238,8 @@ jobs: uses: ./.github/workflows/aws_deploy.yml with: aws_account_id: 107155005276 - aws_resource_prefix: core-staging + aws_role_prefix: core-staging + aws_task_prefix: core-staging environment: staging permissions: id-token: write diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb index 2df2d21b1..8c5f45db5 100644 --- a/app/helpers/filters_helper.rb +++ b/app/helpers/filters_helper.rb @@ -132,7 +132,7 @@ module FiltersHelper end def user_lettings_path? - request.path == "/lettings-logs" + request.path == lettings_logs_path end def user_or_org_lettings_path? diff --git a/app/helpers/navigation_items_helper.rb b/app/helpers/navigation_items_helper.rb index adf109f15..13462eb2b 100644 --- a/app/helpers/navigation_items_helper.rb +++ b/app/helpers/navigation_items_helper.rb @@ -5,18 +5,18 @@ module NavigationItemsHelper if current_user.support? [ NavigationItem.new("Organisations", organisations_path, organisations_current?(path)), - NavigationItem.new("Users", "/users", users_current?(path)), + NavigationItem.new("Users", users_path, users_current?(path)), NavigationItem.new("Lettings logs", lettings_logs_path, lettings_logs_current?(path)), NavigationItem.new("Sales logs", sales_logs_path, sales_logs_current?(path)), - NavigationItem.new("Schemes", "/schemes", supported_housing_schemes_current?(path)), + NavigationItem.new("Schemes", schemes_path, supported_housing_schemes_current?(path)), ].compact else [ NavigationItem.new("Lettings logs", lettings_logs_path, lettings_logs_current?(path)), NavigationItem.new("Sales logs", sales_logs_path, sales_logs_current?(path)), - (NavigationItem.new("Schemes", "/schemes", supported_housing_schemes_current?(path)) if current_user.organisation.holds_own_stock? || current_user.organisation.stock_owners.present?), + (NavigationItem.new("Schemes", schemes_path, non_support_supported_housing_schemes_current?(path)) if current_user.organisation.holds_own_stock? || current_user.organisation.stock_owners.present?), NavigationItem.new("Users", users_organisation_path(current_user.organisation), subnav_users_path?(path)), - NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", subnav_details_path?(path)), + NavigationItem.new("About your organisation", organisation_path(current_user.organisation.id), subnav_details_path?(path)), NavigationItem.new("Stock owners", stock_owners_organisation_path(current_user.organisation), stock_owners_path?(path)), NavigationItem.new("Managing agents", managing_agents_organisation_path(current_user.organisation), managing_agents_path?(path)), ].compact @@ -25,11 +25,11 @@ module NavigationItemsHelper def secondary_items(path, current_organisation_id) [ - NavigationItem.new("Lettings logs", "/organisations/#{current_organisation_id}/lettings-logs", subnav_lettings_logs_path?(path)), - NavigationItem.new("Sales logs", "/organisations/#{current_organisation_id}/sales-logs", subnav_sales_logs_path?(path)), - (NavigationItem.new("Schemes", "/organisations/#{current_organisation_id}/schemes", subnav_supported_housing_schemes_path?(path)) if current_user.organisation.holds_own_stock? || current_user.organisation.stock_owners.present?), - NavigationItem.new("Users", "/organisations/#{current_organisation_id}/users", subnav_users_path?(path)), - NavigationItem.new("About this organisation", "/organisations/#{current_organisation_id}", subnav_details_path?(path)), + NavigationItem.new("Lettings logs", lettings_logs_organisation_path(current_organisation_id), subnav_lettings_logs_path?(path)), + NavigationItem.new("Sales logs", sales_logs_organisation_path(current_organisation_id), subnav_sales_logs_path?(path)), + (NavigationItem.new("Schemes", schemes_organisation_path(current_organisation_id), subnav_supported_housing_schemes_path?(path)) if current_user.organisation.holds_own_stock? || current_user.organisation.stock_owners.present?), + NavigationItem.new("Users", users_organisation_path(current_organisation_id), subnav_users_path?(path)), + NavigationItem.new("About this organisation", organisation_path(current_organisation_id), subnav_details_path?(path)), NavigationItem.new("Stock owners", stock_owners_organisation_path(current_organisation_id), stock_owners_path?(path)), NavigationItem.new("Managing agents", managing_agents_organisation_path(current_organisation_id), managing_agents_path?(path)), ].compact @@ -37,31 +37,35 @@ module NavigationItemsHelper def scheme_items(path, current_scheme_id, title) [ - NavigationItem.new("Scheme", "/schemes/#{current_scheme_id}", !path.include?("locations")), - NavigationItem.new(title, "/schemes/#{current_scheme_id}/locations", path.include?("locations")), + NavigationItem.new("Scheme", scheme_path(current_scheme_id), !path.include?("locations")), + NavigationItem.new(title, scheme_locations_path(current_scheme_id), path.include?("locations")), ] end private def lettings_logs_current?(path) - path.starts_with?("/lettings-logs") + path.starts_with?(lettings_logs_path) end def sales_logs_current?(path) - path.starts_with?("/sales-logs") + path.starts_with?(sales_logs_path) end def users_current?(path) - path == "/users" || path.include?("/users/") + path == users_path || path.include?("/users/") end def supported_housing_schemes_current?(path) - path == "/schemes" || path.include?("/schemes/") + path == schemes_path || path.include?("/schemes/") + end + + def non_support_supported_housing_schemes_current?(path) + path.starts_with?(organisations_path) && path.include?("/schemes") || path.include?("/schemes/") end def organisations_current?(path) - path == "/organisations" || path.include?("/organisations/") + path == organisations_path || path.include?("/organisations/") end def subnav_supported_housing_schemes_path?(path) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 3b051a8bc..30ec7d098 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -87,7 +87,7 @@ <%= govuk_header( classes: govuk_header_classes(current_user), - service_url: current_user.nil? ? "/" : "/logs", + service_url: current_user.nil? ? root_path : logs_path, navigation_classes: "govuk-header__navigation--end", ) do |component| component.product_name(name: t("service_name")) diff --git a/app/views/organisations/index.html.erb b/app/views/organisations/index.html.erb index 75a4d799c..72d1d2f43 100644 --- a/app/views/organisations/index.html.erb +++ b/app/views/organisations/index.html.erb @@ -3,7 +3,7 @@ <% content_for :title, title %> -<%= render partial: "organisations/headings", locals: request.path == "/organisations" ? { main: "Organisations", sub: nil } : { main: @organisation.name, sub: "Organisations" } %> +<%= render partial: "organisations/headings", locals: request.path == organisations_path ? { main: "Organisations", sub: nil } : { main: @organisation.name, sub: "Organisations" } %> <% if current_user.support? %> <%= govuk_button_link_to "Create a new organisation", new_organisation_path, html: { method: :get } %> diff --git a/config.ru b/config.ru index 4a3c09a68..9b96fe939 100644 --- a/config.ru +++ b/config.ru @@ -2,5 +2,7 @@ require_relative "config/environment" -run Rails.application -Rails.application.load_server +map DataCollector::Application.config.relative_url_root || "/" do + run Rails.application + Rails.application.load_server +end diff --git a/config/application.rb b/config/application.rb index 4fd65c695..2cda05fea 100644 --- a/config/application.rb +++ b/config/application.rb @@ -50,5 +50,7 @@ module DataCollector helper_specs: false, controller_specs: false end + + config.relative_url_root = ENV["RAILS_RELATIVE_URL_ROOT"] end end diff --git a/config/environments/review.rb b/config/environments/review.rb index 27b4a5c50..ec4c67726 100644 --- a/config/environments/review.rb +++ b/config/environments/review.rb @@ -58,7 +58,7 @@ Rails.application.configure do config.action_mailer.perform_caching = false - config.action_mailer.default_url_options = { host: ENV["APP_HOST"] } + config.action_mailer.default_url_options = { host: ENV["APP_HOST"], script_name: Rails.application.config.relative_url_root } config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { address: "smtp.gmail.com", diff --git a/config/initializers/sentry.rb b/config/initializers/sentry.rb index 05eecc89f..da0a2a59e 100644 --- a/config/initializers/sentry.rb +++ b/config/initializers/sentry.rb @@ -24,3 +24,4 @@ Sentry.init do |config| end Sentry.set_tags("app_host": ENV["APP_HOST"]) +Sentry.set_tags("url_root": ENV["RAILS_RELATIVE_URL_ROOT"]) diff --git a/config/routes.rb b/config/routes.rb index 052570cb1..3c58e5a29 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -31,7 +31,7 @@ Rails.application.routes.draw do root to: "start#index" - get "/logs", to: redirect("/lettings-logs") + get "/logs", to: redirect("lettings-logs") get "/accessibility-statement", to: "content#accessibility_statement" get "/privacy-notice", to: "content#privacy_notice" get "/data-sharing-agreement", to: "content#data_sharing_agreement" diff --git a/spec/helpers/navigation_items_helper_spec.rb b/spec/helpers/navigation_items_helper_spec.rb index 5730d52ae..0c6ced3ba 100644 --- a/spec/helpers/navigation_items_helper_spec.rb +++ b/spec/helpers/navigation_items_helper_spec.rb @@ -3,9 +3,6 @@ require "rails_helper" RSpec.describe NavigationItemsHelper do let(:current_user) { create(:user, :data_coordinator) } - let(:users_path) { "/organisations/#{current_user.organisation.id}/users" } - let(:organisation_path) { "/organisations/#{current_user.organisation.id}" } - describe "#primary_items" do context "when the user is a data coordinator" do context "when the user's org does not own stock" do @@ -17,8 +14,8 @@ RSpec.describe NavigationItemsHelper do [ NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), - NavigationItemsHelper::NavigationItem.new("Users", users_path, false), - NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), + NavigationItemsHelper::NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", false), NavigationItemsHelper::NavigationItem.new("Stock owners", "/organisations/#{current_user.organisation.id}/stock-owners", false), NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] @@ -40,8 +37,8 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), - NavigationItemsHelper::NavigationItem.new("Users", users_path, false), - NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), + NavigationItemsHelper::NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", false), NavigationItemsHelper::NavigationItem.new("Stock owners", "/organisations/#{current_user.organisation.id}/stock-owners", false), NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] @@ -59,8 +56,8 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), - NavigationItemsHelper::NavigationItem.new("Users", users_path, false), - NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), + NavigationItemsHelper::NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", false), NavigationItemsHelper::NavigationItem.new("Stock owners", "/organisations/#{current_user.organisation.id}/stock-owners", false), NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] @@ -77,8 +74,8 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", true), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), - NavigationItemsHelper::NavigationItem.new("Users", users_path, false), - NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), + NavigationItemsHelper::NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", false), NavigationItemsHelper::NavigationItem.new("Stock owners", "/organisations/#{current_user.organisation.id}/stock-owners", false), NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] @@ -95,15 +92,15 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), - NavigationItemsHelper::NavigationItem.new("Users", users_path, true), - NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", true), + NavigationItemsHelper::NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", false), NavigationItemsHelper::NavigationItem.new("Stock owners", "/organisations/#{current_user.organisation.id}/stock-owners", false), NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] end it "returns navigation items with the users item set as current" do - expect(primary_items(users_path, current_user)).to eq(expected_navigation_items) + expect(primary_items("/organisations/#{current_user.organisation.id}/users", current_user)).to eq(expected_navigation_items) end end @@ -113,15 +110,15 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), - NavigationItemsHelper::NavigationItem.new("Users", users_path, false), - NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, true), + NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), + NavigationItemsHelper::NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", true), NavigationItemsHelper::NavigationItem.new("Stock owners", "/organisations/#{current_user.organisation.id}/stock-owners", false), NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] end it "returns navigation items with the users item set as current" do - expect(primary_items("#{organisation_path}/details", current_user)).to eq(expected_navigation_items) + expect(primary_items("/organisations/#{current_user.organisation.id}/details", current_user)).to eq(expected_navigation_items) end end @@ -132,7 +129,7 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), - NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", false), NavigationItemsHelper::NavigationItem.new("Stock owners", "/organisations/#{current_user.organisation.id}/stock-owners", false), NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] @@ -150,7 +147,7 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", true), - NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", false), NavigationItemsHelper::NavigationItem.new("Stock owners", "/organisations/#{current_user.organisation.id}/stock-owners", false), NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] @@ -168,7 +165,7 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", true), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), - NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", false), NavigationItemsHelper::NavigationItem.new("Stock owners", "/organisations/#{current_user.organisation.id}/stock-owners", false), NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] @@ -196,8 +193,8 @@ RSpec.describe NavigationItemsHelper do [ NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), - NavigationItemsHelper::NavigationItem.new("Users", users_path, false), - NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), + NavigationItemsHelper::NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", false), NavigationItemsHelper::NavigationItem.new("Stock owners", "/organisations/#{current_user.organisation.id}/stock-owners", false), NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] @@ -219,8 +216,8 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), - NavigationItemsHelper::NavigationItem.new("Users", users_path, false), - NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), + NavigationItemsHelper::NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", false), NavigationItemsHelper::NavigationItem.new("Stock owners", "/organisations/#{current_user.organisation.id}/stock-owners", false), NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ]