Browse Source

CLDC-2319 prevent log creation (#1684)

* Remove bulk_upload_lettings_logs flag

* Add spacing above actions in data sharing agreement

* Add banner

* Add model validation

* fix log component

* Fix factory

* Put validation behind feature flag

* start adapting to data protection confirmation

* Make tests more generic

* Add tests for display_organisation_attributes

* Use data_protection_confirmed? method

* Address code review

* rubocop

* Prevent access to bulk upload pages when DPC not signed

* Address PO review
pull/1693/head
Jack 2 years ago committed by GitHub
parent
commit
6d7ce8af16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      app/components/create_log_actions_component.html.erb
  2. 55
      app/components/create_log_actions_component.rb
  3. 16
      app/components/data_protection_confirmation_banner_component.html.erb
  4. 38
      app/components/data_protection_confirmation_banner_component.rb
  5. 7
      app/controllers/bulk_upload_lettings_logs_controller.rb
  6. 7
      app/controllers/bulk_upload_sales_logs_controller.rb
  7. 30
      app/controllers/organisations_controller.rb
  8. 34
      app/helpers/data_sharing_agreement_helper.rb
  9. 7
      app/helpers/logs_helper.rb
  10. 4
      app/models/data_sharing_agreement.rb
  11. 9
      app/models/log.rb
  12. 15
      app/models/organisation.rb
  13. 6
      app/services/feature_toggle.rb
  14. 2
      app/views/layouts/application.html.erb
  15. 10
      app/views/logs/_create_for_org_actions.html.erb
  16. 12
      app/views/logs/_log_filters.html.erb
  17. 30
      app/views/logs/index.html.erb
  18. 20
      app/views/organisations/data_sharing_agreement.html.erb
  19. 16
      app/views/organisations/logs.html.erb
  20. 2
      app/views/organisations/show.html.erb
  21. 2
      config/locales/en.yml
  22. 5
      db/migrate/20230609101144_drop_data_sharing_adreement_table.rb
  23. 18
      db/schema.rb
  24. 12
      db/seeds.rb
  25. 170
      spec/components/create_log_actions_component_spec.rb
  26. 128
      spec/components/data_protection_confirmation_banner_component_spec.rb
  27. 2
      spec/controllers/modules/search_filter_spec.rb
  28. 12
      spec/db/seeds_spec.rb
  29. 5
      spec/factories/data_protection_confirmation.rb
  30. 15
      spec/factories/data_sharing_agreement.rb
  31. 22
      spec/factories/organisation.rb
  32. 6
      spec/features/lettings_log_spec.rb
  33. 26
      spec/models/form/lettings/questions/created_by_id_spec.rb
  34. 25
      spec/models/form/sales/questions/created_by_id_spec.rb
  35. 111
      spec/models/organisation_spec.rb
  36. 54
      spec/models/user_spec.rb
  37. 13
      spec/requests/bulk_upload_lettings_logs_controller_spec.rb
  38. 13
      spec/requests/bulk_upload_sales_logs_controller_spec.rb
  39. 43
      spec/requests/organisations_controller_spec.rb
  40. 20
      spec/requests/users_controller_spec.rb
  41. 10
      spec/services/imports/data_protection_confirmation_import_service_spec.rb
  42. 49
      spec/shared/shared_log_examples.rb
  43. 50
      spec/views/logs/_create_for_org_actions.html.erb_spec.rb
  44. 42
      spec/views/organisations/data_sharing_agreement.html.erb_spec.rb
  45. 41
      spec/views/organisations/show.html.erb_spec.rb

10
app/components/create_log_actions_component.html.erb

@ -0,0 +1,10 @@
<% if display_actions? %>
<div class="govuk-button-group app-filter-toggle govuk-!-margin-bottom-6">
<% if create_button_href.present? %>
<%= govuk_button_to create_button_copy, create_button_href, class: "govuk-!-margin-right-6" %>
<% end %>
<% if upload_button_href.present? %>
<%= govuk_button_link_to upload_button_copy, upload_button_href, secondary: true %>
<% end %>
</div>
<% end %>

55
app/components/create_log_actions_component.rb

@ -0,0 +1,55 @@
class CreateLogActionsComponent < ViewComponent::Base
include Rails.application.routes.url_helpers
attr_reader :bulk_upload, :user, :log_type
def initialize(user:, log_type:, bulk_upload: nil)
@bulk_upload = bulk_upload
@user = user
@log_type = log_type
super
end
def display_actions?
return false if bulk_upload.present?
return true unless FeatureToggle.new_data_protection_confirmation?
return true if user.support?
user.organisation.data_protection_confirmed?
end
def create_button_href
case log_type
when "lettings"
lettings_logs_path
when "sales"
sales_logs_path
end
end
def create_button_copy
case log_type
when "lettings"
"Create a new lettings log"
when "sales"
"Create a new sales log"
end
end
def upload_button_copy
if log_type == "lettings"
"Upload lettings logs in bulk"
elsif FeatureToggle.bulk_upload_sales_logs? && log_type == "sales"
"Upload sales logs in bulk"
end
end
def upload_button_href
if log_type == "lettings"
bulk_upload_lettings_log_path(id: "start")
elsif FeatureToggle.bulk_upload_sales_logs? && log_type == "sales"
bulk_upload_sales_log_path(id: "start")
end
end
end

16
app/components/data_protection_confirmation_banner_component.html.erb

@ -0,0 +1,16 @@
<% if display_banner? %>
<%= govuk_notification_banner(title_text: "Important") do %>
<p class="govuk-notification-banner__heading govuk-!-width-full" style="max-width: fit-content">
<%= I18n.t("validations.organisation.data_sharing_agreement_not_signed") %>
<p>
<% if user.is_dpo? %>
<%= govuk_link_to(
"Read the Data Sharing Agreement",
data_sharing_agreement_href,
class: "govuk-notification-banner__link govuk-!-font-weight-bold",
) %>
<% else %>
<%= data_protection_officers_text %>
<% end %>
<% end %>
<% end %>

38
app/components/data_protection_confirmation_banner_component.rb

@ -0,0 +1,38 @@
class DataProtectionConfirmationBannerComponent < ViewComponent::Base
include Rails.application.routes.url_helpers
attr_reader :user, :organisation
def initialize(user:, organisation: nil)
@user = user
@organisation = organisation
super
end
def display_banner?
return false unless FeatureToggle.new_data_protection_confirmation?
return false if user.support? && organisation.blank?
!DataProtectionConfirmation.exists?(
organisation: org_or_user_org,
confirmed: true,
)
end
def data_protection_officers_text
if org_or_user_org.data_protection_officers.any?
"You can ask: #{org_or_user_org.data_protection_officers.map(&:name).join(', ')}"
end
end
def data_sharing_agreement_href
data_sharing_agreement_organisation_path(org_or_user_org)
end
private
def org_or_user_org
organisation.presence || user.organisation
end
end

7
app/controllers/bulk_upload_lettings_logs_controller.rb

@ -1,5 +1,6 @@
class BulkUploadLettingsLogsController < ApplicationController class BulkUploadLettingsLogsController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
before_action :validate_data_protection_agrement_signed!
def start def start
if in_crossover_period? if in_crossover_period?
@ -23,6 +24,12 @@ class BulkUploadLettingsLogsController < ApplicationController
private private
def validate_data_protection_agrement_signed!
unless @current_user.organisation.data_protection_confirmed?
redirect_to lettings_logs_path
end
end
def current_year def current_year
FormHandler.instance.current_collection_start_year FormHandler.instance.current_collection_start_year
end end

7
app/controllers/bulk_upload_sales_logs_controller.rb

@ -1,5 +1,6 @@
class BulkUploadSalesLogsController < ApplicationController class BulkUploadSalesLogsController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
before_action :validate_data_protection_agrement_signed!
def start def start
if in_crossover_period? if in_crossover_period?
@ -23,6 +24,12 @@ class BulkUploadSalesLogsController < ApplicationController
private private
def validate_data_protection_agrement_signed!
unless @current_user.organisation.data_protection_confirmed?
redirect_to sales_logs_path
end
end
def current_year def current_year
FormHandler.instance.forms["current_sales"].start_date.year FormHandler.instance.forms["current_sales"].start_date.year
end end

30
app/controllers/organisations_controller.rb

@ -157,35 +157,35 @@ class OrganisationsController < ApplicationController
end end
def data_sharing_agreement def data_sharing_agreement
return render_not_found unless FeatureToggle.new_data_sharing_agreement? return render_not_found unless FeatureToggle.new_data_protection_confirmation?
@data_sharing_agreement = current_user.organisation.data_sharing_agreement @data_protection_confirmation = current_user.organisation.data_protection_confirmation
end end
def confirm_data_sharing_agreement def confirm_data_sharing_agreement
return render_not_found unless FeatureToggle.new_data_sharing_agreement? return render_not_found unless FeatureToggle.new_data_protection_confirmation?
return render_not_found unless current_user.is_dpo? return render_not_found unless current_user.is_dpo?
return render_not_found if @organisation.data_sharing_agreement.present? return render_not_found if @organisation.data_protection_confirmed?
data_sharing_agreement = DataSharingAgreement.new( if @organisation.data_protection_confirmation
@organisation.data_protection_confirmation.update!(
confirmed: true,
data_protection_officer: current_user,
# When it was signed
created_at: Time.zone.now,
)
else
DataProtectionConfirmation.create!(
organisation: current_user.organisation, organisation: current_user.organisation,
signed_at: Time.zone.now, confirmed: true,
data_protection_officer: current_user, data_protection_officer: current_user,
organisation_name: @organisation.name,
organisation_address: @organisation.address_row,
organisation_phone_number: @organisation.phone,
dpo_email: current_user.email,
dpo_name: current_user.name,
) )
end
if data_sharing_agreement.save
flash[:notice] = "You have accepted the Data Sharing Agreement" flash[:notice] = "You have accepted the Data Sharing Agreement"
flash[:notification_banner_body] = "Your organisation can now submit logs." flash[:notification_banner_body] = "Your organisation can now submit logs."
redirect_to details_organisation_path(@organisation) redirect_to details_organisation_path(@organisation)
else
render :data_sharing_agreement
end
end end
private private

34
app/helpers/data_sharing_agreement_helper.rb

@ -21,9 +21,9 @@ module DataSharingAgreementHelper
end end
end end
def name_for_data_sharing_agreement(data_sharing_agreement, user) def name_for_data_sharing_agreement(data_protection_confirmation, user)
if data_sharing_agreement.present? if data_protection_confirmation&.confirmed?
data_sharing_agreement.data_protection_officer.name data_protection_confirmation.data_protection_officer.name
elsif user.is_dpo? elsif user.is_dpo?
user.name user.name
else else
@ -31,22 +31,22 @@ module DataSharingAgreementHelper
end end
end end
def org_name_for_data_sharing_agreement(data_sharing_agreement, user) def org_name_for_data_sharing_agreement(data_protection_confirmation, user)
if data_sharing_agreement.present? if data_protection_confirmation&.confirmed?
data_sharing_agreement.organisation_name data_protection_confirmation.organisation.name
else else
user.organisation.name user.organisation.name
end end
end end
# rubocop:disable Rails/HelperInstanceVariable # rubocop:disable Rails/HelperInstanceVariable
def section_12_2(data_sharing_agreement:, user:, organisation:) def present_section_12_2(data_protection_confirmation:, user:, organisation:)
if data_sharing_agreement if data_protection_confirmation&.confirmed?
@org_address = data_sharing_agreement.organisation_address @org_address = data_protection_confirmation.organisation.address_row
@org_name = data_sharing_agreement.organisation_name @org_name = data_protection_confirmation.organisation.name
@org_phone = data_sharing_agreement.organisation_phone_number @org_phone = data_protection_confirmation.organisation.phone
@dpo_name = data_sharing_agreement.dpo_name @dpo_name = data_protection_confirmation.data_protection_officer.name
@dpo_email = data_sharing_agreement.dpo_email @dpo_email = data_protection_confirmation.data_protection_officer.email
else else
@org_name = organisation.name @org_name = organisation.name
@org_address = organisation.address_row @org_address = organisation.address_row
@ -68,18 +68,18 @@ module DataSharingAgreementHelper
private private
def data_sharing_agreement_first_line(organisation:, user:) def data_sharing_agreement_first_line(organisation:, user:)
return "Not accepted" if organisation.data_sharing_agreement.blank? return "Not accepted" unless organisation.data_protection_confirmed?
if user.support? if user.support?
"Accepted #{organisation.data_sharing_agreement.signed_at.strftime('%d/%m/%Y')}" "Accepted #{organisation.data_protection_confirmation.created_at.strftime('%d/%m/%Y')}"
else else
"Accepted" "Accepted"
end end
end end
def data_sharing_agreement_second_line(organisation:, user:) def data_sharing_agreement_second_line(organisation:, user:)
if organisation.data_sharing_agreement.present? if organisation.data_protection_confirmed?
organisation.data_sharing_agreement.data_protection_officer.name if user.support? organisation.data_protection_confirmation.data_protection_officer.name if user.support?
else else
"Data protection officer must sign" unless user.is_dpo? "Data protection officer must sign" unless user.is_dpo?
end end

7
app/helpers/logs_helper.rb

@ -8,13 +8,6 @@ module LogsHelper
end end
end end
def bulk_upload_path_for_controller(controller, id:)
case log_type_for_controller(controller)
when "lettings" then bulk_upload_lettings_log_path(id:)
when "sales" then bulk_upload_sales_log_path(id:)
end
end
def bulk_upload_options(bulk_upload) def bulk_upload_options(bulk_upload)
array = bulk_upload ? [bulk_upload.id] : [] array = bulk_upload ? [bulk_upload.id] : []
array.index_with { |_bulk_upload_id| "With logs from bulk upload" } array.index_with { |_bulk_upload_id| "With logs from bulk upload" }

4
app/models/data_sharing_agreement.rb

@ -1,4 +0,0 @@
class DataSharingAgreement < ApplicationRecord
belongs_to :organisation
belongs_to :data_protection_officer, class_name: "User"
end

9
app/models/log.rb

@ -9,6 +9,7 @@ class Log < ApplicationRecord
belongs_to :bulk_upload, optional: true belongs_to :bulk_upload, optional: true
before_save :update_status! before_save :update_status!
before_validation :verify_data_protection_confirmation, on: :create
STATUS = { STATUS = {
"not_started" => 0, "not_started" => 0,
@ -177,6 +178,14 @@ class Log < ApplicationRecord
private private
def verify_data_protection_confirmation
return unless FeatureToggle.new_data_protection_confirmation?
return unless owning_organisation
return if owning_organisation.data_protection_confirmed?
errors.add :owning_organisation, I18n.t("validations.organisation.data_sharing_agreement_not_signed")
end
# Handle logs that are older than previous collection start date # Handle logs that are older than previous collection start date
def older_than_previous_collection_year? def older_than_previous_collection_year?
return false unless startdate return false unless startdate

15
app/models/organisation.rb

@ -1,10 +1,10 @@
class Organisation < ApplicationRecord class Organisation < ApplicationRecord
has_many :users, dependent: :delete_all has_many :users, dependent: :delete_all
has_many :data_protection_officers, -> { where(is_dpo: true) }, class_name: "User"
has_many :owned_lettings_logs, class_name: "LettingsLog", foreign_key: "owning_organisation_id", dependent: :delete_all has_many :owned_lettings_logs, class_name: "LettingsLog", foreign_key: "owning_organisation_id", dependent: :delete_all
has_many :managed_lettings_logs, class_name: "LettingsLog", foreign_key: "managing_organisation_id" has_many :managed_lettings_logs, class_name: "LettingsLog", foreign_key: "managing_organisation_id"
has_many :owned_sales_logs, class_name: "SalesLog", foreign_key: "owning_organisation_id", dependent: :delete_all has_many :owned_sales_logs, class_name: "SalesLog", foreign_key: "owning_organisation_id", dependent: :delete_all
has_many :data_protection_confirmations has_one :data_protection_confirmation
has_one :data_sharing_agreement
has_many :organisation_rent_periods has_many :organisation_rent_periods
has_many :owned_schemes, class_name: "Scheme", foreign_key: "owning_organisation_id", dependent: :delete_all has_many :owned_schemes, class_name: "Scheme", foreign_key: "owning_organisation_id", dependent: :delete_all
has_many :parent_organisation_relationships, foreign_key: :child_organisation_id, class_name: "OrganisationRelationship" has_many :parent_organisation_relationships, foreign_key: :child_organisation_id, class_name: "OrganisationRelationship"
@ -89,7 +89,7 @@ class Organisation < ApplicationRecord
end end
def data_protection_confirmed? def data_protection_confirmed?
!!data_protection_confirmations.order(created_at: :desc).first&.confirmed !!data_protection_confirmation&.confirmed?
end end
def data_protection_agreement_string def data_protection_agreement_string
@ -103,7 +103,7 @@ class Organisation < ApplicationRecord
end end
def display_organisation_attributes def display_organisation_attributes
[ attrs = [
{ name: "Name", value: name, editable: true }, { name: "Name", value: name, editable: true },
{ name: "Address", value: address_string, editable: true }, { name: "Address", value: address_string, editable: true },
{ name: "Telephone_number", value: phone, editable: true }, { name: "Telephone_number", value: phone, editable: true },
@ -111,8 +111,13 @@ class Organisation < ApplicationRecord
{ name: "Registration number", value: housing_registration_no || "", editable: false }, { name: "Registration number", value: housing_registration_no || "", editable: false },
{ name: "Rent_periods", value: rent_period_labels, editable: false, format: :bullet }, { name: "Rent_periods", value: rent_period_labels, editable: false, format: :bullet },
{ name: "Owns housing stock", value: holds_own_stock ? "Yes" : "No", editable: false }, { name: "Owns housing stock", value: holds_own_stock ? "Yes" : "No", editable: false },
{ name: "Data protection agreement", value: data_protection_agreement_string, editable: false },
].compact ].compact
unless FeatureToggle.new_data_protection_confirmation?
attrs << { name: "Data protection agreement", value: data_protection_agreement_string, editable: false }
end
attrs
end end
def has_managing_agents? def has_managing_agents?

6
app/services/feature_toggle.rb

@ -20,10 +20,6 @@ class FeatureToggle
true true
end end
def self.bulk_upload_lettings_logs?
true
end
def self.bulk_upload_sales_logs? def self.bulk_upload_sales_logs?
!Rails.env.production? !Rails.env.production?
end end
@ -46,7 +42,7 @@ class FeatureToggle
!Rails.env.production? !Rails.env.production?
end end
def self.new_data_sharing_agreement? def self.new_data_protection_confirmation?
!Rails.env.production? !Rails.env.production?
end end
end end

2
app/views/layouts/application.html.erb

@ -126,7 +126,7 @@
) do |notification_banner| ) do |notification_banner|
notification_banner.heading(text: flash.notice.html_safe) notification_banner.heading(text: flash.notice.html_safe)
if flash[:notification_banner_body] if flash[:notification_banner_body]
tag.p flash[:notification_banner_body] tag.p flash[:notification_banner_body]&.html_safe
end end
end %> end %>
<% end %> <% end %>

10
app/views/logs/_create_for_org_actions.html.erb

@ -0,0 +1,10 @@
<div class="govuk-button-group app-filter-toggle">
<% if !FeatureToggle.new_data_protection_confirmation? || @organisation.data_protection_confirmed? %>
<% if current_page?(controller: 'organisations', action: 'lettings_logs') %>
<%= govuk_button_to "Create a new lettings log for this organisation", lettings_logs_path(lettings_log: { owning_organisation_id: @organisation.id }, method: :post) %>
<% end %>
<% if current_page?(controller: 'organisations', action: 'sales_logs') %>
<%= govuk_button_to "Create a new sales log for this organisation", sales_logs_path(sales_log: { owning_organisation_id: @organisation.id }, method: :post) %>
<% end %>
<% end %>
</div>

12
app/views/logs/_log_filters.erb → app/views/logs/_log_filters.html.erb

@ -6,12 +6,12 @@
<div class="app-filter__content"> <div class="app-filter__content">
<%= form_with html: { method: :get } do |f| %> <%= form_with html: { method: :get } do |f| %>
<% all_or_yours = { "all": { label: "All" }, "yours": { label: "Yours" }} %> <% all_or_yours = { "all": { label: "All" }, "yours": { label: "Yours" } } %>
<% if bulk_upload_options(@bulk_upload).present? %> <% if bulk_upload_options(@bulk_upload).present? %>
<%= render partial: "filters/checkbox_filter", <%= render partial: "filters/checkbox_filter",
locals: { locals: {
f: f, f:,
options: bulk_upload_options(@bulk_upload), options: bulk_upload_options(@bulk_upload),
label: "Bulk upload", label: "Bulk upload",
category: "bulk_upload_id", category: "bulk_upload_id",
@ -21,7 +21,7 @@
<% if bulk_upload_options(@bulk_upload).blank? %> <% if bulk_upload_options(@bulk_upload).blank? %>
<%= render partial: "filters/checkbox_filter", <%= render partial: "filters/checkbox_filter",
locals: { locals: {
f: f, f:,
options: collection_year_options, options: collection_year_options,
label: "Collection year", label: "Collection year",
category: "years", category: "years",
@ -29,7 +29,7 @@
<%= render partial: "filters/checkbox_filter", <%= render partial: "filters/checkbox_filter",
locals: { locals: {
f: f, f:,
options: status_filters, options: status_filters,
label: "Status", label: "Status",
category: "status", category: "status",
@ -38,7 +38,7 @@
<%= render partial: "filters/radio_filter", <%= render partial: "filters/radio_filter",
locals: { locals: {
f: f, f:,
options: all_or_yours, options: all_or_yours,
label: "Logs", label: "Logs",
category: "user", category: "user",
@ -46,7 +46,7 @@
<% if (@current_user.support? || @current_user.organisation.has_managing_agents?) && request.path == "/lettings-logs" %> <% if (@current_user.support? || @current_user.organisation.has_managing_agents?) && request.path == "/lettings-logs" %>
<%= render partial: "filters/radio_filter", locals: { <%= render partial: "filters/radio_filter", locals: {
f: f, f:,
options: { options: {
"all": { label: "All" }, "all": { label: "All" },
"specific_org": { "specific_org": {

30
app/views/logs/index.html.erb

@ -3,6 +3,11 @@
<% content_for :title, title %> <% content_for :title, title %>
<%= render DataProtectionConfirmationBannerComponent.new(
user: current_user,
organisation: @organisation,
) %>
<% if current_page?(controller: 'lettings_logs', action: 'index') %> <% if current_page?(controller: 'lettings_logs', action: 'index') %>
<% if @unresolved_count > 0 %> <% if @unresolved_count > 0 %>
<%= govuk_notification_banner( <%= govuk_notification_banner(
@ -45,26 +50,11 @@
<% end %> <% end %>
<div class="app-filter-layout" data-controller="filter-layout"> <div class="app-filter-layout" data-controller="filter-layout">
<% unless @bulk_upload %> <%= render CreateLogActionsComponent.new(
<div class="govuk-button-group app-filter-toggle govuk-!-margin-bottom-6"> bulk_upload: @bulk_upload,
<% if current_page?(controller: 'lettings_logs', action: 'index') %> user: current_user,
<%= govuk_button_to "Create a new lettings log", lettings_logs_path, class: "govuk-!-margin-right-6" %> log_type: log_type_for_controller(controller),
<% end %> ) %>
<% if current_page?(controller: 'sales_logs', action: 'index') %>
<%= govuk_button_to "Create a new sales log", sales_logs_path, class: "govuk-!-margin-right-6" %>
<% end %>
<% if FeatureToggle.bulk_upload_lettings_logs? && log_type_for_controller(controller) == "lettings" %>
<%= govuk_button_link_to "Upload lettings logs in bulk", bulk_upload_path_for_controller(controller, id: "start"), secondary: true %>
<% end %>
<% if FeatureToggle.bulk_upload_sales_logs? && log_type_for_controller(controller) == "sales" %>
<%= govuk_button_link_to "Upload sales logs in bulk", bulk_upload_path_for_controller(controller, id: "start"), secondary: true %>
<% end %>
</div>
<% end %>
<%= render partial: "log_filters" %> <%= render partial: "log_filters" %>
<div class="app-filter-layout__content"> <div class="app-filter-layout__content">

20
app/views/organisations/data_sharing_agreement.html.erb

@ -3,11 +3,11 @@
<div class="govuk-grid-row"> <div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds-from-desktop"> <div class="govuk-grid-column-two-thirds-from-desktop">
<h2 id="data-provider-organisation-and-department-for-levelling-up-housing-and-communities" class="govuk-heading-l"> <h2 id="data-provider-organisation-and-department-for-levelling-up-housing-and-communities" class="govuk-heading-l">
<%= org_name_for_data_sharing_agreement(@data_sharing_agreement, current_user) %> and Department for Levelling Up, Housing and Communities <%= org_name_for_data_sharing_agreement(@data_protection_confirmation, current_user) %> and Department for Levelling Up, Housing and Communities
</h2> </h2>
<p class="govuk-body-m"> <p class="govuk-body-m">
<% if @data_sharing_agreement %> <% if @data_protection_confirmation&.confirmed? %>
This agreement is made the <%= @data_sharing_agreement.signed_at.day.ordinalize %> day of <%= @data_sharing_agreement.signed_at.strftime("%B") %> <%= @data_sharing_agreement.signed_at.year %> This agreement is made the <%= @data_protection_confirmation.created_at.day.ordinalize %> day of <%= @data_protection_confirmation.created_at.strftime("%B") %> <%= @data_protection_confirmation.created_at.year %>
<% elsif current_user.is_dpo? %> <% elsif current_user.is_dpo? %>
This agreement is made the <%= Time.zone.now.day.ordinalize %> day of <%= Time.zone.now.strftime("%B") %> <%= Time.zone.now.year %> This agreement is made the <%= Time.zone.now.day.ordinalize %> day of <%= Time.zone.now.strftime("%B") %> <%= Time.zone.now.year %>
<% else %> <% else %>
@ -15,8 +15,8 @@
<% end %> <% end %>
</p> </p>
<p class="govuk-body-m"><strong>between</strong></p> <p class="govuk-body-m"><strong>between</strong></p>
<% if @data_sharing_agreement %> <% if @data_protection_confirmation&.confirmed? %>
<p class="govuk-body-m">1) <%= @data_sharing_agreement.organisation_name %> of <%= @data_sharing_agreement.organisation_address %> (“CORE Data Provider”)</p> <p class="govuk-body-m">1) <%= @data_protection_confirmation.organisation.name %> of <%= @data_protection_confirmation.organisation.address_row %> (“CORE Data Provider”)</p>
<% else %> <% else %>
<p class="govuk-body-m">1) <%= @organisation.name %> of <%= @organisation.address_row %> (“CORE Data Provider”)</p> <p class="govuk-body-m">1) <%= @organisation.name %> of <%= @organisation.address_row %> (“CORE Data Provider”)</p>
<% end %> <% end %>
@ -106,7 +106,7 @@
<h3 id="12-authorised-representatives" class="govuk-heading-m">12. Authorised representatives</h3> <h3 id="12-authorised-representatives" class="govuk-heading-m">12. Authorised representatives</h3>
<p class="govuk-body-m">12.1. CORE data providers and DLUHC will each appoint an Authorised Representative to be the primary point of contact in all day-to-day matters relating to this Agreement:</p> <p class="govuk-body-m">12.1. CORE data providers and DLUHC will each appoint an Authorised Representative to be the primary point of contact in all day-to-day matters relating to this Agreement:</p>
<p class="govuk-body-m"> <p class="govuk-body-m">
<%= section_12_2(data_sharing_agreement: @data_sharing_agreement, user: current_user, organisation: @organisation) %> <%= present_section_12_2(data_protection_confirmation: @data_protection_confirmation, user: current_user, organisation: @organisation) %>
</p> </p>
<p class="govuk-body-m">12.3. For DLUHC: Name: Rachel Worledge, <p class="govuk-body-m">12.3. For DLUHC: Name: Rachel Worledge,
Postal Address: South-west section, 4th Floor, Fry Building, 2 Marsham Street, London, SW1P 4DF, Postal Address: South-west section, 4th Floor, Fry Building, 2 Marsham Street, London, SW1P 4DF,
@ -123,9 +123,9 @@
<h3 id="16-statutory-compliance" class="govuk-heading-m">16. Statutory compliance</h3> <h3 id="16-statutory-compliance" class="govuk-heading-m">16. Statutory compliance</h3>
<p class="govuk-body-m">16.1. The Parties shall comply with all relevant legislation, regulations, orders, statutory instruments and any amendments or re-enactments thereof from the commencement of this agreement.</p> <p class="govuk-body-m">16.1. The Parties shall comply with all relevant legislation, regulations, orders, statutory instruments and any amendments or re-enactments thereof from the commencement of this agreement.</p>
<p class="govuk-body-m">As witness of which the parties have set their hands on the day and year first above written <p class="govuk-body-m">As witness of which the parties have set their hands on the day and year first above written
signed for and on behalf of the Data Protection Officer for <%= org_name_for_data_sharing_agreement(@data_sharing_agreement, current_user) %>, by:</p> signed for and on behalf of the Data Protection Officer for <%= org_name_for_data_sharing_agreement(@data_protection_confirmation, current_user) %>, by:</p>
<ul class="govuk-list govuk-list--bullet"> <ul class="govuk-list govuk-list--bullet">
<li>Name: <%= name_for_data_sharing_agreement(@data_sharing_agreement, current_user) %></li> <li>Name: <%= name_for_data_sharing_agreement(@data_protection_confirmation, current_user) %></li>
<li>Title: Data Protection Officer</li> <li>Title: Data Protection Officer</li>
</ul> </ul>
<p class="govuk-body-m">SIGNED for and on behalf of the deputy director of the data, analytics &amp; statistics in the Department for Levelling Up, Housing and Communities, by:</p> <p class="govuk-body-m">SIGNED for and on behalf of the deputy director of the data, analytics &amp; statistics in the Department for Levelling Up, Housing and Communities, by:</p>
@ -134,8 +134,8 @@
<li>Title: Deputy Director</li> <li>Title: Deputy Director</li>
</ul> </ul>
<% if current_user.is_dpo? && @organisation.data_sharing_agreement.nil? %> <% if current_user.is_dpo? && !(@organisation.data_protection_confirmed?) %>
<div class="govuk-button-group"> <div class="govuk-button-group govuk-!-margin-top-9">
<%= govuk_button_to("Accept this agreement", data_sharing_agreement_organisation_path(@organisation), method: :post) %> <%= govuk_button_to("Accept this agreement", data_sharing_agreement_organisation_path(@organisation), method: :post) %>
<%= govuk_button_link_to("Cancel", details_organisation_path(@organisation), secondary: true) %> <%= govuk_button_link_to("Cancel", details_organisation_path(@organisation), secondary: true) %>
</div> </div>

16
app/views/organisations/logs.html.erb

@ -5,6 +5,11 @@
<%= render partial: "organisations/headings", locals: { main: @organisation.name, sub: nil } %> <%= render partial: "organisations/headings", locals: { main: @organisation.name, sub: nil } %>
<%= render DataProtectionConfirmationBannerComponent.new(
user: current_user,
organisation: @organisation,
) %>
<% if current_user.support? %> <% if current_user.support? %>
<%= render SubNavigationComponent.new( <%= render SubNavigationComponent.new(
items: secondary_items(request.path, @organisation.id), items: secondary_items(request.path, @organisation.id),
@ -13,14 +18,7 @@
<% end %> <% end %>
<div class="app-filter-layout" data-controller="filter-layout"> <div class="app-filter-layout" data-controller="filter-layout">
<div class="govuk-button-group app-filter-toggle"> <%= render partial: "logs/create_for_org_actions" %>
<% if current_page?(controller: 'organisations', action: 'lettings_logs') %>
<%= govuk_button_to "Create a new lettings log for this organisation", lettings_logs_path(lettings_log: { owning_organisation_id: @organisation.id }, method: :post) %>
<% end %>
<% if current_page?(controller: 'organisations', action: 'sales_logs') %>
<%= govuk_button_to "Create a new sales log for this organisation", sales_logs_path(sales_log: { owning_organisation_id: @organisation.id }, method: :post) %>
<% end %>
</div>
<%= render partial: "logs/log_filters" %> <%= render partial: "logs/log_filters" %>
<div class="app-filter-layout__content"> <div class="app-filter-layout__content">
@ -37,6 +35,6 @@
csv_download_url: csv_download_url_by_log_type(@log_type, @organisation, search: @search_term, codes_only: false), csv_download_url: csv_download_url_by_log_type(@log_type, @organisation, search: @search_term, codes_only: false),
csv_codes_only_download_url: csv_download_url_by_log_type(@log_type, @organisation, search: @search_term, codes_only: true), csv_codes_only_download_url: csv_download_url_by_log_type(@log_type, @organisation, search: @search_term, codes_only: true),
} %> } %>
<%== render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "logs" } %> <%= render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "logs" } %>
</div> </div>
</div> </div>

2
app/views/organisations/show.html.erb

@ -33,7 +33,7 @@
<% end %> <% end %>
<% end %> <% end %>
<% end %> <% end %>
<% if FeatureToggle.new_data_sharing_agreement? %> <% if FeatureToggle.new_data_protection_confirmation? %>
<%= data_sharing_agreement_row(organisation: @organisation, user: current_user, summary_list:) %> <%= data_sharing_agreement_row(organisation: @organisation, user: current_user, summary_list:) %>
<% end %> <% end %>
<% end %> <% end %>

2
config/locales/en.yml

@ -105,7 +105,6 @@ en:
confirm_soft_errors: confirm_soft_errors:
blank: You must select if there are errors in these fields blank: You must select if there are errors in these fields
activerecord: activerecord:
attributes: attributes:
user: user:
@ -178,6 +177,7 @@ en:
validations: validations:
organisation: organisation:
data_sharing_agreement_not_signed: Your organisation must accept the Data Sharing Agreement before you can create any logs.
name_missing: "Enter the name of the organisation" name_missing: "Enter the name of the organisation"
provider_type_missing: "Select the organisation type" provider_type_missing: "Select the organisation type"
stock_owner: stock_owner:

5
db/migrate/20230609101144_drop_data_sharing_adreement_table.rb

@ -0,0 +1,5 @@
class DropDataSharingAdreementTable < ActiveRecord::Migration[7.0]
def change
drop_table :data_sharing_agreements # rubocop:disable Rails/ReversibleMigration
end
end

18
db/schema.rb

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2023_05_30_094653) do ActiveRecord::Schema[7.0].define(version: 2023_06_09_101144) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -56,22 +56,6 @@ ActiveRecord::Schema[7.0].define(version: 2023_05_30_094653) do
t.index ["organisation_id"], name: "index_data_protection_confirmations_on_organisation_id" t.index ["organisation_id"], name: "index_data_protection_confirmations_on_organisation_id"
end end
create_table "data_sharing_agreements", force: :cascade do |t|
t.bigint "organisation_id"
t.bigint "data_protection_officer_id"
t.datetime "signed_at", null: false
t.string "organisation_name", null: false
t.string "organisation_address", null: false
t.string "organisation_phone_number"
t.string "dpo_email", null: false
t.string "dpo_name", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["data_protection_officer_id"], name: "index_data_sharing_agreements_on_data_protection_officer_id"
t.index ["organisation_id", "data_protection_officer_id"], name: "data_sharing_agreements_unique", unique: true
t.index ["organisation_id"], name: "index_data_sharing_agreements_on_organisation_id"
end
create_table "la_rent_ranges", force: :cascade do |t| create_table "la_rent_ranges", force: :cascade do |t|
t.integer "ranges_rent_id" t.integer "ranges_rent_id"
t.integer "lettype" t.integer "lettype"

12
db/seeds.rb

@ -7,6 +7,14 @@
# Character.create(name: 'Luke', movie: movies.first) # Character.create(name: 'Luke', movie: movies.first)
# rubocop:disable Rails/Output # rubocop:disable Rails/Output
def create_data_protection_confirmation(user)
DataProtectionConfirmation.find_or_create_by!(
organisation: user.organisation,
confirmed: true,
data_protection_officer: user,
)
end
unless Rails.env.test? unless Rails.env.test?
stock_owner1 = Organisation.find_or_create_by!( stock_owner1 = Organisation.find_or_create_by!(
name: "Stock Owner 1", name: "Stock Owner 1",
@ -86,6 +94,7 @@ unless Rails.env.test?
) do |user| ) do |user|
user.password = "password" user.password = "password"
user.confirmed_at = Time.zone.now user.confirmed_at = Time.zone.now
create_data_protection_confirmation(user)
end end
User.find_or_create_by!( User.find_or_create_by!(
@ -96,6 +105,7 @@ unless Rails.env.test?
) do |user| ) do |user|
user.password = "password" user.password = "password"
user.confirmed_at = Time.zone.now user.confirmed_at = Time.zone.now
create_data_protection_confirmation(user)
end end
standalone_no_stock = Organisation.find_or_create_by!( standalone_no_stock = Organisation.find_or_create_by!(
@ -177,6 +187,8 @@ unless Rails.env.test?
user.confirmed_at = Time.zone.now user.confirmed_at = Time.zone.now
end end
create_data_protection_confirmation(support_user)
pp "Seeded 3 dummy users" pp "Seeded 3 dummy users"
end end

170
spec/components/create_log_actions_component_spec.rb

@ -0,0 +1,170 @@
require "rails_helper"
RSpec.describe CreateLogActionsComponent, type: :component do
include GovukComponentsHelper
include GovukLinkHelper
let(:component) { described_class.new(user:, log_type:, bulk_upload:) }
let(:render) { render_inline(component) }
let(:log_type) { "lettings" }
let(:user) { create(:user) }
context "when bulk upload present" do
let(:bulk_upload) { true }
it "does not render actions" do
expect(component.display_actions?).to eq(false)
end
end
context "when bulk upload nil" do
let(:bulk_upload) { nil }
context "when flag disabled" do
before do
allow(FeatureToggle).to receive(:new_data_protection_confirmation?).and_return(false)
end
it "renders actions" do
expect(component.display_actions?).to eq(true)
end
it "returns create button copy" do
expect(component.create_button_copy).to eq("Create a new lettings log")
end
it "returns create button href" do
render
expect(component.create_button_href).to eq("/lettings-logs")
end
it "returns upload button copy" do
expect(component.upload_button_copy).to eq("Upload lettings logs in bulk")
end
it "returns upload button href" do
render
expect(component.upload_button_href).to eq("/lettings-logs/bulk-upload-logs/start")
end
context "when sales log type" do
let(:log_type) { "sales" }
it "renders actions" do
expect(component.display_actions?).to eq(true)
end
it "returns create button copy" do
expect(component.create_button_copy).to eq("Create a new sales log")
end
it "returns create button href" do
render
expect(component.create_button_href).to eq("/sales-logs")
end
end
end
context "when flag enabled" do
before do
allow(FeatureToggle).to receive(:new_data_protection_confirmation?).and_return(true)
end
context "when support user" do
let(:user) { create(:user, :support) }
it "renders actions" do
expect(component.display_actions?).to eq(true)
end
it "returns create button copy" do
expect(component.create_button_copy).to eq("Create a new lettings log")
end
it "returns create button href" do
render
expect(component.create_button_href).to eq("/lettings-logs")
end
it "returns upload button copy" do
expect(component.upload_button_copy).to eq("Upload lettings logs in bulk")
end
it "returns upload button href" do
render
expect(component.upload_button_href).to eq("/lettings-logs/bulk-upload-logs/start")
end
context "when sales log type" do
let(:log_type) { "sales" }
it "renders actions" do
expect(component.display_actions?).to eq(true)
end
it "returns create button copy" do
expect(component.create_button_copy).to eq("Create a new sales log")
end
it "returns create button href" do
render
expect(component.create_button_href).to eq("/sales-logs")
end
end
end
context "when not support user" do
context "without data sharing agreement" do
let(:user) { create(:user, organisation: create(:organisation, :without_dpc)) }
it "does not render actions" do
expect(component).not_to be_display_actions
end
end
context "when has data sharing agremeent" do
let(:user) { create(:user, :support) }
it "renders actions" do
expect(component.display_actions?).to eq(true)
end
it "returns create button copy" do
expect(component.create_button_copy).to eq("Create a new lettings log")
end
it "returns create button href" do
render
expect(component.create_button_href).to eq("/lettings-logs")
end
it "returns upload button copy" do
expect(component.upload_button_copy).to eq("Upload lettings logs in bulk")
end
it "returns upload button href" do
render
expect(component.upload_button_href).to eq("/lettings-logs/bulk-upload-logs/start")
end
context "when sales log type" do
let(:log_type) { "sales" }
it "renders actions" do
expect(component.display_actions?).to eq(true)
end
it "returns create button copy" do
expect(component.create_button_copy).to eq("Create a new sales log")
end
it "returns create button href" do
render
expect(component.create_button_href).to eq("/sales-logs")
end
end
end
end
end
end
end

128
spec/components/data_protection_confirmation_banner_component_spec.rb

@ -0,0 +1,128 @@
require "rails_helper"
RSpec.describe DataProtectionConfirmationBannerComponent, type: :component do
let(:component) { described_class.new(user:, organisation:) }
let(:render) { render_inline(component) }
let(:user) { create(:user) }
let(:organisation) { user.organisation }
context "when flag disabled" do
before do
allow(FeatureToggle).to receive(:new_data_protection_confirmation?).and_return(false)
end
it "does not display banner" do
expect(component.display_banner?).to eq(false)
end
end
context "when flag enabled" do
before do
allow(FeatureToggle).to receive(:new_data_protection_confirmation?).and_return(true)
end
describe "#data_protection_officers_text" do
it "returns the correct text" do
expect(component.data_protection_officers_text).to eq("You can ask: Danny Rojas")
end
context "with two DPOs" do
before do
create(:user, organisation:, is_dpo: true, name: "Test McTest")
end
it "returns the correct text" do
expect(component.data_protection_officers_text).to eq("You can ask: Danny Rojas, Test McTest")
end
end
end
context "when user is not support and not dpo" do
let(:user) { create(:user) }
context "when org blank" do
let(:organisation) { nil }
before do
allow(DataProtectionConfirmation).to receive(:exists?).and_call_original
end
context "when data sharing agreement present" do
it "does not display banner" do
expect(component.display_banner?).to eq(false)
end
it "verifies DSA exists for organisation" do
render
expect(DataProtectionConfirmation).to have_received(:exists?).with(organisation: user.organisation, confirmed: true)
end
end
context "when data sharing agreement not present" do
let(:user) { create(:user, organisation: create(:organisation, :without_dpc)) }
it "displays the banner" do
expect(component.display_banner?).to eq(true)
end
it "produces the correct link" do
render
expect(component.data_sharing_agreement_href).to eq("/organisations/#{user.organisation.id}/data-sharing-agreement")
end
it "verifies DSA exists for organisation" do
render
expect(DataProtectionConfirmation).to have_received(:exists?).with(organisation: user.organisation, confirmed: true)
end
end
end
end
context "when user is support" do
let(:user) { create(:user, :support) }
context "when org blank" do
let(:organisation) { nil }
it "does not display banner" do
expect(component.display_banner?).to eq(false)
end
end
context "when org present" do
before do
allow(DataProtectionConfirmation).to receive(:exists?).and_call_original
end
context "when data sharing agreement present" do
it "does not display banner" do
expect(component.display_banner?).to eq(false)
end
it "verifies DSA exists for organisation" do
render
expect(DataProtectionConfirmation).to have_received(:exists?).with(organisation:, confirmed: true)
end
end
context "when data sharing agreement not present" do
let(:organisation) { create(:organisation, :without_dpc) }
it "displays the banner" do
expect(component.display_banner?).to eq(true)
end
it "produces the correct link" do
render
expect(component.data_sharing_agreement_href).to eq("/organisations/#{organisation.id}/data-sharing-agreement")
end
it "verifies DSA exists for organisation" do
render
expect(DataProtectionConfirmation).to have_received(:exists?).with(organisation:, confirmed: true)
end
end
end
end
end
end

2
spec/controllers/modules/search_filter_spec.rb

@ -49,7 +49,7 @@ RSpec.describe Modules::SearchFilter do
let(:search_term) { nil } let(:search_term) { nil }
it "returns all the users" do it "returns all the users" do
expect(instance.filtered_users(user_list, search_term).count).to eq(7) expect(instance.filtered_users(user_list, search_term).count).to eq(user_list.count)
end end
end end
end end

12
spec/db/seeds_spec.rb

@ -24,12 +24,12 @@ RSpec.describe "seeding process", type: task do
it "sets up correct data" do it "sets up correct data" do
expect { expect {
Rails.application.load_seed Rails.application.load_seed
}.to change(User, :count).by(7) }.to change(User, :count)
.and change(Organisation, :count).by(8) .and change(Organisation, :count)
.and change(OrganisationRelationship, :count).by(4) .and change(OrganisationRelationship, :count)
.and change(Scheme, :count).by(3) .and change(Scheme, :count)
.and change(Location, :count).by(3) .and change(Location, :count)
.and change(LaRentRange, :count).by(22_850) .and change(LaRentRange, :count)
end end
it "is idempotent" do it "is idempotent" do

5
spec/factories/data_protection_confirmation.rb

@ -1,7 +1,8 @@
FactoryBot.define do FactoryBot.define do
factory :data_protection_confirmation do factory :data_protection_confirmation do
organisation organisation { association :organisation, data_protection_confirmation: instance }
data_protection_officer { FactoryBot.create(:user, :data_protection_officer) } data_protection_officer { association :user, :data_protection_officer, organisation: (instance.organisation || organisation) }
confirmed { true } confirmed { true }
old_org_id { "7c5bd5fb549c09a2c55d7cb90d7ba84927e64618" } old_org_id { "7c5bd5fb549c09a2c55d7cb90d7ba84927e64618" }
old_id { "7c5bd5fb549c09a2c55d7cb90d7ba84927e64618" } old_id { "7c5bd5fb549c09a2c55d7cb90d7ba84927e64618" }

15
spec/factories/data_sharing_agreement.rb

@ -1,15 +0,0 @@
FactoryBot.define do
factory :data_sharing_agreement do
organisation
data_protection_officer { create(:user, is_dpo: true) }
signed_at { Time.zone.now }
created_at { Time.zone.now }
updated_at { Time.zone.now }
dpo_name { data_protection_officer.name }
dpo_email { data_protection_officer.email }
organisation_address { organisation.address_string }
organisation_phone_number { organisation.phone }
organisation_name { organisation.name }
end
end

22
spec/factories/organisation.rb

@ -10,6 +10,20 @@ FactoryBot.define do
updated_at { Time.zone.now } updated_at { Time.zone.now }
holds_own_stock { true } holds_own_stock { true }
transient do
with_dsa { true }
end
after(:create) do |org, evaluator|
if evaluator.with_dsa
create(
:data_protection_confirmation,
organisation: org,
data_protection_officer: org.users.any? ? org.users.first : create(:user, :data_protection_officer, organisation: org),
)
end
end
trait :with_old_visible_id do trait :with_old_visible_id do
old_visible_id { rand(9_999_999).to_s } old_visible_id { rand(9_999_999).to_s }
end end
@ -21,6 +35,14 @@ FactoryBot.define do
trait :does_not_own_stock do trait :does_not_own_stock do
holds_own_stock { false } holds_own_stock { false }
end end
trait :without_dpc do
transient do
with_dsa { false }
end
data_protection_confirmation { nil }
end
end end
factory :organisation_rent_period do factory :organisation_rent_period do

6
spec/features/lettings_log_spec.rb

@ -85,7 +85,7 @@ RSpec.describe "Lettings Log Features" do
click_link("Set up this lettings log") click_link("Set up this lettings log")
select(support_user.organisation.name, from: "lettings-log-owning-organisation-id-field") select(support_user.organisation.name, from: "lettings-log-owning-organisation-id-field")
click_button("Save and continue") click_button("Save and continue")
select(support_user.name, from: "lettings-log-created-by-id-field") select("#{support_user.name} (#{support_user.email})", from: "lettings-log-created-by-id-field")
click_button("Save and continue") click_button("Save and continue")
log_id = page.current_path.scan(/\d/).join log_id = page.current_path.scan(/\d/).join
visit("lettings-logs/#{log_id}/setup/check-answers") visit("lettings-logs/#{log_id}/setup/check-answers")
@ -95,7 +95,7 @@ RSpec.describe "Lettings Log Features" do
end end
context "when visiting a subsection check answers page" do context "when visiting a subsection check answers page" do
let(:lettings_log) { FactoryBot.create(:lettings_log, :setup_completed) } let(:lettings_log) { create(:lettings_log, :setup_completed) }
it "has the correct breadcrumbs with the correct links" do it "has the correct breadcrumbs with the correct links" do
visit lettings_log_setup_check_answers_path(lettings_log) visit lettings_log_setup_check_answers_path(lettings_log)
@ -108,7 +108,7 @@ RSpec.describe "Lettings Log Features" do
end end
context "when reviewing a complete log" do context "when reviewing a complete log" do
let(:lettings_log) { FactoryBot.create(:lettings_log, :completed) } let(:lettings_log) { create(:lettings_log, :completed) }
it "has the correct breadcrumbs with the correct links" do it "has the correct breadcrumbs with the correct links" do
visit review_lettings_log_path(lettings_log) visit review_lettings_log_path(lettings_log)

26
spec/models/form/lettings/questions/created_by_id_spec.rb

@ -41,6 +41,12 @@ RSpec.describe Form::Lettings::Questions::CreatedById, type: :model do
expect(question.derived?).to be true expect(question.derived?).to be true
end end
def expected_option_for_users(users)
users.each_with_object({ "" => "Select an option" }) do |user, obj|
obj[user.id] = "#{user.name} (#{user.email})"
end
end
context "when the current user is support" do context "when the current user is support" do
let(:owning_org_user) { create(:user) } let(:owning_org_user) { create(:user) }
let(:managing_org_user) { create(:user) } let(:managing_org_user) { create(:user) }
@ -51,17 +57,8 @@ RSpec.describe Form::Lettings::Questions::CreatedById, type: :model do
create(:lettings_log, created_by: support_user, owning_organisation: owning_org_user.organisation, managing_organisation: managing_org_user.organisation) create(:lettings_log, created_by: support_user, owning_organisation: owning_org_user.organisation, managing_organisation: managing_org_user.organisation)
end end
let(:expected_answer_options) do
{
"" => "Select an option",
managing_org_user.id => "#{managing_org_user.name} (#{managing_org_user.email})",
owning_org_user.id => "#{owning_org_user.name} (#{owning_org_user.email})",
support_user.id => "#{support_user.name} (#{support_user.email})",
}
end
it "only displays users that belong to owning and managing organisations" do it "only displays users that belong to owning and managing organisations" do
expect(question.displayed_answer_options(lettings_log, support_user)).to eq(expected_answer_options) expect(question.displayed_answer_options(lettings_log, support_user)).to eq(expected_option_for_users(managing_org_user.organisation.users + owning_org_user.organisation.users))
end end
end end
end end
@ -77,15 +74,8 @@ RSpec.describe Form::Lettings::Questions::CreatedById, type: :model do
let(:user_in_same_org) { create(:user, organisation: data_coordinator.organisation) } let(:user_in_same_org) { create(:user, organisation: data_coordinator.organisation) }
let(:expected_answer_options) do
{
"" => "Select an option",
data_coordinator.id => "#{data_coordinator.name} (#{data_coordinator.email})",
}
end
it "only displays users that belong user's org" do it "only displays users that belong user's org" do
expect(question.displayed_answer_options(lettings_log, data_coordinator)).to eq(expected_answer_options) expect(question.displayed_answer_options(lettings_log, data_coordinator)).to eq(expected_option_for_users(data_coordinator.organisation.users))
end end
end end
end end

25
spec/models/form/sales/questions/created_by_id_spec.rb

@ -37,6 +37,12 @@ RSpec.describe Form::Sales::Questions::CreatedById, type: :model do
expect(question.derived?).to be true expect(question.derived?).to be true
end end
def expected_option_for_users(users)
users.each_with_object({ "" => "Select an option" }) do |user, obj|
obj[user.id] = "#{user.name} (#{user.email})"
end
end
context "when the current user is support" do context "when the current user is support" do
let(:support_user) { build(:user, :support) } let(:support_user) { build(:user, :support) }
@ -47,15 +53,9 @@ RSpec.describe Form::Sales::Questions::CreatedById, type: :model do
describe "#displayed_answer_options" do describe "#displayed_answer_options" do
let(:owning_org_user) { create(:user) } let(:owning_org_user) { create(:user) }
let(:sales_log) { create(:sales_log, owning_organisation: owning_org_user.organisation) } let(:sales_log) { create(:sales_log, owning_organisation: owning_org_user.organisation) }
let(:expected_answer_options) do
{
"" => "Select an option",
owning_org_user.id => "#{owning_org_user.name} (#{owning_org_user.email})",
}
end
it "only displays users that belong to the owning organisation" do it "only displays users that belong to the owning organisation" do
expect(question.displayed_answer_options(sales_log, support_user)).to eq(expected_answer_options) expect(question.displayed_answer_options(sales_log, support_user)).to eq(expected_option_for_users(owning_org_user.organisation.users))
end end
end end
end end
@ -70,18 +70,13 @@ RSpec.describe Form::Sales::Questions::CreatedById, type: :model do
describe "#displayed_answer_options" do describe "#displayed_answer_options" do
let(:owning_org_user) { create(:user) } let(:owning_org_user) { create(:user) }
let(:sales_log) { create(:sales_log, owning_organisation: owning_org_user.organisation) } let(:sales_log) { create(:sales_log, owning_organisation: owning_org_user.organisation) }
let!(:user_in_same_org) { create(:user, organisation: data_coordinator.organisation) }
let(:expected_answer_options) do before do
{ create(:user, organisation: data_coordinator.organisation)
"" => "Select an option",
user_in_same_org.id => "#{user_in_same_org.name} (#{user_in_same_org.email})",
data_coordinator.id => "#{data_coordinator.name} (#{data_coordinator.email})",
}
end end
it "only displays users that belong user's org" do it "only displays users that belong user's org" do
expect(question.displayed_answer_options(sales_log, data_coordinator)).to eq(expected_answer_options) expect(question.displayed_answer_options(sales_log, data_coordinator)).to eq(expected_option_for_users(data_coordinator.organisation.users))
end end
end end
end end

111
spec/models/organisation_spec.rb

@ -2,39 +2,35 @@ require "rails_helper"
RSpec.describe Organisation, type: :model do RSpec.describe Organisation, type: :model do
describe "#new" do describe "#new" do
let(:user) { FactoryBot.create(:user) } let(:user) { create(:user) }
let!(:organisation) { user.organisation } let!(:organisation) { user.organisation }
let!(:scheme) { FactoryBot.create(:scheme, owning_organisation: organisation) } let!(:scheme) { create(:scheme, owning_organisation: organisation) }
it "has expected fields" do it "has expected fields" do
expect(organisation.attribute_names).to include("name", "phone", "provider_type") expect(organisation.attribute_names).to include("name", "phone", "provider_type")
end end
it "has users" do
expect(organisation.users.first).to eq(user)
end
it "has owned_schemes" do it "has owned_schemes" do
expect(organisation.owned_schemes.first).to eq(scheme) expect(organisation.owned_schemes.first).to eq(scheme)
end end
it "validates provider_type presence" do it "validates provider_type presence" do
expect { FactoryBot.create(:organisation, provider_type: nil) } expect { create(:organisation, provider_type: nil) }
.to raise_error(ActiveRecord::RecordInvalid, "Validation failed: Provider type #{I18n.t('validations.organisation.provider_type_missing')}") .to raise_error(ActiveRecord::RecordInvalid, "Validation failed: Provider type #{I18n.t('validations.organisation.provider_type_missing')}")
end end
context "with parent/child associations", :aggregate_failures do context "with parent/child associations", :aggregate_failures do
let!(:child_organisation) { FactoryBot.create(:organisation, name: "DLUHC Child") } let!(:child_organisation) { create(:organisation, name: "DLUHC Child") }
let!(:grandchild_organisation) { FactoryBot.create(:organisation, name: "DLUHC Grandchild") } let!(:grandchild_organisation) { create(:organisation, name: "DLUHC Grandchild") }
before do before do
FactoryBot.create( create(
:organisation_relationship, :organisation_relationship,
child_organisation:, child_organisation:,
parent_organisation: organisation, parent_organisation: organisation,
) )
FactoryBot.create( create(
:organisation_relationship, :organisation_relationship,
child_organisation: grandchild_organisation, child_organisation: grandchild_organisation,
parent_organisation: child_organisation, parent_organisation: child_organisation,
@ -53,17 +49,17 @@ RSpec.describe Organisation, type: :model do
end end
context "with owning association", :aggregate_failures do context "with owning association", :aggregate_failures do
let!(:child_organisation) { FactoryBot.create(:organisation, name: "DLUHC Child") } let!(:child_organisation) { create(:organisation, name: "DLUHC Child") }
let!(:grandchild_organisation) { FactoryBot.create(:organisation, name: "DLUHC Grandchild") } let!(:grandchild_organisation) { create(:organisation, name: "DLUHC Grandchild") }
before do before do
FactoryBot.create( create(
:organisation_relationship, :organisation_relationship,
child_organisation:, child_organisation:,
parent_organisation: organisation, parent_organisation: organisation,
) )
FactoryBot.create( create(
:organisation_relationship, :organisation_relationship,
child_organisation: grandchild_organisation, child_organisation: grandchild_organisation,
parent_organisation: child_organisation, parent_organisation: child_organisation,
@ -77,17 +73,17 @@ RSpec.describe Organisation, type: :model do
end end
context "with managing association", :aggregate_failures do context "with managing association", :aggregate_failures do
let!(:child_organisation) { FactoryBot.create(:organisation, name: "DLUHC Child") } let!(:child_organisation) { create(:organisation, name: "DLUHC Child") }
let!(:grandchild_organisation) { FactoryBot.create(:organisation, name: "DLUHC Grandchild") } let!(:grandchild_organisation) { create(:organisation, name: "DLUHC Grandchild") }
before do before do
FactoryBot.create( create(
:organisation_relationship, :organisation_relationship,
child_organisation:, child_organisation:,
parent_organisation: organisation, parent_organisation: organisation,
) )
FactoryBot.create( create(
:organisation_relationship, :organisation_relationship,
child_organisation: grandchild_organisation, child_organisation: grandchild_organisation,
parent_organisation: child_organisation, parent_organisation: child_organisation,
@ -103,8 +99,8 @@ RSpec.describe Organisation, type: :model do
context "with data protection confirmations" do context "with data protection confirmations" do
before do before do
FactoryBot.create(:data_protection_confirmation, organisation:, confirmed: false, created_at: Time.utc(2018, 0o6, 0o5, 10, 36, 49)) create(:data_protection_confirmation, organisation:, confirmed: false, created_at: Time.utc(2018, 0o6, 0o5, 10, 36, 49))
FactoryBot.create(:data_protection_confirmation, organisation:, created_at: Time.utc(2019, 0o6, 0o5, 10, 36, 49)) create(:data_protection_confirmation, organisation:, created_at: Time.utc(2019, 0o6, 0o5, 10, 36, 49))
end end
it "takes the most recently created" do it "takes the most recently created" do
@ -118,11 +114,11 @@ RSpec.describe Organisation, type: :model do
end end
before do before do
FactoryBot.create(:organisation_rent_period, organisation:, rent_period: 2) create(:organisation_rent_period, organisation:, rent_period: 2)
FactoryBot.create(:organisation_rent_period, organisation:, rent_period: 3) create(:organisation_rent_period, organisation:, rent_period: 3)
# Unmapped and ignored by `rent_period_labels` # Unmapped and ignored by `rent_period_labels`
FactoryBot.create(:organisation_rent_period, organisation:, rent_period: 10) create(:organisation_rent_period, organisation:, rent_period: 10)
allow(RentPeriod).to receive(:rent_period_mappings).and_return(rent_period_mappings) allow(RentPeriod).to receive(:rent_period_mappings).and_return(rent_period_mappings)
end end
@ -142,9 +138,9 @@ RSpec.describe Organisation, type: :model do
end end
context "with lettings logs" do context "with lettings logs" do
let(:other_organisation) { FactoryBot.create(:organisation) } let(:other_organisation) { create(:organisation) }
let!(:owned_lettings_log) do let!(:owned_lettings_log) do
FactoryBot.create( create(
:lettings_log, :lettings_log,
:completed, :completed,
managing_organisation: other_organisation, managing_organisation: other_organisation,
@ -152,7 +148,7 @@ RSpec.describe Organisation, type: :model do
) )
end end
let!(:managed_lettings_log) do let!(:managed_lettings_log) do
FactoryBot.create( create(
:lettings_log, :lettings_log,
created_by: user, created_by: user,
) )
@ -173,7 +169,7 @@ RSpec.describe Organisation, type: :model do
end end
describe "paper trail" do describe "paper trail" do
let(:organisation) { FactoryBot.create(:organisation) } let(:organisation) { create(:organisation) }
it "creates a record of changes to a log" do it "creates a record of changes to a log" do
expect { organisation.update!(name: "new test name") }.to change(organisation.versions, :count).by(1) expect { organisation.update!(name: "new test name") }.to change(organisation.versions, :count).by(1)
@ -187,11 +183,11 @@ RSpec.describe Organisation, type: :model do
describe "delete cascade" do describe "delete cascade" do
context "when the organisation is deleted" do context "when the organisation is deleted" do
let!(:organisation) { FactoryBot.create(:organisation) } let!(:organisation) { create(:organisation) }
let!(:user) { FactoryBot.create(:user, :support, last_sign_in_at: Time.zone.now, organisation:) } let!(:user) { create(:user, :support, last_sign_in_at: Time.zone.now, organisation:) }
let!(:scheme_to_delete) { FactoryBot.create(:scheme, owning_organisation: user.organisation) } let!(:scheme_to_delete) { create(:scheme, owning_organisation: user.organisation) }
let!(:log_to_delete) { FactoryBot.create(:lettings_log, owning_organisation: user.organisation) } let!(:log_to_delete) { create(:lettings_log, owning_organisation: user.organisation) }
let!(:sales_log_to_delete) { FactoryBot.create(:sales_log, owning_organisation: user.organisation) } let!(:sales_log_to_delete) { create(:sales_log, owning_organisation: user.organisation) }
context "when organisation is deleted" do context "when organisation is deleted" do
it "child relationships ie logs, schemes and users are deleted too - application" do it "child relationships ie logs, schemes and users are deleted too - application" do
@ -216,8 +212,8 @@ RSpec.describe Organisation, type: :model do
describe "scopes" do describe "scopes" do
before do before do
FactoryBot.create(:organisation, name: "Joe Bloggs") create(:organisation, name: "Joe Bloggs")
FactoryBot.create(:organisation, name: "Tom Smith") create(:organisation, name: "Tom Smith")
end end
context "when searching by name" do context "when searching by name" do
@ -234,4 +230,49 @@ RSpec.describe Organisation, type: :model do
end end
end end
end end
describe "display_organisation_attributes" do
let(:organisation) { create(:organisation) }
context "when new_data_protection_confirmation flag enabled" do
before do
allow(FeatureToggle).to receive(:new_data_protection_confirmation?).and_return(true)
end
it "does not include data protection agreement" do
expect(organisation.display_organisation_attributes).to eq(
[{ editable: true, name: "Name", value: "DLUHC" },
{ editable: true,
name: "Address",
value: "2 Marsham Street\nLondon\nSW1P 4DF" },
{ editable: true, name: "Telephone_number", value: nil },
{ editable: false, name: "Type of provider", value: "Local authority" },
{ editable: false, name: "Registration number", value: "1234" },
{ editable: false, format: :bullet, name: "Rent_periods", value: %w[All] },
{ editable: false, name: "Owns housing stock", value: "Yes" }],
)
end
end
context "when new_data_protection_confirmation flag disabled" do
before do
allow(FeatureToggle).to receive(:new_data_protection_confirmation?).and_return(false)
end
it "includes data protection agreement" do
expect(organisation.display_organisation_attributes).to eq(
[{ editable: true, name: "Name", value: "DLUHC" },
{ editable: true,
name: "Address",
value: "2 Marsham Street\nLondon\nSW1P 4DF" },
{ editable: true, name: "Telephone_number", value: nil },
{ editable: false, name: "Type of provider", value: "Local authority" },
{ editable: false, name: "Registration number", value: "1234" },
{ editable: false, format: :bullet, name: "Rent_periods", value: %w[All] },
{ editable: false, name: "Owns housing stock", value: "Yes" },
{ editable: false, name: "Data protection agreement", value: "Accepted" }],
)
end
end
end
end end

54
spec/models/user_spec.rb

@ -2,10 +2,10 @@ require "rails_helper"
RSpec.describe User, type: :model do RSpec.describe User, type: :model do
describe "#new" do describe "#new" do
let(:user) { FactoryBot.create(:user, old_user_id: "3") } let(:user) { create(:user, old_user_id: "3") }
let(:other_organisation) { FactoryBot.create(:organisation) } let(:other_organisation) { create(:organisation) }
let!(:owned_lettings_log) do let!(:owned_lettings_log) do
FactoryBot.create( create(
:lettings_log, :lettings_log,
:completed, :completed,
managing_organisation: other_organisation, managing_organisation: other_organisation,
@ -13,7 +13,7 @@ RSpec.describe User, type: :model do
) )
end end
let!(:managed_lettings_log) do let!(:managed_lettings_log) do
FactoryBot.create( create(
:lettings_log, :lettings_log,
created_by: user, created_by: user,
owning_organisation: other_organisation, owning_organisation: other_organisation,
@ -103,7 +103,7 @@ RSpec.describe User, type: :model do
end end
context "when the user is a data coordinator" do context "when the user is a data coordinator" do
let(:user) { FactoryBot.create(:user, :data_coordinator) } let(:user) { create(:user, :data_coordinator) }
it "can assign all roles except support" do it "can assign all roles except support" do
expect(user.assignable_roles).to eq({ expect(user.assignable_roles).to eq({
@ -124,7 +124,7 @@ RSpec.describe User, type: :model do
context "and their organisation has managing agents" do context "and their organisation has managing agents" do
before do before do
FactoryBot.create(:organisation_relationship, parent_organisation: user.organisation) create(:organisation_relationship, parent_organisation: user.organisation)
end end
it "can filter lettings logs by user, year, status and organisation" do it "can filter lettings logs by user, year, status and organisation" do
@ -134,8 +134,8 @@ RSpec.describe User, type: :model do
end end
context "when the user is a Customer Support person" do context "when the user is a Customer Support person" do
let(:user) { FactoryBot.create(:user, :support) } let(:user) { create(:user, :support) }
let!(:other_orgs_log) { FactoryBot.create(:lettings_log) } let!(:other_orgs_log) { create(:lettings_log) }
it "has access to logs from all organisations" do it "has access to logs from all organisations" do
expect(user.lettings_logs.to_a).to match_array([owned_lettings_log, managed_lettings_log, other_orgs_log]) expect(user.lettings_logs.to_a).to match_array([owned_lettings_log, managed_lettings_log, other_orgs_log])
@ -159,7 +159,7 @@ RSpec.describe User, type: :model do
end end
context "when the user is in development environment" do context "when the user is in development environment" do
let(:user) { FactoryBot.create(:user, :support) } let(:user) { create(:user, :support) }
before do before do
allow(Rails.env).to receive(:development?).and_return(true) allow(Rails.env).to receive(:development?).and_return(true)
@ -171,7 +171,7 @@ RSpec.describe User, type: :model do
end end
context "when the user is in review environment" do context "when the user is in review environment" do
let(:user) { FactoryBot.create(:user, :support) } let(:user) { create(:user, :support) }
before do before do
allow(Rails.env).to receive(:development?).and_return(false) allow(Rails.env).to receive(:development?).and_return(false)
@ -185,7 +185,7 @@ RSpec.describe User, type: :model do
end end
describe "paper trail" do describe "paper trail" do
let(:user) { FactoryBot.create(:user) } let(:user) { create(:user) }
it "creates a record of changes to a log" do it "creates a record of changes to a log" do
expect { user.update!(name: "new test name") }.to change(user.versions, :count).by(1) expect { user.update!(name: "new test name") }.to change(user.versions, :count).by(1)
@ -217,13 +217,13 @@ RSpec.describe User, type: :model do
end end
describe "scopes" do describe "scopes" do
let(:organisation_1) { FactoryBot.create(:organisation, name: "A") } let(:organisation_1) { create(:organisation, :without_dpc, name: "A") }
let(:organisation_2) { FactoryBot.create(:organisation, name: "B") } let(:organisation_2) { create(:organisation, :without_dpc, name: "B") }
let!(:user_1) { FactoryBot.create(:user, name: "Joe Bloggs", email: "joe@example.com", organisation: organisation_1, role: "support") } let!(:user_1) { create(:user, name: "Joe Bloggs", email: "joe@example.com", organisation: organisation_1, role: "support") }
let!(:user_3) { FactoryBot.create(:user, name: "Tom Smith", email: "tom@example.com", organisation: organisation_1, role: "data_provider") } let!(:user_3) { create(:user, name: "Tom Smith", email: "tom@example.com", organisation: organisation_1, role: "data_provider") }
let!(:user_2) { FactoryBot.create(:user, name: "Jenny Ford", email: "jenny@smith.com", organisation: organisation_1, role: "data_coordinator") } let!(:user_2) { create(:user, name: "Jenny Ford", email: "jenny@smith.com", organisation: organisation_1, role: "data_coordinator") }
let!(:user_4) { FactoryBot.create(:user, name: "Greg Thomas", email: "greg@org2.com", organisation: organisation_2, role: "data_coordinator") } let!(:user_4) { create(:user, name: "Greg Thomas", email: "greg@org2.com", organisation: organisation_2, role: "data_coordinator") }
let!(:user_5) { FactoryBot.create(:user, name: "Adam Thomas", email: "adam@org2.com", organisation: organisation_2, role: "data_coordinator") } let!(:user_5) { create(:user, name: "Adam Thomas", email: "adam@org2.com", organisation: organisation_2, role: "data_coordinator") }
context "when searching by name" do context "when searching by name" do
it "returns case insensitive matching records" do it "returns case insensitive matching records" do
@ -271,7 +271,7 @@ RSpec.describe User, type: :model do
let(:error_message) { "Validation failed: Password #{I18n.t('activerecord.errors.models.user.attributes.password.too_short', count: 8)}" } let(:error_message) { "Validation failed: Password #{I18n.t('activerecord.errors.models.user.attributes.password.too_short', count: 8)}" }
it "validates password length" do it "validates password length" do
expect { FactoryBot.create(:user, password:) } expect { create(:user, password:) }
.to raise_error(ActiveRecord::RecordInvalid, error_message) .to raise_error(ActiveRecord::RecordInvalid, error_message)
end end
end end
@ -281,27 +281,27 @@ RSpec.describe User, type: :model do
let(:error_message) { "Validation failed: email #{I18n.t('activerecord.errors.models.user.attributes.email.invalid')}" } let(:error_message) { "Validation failed: email #{I18n.t('activerecord.errors.models.user.attributes.email.invalid')}" }
it "validates email format" do it "validates email format" do
expect { FactoryBot.create(:user, email: invalid_email) } expect { create(:user, email: invalid_email) }
.to raise_error(ActiveRecord::RecordInvalid, error_message) .to raise_error(ActiveRecord::RecordInvalid, error_message)
end end
end end
context "when the email entered has already been used" do context "when the email entered has already been used" do
let(:user) { FactoryBot.create(:user) } let(:user) { create(:user) }
let(:error_message) { "Validation failed: email #{I18n.t('activerecord.errors.models.user.attributes.email.taken')}" } let(:error_message) { "Validation failed: email #{I18n.t('activerecord.errors.models.user.attributes.email.taken')}" }
it "validates email uniqueness" do it "validates email uniqueness" do
expect { FactoryBot.create(:user, email: user.email) } expect { create(:user, email: user.email) }
.to raise_error(ActiveRecord::RecordInvalid, error_message) .to raise_error(ActiveRecord::RecordInvalid, error_message)
end end
end end
end end
describe "delete" do describe "delete" do
let(:user) { FactoryBot.create(:user) } let(:user) { create(:user) }
before do before do
FactoryBot.create( create(
:lettings_log, :lettings_log,
:completed, :completed,
owning_organisation: user.organisation, owning_organisation: user.organisation,
@ -309,7 +309,7 @@ RSpec.describe User, type: :model do
created_by: user, created_by: user,
) )
FactoryBot.create( create(
:sales_log, :sales_log,
owning_organisation: user.organisation, owning_organisation: user.organisation,
created_by: user, created_by: user,
@ -319,13 +319,13 @@ RSpec.describe User, type: :model do
context "when the user is deleted" do context "when the user is deleted" do
it "owned lettings logs are not deleted as a result" do it "owned lettings logs are not deleted as a result" do
expect { user.destroy! } expect { user.destroy! }
.to change(described_class, :count).from(1).to(0) .to change(described_class, :count).by(-1)
.and change(LettingsLog, :count).by(0) .and change(LettingsLog, :count).by(0)
end end
it "owned sales logs are not deleted as a result" do it "owned sales logs are not deleted as a result" do
expect { user.destroy! } expect { user.destroy! }
.to change(described_class, :count).from(1).to(0) .to change(described_class, :count).by(-1)
.and change(SalesLog, :count).by(0) .and change(SalesLog, :count).by(0)
end end
end end

13
spec/requests/bulk_upload_lettings_logs_controller_spec.rb

@ -1,7 +1,7 @@
require "rails_helper" require "rails_helper"
RSpec.describe BulkUploadLettingsLogsController, type: :request do RSpec.describe BulkUploadLettingsLogsController, type: :request do
let(:user) { FactoryBot.create(:user) } let(:user) { create(:user) }
let(:organisation) { user.organisation } let(:organisation) { user.organisation }
before do before do
@ -9,6 +9,17 @@ RSpec.describe BulkUploadLettingsLogsController, type: :request do
end end
describe "GET /lettings-logs/bulk-upload-logs/start" do describe "GET /lettings-logs/bulk-upload-logs/start" do
context "when data protection confirmation not signed" do
let(:organisation) { create(:organisation, :without_dpc) }
let(:user) { create(:user, organisation:) }
it "redirects to lettings index page" do
get "/lettings-logs/bulk-upload-logs/start", params: {}
expect(response).to redirect_to("/lettings-logs")
end
end
context "when not in crossover period" do context "when not in crossover period" do
let(:expected_year) { 2022 } let(:expected_year) { 2022 }

13
spec/requests/bulk_upload_sales_logs_controller_spec.rb

@ -1,7 +1,7 @@
require "rails_helper" require "rails_helper"
RSpec.describe BulkUploadSalesLogsController, type: :request do RSpec.describe BulkUploadSalesLogsController, type: :request do
let(:user) { FactoryBot.create(:user) } let(:user) { create(:user) }
let(:organisation) { user.organisation } let(:organisation) { user.organisation }
before do before do
@ -9,6 +9,17 @@ RSpec.describe BulkUploadSalesLogsController, type: :request do
end end
describe "GET /sales-logs/bulk-upload-logs/start" do describe "GET /sales-logs/bulk-upload-logs/start" do
context "when data protection confirmation not signed" do
let(:organisation) { create(:organisation, :without_dpc) }
let(:user) { create(:user, organisation:) }
it "redirects to sales index page" do
get "/sales-logs/bulk-upload-logs/start", params: {}
expect(response).to redirect_to("/sales-logs")
end
end
context "when not in crossover period" do context "when not in crossover period" do
let(:expected_year) { FormHandler.instance.forms["current_sales"].start_date.year } let(:expected_year) { FormHandler.instance.forms["current_sales"].start_date.year }

43
spec/requests/organisations_controller_spec.rb

@ -285,7 +285,7 @@ RSpec.describe OrganisationsController, type: :request do
end end
it "shows the pagination count" do it "shows the pagination count" do
expect(page).to have_content("3 total users") expect(page).to have_content("#{user.organisation.users.count} total users")
end end
end end
@ -1424,7 +1424,7 @@ RSpec.describe OrganisationsController, type: :request do
it "only includes users from that organisation" do it "only includes users from that organisation" do
get "/organisations/#{other_organisation.id}/users", headers:, params: {} get "/organisations/#{other_organisation.id}/users", headers:, params: {}
csv = CSV.parse(response.body) csv = CSV.parse(response.body)
expect(csv.count).to eq(3) expect(csv.count).to eq(other_organisation.users.count + 1)
end end
end end
end end
@ -1446,7 +1446,7 @@ RSpec.describe OrganisationsController, type: :request do
context "when flag not enabled" do context "when flag not enabled" do
before do before do
allow(FeatureToggle).to receive(:new_data_sharing_agreement?).and_return(false) allow(FeatureToggle).to receive(:new_data_protection_confirmation?).and_return(false)
end end
it "returns not found" do it "returns not found" do
@ -1457,7 +1457,7 @@ RSpec.describe OrganisationsController, type: :request do
context "when flag enabled" do context "when flag enabled" do
before do before do
allow(FeatureToggle).to receive(:new_data_sharing_agreement?).and_return(true) allow(FeatureToggle).to receive(:new_data_protection_confirmation?).and_return(true)
end end
it "returns ok" do it "returns ok" do
@ -1469,6 +1469,8 @@ RSpec.describe OrganisationsController, type: :request do
end end
describe "POST #data_sharing_agreement" do describe "POST #data_sharing_agreement" do
let(:organisation) { create(:organisation, :without_dpc) }
context "when not signed in" do context "when not signed in" do
it "redirects to sign in" do it "redirects to sign in" do
post "/organisations/#{organisation.id}/data-sharing-agreement", headers: headers post "/organisations/#{organisation.id}/data-sharing-agreement", headers: headers
@ -1484,7 +1486,7 @@ RSpec.describe OrganisationsController, type: :request do
context "when flag not enabled" do context "when flag not enabled" do
before do before do
allow(FeatureToggle).to receive(:new_data_sharing_agreement?).and_return(false) allow(FeatureToggle).to receive(:new_data_protection_confirmation?).and_return(false)
end end
it "returns not found" do it "returns not found" do
@ -1495,7 +1497,7 @@ RSpec.describe OrganisationsController, type: :request do
context "when flag enabled" do context "when flag enabled" do
before do before do
allow(FeatureToggle).to receive(:new_data_sharing_agreement?).and_return(true) allow(FeatureToggle).to receive(:new_data_protection_confirmation?).and_return(true)
end end
context "when user not dpo" do context "when user not dpo" do
@ -1508,7 +1510,17 @@ RSpec.describe OrganisationsController, type: :request do
end end
context "when user is dpo" do context "when user is dpo" do
let(:user) { create(:user, is_dpo: true) } context "when the organisation has a non-confirmed confirmation" do
let(:user) { create(:user, is_dpo: false) }
it "returns not found" do
post "/organisations/#{organisation.id}/data-sharing-agreement", headers: headers
expect(response).to have_http_status(:not_found)
end
end
context "when the organisation does not have a confirmation" do
let(:user) { create(:user, is_dpo: true, organisation:) }
it "returns redirects to details page" do it "returns redirects to details page" do
post "/organisations/#{organisation.id}/data-sharing-agreement", headers: headers post "/organisations/#{organisation.id}/data-sharing-agreement", headers: headers
@ -1519,23 +1531,21 @@ RSpec.describe OrganisationsController, type: :request do
end end
it "creates a data sharing agreement" do it "creates a data sharing agreement" do
expect(organisation.reload.data_sharing_agreement).to be_nil expect(organisation.reload.data_protection_confirmation).to be_nil
post("/organisations/#{organisation.id}/data-sharing-agreement", headers:) post("/organisations/#{organisation.id}/data-sharing-agreement", headers:)
data_sharing_agreement = organisation.reload.data_sharing_agreement data_protection_confirmation = organisation.reload.data_protection_confirmation
expect(data_sharing_agreement.organisation_address).to eq(organisation.address_row) expect(data_protection_confirmation.organisation.address_row).to eq(organisation.address_row)
expect(data_sharing_agreement.organisation_name).to eq(organisation.name) expect(data_protection_confirmation.organisation.name).to eq(organisation.name)
expect(data_sharing_agreement.organisation_phone_number).to eq(organisation.phone) expect(data_protection_confirmation.organisation.phone).to eq(organisation.phone)
expect(data_sharing_agreement.data_protection_officer).to eq(user) expect(data_protection_confirmation.data_protection_officer).to eq(user)
expect(data_sharing_agreement.dpo_name).to eq(user.name)
expect(data_sharing_agreement.dpo_email).to eq(user.email)
end end
context "when the user has already accepted the agreement" do context "when the user has already accepted the agreement" do
before do before do
create(:data_sharing_agreement, data_protection_officer: user, organisation: user.organisation) create(:data_protection_confirmation, data_protection_officer: user, organisation: user.organisation)
end end
it "returns not found" do it "returns not found" do
@ -1547,4 +1557,5 @@ RSpec.describe OrganisationsController, type: :request do
end end
end end
end end
end
end end

20
spec/requests/users_controller_spec.rb

@ -363,7 +363,7 @@ RSpec.describe UsersController, type: :request do
end end
context "when user is signed in as a data coordinator" do context "when user is signed in as a data coordinator" do
let(:user) { FactoryBot.create(:user, :data_coordinator, email: "coordinator@example.com") } let(:user) { FactoryBot.create(:user, :data_coordinator, email: "coordinator@example.com", organisation: create(:organisation, :without_dpc)) }
let!(:other_user) { FactoryBot.create(:user, organisation: user.organisation, name: "filter name", email: "filter@example.com") } let!(:other_user) { FactoryBot.create(:user, organisation: user.organisation, name: "filter name", email: "filter@example.com") }
describe "#index" do describe "#index" do
@ -969,7 +969,7 @@ RSpec.describe UsersController, type: :request do
end end
context "when user is signed in as a support user" do context "when user is signed in as a support user" do
let(:user) { FactoryBot.create(:user, :support) } let(:user) { FactoryBot.create(:user, :support, organisation: create(:organisation, :without_dpc)) }
let(:other_user) { FactoryBot.create(:user, organisation: user.organisation) } let(:other_user) { FactoryBot.create(:user, organisation: user.organisation) }
before do before do
@ -979,7 +979,7 @@ RSpec.describe UsersController, type: :request do
describe "#index" do describe "#index" do
let!(:other_user) { FactoryBot.create(:user, organisation: user.organisation, name: "User 2", email: "other@example.com") } let!(:other_user) { FactoryBot.create(:user, organisation: user.organisation, name: "User 2", email: "other@example.com") }
let!(:inactive_user) { FactoryBot.create(:user, organisation: user.organisation, active: false, name: "User 3", email: "inactive@example.com") } let!(:inactive_user) { FactoryBot.create(:user, organisation: user.organisation, active: false, name: "User 3", email: "inactive@example.com") }
let!(:other_org_user) { FactoryBot.create(:user, name: "User 4", email: "otherorg@otherexample.com") } let!(:other_org_user) { FactoryBot.create(:user, name: "User 4", email: "otherorg@otherexample.com", organisation: create(:organisation, :without_dpc)) }
before do before do
sign_in user sign_in user
@ -1058,7 +1058,7 @@ RSpec.describe UsersController, type: :request do
context "when our search term matches an email and a name" do context "when our search term matches an email and a name" do
let!(:other_user) { FactoryBot.create(:user, organisation: user.organisation, name: "joe", email: "other@example.com") } let!(:other_user) { FactoryBot.create(:user, organisation: user.organisation, name: "joe", email: "other@example.com") }
let!(:other_org_user) { FactoryBot.create(:user, name: "User 4", email: "joe@otherexample.com") } let!(:other_org_user) { FactoryBot.create(:user, name: "User 4", email: "joe@otherexample.com", organisation: create(:organisation, :without_dpc)) }
let(:search_param) { "joe" } let(:search_param) { "joe" }
it "returns any results including joe" do it "returns any results including joe" do
@ -1090,15 +1090,19 @@ RSpec.describe UsersController, type: :request do
get "/users", headers:, params: {} get "/users", headers:, params: {}
end end
let(:byte_order_mark) { "\uFEFF" }
it "downloads a CSV file with headers" do it "downloads a CSV file with headers" do
csv = CSV.parse(response.body) csv = CSV.parse(response.body)
expect(csv.first.second).to eq("email")
expect(csv.second.first).to eq(user.id.to_s) expect(csv.first.to_csv).to eq(
"#{byte_order_mark}id,email,name,organisation_name,role,old_user_id,is_dpo,is_key_contact,active,sign_in_count,last_sign_in_at\n",
)
end end
it "downloads all users" do it "downloads all users" do
csv = CSV.parse(response.body) csv = CSV.parse(response.body)
expect(csv.count).to eq(27) expect(csv.count).to eq(User.all.count + 1) # +1 for the headers
end end
it "downloads organisation names rather than ids" do it "downloads organisation names rather than ids" do
@ -1517,7 +1521,7 @@ RSpec.describe UsersController, type: :request do
end end
describe "#create" do describe "#create" do
let(:organisation) { FactoryBot.create(:organisation) } let(:organisation) { FactoryBot.create(:organisation, :without_dpc) }
let(:email) { "new_user@example.com" } let(:email) { "new_user@example.com" }
let(:params) do let(:params) do
{ {

10
spec/services/imports/data_protection_confirmation_import_service_spec.rb

@ -29,7 +29,7 @@ RSpec.describe Imports::DataProtectionConfirmationImportService do
end end
context "when the organisation does exist" do context "when the organisation does exist" do
let!(:organisation) { FactoryBot.create(:organisation, old_org_id:) } let!(:organisation) { create(:organisation, :without_dpc, old_org_id:) }
context "when a data protection officer with matching name does not exists for the organisation" do context "when a data protection officer with matching name does not exists for the organisation" do
it "creates a data protection officer without sign in credentials" do it "creates a data protection officer without sign in credentials" do
@ -41,7 +41,7 @@ RSpec.describe Imports::DataProtectionConfirmationImportService do
it "successfully create a data protection confirmation record with the expected data" do it "successfully create a data protection confirmation record with the expected data" do
import_service.create_data_protection_confirmations("data_protection_directory") import_service.create_data_protection_confirmations("data_protection_directory")
confirmation = Organisation.find_by(old_org_id:).data_protection_confirmations.last confirmation = Organisation.find_by(old_org_id:).data_protection_confirmation
expect(confirmation.data_protection_officer.name).to eq("John Doe") expect(confirmation.data_protection_officer.name).to eq("John Doe")
expect(confirmation.confirmed).to be_truthy expect(confirmation.confirmed).to be_truthy
expect(Time.zone.local_to_utc(confirmation.created_at)).to eq(Time.utc(2018, 0o6, 0o5, 10, 36, 49)) expect(Time.zone.local_to_utc(confirmation.created_at)).to eq(Time.utc(2018, 0o6, 0o5, 10, 36, 49))
@ -50,13 +50,13 @@ RSpec.describe Imports::DataProtectionConfirmationImportService do
context "when a data protection officer with matching name already exists for the organisation" do context "when a data protection officer with matching name already exists for the organisation" do
let!(:data_protection_officer) do let!(:data_protection_officer) do
FactoryBot.create(:user, :data_protection_officer, name: "John Doe", organisation:) create(:user, :data_protection_officer, name: "John Doe", organisation:)
end end
it "successfully creates a data protection confirmation record with the expected data" do it "successfully creates a data protection confirmation record with the expected data" do
import_service.create_data_protection_confirmations("data_protection_directory") import_service.create_data_protection_confirmations("data_protection_directory")
confirmation = Organisation.find_by(old_org_id:).data_protection_confirmations.last confirmation = Organisation.find_by(old_org_id:).data_protection_confirmation
expect(confirmation.data_protection_officer.id).to eq(data_protection_officer.id) expect(confirmation.data_protection_officer.id).to eq(data_protection_officer.id)
expect(confirmation.confirmed).to be_truthy expect(confirmation.confirmed).to be_truthy
expect(Time.zone.local_to_utc(confirmation.created_at)).to eq(Time.utc(2018, 0o6, 0o5, 10, 36, 49)) expect(Time.zone.local_to_utc(confirmation.created_at)).to eq(Time.utc(2018, 0o6, 0o5, 10, 36, 49))
@ -64,7 +64,7 @@ RSpec.describe Imports::DataProtectionConfirmationImportService do
context "when the data protection record has already been imported previously" do context "when the data protection record has already been imported previously" do
before do before do
FactoryBot.create( create(
:data_protection_confirmation, :data_protection_confirmation,
organisation:, organisation:,
data_protection_officer:, data_protection_officer:,

49
spec/shared/shared_log_examples.rb

@ -104,5 +104,54 @@ RSpec.shared_examples "shared log examples" do |log_type|
end end
end end
end end
describe "#verify_data_protection_confirmation" do
before do
allow(FeatureToggle).to receive(:new_data_protection_confirmation?).and_return(false)
end
it "is valid if the DSA is signed" do
log = build(log_type, :in_progress, owning_organisation: create(:organisation))
expect(log).to be_valid
end
it "is valid when owning_organisation nil" do
log = build(log_type, owning_organisation: nil)
expect(log).to be_valid
end
it "is not valid if the DSA is not signed" do
log = build(log_type, owning_organisation: create(:organisation, :without_dpc))
expect(log).to be_valid
end
end
context "when flag enabled" do
before do
allow(FeatureToggle).to receive(:new_data_protection_confirmation?).and_return(true)
end
it "is valid if the DSA is signed" do
log = build(log_type, :in_progress, owning_organisation: create(:organisation))
expect(log).to be_valid
end
it "is valid when owning_organisation nil" do
log = build(log_type, owning_organisation: nil)
expect(log).to be_valid
end
it "is not valid if the DSA is not signed" do
log = build(log_type, owning_organisation: create(:organisation, :without_dpc))
expect(log).not_to be_valid
expect(log.errors[:owning_organisation]).to eq(["Your organisation must accept the Data Sharing Agreement before you can create any logs."])
end
end
end end
# rubocop:enable RSpec/AnyInstance # rubocop:enable RSpec/AnyInstance

50
spec/views/logs/_create_for_org_actions.html.erb_spec.rb

@ -0,0 +1,50 @@
require "rails_helper"
RSpec.describe "logs/_create_for_org_actions.html.erb" do
before do
allow(view).to receive(:current_user).and_return(user)
allow(view).to receive(:current_page?).and_return(true)
assign(:organisation, user.organisation)
end
let(:fragment) { Capybara::Node::Simple.new(rendered) }
let(:user) { create(:user) }
context "when flag disabled" do
before do
allow(FeatureToggle).to receive(:new_data_protection_confirmation?).and_return(false)
end
it "shows create buttons" do
render
expect(fragment).to have_button("Create a new lettings log for this organisation")
expect(fragment).to have_button("Create a new sales log for this organisation")
end
end
context "when flag enabled" do
before do
allow(FeatureToggle).to receive(:new_data_protection_confirmation?).and_return(true)
end
context "with data sharing agreement" do
it "does include create log buttons" do
render
expect(fragment).to have_button("Create a new lettings log for this organisation")
expect(fragment).to have_button("Create a new sales log for this organisation")
end
end
context "without data sharing agreement" do
let(:user) { create(:user, organisation: create(:organisation, :without_dpc)) }
it "does not include create log buttons" do
render
expect(fragment).not_to have_button("Create a new lettings log for this organisation")
expect(fragment).not_to have_button("Create a new sales log for this organisation")
end
end
end
end

42
spec/views/organisations/data_sharing_agreement.html.erb_spec.rb

@ -5,7 +5,7 @@ RSpec.describe "organisations/data_sharing_agreement.html.erb", :aggregate_failu
Timecop.freeze(Time.zone.local(2023, 1, 10)) Timecop.freeze(Time.zone.local(2023, 1, 10))
allow(view).to receive(:current_user).and_return(user) allow(view).to receive(:current_user).and_return(user)
assign(:organisation, organisation) assign(:organisation, organisation)
assign(:data_sharing_agreement, data_sharing_agreement) assign(:data_protection_confirmation, data_protection_confirmation)
end end
after do after do
@ -14,10 +14,10 @@ RSpec.describe "organisations/data_sharing_agreement.html.erb", :aggregate_failu
let(:fragment) { Capybara::Node::Simple.new(rendered) } let(:fragment) { Capybara::Node::Simple.new(rendered) }
let(:organisation) { user.organisation } let(:organisation) { user.organisation }
let(:data_sharing_agreement) { nil } let(:data_protection_confirmation) { nil }
context "when dpo" do context "when dpo" do
let(:user) { create(:user, is_dpo: true) } let(:user) { create(:user, is_dpo: true, organisation: create(:organisation, :without_dpc)) }
it "renders dynamic content" do it "renders dynamic content" do
render render
@ -36,32 +36,34 @@ RSpec.describe "organisations/data_sharing_agreement.html.erb", :aggregate_failu
expect(fragment).to have_content("12.2. For #{organisation.name}: Name: #{user.name}, Postal Address: #{organisation.address_row}, E-mail address: #{user.email}, Telephone number: #{organisation.phone}") expect(fragment).to have_content("12.2. For #{organisation.name}: Name: #{user.name}, Postal Address: #{organisation.address_row}, E-mail address: #{user.email}, Telephone number: #{organisation.phone}")
end end
context "when accepted" do context "when confirmed" do
let(:data_sharing_agreement) do let(:data_protection_confirmation) do
create( create(
:data_sharing_agreement, :data_protection_confirmation,
organisation:, organisation:,
signed_at: Time.zone.now - 1.day, created_at: Time.zone.now - 1.day,
) )
end end
let(:dpo) { data_protection_confirmation.data_protection_officer }
it "renders dynamic content" do it "renders dynamic content" do
render render
# dpo name # dpo name
expect(fragment).to have_content("Name: #{data_sharing_agreement.dpo_name}") expect(fragment).to have_content("Name: #{dpo.name}")
# org details # org details
expect(fragment).to have_content("#{data_sharing_agreement.organisation_name} of #{data_sharing_agreement.organisation_address} (“CORE Data Provider”)") expect(fragment).to have_content("#{organisation.name} of #{organisation.address_row} (“CORE Data Provider”)")
# header # header
expect(fragment).to have_css("h2", text: "#{data_sharing_agreement.organisation_name} and Department for Levelling Up, Housing and Communities") expect(fragment).to have_css("h2", text: "#{organisation.name} and Department for Levelling Up, Housing and Communities")
# does not show action buttons # does not show action buttons
expect(fragment).not_to have_button(text: "Accept this agreement") expect(fragment).not_to have_button(text: "Accept this agreement")
expect(fragment).not_to have_link(text: "Cancel", href: "/organisations/#{organisation.id}/details") expect(fragment).not_to have_link(text: "Cancel", href: "/organisations/#{organisation.id}/details")
# sees signed_at date # sees signed_at date
expect(fragment).to have_content("9th day of January 2023") expect(fragment).to have_content("9th day of January 2023")
# Shows DPO and org details in 12.2 # Shows DPO and org details in 12.2
expect(fragment).to have_content("12.2. For #{data_sharing_agreement.organisation_name}: Name: #{data_sharing_agreement.dpo_name}, Postal Address: #{data_sharing_agreement.organisation_address}, E-mail address: #{data_sharing_agreement.dpo_email}, Telephone number: #{data_sharing_agreement.organisation_phone_number}") expect(fragment).to have_content("12.2. For #{organisation.name}: Name: #{dpo.name}, Postal Address: #{organisation.address_row}, E-mail address: #{dpo.email}, Telephone number: #{organisation.phone}")
end end
end end
end end
@ -86,30 +88,32 @@ RSpec.describe "organisations/data_sharing_agreement.html.erb", :aggregate_failu
expect(fragment).to have_content("12.2. For #{organisation.name}: Name: [DPO name], Postal Address: #{organisation.address_row}, E-mail address: [DPO email], Telephone number: #{organisation.phone}") expect(fragment).to have_content("12.2. For #{organisation.name}: Name: [DPO name], Postal Address: #{organisation.address_row}, E-mail address: [DPO email], Telephone number: #{organisation.phone}")
end end
context "when accepted" do context "when confirmed" do
let(:data_sharing_agreement) do let(:data_protection_confirmation) do
create( create(
:data_sharing_agreement, :data_protection_confirmation,
organisation:, organisation:,
signed_at: Time.zone.now - 1.day, created_at: Time.zone.now - 1.day,
) )
end end
let(:dpo) { data_protection_confirmation.data_protection_officer }
it "renders dynamic content" do it "renders dynamic content" do
render render
# sees signed_at date # sees signed_at date
expect(fragment).to have_content("9th day of January 2023") expect(fragment).to have_content("9th day of January 2023")
# dpo name placedholder # dpo name placedholder
expect(fragment).to have_content("Name: #{data_sharing_agreement.dpo_name}") expect(fragment).to have_content("Name: #{dpo.name}")
# org details # org details
expect(fragment).to have_content("#{data_sharing_agreement.organisation_name} of #{data_sharing_agreement.organisation_address} (“CORE Data Provider”)") expect(fragment).to have_content("#{organisation.name} of #{organisation.address_row} (“CORE Data Provider”)")
# header # header
expect(fragment).to have_css("h2", text: "#{data_sharing_agreement.organisation_name} and Department for Levelling Up, Housing and Communities") expect(fragment).to have_css("h2", text: "#{organisation.name} and Department for Levelling Up, Housing and Communities")
# does not show action buttons # does not show action buttons
expect(fragment).not_to have_button(text: "Accept this agreement") expect(fragment).not_to have_button(text: "Accept this agreement")
expect(fragment).not_to have_link(text: "Cancel", href: "/organisations/#{organisation.id}/details") expect(fragment).not_to have_link(text: "Cancel", href: "/organisations/#{organisation.id}/details")
# Shows filled in details in 12.2 # Shows filled in details in 12.2
expect(fragment).to have_content("12.2. For #{data_sharing_agreement.organisation_name}: Name: #{data_sharing_agreement.dpo_name}, Postal Address: #{data_sharing_agreement.organisation_address}, E-mail address: #{data_sharing_agreement.dpo_email}, Telephone number: #{data_sharing_agreement.organisation_phone_number}") expect(fragment).to have_content("12.2. For #{organisation.name}: Name: #{dpo.name}, Postal Address: #{organisation.address_row}, E-mail address: #{dpo.email}, Telephone number: #{organisation.phone}")
end end
end end
end end

41
spec/views/organisations/show.html.erb_spec.rb

@ -4,8 +4,7 @@ RSpec.describe "organisations/show.html.erb" do
before do before do
Timecop.freeze(Time.zone.local(2023, 1, 10)) Timecop.freeze(Time.zone.local(2023, 1, 10))
allow(view).to receive(:current_user).and_return(user) allow(view).to receive(:current_user).and_return(user)
assign(:organisation, organisation) assign(:organisation, user.organisation)
organisation.update!(data_sharing_agreement:)
end end
after do after do
@ -13,14 +12,14 @@ RSpec.describe "organisations/show.html.erb" do
end end
let(:fragment) { Capybara::Node::Simple.new(rendered) } let(:fragment) { Capybara::Node::Simple.new(rendered) }
let(:organisation) { user.organisation } let(:organisation_without_dpc) { create(:organisation, :without_dpc) }
let(:data_sharing_agreement) { nil } let(:organisation_with_dsa) { create(:organisation) }
context "when flag disabled" do context "when flag disabled" do
let(:user) { create(:user) } let(:user) { create(:user, organisation: organisation_without_dpc) }
before do before do
allow(FeatureToggle).to receive(:new_data_sharing_agreement?).and_return(false) allow(FeatureToggle).to receive(:new_data_protection_confirmation?).and_return(false)
end end
it "does not include data sharing agreement row" do it "does not include data sharing agreement row" do
@ -31,7 +30,7 @@ RSpec.describe "organisations/show.html.erb" do
end end
context "when dpo" do context "when dpo" do
let(:user) { create(:user, is_dpo: true) } let(:user) { create(:user, is_dpo: true, organisation: organisation_without_dpc) }
it "includes data sharing agreement row" do it "includes data sharing agreement row" do
render render
@ -48,11 +47,11 @@ RSpec.describe "organisations/show.html.erb" do
it "shows link to view data sharing agreement" do it "shows link to view data sharing agreement" do
render render
expect(fragment).to have_link(text: "View agreement", href: "/organisations/#{organisation.id}/data-sharing-agreement") expect(fragment).to have_link(text: "View agreement", href: "/organisations/#{organisation_without_dpc.id}/data-sharing-agreement")
end end
context "when accepted" do context "when accepted" do
let(:data_sharing_agreement) { create(:data_sharing_agreement, organisation:, signed_at: Time.zone.now - 1.day) } let(:user) { create(:user, organisation: organisation_with_dsa) }
it "includes data sharing agreement row" do it "includes data sharing agreement row" do
render render
@ -69,13 +68,13 @@ RSpec.describe "organisations/show.html.erb" do
it "shows link to view data sharing agreement" do it "shows link to view data sharing agreement" do
render render
expect(fragment).to have_link(text: "View agreement", href: "/organisations/#{organisation.id}/data-sharing-agreement") expect(fragment).to have_link(text: "View agreement", href: "/organisations/#{organisation_with_dsa.id}/data-sharing-agreement")
end end
end end
end end
context "when support user" do context "when support user" do
let(:user) { create(:user, :support) } let(:user) { create(:user, :support, organisation: organisation_without_dpc) }
it "includes data sharing agreement row" do it "includes data sharing agreement row" do
render render
@ -98,11 +97,11 @@ RSpec.describe "organisations/show.html.erb" do
it "shows link to view data sharing agreement" do it "shows link to view data sharing agreement" do
render render
expect(fragment).to have_link(text: "View agreement", href: "/organisations/#{organisation.id}/data-sharing-agreement") expect(fragment).to have_link(text: "View agreement", href: "/organisations/#{organisation_without_dpc.id}/data-sharing-agreement")
end end
context "when accepted" do context "when accepted" do
let(:data_sharing_agreement) { create(:data_sharing_agreement, organisation:, signed_at: Time.zone.now - 1.day) } let(:user) { create(:user, :support, organisation: organisation_with_dsa) }
it "includes data sharing agreement row" do it "includes data sharing agreement row" do
render render
@ -113,25 +112,25 @@ RSpec.describe "organisations/show.html.erb" do
it "shows data sharing agreement accepted with date" do it "shows data sharing agreement accepted with date" do
render render
expect(fragment).to have_content("Accepted 09/01/2023") expect(fragment).to have_content("Accepted 10/01/2023")
end end
it "shows show name of who signed the agreement" do it "shows show name of who signed the agreement" do
render render
expect(fragment).to have_content(data_sharing_agreement.dpo_name) expect(fragment).to have_content(user.organisation.data_protection_confirmation.data_protection_officer.name)
end end
it "shows link to view data sharing agreement" do it "shows link to view data sharing agreement" do
render render
expect(fragment).to have_link(text: "View agreement", href: "/organisations/#{organisation.id}/data-sharing-agreement") expect(fragment).to have_link(text: "View agreement", href: "/organisations/#{organisation_with_dsa.id}/data-sharing-agreement")
end end
end end
end end
context "when not dpo" do context "when not dpo" do
let(:user) { create(:user) } let(:user) { create(:user, organisation: organisation_without_dpc) }
it "includes data sharing agreement row" do it "includes data sharing agreement row" do
render render
@ -151,13 +150,11 @@ RSpec.describe "organisations/show.html.erb" do
it "shows link to view data sharing agreement" do it "shows link to view data sharing agreement" do
render render
expect(fragment).to have_link(text: "View agreement", href: "/organisations/#{organisation.id}/data-sharing-agreement") expect(fragment).to have_link(text: "View agreement", href: "/organisations/#{organisation_without_dpc.id}/data-sharing-agreement")
end end
context "when accepted" do context "when accepted" do
let(:data_sharing_agreement) do let(:user) { create(:user, organisation: organisation_with_dsa) }
create(:data_sharing_agreement, organisation:, signed_at: Time.zone.now - 1.day)
end
it "includes data sharing agreement row" do it "includes data sharing agreement row" do
render render
@ -172,7 +169,7 @@ RSpec.describe "organisations/show.html.erb" do
it "shows link to view data sharing agreement" do it "shows link to view data sharing agreement" do
render render
expect(fragment).to have_link(text: "View agreement", href: "/organisations/#{organisation.id}/data-sharing-agreement") expect(fragment).to have_link(text: "View agreement", href: "/organisations/#{organisation_with_dsa.id}/data-sharing-agreement")
end end
end end
end end

Loading…
Cancel
Save