diff --git a/app/controllers/admin/cx_action_plans_controller.rb b/app/controllers/admin/cx_action_plans_controller.rb new file mode 100644 index 000000000..d2dff6c4e --- /dev/null +++ b/app/controllers/admin/cx_action_plans_controller.rb @@ -0,0 +1,63 @@ +class Admin::CxActionPlansController < AdminController + before_action :set_cx_action_plan, only: %i[ show edit update destroy ] + + def index + @cx_action_plans = CxActionPlan.all + end + + def show + end + + def new + @service_providers = ServiceProvider.all.includes(:organization).order('organizations.name', 'service_providers.name') + @cx_action_plan = CxActionPlan.new + end + + def edit + @service_providers = ServiceProvider.all.includes(:organization).order('organizations.name', 'service_providers.name') + end + + def create + @cx_action_plan = CxActionPlan.new(cx_action_plan_params) + + respond_to do |format| + if @cx_action_plan.save + format.html { redirect_to admin_cx_action_plan_url(@cx_action_plan), notice: "Cx action plan was successfully created." } + format.json { render :show, status: :created, location: @cx_action_plan } + else + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @cx_action_plan.errors, status: :unprocessable_entity } + end + end + end + + def update + respond_to do |format| + if @cx_action_plan.update(cx_action_plan_params) + format.html { redirect_to admin_cx_action_plan_url(@cx_action_plan), notice: "Cx action plan was successfully updated." } + format.json { render :show, status: :ok, location: @cx_action_plan } + else + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @cx_action_plan.errors, status: :unprocessable_entity } + end + end + end + + def destroy + @cx_action_plan.destroy + + respond_to do |format| + format.html { redirect_to cx_action_plans_url, notice: "Cx action plan was successfully destroyed." } + format.json { head :no_content } + end + end + + private + def set_cx_action_plan + @cx_action_plan = CxActionPlan.find(params[:id]) + end + + def cx_action_plan_params + params.require(:cx_action_plan).permit(:service_provider_id, :year, :delivered_current_year, :to_deliver_next_year) + end +end diff --git a/app/controllers/api/v1/cx_action_plans_controller.rb b/app/controllers/api/v1/cx_action_plans_controller.rb new file mode 100644 index 000000000..90f0be1bc --- /dev/null +++ b/app/controllers/api/v1/cx_action_plans_controller.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Api + module V1 + class CxActionPlansController < ::ApiController + def index + respond_to do |format| + format.json do + render json: CxActionPlan.order(:id), each_serializer: CxActionPlanSerializer + end + end + end + + def show + respond_to do |format| + format.json do + render json: CxActionPlan.find(params[:id]), serializer: CxActionPlanSerializer + end + end + end + end + end +end diff --git a/app/models/cscrm_data_collection2.rb b/app/models/cscrm_data_collection2.rb index 006a5980c..a669fd341 100644 --- a/app/models/cscrm_data_collection2.rb +++ b/app/models/cscrm_data_collection2.rb @@ -409,6 +409,147 @@ def self.established_process_information_sharing_options } end + + # + # + # Custom logic applied to fields for data export + # example: 8 checkbox values being consolidated into a value between 1-3 + # + # + + def self.export_conversion_question_10(field) + return nil if field.length == 1 + + # 0 = Not Identified + # 1 = 1 or 2 identified + # 2 = All but suppliers identified + # 3 = All identified + # Note: Critical item selections not scored, for info only; however, + # If critical items were selected, assumption was that items had been identified + + question_option_selections = YAML.load(field) # parse the string encoded as an array, to an array + question_option_selections_without_not_identified = question_option_selections - ["Not identified"] # remove Not Identified option + question_option_selections_without_suppliers = question_option_selections_without_not_identified - ["Critical Suppliers Identified"] # remove Not Identified and Suppliers option + + if question_option_selections_without_not_identified.size == 8 # if all are selected + 3 + elsif question_option_selections_without_suppliers.size == 7 + 2 + elsif (1..2).include?(question_option_selections_without_not_identified.size) + 1 + elsif question_option_selections.include?("Not identified") + 0 + else + "not scored" + end + end + + def self.export_conversion_question_12(field) + return nil if field.length == 1 + + # 0 = Not Considered + # 1 = up to 2 selections + # 2 = 3 to 6 selections + # 3 = All + + question_option_selections = YAML.load(field) + question_option_selections_without_not_considered = question_option_selections - ["Not considered"] + question_option_selections_without_other = question_option_selections_without_not_considered - ["Other"] + + if question_option_selections_without_other.size == 7 # if all are selected + 3 + elsif (3..6).include?(question_option_selections_without_other.size) + 2 + elsif (1..2).include?(question_option_selections_without_other.size) + 1 + elsif question_option_selections.include?("Not considered") + 0 + else + "not scored" + end + end + + def self.export_conversion_question_14(field) + return nil if field.length == 1 + + # 0 = Not Considered + # 1 = Some Products and/or Services + # 2 = Some Products/All Services or All + # Products/Some Services + # 3 = All Product and Services + # Note: If 1 “all” option selected score = 2 + + question_option_selections = YAML.load(field) + question_option_selections_without_not_conducted = question_option_selections - ["Not conducted"] + + if question_option_selections_without_not_conducted.include?("Conducted for all prioritized products") && + question_option_selections_without_not_conducted.include?("Conducted for all prioritized services") + 3 + elsif question_option_selections_without_not_conducted.include?("Conducted for all prioritized products") || + question_option_selections_without_not_conducted.include?("Conducted for all prioritized services") + 2 + elsif question_option_selections_without_not_conducted.include?("Conducted for some prioritized products") || + question_option_selections_without_not_conducted.include?("Conducted for some prioritized services") + 1 + elsif question_option_selections.include?("Not conducted") + 0 + else + "not scored" + end + end + + def self.export_conversion_question_16(field) + # 0 = Not established + # 1 = Partial/in-Process Internal process + # 2 = Internal Process established and/or FASC process planned/in-process + # 3 = Internal and FASC process established + + if field == "5" + 3 + elsif field == "2" || + field == "3" || + field == "4" + 2 + elsif field == "1" + 1 + elsif field == "0" + 0 + else + "not scored" + end + end + + def self.export_conversion_question_17(field) + return nil if field.length == 1 + + # 0 = Not Considered; + # 1 = Response option(s), other than SCRAs; + # 2 = Response options includes “SCRAs” but not “mitigations” + # 3 = ”SCRAs” and “Mitigations” options selected + + question_option_selections = YAML.load(field) + + if question_option_selections.include?("SCRAs are conducted for critical suppliers") && + question_option_selections.include?("Mitigations to improve resilience/address assessed risks associated with critical suppliers are identified and implemented") + 3 + elsif question_option_selections.include?("SCRAs are conducted for critical suppliers") && + !question_option_selections.include?("Mitigations to improve resilience/address assessed risks associated with critical suppliers are identified and implemented") + 2 + elsif question_option_selections.include?("Critical Suppliers are identified in COOP and Recovery plans") || + question_option_selections.include?("Business Impact Analysis considers supplier and product dependency risks and resiliency requirements") + 1 + elsif question_option_selections.include?("Not considered") + 0 + else + "not scored" + end + end + + # + # end custom export logic + # + + def self.to_csv collections = CscrmDataCollection2.order('year, quarter') @@ -453,29 +594,34 @@ def self.to_csv "clearly_defined_roles_value", "clearly_defined_roles", "clearly_defined_roles_comments", - "identified_assets_and_essential_functions_value", "identified_assets_and_essential_functions", + "identified_assets_and_essential_functions_value", + "identified_assets_and_essential_functions_translated_value", "identified_assets_and_essential_functions_comments", "prioritization_process_value", "prioritization_process", "prioritization_process_comments", - "considerations_in_procurement_processes_value", "considerations_in_procurement_processes", + "considerations_in_procurement_processes_value", + "considerations_in_procurement_processes_translated_value", "considerations_in_procurement_processes_comments", "documented_methodology_value", "documented_methodology", "documented_methodology_comments", - "conducts_scra_for_prioritized_products_and_services_value", "conducts_scra_for_prioritized_products_and_services", + "conducts_scra_for_prioritized_products_and_services_value", + "conducts_scra_for_prioritized_products_and_services_translated_value", "conducts_scra_for_prioritized_products_and_services_comments", "personnel_required_to_complete_training_value", "personnel_required_to_complete_training", "personnel_required_to_complete_training_comments", - "established_process_information_sharing_with_fasc_value", "established_process_information_sharing_with_fasc", + "established_process_information_sharing_with_fasc_value", + "established_process_information_sharing_with_fasc_translated_value", "established_process_information_sharing_with_fasc_comments", - "cybersecurity_supply_chain_risk_considerations_value", "cybersecurity_supply_chain_risk_considerations", + "cybersecurity_supply_chain_risk_considerations_value", + "cybersecurity_supply_chain_risk_considerations_translated_value", "cybersecurity_supply_chain_risk_considerations_comments", "process_for_product_authenticity_value", "process_for_product_authenticity", @@ -534,30 +680,44 @@ def self.to_csv CscrmDataCollection2.question_9[:options].key(collection.clearly_defined_roles.to_i), collection.clearly_defined_roles, collection.clearly_defined_roles_comments, + CscrmDataCollection2.question_10[:options].key(collection.identified_assets_and_essential_functions.to_i), collection.identified_assets_and_essential_functions, + export_conversion_question_10(collection.identified_assets_and_essential_functions), collection.identified_assets_and_essential_functions_comments, + CscrmDataCollection2.question_11[:options].key(collection.prioritization_process.to_i), collection.prioritization_process, collection.prioritization_process_comments, + CscrmDataCollection2.question_12[:options].key(collection.considerations_in_procurement_processes.to_i), collection.considerations_in_procurement_processes, + export_conversion_question_12(collection.considerations_in_procurement_processes), collection.considerations_in_procurement_processes_comments, + CscrmDataCollection2.question_13[:options].key(collection.documented_methodology.to_i), collection.documented_methodology, collection.documented_methodology_comments, + CscrmDataCollection2.question_14[:options].key(collection.conducts_scra_for_prioritized_products_and_services.to_i), collection.conducts_scra_for_prioritized_products_and_services, + export_conversion_question_14(collection.conducts_scra_for_prioritized_products_and_services), collection.conducts_scra_for_prioritized_products_and_services_comments, + CscrmDataCollection2.question_15[:options].key(collection.personnel_required_to_complete_training.to_i), collection.personnel_required_to_complete_training, collection.personnel_required_to_complete_training_comments, + CscrmDataCollection2.question_16[:options].key(collection.established_process_information_sharing_with_fasc.to_i), collection.established_process_information_sharing_with_fasc, + export_conversion_question_16(collection.established_process_information_sharing_with_fasc), collection.established_process_information_sharing_with_fasc_comments, + CscrmDataCollection2.question_17[:options].key(collection.cybersecurity_supply_chain_risk_considerations.to_i), collection.cybersecurity_supply_chain_risk_considerations, + export_conversion_question_17(collection.cybersecurity_supply_chain_risk_considerations), collection.cybersecurity_supply_chain_risk_considerations_comments, + CscrmDataCollection2.question_18[:options].key(collection.process_for_product_authenticity.to_i), collection.process_for_product_authenticity, collection.process_for_product_authenticity_comments, diff --git a/app/models/cx_action_plan.rb b/app/models/cx_action_plan.rb new file mode 100644 index 000000000..c92e21b38 --- /dev/null +++ b/app/models/cx_action_plan.rb @@ -0,0 +1,20 @@ +class CxActionPlan < ApplicationRecord + belongs_to :service_provider + + + def organization_id + self.service_provider.organization_id + end + + def organization_name + self.service_provider.organization.name + end + + def service_provider_name + self.service_provider.name + end + + def services + self.service_provider.services + end +end diff --git a/app/serializers/cx_action_plan_serializer.rb b/app/serializers/cx_action_plan_serializer.rb new file mode 100644 index 000000000..d3898ddc6 --- /dev/null +++ b/app/serializers/cx_action_plan_serializer.rb @@ -0,0 +1,16 @@ +class CxActionPlanSerializer < ActiveModel::Serializer + attributes :id, + :organization_id, + :organization_name, + :service_provider_id, + :service_provider_name, + :year, + :delivered_current_year, + :to_deliver_next_year, + :services + + + def services + ActiveModel::Serializer::CollectionSerializer.new(object.services, serializer: ServiceSerializer) + end +end diff --git a/app/views/admin/cscrm_data_collections2/edit.html.erb b/app/views/admin/cscrm_data_collections2/edit.html.erb index a7484c466..da45687dc 100644 --- a/app/views/admin/cscrm_data_collections2/edit.html.erb +++ b/app/views/admin/cscrm_data_collections2/edit.html.erb @@ -3,7 +3,7 @@ <% end %>

