From 04fce0cddecd6a303f46f35c2aa673815eb2a575 Mon Sep 17 00:00:00 2001 From: pengyin-shan Date: Mon, 3 Oct 2022 12:21:34 -0400 Subject: [PATCH 01/81] Add multi-phase download feature and fix a Webmock complain --- app/controllers/plan_exports_controller.rb | 16 +- app/controllers/plans_controller.rb | 5 +- app/javascript/src/plans/download.js | 12 +- app/views/shared/export/_plan.erb | 2 +- app/views/shared/export/_plan_txt.erb | 2 +- db/schema.rb | 692 ++++++--------------- spec/features/plans/exports_spec.rb | 165 +++-- spec/rails_helper.rb | 2 +- spec/spec_helper.rb | 4 +- 9 files changed, 347 insertions(+), 553 deletions(-) diff --git a/app/controllers/plan_exports_controller.rb b/app/controllers/plan_exports_controller.rb index b034aa6b5..235460b7f 100644 --- a/app/controllers/plan_exports_controller.rb +++ b/app/controllers/plan_exports_controller.rb @@ -36,12 +36,18 @@ def show @hash = @plan.as_pdf(current_user, @show_coversheet) @formatting = export_params[:formatting] || @plan.settings(:export).formatting - @selected_phase = if params.key?(:phase_id) - @plan.phases.find(params[:phase_id]) - else - @plan.phases.order('phases.updated_at DESC') + if params.key?(:phase_id) + # order phases by phase number asc + @hash[:phases] = @hash[:phases].sort_by{|phase| phase[:number]} + if (params[:phase_id] == "All") + @hash[:all_phases] = true + else + @selected_phase = @plan.phases.find(params[:phase_id]) + end + else + @plan.phases.order("phases.updated_at DESC") .detect { |p| p.visibility_allowed?(@plan) } - end + end # Added contributors to coverage of plans. # Users will see both roles and contributor names if the role is filled diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb index 623cf2477..5d611d0e2 100644 --- a/app/controllers/plans_controller.rb +++ b/app/controllers/plans_controller.rb @@ -376,8 +376,11 @@ def download @plan = Plan.find(params[:id]) authorize @plan @phase_options = @plan.phases.order(:number).pluck(:title, :id) + if @phase_options.length > 1 + @phase_options.insert(0,["All phases", "All"]) + end @export_settings = @plan.settings(:export) - render 'download' + render "download" end # POST /plans/:id/duplicate diff --git a/app/javascript/src/plans/download.js b/app/javascript/src/plans/download.js index e772b8322..6e1440f04 100644 --- a/app/javascript/src/plans/download.js +++ b/app/javascript/src/plans/download.js @@ -21,5 +21,15 @@ $(() => { } else { $('#download-settings').show(); } - }); + + if (frmt === 'csv') { + $('#phase_id').find('option[value="All"').hide(); + $('#phase_id option:eq(1)').attr('selected', 'selected'); + $('#phase_id').val($('#phase_id option:eq(1)').val()); + } else if (frmt === 'pdf' || frmt === 'html' || frmt === 'docx' || frmt === 'text') { + $('#phase_id').find('option[value="All"').show(); + $('#phase_id').val($('#phase_id option:first').val()); + $('#phase_id option:first').attr('selected', 'selected'); + } + }).trigger('change'); }); diff --git a/app/views/shared/export/_plan.erb b/app/views/shared/export/_plan.erb index dac27560f..aae3b9b70 100644 --- a/app/views/shared/export/_plan.erb +++ b/app/views/shared/export/_plan.erb @@ -18,7 +18,7 @@ <% @hash[:phases].each do |phase| %> <%# Only render selected phase %> - <% if phase[:title] == @selected_phase.title %> + <% if @hash[:all_phases] || (@selected_phase.present? && phase[:title] == @selected_phase.title) %> <%# Page break before each phase %>

<%= download_plan_page_title(@plan, phase, @hash) %>

