Skip to content

Setup script

Han edited this page Jul 9, 2025 · 3 revisions
# frozen_string_literal: true

require "factory_bot_rails"

# copy this into lib/tasks/dpr_things.rake
# make prompt
# bin/bundle exec rake dpr_things:setup
# bin/bundle exec rake dpr_things:make_applications
# bin/bundle exec rake dpr_things:make_application_in_consultation
# bin/bundle exec rake dpr_things:make_application_have_consultation REFERENCE=25-00338-HAPP
namespace :dpr_things do
  desc "DPR utilities and tools"

  def build_consultee_responses(with_redaction_order:)
    with_redaction_order.map do |with_redaction|
      FactoryBot.build(
        :consultee_response,
        *(with_redaction ? [:with_redaction] : []),
        summary_tag: Consultee::Response.summary_tags.keys.sample
      )
    end
  end

  def create_consultees(type:, consultation:, with_redaction: false, with_response: false, count: 5, responses: nil, **extra_attributes)
    count.times do
      attributes = {consultation: consultation}.merge(extra_attributes)
      traits = [type, :consulted]

      # Use provided responses if given, otherwise build as before
      if responses
        attributes[:responses] = responses
      elsif with_response
        responses = FactoryBot.build_list(
          :consultee_response,
          1,
          *(with_redaction ? [:with_redaction] : []),
          summary_tag: Consultee::Response.summary_tags.keys.sample
        )
        attributes[:responses] = responses
      end

      FactoryBot.create(:consultee, *traits, **attributes)
    end
  end

  def create_neighbour_responses(consultation:, count: 10, with_redaction: false)
    count.times do
      neighbour = FactoryBot.create(:neighbour, consultation: consultation)
      traits = []
      traits << :without_redaction unless with_redaction
      FactoryBot.create(
        :neighbour_response,
        *traits,
        summary_tag: NeighbourResponse.summary_tags.keys.sample,
        neighbour: neighbour
      )
    end
  end

  def summarise_application(planning_application)
    puts "\n\n"
    puts "Created planning application ✅\n"
    puts "Reference: #{planning_application.reference}"
    puts "Status: #{planning_application.status}"
    puts "Admin url: http://southwark.bops.localhost:3000/planning_applications/#{planning_application.reference}"

    if planning_application.published_at?
      puts "Application is published"
      puts "Public API url: http://southwark.bops.localhost:3000/api/v2/public/planning_applications/#{planning_application.reference}"
    else
      puts "Application is not published"
    end

    if planning_application.consultation.neighbour_responses.any?
      puts "\n\n"
      puts "PUBLIC COMMENTS\n"
      puts "Consultation has #{planning_application.consultation.neighbour_responses.count} neighbour responses"
      puts "Currently #{planning_application.consultation.neighbour_responses.count - planning_application.consultation.neighbour_responses.redacted.count} are available publicly"
      puts "View the public API at: http://southwark.bops.localhost:3000/api/v2/public/planning_applications/#{planning_application.reference}/comments/public"
    end

    if planning_application.consultation.consultees.any?
      puts "\n\n"
      puts "SPECIALIST COMMENTS\n"
      puts "Consultation has #{planning_application.consultation.consultees.count} specialists and #{planning_application.consultation.consultee_responses.count} responses"
      puts "Currently #{planning_application.consultation.consultee_responses.redacted.count} are available publicly"
      puts "View the public API at: http://southwark.bops.localhost:3000/api/v2/public/planning_applications/#{planning_application.reference}/comments/specialist"

      puts "\n\n"

      puts [
        "ID".ljust(10),
        "Name".ljust(30),
        "Responses".ljust(20),
        "Public Responses".ljust(20),
        "Constraints".ljust(60)
      ].join(" | ")

      puts "-" * 110

      planning_application.consultation.consultees.each do |consultee|
        id = consultee.id.to_s.ljust(10)
        name = consultee.name.to_s.ljust(30)
        responses = consultee.responses.count.to_s.ljust(20)
        public_responses = consultee.responses.redacted.count.to_s.ljust(20)
        constraints = consultee.planning_application_constraints.map(&:type).join(", ").to_s.ljust(60)
        puts [id, name, responses, public_responses, constraints].join(" | ")
      end

      # puts "\n\n"
      # puts "Magic links to comment as specialist:"
      # planning_application.consultation.consultees.each do |consultee|
      #   puts "#{consultee.name.to_s}: \n#{consultee.application_link}\n\n"
      # end

    end
  end

  def create_consultation(planning_application)
    # add some new constaints directly to the planning application from BOPS
    constraint1 = FactoryBot.create(:constraint, :listed)
    constraint2 = FactoryBot.create(:constraint, :tpo)
    constraint3 = FactoryBot.create(:constraint)

    planning_application.planning_application_constraints.find_or_create_by(constraint: constraint1, identified: true, identified_by: "BOPS").save!
    planning_application.planning_application_constraints.find_or_create_by(constraint: constraint2, identified: true, identified_by: "BOPS").save!
    planning_application.planning_application_constraints.find_or_create_by(constraint: constraint3, identified: true, identified_by: "BOPS").save!

    # SPECIALIST COMMENTS

    # assign specialists to the constraints
    constraint_consultee_1 = FactoryBot.create(:consultee, :internal, consultation: planning_application.consultation, name: "Harriet Historian")
    constraint_consultee_2 = FactoryBot.create(:consultee, :external, consultation: planning_application.consultation, name: "Chris Wood")

    planning_application.planning_application_constraints.first.update!(consultee_id: constraint_consultee_1.id)
    planning_application.planning_application_constraints.last.update!(consultee_id: constraint_consultee_2.id)

    # create a consultee with mixed visibility responses
    all_private_responses = build_consultee_responses(with_redaction_order: [false, false, false])
    all_public_responses = build_consultee_responses(with_redaction_order: [true, true, true])
    mixed_public_private_responses = build_consultee_responses(with_redaction_order: [true, false, true])
    # random_public_private_responses = build_consultee_responses(with_redaction_order: Array.new(rand(2...15)) { [true, false].sample })

    # for each response type make a new consultee
    {
      "Private" => all_private_responses,
      "Public" => all_public_responses,
      "Mixed" => mixed_public_private_responses
    }.each do |type, responses|
      create_consultees(
        type: :internal,
        consultation: planning_application.consultation,
        responses: responses,
        count: 1,
        name: "#{type} Internalson"
      )
      create_consultees(
        type: :external,
        consultation: planning_application.consultation,
        responses: responses,
        count: 1,
        name: "#{type} Externalson"
      )
    end

    # create 5 internal consultees with no responses
    create_consultees(type: :internal, consultation: planning_application.consultation, with_redaction: false, with_response: false)
    # create 5 internal consultees with redaction
    create_consultees(type: :internal, consultation: planning_application.consultation, with_redaction: true, with_response: true)
    # create 5 internal consultees without redaction
    create_consultees(type: :internal, consultation: planning_application.consultation, with_redaction: false, with_response: true)
    # create 5 external consultees with no responses
    create_consultees(type: :external, consultation: planning_application.consultation, with_redaction: false, with_response: false)
    # create 5 external consultees with redaction
    create_consultees(type: :external, consultation: planning_application.consultation, with_redaction: true, with_response: true)
    # create 5 external consultees without redaction
    create_consultees(type: :external, consultation: planning_application.consultation, with_redaction: false, with_response: true)

    # PUBLIC COMMENTS

    # create 10 public comments without redaction
    create_neighbour_responses(consultation: planning_application.consultation, count: 10, with_redaction: false)

    # create 10 comments with redaction
    create_neighbour_responses(consultation: planning_application.consultation, count: 10, with_redaction: true)

    puts "\n\n"
  end

  task make_application_in_consultation: :environment do
    puts "\n\n"
    puts "Creating application in consultation..."
    local_authority = LocalAuthority.find_by(subdomain: "southwark")

    planning_application = FactoryBot.create(
      :planning_application,
      :planning_permission,
      :published,
      :consulting,
      local_authority: local_authority
    )

    create_consultation(planning_application)
    summarise_application(planning_application)
    puts "\n\n"
  end

  task make_application_have_consultation: :environment do
    reference = ENV["REFERENCE"]

    if reference.blank?
      puts "Please provide a reference using REFERENCE=YOUR_REFERENCE_HERE"
      puts "Example: bin/bundle exec rake dpr_things:make_application_have_consultation REFERENCE=25-00338-HAPP"
      exit
    end

    puts "\n\n"
    puts "Adding consultation details to application #{reference}..."

    planning_application = PlanningApplication.find_by(reference:)

    if planning_application.nil?
      puts "No planning application found with reference #{reference}"
      exit
    end

    create_consultation(planning_application)
    summarise_application(planning_application)
    puts "\n\n"
  end

  task setup: :environment do
    puts "\n\n"
    puts "Setting up the development environment..."
    password = PasswordGenerator.call
    puts "SAVE THIS PASSWORD: #{password}"
    puts "\n\n"

    puts "Checking local authorities exist..."
    local_authority_names = LocalAuthority.pluck(:subdomain).join(", ")
    puts "Local authorities: #{local_authority_names}"
    puts "\n\n"

    puts "Giving local authorities data to make them active..."
    southwark_la = LocalAuthority.find_by(subdomain: "southwark")
    southwark_la.update(reviewer_group_email: "fg-dev@tpximpact.com", email_reply_to_id: SecureRandom.uuid, notify_api_key: SecureRandom.uuid)
    if southwark_la.errors.any?
      puts "Failed to update local authority: #{southwark_la.subdomain}, #{southwark_la.errors.full_messages.join(", ")}"
    else
      puts "Updated local authority: #{southwark_la.subdomain}"
    end
    puts "southwark_la: #{southwark_la.active}"

    puts "\n\n"

    puts "Creating legislation..."
    our_legislation = Legislation.create(
      title: "Guinea Pig Accommodation Act 2025",
      description: "This Act sets out requirements for the appropriate housing of guinea pigs in the United Kingdom, ensuring their accommodation meets welfare standards that protect them from adverse weather, predators, and unsuitable living conditions."
    )
    if our_legislation.persisted?
      puts "Legislation created - #{our_legislation.title}"
    else
      puts "Failed to create legislation: #{our_legislation.errors.full_messages.join(", ")}"
    end
    puts "\n\n"

    puts "Enabling application types..."
    puts "Go to http://config.bops.localhost:3000/application_types and activate all application types!"
    # @todo this:
    # active_application_types = ApplicationType.active
    # if active_application_types.empty?
    #   inactive_application_types = ApplicationType.inactive
    #   inactive_application_types.each do |application_type|
    #     application_type.update(legislation_id: our_legislation.id, status: "active")
    #     if application_type.errors.any?
    #       puts "Failed to enable application type: #{application_type.name}, #{application_type.errors.full_messages.join(", ")}"
    #     else
    #       puts "Enabled application type: #{application_type.name}"
    #     end
    #   end
    #   puts "#{ApplicationType.active.count}"
    # end

    puts "\n\n"

    puts "Creating global user..."
    user = User.create(
      name: "Al Powerful",
      local_authority: nil,
      otp_required_for_login: false,
      role: "global_administrator",
      email: "global_administrator@example.com",
      confirmed_at: Time.zone.now,
      password: password
    )

    if user.persisted?
      puts "Global User created - #{user.email}"
    else
      puts "Failed to create user: #{user.errors.full_messages.join(", ")}"
    end
    puts "\n"
    puts "global_administrator@example.com\n#{password}\nhttp://config.bops.localhost:3000/users/sign_in"
    puts "\n\n"

    puts "Update all the southwark user passwords so we can login..."
    southwark_users = User.where(local_authority_id: southwark_la.id)
    southwark_users.each do |user|
      user.update(password: password, otp_required_for_login: false, confirmed_at: Time.zone.now)
      if user.errors.any?
        puts "Failed to update user: #{user.email}, #{user.errors.full_messages.join(", ")}"
      else
        puts "Updated user: #{user.email}"
      end
      puts "\n\n"
      puts "#{user.email}\n#{password}\nhttp://southwark.bops.localhost:3000/users/sign_in"
    end

    puts "\n\n"

    puts "Getting API token..."
    api_user = ApiUser.find_by(name: "southwark")
    token = api_user.token
    puts "\n"
    puts "token: #{token}\nhttp://southwark.bops.localhost:3000/api/docs/index.html?urls.primaryName=API%20V2%20Docs"

    puts "\n\n"

    puts "Setup complete!"
  end

  task make_applications: :environment do
    local_authority = LocalAuthority.find_by(subdomain: "southwark")
    FactoryBot.create(:planning_application, :in_assessment, local_authority: local_authority)
    FactoryBot.create(:planning_application, :pre_application, local_authority: local_authority)
    FactoryBot.create(:planning_application, :published, local_authority: local_authority)
    # FactoryBot.create(:planning_application, :with_v2_params, local_authority: local_authority)
    # FactoryBot.create(:planning_application, :with_press_notice, local_authority: local_authority)
    FactoryBot.create(:planning_application, :with_heads_of_terms, local_authority: local_authority)
    FactoryBot.create(:planning_application, :with_immunity, local_authority: local_authority)
    # FactoryBot.create(:planning_application, :from_planx_prior_approval_not_accepted, local_authority: local_authority)
    # FactoryBot.create(:planning_application, :from_planx_prior_approval, local_authority: local_authority)
    # FactoryBot.create(:planning_application, :from_planx_immunity, local_authority: local_authority)
    # FactoryBot.create(:planning_application, :from_planx, local_authority: local_authority)
    # api_user = FactoryBot.create(:api_user, name: "PlanX")
    # FactoryBot.create(:planning_application, :with_constraints_and_consultees, local_authority: local_authority, api_user: api_user)
    # FactoryBot.create(:planning_application, :with_constraints, local_authority: local_authority)
    # FactoryBot.create(:planning_application, :with_feedback, local_authority: local_authority)
    FactoryBot.create(:planning_application, :with_recommendation, local_authority: local_authority)
    FactoryBot.create(:planning_application, :with_condition_set, local_authority: local_authority)
    # FactoryBot.create(:planning_application, :with_consultees, local_authority: local_authority)
    # FactoryBot.create(:planning_application, :consulting, local_authority: local_authority)
    FactoryBot.create(:planning_application, :ldc_existing, local_authority: local_authority)
    FactoryBot.create(:planning_application, :ldc_proposed, local_authority: local_authority)
    FactoryBot.create(:planning_application, :lawfulness_certificate, local_authority: local_authority)
    FactoryBot.create(:planning_application, :pre_application, local_authority: local_authority)
    FactoryBot.create(:planning_application, :planning_permission, local_authority: local_authority)
    FactoryBot.create(:planning_application, :prior_approval, local_authority: local_authority)
    FactoryBot.create(:planning_application, :with_boundary_geojson_features, local_authority: local_authority)
    FactoryBot.create(:planning_application, :with_boundary_geojson, local_authority: local_authority)
    FactoryBot.create(:planning_application, :without_result, local_authority: local_authority)
    FactoryBot.create(:planning_application, :invalidated, local_authority: local_authority)
    FactoryBot.create(:planning_application, :closed, local_authority: local_authority)
    FactoryBot.create(:planning_application, :withdrawn, local_authority: local_authority)
    FactoryBot.create(:planning_application, :returned, local_authority: local_authority)
    FactoryBot.create(:planning_application, :determined, local_authority: local_authority)
    FactoryBot.create(:planning_application, :to_be_reviewed, local_authority: local_authority)
    FactoryBot.create(:planning_application, :assessment_in_progress, local_authority: local_authority)
    FactoryBot.create(:planning_application, :in_assessment, local_authority: local_authority)
    FactoryBot.create(:planning_application, :pending, local_authority: local_authority)
    FactoryBot.create(:planning_application, :not_started, local_authority: local_authority)
    FactoryBot.create(:planning_application, :in_committee, local_authority: local_authority)
    FactoryBot.create(:planning_application, :awaiting_determination, local_authority: local_authority)

    FactoryBot.create(:closed_planning_application, local_authority: local_authority)
    FactoryBot.create(:withdrawn_planning_application, local_authority: local_authority)
    FactoryBot.create(:returned_planning_application, local_authority: local_authority)
    FactoryBot.create(:not_started_planning_application, local_authority: local_authority)
    FactoryBot.create(:invalidated_planning_application, local_authority: local_authority)
    FactoryBot.create(:valid_planning_application, local_authority: local_authority)
    FactoryBot.create(:in_assessment_planning_application, local_authority: local_authority)
    FactoryBot.create(:submitted_planning_application, local_authority: local_authority)
    FactoryBot.create(:determined_planning_application, local_authority: local_authority)
  end
end

Clone this wiki locally