- <%= link_to admin_cscrm_data_collections2_index_path(@cscrm_data_collection) do %> + <%= link_to admin_cscrm_data_collections2_path(@cscrm_data_collection) do %> Back to CSCRM Data Collection <% end %> diff --git a/app/views/admin/cx_action_plans/_cx_action_plan.html.erb b/app/views/admin/cx_action_plans/_cx_action_plan.html.erb new file mode 100644 index 000000000..689c5c99a --- /dev/null +++ b/app/views/admin/cx_action_plans/_cx_action_plan.html.erb @@ -0,0 +1,22 @@ +

+

+ Service provider: + <%= cx_action_plan.service_provider_id %> +

+ +

+ Year: + <%= cx_action_plan.year %> +

+ +

+ Delivered current year: + <%= cx_action_plan.delivered_current_year %> +

+ +

+ To deliver next year: + <%= cx_action_plan.to_deliver_next_year %> +

+ +
diff --git a/app/views/admin/cx_action_plans/_form.html.erb b/app/views/admin/cx_action_plans/_form.html.erb new file mode 100644 index 000000000..1cd5a5a02 --- /dev/null +++ b/app/views/admin/cx_action_plans/_form.html.erb @@ -0,0 +1,37 @@ +<%= form_with(model: cx_action_plan, url: cx_action_plan.persisted? ? admin_cx_action_plan_path : admin_cx_action_plans_path, local: true, data: { turbo: false }) do |form| %> + <% if cx_action_plan.errors.any? %> +
+