diff --git a/app/views/shared/export/_plan_txt.erb b/app/views/shared/export/_plan_txt.erb index 7a9c42b87..ff8570c78 100644 --- a/app/views/shared/export/_plan_txt.erb +++ b/app/views/shared/export/_plan_txt.erb @@ -38,7 +38,7 @@ <% @hash[:phases].each do |phase| %> <%# Only render selected phase %> -<% if phase[:title] == @selected_phase.title %> +<% if @hash[:all_phases] || (@selected_phase.present? && phase[:title] == @selected_phase.title) %> <%= (@hash[:phases].length > 1 ? "#{phase[:title]}" : "") %> <% phase[:sections].each do |section| %> <% if display_section?(@hash[:customization], section, @show_custom_sections) && num_section_questions(@plan, section, phase) > 0 %> diff --git a/db/schema.rb b/db/schema.rb index 56dbfef7d..fc2833ad1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -2,207 +2,103 @@ # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. # -# Note that this schema.rb definition is the authoritative source for your -# database schema. If you need to create the application database on another -# system, you should be using db:schema:load, not running all the migrations -# from scratch. The latter is a flawed and unsustainable approach (the more migrations -# you'll amass, the slower it'll run and the greater likelihood for issues). +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. # # It's strongly recommended that you check this file into your version control system. ActiveRecord::Schema.define(version: 2022_03_15_104737) do - create_table "annotations", id: :integer, force: :cascade do |t| - t.integer "question_id" - t.integer "org_id" - t.text "text" - t.integer "type", default: 0, null: false - t.datetime "created_at" - t.datetime "updated_at" - t.string "versionable_id", limit: 36 - t.index ["org_id"], name: "fk_rails_aca7521f72" - t.index ["question_id"], name: "index_annotations_on_question_id" - t.index ["versionable_id"], name: "index_annotations_on_versionable_id" - end +# Could not dump table "annotations" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "answers", id: :integer, force: :cascade do |t| - t.text "text" - t.integer "plan_id" - t.integer "user_id" - t.integer "question_id" - t.datetime "created_at" - t.datetime "updated_at" - t.integer "lock_version", default: 0 - t.index ["plan_id"], name: "fk_rails_84a6005a3e" - t.index ["plan_id"], name: "index_answers_on_plan_id" - t.index ["question_id"], name: "fk_rails_3d5ed4418f" - t.index ["question_id"], name: "index_answers_on_question_id" - t.index ["user_id"], name: "fk_rails_584be190c2" +# Could not dump table "answers" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + + create_table "answers_options", id: false, force: :cascade do |t| + t.integer "answer_id", null: false + t.integer "option_id", null: false + t.index ["answer_id", "option_id"], name: "index_answers_options_on_answer_id_and_option_id" end create_table "answers_question_options", id: false, force: :cascade do |t| t.integer "answer_id", null: false t.integer "question_option_id", null: false t.index ["answer_id"], name: "index_answers_question_options_on_answer_id" + t.index ["question_option_id"], name: "fk_rails_01ba00b569" end - create_table "api_clients", id: :integer, force: :cascade do |t| - t.string "name", null: false - t.string "description" - t.string "homepage" - t.string "contact_name" - t.string "contact_email" - t.string "client_id", null: false - t.string "client_secret", null: false - t.datetime "last_access" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.integer "org_id" - t.text "redirect_uri" - t.string "scopes", default: "", null: false - t.boolean "confidential", default: true - t.boolean "trusted", default: false - t.integer "callback_method" - t.string "callback_uri" - t.index ["name"], name: "index_oauth_applications_on_name" - end +# Could not dump table "api_clients" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "conditions", id: :integer, force: :cascade do |t| - t.integer "question_id" - t.text "option_list" - t.integer "action_type" - t.integer "number" - t.text "remove_data" - t.text "webhook_data" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["question_id"], name: "index_conditions_on_question_id" - end +# Could not dump table "comments" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "contributors", id: :integer, force: :cascade do |t| - t.string "name" - t.string "email" - t.string "phone" - t.integer "roles", null: false - t.integer "org_id" - t.integer "plan_id", null: false - t.datetime "created_at" - t.datetime "updated_at" - t.index ["email"], name: "index_contributors_on_email" - t.index ["name", "id", "org_id"], name: "index_contrib_id_and_org_id" - t.index ["org_id"], name: "index_contributors_on_org_id" - t.index ["plan_id"], name: "index_contributors_on_plan_id" - t.index ["roles"], name: "index_contributors_on_roles" - end +# Could not dump table "conditions" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "departments", id: :integer, force: :cascade do |t| - t.string "name" - t.string "code" - t.integer "org_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["org_id"], name: "index_departments_on_org_id" - end +# Could not dump table "contributors" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "exported_plans", id: :integer, force: :cascade do |t| - t.integer "plan_id" - t.integer "user_id" - t.string "format" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.integer "phase_id" - end +# Could not dump table "departments" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "external_api_access_tokens", force: :cascade do |t| - t.bigint "user_id", null: false - t.string "external_service_name", null: false - t.string "access_token", null: false - t.string "refresh_token" - t.datetime "expires_at" - t.datetime "revoked_at" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["expires_at"], name: "index_external_api_access_tokens_on_expires_at" - t.index ["external_service_name"], name: "index_external_api_access_tokens_on_external_service_name" - t.index ["user_id", "external_service_name"], name: "index_external_tokens_on_user_and_service" - t.index ["user_id"], name: "index_external_api_access_tokens_on_user_id" - end +# Could not dump table "dmptemplate_translations" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "guidance_groups", id: :integer, force: :cascade do |t| - t.string "name" - t.integer "org_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "optional_subset", default: false, null: false - t.boolean "published", default: false, null: false - t.index ["org_id"], name: "index_guidance_groups_on_org_id" - end +# Could not dump table "dmptemplates" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "guidances", id: :integer, force: :cascade do |t| - t.text "text" + create_table "dmptemplates_guidance_groups", id: false, force: :cascade do |t| + t.integer "dmptemplate_id" t.integer "guidance_group_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "published" - t.index ["guidance_group_id"], name: "index_guidances_on_guidance_group_id" end - create_table "identifier_schemes", id: :integer, force: :cascade do |t| - t.string "name" - t.string "description" - t.boolean "active" - t.datetime "created_at" - t.datetime "updated_at" - t.string "logo_url" - t.string "identifier_prefix" - t.integer "context" - t.string "external_service" - end +# Could not dump table "exported_plans" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "identifiers", id: :integer, force: :cascade do |t| - t.string "value", null: false - t.text "attrs" - t.integer "identifier_scheme_id" - t.integer "identifiable_id" - t.string "identifiable_type" - t.datetime "created_at" - t.datetime "updated_at" - t.index ["identifiable_type", "identifiable_id"], name: "index_identifiers_on_identifiable_type_and_identifiable_id" - t.index ["identifier_scheme_id", "identifiable_id", "identifiable_type"], name: "index_identifiers_on_scheme_and_type_and_id" - t.index ["identifier_scheme_id", "value"], name: "index_identifiers_on_identifier_scheme_id_and_value" - end +# Could not dump table "file_types" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "languages", id: :integer, force: :cascade do |t| - t.string "abbreviation" - t.string "description" - t.string "name" - t.boolean "default_language" - end +# Could not dump table "file_uploads" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "licenses", force: :cascade do |t| - t.string "name", null: false - t.string "identifier", null: false - t.string "uri", null: false - t.boolean "osi_approved", default: false - t.boolean "deprecated", default: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["identifier", "osi_approved", "deprecated"], name: "index_license_on_identifier_and_criteria" - t.index ["identifier"], name: "index_licenses_on_identifier" - t.index ["uri"], name: "index_licenses_on_uri" - end +# Could not dump table "friendly_id_slugs" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "metadata_standards", force: :cascade do |t| - t.string "title" - t.text "description" - t.string "rdamsc_id" - t.string "uri" - t.json "locations" - t.json "related_entities" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false +# Could not dump table "guidance_groups" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + + create_table "guidance_in_group", id: false, force: :cascade do |t| + t.integer "guidance_id", null: false + t.integer "guidance_group_id", null: false + t.index ["guidance_id", "guidance_group_id"], name: "index_guidance_in_group_on_guidance_id_and_guidance_group_id" end +# Could not dump table "guidance_translations" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "guidances" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "identifier_schemes" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "identifiers" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "languages" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "licenses" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "metadata_standards" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "metadata_standards_research_outputs", force: :cascade do |t| t.bigint "metadata_standard_id" t.bigint "research_output_id" @@ -210,17 +106,8 @@ t.index ["research_output_id"], name: "metadata_research_outputs_on_ro" end - create_table "notes", id: :integer, force: :cascade do |t| - t.integer "user_id" - t.text "text" - t.boolean "archived", default: false, null: false - t.integer "answer_id" - t.integer "archived_by" - t.datetime "created_at" - t.datetime "updated_at" - t.index ["answer_id"], name: "index_notes_on_answer_id" - t.index ["user_id"], name: "fk_rails_7f2323ad43" - end +# Could not dump table "notes" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 create_table "notification_acknowledgements", id: :integer, force: :cascade do |t| t.integer "user_id" @@ -231,18 +118,14 @@ t.index ["user_id"], name: "index_notification_acknowledgements_on_user_id" end - create_table "notifications", id: :integer, force: :cascade do |t| - t.integer "notification_type" - t.string "title" - t.integer "level" - t.text "body" - t.boolean "dismissable" - t.date "starts_at" - t.date "expires_at" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "enabled", default: true - end +# Could not dump table "notifications" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "option_warnings" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "options" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 create_table "org_token_permissions", id: :integer, force: :cascade do |t| t.integer "org_id" @@ -253,179 +136,97 @@ t.index ["token_permission_type_id"], name: "fk_rails_2aa265f538" end - create_table "orgs", id: :integer, force: :cascade do |t| - t.string "name" - t.string "abbreviation" - t.string "target_url" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "is_other", default: false, null: false - t.integer "region_id" - t.integer "language_id" - t.string "logo_uid" - t.string "logo_name" - t.string "contact_email" - t.integer "org_type", default: 0, null: false - t.text "links" - t.boolean "feedback_enabled", default: false - t.text "feedback_msg" - t.string "contact_name" - t.boolean "managed", default: false, null: false - t.string "api_create_plan_email_subject" - t.text "api_create_plan_email_body" - t.index ["language_id"], name: "fk_rails_5640112cab" - t.index ["region_id"], name: "fk_rails_5a6adf6bab" - t.string "helpdesk_email" - end +# Could not dump table "organisation_types" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "organisations" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "orgs" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "perms", id: :integer, force: :cascade do |t| - t.string "name" +# Could not dump table "perms" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "phase_translations" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "phases" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + + create_table "plan_sections", id: :integer, force: :cascade do |t| + t.integer "user_id" + t.integer "section_id" + t.integer "plan_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.datetime "release_time" end - create_table "phases", id: :integer, force: :cascade do |t| - t.string "title" - t.text "description" - t.integer "number" - t.integer "template_id" - t.datetime "created_at" - t.datetime "updated_at" - t.boolean "modifiable" - t.string "versionable_id", limit: 36 - t.index ["template_id"], name: "index_phases_on_template_id" - t.index ["versionable_id"], name: "index_phases_on_versionable_id" - end - - create_table "plans", id: :integer, force: :cascade do |t| - t.string "title" - t.integer "template_id" - t.datetime "created_at" - t.datetime "updated_at" - t.string "identifier" - t.text "description" - t.integer "visibility", default: 3, null: false - t.boolean "feedback_requested", default: false - t.boolean "complete", default: false - t.integer "org_id" - t.integer "funder_id" - t.integer "grant_id" - t.integer "api_client_id" - t.datetime "start_date" - t.datetime "end_date" - t.boolean "ethical_issues" - t.text "ethical_issues_description" - t.string "ethical_issues_report" - t.integer "funding_status" - t.bigint "research_domain_id" - t.index ["funder_id"], name: "index_plans_on_funder_id" - t.index ["grant_id"], name: "index_plans_on_grant_id" - t.index ["org_id"], name: "index_plans_on_org_id" - t.index ["research_domain_id"], name: "index_plans_on_fos_id" - t.index ["template_id"], name: "index_plans_on_template_id" - t.index ["api_client_id"], name: "index_plans_on_api_client_id" - end +# Could not dump table "plans" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 create_table "plans_guidance_groups", id: :integer, force: :cascade do |t| t.integer "guidance_group_id" t.integer "plan_id" t.index ["guidance_group_id", "plan_id"], name: "index_plans_guidance_groups_on_guidance_group_id_and_plan_id" - t.index ["guidance_group_id"], name: "fk_rails_ec1c5524d7" t.index ["plan_id"], name: "fk_rails_13d0671430" end - create_table "prefs", id: :integer, force: :cascade do |t| - t.text "settings" - t.integer "user_id" - end +# Could not dump table "prefs" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "question_format_labels", id: false, force: :cascade do |t| - t.integer "id" - t.string "description" - t.integer "question_id" - t.integer "number" - t.datetime "created_at" - t.datetime "updated_at" - end - - create_table "question_formats", id: :integer, force: :cascade do |t| - t.string "title" - t.text "description" + create_table "project_groups", id: :integer, force: :cascade do |t| + t.boolean "project_creator" + t.boolean "project_editor" + t.integer "user_id" + t.integer "project_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.boolean "option_based", default: false - t.integer "formattype", default: 0 + t.boolean "project_administrator" end - create_table "question_options", id: :integer, force: :cascade do |t| - t.integer "question_id" - t.string "text" - t.integer "number" - t.boolean "is_default" - t.datetime "created_at" - t.datetime "updated_at" - t.string "versionable_id", limit: 36 - t.index ["question_id"], name: "index_question_options_on_question_id" - t.index ["versionable_id"], name: "index_question_options_on_versionable_id" + create_table "project_guidance", id: false, force: :cascade do |t| + t.integer "project_id", null: false + t.integer "guidance_group_id", null: false + t.index ["project_id", "guidance_group_id"], name: "index_project_guidance_on_project_id_and_guidance_group_id" end - create_table "questions", id: :integer, force: :cascade do |t| - t.text "text" - t.text "default_value" - t.integer "number" - t.integer "section_id" - t.datetime "created_at" - t.datetime "updated_at" - t.integer "question_format_id" - t.boolean "option_comment_display", default: true - t.boolean "modifiable" - t.string "versionable_id", limit: 36 - t.index ["question_format_id"], name: "fk_rails_4fbc38c8c7" - t.index ["section_id"], name: "index_questions_on_section_id" - t.index ["versionable_id"], name: "index_questions_on_versionable_id" - end +# Could not dump table "projects" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "question_format_translations" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "question_formats" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "question_options" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "question_translations" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "questions" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 create_table "questions_themes", id: false, force: :cascade do |t| t.integer "question_id", null: false t.integer "theme_id", null: false t.index ["question_id"], name: "index_questions_themes_on_question_id" + t.index ["theme_id"], name: "fk_rails_0489d5eeba" end - create_table "regions", id: :integer, force: :cascade do |t| - t.string "abbreviation" - t.string "description" - t.string "name" + create_table "region_groups", id: :integer, force: :cascade do |t| t.integer "super_region_id" + t.integer "region_id" end - create_table "related_identifiers", force: :cascade do |t| - t.bigint "identifier_scheme_id" - t.integer "identifier_type", null: false - t.integer "relation_type", null: false - t.bigint "identifiable_id" - t.string "identifiable_type" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "value", null: false - t.index ["identifiable_id", "identifiable_type", "relation_type"], name: "index_relateds_on_identifiable_and_relation_type" - t.index ["identifier_scheme_id"], name: "index_related_identifiers_on_identifier_scheme_id" - t.index ["identifier_type"], name: "index_related_identifiers_on_identifier_type" - t.index ["relation_type"], name: "index_related_identifiers_on_relation_type" - end +# Could not dump table "regions" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "repositories", force: :cascade do |t| - t.string "name", null: false - t.text "description", null: false - t.string "homepage" - t.string "contact" - t.string "uri", null: false - t.json "info" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["homepage"], name: "index_repositories_on_homepage" - t.index ["name"], name: "index_repositories_on_name" - t.index ["uri"], name: "index_repositories_on_uri" - end +# Could not dump table "repositories" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 create_table "repositories_research_outputs", force: :cascade do |t| t.bigint "research_output_id" @@ -434,36 +235,11 @@ t.index ["research_output_id"], name: "index_repositories_research_outputs_on_research_output_id" end - create_table "research_domains", force: :cascade do |t| - t.string "identifier", null: false - t.string "label", null: false - t.bigint "parent_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["parent_id"], name: "index_research_domains_on_parent_id" - end +# Could not dump table "research_domains" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "research_outputs", force: :cascade do |t| - t.integer "plan_id" - t.integer "output_type", default: 3, null: false - t.string "output_type_description" - t.string "title", null: false - t.string "abbreviation" - t.integer "display_order" - t.boolean "is_default" - t.text "description" - t.integer "access", default: 0, null: false - t.datetime "release_date" - t.boolean "personal_data" - t.boolean "sensitive_data" - t.bigint "byte_size" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.bigint "license_id" - t.index ["license_id"], name: "index_research_outputs_on_license_id" - t.index ["output_type"], name: "index_research_outputs_on_output_type" - t.index ["plan_id"], name: "index_research_outputs_on_plan_id" - end +# Could not dump table "research_outputs" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 create_table "roles", id: :integer, force: :cascade do |t| t.integer "user_id" @@ -476,89 +252,35 @@ t.index ["user_id"], name: "index_roles_on_user_id" end - create_table "sections", id: :integer, force: :cascade do |t| - t.string "title" - t.text "description" - t.integer "number" - t.datetime "created_at" - t.datetime "updated_at" - t.integer "phase_id" - t.boolean "modifiable" - t.string "versionable_id", limit: 36 - t.index ["phase_id"], name: "index_sections_on_phase_id" - t.index ["versionable_id"], name: "index_sections_on_versionable_id" - end +# Could not dump table "section_translations" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "sessions", id: :integer, force: :cascade do |t| - t.string "session_id", limit: 64, null: false - t.text "data" - t.datetime "created_at" - t.datetime "updated_at" - t.index ["session_id"], name: "index_sessions_on_session_id", unique: true - t.index ["updated_at"], name: "index_sessions_on_updated_at" - end +# Could not dump table "sections" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "settings", id: :integer, force: :cascade do |t| - t.string "var" - t.text "value" - t.integer "target_id", null: false - t.string "target_type" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - end +# Could not dump table "sessions" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "stats", id: :integer, force: :cascade do |t| - t.bigint "count", default: 0 - t.date "date", null: false - t.string "type", null: false - t.integer "org_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.text "details" - t.boolean "filtered", default: false - end +# Could not dump table "settings" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "subscriptions", force: :cascade do |t| - t.bigint "plan_id" - t.integer "subscription_types", null: false - t.string "callback_uri" - t.bigint "subscriber_id" - t.string "subscriber_type" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.datetime "last_notified" - t.index ["plan_id"], name: "index_subscriptions_on_plan_id" - t.index ["subscriber_id", "subscriber_type", "plan_id"], name: "index_subscribers_on_identifiable_and_plan_id" - end +# Could not dump table "splash_logs" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "templates", id: :integer, force: :cascade do |t| - t.string "title" - t.text "description" - t.boolean "published" - t.integer "org_id" - t.string "locale" - t.boolean "is_default" - t.datetime "created_at" - t.datetime "updated_at" - t.integer "version" - t.integer "visibility" - t.integer "customization_of" - t.integer "family_id" - t.boolean "archived" - t.text "links" - t.index ["family_id", "version"], name: "index_templates_on_family_id_and_version", unique: true - t.index ["family_id"], name: "index_templates_on_family_id" - t.index ["org_id", "family_id"], name: "template_organisation_dmptemplate_index" - t.index ["org_id"], name: "index_templates_on_org_id" - end +# Could not dump table "stats" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "themes", id: :integer, force: :cascade do |t| - t.string "title" - t.text "description" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "locale" - end +# Could not dump table "stylesheets" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "suggested_answers" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "templates" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "themes" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 create_table "themes_in_guidance", id: false, force: :cascade do |t| t.integer "theme_id" @@ -567,61 +289,23 @@ t.index ["theme_id"], name: "index_themes_in_guidance_on_theme_id" end - create_table "token_permission_types", id: :integer, force: :cascade do |t| - t.string "token_type" - t.text "text_description" - t.datetime "created_at" - t.datetime "updated_at" - end +# Could not dump table "token_permission_types" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "trackers", id: :integer, force: :cascade do |t| - t.integer "org_id" - t.string "code" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["org_id"], name: "index_trackers_on_org_id" - end +# Could not dump table "trackers" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - create_table "users", id: :integer, force: :cascade do |t| - t.string "firstname" - t.string "surname" - t.string "email", limit: 80, default: "", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "encrypted_password" - t.string "reset_password_token" - t.datetime "reset_password_sent_at" - t.datetime "remember_created_at" - t.integer "sign_in_count", default: 0 - t.datetime "current_sign_in_at" - t.datetime "last_sign_in_at" - t.string "current_sign_in_ip" - t.string "last_sign_in_ip" - t.string "confirmation_token" - t.datetime "confirmed_at" - t.datetime "confirmation_sent_at" - t.string "invitation_token" - t.datetime "invitation_created_at" - t.datetime "invitation_sent_at" - t.datetime "invitation_accepted_at" - t.string "other_organisation" - t.boolean "accept_terms" - t.integer "org_id" - t.string "api_token" - t.integer "invited_by_id" - t.string "invited_by_type" - t.integer "language_id" - t.string "recovery_email" - t.string "ldap_password" - t.string "ldap_username" - t.boolean "active", default: true - t.integer "department_id" - t.datetime "last_api_access" - t.index ["department_id"], name: "fk_rails_f29bf9cdf2" - t.index ["email"], name: "index_users_on_email" - t.index ["language_id"], name: "fk_rails_45f4f12508" - t.index ["org_id"], name: "index_users_on_org_id" - end +# Could not dump table "user_role_types" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "user_statuses" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "user_types" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "users" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 create_table "users_perms", id: false, force: :cascade do |t| t.integer "user_id" @@ -630,11 +314,25 @@ t.index ["user_id"], name: "index_users_perms_on_user_id" end + create_table "users_roles", id: false, force: :cascade do |t| + t.integer "user_id" + t.integer "role_id" + t.index ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id" + end + +# Could not dump table "version_translations" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + +# Could not dump table "versions" because of following ActiveRecord::StatementInvalid +# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + add_foreign_key "annotations", "orgs" add_foreign_key "annotations", "questions" add_foreign_key "answers", "plans" add_foreign_key "answers", "questions" add_foreign_key "answers", "users" + add_foreign_key "answers_question_options", "answers" + add_foreign_key "answers_question_options", "question_options" add_foreign_key "conditions", "questions" add_foreign_key "guidance_groups", "orgs" add_foreign_key "guidances", "guidance_groups" @@ -654,6 +352,8 @@ add_foreign_key "question_options", "questions" add_foreign_key "questions", "question_formats" add_foreign_key "questions", "sections" + add_foreign_key "questions_themes", "questions" + add_foreign_key "questions_themes", "themes" add_foreign_key "research_domains", "research_domains", column: "parent_id" add_foreign_key "research_outputs", "licenses" add_foreign_key "roles", "plans" @@ -666,4 +366,6 @@ add_foreign_key "users", "departments" add_foreign_key "users", "languages" add_foreign_key "users", "orgs" + add_foreign_key "users_perms", "perms" + add_foreign_key "users_perms", "users" end diff --git a/spec/features/plans/exports_spec.rb b/spec/features/plans/exports_spec.rb index 4feec4484..85cd14a8d 100644 --- a/spec/features/plans/exports_spec.rb +++ b/spec/features/plans/exports_spec.rb @@ -1,8 +1,9 @@ # frozen_string_literal: true -require 'rails_helper' +require "rails_helper" + +RSpec.describe "PlansExports", type: :feature, js: true do -RSpec.describe 'PlansExports', type: :feature, js: true do let!(:template) { create(:template, phases: 2) } let!(:org) { create(:org, managed: true, is_other: false) } let!(:user) { create(:user, org: org) } @@ -16,7 +17,7 @@ sign_in(user) end - scenario 'User downloads plan from organisational plans portion of the dashboard' do + scenario "User downloads plan from organisational plans portion of the dashboard" do new_plan = create(:plan, :publicly_visible, template: template) new_phase = create(:phase, template: template, sections: 2) new_phase.sections do |sect| @@ -34,99 +35,171 @@ find(:css, "a[href*=\"/#{new_plan.id}/export.pdf\"]", visible: false).click end - scenario 'User downloads public plan belonging to other User' do + scenario "User downloads public plan belonging to other User" do new_plan = create(:plan, :publicly_visible, template: template) create(:role, :creator, plan: new_plan) sign_in(user) within("#plan_#{plan.id}") do - click_button('Actions') - click_link 'Download' + click_button("Actions") + click_link "Download" end - select('html') - new_window = window_opened_by { click_button 'Download Plan' } + select("html") + new_window = window_opened_by { click_button "Download Plan" } within_window new_window do expect(page.source).to have_text(plan.title) end end - scenario 'User downloads org plan belonging to User in same org' do + scenario "User downloads org plan belonging to User in same org" do new_plan = create(:plan, :organisationally_visible, template: template) create(:role, :creator, plan: new_plan, user: create(:user, org: org)) sign_in(user) within("#plan_#{plan.id}") do - click_button('Actions') - click_link 'Download' + click_button("Actions") + click_link "Download" end - select('html') - new_window = window_opened_by { click_button 'Download Plan' } + select("html") + new_window = window_opened_by { click_button "Download Plan" } within_window new_window do expect(page.source).to have_text(plan.title) end end - scenario 'User downloads org plan belonging to User in other org' do + scenario "User downloads org plan belonging to User in other org" do new_plan = create(:plan, :organisationally_visible, template: template) create(:role, :creator, plan: new_plan) sign_in(create(:user)) expect(page).not_to have_text(new_plan.title) end - scenario 'User attempts to download private plan belonging to User in same' do + scenario "User attempts to download private plan belonging to User in same" do new_plan = create(:plan, :privately_visible, template: template) create(:role, :creator, plan: new_plan) sign_in(create(:user)) expect(page).not_to have_text(new_plan.title) end - scenario 'User downloads their plan as HTML' do + # Separate code to test all-phase-download for html since it requires operation in new window + scenario "User downloads their plan as HTML" do within("#plan_#{plan.id}") do - click_button('Actions') - click_link 'Download' + click_button("Actions") + click_link "Download" end - select('html') - new_window = window_opened_by { click_button 'Download Plan' } - within_window new_window do - expect(page.source).to have_text(plan.title) + select("html") + if plan.phases.present? + new_window = window_opened_by do + _select_option("phase_id", "All") + click_button "Download Plan" + end + within_window new_window do + expect(page.source).to have_text(plan.title) + plan.phases.each do |phase| + expect(page.source).to have_text(phase.title) + end + end + new_window = window_opened_by do + _select_option("phase_id", plan.phases[1].id) + click_button "Download Plan" + end + within_window new_window do + expect(page.source).to have_text(plan.title) + expect(page.source).to have_text(plan.phases[1].title) + expect(page.source).not_to have_text(plan.phases[2].title) if plan.phases.length > 2 + end + else + _regular_download("html") end end - scenario 'User downloads their plan as PDF' do + scenario "User downloads their plan as PDF" do within("#plan_#{plan.id}") do - click_button('Actions') - click_link 'Download' + click_button("Actions") + click_link "Download" + end + select("pdf") + if plan.phases.present? + _all_phase_download + _single_phase_download + else + _regular_download("pdf") end - select('pdf') - click_button 'Download Plan' - expect(page.source).to have_text(plan.title) end - scenario 'User downloads their plan as CSV' do + scenario "User downloads their plan as CSV" do within("#plan_#{plan.id}") do - click_button('Actions') - click_link 'Download' + click_button("Actions") + click_link "Download" end - select('csv') - click_button 'Download Plan' - expect(page.source).to have_text(plan.title) + select("csv") + _regular_download("csv") end - scenario 'User downloads their plan as text' do + scenario "User downloads their plan as text" do within("#plan_#{plan.id}") do - click_button('Actions') - click_link 'Download' + click_button("Actions") + click_link "Download" + end + select("text") + if plan.phases.present? + _all_phase_download + _single_phase_download + else + _regular_download("text") end - select('text') - click_button 'Download Plan' - expect(page.source).to have_text(plan.title) end - scenario 'User downloads their plan as docx' do + scenario "User downloads their plan as docx" do within("#plan_#{plan.id}") do - click_button('Actions') - click_link 'Download' + click_button("Actions") + click_link "Download" + end + select("docx") + if plan.phases.present? + _all_phase_download + _single_phase_download + else + _regular_download("docx") end - select('docx') - click_button 'Download Plan' + end + + # =========================== + # = Helper methods = + # =========================== + + def _regular_download(format) + if format == "html" + new_window = window_opened_by do + click_button "Download Plan" + end + within_window new_window do + expect(page.source).to have_text(plan.title) + end + else + click_button "Download Plan" + expect(page.source).to have_text(plan.title) + end + end + + def _all_phase_download + _select_option("phase_id", "All") + click_button "Download Plan" expect(page.source).to have_text(plan.title) + plan.phases.each do |phase| # All phase titles should be included in output + p phase.id + expect(page.source).to have_text(phase.title) + end end -end + + def _single_phase_download + _select_option("phase_id", plan.phases[1].id) + click_button "Download Plan" + expect(page.source).to have_text(plan.title) + expect(page.source).to have_text(plan.phases[1].title) + expect(page.source).not_to have_text(plan.phases[2].title) if plan.phases.length > 2 + end + + def _select_option(select_id, option_value) + find(:id, select_id).find("option[value='#{option_value}']").select_option + end + +end \ No newline at end of file diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 34cc24cd3..5ace19ded 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -65,4 +65,4 @@ config.include Devise::Test::ControllerHelpers, type: :controller config.include Devise::Test::ControllerHelpers, type: :view config.include Pundit::Matchers, type: :policy -end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8d1add27e..ec34d2236 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -117,7 +117,7 @@ # Enable Capybara webmocks if we are testing a feature config.before(:each) do |example| if example.metadata[:type] == :feature - Capybara::Webmock.start + # Capybara::Webmock.start # Allow Capybara to make localhost requests and also contact the # google api chromedriver store @@ -134,4 +134,4 @@ config.after(:suite) do |example| Capybara::Webmock.stop if example.metadata[:type] == :feature end -end +end \ No newline at end of file From 0383bcb186e005c5975b0a83553c1777703f3a31 Mon Sep 17 00:00:00 2001 From: pengyin-shan Date: Mon, 3 Oct 2022 12:25:05 -0400 Subject: [PATCH 02/81] fix schema.rb back to DMPRoadmap version --- db/schema.rb | 692 +++++++++++++++++++++++++++++++------------ spec/rails_helper.rb | 2 +- spec/spec_helper.rb | 2 +- 3 files changed, 497 insertions(+), 199 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index fc2833ad1..56dbfef7d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -2,102 +2,206 @@ # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. # -# This file is the source Rails uses to define your schema when running `bin/rails -# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to -# be faster and is potentially less error prone than running all of your -# migrations from scratch. Old migrations may fail to apply correctly if those -# migrations use external dependencies or application code. +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). # # It's strongly recommended that you check this file into your version control system. ActiveRecord::Schema.define(version: 2022_03_15_104737) do -# Could not dump table "annotations" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "answers" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "annotations", id: :integer, force: :cascade do |t| + t.integer "question_id" + t.integer "org_id" + t.text "text" + t.integer "type", default: 0, null: false + t.datetime "created_at" + t.datetime "updated_at" + t.string "versionable_id", limit: 36 + t.index ["org_id"], name: "fk_rails_aca7521f72" + t.index ["question_id"], name: "index_annotations_on_question_id" + t.index ["versionable_id"], name: "index_annotations_on_versionable_id" + end - create_table "answers_options", id: false, force: :cascade do |t| - t.integer "answer_id", null: false - t.integer "option_id", null: false - t.index ["answer_id", "option_id"], name: "index_answers_options_on_answer_id_and_option_id" + create_table "answers", id: :integer, force: :cascade do |t| + t.text "text" + t.integer "plan_id" + t.integer "user_id" + t.integer "question_id" + t.datetime "created_at" + t.datetime "updated_at" + t.integer "lock_version", default: 0 + t.index ["plan_id"], name: "fk_rails_84a6005a3e" + t.index ["plan_id"], name: "index_answers_on_plan_id" + t.index ["question_id"], name: "fk_rails_3d5ed4418f" + t.index ["question_id"], name: "index_answers_on_question_id" + t.index ["user_id"], name: "fk_rails_584be190c2" end create_table "answers_question_options", id: false, force: :cascade do |t| t.integer "answer_id", null: false t.integer "question_option_id", null: false t.index ["answer_id"], name: "index_answers_question_options_on_answer_id" - t.index ["question_option_id"], name: "fk_rails_01ba00b569" end -# Could not dump table "api_clients" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "api_clients", id: :integer, force: :cascade do |t| + t.string "name", null: false + t.string "description" + t.string "homepage" + t.string "contact_name" + t.string "contact_email" + t.string "client_id", null: false + t.string "client_secret", null: false + t.datetime "last_access" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "org_id" + t.text "redirect_uri" + t.string "scopes", default: "", null: false + t.boolean "confidential", default: true + t.boolean "trusted", default: false + t.integer "callback_method" + t.string "callback_uri" + t.index ["name"], name: "index_oauth_applications_on_name" + end -# Could not dump table "comments" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "conditions", id: :integer, force: :cascade do |t| + t.integer "question_id" + t.text "option_list" + t.integer "action_type" + t.integer "number" + t.text "remove_data" + t.text "webhook_data" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["question_id"], name: "index_conditions_on_question_id" + end -# Could not dump table "conditions" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "contributors", id: :integer, force: :cascade do |t| + t.string "name" + t.string "email" + t.string "phone" + t.integer "roles", null: false + t.integer "org_id" + t.integer "plan_id", null: false + t.datetime "created_at" + t.datetime "updated_at" + t.index ["email"], name: "index_contributors_on_email" + t.index ["name", "id", "org_id"], name: "index_contrib_id_and_org_id" + t.index ["org_id"], name: "index_contributors_on_org_id" + t.index ["plan_id"], name: "index_contributors_on_plan_id" + t.index ["roles"], name: "index_contributors_on_roles" + end -# Could not dump table "contributors" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "departments", id: :integer, force: :cascade do |t| + t.string "name" + t.string "code" + t.integer "org_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["org_id"], name: "index_departments_on_org_id" + end -# Could not dump table "departments" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "exported_plans", id: :integer, force: :cascade do |t| + t.integer "plan_id" + t.integer "user_id" + t.string "format" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "phase_id" + end -# Could not dump table "dmptemplate_translations" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "external_api_access_tokens", force: :cascade do |t| + t.bigint "user_id", null: false + t.string "external_service_name", null: false + t.string "access_token", null: false + t.string "refresh_token" + t.datetime "expires_at" + t.datetime "revoked_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["expires_at"], name: "index_external_api_access_tokens_on_expires_at" + t.index ["external_service_name"], name: "index_external_api_access_tokens_on_external_service_name" + t.index ["user_id", "external_service_name"], name: "index_external_tokens_on_user_and_service" + t.index ["user_id"], name: "index_external_api_access_tokens_on_user_id" + end -# Could not dump table "dmptemplates" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "guidance_groups", id: :integer, force: :cascade do |t| + t.string "name" + t.integer "org_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.boolean "optional_subset", default: false, null: false + t.boolean "published", default: false, null: false + t.index ["org_id"], name: "index_guidance_groups_on_org_id" + end - create_table "dmptemplates_guidance_groups", id: false, force: :cascade do |t| - t.integer "dmptemplate_id" + create_table "guidances", id: :integer, force: :cascade do |t| + t.text "text" t.integer "guidance_group_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.boolean "published" + t.index ["guidance_group_id"], name: "index_guidances_on_guidance_group_id" end -# Could not dump table "exported_plans" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "file_types" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "file_uploads" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "friendly_id_slugs" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "guidance_groups" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - - create_table "guidance_in_group", id: false, force: :cascade do |t| - t.integer "guidance_id", null: false - t.integer "guidance_group_id", null: false - t.index ["guidance_id", "guidance_group_id"], name: "index_guidance_in_group_on_guidance_id_and_guidance_group_id" + create_table "identifier_schemes", id: :integer, force: :cascade do |t| + t.string "name" + t.string "description" + t.boolean "active" + t.datetime "created_at" + t.datetime "updated_at" + t.string "logo_url" + t.string "identifier_prefix" + t.integer "context" + t.string "external_service" end -# Could not dump table "guidance_translations" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "guidances" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "identifier_schemes" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "identifiers" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "identifiers", id: :integer, force: :cascade do |t| + t.string "value", null: false + t.text "attrs" + t.integer "identifier_scheme_id" + t.integer "identifiable_id" + t.string "identifiable_type" + t.datetime "created_at" + t.datetime "updated_at" + t.index ["identifiable_type", "identifiable_id"], name: "index_identifiers_on_identifiable_type_and_identifiable_id" + t.index ["identifier_scheme_id", "identifiable_id", "identifiable_type"], name: "index_identifiers_on_scheme_and_type_and_id" + t.index ["identifier_scheme_id", "value"], name: "index_identifiers_on_identifier_scheme_id_and_value" + end -# Could not dump table "languages" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "languages", id: :integer, force: :cascade do |t| + t.string "abbreviation" + t.string "description" + t.string "name" + t.boolean "default_language" + end -# Could not dump table "licenses" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "licenses", force: :cascade do |t| + t.string "name", null: false + t.string "identifier", null: false + t.string "uri", null: false + t.boolean "osi_approved", default: false + t.boolean "deprecated", default: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["identifier", "osi_approved", "deprecated"], name: "index_license_on_identifier_and_criteria" + t.index ["identifier"], name: "index_licenses_on_identifier" + t.index ["uri"], name: "index_licenses_on_uri" + end -# Could not dump table "metadata_standards" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "metadata_standards", force: :cascade do |t| + t.string "title" + t.text "description" + t.string "rdamsc_id" + t.string "uri" + t.json "locations" + t.json "related_entities" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end create_table "metadata_standards_research_outputs", force: :cascade do |t| t.bigint "metadata_standard_id" @@ -106,8 +210,17 @@ t.index ["research_output_id"], name: "metadata_research_outputs_on_ro" end -# Could not dump table "notes" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "notes", id: :integer, force: :cascade do |t| + t.integer "user_id" + t.text "text" + t.boolean "archived", default: false, null: false + t.integer "answer_id" + t.integer "archived_by" + t.datetime "created_at" + t.datetime "updated_at" + t.index ["answer_id"], name: "index_notes_on_answer_id" + t.index ["user_id"], name: "fk_rails_7f2323ad43" + end create_table "notification_acknowledgements", id: :integer, force: :cascade do |t| t.integer "user_id" @@ -118,14 +231,18 @@ t.index ["user_id"], name: "index_notification_acknowledgements_on_user_id" end -# Could not dump table "notifications" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "option_warnings" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "options" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "notifications", id: :integer, force: :cascade do |t| + t.integer "notification_type" + t.string "title" + t.integer "level" + t.text "body" + t.boolean "dismissable" + t.date "starts_at" + t.date "expires_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.boolean "enabled", default: true + end create_table "org_token_permissions", id: :integer, force: :cascade do |t| t.integer "org_id" @@ -136,97 +253,179 @@ t.index ["token_permission_type_id"], name: "fk_rails_2aa265f538" end -# Could not dump table "organisation_types" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "organisations" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "orgs" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "perms" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "phase_translations" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "phases" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "orgs", id: :integer, force: :cascade do |t| + t.string "name" + t.string "abbreviation" + t.string "target_url" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.boolean "is_other", default: false, null: false + t.integer "region_id" + t.integer "language_id" + t.string "logo_uid" + t.string "logo_name" + t.string "contact_email" + t.integer "org_type", default: 0, null: false + t.text "links" + t.boolean "feedback_enabled", default: false + t.text "feedback_msg" + t.string "contact_name" + t.boolean "managed", default: false, null: false + t.string "api_create_plan_email_subject" + t.text "api_create_plan_email_body" + t.index ["language_id"], name: "fk_rails_5640112cab" + t.index ["region_id"], name: "fk_rails_5a6adf6bab" + t.string "helpdesk_email" + end - create_table "plan_sections", id: :integer, force: :cascade do |t| - t.integer "user_id" - t.integer "section_id" - t.integer "plan_id" + create_table "perms", id: :integer, force: :cascade do |t| + t.string "name" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.datetime "release_time" end -# Could not dump table "plans" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "phases", id: :integer, force: :cascade do |t| + t.string "title" + t.text "description" + t.integer "number" + t.integer "template_id" + t.datetime "created_at" + t.datetime "updated_at" + t.boolean "modifiable" + t.string "versionable_id", limit: 36 + t.index ["template_id"], name: "index_phases_on_template_id" + t.index ["versionable_id"], name: "index_phases_on_versionable_id" + end + + create_table "plans", id: :integer, force: :cascade do |t| + t.string "title" + t.integer "template_id" + t.datetime "created_at" + t.datetime "updated_at" + t.string "identifier" + t.text "description" + t.integer "visibility", default: 3, null: false + t.boolean "feedback_requested", default: false + t.boolean "complete", default: false + t.integer "org_id" + t.integer "funder_id" + t.integer "grant_id" + t.integer "api_client_id" + t.datetime "start_date" + t.datetime "end_date" + t.boolean "ethical_issues" + t.text "ethical_issues_description" + t.string "ethical_issues_report" + t.integer "funding_status" + t.bigint "research_domain_id" + t.index ["funder_id"], name: "index_plans_on_funder_id" + t.index ["grant_id"], name: "index_plans_on_grant_id" + t.index ["org_id"], name: "index_plans_on_org_id" + t.index ["research_domain_id"], name: "index_plans_on_fos_id" + t.index ["template_id"], name: "index_plans_on_template_id" + t.index ["api_client_id"], name: "index_plans_on_api_client_id" + end create_table "plans_guidance_groups", id: :integer, force: :cascade do |t| t.integer "guidance_group_id" t.integer "plan_id" t.index ["guidance_group_id", "plan_id"], name: "index_plans_guidance_groups_on_guidance_group_id_and_plan_id" + t.index ["guidance_group_id"], name: "fk_rails_ec1c5524d7" t.index ["plan_id"], name: "fk_rails_13d0671430" end -# Could not dump table "prefs" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - - create_table "project_groups", id: :integer, force: :cascade do |t| - t.boolean "project_creator" - t.boolean "project_editor" + create_table "prefs", id: :integer, force: :cascade do |t| + t.text "settings" t.integer "user_id" - t.integer "project_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "project_administrator" end - create_table "project_guidance", id: false, force: :cascade do |t| - t.integer "project_id", null: false - t.integer "guidance_group_id", null: false - t.index ["project_id", "guidance_group_id"], name: "index_project_guidance_on_project_id_and_guidance_group_id" + create_table "question_format_labels", id: false, force: :cascade do |t| + t.integer "id" + t.string "description" + t.integer "question_id" + t.integer "number" + t.datetime "created_at" + t.datetime "updated_at" end -# Could not dump table "projects" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "question_format_translations" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "question_formats" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "question_options" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "question_formats", id: :integer, force: :cascade do |t| + t.string "title" + t.text "description" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.boolean "option_based", default: false + t.integer "formattype", default: 0 + end -# Could not dump table "question_translations" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "question_options", id: :integer, force: :cascade do |t| + t.integer "question_id" + t.string "text" + t.integer "number" + t.boolean "is_default" + t.datetime "created_at" + t.datetime "updated_at" + t.string "versionable_id", limit: 36 + t.index ["question_id"], name: "index_question_options_on_question_id" + t.index ["versionable_id"], name: "index_question_options_on_versionable_id" + end -# Could not dump table "questions" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "questions", id: :integer, force: :cascade do |t| + t.text "text" + t.text "default_value" + t.integer "number" + t.integer "section_id" + t.datetime "created_at" + t.datetime "updated_at" + t.integer "question_format_id" + t.boolean "option_comment_display", default: true + t.boolean "modifiable" + t.string "versionable_id", limit: 36 + t.index ["question_format_id"], name: "fk_rails_4fbc38c8c7" + t.index ["section_id"], name: "index_questions_on_section_id" + t.index ["versionable_id"], name: "index_questions_on_versionable_id" + end create_table "questions_themes", id: false, force: :cascade do |t| t.integer "question_id", null: false t.integer "theme_id", null: false t.index ["question_id"], name: "index_questions_themes_on_question_id" - t.index ["theme_id"], name: "fk_rails_0489d5eeba" end - create_table "region_groups", id: :integer, force: :cascade do |t| + create_table "regions", id: :integer, force: :cascade do |t| + t.string "abbreviation" + t.string "description" + t.string "name" t.integer "super_region_id" - t.integer "region_id" end -# Could not dump table "regions" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "related_identifiers", force: :cascade do |t| + t.bigint "identifier_scheme_id" + t.integer "identifier_type", null: false + t.integer "relation_type", null: false + t.bigint "identifiable_id" + t.string "identifiable_type" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "value", null: false + t.index ["identifiable_id", "identifiable_type", "relation_type"], name: "index_relateds_on_identifiable_and_relation_type" + t.index ["identifier_scheme_id"], name: "index_related_identifiers_on_identifier_scheme_id" + t.index ["identifier_type"], name: "index_related_identifiers_on_identifier_type" + t.index ["relation_type"], name: "index_related_identifiers_on_relation_type" + end -# Could not dump table "repositories" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "repositories", force: :cascade do |t| + t.string "name", null: false + t.text "description", null: false + t.string "homepage" + t.string "contact" + t.string "uri", null: false + t.json "info" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["homepage"], name: "index_repositories_on_homepage" + t.index ["name"], name: "index_repositories_on_name" + t.index ["uri"], name: "index_repositories_on_uri" + end create_table "repositories_research_outputs", force: :cascade do |t| t.bigint "research_output_id" @@ -235,11 +434,36 @@ t.index ["research_output_id"], name: "index_repositories_research_outputs_on_research_output_id" end -# Could not dump table "research_domains" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "research_domains", force: :cascade do |t| + t.string "identifier", null: false + t.string "label", null: false + t.bigint "parent_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["parent_id"], name: "index_research_domains_on_parent_id" + end -# Could not dump table "research_outputs" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "research_outputs", force: :cascade do |t| + t.integer "plan_id" + t.integer "output_type", default: 3, null: false + t.string "output_type_description" + t.string "title", null: false + t.string "abbreviation" + t.integer "display_order" + t.boolean "is_default" + t.text "description" + t.integer "access", default: 0, null: false + t.datetime "release_date" + t.boolean "personal_data" + t.boolean "sensitive_data" + t.bigint "byte_size" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.bigint "license_id" + t.index ["license_id"], name: "index_research_outputs_on_license_id" + t.index ["output_type"], name: "index_research_outputs_on_output_type" + t.index ["plan_id"], name: "index_research_outputs_on_plan_id" + end create_table "roles", id: :integer, force: :cascade do |t| t.integer "user_id" @@ -252,35 +476,89 @@ t.index ["user_id"], name: "index_roles_on_user_id" end -# Could not dump table "section_translations" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "sections" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "sessions" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "settings" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "sections", id: :integer, force: :cascade do |t| + t.string "title" + t.text "description" + t.integer "number" + t.datetime "created_at" + t.datetime "updated_at" + t.integer "phase_id" + t.boolean "modifiable" + t.string "versionable_id", limit: 36 + t.index ["phase_id"], name: "index_sections_on_phase_id" + t.index ["versionable_id"], name: "index_sections_on_versionable_id" + end -# Could not dump table "splash_logs" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "sessions", id: :integer, force: :cascade do |t| + t.string "session_id", limit: 64, null: false + t.text "data" + t.datetime "created_at" + t.datetime "updated_at" + t.index ["session_id"], name: "index_sessions_on_session_id", unique: true + t.index ["updated_at"], name: "index_sessions_on_updated_at" + end -# Could not dump table "stats" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "settings", id: :integer, force: :cascade do |t| + t.string "var" + t.text "value" + t.integer "target_id", null: false + t.string "target_type" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end -# Could not dump table "stylesheets" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "stats", id: :integer, force: :cascade do |t| + t.bigint "count", default: 0 + t.date "date", null: false + t.string "type", null: false + t.integer "org_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.text "details" + t.boolean "filtered", default: false + end -# Could not dump table "suggested_answers" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "subscriptions", force: :cascade do |t| + t.bigint "plan_id" + t.integer "subscription_types", null: false + t.string "callback_uri" + t.bigint "subscriber_id" + t.string "subscriber_type" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.datetime "last_notified" + t.index ["plan_id"], name: "index_subscriptions_on_plan_id" + t.index ["subscriber_id", "subscriber_type", "plan_id"], name: "index_subscribers_on_identifiable_and_plan_id" + end -# Could not dump table "templates" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "templates", id: :integer, force: :cascade do |t| + t.string "title" + t.text "description" + t.boolean "published" + t.integer "org_id" + t.string "locale" + t.boolean "is_default" + t.datetime "created_at" + t.datetime "updated_at" + t.integer "version" + t.integer "visibility" + t.integer "customization_of" + t.integer "family_id" + t.boolean "archived" + t.text "links" + t.index ["family_id", "version"], name: "index_templates_on_family_id_and_version", unique: true + t.index ["family_id"], name: "index_templates_on_family_id" + t.index ["org_id", "family_id"], name: "template_organisation_dmptemplate_index" + t.index ["org_id"], name: "index_templates_on_org_id" + end -# Could not dump table "themes" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "themes", id: :integer, force: :cascade do |t| + t.string "title" + t.text "description" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "locale" + end create_table "themes_in_guidance", id: false, force: :cascade do |t| t.integer "theme_id" @@ -289,23 +567,61 @@ t.index ["theme_id"], name: "index_themes_in_guidance_on_theme_id" end -# Could not dump table "token_permission_types" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "trackers" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "user_role_types" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "user_statuses" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "token_permission_types", id: :integer, force: :cascade do |t| + t.string "token_type" + t.text "text_description" + t.datetime "created_at" + t.datetime "updated_at" + end -# Could not dump table "user_types" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "trackers", id: :integer, force: :cascade do |t| + t.integer "org_id" + t.string "code" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["org_id"], name: "index_trackers_on_org_id" + end -# Could not dump table "users" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 + create_table "users", id: :integer, force: :cascade do |t| + t.string "firstname" + t.string "surname" + t.string "email", limit: 80, default: "", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "encrypted_password" + t.string "reset_password_token" + t.datetime "reset_password_sent_at" + t.datetime "remember_created_at" + t.integer "sign_in_count", default: 0 + t.datetime "current_sign_in_at" + t.datetime "last_sign_in_at" + t.string "current_sign_in_ip" + t.string "last_sign_in_ip" + t.string "confirmation_token" + t.datetime "confirmed_at" + t.datetime "confirmation_sent_at" + t.string "invitation_token" + t.datetime "invitation_created_at" + t.datetime "invitation_sent_at" + t.datetime "invitation_accepted_at" + t.string "other_organisation" + t.boolean "accept_terms" + t.integer "org_id" + t.string "api_token" + t.integer "invited_by_id" + t.string "invited_by_type" + t.integer "language_id" + t.string "recovery_email" + t.string "ldap_password" + t.string "ldap_username" + t.boolean "active", default: true + t.integer "department_id" + t.datetime "last_api_access" + t.index ["department_id"], name: "fk_rails_f29bf9cdf2" + t.index ["email"], name: "index_users_on_email" + t.index ["language_id"], name: "fk_rails_45f4f12508" + t.index ["org_id"], name: "index_users_on_org_id" + end create_table "users_perms", id: false, force: :cascade do |t| t.integer "user_id" @@ -314,25 +630,11 @@ t.index ["user_id"], name: "index_users_perms_on_user_id" end - create_table "users_roles", id: false, force: :cascade do |t| - t.integer "user_id" - t.integer "role_id" - t.index ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id" - end - -# Could not dump table "version_translations" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - -# Could not dump table "versions" because of following ActiveRecord::StatementInvalid -# Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 - add_foreign_key "annotations", "orgs" add_foreign_key "annotations", "questions" add_foreign_key "answers", "plans" add_foreign_key "answers", "questions" add_foreign_key "answers", "users" - add_foreign_key "answers_question_options", "answers" - add_foreign_key "answers_question_options", "question_options" add_foreign_key "conditions", "questions" add_foreign_key "guidance_groups", "orgs" add_foreign_key "guidances", "guidance_groups" @@ -352,8 +654,6 @@ add_foreign_key "question_options", "questions" add_foreign_key "questions", "question_formats" add_foreign_key "questions", "sections" - add_foreign_key "questions_themes", "questions" - add_foreign_key "questions_themes", "themes" add_foreign_key "research_domains", "research_domains", column: "parent_id" add_foreign_key "research_outputs", "licenses" add_foreign_key "roles", "plans" @@ -366,6 +666,4 @@ add_foreign_key "users", "departments" add_foreign_key "users", "languages" add_foreign_key "users", "orgs" - add_foreign_key "users_perms", "perms" - add_foreign_key "users_perms", "users" end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 5ace19ded..34cc24cd3 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -65,4 +65,4 @@ config.include Devise::Test::ControllerHelpers, type: :controller config.include Devise::Test::ControllerHelpers, type: :view config.include Pundit::Matchers, type: :policy -end \ No newline at end of file +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ec34d2236..bda162c5c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -134,4 +134,4 @@ config.after(:suite) do |example| Capybara::Webmock.stop if example.metadata[:type] == :feature end -end \ No newline at end of file +end From d8f10606df65bd9e556e8b4d9afb85780e1c1438 Mon Sep 17 00:00:00 2001 From: pengyin-shan Date: Mon, 3 Oct 2022 12:31:34 -0400 Subject: [PATCH 03/81] fix rubocup issue --- app/controllers/plan_exports_controller.rb | 8 +- app/controllers/plans_controller.rb | 6 +- spec/features/plans/exports_spec.rb | 106 ++++++++++----------- 3 files changed, 58 insertions(+), 62 deletions(-) diff --git a/app/controllers/plan_exports_controller.rb b/app/controllers/plan_exports_controller.rb index 235460b7f..a0f8a362e 100644 --- a/app/controllers/plan_exports_controller.rb +++ b/app/controllers/plan_exports_controller.rb @@ -38,15 +38,15 @@ def show @formatting = export_params[:formatting] || @plan.settings(:export).formatting if params.key?(:phase_id) # order phases by phase number asc - @hash[:phases] = @hash[:phases].sort_by{|phase| phase[:number]} - if (params[:phase_id] == "All") + @hash[:phases] = @hash[:phases].sort_by { |phase| phase[:number] } + if params[:phase_id] == 'All' @hash[:all_phases] = true else @selected_phase = @plan.phases.find(params[:phase_id]) end else - @plan.phases.order("phases.updated_at DESC") - .detect { |p| p.visibility_allowed?(@plan) } + @plan.phases.order('phases.updated_at DESC') + .detect { |p| p.visibility_allowed?(@plan) } end # Added contributors to coverage of plans. diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb index 5d611d0e2..3f09ad0e3 100644 --- a/app/controllers/plans_controller.rb +++ b/app/controllers/plans_controller.rb @@ -376,11 +376,9 @@ def download @plan = Plan.find(params[:id]) authorize @plan @phase_options = @plan.phases.order(:number).pluck(:title, :id) - if @phase_options.length > 1 - @phase_options.insert(0,["All phases", "All"]) - end + @phase_options.insert(0, ['All phases', 'All']) if @phase_options.length > 1 @export_settings = @plan.settings(:export) - render "download" + render 'download' end # POST /plans/:id/duplicate diff --git a/spec/features/plans/exports_spec.rb b/spec/features/plans/exports_spec.rb index 85cd14a8d..fe6bf244a 100644 --- a/spec/features/plans/exports_spec.rb +++ b/spec/features/plans/exports_spec.rb @@ -1,9 +1,8 @@ # frozen_string_literal: true -require "rails_helper" - -RSpec.describe "PlansExports", type: :feature, js: true do +require 'rails_helper' +RSpec.describe 'PlansExports', type: :feature, js: true do let!(:template) { create(:template, phases: 2) } let!(:org) { create(:org, managed: true, is_other: false) } let!(:user) { create(:user, org: org) } @@ -17,7 +16,7 @@ sign_in(user) end - scenario "User downloads plan from organisational plans portion of the dashboard" do + scenario 'User downloads plan from organisational plans portion of the dashboard' do new_plan = create(:plan, :publicly_visible, template: template) new_phase = create(:phase, template: template, sections: 2) new_phase.sections do |sect| @@ -35,44 +34,44 @@ find(:css, "a[href*=\"/#{new_plan.id}/export.pdf\"]", visible: false).click end - scenario "User downloads public plan belonging to other User" do + scenario 'User downloads public plan belonging to other User' do new_plan = create(:plan, :publicly_visible, template: template) create(:role, :creator, plan: new_plan) sign_in(user) within("#plan_#{plan.id}") do - click_button("Actions") - click_link "Download" + click_button('Actions') + click_link 'Download' end - select("html") - new_window = window_opened_by { click_button "Download Plan" } + select('html') + new_window = window_opened_by { click_button 'Download Plan' } within_window new_window do expect(page.source).to have_text(plan.title) end end - scenario "User downloads org plan belonging to User in same org" do + scenario 'User downloads org plan belonging to User in same org' do new_plan = create(:plan, :organisationally_visible, template: template) create(:role, :creator, plan: new_plan, user: create(:user, org: org)) sign_in(user) within("#plan_#{plan.id}") do - click_button("Actions") - click_link "Download" + click_button('Actions') + click_link 'Download' end - select("html") - new_window = window_opened_by { click_button "Download Plan" } + select('html') + new_window = window_opened_by { click_button 'Download Plan' } within_window new_window do expect(page.source).to have_text(plan.title) end end - scenario "User downloads org plan belonging to User in other org" do + scenario 'User downloads org plan belonging to User in other org' do new_plan = create(:plan, :organisationally_visible, template: template) create(:role, :creator, plan: new_plan) sign_in(create(:user)) expect(page).not_to have_text(new_plan.title) end - scenario "User attempts to download private plan belonging to User in same" do + scenario 'User attempts to download private plan belonging to User in same' do new_plan = create(:plan, :privately_visible, template: template) create(:role, :creator, plan: new_plan) sign_in(create(:user)) @@ -80,16 +79,16 @@ end # Separate code to test all-phase-download for html since it requires operation in new window - scenario "User downloads their plan as HTML" do + scenario 'User downloads their plan as HTML' do within("#plan_#{plan.id}") do - click_button("Actions") - click_link "Download" + click_button('Actions') + click_link 'Download' end - select("html") + select('html') if plan.phases.present? new_window = window_opened_by do - _select_option("phase_id", "All") - click_button "Download Plan" + _select_option('phase_id', 'All') + click_button 'Download Plan' end within_window new_window do expect(page.source).to have_text(plan.title) @@ -98,8 +97,8 @@ end end new_window = window_opened_by do - _select_option("phase_id", plan.phases[1].id) - click_button "Download Plan" + _select_option('phase_id', plan.phases[1].id) + click_button 'Download Plan' end within_window new_window do expect(page.source).to have_text(plan.title) @@ -107,58 +106,58 @@ expect(page.source).not_to have_text(plan.phases[2].title) if plan.phases.length > 2 end else - _regular_download("html") + _regular_download('html') end end - scenario "User downloads their plan as PDF" do + scenario 'User downloads their plan as PDF' do within("#plan_#{plan.id}") do - click_button("Actions") - click_link "Download" + click_button('Actions') + click_link 'Download' end - select("pdf") + select('pdf') if plan.phases.present? _all_phase_download _single_phase_download else - _regular_download("pdf") + _regular_download('pdf') end end - scenario "User downloads their plan as CSV" do + scenario 'User downloads their plan as CSV' do within("#plan_#{plan.id}") do - click_button("Actions") - click_link "Download" + click_button('Actions') + click_link 'Download' end - select("csv") - _regular_download("csv") + select('csv') + _regular_download('csv') end - scenario "User downloads their plan as text" do + scenario 'User downloads their plan as text' do within("#plan_#{plan.id}") do - click_button("Actions") - click_link "Download" + click_button('Actions') + click_link 'Download' end - select("text") + select('text') if plan.phases.present? _all_phase_download _single_phase_download else - _regular_download("text") + _regular_download('text') end end - scenario "User downloads their plan as docx" do + scenario 'User downloads their plan as docx' do within("#plan_#{plan.id}") do - click_button("Actions") - click_link "Download" + click_button('Actions') + click_link 'Download' end - select("docx") + select('docx') if plan.phases.present? _all_phase_download _single_phase_download else - _regular_download("docx") + _regular_download('docx') end end @@ -167,22 +166,22 @@ # =========================== def _regular_download(format) - if format == "html" + if format == 'html' new_window = window_opened_by do - click_button "Download Plan" + click_button 'Download Plan' end within_window new_window do expect(page.source).to have_text(plan.title) end else - click_button "Download Plan" + click_button 'Download Plan' expect(page.source).to have_text(plan.title) end end def _all_phase_download - _select_option("phase_id", "All") - click_button "Download Plan" + _select_option('phase_id', 'All') + click_button 'Download Plan' expect(page.source).to have_text(plan.title) plan.phases.each do |phase| # All phase titles should be included in output p phase.id @@ -191,8 +190,8 @@ def _all_phase_download end def _single_phase_download - _select_option("phase_id", plan.phases[1].id) - click_button "Download Plan" + _select_option('phase_id', plan.phases[1].id) + click_button 'Download Plan' expect(page.source).to have_text(plan.title) expect(page.source).to have_text(plan.phases[1].title) expect(page.source).not_to have_text(plan.phases[2].title) if plan.phases.length > 2 @@ -201,5 +200,4 @@ def _single_phase_download def _select_option(select_id, option_value) find(:id, select_id).find("option[value='#{option_value}']").select_option end - -end \ No newline at end of file +end From a5c2e9cc5cfc68ae5eb7efb2f5a05b3680a33f8c Mon Sep 17 00:00:00 2001 From: pengyin-shan Date: Mon, 3 Oct 2022 13:00:22 -0400 Subject: [PATCH 04/81] add rubocup exception --- spec/features/plans/exports_spec.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/features/plans/exports_spec.rb b/spec/features/plans/exports_spec.rb index fe6bf244a..38081afb3 100644 --- a/spec/features/plans/exports_spec.rb +++ b/spec/features/plans/exports_spec.rb @@ -165,6 +165,8 @@ # = Helper methods = # =========================== + # rubocop:disable Metrics/AbcSize + # disable Rubocup metrics check to confirm both plan title and phase title on downloaded file def _regular_download(format) if format == 'html' new_window = window_opened_by do @@ -184,7 +186,6 @@ def _all_phase_download click_button 'Download Plan' expect(page.source).to have_text(plan.title) plan.phases.each do |phase| # All phase titles should be included in output - p phase.id expect(page.source).to have_text(phase.title) end end @@ -197,6 +198,7 @@ def _single_phase_download expect(page.source).not_to have_text(plan.phases[2].title) if plan.phases.length > 2 end + # rubocop:enable Metrics/AbcSize def _select_option(select_id, option_value) find(:id, select_id).find("option[value='#{option_value}']").select_option end From e7a9b65c70ed84e2292e7f24556e22d19c0c3b4c Mon Sep 17 00:00:00 2001 From: pengyin-shan Date: Wed, 5 Oct 2022 13:40:51 -0400 Subject: [PATCH 05/81] add missing translation and adjust variables --- app/controllers/plan_exports_controller.rb | 8 ++++---- db/schema.rb | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/plan_exports_controller.rb b/app/controllers/plan_exports_controller.rb index a0f8a362e..2c692e991 100644 --- a/app/controllers/plan_exports_controller.rb +++ b/app/controllers/plan_exports_controller.rb @@ -36,7 +36,7 @@ def show @hash = @plan.as_pdf(current_user, @show_coversheet) @formatting = export_params[:formatting] || @plan.settings(:export).formatting - if params.key?(:phase_id) + if params.key?(:phase_id) && params[:phase_id].length.positive? # order phases by phase number asc @hash[:phases] = @hash[:phases].sort_by { |phase| phase[:number] } if params[:phase_id] == 'All' @@ -45,8 +45,8 @@ def show @selected_phase = @plan.phases.find(params[:phase_id]) end else - @plan.phases.order('phases.updated_at DESC') - .detect { |p| p.visibility_allowed?(@plan) } + @selected_phase = @plan.phases.order('phases.updated_at DESC') + .detect { |p| p.visibility_allowed?(@plan) } end # Added contributors to coverage of plans. @@ -107,7 +107,7 @@ def show_pdf date: l(@plan.updated_at.to_date, format: :readable)), font_size: 8, spacing: (Integer(@formatting[:margin][:bottom]) / 2) - 4, - right: '[page] of [topage]', + right: _('[page] of [topage]'), encoding: 'utf8' } end diff --git a/db/schema.rb b/db/schema.rb index 56dbfef7d..ae11e2f11 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -666,4 +666,4 @@ add_foreign_key "users", "departments" add_foreign_key "users", "languages" add_foreign_key "users", "orgs" -end +end \ No newline at end of file From 3b504ea6190b3820983c71ddaa0c0604864a10de Mon Sep 17 00:00:00 2001 From: briri Date: Thu, 27 Oct 2022 09:42:10 -0700 Subject: [PATCH 06/81] changes to support ruby 3's stricter rules around keyword args --- app/controllers/usage_controller.rb | 11 ++++++----- app/models/phase.rb | 2 +- app/models/question.rb | 6 +++--- app/models/section.rb | 2 +- app/models/template.rb | 17 ++++++++++------- app/services/org/total_count_stat_service.rb | 2 +- .../template/upgrade_customization_service.rb | 10 +++++----- lib/csvable.rb | 3 ++- spec/models/annotation_spec.rb | 3 ++- spec/models/phase_spec.rb | 2 +- spec/models/question_option_spec.rb | 2 +- spec/models/question_spec.rb | 4 ++-- spec/models/section_spec.rb | 2 +- spec/models/template_spec.rb | 9 ++++++--- 14 files changed, 42 insertions(+), 33 deletions(-) diff --git a/app/controllers/usage_controller.rb b/app/controllers/usage_controller.rb index a40682843..e84eb8671 100644 --- a/app/controllers/usage_controller.rb +++ b/app/controllers/usage_controller.rb @@ -35,7 +35,8 @@ def global_statistics # for global usage authorize :usage - data = Org::TotalCountStatService.call(filtered: parse_filtered) # TODO: Update + args = { filtered: parse_filtered } + data = Org::TotalCountStatService.call(**args) # TODO: Update sep = sep_param data_csvified = Csvable.from_array_of_hashes(data, true, sep) @@ -162,24 +163,24 @@ def min_max_dates(args:) end def user_data(args:, as_json: false, sort: :asc) - @users_per_month = StatJoinedUser.monthly_range(args.except(:filtered)) + @users_per_month = StatJoinedUser.monthly_range(**args.except(:filtered)) .order(date: sort) @users_per_month = @users_per_month.map(&:to_json) if as_json end def plan_data(args:, as_json: false, sort: :asc) - @plans_per_month = StatCreatedPlan.monthly_range(args) + @plans_per_month = StatCreatedPlan.monthly_range(**args) .where.not(details: '{"by_template":[]}') .order(date: sort) @plans_per_month = @plans_per_month.map(&:to_json) if as_json end def total_plans(args:) - @total_org_plans = StatCreatedPlan.monthly_range(args).sum(:count) + @total_org_plans = StatCreatedPlan.monthly_range(**args).sum(:count) end def total_users(args:) - @total_org_users = StatJoinedUser.monthly_range(args.except(:filtered)).sum(:count) + @total_org_users = StatJoinedUser.monthly_range(**args.except(:filtered)).sum(:count) end def first_plan_date diff --git a/app/models/phase.rb b/app/models/phase.rb index 9dfd1b11c..0d74df9a4 100644 --- a/app/models/phase.rb +++ b/app/models/phase.rb @@ -102,7 +102,7 @@ def deep_copy(**options) copy.template_id = options.fetch(:template_id, nil) copy.save!(validate: false) if options.fetch(:save, false) options[:phase_id] = copy.id - sections.each { |section| copy.sections << section.deep_copy(options) } + sections.each { |section| copy.sections << section.deep_copy(**options) } copy end diff --git a/app/models/question.rb b/app/models/question.rb index f5f247bbc..dd66c3cc4 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -120,12 +120,12 @@ def deep_copy(**options) copy.section_id = options.fetch(:section_id, nil) copy.save!(validate: false) if options.fetch(:save, false) options[:question_id] = copy.id - question_options.each { |qo| copy.question_options << qo.deep_copy(options) } + question_options.each { |qo| copy.question_options << qo.deep_copy(**options) } annotations.each do |annotation| - copy.annotations << annotation.deep_copy(options) + copy.annotations << annotation.deep_copy(**options) end themes.each { |theme| copy.themes << theme } - conditions.each { |condition| copy.conditions << condition.deep_copy(options) } + conditions.each { |condition| copy.conditions << condition.deep_copy(**options) } copy.conditions = copy.conditions.sort_by(&:number) copy end diff --git a/app/models/section.rb b/app/models/section.rb index 80a495b27..70e0c760a 100644 --- a/app/models/section.rb +++ b/app/models/section.rb @@ -124,7 +124,7 @@ def deep_copy(**options) copy.phase_id = options.fetch(:phase_id, nil) copy.save!(validate: false) if options.fetch(:save, false) options[:section_id] = copy.id - questions.map { |question| copy.questions << question.deep_copy(options) } + questions.map { |question| copy.questions << question.deep_copy(**options) } copy end diff --git a/app/models/template.rb b/app/models/template.rb index eaac5f295..f10ddfae7 100644 --- a/app/models/template.rb +++ b/app/models/template.rb @@ -288,7 +288,7 @@ def deep_copy(attributes: {}, **options) end copy.save! if options.fetch(:save, false) options[:template_id] = copy.id - phases.each { |phase| copy.phases << phase.deep_copy(options) } + phases.each { |phase| copy.phases << phase.deep_copy(**options) } # transfer the conditions to the new template # done here as the new questions are not accessible when the conditions deep copy copy.conditions.each do |cond| @@ -373,7 +373,7 @@ def generate_copy!(org) # Assume customizing_org is persisted raise _('generate_copy! requires an organisation target') unless org.is_a?(Org) - deep_copy( + args = { attributes: { version: 0, published: false, @@ -382,20 +382,22 @@ def generate_copy!(org) is_default: false, title: format(_('Copy of %{template}'), template: title) }, modifiable: true, save: true - ) + } + deep_copy(**args) end # Generates a new copy of self with an incremented version number def generate_version! raise _('generate_version! requires a published template') unless published - deep_copy( + args = { attributes: { version: version + 1, published: false, org: org }, save: true - ) + } + deep_copy(**args) end # Generates a new copy of self for the specified customizing_org @@ -406,7 +408,7 @@ def customize!(customizing_org) # Assume self has org associated raise ArgumentError, _('customize! requires a template from a funder') if !org.funder_only? && !is_default - deep_copy( + args = { attributes: { version: 0, published: false, @@ -416,7 +418,8 @@ def customize!(customizing_org) visibility: Template.visibilities[:organisationally_visible], is_default: false }, modifiable: false, save: true - ) + } + deep_copy(**args) end # Generates a new copy of self including latest changes from the funder this diff --git a/app/services/org/total_count_stat_service.rb b/app/services/org/total_count_stat_service.rb index a8c1062b9..03a123db2 100644 --- a/app/services/org/total_count_stat_service.rb +++ b/app/services/org/total_count_stat_service.rb @@ -30,7 +30,7 @@ def reducer_body(acc, count, key_target) else args = { org_name: org_name } args[key_target] = count - acc[org_name] = build_model(args) + acc[org_name] = build_model(**args) end acc diff --git a/app/services/template/upgrade_customization_service.rb b/app/services/template/upgrade_customization_service.rb index 5a055f819..10017e244 100644 --- a/app/services/template/upgrade_customization_service.rb +++ b/app/services/template/upgrade_customization_service.rb @@ -49,9 +49,8 @@ def initialize(template) @original_funder_template = Template.published(@source_template.customization_of).first - @copy_of_original_customizations = @source_template.deep_copy( - attributes: { version: @source_template.version + 1, published: false } - ) + args = { attributes: { version: @source_template.version + 1, published: false } } + @copy_of_original_customizations = @source_template.deep_copy(**args) @updated_template = init_updated_template end @@ -101,7 +100,7 @@ def call # # Returns {Template} def init_updated_template - @updated_template = @original_funder_template&.deep_copy( + args = { attributes: { version: @copy_of_original_customizations.version, published: @copy_of_original_customizations.published, @@ -111,7 +110,8 @@ def init_updated_template visibility: Template.visibilities[:organisationally_visible], is_default: false }, modifiable: false, save: true - ) + } + @updated_template = @original_funder_template&.deep_copy(**args) end # Find an item within collection that has the same versionable_id as record diff --git a/lib/csvable.rb b/lib/csvable.rb index 94cc64233..b86c19bf0 100644 --- a/lib/csvable.rb +++ b/lib/csvable.rb @@ -18,7 +18,8 @@ def from_array_of_hashes(data = [], humanize = true, sep = ',') .map(&:to_s) end - CSV.generate({ col_sep: sep }) do |csv| + args = { col_sep: sep } + CSV.generate(**args) do |csv| csv << headers data.each do |row| csv << row.values diff --git a/spec/models/annotation_spec.rb b/spec/models/annotation_spec.rb index 7dcb82741..1e1aa1746 100644 --- a/spec/models/annotation_spec.rb +++ b/spec/models/annotation_spec.rb @@ -56,7 +56,8 @@ context 'when question_id option is set' do before do @annotation = create(:annotation) - @new_annotation = @annotation.deep_copy(question_id: 1) + args = { question_id: 1 } + @new_annotation = @annotation.deep_copy(**args) end it 'sets question_id to nil' do diff --git a/spec/models/phase_spec.rb b/spec/models/phase_spec.rb index a89ae70e1..b28344974 100644 --- a/spec/models/phase_spec.rb +++ b/spec/models/phase_spec.rb @@ -66,7 +66,7 @@ let!(:options) { {} } - subject { phase.deep_copy(options) } + subject { phase.deep_copy(**options) } context 'when no options are provided' do before do diff --git a/spec/models/question_option_spec.rb b/spec/models/question_option_spec.rb index 1cae7efda..a6eddcfe4 100644 --- a/spec/models/question_option_spec.rb +++ b/spec/models/question_option_spec.rb @@ -44,7 +44,7 @@ let!(:question_option) { create(:question_option, is_default: true) } - subject { question_option.deep_copy(options) } + subject { question_option.deep_copy(**options) } context 'when no options provided' do it 'builds a new record' do diff --git a/spec/models/question_spec.rb b/spec/models/question_spec.rb index ff3f995a4..47cb64b13 100644 --- a/spec/models/question_spec.rb +++ b/spec/models/question_spec.rb @@ -106,7 +106,7 @@ let!(:options) { {} } - subject { question.deep_copy(options) } + subject { question.deep_copy(**options) } context 'when no options are provided' do before do @@ -163,7 +163,7 @@ it "ignores the original record's value" do question.modifiable = false - expect(question.deep_copy(options).modifiable).to eql(true) + expect(question.deep_copy(**options).modifiable).to eql(true) end end diff --git a/spec/models/section_spec.rb b/spec/models/section_spec.rb index 8eaa0650f..f7839b5a6 100644 --- a/spec/models/section_spec.rb +++ b/spec/models/section_spec.rb @@ -37,7 +37,7 @@ let!(:section) { create(:section) } - subject { section.deep_copy(options) } + subject { section.deep_copy(**options) } context 'when no options provided' do before do diff --git a/spec/models/template_spec.rb b/spec/models/template_spec.rb index dd598b189..5e66ac041 100644 --- a/spec/models/template_spec.rb +++ b/spec/models/template_spec.rb @@ -696,7 +696,8 @@ let!(:template) { create(:template, :published, phases: 2) } subject do - template.deep_copy(attributes: { title: 'foo', description: 'bar' }) + args = { attributes: { title: 'foo', description: 'bar' } } + template.deep_copy(**args) end it 'updates title with the provided value' do @@ -711,7 +712,8 @@ context 'when options save is true' do let!(:template) { create(:template, :published, phases: 2) } - subject { template.deep_copy(attributes: { family_id: 123 }, save: true) } + args = { attributes: { family_id: 123 }, save: true } + subject { template.deep_copy(**args) } it 'returns a persisted record' do expect(subject).to be_persisted @@ -730,7 +732,8 @@ context 'when options save is false' do let!(:template) { create(:template, :published, phases: 2) } - subject { template.deep_copy(attributes: { family_id: 123 }, save: false) } + args = { attributes: { family_id: 123 }, save: false } + subject { template.deep_copy(**args) } it 'returns a new record' do expect(subject).to be_new_record From 7bc47a26370ad086b1d797c65fbde7a7cd6c0650 Mon Sep 17 00:00:00 2001 From: briri Date: Fri, 28 Oct 2022 11:32:17 -0700 Subject: [PATCH 07/81] fixed another keyword args change. updated github actions to use ruby 3.0 --- .github/workflows/mysql.yml | 2 +- .github/workflows/postgres.yml | 2 +- .github/workflows/rubocop.yml | 2 +- Gemfile.lock | 5 ++++- app/controllers/concerns/paginable.rb | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/mysql.yml b/.github/workflows/mysql.yml index 6cc54855e..fecac7bff 100644 --- a/.github/workflows/mysql.yml +++ b/.github/workflows/mysql.yml @@ -19,7 +19,7 @@ jobs: # Install Ruby and run bundler - uses: ruby/setup-ruby@v1 with: - ruby-version: 2.7.6 + ruby-version: '3.0' bundler-cache: true # Install Node diff --git a/.github/workflows/postgres.yml b/.github/workflows/postgres.yml index 7d5c3978a..3fe8abbe6 100644 --- a/.github/workflows/postgres.yml +++ b/.github/workflows/postgres.yml @@ -35,7 +35,7 @@ jobs: # Install Ruby and run bundler - uses: ruby/setup-ruby@v1 with: - ruby-version: 2.7.6 + ruby-version: '3.0' bundler-cache: true # Install Node diff --git a/.github/workflows/rubocop.yml b/.github/workflows/rubocop.yml index 57e84481c..c67d5f543 100644 --- a/.github/workflows/rubocop.yml +++ b/.github/workflows/rubocop.yml @@ -13,7 +13,7 @@ jobs: # Install Ruby and run bundler - uses: ruby/setup-ruby@v1 with: - ruby-version: 2.7.6 + ruby-version: '3.0' bundler-cache: true # Run the Rubocop linter checks diff --git a/Gemfile.lock b/Gemfile.lock index 575e50793..670aa8b1d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -268,6 +268,8 @@ GEM mysql2 (0.5.4) nenv (0.3.0) nio4r (2.5.8) + nokogiri (1.13.9-arm64-darwin) + racc (~> 1.4) nokogiri (1.13.9-x86_64-linux) racc (~> 1.4) notiffany (0.1.3) @@ -498,6 +500,7 @@ GEM zeitwerk (2.6.1) PLATFORMS + arm64-darwin-21 x86_64-linux DEPENDENCIES @@ -580,4 +583,4 @@ RUBY VERSION ruby 2.7.6p219 BUNDLED WITH - 2.3.15 + 2.3.24 diff --git a/app/controllers/concerns/paginable.rb b/app/controllers/concerns/paginable.rb index 71d3eacb0..fccc485b2 100644 --- a/app/controllers/concerns/paginable.rb +++ b/app/controllers/concerns/paginable.rb @@ -200,7 +200,7 @@ def sort_link_url(sort_field) end base_url = paginable_base_url(query_params[:page]) sort_url = URI(base_url) - sort_url.query = stringify_query_params(query_params) + sort_url.query = stringify_query_params(**query_params) sort_url.to_s "#{sort_url}&#{stringify_nonpagination_query_params}" end From 3483c22867d1a7a2d249091a53b21917ca2f1976 Mon Sep 17 00:00:00 2001 From: pengyin-shan Date: Tue, 15 Nov 2022 13:38:49 -0500 Subject: [PATCH 08/81] add translation ability to funding status by creating corresponding enum --- app/models/plan.rb | 6 ++++++ app/views/plans/_project_details.html.erb | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/models/plan.rb b/app/models/plan.rb index 0cf221887..41ca343fc 100644 --- a/app/models/plan.rb +++ b/app/models/plan.rb @@ -63,6 +63,12 @@ class Plan < ApplicationRecord privately_visible: _('private') }.freeze + FUNDING_STATUS = { + planned: _('Planned'), + funded: _('Funded'), + denied: _('Denied') + }.freeze + # ============== # = Attributes = # ============== diff --git a/app/views/plans/_project_details.html.erb b/app/views/plans/_project_details.html.erb index 125d3cabf..fc31c278a 100644 --- a/app/views/plans/_project_details.html.erb +++ b/app/views/plans/_project_details.html.erb @@ -167,7 +167,14 @@ ethics_report_tooltip = _("Link to a protocol from a meeting with an ethics comm <%= form.label(:funding_status, _("Funding status"), class: "control-label") %>
- <% funding_statuses = Plan.funding_statuses.map { |status| [status[0].capitalize, status[0]] } %> + <% funding_statuses = Plan::FUNDING_STATUS.map { |status| [_(status[0].to_s.capitalize), _(status[0].to_s)] } %> + <%= form.select :funding_status, + options_for_select(funding_statuses, form.object.funding_status), + { + include_blank: _("- Please select one -") + }, + { class: "form-control" } %> +
<%= form.select :funding_status, options_for_select(funding_statuses, form.object.funding_status), { include_blank: _("- Please select one -"), From 6a72efe177c7fa910b863b5e31ed8f75f09f51d5 Mon Sep 17 00:00:00 2001 From: pengyin-shan Date: Tue, 15 Nov 2022 15:29:27 -0500 Subject: [PATCH 09/81] remove extra lines --- app/views/plans/_project_details.html.erb | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/app/views/plans/_project_details.html.erb b/app/views/plans/_project_details.html.erb index fc31c278a..893ce2957 100644 --- a/app/views/plans/_project_details.html.erb +++ b/app/views/plans/_project_details.html.erb @@ -168,21 +168,13 @@ ethics_report_tooltip = _("Link to a protocol from a meeting with an ethics comm
<% funding_statuses = Plan::FUNDING_STATUS.map { |status| [_(status[0].to_s.capitalize), _(status[0].to_s)] } %> - <%= form.select :funding_status, - options_for_select(funding_statuses, form.object.funding_status), - { - include_blank: _("- Please select one -") - }, - { class: "form-control" } %> -
- <%= form.select :funding_status, options_for_select(funding_statuses, form.object.funding_status), + <%= form.select :funding_status, options_for_select(funding_statuses, form.object.funding_status), { include_blank: _("- Please select one -"), selected: form.object.funding_status }, { class: "form-control" } %> - <%= form.fields_for :grant, plan.grant do |grant_fields| %>
<%= grant_fields.label(:value, _("Grant number/url"), class: "control-label") %> From a1fcc7cf2f1f317c3167904ce9131112bfd14dee Mon Sep 17 00:00:00 2001 From: briri Date: Tue, 13 Dec 2022 07:50:54 -0800 Subject: [PATCH 10/81] reran bundle with ruby 3.0.5 --- Gemfile.lock | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 99845515e..20f696435 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -95,16 +95,17 @@ GEM bundler (>= 1.2.0, < 3) thor (~> 1.0) byebug (11.1.3) - capybara (3.38.0) + capybara (2.18.0) addressable - matrix mini_mime (>= 0.1.3) - nokogiri (~> 1.8) - rack (>= 1.6.0) - rack-test (>= 0.6.3) - regexp_parser (>= 1.5, < 3.0) - xpath (~> 3.2) - capybara-webmock (0.1.0) + nokogiri (>= 1.3.3) + rack (>= 1.0.0) + rack-test (>= 0.5.4) + xpath (>= 2.0, < 4.0) + capybara-webmock (0.2.3) + capybara (~> 2.4) + rack (>= 1.4) + rack-proxy (= 0.6.0) claide (1.1.0) claide-plugins (0.9.2) cork @@ -297,7 +298,6 @@ GEM net-pop net-smtp marcel (1.0.2) - matrix (0.4.2) method_source (1.0.0) mime-types (3.4.1) mime-types-data (~> 3.2015) @@ -306,7 +306,6 @@ GEM nokogiri (~> 1) rake mini_mime (1.1.2) - mini_portile2 (2.8.0) minitest (5.16.3) mocha (2.0.2) ruby2_keywords (>= 0.0.5) @@ -328,8 +327,7 @@ GEM net-protocol nio4r (2.5.8) no_proxy_fix (0.1.2) - nokogiri (1.13.10) - mini_portile2 (~> 2.8.0) + nokogiri (1.13.10-arm64-darwin) racc (~> 1.4) notiffany (0.1.3) nenv (~> 0.1) @@ -388,7 +386,7 @@ GEM rack (>= 1.2.0) rack-protection (3.0.4) rack - rack-proxy (0.7.4) + rack-proxy (0.6.0) rack rack-test (2.0.2) rack (>= 1.3) @@ -490,7 +488,6 @@ GEM rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) - semantic_range (3.0.0) shellany (0.0.1) shoulda (4.0.0) shoulda-context (~> 2.0) @@ -549,11 +546,10 @@ GEM addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - webpacker (5.4.3) - activesupport (>= 5.2) - rack-proxy (>= 0.6.1) - railties (>= 5.2) - semantic_range (>= 2.3.0) + webpacker (2.0) + activesupport (>= 4.2) + multi_json (~> 1.2) + railties (>= 4.2) webrick (1.7.0) websocket (1.2.9) websocket-driver (0.7.5) @@ -572,7 +568,7 @@ GEM zeitwerk (2.6.6) PLATFORMS - ruby + arm64-darwin-21 DEPENDENCIES activerecord_json_validator @@ -652,7 +648,7 @@ DEPENDENCIES yard-tomdoc RUBY VERSION - ruby 2.7.6p219 + ruby 3.0.5p211 BUNDLED WITH - 2.1.4 + 2.2.33 From 21b9d87c5f44e61f62ebb5ecc1933d41d6a6adb1 Mon Sep 17 00:00:00 2001 From: briri Date: Tue, 13 Dec 2022 13:48:40 -0800 Subject: [PATCH 11/81] finished ruby 3.0 upgrade --- Gemfile | 54 ++---------- Gemfile.lock | 41 +++++---- app/assets/stylesheets/application.scss | 6 +- config/environments/test.rb | 3 + spec/rails_helper.rb | 26 +++++- spec/spec_helper.rb | 17 ++-- spec/support/capybara.rb | 39 ++------- yarn.lock | 111 ++++++++++++++---------- 8 files changed, 131 insertions(+), 166 deletions(-) diff --git a/Gemfile b/Gemfile index b700dace3..cd61d7fdc 100644 --- a/Gemfile +++ b/Gemfile @@ -2,7 +2,7 @@ source 'https://rubygems.org' -ruby '>= 2.7' +ruby '>= 3.0' # ===========# # CORE RAILS # @@ -17,9 +17,6 @@ gem 'rails', '~> 6.1' # Analysis of the issue: https://www.theregister.com/2021/03/25/ruby_rails_code/ gem 'mimemagic' -# Use sqlite3 as the database for Active Record -# gem 'sqlite3', '~> 1.4' - # Use Puma as the app server gem 'puma', group: :puma, require: false @@ -165,19 +162,12 @@ gem 'api-pagination' gem 'sassc-rails' # Font-Awesome SASS (https://github.com/FortAwesome/font-awesome-sass) -gem 'font-awesome-sass', '~> 5' - -# Use webpack to manage app-like JavaScript modules in Rails -# (https://github.com/rails/webpacker) -# gem "webpacker" +gem 'font-awesome-sass' # Parse CSS and add vendor prefixes to CSS rules using values from the Can # I Use website. (https://github.com/ai/autoprefixer-rails) gem 'autoprefixer-rails' -# Minimal embedded v8 for Ruby (https://github.com/discourse/mini_racer) -# gem "mini_racer" - # ========= # # EXPORTING # # ========= # @@ -245,18 +235,10 @@ group :test do # Guard keeps an eye on your file modifications (https://github.com/guard/guard) gem 'guard' - # Guard gem for RSpec (https://github.com/guard/guard-rspec) - # gem 'guard-rspec' - # Library for stubbing HTTP requests in Ruby. # (http://github.com/bblimke/webmock) gem 'webmock' - # Code coverage for Ruby 1.9+ with a powerful configuration library and - # automatic merging of coverage across test suites - # (http://github.com/colszowka/simplecov) - # gem 'simplecov', require: false - # Strategies for cleaning databases. Can be used to ensure a clean state # for testing. (http://github.com/DatabaseCleaner/database_cleaner) gem 'database_cleaner', require: false @@ -270,17 +252,9 @@ group :test do # Adds support for Capybara system testing and selenium driver gem 'capybara' - gem 'selenium-webdriver' + # gem 'selenium-webdriver' # Easy installation and use of web drivers to run system tests with browsers - gem 'webdrivers', '~> 5.2' - - # Automatically create snapshots when Cucumber steps fail with Capybara - # and Rails (http://github.com/mattheworiordan/capybara-screenshot) - # gem 'capybara-screenshot' - - # Browser integration tests are expensive. We can mock external requests - # in our tests, but once a browser is involved, we lose control. - gem 'capybara-webmock' + gem 'webdrivers' #, '~> 5.2' # RSpec::CollectionMatchers lets you express expected outcomes on # collections of an object in an example. @@ -294,7 +268,7 @@ group :test do gem 'rails-controller-testing' # automating code review - gem 'danger', '~> 9.0', require: false + gem 'danger' #, '~> 9.0', require: false end group :ci, :development do @@ -313,24 +287,6 @@ group :ci, :development do # RuboCop rules for detecting and autocorrecting undecorated strings for i18n # (gettext and rails-i18n) gem 'rubocop-i18n' - - # A collection of RuboCop cops to check for performance optimizations in Ruby code. - # gem 'rubocop-performance' - - # Automatic Rails code style checking tool. A RuboCop extension focused on enforcing - # Rails best practices and coding conventions. - # gem 'rubocop-rails' - - # A RuboCop plugin for Rake tasks - # gem 'rubocop-rake' - - # Code style checking for RSpec files. A plugin for the RuboCop code style enforcing - # & linting tool. - # gem 'rubocop-rspec' - - # Thread-safety checks via static analysis. A plugin for the RuboCop code style - # enforcing & linting tool. - # gem 'rubocop-thread_safety' end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 20f696435..322ab230e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -95,17 +95,15 @@ GEM bundler (>= 1.2.0, < 3) thor (~> 1.0) byebug (11.1.3) - capybara (2.18.0) + capybara (3.38.0) addressable + matrix mini_mime (>= 0.1.3) - nokogiri (>= 1.3.3) - rack (>= 1.0.0) - rack-test (>= 0.5.4) - xpath (>= 2.0, < 4.0) - capybara-webmock (0.2.3) - capybara (~> 2.4) - rack (>= 1.4) - rack-proxy (= 0.6.0) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (>= 1.5, < 3.0) + xpath (~> 3.2) claide (1.1.0) claide-plugins (0.9.2) cork @@ -217,8 +215,8 @@ GEM fog-xml (0.1.4) fog-core nokogiri (>= 1.5.11, < 2.0.0) - font-awesome-sass (5.15.1) - sassc (>= 1.11) + font-awesome-sass (6.2.1) + sassc (~> 2.0) formatador (1.1.0) forwardable (1.3.3) fuubar (2.5.1) @@ -298,6 +296,7 @@ GEM net-pop net-smtp marcel (1.0.2) + matrix (0.4.2) method_source (1.0.0) mime-types (3.4.1) mime-types-data (~> 3.2015) @@ -386,7 +385,7 @@ GEM rack (>= 1.2.0) rack-protection (3.0.4) rack - rack-proxy (0.6.0) + rack-proxy (0.7.4) rack rack-test (2.0.2) rack (>= 1.3) @@ -488,6 +487,7 @@ GEM rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) + semantic_range (3.0.0) shellany (0.0.1) shoulda (4.0.0) shoulda-context (~> 2.0) @@ -546,10 +546,11 @@ GEM addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - webpacker (2.0) - activesupport (>= 4.2) - multi_json (~> 1.2) - railties (>= 4.2) + webpacker (5.4.3) + activesupport (>= 5.2) + rack-proxy (>= 0.6.1) + railties (>= 5.2) + semantic_range (>= 2.3.0) webrick (1.7.0) websocket (1.2.9) websocket-driver (0.7.5) @@ -584,9 +585,8 @@ DEPENDENCIES bundle-audit byebug capybara - capybara-webmock contact_us - danger (~> 9.0) + danger database_cleaner devise devise_invitable @@ -596,7 +596,7 @@ DEPENDENCIES factory_bot_rails faker flag_shih_tzu - font-awesome-sass (~> 5) + font-awesome-sass fuubar guard htmltoword @@ -630,7 +630,6 @@ DEPENDENCIES rubocop-i18n sass-rails sassc-rails - selenium-webdriver shoulda spring spring-commands-rspec @@ -639,7 +638,7 @@ DEPENDENCIES translation turbo-rails web-console - webdrivers (~> 5.2) + webdrivers webmock webpacker wicked_pdf diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 58ceda63b..0b874792e 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -1,11 +1,11 @@ // Import locally defined variables. Load this before 'bootstrap' - @import "variables/*"; // Pull in the webpacker managed copy of Bootstrap Stylesheets @import "../../../node_modules/bootstrap-sass/assets/stylesheets/_bootstrap.scss"; @import "../../../node_modules/bootstrap-select/sass/bootstrap-select.scss"; +// Pull in the DMPRoadmap CSS @import "blocks/*"; @import "utils/*"; @@ -13,5 +13,5 @@ // we are using the Datepicker and Sortable at the very least @import "../../../node_modules/jquery-ui-sass/assets/sass/jquery-ui.scss"; -@import "font-awesome-sprockets"; -@import "font-awesome"; \ No newline at end of file +// Pull in Fontawesome +@import "font-awesome"; diff --git a/config/environments/test.rb b/config/environments/test.rb index 7d008cd21..0dd1ff31b 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -23,6 +23,9 @@ 'Cache-Control' => "public, max-age=#{1.hour.to_i}" } + # We need to precompile assets for feature tests + config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif *.svg *.ico *.eot *.ttf) + # Disable fragment caching used in ExternalApis and OrgSelection services config.cache_store = :null_store diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 34cc24cd3..7197d55c1 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,14 +1,21 @@ # frozen_string_literal: true # This file is copied to spec/ when you run 'rails generate rspec:install' +require 'capybara/rails' +require 'rspec/rails' require 'spec_helper' +require 'webmock/rspec' + +# Helpers for some of the common UI componentsand Devise auth +# require_relative 'support/helpers/autocomplete_helper' +# require_relative 'support/helpers/capybara_helper' +# require_relative 'support/helpers/sessions_helper' +# require_relative 'support/helpers/tiny_mce_helper' + ENV['RAILS_ENV'] ||= 'test' require File.expand_path('../config/environment', __dir__) # Prevent database truncation if the environment is production abort('The Rails environment is running in production mode!') if Rails.env.production? -require 'rspec/rails' -# require "capybara-screenshot/rspec" -require 'webmock/rspec' # Add additional requires below this line. Rails is not loaded until this point! # Requires supporting ruby files with custom matchers and macros, etc, in @@ -36,7 +43,20 @@ # No need to run this during CI because we build the DB from the schema # ActiveRecord::Migration.maintain_test_schema! +# Block all external HTTP requests except to the Google APIs URL so that WebDrivers can fetch +# the latest Chromedrivers. +WebMock.disable_net_connect!( + allow_localhost: true, + allow: %w[chromedriver.storage.googleapis.com] +) + +# Configure RSpec RSpec.configure do |config| + config.include(AutoCompleteHelper, type: :feature) + config.include(CapybaraHelper, type: :feature) + config.include(SessionsHelper, type: :feature) + config.include(TinyMceHelper, type: :feature) + # If you're not using ActiveRecord, or you'd prefer not to run each of your # examples within a transaction, remove the following line or assign false # instead of true. diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index bda162c5c..ddd742951 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,12 +1,7 @@ # frozen_string_literal: true +require 'capybara/rspec' require 'mocha' -# require 'simplecov' - -# Start up the SimpleCov Test Coverage service. This must run before the app's -# code is loaded/required! -# SimpleCov writes the results to the ./coverage dir once the tests complete -# SimpleCov.start 'rails' $LOAD_PATH.unshift(File.expand_path(__dir__)) @@ -121,10 +116,10 @@ # Allow Capybara to make localhost requests and also contact the # google api chromedriver store - WebMock.disable_net_connect!( - allow_localhost: true, - allow: %w[chromedriver.storage.googleapis.com] - ) + # WebMock.disable_net_connect!( + # allow_localhost: true, + # allow: %w[chromedriver.storage.googleapis.com] + # ) end # Ensure that there is always a default Language @@ -132,6 +127,6 @@ end config.after(:suite) do |example| - Capybara::Webmock.stop if example.metadata[:type] == :feature + # Capybara::Webmock.stop if example.metadata[:type] == :feature end end diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index 8165a7459..e8ac5b282 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -1,48 +1,23 @@ # frozen_string_literal: true require 'webdrivers/chromedriver' -require_relative 'helpers/capybara_helper' -require_relative 'helpers/sessions_helper' -require_relative 'helpers/tiny_mce_helper' -require_relative 'helpers/autocomplete_helper' - -Capybara.default_driver = :rack_test # Cache for one hour Webdrivers.cache_time = 3600 -# This is a customisation of the default :selenium_chrome_headless config in: -# https://github.com/teamcapybara/capybara/blob/master/lib/capybara.rb -# -# This adds the --no-sandbox flag to fix TravisCI as described here: -# https://docs.travis-ci.com/user/chrome#sandboxing -Capybara.register_driver :selenium_chrome_headless do |app| - Capybara::Selenium::Driver.load_selenium - browser_options = ::Selenium::WebDriver::Chrome::Options.new - browser_options.args << '--headless' - browser_options.args << '--no-sandbox' - browser_options.args << '--disable-gpu' if Gem.win_platform? - Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options) -end + +# Use Puma as the webserver for feature tests +Capybara.server = :puma, { Silent: true } + +# Use the fast rack_test driver for non-feature tests by default +Capybara.default_driver = :rack_test RSpec.configure do |config| config.before(:each, type: :feature, js: false) do Capybara.use_default_driver end + # Use the Selenium headless Chrome driver for feature tests config.before(:each, type: :feature, js: true) do Capybara.current_driver = :selenium_chrome_headless end end - -Capybara.configure do |config| - config.default_max_wait_time = 5 # seconds - config.server = :webrick - config.raise_server_errors = true -end - -RSpec.configure do |config| - config.include(CapybaraHelper, type: :feature) - config.include(SessionsHelper, type: :feature) - config.include(TinyMceHelper, type: :feature) - config.include(AutoCompleteHelper, type: :feature) -end diff --git a/yarn.lock b/yarn.lock index 6ec55c5b5..7b75c981d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1171,9 +1171,11 @@ integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== "@types/cors@^2.8.12": - version "2.8.12" - resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" - integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== + version "2.8.13" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.13.tgz#b8ade22ba455a1b8cb3b5d3f35910fd204f84f94" + integrity sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA== + dependencies: + "@types/node" "*" "@types/eslint@^7.29.0": version "7.29.0" @@ -1230,9 +1232,9 @@ integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== "@types/node@*", "@types/node@>=10.0.0": - version "18.11.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4" - integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg== + version "18.11.14" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.14.tgz#a8571b25f3a31e9ded14e3ab9488509adef831d8" + integrity sha512-0KXV57tENYmmJMl+FekeW9V3O/rlcqGQQJ/hNh9r8pKIj304pskWuEd8fCyNT86g/TpO0gcOTiLzsHLEURFMIQ== "@types/parse-json@^4.0.0": version "4.0.0" @@ -2125,9 +2127,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001400: - version "1.0.30001435" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001435.tgz#502c93dbd2f493bee73a408fe98e98fb1dad10b2" - integrity sha512-kdCkUTjR+v4YAJelyiDTqiu82BDr4W4CP5sgTA0ZBmqn30XfS2ZghPLMowik9TPhS+psWJiUNxsqLyurDbmutA== + version "1.0.30001439" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz#ab7371faeb4adff4b74dad1718a6fd122e45d9cb" + integrity sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A== case-sensitive-paths-webpack-plugin@^2.4.0: version "2.4.0" @@ -2793,9 +2795,9 @@ decamelize@^1.2.0: integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og== + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== deep-is@^0.1.3: version "0.1.4" @@ -3080,9 +3082,9 @@ error-ex@^1.3.1: is-arrayish "^0.2.1" es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.20.4: - version "1.20.4" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.4.tgz#1d103f9f8d78d4cf0713edcd6d0ed1a46eed5861" - integrity sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA== + version "1.20.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.5.tgz#e6dc99177be37cacda5988e692c3fa8b218e95d2" + integrity sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ== dependencies: call-bind "^1.0.2" es-to-primitive "^1.2.1" @@ -3090,6 +3092,7 @@ es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.20.4: function.prototype.name "^1.1.5" get-intrinsic "^1.1.3" get-symbol-description "^1.0.0" + gopd "^1.0.1" has "^1.0.3" has-property-descriptors "^1.0.0" has-symbols "^1.0.3" @@ -3105,8 +3108,8 @@ es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.20.4: object.assign "^4.1.4" regexp.prototype.flags "^1.4.3" safe-regex-test "^1.0.0" - string.prototype.trimend "^1.0.5" - string.prototype.trimstart "^1.0.5" + string.prototype.trimend "^1.0.6" + string.prototype.trimstart "^1.0.6" unbox-primitive "^1.0.2" es-array-method-boxes-properly@^1.0.0: @@ -3240,9 +3243,9 @@ eslint-webpack-plugin@^2.6.0: schema-utils "^3.1.1" eslint@^8.18.0: - version "8.28.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.28.0.tgz#81a680732634677cc890134bcdd9fdfea8e63d6e" - integrity sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ== + version "8.29.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.29.0.tgz#d74a88a20fb44d59c51851625bc4ee8d0ec43f87" + integrity sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg== dependencies: "@eslint/eslintrc" "^1.3.3" "@humanwhocodes/config-array" "^0.11.6" @@ -3472,9 +3475,9 @@ fast-levenshtein@^2.0.6: integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + version "1.14.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.14.0.tgz#107f69d7295b11e0fccc264e1fc6389f623731ce" + integrity sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg== dependencies: reusify "^1.0.4" @@ -3847,12 +3850,19 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.15.0: - version "13.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.18.0.tgz#fb224daeeb2bb7d254cd2c640f003528b8d0c1dc" - integrity sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A== + version "13.19.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.19.0.tgz#7a42de8e6ad4f7242fbcca27ea5b23aca367b5c8" + integrity sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ== dependencies: type-fest "^0.20.2" +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.6: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" @@ -4570,9 +4580,9 @@ jquery-ui@^1.12.1: jquery ">=1.8.0 <4.0.0" "jquery@>=1.8.0 <4.0.0", jquery@^3.5.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.1.tgz#fab0408f8b45fc19f956205773b62b292c147a16" - integrity sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw== + version "3.6.2" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.2.tgz#8302bbc9160646f507bdf59d136a478b312783c4" + integrity sha512-/e7ulNIEEYk1Z/l4X0vpxGt+B/dNsV8ghOPAWZaJs8pkGvsSC0tm33aMGylXcj/U7y4IcvwtMXPMyBFZn/gK9A== js-cookie@^3.0.1: version "3.0.1" @@ -5110,6 +5120,13 @@ minipass@^3.0.0, minipass@^3.1.1: dependencies: yallist "^4.0.0" +minipass@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.0.0.tgz#7cebb0f9fa7d56f0c5b17853cbe28838a8dbbd3b" + integrity sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw== + dependencies: + yallist "^4.0.0" + minizlib@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" @@ -5266,9 +5283,9 @@ node-libs-browser@^2.2.1: vm-browserify "^1.0.1" node-releases@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" - integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== + version "2.0.7" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.7.tgz#593edbc7c22860ee4d32d3933cfebdfab0c0e0e5" + integrity sha512-EJ3rzxL9pTWPjk5arA0s0dgXpnyiAbJDE6wHT62g7VsgrgQgmmZ+Ru++M1BFofncWja+Pnn3rEr3fieRySAdKQ== normalize-path@^2.1.1: version "2.1.1" @@ -6822,9 +6839,9 @@ sass-loader@10.1.1: semver "^7.3.2" sass@^1.38.0: - version "1.56.1" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.56.1.tgz#94d3910cd468fd075fa87f5bb17437a0b617d8a7" - integrity sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ== + version "1.56.2" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.56.2.tgz#9433b345ab3872996c82a53a58c014fd244fd095" + integrity sha512-ciEJhnyCRwzlBCB+h5cCPM6ie/6f8HrhZMQOf5vlU60Y1bI1rx5Zb0vlDZvaycHsg/MqFfF1Eq2eokAa32iw8w== dependencies: chokidar ">=3.0.0 <4.0.0" immutable "^4.0.0" @@ -7308,7 +7325,7 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string.prototype.trimend@^1.0.5: +string.prototype.trimend@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== @@ -7317,7 +7334,7 @@ string.prototype.trimend@^1.0.5: define-properties "^1.1.4" es-abstract "^1.20.4" -string.prototype.trimstart@^1.0.5: +string.prototype.trimstart@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== @@ -7444,13 +7461,13 @@ tapable@^1.0.0, tapable@^1.1.3: integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== tar@^6.0.2: - version "6.1.12" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.12.tgz#3b742fb05669b55671fb769ab67a7791ea1a62e6" - integrity sha512-jU4TdemS31uABHd+Lt5WEYJuzn+TJTCBLljvIAHZOz6M9Os5pJ4dD+vRFLxPa/n3T0iEFzpi+0x1UfuDZYbRMw== + version "6.1.13" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.13.tgz#46e22529000f612180601a6fe0680e7da508847b" + integrity sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" - minipass "^3.0.0" + minipass "^4.0.0" minizlib "^2.1.1" mkdirp "^1.0.3" yallist "^4.0.0" @@ -7495,9 +7512,9 @@ terser@^4.1.2: source-map-support "~0.5.12" terser@^5.3.4: - version "5.16.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.0.tgz#29362c6f5506e71545c73b069ccd199bb28f7f54" - integrity sha512-KjTV81QKStSfwbNiwlBXfcgMcOloyuRdb62/iLFPGBcVNF4EXjhdYBhYHmbJpiBrVxZhDvltE11j+LBQUxEEJg== + version "5.16.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.1.tgz#5af3bc3d0f24241c7fb2024199d5c461a1075880" + integrity sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw== dependencies: "@jridgewell/source-map" "^0.3.2" acorn "^8.5.0" @@ -7540,9 +7557,9 @@ timsort@^0.3.0: integrity sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A== tinymce@^5.10.0: - version "5.10.6" - resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-5.10.6.tgz#ea03927e9d20c035619dfd32ec4fd471c55e32c5" - integrity sha512-bnF2LUoycDsoZZLQBNHbOijrmoJuEeR1rQdqgo4s77BedufpOVnDh00OZKbseHeTMCxhVH05wvOqxLsi6vpeZw== + version "5.10.7" + resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-5.10.7.tgz#d89d446f1962f2a1df6b2b70018ce475ec7ffb80" + integrity sha512-9UUjaO0R7FxcFo0oxnd1lMs7H+D0Eh+dDVo5hKbVe1a+VB0nit97vOqlinj+YwgoBDt6/DSCUoWqAYlLI8BLYA== tmp@^0.2.1: version "0.2.1" From efa74d6adde43093d79d6428482d983c1fa0cedf Mon Sep 17 00:00:00 2001 From: briri Date: Tue, 13 Dec 2022 14:26:52 -0800 Subject: [PATCH 12/81] fixed up rubocop complaints --- app/controllers/concerns/paginable.rb | 2 +- app/models/language.rb | 2 +- app/models/plan.rb | 3 ++- app/models/settings/template.rb | 4 ++-- config/environments/production.rb | 2 +- config/environments/test.rb | 3 --- config/initializers/wicked_pdf.rb.example | 1 + lib/cleanup/deprecators/get_deprecator.rb | 2 +- lib/cleanup/deprecators/predicate_deprecator.rb | 2 +- lib/cleanup/deprecators/set_deprecator.rb | 2 +- spec/mixins/versionable_model.rb | 2 +- spec/rails_helper.rb | 6 ++---- 12 files changed, 14 insertions(+), 17 deletions(-) diff --git a/app/controllers/concerns/paginable.rb b/app/controllers/concerns/paginable.rb index fccc485b2..40937f01a 100644 --- a/app/controllers/concerns/paginable.rb +++ b/app/controllers/concerns/paginable.rb @@ -8,7 +8,7 @@ module Paginable ## # Regex to validate sort_field param is safe - SORT_COLUMN_FORMAT = /[\w_]+\.[\w_]+$/.freeze + SORT_COLUMN_FORMAT = /[\w_]+\.[\w_]+$/ PAGINATION_QUERY_PARAMS = %i[page sort_field sort_direction search controller action].freeze diff --git a/app/models/language.rb b/app/models/language.rb index d08a70191..3755e29ba 100644 --- a/app/models/language.rb +++ b/app/models/language.rb @@ -19,7 +19,7 @@ class Language < ApplicationRecord ABBREVIATION_MAXIMUM_LENGTH = 5 - ABBREVIATION_FORMAT = /\A[a-z]{2}(-[A-Z]{2})?\Z/.freeze + ABBREVIATION_FORMAT = /\A[a-z]{2}(-[A-Z]{2})?\Z/ NAME_MAXIMUM_LENGTH = 20 diff --git a/app/models/plan.rb b/app/models/plan.rb index 0cf221887..ccb050dcb 100644 --- a/app/models/plan.rb +++ b/app/models/plan.rb @@ -441,7 +441,8 @@ def latest_update def owner r = roles.select { |rr| rr.active && rr.administrator } .min { |a, b| a.created_at <=> b.created_at } - r.nil? ? nil : r.user + # return the selected user or nil + r&.user end # Creates a role for the specified user (will update the user's diff --git a/app/models/settings/template.rb b/app/models/settings/template.rb index a0ee4c637..21ef58b92 100644 --- a/app/models/settings/template.rb +++ b/app/models/settings/template.rb @@ -21,8 +21,8 @@ class Template < RailsSettings::SettingObject 'Arial, Helvetica, Sans-Serif' ].freeze - VALID_FONT_SIZE_RANGE = (8..14).freeze - VALID_MARGIN_RANGE = (5..25).freeze + VALID_FONT_SIZE_RANGE = (8..14) + VALID_MARGIN_RANGE = (5..25) VALID_ADMIN_FIELDS = %w[project_name project_identifier grant_title principal_investigator project_data_contact diff --git a/config/environments/production.rb b/config/environments/production.rb index 9d17aeffd..8e1c4099f 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -87,7 +87,7 @@ config.active_support.disallowed_deprecation_warnings = [] # Use default logging formatter so that PID and timestamp are not suppressed. - config.log_formatter = ::Logger::Formatter.new + config.log_formatter = Logger::Formatter.new # Use a different logger for distributed setups. # require 'syslog/logger' diff --git a/config/environments/test.rb b/config/environments/test.rb index 0dd1ff31b..7d008cd21 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -23,9 +23,6 @@ 'Cache-Control' => "public, max-age=#{1.hour.to_i}" } - # We need to precompile assets for feature tests - config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif *.svg *.ico *.eot *.ttf) - # Disable fragment caching used in ExternalApis and OrgSelection services config.cache_store = :null_store diff --git a/config/initializers/wicked_pdf.rb.example b/config/initializers/wicked_pdf.rb.example index 358af1777..1a21f6228 100644 --- a/config/initializers/wicked_pdf.rb.example +++ b/config/initializers/wicked_pdf.rb.example @@ -1,6 +1,7 @@ # frozen_string_literal: true module DMPRoadmap + # WickedPDF gem configuration class Application < Rails::Application WickedPdf.config = { exe_path: ENV.fetch('WICKED_PDF_PATH', '/usr/local/bin/wkhtmltopdf') diff --git a/lib/cleanup/deprecators/get_deprecator.rb b/lib/cleanup/deprecators/get_deprecator.rb index 673ce2859..f59fd5694 100644 --- a/lib/cleanup/deprecators/get_deprecator.rb +++ b/lib/cleanup/deprecators/get_deprecator.rb @@ -13,7 +13,7 @@ class GetDeprecator # Default message to display to developer when deprecated method called. MESSAGE = '%{deprecated_method} is deprecated. ' \ 'Instead, you should use: %{new_method}. ' \ - "Read #{__FILE__} for more information." + "Read #{__FILE__} for more information.".freeze # Message printed to STDOUT when a deprecated method is called. def deprecation_warning(deprecated_method, _message, _backtrace = nil) diff --git a/lib/cleanup/deprecators/predicate_deprecator.rb b/lib/cleanup/deprecators/predicate_deprecator.rb index ee774fc55..8191363be 100644 --- a/lib/cleanup/deprecators/predicate_deprecator.rb +++ b/lib/cleanup/deprecators/predicate_deprecator.rb @@ -12,7 +12,7 @@ class PredicateDeprecator # Default message to display to developer when deprecated method called. MESSAGE = '%{deprecated_method} is deprecated. ' \ 'Instead, you should use: %{new_method}. ' \ - "Read #{__FILE__} for more information." + "Read #{__FILE__} for more information.".freeze # Message printed to STDOUT when a deprecated method is called. def deprecation_warning(deprecated_method, _message, _backtrace = nil) diff --git a/lib/cleanup/deprecators/set_deprecator.rb b/lib/cleanup/deprecators/set_deprecator.rb index 28554e311..33349e9e2 100644 --- a/lib/cleanup/deprecators/set_deprecator.rb +++ b/lib/cleanup/deprecators/set_deprecator.rb @@ -13,7 +13,7 @@ class SetDeprecator # Default message to display to developer when deprecated method called. MESSAGE = '%{deprecated_method} is deprecated. ' \ 'Instead, you should use: %{new_method}. ' \ - "Read #{__FILE__} for more information." + "Read #{__FILE__} for more information.".freeze # Message printed to STDOUT when a deprecated method is called. def deprecation_warning(deprecated_method, _message, _backtrace = nil) diff --git a/spec/mixins/versionable_model.rb b/spec/mixins/versionable_model.rb index 66c6ce883..aa6ed1c9c 100644 --- a/spec/mixins/versionable_model.rb +++ b/spec/mixins/versionable_model.rb @@ -2,7 +2,7 @@ require 'rails_helper' -UUID_REGEX = /\A[\w\d]{8}(-[\w\d]{4}){3}-[\w\d]{12}\Z/i.freeze +UUID_REGEX = /\A[\w\d]{8}(-[\w\d]{4}){3}-[\w\d]{12}\Z/i shared_examples_for 'VersionableModel' do context 'attributes' do diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 7197d55c1..b8cad2e4c 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -31,11 +31,9 @@ # directory. Alternatively, in the individual `*_spec.rb` files, manually # require only the support files necessary. # -Dir[Rails.root.join('spec/support/**/*.rb')].sort { |a, b| a <=> b } - .each { |f| require f } +Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } -Dir[Rails.root.join('spec/mixins/*.rb')].sort { |a, b| a <=> b } - .each { |f| require f } +Dir[Rails.root.join('spec/mixins/*.rb')].each { |f| require f } # Checks for pending migrations and applies them before tests are run. # If you are not using ActiveRecord, you can remove this line.s From 3a9f9aa47ff7eaaeb8da51f0136af4881538eb03 Mon Sep 17 00:00:00 2001 From: briri Date: Tue, 13 Dec 2022 14:29:08 -0800 Subject: [PATCH 13/81] fixed issue with Gemfile including rubocop extensions we are not ready for --- Gemfile | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/Gemfile b/Gemfile index cd61d7fdc..21101fd68 100644 --- a/Gemfile +++ b/Gemfile @@ -47,14 +47,6 @@ gem 'jbuilder' # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', require: false -# GEMS ADDED TO HELP HANDLE RAILS MIGRATION FROM 3.x to 4.2 -# THESE GEMS HELP SUPPORT DEPRACATED FUNCTIONALITY AND WILL LOSE SUPPORT IN -# FUTURE VERSIONS WE SHOULD CONSIDER BRINGING THE CODE UP TO DATE INSTEAD - -# A set of Rails responders to dry up your application -# (http://github.com/plataformatec/responders) -# gem "responders" - # ============== # # ERROR HANDLING # # ============== # @@ -252,9 +244,9 @@ group :test do # Adds support for Capybara system testing and selenium driver gem 'capybara' - # gem 'selenium-webdriver' + # Easy installation and use of web drivers to run system tests with browsers - gem 'webdrivers' #, '~> 5.2' + gem 'webdrivers' # RSpec::CollectionMatchers lets you express expected outcomes on # collections of an object in an example. @@ -268,7 +260,7 @@ group :test do gem 'rails-controller-testing' # automating code review - gem 'danger' #, '~> 9.0', require: false + gem 'danger' end group :ci, :development do From 0fcbbad3a0f9a744ca02163b7fd094859b975052 Mon Sep 17 00:00:00 2001 From: briri Date: Tue, 13 Dec 2022 14:43:11 -0800 Subject: [PATCH 14/81] updated bundler to add x86_64-linux as a valid platform --- Gemfile.lock | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Gemfile.lock b/Gemfile.lock index 322ab230e..724261714 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -328,6 +328,8 @@ GEM no_proxy_fix (0.1.2) nokogiri (1.13.10-arm64-darwin) racc (~> 1.4) + nokogiri (1.13.10-x86_64-linux) + racc (~> 1.4) notiffany (0.1.3) nenv (~> 0.1) shellany (~> 0.0) @@ -570,6 +572,7 @@ GEM PLATFORMS arm64-darwin-21 + x86_64-linux DEPENDENCIES activerecord_json_validator From 6fa280f733374b3bd3b04852b05739cd88bc4e41 Mon Sep 17 00:00:00 2001 From: briri Date: Tue, 13 Dec 2022 15:00:21 -0800 Subject: [PATCH 15/81] updated CHANGELOG --- CHANGELOG.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b64a2b09a..81af9f3bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,29 @@ # Changelog -### Added +## v4.1.0 + +Note this upgrade is a migration from Ruby v2.7.6 to v3.0.5. Note that this could have an impact on any customizations you may have made to your fork of this project. Please see https://www.fastruby.io/blog/ruby/upgrades/upgrade-ruby-from-2.7-to-3.0.html for further information on what to check. + +### Added - Added CHANGELOG.md and Danger Github Action [#3257](https://github.com/DMPRoadmap/roadmap/issues/3257) ### Fixed +- Issue with `@import 'font-awesome-sprockets';` line in `app/assets/stylesheets/application.scss`. Removed that line after referring to the latest font-awesome install/setup guide which no longer includes it. +- Updated places that were incorrectly using keyword args. See [this article](https://makandracards.com/makandra/496481-changes-to-positional-and-keyword-args-in-ruby-3-0) for an overview +- Removed `.freeze` from Regex and Range constants since those types are already immutable +- Fixed Rubocop complaint about redundancy of `r.nil? ? nil : r.user`, so changed it to `r&.user` in `app/models/plan.rb` +- Fixed Rubocop complaint about redundant `::` in config.log_formatter = `::Logger::Formatter.new` in `config/environments/production.rb` +- Froze `lib/deprecators/*.rb` constants that were Strings + ### Changed + +- Upgrade to Ruby version 3.0.5 [#3225](https://github.com/DMPRoadmap/roadmap/issues/3225) +- Bumped all Github actions to use ruby 3.0 +- Cleaned up Gemfile by: + - removing gems that were already commented out + - removed selenium-webdriver and capybara-webmock + - removing version restrictions on: danger, font-awesome-sass, webdrivers +- Cleaned up `spec/rails_helper.rb` and `spec/spec_helper.rb` +- Simplified the `spec/support/capybara.rb` helper to work with the latest version of Capybara and use its built in headless Chrome driver \ No newline at end of file From 33bfb83bd92825bd377abcc14b608c49cdf14c68 Mon Sep 17 00:00:00 2001 From: briri Date: Thu, 15 Dec 2022 08:01:52 -0800 Subject: [PATCH 16/81] changed import/require order in rspec_rails.rb --- spec/rails_helper.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index b8cad2e4c..27cd766e1 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,8 +1,10 @@ # frozen_string_literal: true +# Must include rspec/rails first! +require 'rspec/rails' + # This file is copied to spec/ when you run 'rails generate rspec:install' require 'capybara/rails' -require 'rspec/rails' require 'spec_helper' require 'webmock/rspec' From fc357d1443bf8b9bf896f87dcbb47b7e0ca2594b Mon Sep 17 00:00:00 2001 From: briri Date: Thu, 15 Dec 2022 08:13:04 -0800 Subject: [PATCH 17/81] fixed issue with the order in which things are loaded in rails_helper.rb --- spec/rails_helper.rb | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 27cd766e1..287286954 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,21 +1,17 @@ # frozen_string_literal: true -# Must include rspec/rails first! +# Do not change the order of these require statements, they are dependent on one another! +require 'spec_helper' + +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../config/environment', __dir__) + require 'rspec/rails' # This file is copied to spec/ when you run 'rails generate rspec:install' require 'capybara/rails' -require 'spec_helper' require 'webmock/rspec' -# Helpers for some of the common UI componentsand Devise auth -# require_relative 'support/helpers/autocomplete_helper' -# require_relative 'support/helpers/capybara_helper' -# require_relative 'support/helpers/sessions_helper' -# require_relative 'support/helpers/tiny_mce_helper' - -ENV['RAILS_ENV'] ||= 'test' -require File.expand_path('../config/environment', __dir__) # Prevent database truncation if the environment is production abort('The Rails environment is running in production mode!') if Rails.env.production? From 331dd2e26796eba81e20cf73477467da25811fcd Mon Sep 17 00:00:00 2001 From: briri Date: Thu, 15 Dec 2022 08:22:13 -0800 Subject: [PATCH 18/81] Hopeful fix for randomly failing plan_spec test --- spec/features/plans_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/features/plans_spec.rb b/spec/features/plans_spec.rb index 7e931771a..eb7ba84a4 100644 --- a/spec/features/plans_spec.rb +++ b/spec/features/plans_spec.rb @@ -9,8 +9,8 @@ @default_template = create(:template, :default, :published) @org = create(:org) @research_org = create(:org, :organisation, :research_institute, - templates: 1) - @funding_org = create(:org, :funder, templates: 1) + name: 'Test Research Org', templates: 1) + @funding_org = create(:org, :funder, name: 'Test Funder Org', templates: 1) @template = create(:template, org: @org) @user = create(:user, org: @org) sign_in(@user) From 71c9e5574ed1c41f5c6b2b734a44bc90e0a21ea5 Mon Sep 17 00:00:00 2001 From: John Pinto Date: Thu, 8 Dec 2022 12:49:24 +0000 Subject: [PATCH 19/81] Fix for bug #3214 which had noted there was no request rate limit to resetting the password. The Rack-Attack middleware for blocking & throttling abusive requests is being used. https://github.com/rack/rack-attack/blob/6-stable/README.md Changes: - Added rack-attack version 6.6.1 gem. https://rubygems.org/gems/rack-attack/versions/6.6.1 - Added config/initializers/rack_attack.rb: - The rack-attack functionality is enabled with Rack::Attack.enabled = true but may be switched off Rack::Attack.enabled = false. - Password reset requests are currently throttled from from an IP address for POSTs to path /users/passwords and is limited 2 requests every 30 seconds. ess - Login requests are throttled from an IP address for POSTs to path /users/sign_in and is limited 4 requests every 30 seconds. - A new html page public/429.html with title "Too Many Request" is added. --- CHANGELOG.md | 5 ++++- Gemfile | 3 +++ config/initializers/rack_attack.rb | 25 +++++++++++++++++++++++++ public/429.html | 29 +++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 config/initializers/rack_attack.rb create mode 100644 public/429.html diff --git a/CHANGELOG.md b/CHANGELOG.md index b64a2b09a..7f95230bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,12 @@ # Changelog -### Added +### Added - Added CHANGELOG.md and Danger Github Action [#3257](https://github.com/DMPRoadmap/roadmap/issues/3257) + - Added rack-attack version 6.6.1 gem. https://rubygems.org/gems/rack-attack/versions/6.6.1 + ### Fixed +- Using Rack-attack address vulnerabilities pointed out in password reset and login: there was no request rate limit.[#3214](https://github.com/DMPRoadmap/roadmap/issues/3214) ### Changed diff --git a/Gemfile b/Gemfile index b700dace3..197d98843 100644 --- a/Gemfile +++ b/Gemfile @@ -119,6 +119,9 @@ gem 'jwt' # OO authorization for Rails (https://github.com/elabs/pundit) gem 'pundit' +# Gem for throttling malicious attacks +gem 'rack-attack', '~> 6.6', '>= 6.6.1' + # ========== # # UI / VIEWS # # ========== # diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb new file mode 100644 index 000000000..712315de9 --- /dev/null +++ b/config/initializers/rack_attack.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +# NB: `req` is a Rack::Request object (basically an env hash with friendly accessor methods) + +# Enable/disable Rack::Attack +Rack::Attack.enabled = true + +# Cache store required to work. +Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new # defaults to Rails.cache + +# Throttle should send a 429 Error responsec code and display public/429.html +Rack::Attack.throttled_responder = lambda do |env| + html = ActionView::Base.empty.render(file: 'public/429.html') + [429, {'Content-Type' => 'text/html'}, [html]] +end + +# Throttle attempts to a particular path. 2 POSTs to /users/password every 30 seconds +Rack::Attack.throttle "password_resets/ip", limit: 2, period: 30.seconds do |req| + req.post? && req.path == "/users/password" && req.ip +end + +# Throttle attempts to a particular path. 4 POSTs to /users/sign_in every 30 seconds +Rack::Attack.throttle "logins/ip", limit: 4, period: 30.seconds do |req| + req.post? && req.path == "/users/sign_in" && req.ip +end diff --git a/public/429.html b/public/429.html new file mode 100644 index 000000000..33324d5b6 --- /dev/null +++ b/public/429.html @@ -0,0 +1,29 @@ + + + + We're sorry, but something went wrong (500) + + + + + +
+

Too Many Requests

+ +

You have exceeded the number of requests for this resource. For security reasons access is limited to a fixed number in a given period. Retry later.

+ + +
+ + From b82338d3b174c8e1bfa1b83e062367d53db2a930 Mon Sep 17 00:00:00 2001 From: Benjamin FAURE Date: Fri, 13 Jan 2023 10:40:30 +0100 Subject: [PATCH 20/81] Migrated from webpacker to jsbundling-rails --- .gitignore | 4 +- Gemfile | 5 +- Gemfile.lock | 14 +- Procfile.dev | 2 + app/assets/config/manifest.js | 1 + app/javascript/application.js | 1 + app/javascript/packs/application.js | 2 +- app/views/layouts/application.html.erb | 2 +- bin/dev | 8 + bin/webpack | 18 - bin/webpack-dev-server | 18 - config/initializers/assets.rb | 2 - .../initializers/content_security_policy.rb | 5 - config/webpack/development.js | 5 - config/webpack/environment.js | 23 - config/webpack/loaders/erb.js | 6 +- config/webpack/production.js | 5 - config/webpack/test.js | 5 - config/webpack/webpack.config.js | 35 + package.json | 23 +- yarn.lock | 5401 ++--------------- 21 files changed, 747 insertions(+), 4838 deletions(-) create mode 100644 Procfile.dev create mode 100644 app/javascript/application.js create mode 100755 bin/dev delete mode 100755 bin/webpack delete mode 100755 bin/webpack-dev-server delete mode 100644 config/webpack/development.js delete mode 100644 config/webpack/environment.js delete mode 100644 config/webpack/production.js delete mode 100644 config/webpack/test.js create mode 100644 config/webpack/webpack.config.js diff --git a/.gitignore b/.gitignore index 4cdd5fee2..9ce9eb835 100644 --- a/.gitignore +++ b/.gitignore @@ -114,4 +114,6 @@ yarn-debug.log* .yarn-integrity # Ignore briley AWS cloud9 script to start the application -cloud9-start.sh \ No newline at end of file +cloud9-start.sh +/app/assets/builds/* +!/app/assets/builds/.keep diff --git a/Gemfile b/Gemfile index b700dace3..ea7f99e8d 100644 --- a/Gemfile +++ b/Gemfile @@ -28,8 +28,9 @@ gem 'puma', group: :puma, require: false # SEE: https://dev.to/kolide/how-to-migrate-a-rails-6-app-from-sass-rails-to-cssbundling-rails-4l41 gem 'sass-rails' -# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker -gem 'webpacker' +# Use esbuild, rollup.js, or Webpack to bundle your JavaScript, then deliver it via the asset pipeline in Rails +# Read more: https://github.com/rails/jsbundling-rails +gem 'jsbundling-rails' # Turbo gives you the speed of a single-page web application without having to write any JavaScript.. # Read more: https://github.com/hotwired/turbo-rails diff --git a/Gemfile.lock b/Gemfile.lock index e59b27228..1d7ba9fde 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -238,6 +238,8 @@ GEM jbuilder (2.11.5) actionview (>= 5.0.0) activesupport (>= 5.0.0) + jsbundling-rails (1.1.1) + railties (>= 6.0.0) json (2.6.2) json_schemer (0.2.23) ecma-re-validator (~> 0.3) @@ -356,8 +358,6 @@ GEM rack (>= 1.2.0) rack-protection (3.0.4) rack - rack-proxy (0.7.4) - rack rack-test (2.0.2) rack (>= 1.3) rails (6.1.7) @@ -459,7 +459,6 @@ GEM rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) - semantic_range (3.0.0) shellany (0.0.1) shoulda (4.0.0) shoulda-context (~> 2.0) @@ -517,11 +516,6 @@ GEM addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - webpacker (5.4.3) - activesupport (>= 5.2) - rack-proxy (>= 0.6.1) - railties (>= 5.2) - semantic_range (>= 2.3.0) webrick (1.7.0) websocket (1.2.9) websocket-driver (0.7.5) @@ -575,6 +569,7 @@ DEPENDENCIES htmltoword httparty jbuilder + jsbundling-rails jwt kaminari ledermann-rails-settings @@ -614,7 +609,6 @@ DEPENDENCIES web-console webdrivers (~> 5.2) webmock - webpacker wicked_pdf wkhtmltopdf-binary yard @@ -624,4 +618,4 @@ RUBY VERSION ruby 2.7.6p219 BUNDLED WITH - 2.3.25 + 2.4.3 diff --git a/Procfile.dev b/Procfile.dev new file mode 100644 index 000000000..000e2ed4c --- /dev/null +++ b/Procfile.dev @@ -0,0 +1,2 @@ +web: unset PORT && bin/rails server +js: yarn build --watch diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js index 8388c7159..ec08b198c 100644 --- a/app/assets/config/manifest.js +++ b/app/assets/config/manifest.js @@ -4,3 +4,4 @@ // We use Webpacker to manage our JS, so removed the '=' sign here to tell // Sprockets to ignore JS // link_directory ../javascripts .js +//= link_tree ../builds diff --git a/app/javascript/application.js b/app/javascript/application.js new file mode 100644 index 000000000..db91aa886 --- /dev/null +++ b/app/javascript/application.js @@ -0,0 +1 @@ +// Entry point for the build script in your package.json diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index 802f33f00..4dc0b934d 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -4,7 +4,7 @@ // a relevant structure within app/javascript and only use these pack files to reference // that code so it'll be compiled. // -// To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate +// To reference this file, add <%= javascript_include_tag 'application' %> to the appropriate // layout file, like app/views/layouts/application.html.erb import 'core-js/stable'; diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 413a83403..558320ae8 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -61,11 +61,11 @@ <%= stylesheet_link_tag(stylesheet_manifest_file) %> - <%= javascript_pack_tag 'application', 'data-turbo-track': 'reload' %> <%= csrf_meta_tags %> + <%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>