<%= pluralize(cx_action_plan.errors.count, "error") %> prohibited this cx_action_plan from being saved:

+ + +
+ <% end %> + +
+ <%= form.label :service_provider_id, class: "usa-label" %> + <%= form.select :service_provider_id, options_for_select(@service_providers.map { |p| ["#{p.organization.abbreviation} - #{p.name}", p.id] }, cx_action_plan.service_provider_id), { prompt: "Which Service Provider?" }, { class: "usa-select" } %> +
+ +
+ <%= form.label :year, class: "usa-label" %> + <%= form.number_field :year, class: "usa-input" %> +
+ +
+ <%= form.label :delivered_current_year, class: "usa-label" %> + <%= form.text_area :delivered_current_year, class: "usa-textarea" %> +
+ +
+ <%= form.label :to_deliver_next_year, class: "usa-label" %> + <%= form.text_area :to_deliver_next_year, class: "usa-textarea" %> +
+ +

+ <%= form.submit class: "usa-button" %> +

+<% end %> diff --git a/app/views/admin/cx_action_plans/edit.html.erb b/app/views/admin/cx_action_plans/edit.html.erb new file mode 100644 index 000000000..f826fa8ef --- /dev/null +++ b/app/views/admin/cx_action_plans/edit.html.erb @@ -0,0 +1,13 @@ +<% content_for :navigation_title do %> + Editing CX Action Plan +<% end %> + +

+ <%= link_to admin_cx_action_plan_path(@cx_action_plan) do %> + + Back to CX Action Plan + <% end %> +

+

+ +<%= render "form", cx_action_plan: @cx_action_plan %> diff --git a/app/views/admin/cx_action_plans/index.html.erb b/app/views/admin/cx_action_plans/index.html.erb new file mode 100644 index 000000000..640d2a596 --- /dev/null +++ b/app/views/admin/cx_action_plans/index.html.erb @@ -0,0 +1,44 @@ +<% content_for :navigation_title do %> + CX Action Plans + + <%= link_to new_admin_cx_action_plan_path, class: "usa-button usa-button-inverted float-right" do %> + + New CX Action Plan + <% end %> +<% end %> + +
+ + + + + + + + + + <% @cx_action_plans.each do |cx_action_plan| %> + + + + + + + <% end %> +
+ Organization name + + Service Provider name + + Year + +
+ <%= cx_action_plan.service_provider.organization.name %> + + <%= cx_action_plan.service_provider.name %> + + <%= cx_action_plan.year %> + + <%= link_to 'View', admin_cx_action_plan_path(cx_action_plan) %> +
+
diff --git a/app/views/admin/cx_action_plans/new.html.erb b/app/views/admin/cx_action_plans/new.html.erb new file mode 100644 index 000000000..b6ae15f2f --- /dev/null +++ b/app/views/admin/cx_action_plans/new.html.erb @@ -0,0 +1,11 @@ +<% content_for :navigation_title do %> + New CX Action Plan +<% end %> +

+ <%= link_to admin_cx_action_plans_path do %> + + Back to CX Action Plans + <% end %> +

+ +<%= render "form", cx_action_plan: @cx_action_plan %> diff --git a/app/views/admin/cx_action_plans/show.html.erb b/app/views/admin/cx_action_plans/show.html.erb new file mode 100644 index 000000000..edd16a422 --- /dev/null +++ b/app/views/admin/cx_action_plans/show.html.erb @@ -0,0 +1,46 @@ +<% content_for :navigation_title do %> + CX Action Plan + <%= link_to edit_admin_cx_action_plan_path(@cx_action_plan), class: "usa-button usa-button-inverted float-right" do %> + + Edit + <% end %> +<% end %> +

+ <%= link_to admin_cx_action_plans_path do %> + + Back to CX Action Plans + <% end %> +

+ +
> +

+ Organization name: + <%= @cx_action_plan.service_provider.organization.name %> +

+ +

+ Service provider: + <%= link_to @cx_action_plan.service_provider.name, admin_service_provider_path(@cx_action_plan.service_provider) %> +

+ +

+ Year: + <%= @cx_action_plan.year %> +

+ +

+ Delivered current year: + <%= to_markdown(@cx_action_plan.delivered_current_year) %> +

+ +

+ To deliver next year: + <%= to_markdown(@cx_action_plan.to_deliver_next_year) %> +

+
+ +
+
+ <%= button_to "Destroy", admin_cx_action_plan_path(@cx_action_plan), class: "usa-button usa-button--secondary float-right", method: :delete %> +
+
diff --git a/app/views/components/forms/_custom_layout.html.erb b/app/views/components/forms/_custom_layout.html.erb index 917fb1e9b..2ca7103a7 100644 --- a/app/views/components/forms/_custom_layout.html.erb +++ b/app/views/components/forms/_custom_layout.html.erb @@ -16,7 +16,7 @@

<% end %>

- A red asterisk (*) indicates a required field. + <%= t :required_text_html %>

<%= render 'components/forms/flash', form: form %> <%= render partial: "components/forms/custom", locals: { form: form, questions: form.questions } %> diff --git a/app/views/components/widget/_no_modal.html.erb b/app/views/components/widget/_no_modal.html.erb index 341a911e4..7c3151907 100644 --- a/app/views/components/widget/_no_modal.html.erb +++ b/app/views/components/widget/_no_modal.html.erb @@ -12,20 +12,22 @@ <% unless form.delivery_method == "inline" %> - × + × <% end %> <% if form.instructions? %>

<%= sanitize(form.instructions) %>

- <% end %> + <% end -%>

- A red asterisk (*) indicates a required field. + <%= t :required_field_html %>

-
<%= render 'components/forms/flash', form: form %> <%= render partial: "components/forms/custom", locals: { form: form, questions: form.questions } %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 500f93346..111d3724e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -138,6 +138,7 @@ en-US: characters_allowed: "characters allowed" characters_left: "characters left" form: + required_field_html: 'A red asterisk (*) indicates a required field.' submit: "Submit" submit_thankyou: "Thank you. Your feedback has been received." help_improve: "Help improve this site" diff --git a/config/locales/es.yml b/config/locales/es.yml index 04331cd21..bdffeb0a0 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -26,6 +26,7 @@ es: characters_allowed: "caracteres permitidos" characters_left: "caracteres restantes" form: + required_field_html: 'Un asterisco rojo (*) indica un campo obligatorio.' submit: "Enviar" submit_thankyou: "Gracias. Su comentario ha sido recibido." help_improve: "Ayuda a mejorar este sitio" diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 740b29950..cd126e8dc 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -46,6 +46,7 @@ zh-CN: characters_allowed: "允许的字符" characters_left: "剩余字符数" form: + required_field_html: '红色星号 (*) 表示必填字段。' submit: "提交" submit_thankyou: "谢谢. 已收到您的反馈." help_improve: "帮助改善这个网站" diff --git a/config/routes.rb b/config/routes.rb index 4dce97061..a4de109b2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -45,6 +45,7 @@ resources :forms, only: %i[index show] resources :websites, only: [:index] resources :service_providers, only: [:index] + resources :cx_action_plans, only: %i[index show] resources :services, only: %i[index show] resources :personas, only: [:index] resources :goals, only: [:index] @@ -103,6 +104,7 @@ post 'remove_service_provider_manager', to: 'service_providers#remove_service_provider_manager', as: :remove_service_provider_manager end end + resources :cx_action_plans resources :services do collection do get 'catalog', to: 'services#catalog', as: :catalog @@ -144,6 +146,7 @@ get 'events', to: 'collections#events', as: :events end end + resources :omb_cx_reporting_collections resources :cscrm_data_collections do member do diff --git a/db/migrate/20230927214053_create_cx_action_plans.rb b/db/migrate/20230927214053_create_cx_action_plans.rb new file mode 100644 index 000000000..657968609 --- /dev/null +++ b/db/migrate/20230927214053_create_cx_action_plans.rb @@ -0,0 +1,12 @@ +class CreateCxActionPlans < ActiveRecord::Migration[7.0] + def change + create_table :cx_action_plans do |t| + t.integer :service_provider_id + t.integer :year + t.text :delivered_current_year + t.text :to_deliver_next_year + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 07a472680..3a37111bc 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_09_26_183233) do +ActiveRecord::Schema[7.0].define(version: 2023_09_27_214053) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -178,6 +178,15 @@ t.index ["user_id"], name: "index_cscrm_data_collections2_on_user_id" end + create_table "cx_action_plans", force: :cascade do |t| + t.integer "service_provider_id" + t.integer "year" + t.text "delivered_current_year" + t.text "to_deliver_next_year" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "digital_product_versions", force: :cascade do |t| t.bigint "digital_product_id" t.string "store_url" diff --git a/spec/models/cx_action_plan_spec.rb b/spec/models/cx_action_plan_spec.rb new file mode 100644 index 000000000..6ebec0ef9 --- /dev/null +++ b/spec/models/cx_action_plan_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe CxActionPlan, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/admin/cx_action_plans_spec.rb b/spec/requests/admin/cx_action_plans_spec.rb new file mode 100644 index 000000000..a4ee7f117 --- /dev/null +++ b/spec/requests/admin/cx_action_plans_spec.rb @@ -0,0 +1,141 @@ +require 'rails_helper' + +# This spec was generated by rspec-rails when you ran the scaffold generator. +# It demonstrates how one might use RSpec to test the controller code that +# was generated by Rails when you ran the scaffold generator. +# +# It assumes that the implementation code is generated by the rails scaffold +# generator. If you are using any extension libraries to generate different +# controller code, this generated spec may or may not pass. +# +# It only uses APIs available in rails and/or rspec-rails. There are a number +# of tools you can use to make these specs even more expressive, but we're +# sticking to rails and rspec-rails APIs to keep things simple and stable. + +RSpec.describe "/admin/cx_action_plans", type: :request do + + # This should return the minimal set of attributes required to create a valid + # CxActionPlan. As you add validations to CxActionPlan, be sure to + # adjust the attributes here as well. + let(:valid_attributes) { + skip("Add a hash of attributes valid for your model") + } + + let(:invalid_attributes) { + skip("Add a hash of attributes invalid for your model") + } + + describe "GET /index" do + it "renders a successful response" do + CxActionPlan.create! valid_attributes + get admin_cx_action_plans_url + expect(response).to be_successful + end + end + + describe "GET /show" do + it "renders a successful response" do + cx_action_plan = CxActionPlan.create! valid_attributes + get admin_cx_action_plan_url(cx_action_plan) + expect(response).to be_successful + end + end + + describe "GET /new" do + let(:user) { FactoryBot.create(:user, :admin) } + + before do + sign_in(user) + end + + it "renders a successful response" do + get new_admin_cx_action_plan_url + expect(response).to be_successful + end + end + + describe "GET /edit" do + it "renders a successful response" do + cx_action_plan = CxActionPlan.create! valid_attributes + get edit_admin_cx_action_plan_url(cx_action_plan) + expect(response).to be_successful + end + end + + describe "POST /create" do + context "with valid parameters" do + it "creates a new CxActionPlan" do + expect { + post admin_cx_action_plans_url, params: { cx_action_plan: valid_attributes } + }.to change(CxActionPlan, :count).by(1) + end + + it "redirects to the created cx_action_plan" do + post admin_cx_action_plans_url, params: { cx_action_plan: valid_attributes } + expect(response).to redirect_to(cx_action_plan_url(CxActionPlan.last)) + end + end + + context "with invalid parameters" do + it "does not create a new CxActionPlan" do + expect { + post admin_cx_action_plans_url, params: { cx_action_plan: invalid_attributes } + }.to change(CxActionPlan, :count).by(0) + end + + + it "renders a response with 422 status (i.e. to display the 'new' template)" do + post admin_cx_action_plans_url, params: { cx_action_plan: invalid_attributes } + expect(response).to have_http_status(:unprocessable_entity) + end + + end + end + + describe "PATCH /update" do + context "with valid parameters" do + let(:new_attributes) { + skip("Add a hash of attributes valid for your model") + } + + it "updates the requested cx_action_plan" do + cx_action_plan = CxActionPlan.create! valid_attributes + patch admin_cx_action_plan_url(cx_action_plan), params: { cx_action_plan: new_attributes } + cx_action_plan.reload + skip("Add assertions for updated state") + end + + it "redirects to the cx_action_plan" do + cx_action_plan = CxActionPlan.create! valid_attributes + patch admin_cx_action_plan_url(cx_action_plan), params: { cx_action_plan: new_attributes } + cx_action_plan.reload + expect(response).to redirect_to(cx_action_plan_url(cx_action_plan)) + end + end + + context "with invalid parameters" do + + it "renders a response with 422 status (i.e. to display the 'edit' template)" do + cx_action_plan = CxActionPlan.create! valid_attributes + patch cx_action_plan_url(cx_action_plan), params: { cx_action_plan: invalid_attributes } + expect(response).to have_http_status(:unprocessable_entity) + end + + end + end + + describe "DELETE /destroy" do + it "destroys the requested cx_action_plan" do + cx_action_plan = CxActionPlan.create! valid_attributes + expect { + delete cx_action_plan_url(cx_action_plan) + }.to change(CxActionPlan, :count).by(-1) + end + + it "redirects to the cx_action_plans list" do + cx_action_plan = CxActionPlan.create! valid_attributes + delete cx_action_plan_url(cx_action_plan) + expect(response).to redirect_to(cx_action_plans_url) + end + end +end