From 5d0b74cb07b942af793209274002136ad941a5ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Tue, 8 Jan 2019 15:15:36 +0100 Subject: [PATCH 001/183] Initialize graphql after application initialization Proposal, Debate and Comment "globalize_accessors" class method were loaded before application available locales initialization because of graphql initializer. This will cause unexpected translation errors at any translatable classes declared at graphql api definition (api.yml). Doing GraphQL initialization after application initialization should solve this issue. --- config/application.rb | 5 ++++- config/initializers/graphql_api.rb | 11 +++++++++++ spec/lib/graphql_spec.rb | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 config/initializers/graphql_api.rb diff --git a/config/application.rb b/config/application.rb index ee6d15717..dcd309a5c 100644 --- a/config/application.rb +++ b/config/application.rb @@ -57,7 +57,10 @@ module Consul config.i18n.load_path += Dir[Rails.root.join("config", "locales", "**", "*.{rb,yml}")] config.i18n.load_path += Dir[Rails.root.join("config", "locales", "custom", "**", "*.{rb,yml}")] - config.after_initialize { Globalize.set_fallbacks_to_all_available_locales } + config.after_initialize do + Globalize.set_fallbacks_to_all_available_locales + GraphQLApi::Loader.setup + end config.assets.paths << Rails.root.join("app", "assets", "fonts") config.assets.paths << Rails.root.join("vendor", "assets", "fonts") diff --git a/config/initializers/graphql_api.rb b/config/initializers/graphql_api.rb new file mode 100644 index 000000000..c68334244 --- /dev/null +++ b/config/initializers/graphql_api.rb @@ -0,0 +1,11 @@ +module GraphQLApi + class Loader + def self.setup + if ActiveRecord::Base.connection.tables.any? + api_config = YAML.load_file("./config/api.yml") + GraphqlController.const_set "API_TYPE_DEFINITIONS", + GraphQL::ApiTypesCreator::parse_api_config_file(api_config) + end + end + end +end diff --git a/spec/lib/graphql_spec.rb b/spec/lib/graphql_spec.rb index 6493519ef..aad7624f4 100644 --- a/spec/lib/graphql_spec.rb +++ b/spec/lib/graphql_spec.rb @@ -1,6 +1,6 @@ require "rails_helper" -api_types = GraphQL::ApiTypesCreator.create(API_TYPE_DEFINITIONS) +api_types = GraphQL::ApiTypesCreator.create(GraphqlController::API_TYPE_DEFINITIONS) query_type = GraphQL::QueryTypeCreator.create(api_types) ConsulSchema = GraphQL::Schema.define do query query_type From 2e8e7b83a57a4bc06c11726ca1126550cdaced95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 17 Jan 2019 20:02:17 +0100 Subject: [PATCH 002/183] Remove monkey patch Since globalize version update this is no longer needed. New Globalize version initializes globalized_model correctly when building new translations. --- app/models/milestone.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 52f8ccb29..d4219c004 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -11,8 +11,6 @@ class Milestone < ApplicationRecord validates :milestoneable, presence: true validates :publication_date, presence: true - - before_validation :assign_model_to_translations validates_translation :description, presence: true, unless: -> { status_id.present? } scope :order_by_publication_date, -> { order(publication_date: :asc, created_at: :asc) } From 1de23fc7269745495bc01997a6872b2b0b837dba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Tue, 22 Jan 2019 12:38:56 +0100 Subject: [PATCH 003/183] Add paranoid behavior to translations of paranoid models We want to be able to fetch soft deleted translations without using with_deleted scope. --- app/models/concerns/globalizable.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/concerns/globalizable.rb b/app/models/concerns/globalizable.rb index f963787c7..7c961061c 100644 --- a/app/models/concerns/globalizable.rb +++ b/app/models/concerns/globalizable.rb @@ -16,6 +16,10 @@ module Globalizable def description self.read_attribute(:description).try :html_safe end + + if self.paranoid? + translation_class.send :acts_as_paranoid, column: :hidden_at + end end class_methods do From db38a8720524efe080560f29f92a23ecbfd4d035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 21 Jan 2019 12:45:16 +0100 Subject: [PATCH 004/183] Add specs to check how paranoia and globalize work together Create shared model spec to test paranoia and globalize behavior on globalizable and paranoid models. --- spec/shared/models/acts_as_paranoid.rb | 65 ++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 spec/shared/models/acts_as_paranoid.rb diff --git a/spec/shared/models/acts_as_paranoid.rb b/spec/shared/models/acts_as_paranoid.rb new file mode 100644 index 000000000..ee88d13a8 --- /dev/null +++ b/spec/shared/models/acts_as_paranoid.rb @@ -0,0 +1,65 @@ +shared_examples "acts as paranoid" do |factory_name| + let!(:resource) { create(factory_name) } + + it "#{described_class} can be recovered after soft deletion" do + resource.destroy + resource.reload + + expect(resource.hidden_at).not_to be_blank + resource.restore! + resource.reload + + expect(resource.hidden_at).to be_blank + end + + describe "#{described_class} translations" do + + it "should be hidden after parent resource destroy" do + resource.destroy + resource.reload + + expect(resource.translations.with_deleted.first.hidden_at).not_to be_blank + end + + it "should be destroyed after parent resource really_destroy" do + expect{ resource.really_destroy! }.to change { resource.translations.with_deleted.count }.from(1).to(0) + end + + it "cannot be recovered through non recursive restore" do + resource.destroy + resource.reload + + expect{ resource.restore }.not_to change { resource.translations.with_deleted.first.hidden_at } + end + + it "can be recovered through recursive restore after non-recursive restore" do + resource.destroy + resource.restore + resource.destroy + resource.reload + + expect{ resource.restore(recursive: true) }.to change { resource.translations.with_deleted.first.hidden_at } + end + + it "can be recovered after soft deletion through recursive restore" do + original_translation = resource.translations.first + new_translation = resource.translations.build + described_class.translated_attribute_names.each do |translated_attribute_name| + new_translation.send("#{translated_attribute_name}=", original_translation.send(translated_attribute_name)) + end + new_translation.locale = :fr + new_translation.save + + expect(resource.translations.with_deleted.count).to eq(2) + resource.destroy + resource.reload + expect(resource.translations.with_deleted.count).to eq(2) + expect(resource.translations.with_deleted.first.hidden_at).not_to be_blank + expect(resource.translations.with_deleted.second.hidden_at).not_to be_blank + resource.restore!(recursive: true) + resource.reload + expect(resource.translations.with_deleted.first.hidden_at).to be_blank + expect(resource.translations.with_deleted.second.hidden_at).to be_blank + end + end +end From 458fb750eb843d3f5e8696d04eeb754047b4c1dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Tue, 22 Jan 2019 14:38:27 +0100 Subject: [PATCH 005/183] Fix restore method for paranoid models Do not try to update confirmed_hide_at column from models without this column. --- lib/acts_as_paranoid_aliases.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/acts_as_paranoid_aliases.rb b/lib/acts_as_paranoid_aliases.rb index c95acee0d..45e3300df 100644 --- a/lib/acts_as_paranoid_aliases.rb +++ b/lib/acts_as_paranoid_aliases.rb @@ -28,7 +28,7 @@ module ActsAsParanoidAliases def restore(opts = {}) return false unless hidden? super(opts) - update_attribute(:confirmed_hide_at, nil) + update_attribute(:confirmed_hide_at, nil) if self.class.column_names.include? "confirmed_hide_at" after_restore end From f6b41f916bb34dfd3ea8e3630823d7f4fb2ae5b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 21 Jan 2019 13:17:15 +0100 Subject: [PATCH 006/183] Enable soft_deletion of Legislation::DraftVersion::Translations --- ...d_hidden_at_to_legislation_draft_version_translations.rb | 6 ++++++ db/schema.rb | 2 ++ spec/models/legislation/draft_version_spec.rb | 6 ++++-- 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20190121121420_add_hidden_at_to_legislation_draft_version_translations.rb diff --git a/db/migrate/20190121121420_add_hidden_at_to_legislation_draft_version_translations.rb b/db/migrate/20190121121420_add_hidden_at_to_legislation_draft_version_translations.rb new file mode 100644 index 000000000..b83dc1adc --- /dev/null +++ b/db/migrate/20190121121420_add_hidden_at_to_legislation_draft_version_translations.rb @@ -0,0 +1,6 @@ +class AddHiddenAtToLegislationDraftVersionTranslations < ActiveRecord::Migration[4.2] + def change + add_column :legislation_draft_version_translations, :hidden_at, :datetime + add_index :legislation_draft_version_translations, :hidden_at + end +end diff --git a/db/schema.rb b/db/schema.rb index 313147f38..6bc039cdc 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -716,6 +716,8 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.text "body" t.text "body_html" t.text "toc_html" + t.datetime "hidden_at" + t.index ["hidden_at"], name: "index_legislation_draft_version_translations_on_hidden_at", using: :btree t.index ["legislation_draft_version_id"], name: "index_900e5ba94457606e69e89193db426e8ddff809bc", using: :btree t.index ["locale"], name: "index_legislation_draft_version_translations_on_locale", using: :btree end diff --git a/spec/models/legislation/draft_version_spec.rb b/spec/models/legislation/draft_version_spec.rb index 42d9e6401..0b8ceb451 100644 --- a/spec/models/legislation/draft_version_spec.rb +++ b/spec/models/legislation/draft_version_spec.rb @@ -1,7 +1,9 @@ require "rails_helper" -RSpec.describe Legislation::DraftVersion, type: :model do - let(:legislation_draft_version) { build(:legislation_draft_version) } +describe Legislation::DraftVersion do + let(:legislation_draft_version) { build(:legislation_draft_version) } + + it_behaves_like "acts as paranoid", :legislation_draft_version it "is valid" do expect(legislation_draft_version).to be_valid From 049c56e9f84590bbee90cf69c1f0918a9719117f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 21 Jan 2019 13:21:22 +0100 Subject: [PATCH 007/183] Enable soft_deletion of Legislation::Process::Translations --- ...823_add_hidden_at_to_legislation_process_translations.rb | 6 ++++++ db/schema.rb | 2 ++ spec/models/legislation/process_spec.rb | 2 ++ 3 files changed, 10 insertions(+) create mode 100644 db/migrate/20190121121823_add_hidden_at_to_legislation_process_translations.rb diff --git a/db/migrate/20190121121823_add_hidden_at_to_legislation_process_translations.rb b/db/migrate/20190121121823_add_hidden_at_to_legislation_process_translations.rb new file mode 100644 index 000000000..a688f93a8 --- /dev/null +++ b/db/migrate/20190121121823_add_hidden_at_to_legislation_process_translations.rb @@ -0,0 +1,6 @@ +class AddHiddenAtToLegislationProcessTranslations < ActiveRecord::Migration[4.2] + def change + add_column :legislation_process_translations, :hidden_at, :datetime + add_index :legislation_process_translations, :hidden_at + end +end diff --git a/db/schema.rb b/db/schema.rb index 6bc039cdc..9d1a44018 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -788,6 +788,8 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.text "additional_info" t.text "milestones_summary" t.text "homepage" + t.datetime "hidden_at" + t.index ["hidden_at"], name: "index_legislation_process_translations_on_hidden_at", using: :btree t.index ["legislation_process_id"], name: "index_199e5fed0aca73302243f6a1fca885ce10cdbb55", using: :btree t.index ["locale"], name: "index_legislation_process_translations_on_locale", using: :btree end diff --git a/spec/models/legislation/process_spec.rb b/spec/models/legislation/process_spec.rb index 0813b6064..aca03281c 100644 --- a/spec/models/legislation/process_spec.rb +++ b/spec/models/legislation/process_spec.rb @@ -3,6 +3,8 @@ require "rails_helper" describe Legislation::Process do let(:process) { create(:legislation_process) } + it_behaves_like "acts as paranoid", :legislation_process + it "is valid" do expect(process).to be_valid end From e0649f983fd2efd1d354e9fc4aa482416abcd0b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 21 Jan 2019 13:25:20 +0100 Subject: [PATCH 008/183] Enable soft_deletion of Legislation::QuestionOption::Translations --- ...hidden_at_to_legislation_question_option_translations.rb | 6 ++++++ db/schema.rb | 2 ++ spec/models/legislation/question_option_spec.rb | 4 +++- 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20190121122302_add_hidden_at_to_legislation_question_option_translations.rb diff --git a/db/migrate/20190121122302_add_hidden_at_to_legislation_question_option_translations.rb b/db/migrate/20190121122302_add_hidden_at_to_legislation_question_option_translations.rb new file mode 100644 index 000000000..9f65ce5e1 --- /dev/null +++ b/db/migrate/20190121122302_add_hidden_at_to_legislation_question_option_translations.rb @@ -0,0 +1,6 @@ +class AddHiddenAtToLegislationQuestionOptionTranslations < ActiveRecord::Migration[4.2] + def change + add_column :legislation_question_option_translations, :hidden_at, :datetime + add_index :legislation_question_option_translations, :hidden_at + end +end diff --git a/db/schema.rb b/db/schema.rb index 9d1a44018..a9a8459b1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -879,6 +879,8 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "value" + t.datetime "hidden_at" + t.index ["hidden_at"], name: "index_legislation_question_option_translations_on_hidden_at", using: :btree t.index ["legislation_question_option_id"], name: "index_61bcec8729110b7f8e1e9e5ce08780878597a209", using: :btree t.index ["locale"], name: "index_legislation_question_option_translations_on_locale", using: :btree end diff --git a/spec/models/legislation/question_option_spec.rb b/spec/models/legislation/question_option_spec.rb index 0c681872a..20f288dbf 100644 --- a/spec/models/legislation/question_option_spec.rb +++ b/spec/models/legislation/question_option_spec.rb @@ -1,8 +1,10 @@ require "rails_helper" -RSpec.describe Legislation::QuestionOption, type: :model do +describe Legislation::QuestionOption do let(:legislation_question_option) { build(:legislation_question_option) } + it_behaves_like "acts as paranoid", :legislation_question_option + it "is valid" do expect(legislation_question_option).to be_valid end From 441f0773a66b235652e026d58fd31d6cda4fb3e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 21 Jan 2019 13:28:26 +0100 Subject: [PATCH 009/183] Enable soft_deletion of Legislation::Question::Translations --- ...46_add_hidden_at_to_legislation_question_translations.rb | 6 ++++++ db/schema.rb | 2 ++ spec/models/legislation/question_spec.rb | 2 ++ 3 files changed, 10 insertions(+) create mode 100644 db/migrate/20190121122546_add_hidden_at_to_legislation_question_translations.rb diff --git a/db/migrate/20190121122546_add_hidden_at_to_legislation_question_translations.rb b/db/migrate/20190121122546_add_hidden_at_to_legislation_question_translations.rb new file mode 100644 index 000000000..277cdb43e --- /dev/null +++ b/db/migrate/20190121122546_add_hidden_at_to_legislation_question_translations.rb @@ -0,0 +1,6 @@ +class AddHiddenAtToLegislationQuestionTranslations < ActiveRecord::Migration[4.2] + def change + add_column :legislation_question_translations, :hidden_at, :datetime + add_index :legislation_question_translations, :hidden_at + end +end diff --git a/db/schema.rb b/db/schema.rb index a9a8459b1..ff20fd9de 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -902,6 +902,8 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.text "title" + t.datetime "hidden_at" + t.index ["hidden_at"], name: "index_legislation_question_translations_on_hidden_at", using: :btree t.index ["legislation_question_id"], name: "index_d34cc1e1fe6d5162210c41ce56533c5afabcdbd3", using: :btree t.index ["locale"], name: "index_legislation_question_translations_on_locale", using: :btree end diff --git a/spec/models/legislation/question_spec.rb b/spec/models/legislation/question_spec.rb index 88dd10a09..e78589ad5 100644 --- a/spec/models/legislation/question_spec.rb +++ b/spec/models/legislation/question_spec.rb @@ -3,6 +3,8 @@ require "rails_helper" describe Legislation::Question do let(:question) { create(:legislation_question) } + it_behaves_like "acts as paranoid", :legislation_question + describe "Concerns" do it_behaves_like "notifiable" end From e451c4657cb2a8e6c551bd7c0b8dc12976df9e9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 21 Jan 2019 13:31:20 +0100 Subject: [PATCH 010/183] Enable soft_deletion of Poll::Translations --- .../20190121122946_add_hidden_at_to_poll_translations.rb | 6 ++++++ db/schema.rb | 2 ++ spec/models/poll/poll_spec.rb | 1 + 3 files changed, 9 insertions(+) create mode 100644 db/migrate/20190121122946_add_hidden_at_to_poll_translations.rb diff --git a/db/migrate/20190121122946_add_hidden_at_to_poll_translations.rb b/db/migrate/20190121122946_add_hidden_at_to_poll_translations.rb new file mode 100644 index 000000000..efa49d872 --- /dev/null +++ b/db/migrate/20190121122946_add_hidden_at_to_poll_translations.rb @@ -0,0 +1,6 @@ +class AddHiddenAtToPollTranslations < ActiveRecord::Migration[4.2] + def change + add_column :poll_translations, :hidden_at, :datetime + add_index :poll_translations, :hidden_at + end +end diff --git a/db/schema.rb b/db/schema.rb index ff20fd9de..e882755bc 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1223,6 +1223,8 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.string "name" t.text "summary" t.text "description" + t.datetime "hidden_at" + t.index ["hidden_at"], name: "index_poll_translations_on_hidden_at", using: :btree t.index ["locale"], name: "index_poll_translations_on_locale", using: :btree t.index ["poll_id"], name: "index_poll_translations_on_poll_id", using: :btree end diff --git a/spec/models/poll/poll_spec.rb b/spec/models/poll/poll_spec.rb index e03d941b1..3cfe2f335 100644 --- a/spec/models/poll/poll_spec.rb +++ b/spec/models/poll/poll_spec.rb @@ -6,6 +6,7 @@ describe Poll do describe "Concerns" do it_behaves_like "notifiable" + it_behaves_like "acts as paranoid", :poll it_behaves_like "reportable" end From caa9e1cd49f8af86ea81ba661e37af3c7f4dad46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 21 Jan 2019 13:34:25 +0100 Subject: [PATCH 011/183] Enable soft_deletion of Poll::Question::Translations --- ...121123230_add_hidden_at_to_poll_question_translations.rb | 6 ++++++ db/schema.rb | 2 ++ spec/models/poll/question_spec.rb | 4 ++++ 3 files changed, 12 insertions(+) create mode 100644 db/migrate/20190121123230_add_hidden_at_to_poll_question_translations.rb diff --git a/db/migrate/20190121123230_add_hidden_at_to_poll_question_translations.rb b/db/migrate/20190121123230_add_hidden_at_to_poll_question_translations.rb new file mode 100644 index 000000000..62a14f1c6 --- /dev/null +++ b/db/migrate/20190121123230_add_hidden_at_to_poll_question_translations.rb @@ -0,0 +1,6 @@ +class AddHiddenAtToPollQuestionTranslations < ActiveRecord::Migration[4.2] + def change + add_column :poll_question_translations, :hidden_at, :datetime + add_index :poll_question_translations, :hidden_at + end +end diff --git a/db/schema.rb b/db/schema.rb index e882755bc..6076e9cf3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1161,6 +1161,8 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "title" + t.datetime "hidden_at" + t.index ["hidden_at"], name: "index_poll_question_translations_on_hidden_at", using: :btree t.index ["locale"], name: "index_poll_question_translations_on_locale", using: :btree t.index ["poll_question_id"], name: "index_poll_question_translations_on_poll_question_id", using: :btree end diff --git a/spec/models/poll/question_spec.rb b/spec/models/poll/question_spec.rb index 7adee447d..c10ca1c32 100644 --- a/spec/models/poll/question_spec.rb +++ b/spec/models/poll/question_spec.rb @@ -3,6 +3,10 @@ require "rails_helper" RSpec.describe Poll::Question, type: :model do let(:poll_question) { build(:poll_question) } + describe "Concerns" do + it_behaves_like "acts as paranoid", :poll_question + end + describe "#poll_question_id" do it "is invalid if a poll is not selected" do poll_question.poll_id = nil From 206f92b9fa7b3bc0b6a5c77143dca5e5fe76d475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Tue, 22 Jan 2019 14:46:00 +0100 Subject: [PATCH 012/183] Enable soft_deletion of Banner::Translations Also create missing banner model spec. --- ...133850_add_hidden_at_to_banner_translations.rb | 6 ++++++ db/schema.rb | 2 ++ spec/models/banner_spec.rb | 15 +++++++++++++++ 3 files changed, 23 insertions(+) create mode 100644 db/migrate/20190122133850_add_hidden_at_to_banner_translations.rb create mode 100644 spec/models/banner_spec.rb diff --git a/db/migrate/20190122133850_add_hidden_at_to_banner_translations.rb b/db/migrate/20190122133850_add_hidden_at_to_banner_translations.rb new file mode 100644 index 000000000..43e35c457 --- /dev/null +++ b/db/migrate/20190122133850_add_hidden_at_to_banner_translations.rb @@ -0,0 +1,6 @@ +class AddHiddenAtToBannerTranslations < ActiveRecord::Migration[4.2] + def change + add_column :banner_translations, :hidden_at, :datetime + add_index :banner_translations, :hidden_at + end +end diff --git a/db/schema.rb b/db/schema.rb index 6076e9cf3..438c9b53e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -98,7 +98,9 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.datetime "updated_at", null: false t.string "title" t.text "description" + t.datetime "hidden_at" t.index ["banner_id"], name: "index_banner_translations_on_banner_id", using: :btree + t.index ["hidden_at"], name: "index_banner_translations_on_hidden_at", using: :btree t.index ["locale"], name: "index_banner_translations_on_locale", using: :btree end diff --git a/spec/models/banner_spec.rb b/spec/models/banner_spec.rb new file mode 100644 index 000000000..fac153a25 --- /dev/null +++ b/spec/models/banner_spec.rb @@ -0,0 +1,15 @@ +require "rails_helper" + +describe Banner do + + let(:banner) { build(:banner) } + + describe "Concerns" do + it_behaves_like "acts as paranoid", :banner + end + + it "is valid" do + expect(banner).to be_valid + end + +end From 5881f8241e3323502e6e1c60a9fd5c100dff6ced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sun, 23 Dec 2018 01:08:13 +0100 Subject: [PATCH 013/183] Sanitization shared spec Create sanitization shared spec to check sanitizable concern features in all translatable models. --- spec/shared/models/sanitizable.rb | 51 +++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 spec/shared/models/sanitizable.rb diff --git a/spec/shared/models/sanitizable.rb b/spec/shared/models/sanitizable.rb new file mode 100644 index 000000000..542bc8126 --- /dev/null +++ b/spec/shared/models/sanitizable.rb @@ -0,0 +1,51 @@ +shared_examples "sanitizable" do + let(:sanitizable) { build(model_name(described_class)) } + + it "is sanitized" do + sanitizable.description = "" + + sanitizable.valid? + + expect(sanitizable.description).to eq("alert('danger');") + end + + it "is html_safe" do + sanitizable.description = "" + + sanitizable.valid? + + expect(sanitizable.description).to be_html_safe + end + + it "is sanitized using globalize accessors" do + sanitizable.description_en = "" + + sanitizable.valid? + + expect(sanitizable.description_en).to eq("alert('danger');") + end + + it "is html_safe using globalize accessors" do + sanitizable.description_en = "" + + sanitizable.valid? + + expect(sanitizable.description_en).to be_html_safe + end + + describe "#tag_list" do + before do + unless described_class.included_modules.include?(Taggable) + skip "#{described_class} does not have a tag list" + end + end + + it "sanitizes the tag list" do + sanitizable.tag_list = "user_id=1" + + sanitizable.valid? + + expect(sanitizable.tag_list).to eq(["user_id1"]) + end + end +end From 4f0d1399f254516c02a5460b308251f90023e0b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sun, 23 Dec 2018 12:02:14 +0100 Subject: [PATCH 014/183] Fix html with links sanitization Globalize attribute accessors were arriving here as Strings intead of ActiveSupport::SafeBuffer so they were not sanitized correctly. --- app/helpers/text_with_links_helper.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/helpers/text_with_links_helper.rb b/app/helpers/text_with_links_helper.rb index 9144bdd6b..b59c6ae7f 100644 --- a/app/helpers/text_with_links_helper.rb +++ b/app/helpers/text_with_links_helper.rb @@ -8,6 +8,7 @@ module TextWithLinksHelper def safe_html_with_links(html) return if html.nil? + html = ActiveSupport::SafeBuffer.new(html) if html.is_a?(String) return html.html_safe unless html.html_safe? Rinku.auto_link(html, :all, 'target="_blank" rel="nofollow"').html_safe end From cf370cab84e227d00071cbd16c09fe5fa324afc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sat, 12 Jan 2019 14:23:00 +0100 Subject: [PATCH 015/183] Adapt suggest script for translations Proposal, Debate, Budget Investment and Comment will be translatable models soon. This commit prepares suggestions script to work well with translatable forms elements too. --- app/assets/javascripts/suggest.js.coffee | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/suggest.js.coffee b/app/assets/javascripts/suggest.js.coffee index 854f7ccf1..c8e242cf6 100644 --- a/app/assets/javascripts/suggest.js.coffee +++ b/app/assets/javascripts/suggest.js.coffee @@ -9,11 +9,15 @@ App.Suggest = callback = -> $.ajax url: $this.data("js-url") - data: { search: $this.val() }, - type: "GET", + data: + search: $this.val() + type: "GET" dataType: "html" success: (stHtml) -> js_suggest_selector = $this.data("js-suggest") + if js_suggest_selector.startsWith(".") + locale = $this.closest(".translatable-fields").data("locale") + js_suggest_selector += "[data-locale=#{locale}]" $(js_suggest_selector).html(stHtml) timer = null From 3d04b388adbe5b4e34e8865bc2340c3bc8458e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Fri, 25 Jan 2019 17:07:14 +0100 Subject: [PATCH 016/183] Adapt translatable shared specs Adapt translatable shared specs to define an owner when running at frontend feature specs. --- spec/shared/features/translatable.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/spec/shared/features/translatable.rb b/spec/shared/features/translatable.rb index f7f0809ae..d764d0fb7 100644 --- a/spec/shared/features/translatable.rb +++ b/spec/shared/features/translatable.rb @@ -32,6 +32,7 @@ shared_examples "translatable" do |factory_name, path_name, input_fields, textar fields - optional_fields end + let(:user) { create(:administrator).user } let(:translatable) do if factory_name == "budget_phase" budget = create(:budget) @@ -41,9 +42,12 @@ shared_examples "translatable" do |factory_name, path_name, input_fields, textar create(factory_name, attributes) end end - let(:path) { send(path_name, *resource_hierarchy_for(translatable)) } - before { login_as(create(:administrator).user) } + + before do + login_as(user) + translatable.update(author: user) if front_end_path_to_visit?(path_name) + end context "Manage translations" do before do @@ -353,3 +357,7 @@ def update_button_text "Save changes" end end + +def front_end_path_to_visit?(path) + path[/admin|managment|valuation/].blank? +end From ba9e9887edc4103d615f24d890b65b2c248267c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 28 Jan 2019 23:12:09 +0100 Subject: [PATCH 017/183] Set globalize fallbacks for requests New version of globalize uses RequestStore gem to store I18n.locale and Globalize.fallbacks in a per request basis to avoid collissions between different requests. This gem update broke Globalize.fallback results because it tries to fetch fallbacks from RequestStore, where there is no locale fallbacks definition. --- spec/shared/features/translatable.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spec/shared/features/translatable.rb b/spec/shared/features/translatable.rb index d764d0fb7..4f4458a78 100644 --- a/spec/shared/features/translatable.rb +++ b/spec/shared/features/translatable.rb @@ -56,6 +56,22 @@ shared_examples "translatable" do |factory_name, path_name, input_fields, textar end end + scenario "should show first available fallback when current locale translation does not exist", :js do + attributes = fields.product(%i[fr]).map do |field, locale| + [:"#{field}_#{locale}", text_for(field, locale)] + end.to_h + translatable.update(attributes) + visit path + + select "English", from: :translation_locale + click_link "Remove language" + select "Español", from: :translation_locale + click_link "Remove language" + click_button update_button_text + + expect(page).to have_content "en Français" + end + scenario "Add a translation", :js do visit path From f53043ee2a4099e8f59a67382eea37fe7ec28f79 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 25 Jan 2019 13:44:17 +0100 Subject: [PATCH 018/183] Install gem 'translator-text' to conect with MicrosoftTranslation Service API Wrapper for the Microsoft Translator Text API 3.0 --- Gemfile | 1 + Gemfile.lock | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/Gemfile b/Gemfile index dc5e1a0e7..6e8cf5c24 100644 --- a/Gemfile +++ b/Gemfile @@ -49,6 +49,7 @@ gem "savon", "~> 2.12.0" gem "sitemap_generator", "~> 6.0.1" gem "social-share-button", "~> 1.1" gem "sprockets", "~> 3.7.2" +gem "translator-text", "~> 0.1.0" gem "turbolinks", "~> 2.5.3" gem "turnout", "~> 2.4.0" gem "uglifier", "~> 4.1.2" diff --git a/Gemfile.lock b/Gemfile.lock index e90a4c4a0..582f12578 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -168,6 +168,31 @@ GEM devise (>= 4.0) diff-lcs (1.3) docile (1.3.1) + dry-configurable (0.7.0) + concurrent-ruby (~> 1.0) + dry-container (0.6.0) + concurrent-ruby (~> 1.0) + dry-configurable (~> 0.1, >= 0.1.3) + dry-core (0.4.7) + concurrent-ruby (~> 1.0) + dry-equalizer (0.2.1) + dry-inflector (0.1.2) + dry-logic (0.4.2) + dry-container (~> 0.2, >= 0.2.6) + dry-core (~> 0.2) + dry-equalizer (~> 0.2) + dry-struct (0.5.1) + dry-core (~> 0.4, >= 0.4.3) + dry-equalizer (~> 0.2) + dry-types (~> 0.13) + ice_nine (~> 0.11) + dry-types (0.13.3) + concurrent-ruby (~> 1.0) + dry-container (~> 0.3) + dry-core (~> 0.4, >= 0.4.4) + dry-equalizer (~> 0.2) + dry-inflector (~> 0.1, >= 0.1.2) + dry-logic (~> 0.4, >= 0.4.2) email_spec (2.1.1) htmlentities (~> 4.3.3) launchy (~> 2.1) @@ -223,6 +248,9 @@ GEM highline (2.0.0) html_tokenizer (0.0.7) htmlentities (4.3.4) + httparty (0.17.0) + mime-types (~> 3.0) + multi_xml (>= 0.5.2) httpi (2.4.4) rack socksify @@ -237,6 +265,7 @@ GEM parser (>= 2.2.3.0) rainbow (>= 2.2.2, < 4.0) terminal-table (>= 1.5.1) + ice_nine (0.11.2) initialjs-rails (0.2.0.5) railties (>= 3.1, < 6.0) invisible_captcha (0.10.0) @@ -493,6 +522,9 @@ GEM tilt (2.0.8) tins (1.16.3) tomlrb (1.2.7) + translator-text (0.1.0) + dry-struct (~> 0.5.0) + httparty (~> 0.15) turbolinks (2.5.4) coffee-rails turnout (2.4.1) @@ -614,6 +646,7 @@ DEPENDENCIES spring (~> 2.0.1) spring-commands-rspec (~> 1.0.4) sprockets (~> 3.7.2) + translator-text (~> 0.1.0) turbolinks (~> 2.5.3) turnout (~> 2.4.0) uglifier (~> 4.1.2) From fa80d96249464931cbb99d93e8df33f1c13b112c Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 25 Jan 2019 13:44:59 +0100 Subject: [PATCH 019/183] Add new key to api's secrets group --- config/secrets.yml.example | 1 + 1 file changed, 1 insertion(+) diff --git a/config/secrets.yml.example b/config/secrets.yml.example index 798779fc6..3a8678766 100644 --- a/config/secrets.yml.example +++ b/config/secrets.yml.example @@ -7,6 +7,7 @@ maps: &maps map_tiles_provider_attribution: "© OpenStreetMap contributors" apis: &apis + microsoft_api_key: "" census_api_end_point: "" census_api_institution_code: "" census_api_portal_name: "" From 31011033a7f5c36e3a5eba69e561149581a9e678 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 25 Jan 2019 14:04:38 +0100 Subject: [PATCH 020/183] Create MicrosoftTranslateClient - Conect to remote translation service and translate array of strings - Create SentencesParser module with texts management methods: - Detect split position method: When the text requested to translate is too large, we need split it in smaller parts for we can translate. This method search first valid point (dot or whitespace) for split this text so then we can get an response without dividing the word in half. --- lib/microsoft_translate_client.rb | 81 ++++++++++ lib/sentences_parser.rb | 24 +++ spec/lib/microsoft_translate_client_spec.rb | 168 ++++++++++++++++++++ 3 files changed, 273 insertions(+) create mode 100644 lib/microsoft_translate_client.rb create mode 100644 lib/sentences_parser.rb create mode 100644 spec/lib/microsoft_translate_client_spec.rb diff --git a/lib/microsoft_translate_client.rb b/lib/microsoft_translate_client.rb new file mode 100644 index 000000000..23b595403 --- /dev/null +++ b/lib/microsoft_translate_client.rb @@ -0,0 +1,81 @@ +require "translator-text" +include SentencesParser + +class MicrosoftTranslateClient + CHARACTERS_LIMIT_PER_REQUEST = 5000 + PREVENTING_TRANSLATION_KEY = "notranslate" + + def initialize + api_key = Rails.application.secrets.microsoft_api_key + @client = TranslatorText::Client.new(api_key) + end + + def call(fields_values, locale) + texts = prepare_texts(fields_values) + valid_locale = parse_locale(locale) + request_translation(texts, valid_locale) + end + + def fragments_for(text) + return [text] if text.size <= CHARACTERS_LIMIT_PER_REQUEST + + split_position = detect_split_position(text) + start_text = text[0..split_position] + end_text = text[split_position + 1 .. text.size] + + fragments_for(start_text) + [end_text] + end + + private + + def request_translation(texts, locale) + response = [] + split_response = false + + if characters_count(texts) <= CHARACTERS_LIMIT_PER_REQUEST + response = @client.translate(texts, to: locale) + else + texts.each do |text| + response << translate_text(text, locale) + end + split_response = true + end + + parse_response(response, split_response) + end + + def translate_text(text, locale) + fragments_for(text).map do |fragment| + @client.translate([fragment], to: locale) + end.flatten + end + + def parse_response(response, split_response) + response.map do |object| + if split_response + build_translation(object) + else + get_field_value(object) + end + end + end + + def build_translation(objects) + objects.map { |object| get_field_value(object) }.join + end + + def get_field_value(object) + text = object.translations[0].text + notranslate?(text) ? nil : text + end + + def prepare_texts(texts) + texts.map { |text| text || PREVENTING_TRANSLATION_KEY } + #https://docs.microsoft.com/es-es/azure/cognitive-services/translator/prevent-translation + end + + def notranslate?(text) + text.downcase == PREVENTING_TRANSLATION_KEY + end + +end diff --git a/lib/sentences_parser.rb b/lib/sentences_parser.rb new file mode 100644 index 000000000..890a6eb57 --- /dev/null +++ b/lib/sentences_parser.rb @@ -0,0 +1,24 @@ +module SentencesParser + + def detect_split_position(text) + minimum_valid_index = text.size - MicrosoftTranslateClient::CHARACTERS_LIMIT_PER_REQUEST + valid_point = text[minimum_valid_index..text.size].index(".") + valid_whitespace = text[minimum_valid_index..text.size].index(" ") + + get_split_position(valid_point, valid_whitespace, minimum_valid_index) + end + + def get_split_position(valid_point, valid_whitespace, minimum_valid_index) + split_position = minimum_valid_index + if valid_point.present? || valid_whitespace.present? + valid_position = valid_point.present? ? valid_point : valid_whitespace + split_position = split_position + valid_position + end + split_position + end + + def characters_count(texts) + texts.map(&:size).reduce(:+) + end + +end diff --git a/spec/lib/microsoft_translate_client_spec.rb b/spec/lib/microsoft_translate_client_spec.rb new file mode 100644 index 000000000..e93203502 --- /dev/null +++ b/spec/lib/microsoft_translate_client_spec.rb @@ -0,0 +1,168 @@ +require "rails_helper" + +describe MicrosoftTranslateClient do + + let(:microsoft_client) { described_class.new } + + describe "#call" do + + context "when characters from request are less than the characters limit" do + it "response has the expected result" do + response = create_response("Nuevo título", "Nueva descripción") + + expect_any_instance_of(TranslatorText::Client).to receive(:translate).and_return(response) + + result = microsoft_client.call([ "New title", "New description"], :es) + + expect(result).to eq(["Nuevo título", "Nueva descripción"]) + end + + it "response nil has the expected result when request has nil value" do + response = create_response("Notranslate", "Nueva descripción") + + expect_any_instance_of(TranslatorText::Client).to receive(:translate).and_return(response) + + result = microsoft_client.call([nil, "New description"], :es) + + expect(result).to eq([nil, "Nueva descripción"]) + end + + end + + context "when characters from request are greater than characters limit" do + it "response has the expected result when the request has 2 texts, where both less than CHARACTERS_LIMIT_PER_REQUEST" do + stub_const("MicrosoftTranslateClient::CHARACTERS_LIMIT_PER_REQUEST", 20) + text_en = Faker::Lorem.characters(11) + another_text_en = Faker::Lorem.characters(11) + + translated_text_es = Faker::Lorem.characters(11) + another_translated_text_es = Faker::Lorem.characters(11) + response_text = create_response(translated_text_es) + response_another_text = create_response(another_translated_text_es) + + expect_any_instance_of(TranslatorText::Client).to receive(:translate).exactly(1) + .times + .and_return(response_text) + expect_any_instance_of(TranslatorText::Client).to receive(:translate).exactly(1) + .times + .and_return(response_another_text) + + result = microsoft_client.call([text_en, another_text_en], :es) + + expect(result).to eq([translated_text_es, another_translated_text_es]) + end + + it "response has the expected result when the request has 2 texts and both are greater than CHARACTERS_LIMIT_PER_REQUEST" do + stub_const("MicrosoftTranslateClient::CHARACTERS_LIMIT_PER_REQUEST", 20) + start_text_en = Faker::Lorem.characters(10) + " " + end_text_en = Faker::Lorem.characters(10) + text_en = start_text_en + end_text_en + + start_translated_text_es = Faker::Lorem.characters(10) + " " + end_translated_text_es = Faker::Lorem.characters(10) + translated_text_es = start_translated_text_es + end_translated_text_es + response_start_text = create_response(start_translated_text_es) + response_end_text = create_response(end_translated_text_es) + + expect_any_instance_of(TranslatorText::Client).to receive(:translate).with([start_text_en], to: :es) + .exactly(1) + .times + .and_return(response_start_text) + expect_any_instance_of(TranslatorText::Client).to receive(:translate).with([end_text_en], to: :es) + .exactly(1) + .times + .and_return(response_end_text) + + start_another_text_en = Faker::Lorem.characters(12) + "." + end_another_text_en = Faker::Lorem.characters(12) + another_text_en = start_another_text_en + end_another_text_en + + another_start_translated_text_es = Faker::Lorem.characters(12) + "." + another_end_translated_text_es = Faker::Lorem.characters(12) + another_translated_text_es = another_start_translated_text_es + another_end_translated_text_es + response_another_start_text = create_response(another_start_translated_text_es) + response_another_end_text = create_response(another_end_translated_text_es) + + expect_any_instance_of(TranslatorText::Client).to receive(:translate).with([start_another_text_en], to: :es) + .exactly(1) + .times + .and_return(response_another_start_text) + expect_any_instance_of(TranslatorText::Client).to receive(:translate).with([end_another_text_en], to: :es) + .exactly(1) + .times + .and_return(response_another_end_text) + + result = microsoft_client.call([text_en, another_text_en], :es) + + expect(result).to eq([translated_text_es, another_translated_text_es]) + end + + end + + end + + describe "#detect_split_position" do + + context "text has less characters than characters limit" do + it "does not split the text" do + stub_const("MicrosoftTranslateClient::CHARACTERS_LIMIT_PER_REQUEST", 20) + text_to_translate = Faker::Lorem.characters(10) + + result = microsoft_client.fragments_for(text_to_translate) + + expect(result).to eq [text_to_translate] + end + end + + context "text has more characters than characters limit" do + it "to split text by first valid dot when there is a dot for split" do + stub_const("MicrosoftTranslateClient::CHARACTERS_LIMIT_PER_REQUEST", 20) + start_text = Faker::Lorem.characters(10) + "." + end_text = Faker::Lorem.characters(10) + text_to_translate = start_text + end_text + + result = microsoft_client.fragments_for(text_to_translate) + + expect(result).to eq([start_text, end_text]) + end + + it "to split text by first valid space when there is not a dot for split but there is a space" do + stub_const("MicrosoftTranslateClient::CHARACTERS_LIMIT_PER_REQUEST", 20) + start_text = Faker::Lorem.characters(10) + " " + end_text = Faker::Lorem.characters(10) + text_to_translate = start_text + end_text + + result = microsoft_client.fragments_for(text_to_translate) + + expect(result).to eq([start_text, end_text]) + end + + it "to split text in the middle of a word when there are not valid dots and spaces" do + stub_const("MicrosoftTranslateClient::CHARACTERS_LIMIT_PER_REQUEST", 40) + sub_part_text_1 = Faker::Lorem.characters(5) + " ." + sub_part_text_2 = Faker::Lorem.characters(5) + sub_part_text_3 = Faker::Lorem.characters(9) + sub_part_text_4 = Faker::Lorem.characters(30) + text_to_translate = sub_part_text_1 + sub_part_text_2 + sub_part_text_3 + sub_part_text_4 + + result = microsoft_client.fragments_for(text_to_translate) + + expect(result).to eq([sub_part_text_1 + sub_part_text_2, sub_part_text_3 + sub_part_text_4]) + end + + end + end +end + +def create_response(*args) + # response = [#] detectedLanguage={"language"=>"en", "score"=>1.0}>, #] detectedLanguage={"language"=>"en", "score"=>1.0}>] + translations = Struct.new(:translations) + text = Struct.new(:text) + response = [] + + args.each do |text_to_response| + response << translations.new([text.new(text_to_response)]) + end + + response +end From 90df1faf076d4003ed879a7f01ef099c8b91d981 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 25 Jan 2019 14:15:31 +0100 Subject: [PATCH 021/183] Maganement of available locales in MicrosoftTranslateClient - Create remote_available_locales method to recover available locales from microsoft tanslate client. This method will be useful to display the translation button as long as the locale sent is valid. - Create parse_locale method: Need parse available locales in Consul to will be valid on Microsoft Translate Client --- lib/microsoft_translate_client.rb | 1 + lib/remote_available_locales.rb | 45 +++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 lib/remote_available_locales.rb diff --git a/lib/microsoft_translate_client.rb b/lib/microsoft_translate_client.rb index 23b595403..45c8845c8 100644 --- a/lib/microsoft_translate_client.rb +++ b/lib/microsoft_translate_client.rb @@ -1,5 +1,6 @@ require "translator-text" include SentencesParser +include RemoteAvailableLocales class MicrosoftTranslateClient CHARACTERS_LIMIT_PER_REQUEST = 5000 diff --git a/lib/remote_available_locales.rb b/lib/remote_available_locales.rb new file mode 100644 index 000000000..a7e66437a --- /dev/null +++ b/lib/remote_available_locales.rb @@ -0,0 +1,45 @@ +require "net/https" +require "uri" +require "cgi" +require "json" + +module RemoteAvailableLocales + + def load_remote_locales + remote_available_locales.map { |locale| locale.first } + end + + def parse_locale(locale) + case locale + when :"pt-BR" + :pt + when :"zh-CN" + :"zh-Hans" + when :"zh-TW" + :"zh-Hant" + else + locale + end + end + + private + + def remote_available_locales + host = "https://api.cognitive.microsofttranslator.com" + path = "/languages?api-version=3.0" + + uri = URI (host + path) + + request = Net::HTTP::Get.new(uri) + request["Ocp-Apim-Subscription-Key"] = Rails.application.secrets.microsoft_api_key + + response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == "https") do |http| + http.request (request) + end + + result = response.body.force_encoding("utf-8") + + JSON.parse(result)["translation"] + end + +end From b86579c40fd08dca07f46e121a781bac84b24bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Wed, 13 Feb 2019 17:51:19 +0100 Subject: [PATCH 022/183] Avoid crash when adding new translations Paranoia is activated on translation classes by reflection, this is making Rails to load translation classes before to execute migration that adds the new column. With this extra check Rails will not execute this code until translation table has this column created. --- app/models/concerns/globalizable.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/concerns/globalizable.rb b/app/models/concerns/globalizable.rb index 7c961061c..df054caaf 100644 --- a/app/models/concerns/globalizable.rb +++ b/app/models/concerns/globalizable.rb @@ -17,7 +17,7 @@ module Globalizable self.read_attribute(:description).try :html_safe end - if self.paranoid? + if self.paranoid? && translation_class.attribute_names.include?("hidden_at") translation_class.send :acts_as_paranoid, column: :hidden_at end end From 2964d91303e2d04bf8a5a3975508950a9979bc24 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 22 Mar 2019 15:15:40 +0100 Subject: [PATCH 023/183] Fix specs active_polls_spec.rb:10 --- spec/shared/features/translatable.rb | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/spec/shared/features/translatable.rb b/spec/shared/features/translatable.rb index 4f4458a78..05c914864 100644 --- a/spec/shared/features/translatable.rb +++ b/spec/shared/features/translatable.rb @@ -57,6 +57,9 @@ shared_examples "translatable" do |factory_name, path_name, input_fields, textar end scenario "should show first available fallback when current locale translation does not exist", :js do + if translatable_class.name == "ActivePoll" + skip("Skip because after updating it doesn't render the description") + end attributes = fields.product(%i[fr]).map do |field, locale| [:"#{field}_#{locale}", text_for(field, locale)] end.to_h @@ -72,6 +75,26 @@ shared_examples "translatable" do |factory_name, path_name, input_fields, textar expect(page).to have_content "en Français" end + scenario "should show first available fallback when current locale translation does not exist for active polls", :js do + if translatable_class.name != "ActivePoll" + skip("Skip because force visit polls_path after update") + end + attributes = fields.product(%i[fr]).map do |field, locale| + [:"#{field}_#{locale}", text_for(field, locale)] + end.to_h + translatable.update(attributes) + visit path + + select "English", from: :translation_locale + click_link "Remove language" + select "Español", from: :translation_locale + click_link "Remove language" + click_button update_button_text + visit polls_path + + expect(page).to have_content "en Français" + end + scenario "Add a translation", :js do visit path From 1687fb3a7be027d859081da78e3e4b49790ebc72 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 22 Mar 2019 16:00:07 +0100 Subject: [PATCH 024/183] Fix specs budget_phases_spec.rb:13 --- spec/shared/features/translatable.rb | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/spec/shared/features/translatable.rb b/spec/shared/features/translatable.rb index 05c914864..f27ffdc23 100644 --- a/spec/shared/features/translatable.rb +++ b/spec/shared/features/translatable.rb @@ -36,8 +36,8 @@ shared_examples "translatable" do |factory_name, path_name, input_fields, textar let(:translatable) do if factory_name == "budget_phase" budget = create(:budget) - budget.phases.first.update attributes - budget.phases.first + budget.phases.last.update attributes + budget.phases.last else create(factory_name, attributes) end @@ -57,7 +57,7 @@ shared_examples "translatable" do |factory_name, path_name, input_fields, textar end scenario "should show first available fallback when current locale translation does not exist", :js do - if translatable_class.name == "ActivePoll" + if translatable_class.name == "ActivePoll" || translatable_class.name == "Budget::Phase" skip("Skip because after updating it doesn't render the description") end attributes = fields.product(%i[fr]).map do |field, locale| @@ -75,6 +75,26 @@ shared_examples "translatable" do |factory_name, path_name, input_fields, textar expect(page).to have_content "en Français" end + scenario "should show first available fallback when current locale translation does not exist", :js do + if translatable_class.name != "Budget::Phase" + skip("Skip because force visit budgets_path after update") + end + attributes = fields.product(%i[fr]).map do |field, locale| + [:"#{field}_#{locale}", text_for(field, locale)] + end.to_h + translatable.update(attributes) + visit path + + select "English", from: :translation_locale + click_link "Remove language" + select "Español", from: :translation_locale + click_link "Remove language" + click_button update_button_text + visit budgets_path + + expect(page).to have_content "en Français" + end + scenario "should show first available fallback when current locale translation does not exist for active polls", :js do if translatable_class.name != "ActivePoll" skip("Skip because force visit polls_path after update") From 98074a9a737fee8583b5b62de648be0b71db5a3d Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 22 Mar 2019 16:13:57 +0100 Subject: [PATCH 025/183] Refactor specs from shared translatable --- spec/shared/features/translatable.rb | 98 +++++++++++++++------------- 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/spec/shared/features/translatable.rb b/spec/shared/features/translatable.rb index f27ffdc23..e2aa5a8b8 100644 --- a/spec/shared/features/translatable.rb +++ b/spec/shared/features/translatable.rb @@ -56,63 +56,67 @@ shared_examples "translatable" do |factory_name, path_name, input_fields, textar end end - scenario "should show first available fallback when current locale translation does not exist", :js do - if translatable_class.name == "ActivePoll" || translatable_class.name == "Budget::Phase" - skip("Skip because after updating it doesn't render the description") + describe "Should show first available fallback when current locale translation does not exist" do + + scenario "For all translatable except ActivePoll and Budget::Phase", :js do + if translatable_class.name == "ActivePoll" || translatable_class.name == "Budget::Phase" + skip("Skip because after updating it doesn't render the description") + end + attributes = fields.product(%i[fr]).map do |field, locale| + [:"#{field}_#{locale}", text_for(field, locale)] + end.to_h + translatable.update(attributes) + visit path + + select "English", from: :translation_locale + click_link "Remove language" + select "Español", from: :translation_locale + click_link "Remove language" + click_button update_button_text + + expect(page).to have_content "en Français" end - attributes = fields.product(%i[fr]).map do |field, locale| - [:"#{field}_#{locale}", text_for(field, locale)] - end.to_h - translatable.update(attributes) - visit path - select "English", from: :translation_locale - click_link "Remove language" - select "Español", from: :translation_locale - click_link "Remove language" - click_button update_button_text + scenario "For Budget::Phase", :js do + if translatable_class.name != "Budget::Phase" + skip("Skip because force visit budgets_path after update") + end + attributes = fields.product(%i[fr]).map do |field, locale| + [:"#{field}_#{locale}", text_for(field, locale)] + end.to_h + translatable.update(attributes) + visit path - expect(page).to have_content "en Français" - end + select "English", from: :translation_locale + click_link "Remove language" + select "Español", from: :translation_locale + click_link "Remove language" + click_button update_button_text + visit budgets_path - scenario "should show first available fallback when current locale translation does not exist", :js do - if translatable_class.name != "Budget::Phase" - skip("Skip because force visit budgets_path after update") + expect(page).to have_content "en Français" end - attributes = fields.product(%i[fr]).map do |field, locale| - [:"#{field}_#{locale}", text_for(field, locale)] - end.to_h - translatable.update(attributes) - visit path - select "English", from: :translation_locale - click_link "Remove language" - select "Español", from: :translation_locale - click_link "Remove language" - click_button update_button_text - visit budgets_path + scenario "For ActivePoll", :js do + if translatable_class.name != "ActivePoll" + skip("Skip because force visit polls_path after update") + end + attributes = fields.product(%i[fr]).map do |field, locale| + [:"#{field}_#{locale}", text_for(field, locale)] + end.to_h + translatable.update(attributes) + visit path - expect(page).to have_content "en Français" - end + select "English", from: :translation_locale + click_link "Remove language" + select "Español", from: :translation_locale + click_link "Remove language" + click_button update_button_text + visit polls_path - scenario "should show first available fallback when current locale translation does not exist for active polls", :js do - if translatable_class.name != "ActivePoll" - skip("Skip because force visit polls_path after update") + expect(page).to have_content "en Français" end - attributes = fields.product(%i[fr]).map do |field, locale| - [:"#{field}_#{locale}", text_for(field, locale)] - end.to_h - translatable.update(attributes) - visit path - select "English", from: :translation_locale - click_link "Remove language" - select "Español", from: :translation_locale - click_link "Remove language" - click_button update_button_text - visit polls_path - - expect(page).to have_content "en Français" end scenario "Add a translation", :js do From 0ffb52257f823b967cc5b3676ad4b5a3d68fe159 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 22 Mar 2019 19:18:37 +0100 Subject: [PATCH 026/183] Fix specs budget_investments_spec.b:99 --- app/models/budget/investment.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index 9da713c84..1ef54653e 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -194,7 +194,7 @@ class Budget def searchable_values { title => "A", author.username => "B", - heading.try(:name) => "B", + heading.name => "B", tag_list.join(" ") => "B", description => "C" } From 96d1666899ce4faa70f817faceedd7f89f36bae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Tue, 8 Jan 2019 15:15:36 +0100 Subject: [PATCH 027/183] Initialize graphql after application initialization Proposal, Debate and Comment "globalize_accessors" class method were loaded before application available locales initialization because of graphql initializer. This will cause unexpected translation errors at any translatable classes declared at graphql api definition (api.yml). Doing GraphQL initialization after application initialization should solve this issue. --- config/initializers/graphql.rb | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 config/initializers/graphql.rb diff --git a/config/initializers/graphql.rb b/config/initializers/graphql.rb deleted file mode 100644 index 15a5a95cf..000000000 --- a/config/initializers/graphql.rb +++ /dev/null @@ -1,4 +0,0 @@ -if ActiveRecord::Base.connection.tables.any? - api_config = YAML.load_file("./config/api.yml") - API_TYPE_DEFINITIONS = GraphQL::ApiTypesCreator::parse_api_config_file(api_config) -end From 2b4fce1598a0f2260b4f68f72953dde711ef353f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 21 Feb 2019 16:55:12 +0100 Subject: [PATCH 028/183] Remove deprecated attributes from Banner Some attributes from Banner are translatable and we no longer need to have them at database table. This will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ...19_remove_deprecated_translatable_fields_from_banners.rb | 6 ++++++ db/schema.rb | 6 ++---- 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20190221154819_remove_deprecated_translatable_fields_from_banners.rb diff --git a/db/migrate/20190221154819_remove_deprecated_translatable_fields_from_banners.rb b/db/migrate/20190221154819_remove_deprecated_translatable_fields_from_banners.rb new file mode 100644 index 000000000..b69b882bd --- /dev/null +++ b/db/migrate/20190221154819_remove_deprecated_translatable_fields_from_banners.rb @@ -0,0 +1,6 @@ +class RemoveDeprecatedTranslatableFieldsFromBanners < ActiveRecord::Migration[4.2] + def change + remove_column :banners, :title, :string + remove_column :banners, :description, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 438c9b53e..0138b4fdd 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -105,14 +105,12 @@ ActiveRecord::Schema.define(version: 20190607160900) do end create_table "banners", force: :cascade do |t| - t.string "title", limit: 80 - t.string "description" t.string "target_url" t.date "post_started_at" t.date "post_ended_at" t.datetime "hidden_at" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.text "background_color" t.text "font_color" t.index ["hidden_at"], name: "index_banners_on_hidden_at", using: :btree From 2575f863bc9174025a006889b7daaad695b40a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 21 Feb 2019 17:28:09 +0100 Subject: [PATCH 029/183] Remove deprecated attributes from Poll Some fields from Poll are translatable and we no longer need them. This commit will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ...450_remove_deprecated_translatable_fields_from_polls.rb | 7 +++++++ db/schema.rb | 3 --- 2 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20190221162450_remove_deprecated_translatable_fields_from_polls.rb diff --git a/db/migrate/20190221162450_remove_deprecated_translatable_fields_from_polls.rb b/db/migrate/20190221162450_remove_deprecated_translatable_fields_from_polls.rb new file mode 100644 index 000000000..c26296066 --- /dev/null +++ b/db/migrate/20190221162450_remove_deprecated_translatable_fields_from_polls.rb @@ -0,0 +1,7 @@ +class RemoveDeprecatedTranslatableFieldsFromPolls < ActiveRecord::Migration[4.2] + def change + remove_column :polls, :name, :string + remove_column :polls, :summary, :text + remove_column :polls, :description, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 0138b4fdd..70a8ec763 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1256,13 +1256,10 @@ ActiveRecord::Schema.define(version: 20190607160900) do end create_table "polls", force: :cascade do |t| - t.string "name" t.datetime "starts_at" t.datetime "ends_at" t.boolean "published", default: false t.boolean "geozone_restricted", default: false - t.text "summary" - t.text "description" t.integer "comments_count", default: 0 t.integer "author_id" t.datetime "hidden_at" From 34069836728ebaecb977964d1ee2828afde9c1c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 21 Feb 2019 17:30:56 +0100 Subject: [PATCH 030/183] Remove deprecated attributes from Poll:Question Some fields from Poll::Question are translatable and we no longer need them. This commit will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ...ove_deprecated_translatable_fields_from_poll_questions.rb | 5 +++++ db/schema.rb | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20190221162858_remove_deprecated_translatable_fields_from_poll_questions.rb diff --git a/db/migrate/20190221162858_remove_deprecated_translatable_fields_from_poll_questions.rb b/db/migrate/20190221162858_remove_deprecated_translatable_fields_from_poll_questions.rb new file mode 100644 index 000000000..41823395a --- /dev/null +++ b/db/migrate/20190221162858_remove_deprecated_translatable_fields_from_poll_questions.rb @@ -0,0 +1,5 @@ +class RemoveDeprecatedTranslatableFieldsFromPollQuestions < ActiveRecord::Migration[4.2] + def change + remove_column :poll_questions, :title, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 70a8ec763..883952cad 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1172,7 +1172,6 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.integer "poll_id" t.integer "author_id" t.string "author_visible_name" - t.string "title" t.integer "comments_count" t.datetime "hidden_at" t.datetime "created_at" From 2b23e9603d2f3856ce2ccb1753c97b9c7e5a3d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 21 Feb 2019 17:33:38 +0100 Subject: [PATCH 031/183] Remove deprecated attributes from Poll::Question::Answer Some fields from Poll::Question::Answer are translatable and we no longer need them. This commit will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ...ecated_translatable_fields_from_poll_question_answers.rb | 6 ++++++ db/schema.rb | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20190221163117_remove_deprecated_translatable_fields_from_poll_question_answers.rb diff --git a/db/migrate/20190221163117_remove_deprecated_translatable_fields_from_poll_question_answers.rb b/db/migrate/20190221163117_remove_deprecated_translatable_fields_from_poll_question_answers.rb new file mode 100644 index 000000000..f62c4b7dc --- /dev/null +++ b/db/migrate/20190221163117_remove_deprecated_translatable_fields_from_poll_question_answers.rb @@ -0,0 +1,6 @@ +class RemoveDeprecatedTranslatableFieldsFromPollQuestionAnswers < ActiveRecord::Migration[4.2] + def change + remove_column :poll_question_answers, :title, :string + remove_column :poll_question_answers, :description, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 883952cad..1c8aa841b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1146,8 +1146,6 @@ ActiveRecord::Schema.define(version: 20190607160900) do end create_table "poll_question_answers", force: :cascade do |t| - t.string "title" - t.text "description" t.integer "question_id" t.integer "given_order", default: 1 t.boolean "most_voted", default: false From 43d7d24e3ca2107c85c0f2c5330b7831af24ddd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 21 Feb 2019 17:40:08 +0100 Subject: [PATCH 032/183] Remove deprecated attributes from AdminNotification Some fields from AdminNotification are translatable and we no longer need them. This commit will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ...precated_translatable_fields_from_admin_notifications.rb | 6 ++++++ db/schema.rb | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20190221163818_remove_deprecated_translatable_fields_from_admin_notifications.rb diff --git a/db/migrate/20190221163818_remove_deprecated_translatable_fields_from_admin_notifications.rb b/db/migrate/20190221163818_remove_deprecated_translatable_fields_from_admin_notifications.rb new file mode 100644 index 000000000..ff7d9230d --- /dev/null +++ b/db/migrate/20190221163818_remove_deprecated_translatable_fields_from_admin_notifications.rb @@ -0,0 +1,6 @@ +class RemoveDeprecatedTranslatableFieldsFromAdminNotifications < ActiveRecord::Migration[4.2] + def change + remove_column :admin_notifications, :title, :string + remove_column :admin_notifications, :body, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 1c8aa841b..bbde1f21d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -55,8 +55,6 @@ ActiveRecord::Schema.define(version: 20190607160900) do end create_table "admin_notifications", force: :cascade do |t| - t.string "title" - t.text "body" t.string "link" t.string "segment_recipient" t.integer "recipients_count" From 400a5719dff51f6334e58f7a0368985414fe0728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 21 Feb 2019 17:42:58 +0100 Subject: [PATCH 033/183] Remove deprecated attributes from Milestone Some fields from Milestone are translatable and we no longer need them. This commit will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ...remove_deprecated_translatable_fields_from_milestones.rb | 6 ++++++ db/schema.rb | 6 ++---- 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20190221164056_remove_deprecated_translatable_fields_from_milestones.rb diff --git a/db/migrate/20190221164056_remove_deprecated_translatable_fields_from_milestones.rb b/db/migrate/20190221164056_remove_deprecated_translatable_fields_from_milestones.rb new file mode 100644 index 000000000..f613d080f --- /dev/null +++ b/db/migrate/20190221164056_remove_deprecated_translatable_fields_from_milestones.rb @@ -0,0 +1,6 @@ +class RemoveDeprecatedTranslatableFieldsFromMilestones < ActiveRecord::Migration[4.2] + def change + remove_column :milestones, :title, :string + remove_column :milestones, :description, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index bbde1f21d..921db1fc0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -985,12 +985,10 @@ ActiveRecord::Schema.define(version: 20190607160900) do create_table "milestones", force: :cascade do |t| t.string "milestoneable_type" t.integer "milestoneable_id" - t.string "title", limit: 80 - t.text "description" t.datetime "publication_date" t.integer "status_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["status_id"], name: "index_milestones_on_status_id", using: :btree end From e28a1a4a8ebf8d764a5e4ebd23d296e39289569a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 21 Feb 2019 17:48:45 +0100 Subject: [PATCH 034/183] Remove deprecated attributes from Legislation::Draft::Version Some fields from LegislationDraftVersion are translatable and we no longer need them. This commit will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ...ranslatable_fields_from_legislation_draft_versions.rb | 9 +++++++++ db/schema.rb | 5 ----- 2 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 db/migrate/20190221164559_remove_deprecated_translatable_fields_from_legislation_draft_versions.rb diff --git a/db/migrate/20190221164559_remove_deprecated_translatable_fields_from_legislation_draft_versions.rb b/db/migrate/20190221164559_remove_deprecated_translatable_fields_from_legislation_draft_versions.rb new file mode 100644 index 000000000..7a9fe3611 --- /dev/null +++ b/db/migrate/20190221164559_remove_deprecated_translatable_fields_from_legislation_draft_versions.rb @@ -0,0 +1,9 @@ +class RemoveDeprecatedTranslatableFieldsFromLegislationDraftVersions < ActiveRecord::Migration[4.2] + def change + remove_column :legislation_draft_versions, :title, :string + remove_column :legislation_draft_versions, :changelog, :text + remove_column :legislation_draft_versions, :body, :text + remove_column :legislation_draft_versions, :body_html, :text + remove_column :legislation_draft_versions, :toc_html, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 921db1fc0..32decd5e7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -722,16 +722,11 @@ ActiveRecord::Schema.define(version: 20190607160900) do create_table "legislation_draft_versions", force: :cascade do |t| t.integer "legislation_process_id" - t.string "title" - t.text "changelog" t.string "status", default: "draft" t.boolean "final_version", default: false - t.text "body" t.datetime "hidden_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.text "body_html" - t.text "toc_html" t.index ["hidden_at"], name: "index_legislation_draft_versions_on_hidden_at", using: :btree t.index ["legislation_process_id"], name: "index_legislation_draft_versions_on_legislation_process_id", using: :btree t.index ["status"], name: "index_legislation_draft_versions_on_status", using: :btree From 957959e11d215db0df80cfe7ff723a3d80160442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 21 Feb 2019 17:53:06 +0100 Subject: [PATCH 035/183] Remove deprecated attributes from Legislation::Process Some fields from Legislation::Process are translatable and we no longer need them. This commit will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ...ated_translatable_fields_from_legislation_processes.rb | 8 ++++++++ db/schema.rb | 4 ---- 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20190221164928_remove_deprecated_translatable_fields_from_legislation_processes.rb diff --git a/db/migrate/20190221164928_remove_deprecated_translatable_fields_from_legislation_processes.rb b/db/migrate/20190221164928_remove_deprecated_translatable_fields_from_legislation_processes.rb new file mode 100644 index 000000000..91452c788 --- /dev/null +++ b/db/migrate/20190221164928_remove_deprecated_translatable_fields_from_legislation_processes.rb @@ -0,0 +1,8 @@ +class RemoveDeprecatedTranslatableFieldsFromLegislationProcesses < ActiveRecord::Migration[4.2] + def change + remove_column :legislation_processes, :title, :string + remove_column :legislation_processes, :summary, :text + remove_column :legislation_processes, :description, :text + remove_column :legislation_processes, :additional_info, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 32decd5e7..353a522b2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -788,9 +788,6 @@ ActiveRecord::Schema.define(version: 20190607160900) do end create_table "legislation_processes", force: :cascade do |t| - t.string "title" - t.text "description" - t.text "additional_info" t.date "start_date" t.date "end_date" t.date "debate_start_date" @@ -802,7 +799,6 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.datetime "hidden_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.text "summary" t.boolean "debate_phase_enabled", default: false t.boolean "allegations_phase_enabled", default: false t.boolean "draft_publication_enabled", default: false From 8b33a48e0eadd5ff8cf8a76723670d75f2b45e15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 21 Feb 2019 17:55:09 +0100 Subject: [PATCH 036/183] Remove deprecated attributes from Legislation::Question Some fields from Legislation::Question are translatable and we no longer need them. This commit will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ...recated_translatable_fields_from_legislation_questions.rb | 5 +++++ db/schema.rb | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20190221165347_remove_deprecated_translatable_fields_from_legislation_questions.rb diff --git a/db/migrate/20190221165347_remove_deprecated_translatable_fields_from_legislation_questions.rb b/db/migrate/20190221165347_remove_deprecated_translatable_fields_from_legislation_questions.rb new file mode 100644 index 000000000..a183c40c7 --- /dev/null +++ b/db/migrate/20190221165347_remove_deprecated_translatable_fields_from_legislation_questions.rb @@ -0,0 +1,5 @@ +class RemoveDeprecatedTranslatableFieldsFromLegislationQuestions < ActiveRecord::Migration[4.2] + def change + remove_column :legislation_questions, :title, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 353a522b2..8e19a9fe7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -899,7 +899,6 @@ ActiveRecord::Schema.define(version: 20190607160900) do create_table "legislation_questions", force: :cascade do |t| t.integer "legislation_process_id" - t.text "title" t.integer "answers_count", default: 0 t.datetime "hidden_at" t.datetime "created_at", null: false From 9f1ca4941f7c3e4d46a0f0203ea80f43132c8bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 21 Feb 2019 18:16:49 +0100 Subject: [PATCH 037/183] Remove deprecated attibutes from Legislation::Question::Option Some fields from Legislation::Question::Option are translatable and we no longer need them. This commit will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ..._translatable_fields_from_legislation_question_options.rb | 5 +++++ db/schema.rb | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20190221171155_remove_deprecated_translatable_fields_from_legislation_question_options.rb diff --git a/db/migrate/20190221171155_remove_deprecated_translatable_fields_from_legislation_question_options.rb b/db/migrate/20190221171155_remove_deprecated_translatable_fields_from_legislation_question_options.rb new file mode 100644 index 000000000..efffef2be --- /dev/null +++ b/db/migrate/20190221171155_remove_deprecated_translatable_fields_from_legislation_question_options.rb @@ -0,0 +1,5 @@ +class RemoveDeprecatedTranslatableFieldsFromLegislationQuestionOptions < ActiveRecord::Migration[4.2] + def change + remove_column :legislation_question_options, :value, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 8e19a9fe7..21ba5dbb8 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -876,7 +876,6 @@ ActiveRecord::Schema.define(version: 20190607160900) do create_table "legislation_question_options", force: :cascade do |t| t.integer "legislation_question_id" - t.string "value" t.integer "answers_count", default: 0 t.datetime "hidden_at" t.datetime "created_at", null: false From 6e49a09a21d88cd8fa96d048145da96ed73b4db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 21 Feb 2019 18:21:03 +0100 Subject: [PATCH 038/183] Remove deprecated attributes from SiteCustomization::Page Some fields from SiteCustomization::page are translatable and we no longer need them. This commit will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ...ed_translatable_fields_from_site_customization_pages.rb | 7 +++++++ db/schema.rb | 3 --- 2 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20190221171859_remove_deprecated_translatable_fields_from_site_customization_pages.rb diff --git a/db/migrate/20190221171859_remove_deprecated_translatable_fields_from_site_customization_pages.rb b/db/migrate/20190221171859_remove_deprecated_translatable_fields_from_site_customization_pages.rb new file mode 100644 index 000000000..0d5f1e689 --- /dev/null +++ b/db/migrate/20190221171859_remove_deprecated_translatable_fields_from_site_customization_pages.rb @@ -0,0 +1,7 @@ +class RemoveDeprecatedTranslatableFieldsFromSiteCustomizationPages < ActiveRecord::Migration[4.2] + def change + remove_column :site_customization_pages, :title, :string + remove_column :site_customization_pages, :subtitle, :string + remove_column :site_customization_pages, :content, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 21ba5dbb8..6544fb28e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1425,9 +1425,6 @@ ActiveRecord::Schema.define(version: 20190607160900) do create_table "site_customization_pages", force: :cascade do |t| t.string "slug", null: false - t.string "title" - t.string "subtitle" - t.text "content" t.boolean "more_info_flag" t.boolean "print_content_flag" t.string "status", default: "draft" From e847aa22f7b04e5bb9088606bc37c130ccf1d960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 21 Feb 2019 18:23:49 +0100 Subject: [PATCH 039/183] Remove deprecated attributes from Widget::Card Some fields from Widget::Card are translatable and we no longer need them. This commit will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ...ve_deprecated_translatable_fields_from_widget_cards.rb | 8 ++++++++ db/schema.rb | 4 ---- 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20190221172209_remove_deprecated_translatable_fields_from_widget_cards.rb diff --git a/db/migrate/20190221172209_remove_deprecated_translatable_fields_from_widget_cards.rb b/db/migrate/20190221172209_remove_deprecated_translatable_fields_from_widget_cards.rb new file mode 100644 index 000000000..c857aec7e --- /dev/null +++ b/db/migrate/20190221172209_remove_deprecated_translatable_fields_from_widget_cards.rb @@ -0,0 +1,8 @@ +class RemoveDeprecatedTranslatableFieldsFromWidgetCards < ActiveRecord::Migration[4.2] + def change + remove_column :widget_cards, :label, :string + remove_column :widget_cards, :title, :string + remove_column :widget_cards, :description, :text + remove_column :widget_cards, :link_text, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 6544fb28e..dc7239e19 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1677,11 +1677,7 @@ ActiveRecord::Schema.define(version: 20190607160900) do end create_table "widget_cards", force: :cascade do |t| - t.string "title" - t.text "description" - t.string "link_text" t.string "link_url" - t.string "label" t.boolean "header", default: false t.datetime "created_at", null: false t.datetime "updated_at", null: false From ce7be5f2d6943f19083c96a3273f01c21cd102a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 21 Feb 2019 20:02:38 +0100 Subject: [PATCH 040/183] Change the way to retrieve notifiable body Using 'try' method to get notifiable is not working with translations anymore. It was returning 'nil' always even when body translation is populated. --- app/models/concerns/notifiable.rb | 4 ++++ app/models/notification.rb | 5 +++-- app/views/notifications/_notification.html.erb | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/models/concerns/notifiable.rb b/app/models/concerns/notifiable.rb index b10c57f70..aa7d4d3bc 100644 --- a/app/models/concerns/notifiable.rb +++ b/app/models/concerns/notifiable.rb @@ -12,6 +12,10 @@ module Notifiable end end + def notifiable_body + body if attribute_names.include?("body") + end + def notifiable_available? case self.class.name when "ProposalNotification" diff --git a/app/models/notification.rb b/app/models/notification.rb index 738e5ab5f..e5a8e2b95 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -11,8 +11,9 @@ class Notification < ApplicationRecord scope :recent, -> { order(id: :desc) } scope :for_render, -> { includes(:notifiable) } - delegate :notifiable_title, :notifiable_available?, :check_availability, - :linkable_resource, to: :notifiable, allow_nil: true + delegate :notifiable_title, :notifiable_body, :notifiable_available?, + :check_availability, :linkable_resource, + to: :notifiable, allow_nil: true def mark_as_read update(read_at: Time.current) diff --git a/app/views/notifications/_notification.html.erb b/app/views/notifications/_notification.html.erb index cdbad536f..ca14385da 100644 --- a/app/views/notifications/_notification.html.erb +++ b/app/views/notifications/_notification.html.erb @@ -3,7 +3,7 @@ <% locals = { notification: notification, timestamp: notification.timestamp, title: notification.notifiable_title, - body: notification.notifiable.try(:body) } %> + body: notification.notifiable_body } %> <% link_text = render partial: "/notifications/notification_body", locals: locals %> <%= link_to_if notification.link.present?, link_text, notification.link %> <% else %> From b503eeac66f393ce4cd01bda2dc2cf2ca789e076 Mon Sep 17 00:00:00 2001 From: taitus Date: Mon, 25 Mar 2019 19:39:34 +0100 Subject: [PATCH 041/183] Fix spec models/widget/feed_spec.rb:61 as branch master. --- app/models/widget/feed.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/widget/feed.rb b/app/models/widget/feed.rb index 2ddd00d62..553d35db6 100644 --- a/app/models/widget/feed.rb +++ b/app/models/widget/feed.rb @@ -34,4 +34,4 @@ class Widget::Feed < ApplicationRecord Legislation::Process.open.published.order("created_at DESC").limit(limit) end -end \ No newline at end of file +end From b5e17eac07574049c7a6b84122cca7491092ce2f Mon Sep 17 00:00:00 2001 From: taitus Date: Mon, 25 Mar 2019 19:49:47 +0100 Subject: [PATCH 042/183] Remove deprecated attributes from Budgets Some fields from Budget are translatable and we no longer need them. This commit will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ...500_remove_deprecated_translatable_fields_from_budgets.rb | 5 +++++ db/schema.rb | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20190325184500_remove_deprecated_translatable_fields_from_budgets.rb diff --git a/db/migrate/20190325184500_remove_deprecated_translatable_fields_from_budgets.rb b/db/migrate/20190325184500_remove_deprecated_translatable_fields_from_budgets.rb new file mode 100644 index 000000000..790d668fc --- /dev/null +++ b/db/migrate/20190325184500_remove_deprecated_translatable_fields_from_budgets.rb @@ -0,0 +1,5 @@ +class RemoveDeprecatedTranslatableFieldsFromBudgets < ActiveRecord::Migration[4.2] + def change + remove_column :budgets, :name, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index dc7239e19..7a85b754b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -379,7 +379,6 @@ ActiveRecord::Schema.define(version: 20190607160900) do end create_table "budgets", force: :cascade do |t| - t.string "name", limit: 80 t.string "currency_symbol", limit: 10 t.string "phase", limit: 40, default: "accepting" t.datetime "created_at", null: false From 952f03bb5818d55a1cd374128445fa0807d3d128 Mon Sep 17 00:00:00 2001 From: taitus Date: Mon, 25 Mar 2019 19:53:50 +0100 Subject: [PATCH 043/183] Remove deprecated attributes from Budget::Group Some fields from Budget::Group are translatable and we no longer need them. This commit will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ...move_deprecated_translatable_fields_from_budget_groups.rb | 5 +++++ db/schema.rb | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20190325185046_remove_deprecated_translatable_fields_from_budget_groups.rb diff --git a/db/migrate/20190325185046_remove_deprecated_translatable_fields_from_budget_groups.rb b/db/migrate/20190325185046_remove_deprecated_translatable_fields_from_budget_groups.rb new file mode 100644 index 000000000..1fc61c89a --- /dev/null +++ b/db/migrate/20190325185046_remove_deprecated_translatable_fields_from_budget_groups.rb @@ -0,0 +1,5 @@ +class RemoveDeprecatedTranslatableFieldsFromBudgetGroups < ActiveRecord::Migration[4.2] + def change + remove_column :budget_groups, :name, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 7a85b754b..2c549445e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -167,9 +167,8 @@ ActiveRecord::Schema.define(version: 20190607160900) do create_table "budget_groups", force: :cascade do |t| t.integer "budget_id" - t.string "name", limit: 50 t.string "slug" - t.integer "max_votable_headings", default: 1 + t.integer "max_votable_headings", default: 1 t.index ["budget_id"], name: "index_budget_groups_on_budget_id", using: :btree end From 3b81bf67d1c2987bafd15755fe8246c2768ffb07 Mon Sep 17 00:00:00 2001 From: taitus Date: Mon, 25 Mar 2019 19:55:37 +0100 Subject: [PATCH 044/183] Remove deprecated attributes from Budget::Heading Some fields from Budget::Heading are translatable and we no longer need them. This commit will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ...ve_deprecated_translatable_fields_from_budget_headings.rb | 5 +++++ db/schema.rb | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20190325185405_remove_deprecated_translatable_fields_from_budget_headings.rb diff --git a/db/migrate/20190325185405_remove_deprecated_translatable_fields_from_budget_headings.rb b/db/migrate/20190325185405_remove_deprecated_translatable_fields_from_budget_headings.rb new file mode 100644 index 000000000..6f0f98ebd --- /dev/null +++ b/db/migrate/20190325185405_remove_deprecated_translatable_fields_from_budget_headings.rb @@ -0,0 +1,5 @@ +class RemoveDeprecatedTranslatableFieldsFromBudgetHeadings < ActiveRecord::Migration[4.2] + def change + remove_column :budget_headings, :name, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 2c549445e..b64d6f544 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -184,11 +184,10 @@ ActiveRecord::Schema.define(version: 20190607160900) do create_table "budget_headings", force: :cascade do |t| t.integer "group_id" - t.string "name", limit: 50 t.bigint "price" t.integer "population" t.string "slug" - t.boolean "allow_custom_content", default: false + t.boolean "allow_custom_content", default: false t.text "latitude" t.text "longitude" t.index ["group_id"], name: "index_budget_headings_on_group_id", using: :btree From 5343448c5a3d006e3b377f07cf97a54f6884c469 Mon Sep 17 00:00:00 2001 From: taitus Date: Mon, 25 Mar 2019 19:58:56 +0100 Subject: [PATCH 045/183] Remove deprecated attributes from Budget::Phase Some fields from Budget::Phase are translatable and we no longer need them. This commit will remove the annoying deprecation warning thrown by Globalize gem after gem version update. --- ...ove_deprecated_translatable_fields_from_budget_phases.rb | 6 ++++++ db/schema.rb | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20190325185550_remove_deprecated_translatable_fields_from_budget_phases.rb diff --git a/db/migrate/20190325185550_remove_deprecated_translatable_fields_from_budget_phases.rb b/db/migrate/20190325185550_remove_deprecated_translatable_fields_from_budget_phases.rb new file mode 100644 index 000000000..d293ff5e0 --- /dev/null +++ b/db/migrate/20190325185550_remove_deprecated_translatable_fields_from_budget_phases.rb @@ -0,0 +1,6 @@ +class RemoveDeprecatedTranslatableFieldsFromBudgetPhases < ActiveRecord::Migration[4.2] + def change + remove_column :budget_phases, :summary, :text + remove_column :budget_phases, :description, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index b64d6f544..36bfc4c7c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -297,8 +297,6 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.integer "budget_id" t.integer "next_phase_id" t.string "kind", null: false - t.text "summary" - t.text "description" t.datetime "starts_at" t.datetime "ends_at" t.boolean "enabled", default: true From 02be0c61f9c86e703890379e4dc05e8a9ca1d730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sat, 22 Dec 2018 23:35:32 +0100 Subject: [PATCH 046/183] Add proposal translations Adapt retire form to include needed translations and move validations from controller to model. Also change sanitizable concern to sanitize not marked for destruction translations. --- app/controllers/proposals_controller.rb | 11 +-- app/models/proposal.rb | 20 +++--- app/views/proposals/retire_form.html.erb | 17 +++-- ...181129115006_add_proposals_translations.rb | 17 +++++ db/schema.rb | 13 ++++ spec/factories/proposals.rb | 2 + spec/features/proposals_spec.rb | 12 ++-- spec/models/proposal_notification_spec.rb | 4 +- spec/models/proposal_spec.rb | 69 ++++++++++++++++++- spec/shared/models/notifiable.rb | 3 +- 10 files changed, 137 insertions(+), 31 deletions(-) create mode 100644 db/migrate/20181129115006_add_proposals_translations.rb diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index fc596c5f0..d2b876f06 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -62,7 +62,7 @@ class ProposalsController < ApplicationController end def retire - if valid_retired_params? && @proposal.update(retired_params.merge(retired_at: Time.current)) + if @proposal.update(retired_params.merge(retired_at: Time.current)) redirect_to proposal_path(@proposal), notice: t("proposals.notice.retired") else render action: :retire_form @@ -107,13 +107,8 @@ class ProposalsController < ApplicationController end def retired_params - params.require(:proposal).permit(:retired_reason, :retired_explanation) - end - - def valid_retired_params? - @proposal.errors.add(:retired_reason, I18n.t("errors.messages.blank")) if params[:proposal][:retired_reason].blank? - @proposal.errors.add(:retired_explanation, I18n.t("errors.messages.blank")) if params[:proposal][:retired_explanation].blank? - @proposal.errors.empty? + attributes = [:retired_reason] + params.require(:proposal).permit(attributes, translation_params(Proposal)) end def resource_model diff --git a/app/models/proposal.rb b/app/models/proposal.rb index e0f707918..4961b237d 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -28,6 +28,13 @@ class Proposal < ApplicationRecord RETIRE_OPTIONS = %w[duplicated started unfeasible done other] + translates :title, touch: true + translates :description, touch: true + translates :summary, touch: true + translates :retired_explanation, touch: true + include Globalizable + translation_class_delegate :retired_at + belongs_to :author, -> { with_hidden }, class_name: "User", foreign_key: "author_id" belongs_to :geozone has_many :comments, as: :commentable, dependent: :destroy @@ -39,18 +46,16 @@ class Proposal < ApplicationRecord extend DownloadSettings::ProposalCsv delegate :name, :email, to: :author, prefix: true - extend DownloadSettings::ProposalCsv - delegate :name, :email, to: :author, prefix: true + validates_translation :title, presence: true, length: { in: 4..Proposal.title_max_length } + validates_translation :description, length: { maximum: Proposal.description_max_length } + validates_translation :summary, presence: true + validates_translation :retired_explanation, presence: true, unless: -> { retired_at.blank? } - validates :title, presence: true - validates :summary, presence: true validates :author, presence: true validates :responsible_name, presence: true, unless: :skip_user_verification? - validates :title, length: { in: 4..Proposal.title_max_length } - validates :description, length: { maximum: Proposal.description_max_length } validates :responsible_name, length: { in: 6..Proposal.responsible_name_max_length }, unless: :skip_user_verification? - validates :retired_reason, inclusion: { in: RETIRE_OPTIONS, allow_nil: true } + validates :retired_reason, presence: true, inclusion: { in: RETIRE_OPTIONS }, unless: -> { retired_at.blank? } validates :terms_of_service, acceptance: { allow_nil: false }, on: :create @@ -264,5 +269,4 @@ class Proposal < ApplicationRecord self.responsible_name = author.document_number end end - end diff --git a/app/views/proposals/retire_form.html.erb b/app/views/proposals/retire_form.html.erb index 501a2ce22..704d2db3c 100644 --- a/app/views/proposals/retire_form.html.erb +++ b/app/views/proposals/retire_form.html.erb @@ -10,7 +10,9 @@ <%= t("proposals.retire_form.warning") %> - <%= form_for(@proposal, url: retire_proposal_path(@proposal)) do |f| %> + <%= render "admin/shared/globalize_locales", resource: @proposal %> + + <%= translatable_form_for(@proposal, url: retire_proposal_path(@proposal)) do |f| %> <%= render "shared/errors", resource: @proposal %>
@@ -20,11 +22,14 @@
-
- <%= f.label :retired_explanation, t("proposals.retire_form.retired_explanation_label") %> - <%= f.text_area :retired_explanation, rows: 4, maxlength: 500, label: false, - placeholder: t("proposals.retire_form.retired_explanation_placeholder") %> -
+ <%= f.translatable_fields do |translations_form| %> +
+ <%= translations_form.text_area :retired_explanation, + rows: 4, maxlength: 500, + label: t("proposals.retire_form.retired_explanation_label"), + placeholder: t("proposals.retire_form.retired_explanation_placeholder") %> +
+ <% end %>
diff --git a/db/migrate/20181129115006_add_proposals_translations.rb b/db/migrate/20181129115006_add_proposals_translations.rb new file mode 100644 index 000000000..8f05fbffd --- /dev/null +++ b/db/migrate/20181129115006_add_proposals_translations.rb @@ -0,0 +1,17 @@ +class AddProposalsTranslations < ActiveRecord::Migration[4.2] + def self.up + Proposal.create_translation_table!( + { + title: :string, + description: :text, + summary: :text, + retired_explanation: :text + }, + { migrate_data: true } + ) + end + + def self.down + Proposal.drop_translation_table! + end +end diff --git a/db/schema.rb b/db/schema.rb index 36bfc4c7c..c7c0e84d1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1285,6 +1285,19 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.datetime "confirmed_hide_at" end + create_table "proposal_translations", force: :cascade do |t| + t.integer "proposal_id", null: false + t.string "locale", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "title" + t.text "description" + t.text "summary" + t.text "retired_explanation" + t.index ["locale"], name: "index_proposal_translations_on_locale", using: :btree + t.index ["proposal_id"], name: "index_proposal_translations_on_proposal_id", using: :btree + end + create_table "proposals", force: :cascade do |t| t.string "title", limit: 80 t.text "description" diff --git a/spec/factories/proposals.rb b/spec/factories/proposals.rb index 92a925627..08598e977 100644 --- a/spec/factories/proposals.rb +++ b/spec/factories/proposals.rb @@ -62,6 +62,8 @@ FactoryBot.define do trait :retired do retired_at { Time.current } + retired_reason "unfeasible" + retired_explanation "Retired explanation" end trait :published do diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index 5c095d56a..f477ad7ba 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -505,7 +505,7 @@ describe "Proposals" do expect(page).to have_current_path(retire_form_proposal_path(proposal)) select "Duplicated", from: "proposal_retired_reason" - fill_in "proposal_retired_explanation", with: "There are three other better proposals with the same subject" + fill_in "Explanation", with: "There are three other better proposals with the same subject" click_button "Retire proposal" expect(page).to have_content "Proposal retired" @@ -518,7 +518,7 @@ describe "Proposals" do expect(page).to have_content "There are three other better proposals with the same subject" end - scenario "Fields are mandatory" do + scenario "Fields are mandatory", :js do proposal = create(:proposal) login_as(proposal.author) @@ -534,7 +534,7 @@ describe "Proposals" do Setting["feature.featured_proposals"] = true create_featured_proposals not_retired = create(:proposal) - retired = create(:proposal, retired_at: Time.current) + retired = create(:proposal, :retired) visit proposals_path @@ -548,7 +548,7 @@ describe "Proposals" do scenario "Index has a link to retired proposals list" do create_featured_proposals not_retired = create(:proposal) - retired = create(:proposal, retired_at: Time.current) + retired = create(:proposal, :retired) visit proposals_path @@ -568,8 +568,8 @@ describe "Proposals" do end scenario "Retired proposals index has links to filter by retired_reason" do - unfeasible = create(:proposal, retired_at: Time.current, retired_reason: "unfeasible") - duplicated = create(:proposal, retired_at: Time.current, retired_reason: "duplicated") + unfeasible = create(:proposal, :retired, retired_reason: "unfeasible") + duplicated = create(:proposal, :retired, retired_reason: "duplicated") visit proposals_path(retired: "all") diff --git a/spec/models/proposal_notification_spec.rb b/spec/models/proposal_notification_spec.rb index 40670b9d9..24c85c6fd 100644 --- a/spec/models/proposal_notification_spec.rb +++ b/spec/models/proposal_notification_spec.rb @@ -146,7 +146,9 @@ describe ProposalNotification do it "returns false if the resource is retired" do notification = create(:notification, notifiable: notifiable) - notifiable.proposal.update(retired_at: Time.current) + notifiable.proposal.update(retired_at: Time.current, + retired_explanation: "Unfeasible reason explanation", + retired_reason: "unfeasible") expect(notification.check_availability(proposal)).to be(false) end diff --git a/spec/models/proposal_spec.rb b/spec/models/proposal_spec.rb index 7d5d8067c..c589bfad5 100644 --- a/spec/models/proposal_spec.rb +++ b/spec/models/proposal_spec.rb @@ -8,6 +8,7 @@ describe Proposal do it_behaves_like "has_public_author" it_behaves_like "notifiable" it_behaves_like "map validations" + it_behaves_like "globalizable", :proposal end it "is valid" do @@ -44,10 +45,36 @@ describe Proposal do describe "#description" do it "is sanitized" do proposal.description = "" + proposal.valid? + expect(proposal.description).to eq("alert('danger');") end + it "is sanitized using globalize accessors" do + proposal.description_en = "" + + proposal.valid? + + expect(proposal.description_en).to eq("alert('danger');") + end + + it "is html_safe" do + proposal.description = "" + + proposal.valid? + + expect(proposal.description).to be_html_safe + end + + it "is html_safe using globalize accessors" do + proposal.description_en = "" + + proposal.valid? + + expect(proposal.description_en).to be_html_safe + end + it "is not valid when very long" do proposal.description = "a" * 6001 expect(proposal).not_to be_valid @@ -143,6 +170,46 @@ describe Proposal do Setting["proposal_code_prefix"] = "MAD" end + describe "#retired_explanation" do + it "is valid when retired timestamp is present and retired explanation is defined" do + proposal.retired_at = Time.current + proposal.retired_explanation = "Duplicated of ..." + proposal.retired_reason = "duplicated" + expect(proposal).to be_valid + end + + it "is not valid when retired_at is present and retired explanation is empty" do + proposal.retired_at = Time.current + proposal.retired_explanation = nil + proposal.retired_reason = "duplicated" + expect(proposal).not_to be_valid + end + end + + describe "#retired_reason" do + it "is valid when retired timestamp is present and retired reason is defined" do + proposal.retired_at = Time.current + proposal.retired_explanation = "Duplicated of ..." + proposal.retired_reason = "duplicated" + expect(proposal).to be_valid + end + + it "is not valid when retired timestamp is present but defined retired reason + is not included in retired reasons" do + proposal.retired_at = Time.current + proposal.retired_explanation = "Duplicated of ..." + proposal.retired_reason = "duplicate" + expect(proposal).not_to be_valid + end + + it "is not valid when retired_at is present and retired reason is empty" do + proposal.retired_at = Time.current + proposal.retired_explanation = "Duplicated of ..." + proposal.retired_reason = nil + expect(proposal).not_to be_valid + end + end + describe "#editable?" do let(:proposal) { create(:proposal) } @@ -820,7 +887,7 @@ describe Proposal do describe "retired" do let!(:proposal1) { create(:proposal) } - let!(:proposal2) { create(:proposal, retired_at: Time.current) } + let!(:proposal2) { create(:proposal, :retired) } it "retired? is true" do expect(proposal1.retired?).to eq false diff --git a/spec/shared/models/notifiable.rb b/spec/shared/models/notifiable.rb index 8d69e1c00..263d89117 100644 --- a/spec/shared/models/notifiable.rb +++ b/spec/shared/models/notifiable.rb @@ -78,7 +78,8 @@ shared_examples "notifiable" do notification = create(:notification, notifiable: notifiable) if notifiable.respond_to?(:retired_at) - notifiable.update(retired_at: Time.current) + notifiable.update(retired_at: Time.current, retired_reason: "unfeasible", + retired_explanation: "Unfeasibility explanation ...") expect(notification.check_availability(notifiable)).to be(false) end end From e6b3b85e48a557366020762a7ec5ad9b8687722a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Fri, 15 Feb 2019 16:33:13 +0100 Subject: [PATCH 047/183] Rename proposal deprecated fields After adding new translations to proposal we no longer need this attributes in proposals database table, but we keep them with a deprecated name until next release where we drop them completely. Also related column indexes where dropped. --- ...old_translatable_attibutes_in_proposals.rb | 11 ++++++++ db/schema.rb | 28 +++++++++---------- 2 files changed, 24 insertions(+), 15 deletions(-) create mode 100644 db/migrate/20190215152236_rename_old_translatable_attibutes_in_proposals.rb diff --git a/db/migrate/20190215152236_rename_old_translatable_attibutes_in_proposals.rb b/db/migrate/20190215152236_rename_old_translatable_attibutes_in_proposals.rb new file mode 100644 index 000000000..1485e5c69 --- /dev/null +++ b/db/migrate/20190215152236_rename_old_translatable_attibutes_in_proposals.rb @@ -0,0 +1,11 @@ +class RenameOldTranslatableAttibutesInProposals < ActiveRecord::Migration[4.2] + def change + remove_index :proposals, :title + remove_index :proposals, :summary + + rename_column :proposals, :title, :deprecated_title + rename_column :proposals, :description, :deprecated_description + rename_column :proposals, :summary, :deprecated_summary + rename_column :proposals, :retired_explanation, :deprecated_retired_explanation + end +end diff --git a/db/schema.rb b/db/schema.rb index c7c0e84d1..998d0bd86 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1299,30 +1299,30 @@ ActiveRecord::Schema.define(version: 20190607160900) do end create_table "proposals", force: :cascade do |t| - t.string "title", limit: 80 - t.text "description" + t.string "deprecated_title", limit: 80 + t.text "deprecated_description" t.integer "author_id" t.datetime "hidden_at" - t.integer "flags_count", default: 0 + t.integer "flags_count", default: 0 t.datetime "ignored_flag_at" - t.integer "cached_votes_up", default: 0 - t.integer "comments_count", default: 0 + t.integer "cached_votes_up", default: 0 + t.integer "comments_count", default: 0 t.datetime "confirmed_hide_at" - t.bigint "hot_score", default: 0 - t.integer "confidence_score", default: 0 - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "responsible_name", limit: 60 - t.text "summary" + t.bigint "hot_score", default: 0 + t.integer "confidence_score", default: 0 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "responsible_name", limit: 60 + t.text "deprecated_summary" t.string "video_url" t.tsvector "tsv" t.integer "geozone_id" t.datetime "retired_at" t.string "retired_reason" - t.text "retired_explanation" + t.text "deprecated_retired_explanation" t.integer "community_id" t.datetime "published_at" - t.boolean "selected", default: false + t.boolean "selected", default: false t.index ["author_id", "hidden_at"], name: "index_proposals_on_author_id_and_hidden_at", using: :btree t.index ["author_id"], name: "index_proposals_on_author_id", using: :btree t.index ["cached_votes_up"], name: "index_proposals_on_cached_votes_up", using: :btree @@ -1331,8 +1331,6 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.index ["geozone_id"], name: "index_proposals_on_geozone_id", using: :btree t.index ["hidden_at"], name: "index_proposals_on_hidden_at", using: :btree t.index ["hot_score"], name: "index_proposals_on_hot_score", using: :btree - t.index ["summary"], name: "index_proposals_on_summary", using: :btree - t.index ["title"], name: "index_proposals_on_title", using: :btree t.index ["tsv"], name: "index_proposals_on_tsv", using: :gin end From dd310f7507339fce6f0434737816c4812ed68f7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sun, 23 Dec 2018 01:08:13 +0100 Subject: [PATCH 048/183] Add sanitization shared spec to proposal --- spec/models/proposal_spec.rb | 39 +----------------------------------- 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/spec/models/proposal_spec.rb b/spec/models/proposal_spec.rb index c589bfad5..881063f26 100644 --- a/spec/models/proposal_spec.rb +++ b/spec/models/proposal_spec.rb @@ -9,6 +9,7 @@ describe Proposal do it_behaves_like "notifiable" it_behaves_like "map validations" it_behaves_like "globalizable", :proposal + it_behaves_like "sanitizable" end it "is valid" do @@ -43,38 +44,6 @@ describe Proposal do end describe "#description" do - it "is sanitized" do - proposal.description = "" - - proposal.valid? - - expect(proposal.description).to eq("alert('danger');") - end - - it "is sanitized using globalize accessors" do - proposal.description_en = "" - - proposal.valid? - - expect(proposal.description_en).to eq("alert('danger');") - end - - it "is html_safe" do - proposal.description = "" - - proposal.valid? - - expect(proposal.description).to be_html_safe - end - - it "is html_safe using globalize accessors" do - proposal.description_en = "" - - proposal.valid? - - expect(proposal.description_en).to be_html_safe - end - it "is not valid when very long" do proposal.description = "a" * 6001 expect(proposal).not_to be_valid @@ -140,12 +109,6 @@ describe Proposal do end describe "tag_list" do - it "sanitizes the tag list" do - proposal.tag_list = "user_id=1" - proposal.valid? - expect(proposal.tag_list).to eq(["user_id1"]) - end - it "is not valid with a tag list of more than 6 elements" do proposal.tag_list = ["Hacienda", "Economía", "Medio Ambiente", "Corrupción", "Fiestas populares", "Prensa", "Huelgas"] expect(proposal).not_to be_valid From 78c2f54c5d0081bbbcc4756af145a163902975b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Fri, 25 Jan 2019 11:26:39 +0100 Subject: [PATCH 049/183] Fix proposal specs After adding proposal translatable fields to forms, they will be generated with nested translations names and ids so we can no longer use standard id locator. Using input label text to fill in fields works with both types of forms. --- spec/features/management/proposals_spec.rb | 6 +- spec/features/proposals_spec.rb | 72 ++++++++++----------- spec/features/tags/proposals_spec.rb | 22 +++---- spec/shared/features/mappable.rb | 8 +-- spec/shared/features/nested_documentable.rb | 4 +- spec/shared/features/nested_imageable.rb | 4 +- spec/support/common_actions.rb | 6 +- 7 files changed, 61 insertions(+), 61 deletions(-) diff --git a/spec/features/management/proposals_spec.rb b/spec/features/management/proposals_spec.rb index 3f3ef2840..e2a808af2 100644 --- a/spec/features/management/proposals_spec.rb +++ b/spec/features/management/proposals_spec.rb @@ -21,9 +21,9 @@ describe "Proposals" do expect(page).to have_content user.document_number.to_s end - fill_in "proposal_title", with: "Help refugees" - fill_in "proposal_summary", with: "In summary, what we want is..." - fill_in "proposal_description", with: "This is very important because..." + fill_in "Proposal title", with: "Help refugees" + fill_in "Proposal summary", with: "In summary, what we want is..." + fill_in "Proposal text", with: "This is very important because..." fill_in "proposal_video_url", with: "https://www.youtube.com/watch?v=yRYFKcMa_Ek" check "proposal_terms_of_service" diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index f477ad7ba..d2ecf5776 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -238,9 +238,9 @@ describe "Proposals" do visit new_proposal_path - fill_in "proposal_title", with: "Help refugees" - fill_in "proposal_summary", with: "In summary, what we want is..." - fill_in "proposal_description", with: "This is very important because..." + fill_in "Proposal title", with: "Help refugees" + fill_in "Proposal summary", with: "In summary, what we want is..." + fill_in "Proposal text", with: "This is very important because..." fill_in "proposal_video_url", with: "https://www.youtube.com/watch?v=yPQfcG-eimk" fill_in "proposal_responsible_name", with: "Isabel Garcia" fill_in "proposal_tag_list", with: "Refugees, Solidarity" @@ -272,10 +272,10 @@ describe "Proposals" do login_as(author) visit new_proposal_path - fill_in "proposal_title", with: "I am a bot" + fill_in "Proposal title", with: "I am a bot" fill_in "proposal_subtitle", with: "This is the honeypot field" - fill_in "proposal_summary", with: "This is the summary" - fill_in "proposal_description", with: "This is the description" + fill_in "Proposal summary", with: "This is the summary" + fill_in "Proposal text", with: "This is the description" fill_in "proposal_responsible_name", with: "Some other robot" check "proposal_terms_of_service" @@ -293,9 +293,9 @@ describe "Proposals" do login_as(author) visit new_proposal_path - fill_in "proposal_title", with: "I am a bot" - fill_in "proposal_summary", with: "This is the summary" - fill_in "proposal_description", with: "This is the description" + fill_in "Proposal title", with: "I am a bot" + fill_in "Proposal summary", with: "This is the summary" + fill_in "Proposal text", with: "This is the description" fill_in "proposal_responsible_name", with: "Some other robot" check "proposal_terms_of_service" @@ -311,9 +311,9 @@ describe "Proposals" do login_as(author) visit new_proposal_path - fill_in "proposal_title", with: "Help refugees" - fill_in "proposal_summary", with: "In summary, what we want is..." - fill_in "proposal_description", with: "This is very important because..." + fill_in "Proposal title", with: "Help refugees" + fill_in "Proposal summary", with: "In summary, what we want is..." + fill_in "Proposal text", with: "This is very important because..." fill_in "proposal_responsible_name", with: "Isabel Garcia" fill_in "proposal_responsible_name", with: "Isabel Garcia" check "proposal_terms_of_service" @@ -334,9 +334,9 @@ describe "Proposals" do visit new_proposal_path expect(page).not_to have_selector("#proposal_responsible_name") - fill_in "proposal_title", with: "Help refugees" - fill_in "proposal_summary", with: "In summary, what we want is..." - fill_in "proposal_description", with: "This is very important because..." + fill_in "Proposal title", with: "Help refugees" + fill_in "Proposal summary", with: "In summary, what we want is..." + fill_in "Proposal text", with: "This is very important because..." check "proposal_terms_of_service" click_button "Create proposal" @@ -362,9 +362,9 @@ describe "Proposals" do login_as(author) visit new_proposal_path - fill_in "proposal_title", with: "Testing an attack" - fill_in "proposal_summary", with: "In summary, what we want is..." - fill_in "proposal_description", with: "

This is

" + fill_in "Proposal title", with: "Testing an attack" + fill_in "Proposal summary", with: "In summary, what we want is..." + fill_in "Proposal text", with: "

This is

" fill_in "proposal_responsible_name", with: "Isabel Garcia" check "proposal_terms_of_service" @@ -385,9 +385,9 @@ describe "Proposals" do login_as(author) visit new_proposal_path - fill_in "proposal_title", with: "Testing auto link" - fill_in "proposal_summary", with: "In summary, what we want is..." - fill_in "proposal_description", with: "

This is a link www.example.org

" + fill_in "Proposal title", with: "Testing auto link" + fill_in "Proposal summary", with: "In summary, what we want is..." + fill_in "Proposal text", with: "

This is a link www.example.org

" fill_in "proposal_responsible_name", with: "Isabel Garcia" check "proposal_terms_of_service" @@ -407,9 +407,9 @@ describe "Proposals" do login_as(author) visit new_proposal_path - fill_in "proposal_title", with: "Testing auto link" - fill_in "proposal_summary", with: "In summary, what we want is..." - fill_in "proposal_description", with: js_injection_string + fill_in "Proposal title", with: "Testing auto link" + fill_in "Proposal summary", with: "In summary, what we want is..." + fill_in "Proposal text", with: js_injection_string fill_in "proposal_responsible_name", with: "Isabel Garcia" check "proposal_terms_of_service" @@ -465,9 +465,9 @@ describe "Proposals" do visit new_proposal_path - fill_in "proposal_title", with: "Help refugees" - fill_in "proposal_summary", with: "In summary, what we want is..." - fill_in "proposal_description", with: "This is very important because..." + fill_in "Proposal title", with: "Help refugees" + fill_in "Proposal summary", with: "In summary, what we want is..." + fill_in "Proposal text", with: "This is very important because..." fill_in "proposal_video_url", with: "https://www.youtube.com/watch?v=yPQfcG-eimk" fill_in "proposal_responsible_name", with: "Isabel Garcia" check "proposal_terms_of_service" @@ -622,9 +622,9 @@ describe "Proposals" do visit edit_proposal_path(proposal) expect(page).to have_current_path(edit_proposal_path(proposal)) - fill_in "proposal_title", with: "End child poverty" - fill_in "proposal_summary", with: "Basically..." - fill_in "proposal_description", with: "Let's do something to end child poverty" + fill_in "Proposal title", with: "End child poverty" + fill_in "Proposal summary", with: "Basically..." + fill_in "Proposal text", with: "Let's do something to end child poverty" fill_in "proposal_responsible_name", with: "Isabel Garcia" click_button "Save changes" @@ -640,7 +640,7 @@ describe "Proposals" do login_as(proposal.author) visit edit_proposal_path(proposal) - fill_in "proposal_title", with: "" + fill_in "Proposal title", with: "" click_button "Save changes" expect(page).to have_content error_message @@ -1719,7 +1719,7 @@ describe "Proposals" do create(:proposal, title: "Seventh proposal, has search term") visit new_proposal_path - fill_in "proposal_title", with: "search" + fill_in "Proposal title", with: "search" check "proposal_terms_of_service" within("div#js-suggest") do @@ -1735,7 +1735,7 @@ describe "Proposals" do create(:proposal, title: "Second proposal").update_column(:confidence_score, 8) visit new_proposal_path - fill_in "proposal_title", with: "debate" + fill_in "Proposal title", with: "debate" check "proposal_terms_of_service" within("div#js-suggest") do @@ -1913,9 +1913,9 @@ describe "Successful proposals" do expect(current_path).to eq(new_proposal_path) - fill_in "proposal_title", with: "Help refugees" - fill_in "proposal_summary", with: "In summary what we want is..." - fill_in "proposal_description", with: "This is very important because..." + fill_in "Proposal title", with: "Help refugees" + fill_in "Proposal summary", with: "In summary what we want is..." + fill_in "Proposal text", with: "This is very important because..." fill_in "proposal_video_url", with: "https://www.youtube.com/watch?v=yPQfcG-eimk" fill_in "proposal_tag_list", with: "Refugees, Solidarity" check "proposal_terms_of_service" diff --git a/spec/features/tags/proposals_spec.rb b/spec/features/tags/proposals_spec.rb index d471b01e0..db0f02d83 100644 --- a/spec/features/tags/proposals_spec.rb +++ b/spec/features/tags/proposals_spec.rb @@ -69,9 +69,9 @@ describe "Tags" do login_as(user) visit new_proposal_path - fill_in "proposal_title", with: "Help refugees" - fill_in "proposal_summary", with: "In summary, what we want is..." - fill_in "proposal_description", with: "This is very important because..." + fill_in "Proposal title", with: "Help refugees" + fill_in "Proposal summary", with: "In summary, what we want is..." + fill_in "Proposal text", with: "This is very important because..." fill_in "proposal_responsible_name", with: "Isabel Garcia" fill_in "proposal_tag_list", with: "Economía, Hacienda" check "proposal_terms_of_service" @@ -95,9 +95,9 @@ describe "Tags" do visit new_proposal_path - fill_in "proposal_title", with: "Help refugees" - fill_in "proposal_summary", with: "In summary, what we want is..." - fill_in_ckeditor "proposal_description", with: "A description with enough characters" + fill_in "Proposal title", with: "Help refugees" + fill_in "Proposal summary", with: "In summary, what we want is..." + fill_in_ckeditor "Proposal text", with: "A description with enough characters" fill_in "proposal_video_url", with: "https://www.youtube.com/watch?v=Ae6gQmhaMn4" fill_in "proposal_responsible_name", with: "Isabel Garcia" check "proposal_terms_of_service" @@ -120,8 +120,8 @@ describe "Tags" do login_as(user) visit new_proposal_path - fill_in "proposal_title", with: "Title" - fill_in "proposal_description", with: "Description" + fill_in "Proposal title", with: "Title" + fill_in "Proposal text", with: "Description" check "proposal_terms_of_service" fill_in "proposal_tag_list", with: "Impuestos, Economía, Hacienda, Sanidad, Educación, Política, Igualdad" @@ -138,9 +138,9 @@ describe "Tags" do visit new_proposal_path - fill_in "proposal_title", with: "A test of dangerous strings" - fill_in "proposal_summary", with: "In summary, what we want is..." - fill_in "proposal_description", with: "A description suitable for this test" + fill_in "Proposal title", with: "A test of dangerous strings" + fill_in "Proposal summary", with: "In summary, what we want is..." + fill_in "Proposal text", with: "A description suitable for this test" fill_in "proposal_responsible_name", with: "Isabel Garcia" check "proposal_terms_of_service" diff --git a/spec/shared/features/mappable.rb b/spec/shared/features/mappable.rb index bce1071f3..eb426bc34 100644 --- a/spec/shared/features/mappable.rb +++ b/spec/shared/features/mappable.rb @@ -147,7 +147,7 @@ shared_examples "mappable" do |mappable_factory_name, do_login_for mappable.author visit send(mappable_edit_path, id: mappable.id) - fill_in "#{mappable_factory_name}_title", with: "New title" + fill_in "#{mappable_factory_name.camelize} title", with: "New title" click_on("Save changes") mappable.reload @@ -172,7 +172,7 @@ shared_examples "mappable" do |mappable_factory_name, do_login_for mappable.author visit send(mappable_edit_path, id: mappable.id) - fill_in "#{mappable_factory_name}_title", with: "New title" + fill_in "#{mappable_factory_name.camelize} title", with: "New title" click_on("Save changes") expect(page).not_to have_css(".map_location") @@ -249,8 +249,8 @@ def do_login_for(user) end def fill_in_proposal_form - fill_in "proposal_title", with: "Help refugees" - fill_in "proposal_summary", with: "In summary, what we want is..." + fill_in "Proposal title", with: "Help refugees" + fill_in "Proposal summary", with: "In summary, what we want is..." end def submit_proposal_form diff --git a/spec/shared/features/nested_documentable.rb b/spec/shared/features/nested_documentable.rb index e07b26680..9111d085b 100644 --- a/spec/shared/features/nested_documentable.rb +++ b/spec/shared/features/nested_documentable.rb @@ -363,8 +363,8 @@ def expect_document_has_cached_attachment(index, extension) end def documentable_fill_new_valid_proposal - fill_in :proposal_title, with: "Proposal title #{rand(9999)}" - fill_in :proposal_summary, with: "Proposal summary" + fill_in "Proposal title", with: "Proposal title #{rand(9999)}" + fill_in "Proposal summary", with: "Proposal summary" check :proposal_terms_of_service end diff --git a/spec/shared/features/nested_imageable.rb b/spec/shared/features/nested_imageable.rb index 1e5d9ec34..41819fba6 100644 --- a/spec/shared/features/nested_imageable.rb +++ b/spec/shared/features/nested_imageable.rb @@ -289,8 +289,8 @@ def imageable_attach_new_file(_imageable_factory_name, path, success = true) end def imageable_fill_new_valid_proposal - fill_in :proposal_title, with: "Proposal title" - fill_in :proposal_summary, with: "Proposal summary" + fill_in "Proposal title", with: "Proposal title" + fill_in "Proposal summary", with: "Proposal summary" check :proposal_terms_of_service end diff --git a/spec/support/common_actions.rb b/spec/support/common_actions.rb index efabd1532..2a2d2e3b7 100644 --- a/spec/support/common_actions.rb +++ b/spec/support/common_actions.rb @@ -27,9 +27,9 @@ module CommonActions end def fill_in_proposal - fill_in "proposal_title", with: "Help refugees" - fill_in "proposal_summary", with: "In summary what we want is..." - fill_in "proposal_description", with: "This is very important because..." + fill_in "Proposal title", with: "Help refugees" + fill_in "Proposal summary", with: "In summary, what we want is..." + fill_in "Proposal text", with: "This is very important because..." fill_in "proposal_video_url", with: "https://www.youtube.com/watch?v=yPQfcG-eimk" fill_in "proposal_responsible_name", with: "Isabel Garcia" check "proposal_terms_of_service" From 740c738fc53de1e764c63817ec889330fb49a3f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sat, 22 Dec 2018 23:39:41 +0100 Subject: [PATCH 050/183] Add debate translations --- app/models/debate.rb | 11 ++++---- ...20181130141019_add_debates_translations.rb | 15 ++++++++++ db/schema.rb | 11 ++++++++ spec/models/debate_spec.rb | 28 +++++++++++++++++-- 4 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 db/migrate/20181130141019_add_debates_translations.rb diff --git a/app/models/debate.rb b/app/models/debate.rb index 3f1ca7d76..dab92986b 100644 --- a/app/models/debate.rb +++ b/app/models/debate.rb @@ -20,6 +20,10 @@ class Debate < ApplicationRecord acts_as_paranoid column: :hidden_at include ActsAsParanoidAliases + translates :title, touch: true + translates :description, touch: true + include Globalizable + belongs_to :author, -> { with_hidden }, class_name: "User", foreign_key: "author_id" belongs_to :geozone has_many :comments, as: :commentable @@ -27,13 +31,10 @@ class Debate < ApplicationRecord extend DownloadSettings::DebateCsv delegate :name, :email, to: :author, prefix: true - validates :title, presence: true - validates :description, presence: true + validates_translation :title, presence: true, length: { in: 4..Debate.title_max_length } + validates_translation :description, presence: true, length: { in: 10..Debate.description_max_length } validates :author, presence: true - validates :title, length: { in: 4..Debate.title_max_length } - validates :description, length: { in: 10..Debate.description_max_length } - validates :terms_of_service, acceptance: { allow_nil: false }, on: :create before_save :calculate_hot_score, :calculate_confidence_score diff --git a/db/migrate/20181130141019_add_debates_translations.rb b/db/migrate/20181130141019_add_debates_translations.rb new file mode 100644 index 000000000..2cd1ad432 --- /dev/null +++ b/db/migrate/20181130141019_add_debates_translations.rb @@ -0,0 +1,15 @@ +class AddDebatesTranslations < ActiveRecord::Migration[4.2] + def self.up + Debate.create_translation_table!( + { + title: :string, + description: :text + }, + { migrate_data: true } + ) + end + + def self.down + Debate.drop_translation_table! + end +end diff --git a/db/schema.rb b/db/schema.rb index 998d0bd86..a0e4966a1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -488,6 +488,17 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.index ["proposal_id"], name: "index_dashboard_executed_actions_on_proposal_id", using: :btree end + create_table "debate_translations", force: :cascade do |t| + t.integer "debate_id", null: false + t.string "locale", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "title" + t.text "description" + t.index ["debate_id"], name: "index_debate_translations_on_debate_id", using: :btree + t.index ["locale"], name: "index_debate_translations_on_locale", using: :btree + end + create_table "debates", force: :cascade do |t| t.string "title", limit: 80 t.text "description" diff --git a/spec/models/debate_spec.rb b/spec/models/debate_spec.rb index 8f4745007..672748782 100644 --- a/spec/models/debate_spec.rb +++ b/spec/models/debate_spec.rb @@ -4,6 +4,8 @@ require "rails_helper" describe Debate do let(:debate) { build(:debate) } + it_behaves_like "globalizable", :debate + describe "Concerns" do it_behaves_like "has_public_author" it_behaves_like "notifiable" @@ -36,6 +38,7 @@ describe Debate do end describe "#description" do + it "is not valid without a description" do debate.description = nil expect(debate).not_to be_valid @@ -43,13 +46,34 @@ describe Debate do it "is sanitized" do debate.description = "" + debate.valid? + expect(debate.description).to eq("alert('danger');") end + it "is sanitized using globalize accessors" do + debate.description_en = "" + + debate.valid? + + expect(debate.description_en).to eq("alert('danger');") + end + it "is html_safe" do - debate.description = "" - expect(debate.description).to be_html_safe + debate.description_en = "" + + debate.valid? + + expect(debate.description_en).to be_html_safe + end + + it "is html_safe using globalize accessors" do + debate.description_en = "" + + debate.valid? + + expect(debate.description_en).to be_html_safe end it "is not valid when very short" do From e6c90270424151ef46f46cbe98cc8ec7bad70fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Wed, 13 Feb 2019 16:26:23 +0100 Subject: [PATCH 051/183] Rename deprecated fields from debates To avoid deprecation warning thrown by globalize after gem update. --- ...150434_rename_old_translatable_attibutes_in_debates.rb | 8 ++++++++ db/schema.rb | 5 ++--- 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20190213150434_rename_old_translatable_attibutes_in_debates.rb diff --git a/db/migrate/20190213150434_rename_old_translatable_attibutes_in_debates.rb b/db/migrate/20190213150434_rename_old_translatable_attibutes_in_debates.rb new file mode 100644 index 000000000..599f1431d --- /dev/null +++ b/db/migrate/20190213150434_rename_old_translatable_attibutes_in_debates.rb @@ -0,0 +1,8 @@ +class RenameOldTranslatableAttibutesInDebates < ActiveRecord::Migration[4.2] + def change + remove_index :debates, :title + + rename_column :debates, :title, :deprecated_title + rename_column :debates, :description, :deprecated_description + end +end diff --git a/db/schema.rb b/db/schema.rb index a0e4966a1..3e01bc8fa 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -500,8 +500,8 @@ ActiveRecord::Schema.define(version: 20190607160900) do end create_table "debates", force: :cascade do |t| - t.string "title", limit: 80 - t.text "description" + t.string "deprecated_title", limit: 80 + t.text "deprecated_description" t.integer "author_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -531,7 +531,6 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.index ["geozone_id"], name: "index_debates_on_geozone_id", using: :btree t.index ["hidden_at"], name: "index_debates_on_hidden_at", using: :btree t.index ["hot_score"], name: "index_debates_on_hot_score", using: :btree - t.index ["title"], name: "index_debates_on_title", using: :btree t.index ["tsv"], name: "index_debates_on_tsv", using: :gin end From b67cd0fe40cf7d5b1d71d7f2b1d659e294015b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sun, 23 Dec 2018 01:08:13 +0100 Subject: [PATCH 052/183] Add sanitization shared spec to debate --- spec/models/debate_spec.rb | 40 +------------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/spec/models/debate_spec.rb b/spec/models/debate_spec.rb index 672748782..0699d646e 100644 --- a/spec/models/debate_spec.rb +++ b/spec/models/debate_spec.rb @@ -9,6 +9,7 @@ describe Debate do describe "Concerns" do it_behaves_like "has_public_author" it_behaves_like "notifiable" + it_behaves_like "sanitizable" end it "is valid" do @@ -38,44 +39,11 @@ describe Debate do end describe "#description" do - it "is not valid without a description" do debate.description = nil expect(debate).not_to be_valid end - it "is sanitized" do - debate.description = "" - - debate.valid? - - expect(debate.description).to eq("alert('danger');") - end - - it "is sanitized using globalize accessors" do - debate.description_en = "" - - debate.valid? - - expect(debate.description_en).to eq("alert('danger');") - end - - it "is html_safe" do - debate.description_en = "" - - debate.valid? - - expect(debate.description_en).to be_html_safe - end - - it "is html_safe using globalize accessors" do - debate.description_en = "" - - debate.valid? - - expect(debate.description_en).to be_html_safe - end - it "is not valid when very short" do debate.description = "abc" expect(debate).not_to be_valid @@ -88,12 +56,6 @@ describe Debate do end describe "#tag_list" do - it "sanitizes the tag list" do - debate.tag_list = "user_id=1" - debate.valid? - expect(debate.tag_list).to eq(["user_id1"]) - end - it "is not valid with a tag list of more than 6 elements" do debate.tag_list = ["Hacienda", "Economía", "Medio Ambiente", "Corrupción", "Fiestas populares", "Prensa", "Huelgas"] expect(debate).not_to be_valid From f77e7df33e455e5e9e31987d1648cc3eccd60804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Fri, 25 Jan 2019 11:40:43 +0100 Subject: [PATCH 053/183] Fix debate specs After adding debate translatable fields to forms, they will be generated with nested translations names and ids so we can no longer use standard id locator. Using input label text to fill in fields works with both types of forms. --- spec/features/ckeditor_spec.rb | 6 +++--- spec/features/debates_spec.rb | 34 +++++++++++++++--------------- spec/features/tags/debates_spec.rb | 12 +++++------ spec/features/tags_spec.rb | 8 +++---- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/spec/features/ckeditor_spec.rb b/spec/features/ckeditor_spec.rb index 568441d5d..8b5ee04de 100644 --- a/spec/features/ckeditor_spec.rb +++ b/spec/features/ckeditor_spec.rb @@ -8,12 +8,12 @@ describe "CKEditor" do visit new_debate_path - expect(page).to have_css "#cke_debate_description" + expect(page).to have_css ".translatable-fields[data-locale='en'] .cke_wysiwyg_frame" click_link "Debates" click_link "Start a debate" - expect(page).to have_css "#cke_debate_description" + expect(page).to have_css ".translatable-fields[data-locale='en'] .cke_wysiwyg_frame" end -end \ No newline at end of file +end diff --git a/spec/features/debates_spec.rb b/spec/features/debates_spec.rb index c65483c6d..579ede59d 100644 --- a/spec/features/debates_spec.rb +++ b/spec/features/debates_spec.rb @@ -169,8 +169,8 @@ describe "Debates" do login_as(author) visit new_debate_path - fill_in "debate_title", with: "A title for a debate" - fill_in "debate_description", with: "This is very important because..." + fill_in "Debate title", with: "A title for a debate" + fill_in "Initial debate text", with: "This is very important because..." check "debate_terms_of_service" click_button "Start a debate" @@ -187,9 +187,9 @@ describe "Debates" do login_as(author) visit new_debate_path - fill_in "debate_title", with: "I am a bot" + fill_in "Debate title", with: "I am a bot" fill_in "debate_subtitle", with: "This is a honeypot field" - fill_in "debate_description", with: "This is the description" + fill_in "Initial debate text", with: "This is the description" check "debate_terms_of_service" click_button "Start a debate" @@ -206,8 +206,8 @@ describe "Debates" do login_as(author) visit new_debate_path - fill_in "debate_title", with: "I am a bot" - fill_in "debate_description", with: "This is the description" + fill_in "Debate title", with: "I am a bot" + fill_in "Initial debate text", with: "This is the description" check "debate_terms_of_service" click_button "Start a debate" @@ -231,8 +231,8 @@ describe "Debates" do login_as(author) visit new_debate_path - fill_in "debate_title", with: "Testing an attack" - fill_in "debate_description", with: "

This is

" + fill_in "Debate title", with: "Testing an attack" + fill_in "Initial debate text", with: "

This is

" check "debate_terms_of_service" click_button "Start a debate" @@ -249,8 +249,8 @@ describe "Debates" do login_as(author) visit new_debate_path - fill_in "debate_title", with: "Testing auto link" - fill_in "debate_description", with: "

This is a link www.example.org

" + fill_in "Debate title", with: "Testing auto link" + fill_in "Initial debate text", with: "

This is a link www.example.org

" check "debate_terms_of_service" click_button "Start a debate" @@ -266,8 +266,8 @@ describe "Debates" do login_as(author) visit new_debate_path - fill_in "debate_title", with: "Testing auto link" - fill_in "debate_description", with: js_injection_string + fill_in "Debate title", with: "Testing auto link" + fill_in "Initial debate text", with: js_injection_string check "debate_terms_of_service" click_button "Start a debate" @@ -318,8 +318,8 @@ describe "Debates" do visit edit_debate_path(debate) expect(page).to have_current_path(edit_debate_path(debate)) - fill_in "debate_title", with: "End child poverty" - fill_in "debate_description", with: "Let's do something to end child poverty" + fill_in "Debate title", with: "End child poverty" + fill_in "Initial debate text", with: "Let's do something to end child poverty" click_button "Save changes" @@ -333,7 +333,7 @@ describe "Debates" do login_as(debate.author) visit edit_debate_path(debate) - fill_in "debate_title", with: "" + fill_in "Debate title", with: "" click_button "Save changes" expect(page).to have_content error_message @@ -1108,7 +1108,7 @@ describe "Debates" do debate7 = create(:debate, title: "This has seven votes, and is not suggest", description: "This is the seven", cached_votes_up: 7) visit new_debate_path - fill_in "debate_title", with: "debate" + fill_in "Debate title", with: "debate" check "debate_terms_of_service" within("div#js-suggest") do @@ -1124,7 +1124,7 @@ describe "Debates" do debate2 = create(:debate, title: "Second debate has 2 votes", cached_votes_up: 2) visit new_debate_path - fill_in "debate_title", with: "proposal" + fill_in "Debate title", with: "proposal" check "debate_terms_of_service" within("div#js-suggest") do diff --git a/spec/features/tags/debates_spec.rb b/spec/features/tags/debates_spec.rb index ba582a294..2fcd2bb6e 100644 --- a/spec/features/tags/debates_spec.rb +++ b/spec/features/tags/debates_spec.rb @@ -66,8 +66,8 @@ describe "Tags" do login_as(user) visit new_debate_path - fill_in "debate_title", with: "Title" - fill_in "debate_description", with: "Description" + fill_in "Debate title", with: "Title" + fill_in "Initial debate text", with: "Description" check "debate_terms_of_service" fill_in "debate_tag_list", with: "Impuestos, Economía, Hacienda" @@ -85,8 +85,8 @@ describe "Tags" do login_as(user) visit new_debate_path - fill_in "debate_title", with: "Title" - fill_in "debate_description", with: "Description" + fill_in "Debate title", with: "Title" + fill_in "Initial debate text", with: "Description" check "debate_terms_of_service" fill_in "debate_tag_list", with: "Impuestos, Economía, Hacienda, Sanidad, Educación, Política, Igualdad" @@ -103,8 +103,8 @@ describe "Tags" do visit new_debate_path - fill_in "debate_title", with: "A test of dangerous strings" - fill_in "debate_description", with: "A description suitable for this test" + fill_in "Debate title", with: "A test of dangerous strings" + fill_in "Initial debate text", with: "A description suitable for this test" check "debate_terms_of_service" fill_in "debate_tag_list", with: "user_id=1, &a=3, " diff --git a/spec/features/tags_spec.rb b/spec/features/tags_spec.rb index 1b349819c..0d1b28e43 100644 --- a/spec/features/tags_spec.rb +++ b/spec/features/tags_spec.rb @@ -59,8 +59,8 @@ describe "Tags" do login_as(user) visit new_debate_path - fill_in "debate_title", with: "Title" - fill_in "debate_description", with: "Description" + fill_in "Debate title", with: "Title" + fill_in "Initial debate text", with: "Description" check "debate_terms_of_service" fill_in "debate_tag_list", with: "Impuestos, Economía, Hacienda" @@ -78,8 +78,8 @@ describe "Tags" do login_as(user) visit new_debate_path - fill_in "debate_title", with: "Title" - fill_in "debate_description", with: "Description" + fill_in "Debate title", with: "Title" + fill_in "Initial debate text", with: "Description" check "debate_terms_of_service" fill_in "debate_tag_list", with: "Impuestos, Economía, Hacienda, Sanidad, Educación, Política, Igualdad" From 51cda511553ec050c719ad76bd6dc6d19e619a0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sun, 23 Dec 2018 18:31:36 +0100 Subject: [PATCH 054/183] Add debates translation interface Also fix broken spec after removing translatable attributes from strong_parameters definition. Now we need to send these attributes as nested translations attributes. Use activerecord.yml title attribute label so form helper could load it from default location. --- app/controllers/debates_controller.rb | 4 ++- app/views/debates/_form.html.erb | 32 ++++++++++++++------- config/locales/en/activerecord.yml | 2 +- config/locales/es/activerecord.yml | 2 +- spec/controllers/debates_controller_spec.rb | 19 ++++++------ spec/features/debates_spec.rb | 5 ++++ 6 files changed, 43 insertions(+), 21 deletions(-) diff --git a/app/controllers/debates_controller.rb b/app/controllers/debates_controller.rb index b10e28b88..c0def9803 100644 --- a/app/controllers/debates_controller.rb +++ b/app/controllers/debates_controller.rb @@ -2,6 +2,7 @@ class DebatesController < ApplicationController include FeatureFlags include CommentableActions include FlagActions + include Translatable before_action :parse_tag_filter, only: :index before_action :authenticate_user!, except: [:index, :show, :map] @@ -55,7 +56,8 @@ class DebatesController < ApplicationController private def debate_params - params.require(:debate).permit(:title, :description, :tag_list, :terms_of_service) + attributes = [:tag_list, :terms_of_service] + params.require(:debate).permit(attributes, translation_params(Debate)) end def resource_model diff --git a/app/views/debates/_form.html.erb b/app/views/debates/_form.html.erb index 27884b47e..666c73149 100644 --- a/app/views/debates/_form.html.erb +++ b/app/views/debates/_form.html.erb @@ -1,17 +1,29 @@ -<%= form_for(@debate) do |f| %> +<%= render "admin/shared/globalize_locales", resource: @debate %> + +<%= translatable_form_for(@debate) do |f| %> <%= render "shared/errors", resource: @debate %>
-
- <%= f.label :title, t("debates.form.debate_title") %> - <%= f.text_field :title, maxlength: Debate.title_max_length, placeholder: t("debates.form.debate_title"), label: false, data: {js_suggest_result: "js_suggest_result", js_suggest: "#js-suggest", js_url: suggest_debates_path}%> -
-
-
- <%= f.label :description, t("debates.form.debate_text") %> - <%= f.cktext_area :description, maxlength: Debate.description_max_length, ckeditor: { language: I18n.locale }, label: false %> -
+ + <%= f.translatable_fields do |translations_form| %> +
+ <%= translations_form.text_field :title, + maxlength: Debate.title_max_length, + placeholder: t("debates.form.debate_title"), + data: { js_suggest_result: "js_suggest_result", + js_suggest: "#js-suggest", + js_url: suggest_debates_path } %> +
+
+ +
+ <%= translations_form.cktext_area :description, + maxlength: Debate.description_max_length, + ckeditor: { language: I18n.locale }, + label: t("debates.form.debate_text") %> +
+ <% end %> <%= f.invisible_captcha :subtitle %> diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index 2faf6b553..3949fd56d 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -181,7 +181,7 @@ en: author: "Author" description: "Opinion" terms_of_service: "Terms of service" - title: "Title" + title: "Debate title" proposal: author: "Author" title: "Title" diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index 116893436..37513245e 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -183,7 +183,7 @@ es: author: "Autor" description: "Opinión" terms_of_service: "Términos de servicio" - title: "Título" + title: "Título del debate" proposal: author: "Autor" title: "Título" diff --git a/spec/controllers/debates_controller_spec.rb b/spec/controllers/debates_controller_spec.rb index 60c977689..2e8b111d2 100644 --- a/spec/controllers/debates_controller_spec.rb +++ b/spec/controllers/debates_controller_spec.rb @@ -12,16 +12,19 @@ describe DebatesController do end it "creates an ahoy event" do - + debate_attributes = { + terms_of_service: "1", + translations_attributes: { + "0" => { + title: "A sample debate", + description: "this is a sample debate", + locale: "en" + } + } + } sign_in create(:user) - post :create, params: { - debate: { - title: "A sample debate", - description: "this is a sample debate", - terms_of_service: 1 - } - } + post :create, debate: debate_attributes expect(Ahoy::Event.where(name: :debate_created).count).to eq 1 expect(Ahoy::Event.last.properties["debate_id"]).to eq Debate.last.id end diff --git a/spec/features/debates_spec.rb b/spec/features/debates_spec.rb index 579ede59d..ed09e271c 100644 --- a/spec/features/debates_spec.rb +++ b/spec/features/debates_spec.rb @@ -11,6 +11,11 @@ describe "Debates" do context "Concerns" do it_behaves_like "notifiable in-app", Debate it_behaves_like "relationable", Debate + it_behaves_like "translatable", + "debate", + "edit_debate_path", + %w[title], + { "description" => :ckeditor } end scenario "Index" do From 6a6080e6b73f3f9fdb7150cc122e12e79719858e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sat, 12 Jan 2019 16:19:03 +0100 Subject: [PATCH 055/183] Fix debates suggest feature --- app/views/debates/_form.html.erb | 4 ++-- spec/features/debates_spec.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/debates/_form.html.erb b/app/views/debates/_form.html.erb index 666c73149..4ab110806 100644 --- a/app/views/debates/_form.html.erb +++ b/app/views/debates/_form.html.erb @@ -12,10 +12,10 @@ maxlength: Debate.title_max_length, placeholder: t("debates.form.debate_title"), data: { js_suggest_result: "js_suggest_result", - js_suggest: "#js-suggest", + js_suggest: ".js-suggest", js_url: suggest_debates_path } %>
-
+
<%= translations_form.cktext_area :description, diff --git a/spec/features/debates_spec.rb b/spec/features/debates_spec.rb index ed09e271c..cc73bdb4f 100644 --- a/spec/features/debates_spec.rb +++ b/spec/features/debates_spec.rb @@ -1116,7 +1116,7 @@ describe "Debates" do fill_in "Debate title", with: "debate" check "debate_terms_of_service" - within("div#js-suggest") do + within("div.js-suggest") do expect(page).to have_content "You are seeing 5 of 6 debates containing the term 'debate'" end end @@ -1132,7 +1132,7 @@ describe "Debates" do fill_in "Debate title", with: "proposal" check "debate_terms_of_service" - within("div#js-suggest") do + within("div.js-suggest") do expect(page).not_to have_content "You are seeing" end end From 036a3d7636a31eb196a4acc7e30fa91ea06da486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sat, 12 Jan 2019 16:28:48 +0100 Subject: [PATCH 056/183] Add translations to debate pg_search_scope Some Debate attributes are now translatable so we need to include all existing translations on pg_search scope. --- app/models/debate.rb | 22 +++++++++++++++++++--- spec/models/debate_spec.rb | 21 +++++++++++++++++++-- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/app/models/debate.rb b/app/models/debate.rb index dab92986b..eacd4e55b 100644 --- a/app/models/debate.rb +++ b/app/models/debate.rb @@ -65,13 +65,17 @@ class Debate < ApplicationRecord .where("author_id != ?", user.id) end + def searchable_translations_definitions + { title => "A", + description => "D" } + end + def searchable_values - { title => "A", + { author.username => "B", tag_list.join(" ") => "B", geozone.try(:name) => "B", - description => "D" - } + }.merge!(searchable_globalized_values) end def self.search(terms) @@ -161,4 +165,16 @@ class Debate < ApplicationRecord orders << "recommendations" if Setting["feature.user.recommendations_on_debates"] && user&.recommended_debates return orders end + + private + + def searchable_globalized_values + values = {} + translations.each do |translation| + Globalize.with_locale(translation.locale) do + values.merge! searchable_translations_definitions + end + end + values + end end diff --git a/spec/models/debate_spec.rb b/spec/models/debate_spec.rb index 0699d646e..7d6e22763 100644 --- a/spec/models/debate_spec.rb +++ b/spec/models/debate_spec.rb @@ -465,18 +465,35 @@ describe Debate do context "attributes" do + let(:attributes) { { title: "save the world", + description: "in order to save the world one must think about...", + title_es: "para salvar el mundo uno debe pensar en...", + description_es: "uno debe pensar" } } + it "searches by title" do - debate = create(:debate, title: "save the world") + debate = create(:debate, attributes) results = described_class.search("save the world") expect(results).to eq([debate]) end + it "searches by title across all languages translations" do + debate = create(:debate, attributes) + results = described_class.search("salvar el mundo") + expect(results).to eq([debate]) + end + it "searches by description" do - debate = create(:debate, description: "in order to save the world one must think about...") + debate = create(:debate, attributes) results = described_class.search("one must think") expect(results).to eq([debate]) end + it "searches by description across all languages translations" do + debate = create(:debate, attributes) + results = described_class.search("uno debe pensar") + expect(results).to eq([debate]) + end + it "searches by author name" do author = create(:user, username: "Danny Trejo") debate = create(:debate, author: author) From ed750f6cce613d9be2718e115fc2330e2f9af699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Wed, 13 Feb 2019 18:36:55 +0100 Subject: [PATCH 057/183] Move private method to a more reusable location This method will be used by any translatable model that uses pg_search feature so it's better to have it within globalizable model concern so all translatable models can use it. --- app/models/concerns/globalizable.rb | 12 ++++++++++++ app/models/debate.rb | 12 ------------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/models/concerns/globalizable.rb b/app/models/concerns/globalizable.rb index df054caaf..6501041d0 100644 --- a/app/models/concerns/globalizable.rb +++ b/app/models/concerns/globalizable.rb @@ -20,6 +20,18 @@ module Globalizable if self.paranoid? && translation_class.attribute_names.include?("hidden_at") translation_class.send :acts_as_paranoid, column: :hidden_at end + + private + + def searchable_globalized_values + values = {} + translations.each do |translation| + Globalize.with_locale(translation.locale) do + values.merge! searchable_translations_definitions + end + end + values + end end class_methods do diff --git a/app/models/debate.rb b/app/models/debate.rb index eacd4e55b..b3a23200a 100644 --- a/app/models/debate.rb +++ b/app/models/debate.rb @@ -165,16 +165,4 @@ class Debate < ApplicationRecord orders << "recommendations" if Setting["feature.user.recommendations_on_debates"] && user&.recommended_debates return orders end - - private - - def searchable_globalized_values - values = {} - translations.each do |translation| - Globalize.with_locale(translation.locale) do - values.merge! searchable_translations_definitions - end - end - values - end end From 03375ae621713436f647fc85bc7b5bb35b0a9d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Tue, 22 Jan 2019 12:40:01 +0100 Subject: [PATCH 058/183] Fix debates restore feature Add recursive restore option to restore all soft deleted relations. --- app/controllers/admin/hidden_debates_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/admin/hidden_debates_controller.rb b/app/controllers/admin/hidden_debates_controller.rb index 77d30b488..3e93db0a6 100644 --- a/app/controllers/admin/hidden_debates_controller.rb +++ b/app/controllers/admin/hidden_debates_controller.rb @@ -17,7 +17,7 @@ class Admin::HiddenDebatesController < Admin::BaseController end def restore - @debate.restore + @debate.restore!(recursive: true) @debate.ignore_flag Activity.log(current_user, :restore, @debate) redirect_to request.query_parameters.merge(action: :index) From 096a9f6bb84cae0cb30b46a889a643e72c63ce0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Wed, 23 Jan 2019 13:29:11 +0100 Subject: [PATCH 059/183] Enable soft deletion of Debate::Translations --- .../20190123122752_add_hidden_at_to_debate_translations.rb | 6 ++++++ db/schema.rb | 2 ++ spec/models/debate_spec.rb | 1 + 3 files changed, 9 insertions(+) create mode 100644 db/migrate/20190123122752_add_hidden_at_to_debate_translations.rb diff --git a/db/migrate/20190123122752_add_hidden_at_to_debate_translations.rb b/db/migrate/20190123122752_add_hidden_at_to_debate_translations.rb new file mode 100644 index 000000000..6995ad6f2 --- /dev/null +++ b/db/migrate/20190123122752_add_hidden_at_to_debate_translations.rb @@ -0,0 +1,6 @@ +class AddHiddenAtToDebateTranslations < ActiveRecord::Migration[4.2] + def change + add_column :debate_translations, :hidden_at, :datetime + add_index :debate_translations, :hidden_at + end +end diff --git a/db/schema.rb b/db/schema.rb index 3e01bc8fa..90b287745 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -495,7 +495,9 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.datetime "updated_at", null: false t.string "title" t.text "description" + t.datetime "hidden_at" t.index ["debate_id"], name: "index_debate_translations_on_debate_id", using: :btree + t.index ["hidden_at"], name: "index_debate_translations_on_hidden_at", using: :btree t.index ["locale"], name: "index_debate_translations_on_locale", using: :btree end diff --git a/spec/models/debate_spec.rb b/spec/models/debate_spec.rb index 7d6e22763..2b6416284 100644 --- a/spec/models/debate_spec.rb +++ b/spec/models/debate_spec.rb @@ -10,6 +10,7 @@ describe Debate do it_behaves_like "has_public_author" it_behaves_like "notifiable" it_behaves_like "sanitizable" + it_behaves_like "acts as paranoid", :debate end it "is valid" do From 158af0217d0a62b6ab89ca9b967da71918d64c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 24 Dec 2018 15:11:16 +0100 Subject: [PATCH 060/183] Add comments translations Co-Authored-By: Sebastia --- app/models/comment.rb | 5 ++++- .../20181205102153_add_comments_translations.rb | 14 ++++++++++++++ db/schema.rb | 10 ++++++++++ spec/models/comment_spec.rb | 1 + 4 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20181205102153_add_comments_translations.rb diff --git a/app/models/comment.rb b/app/models/comment.rb index e5b83e818..e80a5e048 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -18,7 +18,10 @@ class Comment < ApplicationRecord attr_accessor :as_moderator, :as_administrator - validates :body, presence: true + translates :body, touch: true + include Globalizable + + validates_translation :body, presence: true validates :user, presence: true validates :commentable_type, inclusion: { in: COMMENTABLE_TYPES } diff --git a/db/migrate/20181205102153_add_comments_translations.rb b/db/migrate/20181205102153_add_comments_translations.rb new file mode 100644 index 000000000..a7ea1b64c --- /dev/null +++ b/db/migrate/20181205102153_add_comments_translations.rb @@ -0,0 +1,14 @@ +class AddCommentsTranslations < ActiveRecord::Migration[4.2] + def self.up + Comment.create_translation_table!( + { + body: :text + }, + { migrate_data: true } + ) + end + + def self.down + Comment.drop_translation_table! + end +end diff --git a/db/schema.rb b/db/schema.rb index 90b287745..c2e6c60af 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -415,6 +415,16 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.index ["type"], name: "index_ckeditor_assets_on_type", using: :btree end + create_table "comment_translations", force: :cascade do |t| + t.integer "comment_id", null: false + t.string "locale", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.text "body" + t.index ["comment_id"], name: "index_comment_translations_on_comment_id", using: :btree + t.index ["locale"], name: "index_comment_translations_on_locale", using: :btree + end + create_table "comments", force: :cascade do |t| t.integer "commentable_id" t.string "commentable_type" diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb index 59b016e13..fac612404 100644 --- a/spec/models/comment_spec.rb +++ b/spec/models/comment_spec.rb @@ -5,6 +5,7 @@ describe Comment do let(:comment) { build(:comment) } it_behaves_like "has_public_author" + it_behaves_like "globalizable", :comment it "is valid" do expect(comment).to be_valid From 16b3ec6e5f94c28aa132a511351d0478b721c202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 18 Feb 2019 13:28:54 +0100 Subject: [PATCH 061/183] Rename deprecated attributes from comments To avoid deprecation warning thrown by Globalize after gem update. --- ...18122530_rename_old_translatable_attibutes_in_comments.rb | 5 +++++ db/schema.rb | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20190218122530_rename_old_translatable_attibutes_in_comments.rb diff --git a/db/migrate/20190218122530_rename_old_translatable_attibutes_in_comments.rb b/db/migrate/20190218122530_rename_old_translatable_attibutes_in_comments.rb new file mode 100644 index 000000000..8e456e2fe --- /dev/null +++ b/db/migrate/20190218122530_rename_old_translatable_attibutes_in_comments.rb @@ -0,0 +1,5 @@ +class RenameOldTranslatableAttibutesInComments < ActiveRecord::Migration[4.2] + def change + rename_column :comments, :body, :deprecated_body + end +end diff --git a/db/schema.rb b/db/schema.rb index c2e6c60af..30abee152 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -428,7 +428,7 @@ ActiveRecord::Schema.define(version: 20190607160900) do create_table "comments", force: :cascade do |t| t.integer "commentable_id" t.string "commentable_type" - t.text "body" + t.text "deprecated_body" t.string "subject" t.integer "user_id", null: false t.datetime "created_at" From 4ce006ec9619dd94bb9e5733202499ab587ecbe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Wed, 23 Jan 2019 13:30:32 +0100 Subject: [PATCH 062/183] Enable soft deletion of Comment::Translations --- .../20190123122936_add_hidden_at_to_comment_translations.rb | 6 ++++++ db/schema.rb | 2 ++ spec/models/comment_spec.rb | 1 + 3 files changed, 9 insertions(+) create mode 100644 db/migrate/20190123122936_add_hidden_at_to_comment_translations.rb diff --git a/db/migrate/20190123122936_add_hidden_at_to_comment_translations.rb b/db/migrate/20190123122936_add_hidden_at_to_comment_translations.rb new file mode 100644 index 000000000..bf66b7386 --- /dev/null +++ b/db/migrate/20190123122936_add_hidden_at_to_comment_translations.rb @@ -0,0 +1,6 @@ +class AddHiddenAtToCommentTranslations < ActiveRecord::Migration[4.2] + def change + add_column :comment_translations, :hidden_at, :datetime + add_index :comment_translations, :hidden_at + end +end diff --git a/db/schema.rb b/db/schema.rb index 30abee152..925e935f3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -421,7 +421,9 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.text "body" + t.datetime "hidden_at" t.index ["comment_id"], name: "index_comment_translations_on_comment_id", using: :btree + t.index ["hidden_at"], name: "index_comment_translations_on_hidden_at", using: :btree t.index ["locale"], name: "index_comment_translations_on_locale", using: :btree end diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb index fac612404..d4f368c0b 100644 --- a/spec/models/comment_spec.rb +++ b/spec/models/comment_spec.rb @@ -6,6 +6,7 @@ describe Comment do it_behaves_like "has_public_author" it_behaves_like "globalizable", :comment + it_behaves_like "acts as paranoid", :comment it "is valid" do expect(comment).to be_valid From bd3bb72370432d23f00fb917283867645ead207b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sun, 23 Dec 2018 17:40:10 +0100 Subject: [PATCH 063/183] Add proposals translation interface * Convert proposal form into translatable one. * Adapt translatable shared spec to define an owner when running at frontend feature specs. * Remove old attributes from strong parameters. --- .../management/proposals_controller.rb | 9 +-- app/controllers/proposals_controller.rb | 15 ++--- app/helpers/proposals_helper.rb | 4 ++ app/views/proposals/_form.html.erb | 58 ++++++++++++------- spec/features/proposals_spec.rb | 5 ++ 5 files changed, 60 insertions(+), 31 deletions(-) diff --git a/app/controllers/management/proposals_controller.rb b/app/controllers/management/proposals_controller.rb index f24e94303..93e20f690 100644 --- a/app/controllers/management/proposals_controller.rb +++ b/app/controllers/management/proposals_controller.rb @@ -1,6 +1,7 @@ class Management::ProposalsController < Management::BaseController include HasOrders include CommentableActions + include Translatable before_action :only_verified_users, except: :print before_action :set_proposal, only: [:vote, :show] @@ -52,10 +53,10 @@ class Management::ProposalsController < Management::BaseController end def proposal_params - params.require(:proposal).permit(:title, :summary, :description, :video_url, - :responsible_name, :tag_list, :terms_of_service, :geozone_id, - :skip_map, - map_location_attributes: [:latitude, :longitude, :zoom]) + attributes = [:video_url, :responsible_name, :tag_list, + :terms_of_service, :geozone_id, + :skip_map, map_location_attributes: [:latitude, :longitude, :zoom]] + params.require(:proposal).permit(attributes, translation_params(Proposal)) end def resource_model diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index d2b876f06..9bf5dc7fd 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -3,6 +3,7 @@ class ProposalsController < ApplicationController include CommentableActions include FlagActions include ImageAttributes + include Translatable before_action :parse_tag_filter, only: :index before_action :load_categories, only: [:index, :new, :create, :edit, :map, :summary] @@ -37,7 +38,6 @@ class ProposalsController < ApplicationController def create @proposal = Proposal.new(proposal_params.merge(author: current_user)) - if @proposal.save redirect_to created_proposal_path(@proposal), notice: I18n.t("flash.actions.create.proposal") else @@ -98,12 +98,13 @@ class ProposalsController < ApplicationController private def proposal_params - params.require(:proposal).permit(:title, :summary, :description, :video_url, - :responsible_name, :tag_list, :terms_of_service, - :geozone_id, :skip_map, image_attributes: image_attributes, - documents_attributes: [:id, :title, :attachment, - :cached_attachment, :user_id, :_destroy], - map_location_attributes: [:latitude, :longitude, :zoom]) + attributes = [:video_url,:responsible_name, :tag_list, + :terms_of_service, :geozone_id, :skip_map, + image_attributes: image_attributes, + documents_attributes: [:id, :title, :attachment, :cached_attachment, + :user_id, :_destroy], + map_location_attributes: [:latitude, :longitude, :zoom]] + params.require(:proposal).permit(attributes, translation_params(Proposal)) end def retired_params diff --git a/app/helpers/proposals_helper.rb b/app/helpers/proposals_helper.rb index ecd8a1490..3879d4679 100644 --- a/app/helpers/proposals_helper.rb +++ b/app/helpers/proposals_helper.rb @@ -64,6 +64,10 @@ module ProposalsHelper proposals_current_view == "default" ? "minimal" : "default" end + def summary_help_text_id(translations_form) + "summary-help-text-#{translations_form.locale}" + end + def link_to_toggle_proposal_selection(proposal) if proposal.selected? button_text = t("admin.proposals.index.selected") diff --git a/app/views/proposals/_form.html.erb b/app/views/proposals/_form.html.erb index f7a5e57f9..dbe789e9a 100644 --- a/app/views/proposals/_form.html.erb +++ b/app/views/proposals/_form.html.erb @@ -1,32 +1,50 @@ -<%= form_for(@proposal, url: form_url) do |f| %> +<%= render "admin/shared/globalize_locales", resource: @proposal %> + +<%= translatable_form_for(@proposal, url: form_url) do |f| %> + <%= render "shared/errors", resource: @proposal %>
-
- <%= f.label :title, t("proposals.form.proposal_title") %> - <%= f.text_field :title, maxlength: Proposal.title_max_length, placeholder: t("proposals.form.proposal_title"), label: false, data: {js_suggest_result: "js_suggest_result", js_suggest: "#js-suggest", js_url: suggest_proposals_path}%> -
-
+ + <%= f.translatable_fields do |translations_form| %> +
+ <%= translations_form.text_field :title, + maxlength: Proposal.title_max_length, + placeholder: t("proposals.form.proposal_title"), + label: t("proposals.form.proposal_title"), + data: { js_suggest_result: "js_suggest_result", + js_suggest: "#js-suggest", + js_url: suggest_proposals_path } %> +
+
+ +
+ <%= translations_form.label :summary %> +

> + <%= t("proposals.form.proposal_summary_note") %> +

+ <%= translations_form.text_area :summary, + rows: 4, maxlength: 200, + label: false, + placeholder: t("proposals.form.proposal_summary"), + aria: {describedby: summary_help_text_id(translations_form)} %> +
+ +
+ <%= translations_form.cktext_area :description, + maxlength: Proposal.description_max_length, + ckeditor: { language: I18n.locale }, + label: t("proposals.form.proposal_text") %> +
+ <% end %> <%= f.invisible_captcha :subtitle %> -
- <%= f.label :summary, t("proposals.form.proposal_summary") %> -

<%= t("proposals.form.proposal_summary_note") %>

- <%= f.text_area :summary, rows: 4, maxlength: 200, label: false, - placeholder: t("proposals.form.proposal_summary"), - aria: {describedby: "summary-help-text"} %> -
- -
- <%= f.label :description, t("proposals.form.proposal_text") %> - <%= f.cktext_area :description, maxlength: Proposal.description_max_length, ckeditor: { language: I18n.locale }, label: false %> -
-
<%= f.label :video_url, t("proposals.form.proposal_video_url") %>

<%= t("proposals.form.proposal_video_url_note") %>

- <%= f.text_field :video_url, placeholder: t("proposals.form.proposal_video_url"), label: false, + <%= f.text_field :video_url, placeholder: t("proposals.form.proposal_video_url"), + label: false, aria: {describedby: "video-url-help-text"} %>
diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index d2ecf5776..a101430ad 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -15,6 +15,11 @@ describe "Proposals" do context "Concerns" do it_behaves_like "notifiable in-app", Proposal it_behaves_like "relationable", Proposal + it_behaves_like "translatable", + "proposal", + "edit_proposal_path", + %w[title summary], + { "description" => :ckeditor } end context "Index" do From 0f4fcfb20eb71032674dfe4c7f86982f44693bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sat, 12 Jan 2019 14:23:00 +0100 Subject: [PATCH 064/183] Fix proposals suggest feature Now we need one suggest placeholder for each translation. This also fixes invalid usage of id HTML attribute. --- app/views/proposals/_form.html.erb | 5 ++--- spec/features/proposals_spec.rb | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/views/proposals/_form.html.erb b/app/views/proposals/_form.html.erb index dbe789e9a..29a72b5fd 100644 --- a/app/views/proposals/_form.html.erb +++ b/app/views/proposals/_form.html.erb @@ -5,7 +5,6 @@ <%= render "shared/errors", resource: @proposal %>
- <%= f.translatable_fields do |translations_form| %>
<%= translations_form.text_field :title, @@ -13,10 +12,10 @@ placeholder: t("proposals.form.proposal_title"), label: t("proposals.form.proposal_title"), data: { js_suggest_result: "js_suggest_result", - js_suggest: "#js-suggest", + js_suggest: ".js-suggest", js_url: suggest_proposals_path } %>
-
+
<%= translations_form.label :summary %> diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index a101430ad..0b2e6f4d1 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -1727,7 +1727,7 @@ describe "Proposals" do fill_in "Proposal title", with: "search" check "proposal_terms_of_service" - within("div#js-suggest") do + within("div.js-suggest") do expect(page).to have_content "You are seeing 5 of 6 proposals containing the term 'search'" end end @@ -1743,7 +1743,7 @@ describe "Proposals" do fill_in "Proposal title", with: "debate" check "proposal_terms_of_service" - within("div#js-suggest") do + within("div.js-suggest") do expect(page).not_to have_content "You are seeing" end end From f572d5b579f58dc0a2877db21eab1c3e9e0d14e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sat, 12 Jan 2019 14:56:06 +0100 Subject: [PATCH 065/183] Add translations to proposal pg_search_scope Some Proposal attributes are now translatable so we need to include all existing translations on pg_search scope. --- app/models/concerns/globalizable.rb | 14 ++++++------- app/models/proposal.rb | 18 ++++++++++------- spec/models/proposal_spec.rb | 31 ++++++++++++++++++++++++++--- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/app/models/concerns/globalizable.rb b/app/models/concerns/globalizable.rb index 6501041d0..a225c9236 100644 --- a/app/models/concerns/globalizable.rb +++ b/app/models/concerns/globalizable.rb @@ -23,15 +23,15 @@ module Globalizable private - def searchable_globalized_values - values = {} - translations.each do |translation| - Globalize.with_locale(translation.locale) do - values.merge! searchable_translations_definitions + def searchable_globalized_values + values = {} + translations.each do |translation| + Globalize.with_locale(translation.locale) do + values.merge! searchable_translations_definitions + end end + values end - values - end end class_methods do diff --git a/app/models/proposal.rb b/app/models/proposal.rb index 4961b237d..497d8181e 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -125,14 +125,18 @@ class Proposal < ApplicationRecord "#{id}-#{title}".parameterize end + def searchable_translations_definitions + { title => "A", + summary => "C", + description => "D" } + end + def searchable_values - { title => "A", - author.username => "B", - tag_list.join(" ") => "B", - geozone.try(:name) => "B", - summary => "C", - description => "D" - } + { + author.username => "B", + tag_list.join(" ") => "B", + geozone.try(:name) => "B" + }.merge!(searchable_globalized_values) end def self.search(terms) diff --git a/spec/models/proposal_spec.rb b/spec/models/proposal_spec.rb index 881063f26..9c1d0971c 100644 --- a/spec/models/proposal_spec.rb +++ b/spec/models/proposal_spec.rb @@ -486,24 +486,49 @@ describe Proposal do context "attributes" do + let(:attributes) { { title: "save the world", + summary: "basically", + description: "in order to save the world one must think about...", + title_es: "para salvar el mundo uno debe pensar en...", + summary_es: "basicamente", + description_es: "uno debe pensar" } } + it "searches by title" do - proposal = create(:proposal, title: "save the world") + proposal = create(:proposal, attributes) results = described_class.search("save the world") expect(results).to eq([proposal]) end + it "searches by title across all languages translations" do + proposal = create(:proposal, attributes) + results = described_class.search("salvar el mundo") + expect(results).to eq([proposal]) + end + it "searches by summary" do - proposal = create(:proposal, summary: "basically...") + proposal = create(:proposal, attributes) results = described_class.search("basically") expect(results).to eq([proposal]) end + it "searches by summary across all languages translations" do + proposal = create(:proposal, attributes) + results = described_class.search("basicamente") + expect(results).to eq([proposal]) + end + it "searches by description" do - proposal = create(:proposal, description: "in order to save the world one must think about...") + proposal = create(:proposal, attributes) results = described_class.search("one must think") expect(results).to eq([proposal]) end + it "searches by description across all languages translations" do + proposal = create(:proposal, attributes) + results = described_class.search("uno debe pensar") + expect(results).to eq([proposal]) + end + it "searches by author name" do author = create(:user, username: "Danny Trejo") proposal = create(:proposal, author: author) From fb4d4c6c5a06ebd03a1e2bd8378a9e1159a201b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Tue, 22 Jan 2019 12:40:42 +0100 Subject: [PATCH 066/183] Fix hidden proposals restore feature Add recursive restore option to restore all soft deleted relations. --- app/controllers/admin/hidden_proposals_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/admin/hidden_proposals_controller.rb b/app/controllers/admin/hidden_proposals_controller.rb index 48c910c0c..7442c0626 100644 --- a/app/controllers/admin/hidden_proposals_controller.rb +++ b/app/controllers/admin/hidden_proposals_controller.rb @@ -18,7 +18,7 @@ class Admin::HiddenProposalsController < Admin::BaseController end def restore - @proposal.restore + @proposal.restore(recursive: true) @proposal.ignore_flag Activity.log(current_user, :restore, @proposal) redirect_to request.query_parameters.merge(action: :index) From 207970684572f4db9d5f7e05c818d6348fbeb885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Wed, 23 Jan 2019 13:27:21 +0100 Subject: [PATCH 067/183] Enable soft deletion of Proposal::Translations --- ...20190123122511_add_hidden_at_to_proposal_translations.rb | 6 ++++++ db/schema.rb | 2 ++ spec/models/proposal_spec.rb | 1 + 3 files changed, 9 insertions(+) create mode 100644 db/migrate/20190123122511_add_hidden_at_to_proposal_translations.rb diff --git a/db/migrate/20190123122511_add_hidden_at_to_proposal_translations.rb b/db/migrate/20190123122511_add_hidden_at_to_proposal_translations.rb new file mode 100644 index 000000000..c8250a2eb --- /dev/null +++ b/db/migrate/20190123122511_add_hidden_at_to_proposal_translations.rb @@ -0,0 +1,6 @@ +class AddHiddenAtToProposalTranslations < ActiveRecord::Migration[4.2] + def change + add_column :proposal_translations, :hidden_at, :datetime + add_index :proposal_translations, :hidden_at + end +end diff --git a/db/schema.rb b/db/schema.rb index 925e935f3..fc97b55bb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1318,6 +1318,8 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.text "description" t.text "summary" t.text "retired_explanation" + t.datetime "hidden_at" + t.index ["hidden_at"], name: "index_proposal_translations_on_hidden_at", using: :btree t.index ["locale"], name: "index_proposal_translations_on_locale", using: :btree t.index ["proposal_id"], name: "index_proposal_translations_on_proposal_id", using: :btree end diff --git a/spec/models/proposal_spec.rb b/spec/models/proposal_spec.rb index 9c1d0971c..40459fddf 100644 --- a/spec/models/proposal_spec.rb +++ b/spec/models/proposal_spec.rb @@ -10,6 +10,7 @@ describe Proposal do it_behaves_like "map validations" it_behaves_like "globalizable", :proposal it_behaves_like "sanitizable" + it_behaves_like "acts as paranoid", :proposal end it "is valid" do From 78055555cf1fe806f88e8715f7d4996ea43fa6b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 24 Jan 2019 16:58:25 +0100 Subject: [PATCH 068/183] Add debates translations to dev_seeds Update debates development seeds with translations for all avaialble locales. --- db/dev_seeds/debates.rb | 43 +++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/db/dev_seeds/debates.rb b/db/dev_seeds/debates.rb index bda70f028..9422f0985 100644 --- a/db/dev_seeds/debates.rb +++ b/db/dev_seeds/debates.rb @@ -3,25 +3,40 @@ section "Creating Debates" do 30.times do author = User.all.sample description = "

#{Faker::Lorem.paragraphs.join("

")}

" - Debate.create!(author: author, - title: Faker::Lorem.sentence(3).truncate(60), - created_at: rand((Time.current - 1.week)..Time.current), - description: description, - tag_list: tags.sample(3).join(","), - geozone: Geozone.all.sample, - terms_of_service: "1") + debate = Debate.create!(author: author, + title: Faker::Lorem.sentence(3).truncate(60), + created_at: rand((Time.current - 1.week)..Time.current), + description: description, + tag_list: tags.sample(3).join(","), + geozone: Geozone.all.sample, + terms_of_service: "1") + random_locales.map do |locale| + Globalize.with_locale(locale) do + debate.title = "Title for locale #{locale}" + debate.description = "

Description for locale #{locale}

" + debate.save! + end + end end tags = ActsAsTaggableOn::Tag.where(kind: "category") 30.times do author = User.all.sample description = "

#{Faker::Lorem.paragraphs.join("

")}

" - Debate.create!(author: author, - title: Faker::Lorem.sentence(3).truncate(60), - created_at: rand((Time.current - 1.week)..Time.current), - description: description, - tag_list: tags.sample(3).join(","), - geozone: Geozone.all.sample, - terms_of_service: "1") + + debate = Debate.create!(author: author, + title: Faker::Lorem.sentence(3).truncate(60), + created_at: rand((Time.current - 1.week)..Time.current), + description: description, + tag_list: tags.sample(3).join(","), + geozone: Geozone.all.sample, + terms_of_service: "1") + random_locales.map do |locale| + Globalize.with_locale(locale) do + debate.title = "Title for locale #{locale}" + debate.description = "

Description for locale #{locale}

" + debate.save! + end + end end end From f70adbe23a650d5db002e86ba7c50fbf1dc44a62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 25 Feb 2019 16:55:57 +0100 Subject: [PATCH 069/183] Move label translations to activerecord.yml --- app/views/debates/_form.html.erb | 3 +-- config/locales/en/activerecord.yml | 3 +++ config/locales/en/general.yml | 1 - config/locales/es/activerecord.yml | 3 +++ config/locales/es/general.yml | 1 - 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/views/debates/_form.html.erb b/app/views/debates/_form.html.erb index 4ab110806..b4b3c71e4 100644 --- a/app/views/debates/_form.html.erb +++ b/app/views/debates/_form.html.erb @@ -20,8 +20,7 @@
<%= translations_form.cktext_area :description, maxlength: Debate.description_max_length, - ckeditor: { language: I18n.locale }, - label: t("debates.form.debate_text") %> + ckeditor: { language: I18n.locale } %>
<% end %> diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index 3949fd56d..1ae65f7a0 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -181,7 +181,10 @@ en: author: "Author" description: "Opinion" terms_of_service: "Terms of service" + title: "Title" + debate/translation: title: "Debate title" + description: "Initial debate text" proposal: author: "Author" title: "Title" diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index 510294c5f..595723072 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -101,7 +101,6 @@ en: submit_button: Save changes show_link: View debate form: - debate_text: Initial debate text debate_title: Debate title tags_instructions: Tag this debate. tags_label: Topics diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index 37513245e..fb3bc3138 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -184,6 +184,9 @@ es: description: "Opinión" terms_of_service: "Términos de servicio" title: "Título del debate" + debate/translation: + title: "Título del debate" + description: "Texto inicial del debate" proposal: author: "Autor" title: "Título" diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index 1e9621506..0f69861ae 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -101,7 +101,6 @@ es: submit_button: Guardar cambios show_link: Ver debate form: - debate_text: Texto inicial del debate debate_title: Título del debate tags_instructions: Etiqueta este debate. tags_label: Temas From 8103a16031592db79a8cb1016626b3ed5f082b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sat, 12 Jan 2019 14:57:32 +0100 Subject: [PATCH 070/183] Add proposals translations to dev_seeds Update proposal development seeds with translations for all avaialble locales. --- db/dev_seeds/proposals.rb | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/db/dev_seeds/proposals.rb b/db/dev_seeds/proposals.rb index d961bd7df..e2a460d3b 100644 --- a/db/dev_seeds/proposals.rb +++ b/db/dev_seeds/proposals.rb @@ -24,11 +24,14 @@ end section "Creating Proposals" do tags = Faker::Lorem.words(25) 30.times do + title = Faker::Lorem.sentence(3).truncate(60) + summary = Faker::Lorem.sentence(3) author = User.all.sample description = "

#{Faker::Lorem.paragraphs.join("

")}

" + proposal = Proposal.create!(author: author, - title: Faker::Lorem.sentence(3).truncate(60), - summary: Faker::Lorem.sentence(3), + title: title, + summary: summary, responsible_name: Faker::Name.name, description: description, created_at: rand((Time.current - 1.week)..Time.current), @@ -37,6 +40,14 @@ section "Creating Proposals" do skip_map: "1", terms_of_service: "1", published_at: Time.now) + random_locales.map do |locale| + Globalize.with_locale(locale) do + proposal.title = "Title for locale #{locale}" + proposal.summary = "Summary for locale #{locale}" + proposal.description = "

Description for locale #{locale}

" + proposal.save! + end + end add_image_to proposal end end @@ -58,6 +69,14 @@ section "Creating Archived Proposals" do terms_of_service: "1", created_at: months_to_archive_proposals.to_i.months.ago, published_at: months_to_archive_proposals.to_i.months.ago) + random_locales.map do |locale| + Globalize.with_locale(locale) do + proposal.title = "Archived proposal title for locale #{locale}" + proposal.summary = "Archived proposal title summary for locale #{locale}" + proposal.description = "

Archived proposal description for locale #{locale}

" + proposal.save! + end + end add_image_to proposal end end @@ -79,6 +98,14 @@ section "Creating Successful Proposals" do terms_of_service: "1", cached_votes_up: Setting["votes_for_proposal_success"], published_at: Time.now) + random_locales.map do |locale| + Globalize.with_locale(locale) do + proposal.title = "Successful proposal title for locale #{locale}" + proposal.summary = "Successful proposal title summary for locale #{locale}" + proposal.description = "

Successful proposal description for locale #{locale}

" + proposal.save! + end + end add_image_to proposal end @@ -97,6 +124,14 @@ section "Creating Successful Proposals" do skip_map: "1", terms_of_service: "1", published_at: Time.now) + random_locales.map do |locale| + Globalize.with_locale(locale) do + proposal.title = "Tagged proposal title for locale #{locale}" + proposal.summary = "Tagged proposal title summary for locale #{locale}" + proposal.description = "

Tagged proposal description for locale #{locale}

" + proposal.save! + end + end add_image_to proposal end end From 5dc0f7f0547bc6614bb4e3e22c257dde8196b981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Tue, 19 Feb 2019 13:13:19 +0100 Subject: [PATCH 071/183] Add :except and :only options to translatable_params method Allow to choose among resource model translatable attributes. --- app/controllers/concerns/translatable.rb | 13 ++++++++----- app/controllers/proposals_controller.rb | 6 ++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/controllers/concerns/translatable.rb b/app/controllers/concerns/translatable.rb index 94cdcaaab..533b8db22 100644 --- a/app/controllers/concerns/translatable.rb +++ b/app/controllers/concerns/translatable.rb @@ -3,10 +3,13 @@ module Translatable private - def translation_params(resource_model) - { - translations_attributes: [:id, :_destroy, :locale] + - resource_model.translated_attribute_names - } + def translation_params(resource_model, options = {}) + attributes = [:id, :locale, :_destroy] + if options[:only] + attributes += [*options[:only]] + else + attributes += resource_model.translated_attribute_names + end + { translations_attributes: attributes - [*options[:except]] } end end diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index 9bf5dc7fd..6f35d44be 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -104,12 +104,14 @@ class ProposalsController < ApplicationController documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy], map_location_attributes: [:latitude, :longitude, :zoom]] - params.require(:proposal).permit(attributes, translation_params(Proposal)) + translations_attributes = translation_params(Proposal, except: :retired_explanation) + params.require(:proposal).permit(attributes, translations_attributes) end def retired_params attributes = [:retired_reason] - params.require(:proposal).permit(attributes, translation_params(Proposal)) + translations_attributes = translation_params(Proposal, only: :retired_explanation) + params.require(:proposal).permit(attributes, translations_attributes) end def resource_model From 4236a3a388ccd6083653f40a44c1ead620e6a0be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 25 Feb 2019 17:55:25 +0100 Subject: [PATCH 072/183] Move label translations to activerecord.yml files Moved only :es and :en translations from general.yml to activerecord.yml and use them in related forms. --- app/views/proposals/_form.html.erb | 4 +--- app/views/proposals/retire_form.html.erb | 3 +-- config/locales/en/activerecord.yml | 5 +++++ config/locales/en/general.yml | 1 - config/locales/es/activerecord.yml | 5 +++++ config/locales/es/general.yml | 1 - 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/views/proposals/_form.html.erb b/app/views/proposals/_form.html.erb index 29a72b5fd..7e12add07 100644 --- a/app/views/proposals/_form.html.erb +++ b/app/views/proposals/_form.html.erb @@ -10,7 +10,6 @@ <%= translations_form.text_field :title, maxlength: Proposal.title_max_length, placeholder: t("proposals.form.proposal_title"), - label: t("proposals.form.proposal_title"), data: { js_suggest_result: "js_suggest_result", js_suggest: ".js-suggest", js_url: suggest_proposals_path } %> @@ -32,8 +31,7 @@
<%= translations_form.cktext_area :description, maxlength: Proposal.description_max_length, - ckeditor: { language: I18n.locale }, - label: t("proposals.form.proposal_text") %> + ckeditor: { language: I18n.locale } %>
<% end %> diff --git a/app/views/proposals/retire_form.html.erb b/app/views/proposals/retire_form.html.erb index 704d2db3c..9a73c9782 100644 --- a/app/views/proposals/retire_form.html.erb +++ b/app/views/proposals/retire_form.html.erb @@ -23,10 +23,9 @@
<%= f.translatable_fields do |translations_form| %> -
+
<%= translations_form.text_area :retired_explanation, rows: 4, maxlength: 500, - label: t("proposals.retire_form.retired_explanation_label"), placeholder: t("proposals.retire_form.retired_explanation_placeholder") %>
<% end %> diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index 1ae65f7a0..8e9495564 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -192,6 +192,11 @@ en: description: "Description" selected: "Mark as selected" terms_of_service: "Terms of service" + proposal/translation: + title: "Proposal title" + description: "Proposal text" + summary: "Proposal summary" + retired_explanation: "Explanation" user: login: "Email or username" email: "Email" diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index 595723072..74b793bfd 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -332,7 +332,6 @@ en: warning: "If you retire the proposal it would still accept supports, but will be removed from the main list and a message will be visible to all users stating that the author considers the proposal should not be supported anymore" retired_reason_label: Reason to retire the proposal retired_reason_blank: Choose an option - retired_explanation_label: Explanation retired_explanation_placeholder: Explain shortly why you think this proposal should not receive more supports submit_button: Retire proposal retire_options: diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index fb3bc3138..626796cc4 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -194,6 +194,11 @@ es: description: "Descripción" selected: "Marcar como seleccionada" terms_of_service: "Términos de servicio" + proposal/translation: + title: "Título de la propuesta" + description: "Texto desarrollado de la propuesta" + summary: "Resumen de la propuesta" + retired_explanation: "Explicación" user: login: "Email o nombre de usuario" email: "Email" diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index 0f69861ae..5f7e106de 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -332,7 +332,6 @@ es: warning: "Si sigues adelante tu propuesta podrá seguir recibiendo apoyos, pero dejará de ser listada en la lista principal, y aparecerá un mensaje para todos los usuarios avisándoles de que el autor considera que esta propuesta no debe seguir recogiendo apoyos." retired_reason_label: Razón por la que se retira la propuesta retired_reason_blank: Selecciona una opción - retired_explanation_label: Explicación retired_explanation_placeholder: Explica brevemente por que consideras que esta propuesta no debe recoger más apoyos submit_button: Retirar propuesta retire_options: From 95f848f021b7480a1d121f851b4ab90466905cb7 Mon Sep 17 00:00:00 2001 From: taitus Date: Wed, 27 Mar 2019 22:41:44 +0100 Subject: [PATCH 073/183] Fix specs after rebase with translations branch - Fix spec spec/features/management/proposals_spec.rb:24 adding single quotes. - Remove spec related with 'proposal improvement info link' as master branch. - Fix proposal rake task (now proposals have translations). We put the 'validate: false' to keep the existing html tags in the proposal's description. Without the sanitizable module deleting them. --- lib/tasks/proposals.rake | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/tasks/proposals.rake b/lib/tasks/proposals.rake index 2fe3711ff..76b8a9f9d 100644 --- a/lib/tasks/proposals.rake +++ b/lib/tasks/proposals.rake @@ -11,10 +11,14 @@ namespace :proposals do print "Move external_url to description for #{model}s" model.find_each do |resource| if resource.external_url.present? - resource.update_columns(description: "#{resource.description} "\ - "

#{text_with_links(resource.external_url)}

", - external_url: "", updated_at: Time.current) - print "." + Globalize.with_locale(I18n.default_locale) do + new_description = "#{resource.description}

#{text_with_links(resource.external_url)}

" + resource.description = new_description + resource.external_url = "" + resource.updated_at = Time.current + resource.save(validate: false) + print "." + end end end puts " ✅ " From 7c137faf535a548919e2de038a0f25a2e4dc8265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 25 Feb 2019 19:11:26 +0100 Subject: [PATCH 074/183] Fix broken spec Use existing I18n translations in broken spec. --- .../site_customization/information_texts_spec.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/features/admin/site_customization/information_texts_spec.rb b/spec/features/admin/site_customization/information_texts_spec.rb index dba000a4e..c4aa9ad37 100644 --- a/spec/features/admin/site_customization/information_texts_spec.rb +++ b/spec/features/admin/site_customization/information_texts_spec.rb @@ -106,10 +106,10 @@ describe "Admin custom information texts" do value_en: "Custom debate title", value_es: "Título personalizado de debate") - second_key = "debates.form.debate_text" - debate_text = create(:i18n_content, key: second_key, - value_en: "Custom debate text", - value_es: "Texto personalizado de debate") + second_key = "debates.new.start_new" + page_title = create(:i18n_content, key: second_key, + value_en: "Start a new debate", + value_es: "Empezar un debate") visit admin_site_customization_information_texts_path(tab: "debates") @@ -121,15 +121,15 @@ describe "Admin custom information texts" do visit admin_site_customization_information_texts_path(tab: "debates") click_link "English" - expect(page).to have_content "Custom debate text" + expect(page).to have_content "Start a new debate" expect(page).to have_content "Custom debate title" debate_title.reload - debate_text.reload + page_title.reload - expect(debate_text.value_es).to be(nil) + expect(page_title.value_es).to be(nil) expect(debate_title.value_es).to be(nil) - expect(debate_text.value_en).to eq("Custom debate text") + expect(page_title.value_en).to eq("Start a new debate") expect(debate_title.value_en).to eq("Custom debate title") end end From 4068ef29eec538e5132a636b7a0575ab37f70d69 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 29 Mar 2019 16:20:13 +0100 Subject: [PATCH 075/183] Fix hidden budget investments restore feature Add recursive restore option to restore all soft deleted relations. --- app/controllers/admin/hidden_comments_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/admin/hidden_comments_controller.rb b/app/controllers/admin/hidden_comments_controller.rb index c3e3bdea9..561fe3aef 100644 --- a/app/controllers/admin/hidden_comments_controller.rb +++ b/app/controllers/admin/hidden_comments_controller.rb @@ -14,7 +14,7 @@ class Admin::HiddenCommentsController < Admin::BaseController end def restore - @comment.restore + @comment.restore(recursive: true) @comment.ignore_flag Activity.log(current_user, :restore, @comment) redirect_to request.query_parameters.merge(action: :index) From da1c5fdb01f030957721c410b30fe36beb774f75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Fri, 29 Mar 2019 15:49:11 +0100 Subject: [PATCH 076/183] Remove unneded before validation callbacks After globalize gem update there is no need to keep this monkey patch. More information here [1] [1] https://github.com/consul/consul/commit/3075c89b70354860866384185cb12bdb00f7a04e --- app/models/budget.rb | 2 -- app/models/budget/group.rb | 2 -- app/models/budget/heading.rb | 2 -- app/models/concerns/globalizable.rb | 4 ---- app/models/progress_bar.rb | 1 - 5 files changed, 11 deletions(-) diff --git a/app/models/budget.rb b/app/models/budget.rb index 133956b07..c4fe62eeb 100644 --- a/app/models/budget.rb +++ b/app/models/budget.rb @@ -22,8 +22,6 @@ class Budget < ApplicationRecord CURRENCY_SYMBOLS = %w(€ $ £ ¥).freeze - before_validation :assign_model_to_translations - validates_translation :name, presence: true validates :phase, inclusion: { in: Budget::Phase::PHASE_KINDS } validates :currency_symbol, presence: true diff --git a/app/models/budget/group.rb b/app/models/budget/group.rb index 43d28a0ae..bfa5814c5 100644 --- a/app/models/budget/group.rb +++ b/app/models/budget/group.rb @@ -22,8 +22,6 @@ class Budget has_many :headings, dependent: :destroy - before_validation :assign_model_to_translations - validates_translation :name, presence: true validates :budget_id, presence: true validates :slug, presence: true, format: /\A[a-z0-9\-_]+\z/ diff --git a/app/models/budget/heading.rb b/app/models/budget/heading.rb index 7b33c4e54..108e07fa8 100644 --- a/app/models/budget/heading.rb +++ b/app/models/budget/heading.rb @@ -26,8 +26,6 @@ class Budget has_many :investments has_many :content_blocks - before_validation :assign_model_to_translations - validates_translation :name, presence: true validates :group_id, presence: true validates :price, presence: true diff --git a/app/models/concerns/globalizable.rb b/app/models/concerns/globalizable.rb index a225c9236..15db83919 100644 --- a/app/models/concerns/globalizable.rb +++ b/app/models/concerns/globalizable.rb @@ -9,10 +9,6 @@ module Globalizable translations.reject(&:_destroy).map(&:locale) end - def assign_model_to_translations - translations.each { |translation| translation.globalized_model = self } - end - def description self.read_attribute(:description).try :html_safe end diff --git a/app/models/progress_bar.rb b/app/models/progress_bar.rb index c0bacc7ba..e9994f011 100644 --- a/app/models/progress_bar.rb +++ b/app/models/progress_bar.rb @@ -18,7 +18,6 @@ class ProgressBar < ApplicationRecord } validates :percentage, presence: true, inclusion: RANGE, numericality: { only_integer: true } - before_validation :assign_model_to_translations validates_translation :title, presence: true, unless: :primary? end From c2f393276af6acc99594b89a1788b6336e4fa421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 1 Apr 2019 11:39:23 +0200 Subject: [PATCH 077/183] Move Translation class inside Budget::Group The reason to move Translation class is explained here [1] [1] https://github.com/consul/consul/pull/3359/commits/106649a8a598fb4b1389e174fdd6e70f51767af2 --- app/models/budget/group.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/models/budget/group.rb b/app/models/budget/group.rb index bfa5814c5..741040c78 100644 --- a/app/models/budget/group.rb +++ b/app/models/budget/group.rb @@ -40,5 +40,18 @@ class Budget slug.nil? || budget.drafting? end + class Translation < Globalize::ActiveRecord::Translation + delegate :budget, to: :globalized_model + + validate :name_uniqueness_by_budget + + def name_uniqueness_by_budget + if budget.groups.joins(:translations) + .where(name: name) + .where.not("budget_group_translations.budget_group_id": budget_group_id).any? + errors.add(:name, I18n.t("errors.messages.taken")) + end + end + end end end From 27f6c8804f813078b513d9fd38f118b6e04961da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 1 Apr 2019 11:42:58 +0200 Subject: [PATCH 078/183] Move Translation class inside Budget::Heading The reason to move Translation class is explained here [1] [1] https://github.com/consul/consul/pull/3359/commits/106649a8a598fb4b1389e174fdd6e70f51767af2 --- app/models/budget/heading.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/models/budget/heading.rb b/app/models/budget/heading.rb index 108e07fa8..0221061d7 100644 --- a/app/models/budget/heading.rb +++ b/app/models/budget/heading.rb @@ -60,5 +60,19 @@ class Budget slug.nil? || budget.drafting? end + class Translation < Globalize::ActiveRecord::Translation + delegate :budget, to: :globalized_model + + validate :name_uniqueness_by_budget + + def name_uniqueness_by_budget + if budget.headings + .joins(:translations) + .where(name: name) + .where.not("budget_heading_translations.budget_heading_id": budget_heading_id).any? + errors.add(:name, I18n.t("errors.messages.taken")) + end + end + end end end From 3b03e583f953ad115c85151004a446ada50c59c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 1 Apr 2019 11:44:50 +0200 Subject: [PATCH 079/183] Move Translation class inside Budget::Phase The reason to move Translation class is explained here [1] [1] https://github.com/consul/consul/pull/3359/commits/106649a8a598fb4b1389e174fdd6e70f51767af2 --- app/models/budget/phase.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/models/budget/phase.rb b/app/models/budget/phase.rb index 125368ccd..5d28e65ab 100644 --- a/app/models/budget/phase.rb +++ b/app/models/budget/phase.rb @@ -100,5 +100,14 @@ class Budget PHASE_KINDS.index(kind) >= PHASE_KINDS.index(phase) end + class Translation < Globalize::ActiveRecord::Translation + before_validation :sanitize_description + + private + + def sanitize_description + self.description = WYSIWYGSanitizer.new.sanitize(description) + end + end end end From 0011a0b4c7ddc83dcbab239f16df43814c4b0ab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 1 Apr 2019 11:59:11 +0200 Subject: [PATCH 080/183] Move Translation class inside Budget The reason to move Translation class is explained here [1] [1] https://github.com/consul/consul/pull/3359/commits/106649a8a598fb4b1389e174fdd6e70f51767af2 --- app/models/budget.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/models/budget.rb b/app/models/budget.rb index c4fe62eeb..4904f3923 100644 --- a/app/models/budget.rb +++ b/app/models/budget.rb @@ -229,4 +229,16 @@ class Budget < ApplicationRecord slug.nil? || drafting? end + class Translation < Globalize::ActiveRecord::Translation + validate :name_uniqueness_by_budget + + def name_uniqueness_by_budget + if Budget.joins(:translations) + .where(name: name) + .where.not("budget_translations.budget_id": budget_id).any? + errors.add(:name, I18n.t("errors.messages.taken")) + end + end + end + end From 8c2f1b894dcb52d79731d19b83a4f291f386599c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Fri, 5 Apr 2019 16:05:05 +0200 Subject: [PATCH 081/183] Add controller concern to initialize Globalize fallbacks Ensure to initialize all requests including this concern into all application base controllers. --- app/controllers/application_controller.rb | 6 +----- app/controllers/concerns/globalize_fallbacks.rb | 13 +++++++++++++ app/controllers/management/base_controller.rb | 1 + app/controllers/management/sessions_controller.rb | 1 + 4 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 app/controllers/concerns/globalize_fallbacks.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 794dcd26b..5451451ff 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,6 +1,7 @@ require "application_responder" class ApplicationController < ActionController::Base + include GlobalizeFallbacks include HasFilters include HasOrders include AccessDeniedHandler @@ -14,7 +15,6 @@ class ApplicationController < ActionController::Base before_action :track_email_campaign before_action :set_return_url before_action :set_current_user - before_action :set_fallbacks_to_all_available_locales check_authorization unless: :devise_controller? self.responder = ApplicationResponder @@ -124,8 +124,4 @@ class ApplicationController < ActionController::Base def set_current_user User.current_user = current_user end - - def set_fallbacks_to_all_available_locales - Globalize.set_fallbacks_to_all_available_locales - end end diff --git a/app/controllers/concerns/globalize_fallbacks.rb b/app/controllers/concerns/globalize_fallbacks.rb new file mode 100644 index 000000000..386bb3ae1 --- /dev/null +++ b/app/controllers/concerns/globalize_fallbacks.rb @@ -0,0 +1,13 @@ +module GlobalizeFallbacks + extend ActiveSupport::Concern + + included do + before_action :initialize_globalize_fallbacks + end + + private + + def initialize_globalize_fallbacks + Globalize.set_fallbacks_to_all_available_locales + end +end diff --git a/app/controllers/management/base_controller.rb b/app/controllers/management/base_controller.rb index 4314b2aa7..9f45fab39 100644 --- a/app/controllers/management/base_controller.rb +++ b/app/controllers/management/base_controller.rb @@ -1,4 +1,5 @@ class Management::BaseController < ActionController::Base + include GlobalizeFallbacks layout "management" before_action :verify_manager diff --git a/app/controllers/management/sessions_controller.rb b/app/controllers/management/sessions_controller.rb index a88c1de9f..83e364e00 100644 --- a/app/controllers/management/sessions_controller.rb +++ b/app/controllers/management/sessions_controller.rb @@ -1,6 +1,7 @@ require "manager_authenticator" class Management::SessionsController < ActionController::Base + include GlobalizeFallbacks include AccessDeniedHandler def create From eefb9ca4f7536d9954dd963b9e7a5065bd85d7f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sun, 23 Dec 2018 00:25:23 +0100 Subject: [PATCH 082/183] Add budget investment translations Also fix sort_by_title method [1] [1] Use ruby sort instead of active record order scope because Globalize does not provide a way to search over all available fallbacks when translation for current locale does not exist. --- app/models/budget/investment.rb | 19 ++++--- ...4002_add_budget_investment_translations.rb | 15 ++++++ db/schema.rb | 11 ++++ spec/models/budget/investment_spec.rb | 52 +++++++++++++++++-- 4 files changed, 85 insertions(+), 12 deletions(-) create mode 100644 db/migrate/20181214094002_add_budget_investment_translations.rb diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index 1ef54653e..1a3516199 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -28,6 +28,10 @@ class Budget extend DownloadSettings::BudgetInvestmentCsv + translates :title, touch: true + translates :description, touch: true + include Globalizable + belongs_to :author, -> { with_hidden }, class_name: "User", foreign_key: "author_id" belongs_to :heading belongs_to :group @@ -48,15 +52,13 @@ class Budget delegate :name, :email, to: :author, prefix: true - validates :title, presence: true + validates_translation :title, presence: true, length: { in: 4..Budget::Investment.title_max_length } + validates_translation :description, presence: true, length: { maximum: Budget::Investment.description_max_length } + validates :author, presence: true - validates :description, presence: true validates :heading_id, presence: true validates :unfeasibility_explanation, presence: { if: :unfeasibility_explanation_required? } validates :price, presence: { if: :price_required? } - - validates :title, length: { in: 4..Budget::Investment.title_max_length } - validates :description, length: { maximum: Budget::Investment.description_max_length } validates :terms_of_service, acceptance: { allow_nil: false }, on: :create scope :sort_by_confidence_score, -> { reorder(confidence_score: :desc, id: :desc) } @@ -64,7 +66,6 @@ class Budget scope :sort_by_price, -> { reorder(price: :desc, confidence_score: :desc, id: :desc) } scope :sort_by_id, -> { order("id DESC") } - scope :sort_by_title, -> { order("title ASC") } scope :sort_by_supports, -> { order("cached_votes_up DESC") } scope :valuation_open, -> { where(valuation_finished: false) } @@ -117,6 +118,10 @@ class Budget budget_investment_path(budget, self) end + def self.sort_by_title + all.sort_by(&:title) + end + def self.filter_params(params) params.permit(%i[heading_id group_id administrator_id tag_name valuator_id]) end @@ -187,7 +192,7 @@ class Budget if title_or_id =~ /^[0-9]+$/ results.where(id: title_or_id) else - results.where("title ILIKE ?", "%#{title_or_id}%") + results.with_translations(I18n.locale).where("budget_investment_translations.title ILIKE ?", "%#{title_or_id}%") end end diff --git a/db/migrate/20181214094002_add_budget_investment_translations.rb b/db/migrate/20181214094002_add_budget_investment_translations.rb new file mode 100644 index 000000000..a2da96021 --- /dev/null +++ b/db/migrate/20181214094002_add_budget_investment_translations.rb @@ -0,0 +1,15 @@ +class AddBudgetInvestmentTranslations < ActiveRecord::Migration[4.2] + def self.up + Budget::Investment.create_translation_table!( + { + title: :string, + description: :text + }, + { migrate_data: true } + ) + end + + def self.down + Budget::Investment.drop_translation_table! + end +end diff --git a/db/schema.rb b/db/schema.rb index fc97b55bb..977c14f95 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -234,6 +234,17 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.index ["hidden_at"], name: "index_budget_investment_statuses_on_hidden_at", using: :btree end + create_table "budget_investment_translations", force: :cascade do |t| + t.integer "budget_investment_id", null: false + t.string "locale", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "title" + t.text "description" + t.index ["budget_investment_id"], name: "index_budget_investment_translations_on_budget_investment_id", using: :btree + t.index ["locale"], name: "index_budget_investment_translations_on_locale", using: :btree + end + create_table "budget_investments", force: :cascade do |t| t.integer "author_id" t.integer "administrator_id" diff --git a/spec/models/budget/investment_spec.rb b/spec/models/budget/investment_spec.rb index 439938eff..e021f8f04 100644 --- a/spec/models/budget/investment_spec.rb +++ b/spec/models/budget/investment_spec.rb @@ -5,6 +5,8 @@ describe Budget::Investment do describe "Concerns" do it_behaves_like "notifiable" + it_behaves_like "globalizable", :budget_investment + it_behaves_like "acts as imageable", :budget_investment_image end it "is valid" do @@ -33,12 +35,38 @@ describe Budget::Investment do end end - it_behaves_like "acts as imageable", "budget_investment_image" + describe "#description" do + it "is sanitized" do + investment.description = "" - it "sanitizes description" do - investment.description = "" - investment.valid? - expect(investment.description).to eq("alert('danger');") + investment.valid? + + expect(investment.description).to eq("alert('danger');") + end + + it "is sanitized using globalize accessors" do + investment.description_en = "" + + investment.valid? + + expect(investment.description_en).to eq("alert('danger');") + end + + it "is html_safe" do + investment.description = "" + + investment.valid? + + expect(investment.description).to be_html_safe + end + + it "is html_safe using globalize accessors" do + investment.description_en = "" + + investment.valid? + + expect(investment.description_en).to be_html_safe + end end it "set correct group and budget ids" do @@ -549,6 +577,20 @@ describe Budget::Investment do expect(described_class.unselected.sort).to eq [unselected_undecided_investment, unselected_feasible_investment].sort end end + + describe "sort_by_title" do + it "should take into consideration title fallbacks when there is no + translation for current locale" do + english_investment = create(:budget_investment, :selected, title: "English title") + spanish_investment = Globalize.with_locale(:es) do + I18n.with_locale(:es) do + create(:budget_investment, :selected, title: "Título en español") + end + end + + expect(described_class.sort_by_title).to eq [english_investment, spanish_investment] + end + end end describe "apply_filters_and_search" do From 66f885f8e43313927cfb7a70e3e2f8f80e233b0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 18 Feb 2019 17:27:01 +0100 Subject: [PATCH 083/183] Rename deprecated attributes in budget investments To avoid deprecation warning thrown by Globalize after gem update. We are going to keep these attributes with different names until next release when we will be able to destroy them. --- ...name_old_translatable_attibutes_in_budget_investments.rb | 6 ++++++ db/schema.rb | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20190218162141_rename_old_translatable_attibutes_in_budget_investments.rb diff --git a/db/migrate/20190218162141_rename_old_translatable_attibutes_in_budget_investments.rb b/db/migrate/20190218162141_rename_old_translatable_attibutes_in_budget_investments.rb new file mode 100644 index 000000000..e1ab58d7a --- /dev/null +++ b/db/migrate/20190218162141_rename_old_translatable_attibutes_in_budget_investments.rb @@ -0,0 +1,6 @@ +class RenameOldTranslatableAttibutesInBudgetInvestments < ActiveRecord::Migration[4.2] + def change + rename_column :budget_investments, :title, :deprecated_title + rename_column :budget_investments, :description, :deprecated_description + end +end diff --git a/db/schema.rb b/db/schema.rb index 977c14f95..383c0c078 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -248,8 +248,8 @@ ActiveRecord::Schema.define(version: 20190607160900) do create_table "budget_investments", force: :cascade do |t| t.integer "author_id" t.integer "administrator_id" - t.string "title" - t.text "description" + t.string "deprecated_title" + t.text "deprecated_description" t.string "external_url" t.bigint "price" t.string "feasibility", limit: 15, default: "undecided" From bb2ee6dd3c3a9cedc2340503c7fac36d91b787c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 18 Feb 2019 16:51:22 +0100 Subject: [PATCH 084/183] Fix search_by_title_or_id method Results were not including records without translations for current locale (I18n.locale). Now we search for given title against all translation fallbacks for current locale. --- app/models/budget/investment.rb | 13 ++++++----- .../features/admin/budget_investments_spec.rb | 22 ++++++++++++++----- spec/models/budget/investment_spec.rb | 22 ++++++++++++++++++- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index 1a3516199..cf25dc47d 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -119,7 +119,9 @@ class Budget end def self.sort_by_title - all.sort_by(&:title) + includes(:translations). + with_locales(Globalize.fallbacks(I18n.locale)). + order("budget_investment_translations.title ASC") end def self.filter_params(params) @@ -189,11 +191,10 @@ class Budget end def self.search_by_title_or_id(title_or_id, results) - if title_or_id =~ /^[0-9]+$/ - results.where(id: title_or_id) - else - results.with_translations(I18n.locale).where("budget_investment_translations.title ILIKE ?", "%#{title_or_id}%") - end + return results.where(id: title_or_id) if title_or_id =~ /^[0-9]+$/ + + results.with_translations(Globalize.fallbacks(I18n.locale)). + where("budget_investment_translations.title ILIKE ?", "%#{title_or_id}%") end def searchable_values diff --git a/spec/features/admin/budget_investments_spec.rb b/spec/features/admin/budget_investments_spec.rb index 1c8b14073..829adbff1 100644 --- a/spec/features/admin/budget_investments_spec.rb +++ b/spec/features/admin/budget_investments_spec.rb @@ -826,33 +826,43 @@ describe "Admin budget investments" do end before do - create(:budget_investment, title: "Some investment", budget: budget) + I18n.with_locale(:es) do + Globalize.with_locale(:es) do + create(:budget_investment, title: "Proyecto de inversión", budget: budget) + end + end end scenario "Search investments by title" do visit admin_budget_budget_investments_path(budget) - expect(page).to have_content("Some investment") + expect(page).to have_content("Proyecto de inversión") expect(page).to have_content("Some other investment") - fill_in "title_or_id", with: "Some investment" + fill_in "title_or_id", with: "Proyecto de inversión" click_button "Filter" - expect(page).to have_content("Some investment") + expect(page).to have_content("Proyecto de inversión") expect(page).not_to have_content("Some other investment") + + fill_in "title_or_id", with: "Some other investment" + click_button "Filter" + + expect(page).not_to have_content("Proyecto de inversión") + expect(page).to have_content("Some other investment") end scenario "Search investments by ID" do visit admin_budget_budget_investments_path(budget) - expect(page).to have_content("Some investment") + expect(page).to have_content("Proyecto de inversión") expect(page).to have_content("Some other investment") fill_in "title_or_id", with: first_investment.id click_button "Filter" expect(page).to have_content("Some other investment") - expect(page).not_to have_content("Some investment") + expect(page).not_to have_content("Proyecto de inversión") end end diff --git a/spec/models/budget/investment_spec.rb b/spec/models/budget/investment_spec.rb index e021f8f04..579476b55 100644 --- a/spec/models/budget/investment_spec.rb +++ b/spec/models/budget/investment_spec.rb @@ -585,10 +585,30 @@ describe Budget::Investment do spanish_investment = Globalize.with_locale(:es) do I18n.with_locale(:es) do create(:budget_investment, :selected, title: "Título en español") + + describe "search_by_title_or_id" do + before { create(:budget_investment) } + + let!(:investment) do + I18n.with_locale(:es) do + Globalize.with_locale(:es) do + create(:budget_investment, + title_es: "Título del proyecto de inversión", + description_es: "Descripción del proyecto de inversión") end end + end - expect(described_class.sort_by_title).to eq [english_investment, spanish_investment] + let(:all_investments) { described_class.all } + + it "return investment by given id" do + expect(described_class.search_by_title_or_id(investment.id.to_s, all_investments)). + to eq([investment]) + end + + it "return investments by given title" do + expect(described_class.search_by_title_or_id("Título del proyecto de inversión", all_investments)). + to eq([investment]) end end end From eb2e402a924020533e4d06a8acef6def93cb3b69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 21 Feb 2019 16:24:15 +0100 Subject: [PATCH 085/183] Fix budget investments sorting by title As we cannot order budget investments by any translatable field through AR queries we are doing the same using ruby Array sort method and doing array pagination manually with Kaminari 'paginate_array' helper method. --- .../admin/budget_investments_controller.rb | 5 ++--- app/models/budget/investment.rb | 10 +++++----- app/models/concerns/globalizable.rb | 2 ++ spec/models/budget/investment_spec.rb | 17 +++++++++++++++-- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/app/controllers/admin/budget_investments_controller.rb b/app/controllers/admin/budget_investments_controller.rb index c1bfbcf35..31f7575df 100644 --- a/app/controllers/admin/budget_investments_controller.rb +++ b/app/controllers/admin/budget_investments_controller.rb @@ -81,9 +81,8 @@ class Admin::BudgetInvestmentsController < Admin::BaseController end def load_investments - @investments = Budget::Investment.scoped_filter(params, @current_filter) - .order_filter(params) - + @investments = Budget::Investment.scoped_filter(params, @current_filter).order_filter(params) + @investments = Kaminari.paginate_array(@investments) if @investments.kind_of?(Array) @investments = @investments.page(params[:page]) unless request.format.csv? end diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index cf25dc47d..15bb3a2f4 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -1,7 +1,7 @@ class Budget require "csv" class Investment < ApplicationRecord - SORTING_OPTIONS = {id: "id", title: "title", supports: "cached_votes_up"}.freeze + SORTING_OPTIONS = { id: "id", supports: "cached_votes_up" }.freeze include ActiveModel::Dirty include Rails.application.routes.url_helpers @@ -119,9 +119,7 @@ class Budget end def self.sort_by_title - includes(:translations). - with_locales(Globalize.fallbacks(I18n.locale)). - order("budget_investment_translations.title ASC") + with_translation.sort_by(&:title) end def self.filter_params(params) @@ -169,10 +167,12 @@ class Budget def self.order_filter(params) sorting_key = params[:sort_by]&.downcase&.to_sym allowed_sort_option = SORTING_OPTIONS[sorting_key] + direction = params[:direction] == "desc" ? "desc" : "asc" if allowed_sort_option.present? - direction = params[:direction] == "desc" ? "desc" : "asc" order("#{allowed_sort_option} #{direction}") + elsif sorting_key == :title + direction == "asc" ? sort_by_title : sort_by_title.reverse else order(cached_votes_up: :desc).order(id: :desc) end diff --git a/app/models/concerns/globalizable.rb b/app/models/concerns/globalizable.rb index 15db83919..e511e5cd5 100644 --- a/app/models/concerns/globalizable.rb +++ b/app/models/concerns/globalizable.rb @@ -17,6 +17,8 @@ module Globalizable translation_class.send :acts_as_paranoid, column: :hidden_at end + scope :with_translation, -> { joins("LEFT OUTER JOIN #{translations_table_name} ON #{table_name}.id = #{translations_table_name}.#{reflections["translations"].foreign_key} AND #{translations_table_name}.locale='#{I18n.locale }'") } + private def searchable_globalized_values diff --git a/spec/models/budget/investment_spec.rb b/spec/models/budget/investment_spec.rb index 579476b55..de83e4404 100644 --- a/spec/models/budget/investment_spec.rb +++ b/spec/models/budget/investment_spec.rb @@ -579,12 +579,25 @@ describe Budget::Investment do end describe "sort_by_title" do + it "sorts using the title in the current locale" do + create(:budget_investment, title_en: "CCCC", title_es: "BBBB", description_en: "CCCC", description_es: "BBBB") + create(:budget_investment, title_en: "DDDD", title_es: "AAAA", description_en: "DDDD", description_es: "AAAA") + + expect(described_class.sort_by_title.map(&:title)).to eq %w[CCCC DDDD] + end + it "should take into consideration title fallbacks when there is no translation for current locale" do - english_investment = create(:budget_investment, :selected, title: "English title") + english_investment = create(:budget_investment, title: "BBBB") spanish_investment = Globalize.with_locale(:es) do I18n.with_locale(:es) do - create(:budget_investment, :selected, title: "Título en español") + create(:budget_investment, title: "AAAA") + end + end + + expect(described_class.sort_by_title.map(&:title)).to eq %w[AAAA BBBB] + end + end describe "search_by_title_or_id" do before { create(:budget_investment) } From 88ce8d799027071fcc8300cffd446b793bc1b6d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sun, 23 Dec 2018 01:08:13 +0100 Subject: [PATCH 086/183] Add sanitization shared spec to budget investment --- spec/models/budget/investment_spec.rb | 35 +-------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/spec/models/budget/investment_spec.rb b/spec/models/budget/investment_spec.rb index de83e4404..65865b211 100644 --- a/spec/models/budget/investment_spec.rb +++ b/spec/models/budget/investment_spec.rb @@ -5,6 +5,7 @@ describe Budget::Investment do describe "Concerns" do it_behaves_like "notifiable" + it_behaves_like "sanitizable" it_behaves_like "globalizable", :budget_investment it_behaves_like "acts as imageable", :budget_investment_image end @@ -35,40 +36,6 @@ describe Budget::Investment do end end - describe "#description" do - it "is sanitized" do - investment.description = "" - - investment.valid? - - expect(investment.description).to eq("alert('danger');") - end - - it "is sanitized using globalize accessors" do - investment.description_en = "" - - investment.valid? - - expect(investment.description_en).to eq("alert('danger');") - end - - it "is html_safe" do - investment.description = "" - - investment.valid? - - expect(investment.description).to be_html_safe - end - - it "is html_safe using globalize accessors" do - investment.description_en = "" - - investment.valid? - - expect(investment.description_en).to be_html_safe - end - end - it "set correct group and budget ids" do budget = create(:budget) group_1 = create(:budget_group, budget: budget) From 5eb5f02cbe252749ac07794b9795dc0def4a5c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Fri, 25 Jan 2019 11:50:57 +0100 Subject: [PATCH 087/183] Fix budget investment specs After adding investment translatable fields to forms, they will be generated with nested translations names and ids so we can no longer use standard id locator. Using input label text to fill in fields works with both types of forms. --- .../features/admin/budget_investments_spec.rb | 6 ++--- spec/features/budgets/investments_spec.rb | 18 +++++++------- spec/features/emails_spec.rb | 4 ++-- .../management/budget_investments_spec.rb | 4 ++-- spec/features/tags/budget_investments_spec.rb | 24 +++++++++---------- spec/shared/features/mappable.rb | 4 ++-- spec/shared/features/nested_documentable.rb | 4 ++-- spec/shared/features/nested_imageable.rb | 4 ++-- 8 files changed, 34 insertions(+), 34 deletions(-) diff --git a/spec/features/admin/budget_investments_spec.rb b/spec/features/admin/budget_investments_spec.rb index 829adbff1..6b40587a2 100644 --- a/spec/features/admin/budget_investments_spec.rb +++ b/spec/features/admin/budget_investments_spec.rb @@ -1102,8 +1102,8 @@ describe "Admin budget investments" do visit admin_budget_budget_investment_path(budget_investment.budget, budget_investment) click_link "Edit" - fill_in "budget_investment_title", with: "Potatoes" - fill_in "budget_investment_description", with: "Carrots" + fill_in "Title", with: "Potatoes" + fill_in "Description", with: "Carrots" select "#{budget_investment.group.name}: Barbate", from: "budget_investment[heading_id]" uncheck "budget_investment_incompatible" check "budget_investment_selected" @@ -1365,7 +1365,7 @@ describe "Admin budget investments" do visit admin_budget_budget_investment_path(budget_investment.budget, budget_investment) click_link "Edit" - fill_in "budget_investment_title", with: "" + fill_in "Title", with: "" click_button "Update" diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb index 50c0e4d07..eed55a159 100644 --- a/spec/features/budgets/investments_spec.rb +++ b/spec/features/budgets/investments_spec.rb @@ -860,9 +860,9 @@ describe "Budget Investments" do visit new_budget_investment_path(budget) select heading.name, from: "budget_investment_heading_id" - fill_in "budget_investment_title", with: "I am a bot" + fill_in "Title", with: "I am a bot" fill_in "budget_investment_subtitle", with: "This is the honeypot" - fill_in "budget_investment_description", with: "This is the description" + fill_in "Description", with: "This is the description" check "budget_investment_terms_of_service" click_button "Create Investment" @@ -879,8 +879,8 @@ describe "Budget Investments" do visit new_budget_investment_path(budget) select heading.name, from: "budget_investment_heading_id" - fill_in "budget_investment_title", with: "I am a bot" - fill_in "budget_investment_description", with: "This is the description" + fill_in "Title", with: "I am a bot" + fill_in "Description", with: "This is the description" check "budget_investment_terms_of_service" click_button "Create Investment" @@ -895,8 +895,8 @@ describe "Budget Investments" do visit new_budget_investment_path(budget) select heading.name, from: "budget_investment_heading_id" - fill_in "budget_investment_title", with: "Build a skyscraper" - fill_in "budget_investment_description", with: "I want to live in a high tower over the clouds" + fill_in "Title", with: "Build a skyscraper" + fill_in "Description", with: "I want to live in a high tower over the clouds" fill_in "budget_investment_location", with: "City center" fill_in "budget_investment_organization_name", with: "T.I.A." fill_in "budget_investment_tag_list", with: "Towers" @@ -936,7 +936,7 @@ describe "Budget Investments" do create(factory, title: "This is the last #{factory}", budget: budget) visit new_budget_investment_path(budget) - fill_in "budget_investment_title", with: "search" + fill_in "Title", with: "search" within("div#js-suggest") do expect(page).to have_content "You are seeing 5 of 6 investments containing the term 'search'" @@ -951,7 +951,7 @@ describe "Budget Investments" do end visit new_budget_investment_path(budget) - fill_in "budget_investment_title", with: "item" + fill_in "Title", with: "item" within("div#js-suggest") do expect(page).not_to have_content "You are seeing" @@ -966,7 +966,7 @@ describe "Budget Investments" do end visit new_budget_investment_path(other_budget) - fill_in "budget_investment_title", with: "search" + fill_in "Title", with: "search" within("div#js-suggest") do expect(page).not_to have_content "You are seeing" diff --git a/spec/features/emails_spec.rb b/spec/features/emails_spec.rb index ce98a6bb2..975a3c536 100644 --- a/spec/features/emails_spec.rb +++ b/spec/features/emails_spec.rb @@ -365,8 +365,8 @@ describe "Emails" do visit new_budget_investment_path(budget_id: budget.id) select heading.name, from: "budget_investment_heading_id" - fill_in "budget_investment_title", with: "Build a hospital" - fill_in "budget_investment_description", with: "We have lots of people that require medical attention" + fill_in "Title", with: "Build a hospital" + fill_in "Description", with: "We have lots of people that require medical attention" check "budget_investment_terms_of_service" click_button "Create Investment" diff --git a/spec/features/management/budget_investments_spec.rb b/spec/features/management/budget_investments_spec.rb index 14297ab41..9e53da5a3 100644 --- a/spec/features/management/budget_investments_spec.rb +++ b/spec/features/management/budget_investments_spec.rb @@ -66,8 +66,8 @@ describe "Budget Investments" do end select "Health", from: "budget_investment_heading_id" - fill_in "budget_investment_title", with: "Build a park in my neighborhood" - fill_in "budget_investment_description", with: "There is no parks here..." + fill_in "Title", with: "Build a park in my neighborhood" + fill_in "Description", with: "There is no parks here..." fill_in "budget_investment_location", with: "City center" fill_in "budget_investment_organization_name", with: "T.I.A." fill_in "budget_investment_tag_list", with: "green" diff --git a/spec/features/tags/budget_investments_spec.rb b/spec/features/tags/budget_investments_spec.rb index a0fb60339..836e4d4fd 100644 --- a/spec/features/tags/budget_investments_spec.rb +++ b/spec/features/tags/budget_investments_spec.rb @@ -67,8 +67,8 @@ describe "Tags" do visit new_budget_investment_path(budget_id: budget.id) select heading.name, from: "budget_investment_heading_id" - fill_in "budget_investment_title", with: "Build a skyscraper" - fill_in "budget_investment_description", with: "I want to live in a high tower over the clouds" + fill_in "Title", with: "Build a skyscraper" + fill_in "Description", with: "I want to live in a high tower over the clouds" check "budget_investment_terms_of_service" fill_in "budget_investment_tag_list", with: "#{tag_medio_ambiente.name}, #{tag_economia.name}" @@ -86,8 +86,8 @@ describe "Tags" do visit new_budget_investment_path(budget_id: budget.id) select heading.name, from: "budget_investment_heading_id" - fill_in "budget_investment_title", with: "Build a skyscraper" - fill_in_ckeditor "budget_investment_description", with: "If I had a gym near my place I could go do Zumba" + fill_in "Title", with: "Build a skyscraper" + fill_in_ckeditor "Description", with: "If I had a gym near my place I could go do Zumba" check "budget_investment_terms_of_service" find(".js-add-tag-link", text: tag_economia.name).click @@ -111,8 +111,8 @@ describe "Tags" do click_link "Create a budget investment" select heading.name, from: "budget_investment_heading_id" - fill_in "budget_investment_title", with: "Build a skyscraper" - fill_in_ckeditor "budget_investment_description", with: "If I had a gym near my place I could go do Zumba" + fill_in "Title", with: "Build a skyscraper" + fill_in_ckeditor "Description", with: "If I had a gym near my place I could go do Zumba" check "budget_investment_terms_of_service" find(".js-add-tag-link", text: "Education").click @@ -136,8 +136,8 @@ describe "Tags" do click_link "Create a budget investment" select heading.name, from: "budget_investment_heading_id" - fill_in "budget_investment_title", with: "Build a skyscraper" - fill_in_ckeditor "budget_investment_description", with: "If I had a gym near my place I could go do Zumba" + fill_in "Title", with: "Build a skyscraper" + fill_in_ckeditor "Description", with: "If I had a gym near my place I could go do Zumba" check "budget_investment_terms_of_service" find(".js-add-tag-link", text: "Education").click @@ -157,8 +157,8 @@ describe "Tags" do visit new_budget_investment_path(budget_id: budget.id) select heading.name, from: "budget_investment_heading_id" - fill_in "budget_investment_title", with: "Build a skyscraper" - fill_in "budget_investment_description", with: "I want to live in a high tower over the clouds" + fill_in "Title", with: "Build a skyscraper" + fill_in "Description", with: "I want to live in a high tower over the clouds" check "budget_investment_terms_of_service" fill_in "budget_investment_tag_list", with: "Impuestos, Economía, Hacienda, Sanidad, Educación, Política, Igualdad" @@ -175,8 +175,8 @@ describe "Tags" do visit new_budget_investment_path(budget_id: budget.id) select heading.name, from: "budget_investment_heading_id" - fill_in "budget_investment_title", with: "Build a skyscraper" - fill_in "budget_investment_description", with: "I want to live in a high tower over the clouds" + fill_in "Title", with: "Build a skyscraper" + fill_in "Description", with: "I want to live in a high tower over the clouds" check "budget_investment_terms_of_service" fill_in "budget_investment_tag_list", with: "user_id=1, &a=3, " diff --git a/spec/shared/features/mappable.rb b/spec/shared/features/mappable.rb index eb426bc34..e9fff3662 100644 --- a/spec/shared/features/mappable.rb +++ b/spec/shared/features/mappable.rb @@ -271,8 +271,8 @@ end def fill_in_budget_investment_form page.select mappable.heading.name_scoped_by_group, from: :budget_investment_heading_id - fill_in :budget_investment_title, with: "Budget investment title" - fill_in_ckeditor "budget_investment_description", with: "Budget investment description" + fill_in "Title", with: "Budget investment title" + fill_in_ckeditor "Description", with: "Budget investment description" check :budget_investment_terms_of_service end diff --git a/spec/shared/features/nested_documentable.rb b/spec/shared/features/nested_documentable.rb index 9111d085b..a70e29d5f 100644 --- a/spec/shared/features/nested_documentable.rb +++ b/spec/shared/features/nested_documentable.rb @@ -375,7 +375,7 @@ end def documentable_fill_new_valid_budget_investment page.select documentable.heading.name_scoped_by_group, from: :budget_investment_heading_id - fill_in :budget_investment_title, with: "Budget investment title" - fill_in_ckeditor "budget_investment_description", with: "Budget investment description" + fill_in "Title", with: "Budget investment title" + fill_in_ckeditor "Description", with: "Budget investment description" check :budget_investment_terms_of_service end diff --git a/spec/shared/features/nested_imageable.rb b/spec/shared/features/nested_imageable.rb index 41819fba6..8f0493c4c 100644 --- a/spec/shared/features/nested_imageable.rb +++ b/spec/shared/features/nested_imageable.rb @@ -296,8 +296,8 @@ end def imageable_fill_new_valid_budget_investment page.select imageable.heading.name_scoped_by_group, from: :budget_investment_heading_id - fill_in :budget_investment_title, with: "Budget investment title" - fill_in_ckeditor "budget_investment_description", with: "Budget investment description" + fill_in "Title", with: "Budget investment title" + fill_in_ckeditor "Description", with: "Budget investment description" check :budget_investment_terms_of_service end From 661ca5a5687df53af3f4c56fc542d0ae09b42fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sun, 23 Dec 2018 18:48:13 +0100 Subject: [PATCH 088/183] Add budget investments translation interface * Adapt translatable spec helper method to work with budget investments * Remove old attributes from strong parameters * Add missing locales to admin.yml and budgets.yml * Change SpendingProposal.title_max_length and SpendingProposal.description_max_lenght to Budget::Investment methods * Add budget investment translatable attribute translations --- .../admin/budget_investments_controller.rb | 7 ++-- .../budgets/investments_controller.rb | 7 ++-- .../budgets/investments_controller.rb | 5 +-- .../admin/budget_investments/edit.html.erb | 29 ++++++++------- app/views/budgets/investments/_form.html.erb | 35 +++++++++++-------- config/locales/en/activerecord.yml | 3 ++ config/locales/es/activerecord.yml | 3 ++ .../features/admin/budget_investments_spec.rb | 6 ++++ spec/shared/features/translatable.rb | 2 ++ 9 files changed, 62 insertions(+), 35 deletions(-) diff --git a/app/controllers/admin/budget_investments_controller.rb b/app/controllers/admin/budget_investments_controller.rb index 31f7575df..a5d2ee21a 100644 --- a/app/controllers/admin/budget_investments_controller.rb +++ b/app/controllers/admin/budget_investments_controller.rb @@ -3,6 +3,7 @@ class Admin::BudgetInvestmentsController < Admin::BaseController include CommentableActions include DownloadSettingsHelper include ChangeLogHelper + include Translatable feature_flag :budgets @@ -87,10 +88,10 @@ class Admin::BudgetInvestmentsController < Admin::BaseController end def budget_investment_params - params.require(:budget_investment) - .permit(:title, :description, :external_url, :heading_id, :administrator_id, :tag_list, + attributes = [:external_url, :heading_id, :administrator_id, :tag_list, :valuation_tag_list, :incompatible, :visible_to_valuators, :selected, - :milestone_tag_list, tracker_ids: [], valuator_ids: [], valuator_group_ids: []) + :milestone_tag_list, tracker_ids: [], valuator_ids: [], valuator_group_ids: []] + params.require(:budget_investment).permit(attributes, translation_params(Budget::Investment)) end def load_budget diff --git a/app/controllers/budgets/investments_controller.rb b/app/controllers/budgets/investments_controller.rb index 1aea05085..d5728e254 100644 --- a/app/controllers/budgets/investments_controller.rb +++ b/app/controllers/budgets/investments_controller.rb @@ -6,6 +6,7 @@ module Budgets include FlagActions include RandomSeed include ImageAttributes + include Translatable PER_PAGE = 10 @@ -122,12 +123,12 @@ module Budgets end def investment_params - params.require(:budget_investment) - .permit(:title, :description, :heading_id, :tag_list, + attributes = [:heading_id, :tag_list, :organization_name, :location, :terms_of_service, :skip_map, image_attributes: image_attributes, documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy], - map_location_attributes: [:latitude, :longitude, :zoom]) + map_location_attributes: [:latitude, :longitude, :zoom]] + params.require(:budget_investment).permit(attributes, translation_params(Budget::Investment)) end def load_ballot diff --git a/app/controllers/management/budgets/investments_controller.rb b/app/controllers/management/budgets/investments_controller.rb index 79a65cf15..da7bb117e 100644 --- a/app/controllers/management/budgets/investments_controller.rb +++ b/app/controllers/management/budgets/investments_controller.rb @@ -1,4 +1,5 @@ class Management::Budgets::InvestmentsController < Management::BaseController + include Translatable before_action :load_budget load_resource :budget @@ -53,8 +54,8 @@ class Management::Budgets::InvestmentsController < Management::BaseController end def investment_params - params.require(:budget_investment).permit(:title, :description, :external_url, :heading_id, - :tag_list, :organization_name, :location, :skip_map) + attributes = [:external_url, :heading_id, :tag_list, :organization_name, :location, :skip_map] + params.require(:budget_investment).permit(attributes, translation_params(Budget::Investment)) end def only_verified_users diff --git a/app/views/admin/budget_investments/edit.html.erb b/app/views/admin/budget_investments/edit.html.erb index 23e277dd1..8b94f5cac 100644 --- a/app/views/admin/budget_investments/edit.html.erb +++ b/app/views/admin/budget_investments/edit.html.erb @@ -2,24 +2,30 @@ <%= t("shared.back") %> <% end %> -<%= form_for @investment, - url: admin_budget_budget_investment_path(@budget, @investment) do |f| %> +<%= render "admin/shared/globalize_locales", resource: @investment %> + +<%= translatable_form_for @investment, + url: admin_budget_budget_investment_path(@budget, @investment) do |f| %> + + <%= render "shared/errors", resource: @investment %> <% Budget::Investment.filter_params(params).to_h.each do |filter_name, filter_value| %> <%= hidden_field_tag filter_name, filter_value %> <% end %>
-
- <%= f.text_field :title, - maxlength: Budget::Investment.title_max_length %> -
+ <%= f.translatable_fields do |translations_form| %> +
+ <%= translations_form.text_field :title, + maxlength: Budget::Investment.title_max_length %> +
-
- <%= f.cktext_area :description, - maxlength: Budget::Investment.description_max_length, - ckeditor: { language: I18n.locale } %> -
+
+ <%= translations_form.cktext_area :description, + maxlength: Budget::Investment.description_max_length, + ckeditor: { language: I18n.locale } %> +
+ <% end %>
<%= f.label :tag_list, t("admin.budget_investments.edit.user_tags") %> @@ -51,7 +57,6 @@
-
<%= f.label :valuation_tag_list, t("admin.budget_investments.edit.tags") %>
diff --git a/app/views/budgets/investments/_form.html.erb b/app/views/budgets/investments/_form.html.erb index dcc62d92d..c88caca33 100644 --- a/app/views/budgets/investments/_form.html.erb +++ b/app/views/budgets/investments/_form.html.erb @@ -1,4 +1,7 @@ -<%= form_for(@investment, url: form_url, method: :post, html: { multipart: true }) do |f| %> +<%= render "admin/shared/globalize_locales", resource: @investment %> + +<%= translatable_form_for(@investment, url: form_url, method: :post, html: { multipart: true }) do |f| %> + <%= render "shared/errors", resource: @investment %>
@@ -6,23 +9,25 @@ <%= f.select :heading_id, budget_heading_select_options(@budget), {include_blank: true, } %>
-
- <%= f.text_field :title, - maxlength: Budget::Investment.title_max_length, - data: { js_suggest_result: "js_suggest_result", - js_suggest: "#js-suggest", - js_url: suggest_budget_investments_path(@budget) } %> -
-
+ <%= f.translatable_fields do |translations_form| %> +
+ <%= translations_form.text_field :title, + maxlength: Budget::Investment.title_max_length, + data: { js_suggest_result: "js_suggest_result", + js_suggest: ".js-suggest", + js_url: suggest_budget_investments_path(@budget) }%> +
+
+ +
+ <%= translations_form.cktext_area :description, + maxlength: Budget::Investment.description_max_length, + ckeditor: { language: I18n.locale } %> +
+ <% end %> <%= f.invisible_captcha :subtitle %> -
- <%= f.cktext_area :description, - maxlength: Budget::Investment.description_max_length, - ckeditor: { language: I18n.locale } %> -
- <% if feature?(:allow_images) %>
<%= render "images/nested_image", imageable: @investment, f: f %> diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index 8e9495564..6e5f78f68 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -150,6 +150,9 @@ en: organization_name: "If you are proposing in the name of a collective/organization, or on behalf of more people, write its name" image: "Proposal descriptive image" image_title: "Image title" + budget/investment/translation: + title: "Title" + description: "Description" geozone: name: Name external_code: "External code (optional)" diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index 626796cc4..e8d8a4efb 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -152,6 +152,9 @@ es: organization_name: "Si estás proponiendo en nombre de una organización o colectivo, o en nombre de más gente, escribe su nombre" image: "Imagen descriptiva del proyecto de gasto" image_title: "Título de la imagen" + budget/investment/translation: + title: "Título" + description: "Descripción" geozone: name: Nombre external_code: "Código externo (opcional)" diff --git a/spec/features/admin/budget_investments_spec.rb b/spec/features/admin/budget_investments_spec.rb index 6b40587a2..8a45ac44f 100644 --- a/spec/features/admin/budget_investments_spec.rb +++ b/spec/features/admin/budget_investments_spec.rb @@ -11,6 +11,12 @@ describe "Admin budget investments" do :budget_investment, "admin_budget_budget_investment_path" + it_behaves_like "translatable", + :budget_investment, + "edit_admin_budget_budget_investment_path", + %w[title], + { "description" => :ckeditor } + before do @admin = create(:administrator) login_as(@admin.user) diff --git a/spec/shared/features/translatable.rb b/spec/shared/features/translatable.rb index e2aa5a8b8..9e13643dd 100644 --- a/spec/shared/features/translatable.rb +++ b/spec/shared/features/translatable.rb @@ -402,6 +402,8 @@ def update_button_text "Update milestone" when "AdminNotification" "Update notification" + when "Budget::Investment" + "Update" when "Poll" "Update poll" when "Budget" From 9a459070e901e30844cb5ced34dc702b972528ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sat, 12 Jan 2019 16:34:27 +0100 Subject: [PATCH 089/183] Fix budget investment suggest feature --- spec/features/budgets/investments_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb index eed55a159..5a0e1acca 100644 --- a/spec/features/budgets/investments_spec.rb +++ b/spec/features/budgets/investments_spec.rb @@ -938,7 +938,7 @@ describe "Budget Investments" do visit new_budget_investment_path(budget) fill_in "Title", with: "search" - within("div#js-suggest") do + within("div.js-suggest") do expect(page).to have_content "You are seeing 5 of 6 investments containing the term 'search'" end end @@ -953,7 +953,7 @@ describe "Budget Investments" do visit new_budget_investment_path(budget) fill_in "Title", with: "item" - within("div#js-suggest") do + within("div.js-suggest") do expect(page).not_to have_content "You are seeing" end end @@ -968,7 +968,7 @@ describe "Budget Investments" do visit new_budget_investment_path(other_budget) fill_in "Title", with: "search" - within("div#js-suggest") do + within("div.js-suggest") do expect(page).not_to have_content "You are seeing" end end From e8f53cb8b7feee618aa72c7479afffc86b1b620e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sat, 12 Jan 2019 17:04:58 +0100 Subject: [PATCH 090/183] Add translations to budget investments pg_search_scope Some Budget::Investment attributes are now translatable so we need to include all existing translations on pg_search model scope. --- app/models/budget/investment.rb | 13 ++++++++----- spec/models/budget/investment_spec.rb | 13 ++++++++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index 15bb3a2f4..aa83a499a 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -198,12 +198,10 @@ class Budget end def searchable_values - { title => "A", - author.username => "B", + { author.username => "B", heading.name => "B", - tag_list.join(" ") => "B", - description => "C" - } + tag_list.join(" ") => "B" + }.merge(searchable_globalized_values) end def self.search(terms) @@ -419,5 +417,10 @@ class Budget end end end + + def searchable_translations_definitions + { title => "A", + description => "D" } + end end end diff --git a/spec/models/budget/investment_spec.rb b/spec/models/budget/investment_spec.rb index 65865b211..37d015d8b 100644 --- a/spec/models/budget/investment_spec.rb +++ b/spec/models/budget/investment_spec.rb @@ -683,12 +683,23 @@ describe Budget::Investment do context "attributes" do + let(:attributes) { { title: "save the world", + description: "in order to save the world one must think about...", + title_es: "para salvar el mundo uno debe pensar en...", + description_es: "uno debe pensar" } } + it "searches by title" do - budget_investment = create(:budget_investment, title: "save the world") + budget_investment = create(:budget_investment, attributes) results = described_class.search("save the world") expect(results).to eq([budget_investment]) end + it "searches by title across all languages" do + budget_investment = create(:budget_investment, attributes) + results = described_class.search("salvar el mundo") + expect(results).to eq([budget_investment]) + end + it "searches by author name" do author = create(:user, username: "Danny Trejo") budget_investment = create(:budget_investment, author: author) From ef786d06585ae550ac2bff5db00b262820c1260c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Tue, 22 Jan 2019 12:40:24 +0100 Subject: [PATCH 091/183] Fix hidden budget investments restore feature Add recursive restore option to restore all soft deleted relations. --- app/controllers/admin/hidden_budget_investments_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/admin/hidden_budget_investments_controller.rb b/app/controllers/admin/hidden_budget_investments_controller.rb index 439f3c722..f34818361 100644 --- a/app/controllers/admin/hidden_budget_investments_controller.rb +++ b/app/controllers/admin/hidden_budget_investments_controller.rb @@ -19,7 +19,7 @@ class Admin::HiddenBudgetInvestmentsController < Admin::BaseController end def restore - @investment.restore + @investment.restore(recursive: true) @investment.ignore_flag Activity.log(current_user, :restore, @investment) redirect_to request.query_parameters.merge(action: :index) From f116477d6d5c1b9461d9349ae3381a73d0413c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Wed, 23 Jan 2019 13:24:47 +0100 Subject: [PATCH 092/183] Enable soft_deletion of Budget::Investment::Translations --- ...22113_add_hidden_at_to_budget_investment_translations.rb | 6 ++++++ db/schema.rb | 2 ++ spec/models/budget/investment_spec.rb | 1 + 3 files changed, 9 insertions(+) create mode 100644 db/migrate/20190123122113_add_hidden_at_to_budget_investment_translations.rb diff --git a/db/migrate/20190123122113_add_hidden_at_to_budget_investment_translations.rb b/db/migrate/20190123122113_add_hidden_at_to_budget_investment_translations.rb new file mode 100644 index 000000000..b3d30070f --- /dev/null +++ b/db/migrate/20190123122113_add_hidden_at_to_budget_investment_translations.rb @@ -0,0 +1,6 @@ +class AddHiddenAtToBudgetInvestmentTranslations < ActiveRecord::Migration[4.2] + def change + add_column :budget_investment_translations, :hidden_at, :datetime + add_index :budget_investment_translations, :hidden_at + end +end diff --git a/db/schema.rb b/db/schema.rb index 383c0c078..6680cbe2c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -241,7 +241,9 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.datetime "updated_at", null: false t.string "title" t.text "description" + t.datetime "hidden_at" t.index ["budget_investment_id"], name: "index_budget_investment_translations_on_budget_investment_id", using: :btree + t.index ["hidden_at"], name: "index_budget_investment_translations_on_hidden_at", using: :btree t.index ["locale"], name: "index_budget_investment_translations_on_locale", using: :btree end diff --git a/spec/models/budget/investment_spec.rb b/spec/models/budget/investment_spec.rb index 37d015d8b..7cfc17587 100644 --- a/spec/models/budget/investment_spec.rb +++ b/spec/models/budget/investment_spec.rb @@ -8,6 +8,7 @@ describe Budget::Investment do it_behaves_like "sanitizable" it_behaves_like "globalizable", :budget_investment it_behaves_like "acts as imageable", :budget_investment_image + it_behaves_like "acts as paranoid", :budget_investment end it "is valid" do From 522b1c9ef75950bcbf2e7acc558d29d382cd7c19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 24 Jan 2019 17:02:08 +0100 Subject: [PATCH 093/183] Add budget investment translations to dev_seeds Update budget investments development seeds with translations for all avaialble locales. --- db/dev_seeds/budgets.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/db/dev_seeds/budgets.rb b/db/dev_seeds/budgets.rb index f9dc8bab6..f131eba5f 100644 --- a/db/dev_seeds/budgets.rb +++ b/db/dev_seeds/budgets.rb @@ -138,6 +138,14 @@ section "Creating Investments" do terms_of_service: "1" ) + random_locales.map do |locale| + Globalize.with_locale(locale) do + investment.title = "Title for locale #{locale}" + investment.description = "

Description for locale #{locale}

" + investment.save! + end + end + add_image_to(investment) if Random.rand > 0.5 end end From 1565a5a71ddba3a9d8a09df20ce753d7e2f9b697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Tue, 19 Feb 2019 10:43:48 +0100 Subject: [PATCH 094/183] Fix most of Hound offenses --- app/views/budgets/investments/_form.html.erb | 2 +- spec/models/budget/investment_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/budgets/investments/_form.html.erb b/app/views/budgets/investments/_form.html.erb index c88caca33..dbf9cdb9e 100644 --- a/app/views/budgets/investments/_form.html.erb +++ b/app/views/budgets/investments/_form.html.erb @@ -15,7 +15,7 @@ maxlength: Budget::Investment.title_max_length, data: { js_suggest_result: "js_suggest_result", js_suggest: ".js-suggest", - js_url: suggest_budget_investments_path(@budget) }%> + js_url: suggest_budget_investments_path(@budget) } %>
diff --git a/spec/models/budget/investment_spec.rb b/spec/models/budget/investment_spec.rb index 7cfc17587..b6c471925 100644 --- a/spec/models/budget/investment_spec.rb +++ b/spec/models/budget/investment_spec.rb @@ -556,8 +556,8 @@ describe Budget::Investment do it "should take into consideration title fallbacks when there is no translation for current locale" do - english_investment = create(:budget_investment, title: "BBBB") - spanish_investment = Globalize.with_locale(:es) do + create(:budget_investment, title: "BBBB") + Globalize.with_locale(:es) do I18n.with_locale(:es) do create(:budget_investment, title: "AAAA") end From 44ef1ce5e11455f770fb87ac68450bef44a782ed Mon Sep 17 00:00:00 2001 From: taitus Date: Wed, 10 Apr 2019 17:16:22 +0200 Subject: [PATCH 095/183] Fix houncibot parse error Add missing quotes. Notification Error: warning: 2.6.0-dev-compliant syntax, but you are running 2.6.1. warning: please see https://github.com/whitequark/parser#compatibility-with-ruby-mri. 2 error(s) were found in ERB files expected attribute value after '=' (at >) --- app/views/proposals/_form.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/proposals/_form.html.erb b/app/views/proposals/_form.html.erb index 7e12add07..faeada8d6 100644 --- a/app/views/proposals/_form.html.erb +++ b/app/views/proposals/_form.html.erb @@ -18,7 +18,7 @@
<%= translations_form.label :summary %> -

> +

<%= t("proposals.form.proposal_summary_note") %>

<%= translations_form.text_area :summary, From 673fecf92a14336a9db93319eeb0e884630a2c69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 25 Apr 2019 15:32:37 +0200 Subject: [PATCH 096/183] Add "new_translatable" shared example to check creation of translatable records The existing shared example 'translatable' only works for edit actions. This shared example allow us to check how translations behaves at new resource pages. Now this shared specs only works with Proposals, Budget::Investments and Debates. --- spec/shared/features/new_translatable.rb | 241 +++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 spec/shared/features/new_translatable.rb diff --git a/spec/shared/features/new_translatable.rb b/spec/shared/features/new_translatable.rb new file mode 100644 index 000000000..c66a9770e --- /dev/null +++ b/spec/shared/features/new_translatable.rb @@ -0,0 +1,241 @@ +shared_examples "new_translatable" do |factory_name, path_name, input_fields, textarea_fields = {}| + let(:language_texts) do + { + es: "en español", + en: "in English", + fr: "en Français", + "pt-BR": "Português" + } + end + + let(:translatable_class) { build(factory_name).class } + let(:input_fields) { input_fields } # So it's accessible by methods + let(:textarea_fields) { textarea_fields } # So it's accessible by methods + let(:path_name) { path_name } # So it's accessible by methods + let(:fields) { input_fields + textarea_fields.keys } + + let(:attributes) do + fields.product(%i[en es]).map do |field, locale| + [:"#{field}_#{locale}", text_for(field, locale)] + end.to_h + end + + let(:optional_fields) do + fields.select do |field| + translatable.translations.last.dup.tap { |duplicate| duplicate.send(:"#{field}=", "") }.valid? + end + end + + let(:required_fields) do + fields - optional_fields + end + + let(:user) { create(:user, :in_census) } + + let(:translatable) do + if factory_name == "budget_phase" + budget = create(:budget) + budget.phases.last.update attributes + budget.phases.last + else + create(factory_name, attributes) + end + end + + before do + login_as(user) + end + + context "Manage translations" do + + scenario "Add only single translation at once", :js do + visit new_translatable_path + + fill_in_new_translatable_form :en + click_button create_button_text + + expect(page).to have_content(successul_operation_notice) + end + + scenario "Add single translation should persist introduced field values", :js do + visit new_translatable_path + + fill_in_new_translatable_form :en + click_button create_button_text + + check_introduced_values_at_translatable_edit_or_show_path(:en) + end + + scenario "Add multiple translations at once", :js do + visit new_translatable_path + + fill_in_new_translatable_form :en + select "Français", from: "translation_locale" + fill_in_new_translatable_form :fr + click_button create_button_text + + expect(page).to have_content(successul_operation_notice) + end + + scenario "Add only single translation at once not having the current locale", :js do + visit new_translatable_path + click_link "Remove language" + select "Français", from: "translation_locale" + + fill_in_new_translatable_form :fr + click_button create_button_text + + expect(page).to have_content(successul_operation_notice) + end + + scenario "Add a translation for a locale with non-underscored name", :js do + visit new_translatable_path + click_link "Remove language" + select "Português brasileiro", from: "translation_locale" + + fill_in_new_translatable_form :"pt-BR" + click_button create_button_text + + expect(page).to have_content(successul_operation_notice) + end + + scenario "Add an invalid translation", :js do + skip("can't have invalid translations") if required_fields.empty? + + field = required_fields.sample + + visit new_translatable_path + click_button create_button_text + + expect(page).to have_css "#error_explanation" + expect_page_to_have_translatable_field field, :en, with: "" + end + + scenario "Should show errors when submiting without any active translations", :js do + skip("can't have invalid translations") if required_fields.empty? + + visit new_translatable_path + click_link "Remove language" + click_button create_button_text + + expect(page).to have_css "#error_explanation" + end + end + + context "Globalize javascript interface" do + scenario "Highlight current locale", :js do + visit new_translatable_path + + expect(find("a.js-globalize-locale-link.is-active")).to have_content "English" + end + + scenario "Highlight new locale added", :js do + visit new_translatable_path + + select("Español", from: "locale-switcher") + + expect(find("a.js-globalize-locale-link.is-active")).to have_content "Español" + end + + scenario "Select a locale and add it to the form", :js do + visit new_translatable_path + + select "Français", from: "translation_locale" + + expect(find("a.js-globalize-locale-link.is-active")).to have_content "Français" + expect_page_to_have_translatable_field fields.sample, :fr, with: "" + end + + scenario "Remove a translation", :js do + visit new_translatable_path + + click_link "Remove language" + + expect(page).not_to have_link "English" + end + end +end + +def new_translatable_path + case translatable_class.name + when "Budget::Investment" + budget = create(:budget_heading, name: "Everywhere").group.budget + send path_name, budget + else + send path_name + end +end + +def check_introduced_values_at_translatable_edit_or_show_path(locale) + case translatable_class.name + when "Debate" || "Proposal" + click_link "Edit" + check_translatable_fields(locale) + when "Budget::Investment" + check_translatable_texts(locale) + end +end + +def check_translatable_fields(locale) + fields.each do |field| + text = text_for(field, locale) + expect_page_to_have_translatable_field(field, locale, with: text) + end +end + +def check_translatable_texts(locale) + fields.each do |field| + text = text_for(field, locale) + expect(page).to have_content text + end +end + +def fill_in_new_translatable_form(locale) + fields.each { |field| fill_in_field field, locale, with: text_for(field, locale) } + case translatable_class.name + when "Budget::Investment" + complete_investment_form + when "Debate" + complete_new_debate_form + when "Proposal" + complete_new_proposal_form + end +end + +def complete_investment_form + select "Everywhere", from: "budget_investment_heading_id" + fill_in "budget_investment_location", with: "City center" + fill_in "budget_investment_organization_name", with: "T.I.A." + fill_in "budget_investment_tag_list", with: "Towers" + check "budget_investment_terms_of_service" +end + +def complete_new_debate_form + check "debate_terms_of_service" +end + +def complete_new_proposal_form + check "proposal_terms_of_service" +end + +def successul_operation_notice + case translatable_class.name + when "Budget::Investment" + "Budget Investment created successfully" + when "Proposal" + "Proposal created successfully" + when "Debate" + "Debate created successfully" + end +end + +def create_button_text + case translatable_class.name + when "Debate" + "Start a debate" + when "Budget::Investment" + "Create Investment" + when "Proposal" + "Create proposal" + end +end From 1abcd95441c2ef192de71721cd6e33f539552182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 25 Apr 2019 15:34:22 +0200 Subject: [PATCH 097/183] Add "new_translatable" shared example to budget investments feature specs --- spec/features/budgets/investments_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb index 5a0e1acca..2e136e041 100644 --- a/spec/features/budgets/investments_spec.rb +++ b/spec/features/budgets/investments_spec.rb @@ -24,6 +24,11 @@ describe "Budget Investments" do context "Concerns" do it_behaves_like "notifiable in-app", Budget::Investment it_behaves_like "relationable", Budget::Investment + it_behaves_like "new_translatable", + "budget_investment", + "new_budget_investment_path", + %w[title], + { "description" => :ckeditor } end context "Load" do From 1bcbcf49756d33a60c3ef0592cbae6f02ca38f7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 25 Apr 2019 15:34:33 +0200 Subject: [PATCH 098/183] Add "new_translatable" shared example to debates feature specs --- spec/features/debates_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/features/debates_spec.rb b/spec/features/debates_spec.rb index cc73bdb4f..503898150 100644 --- a/spec/features/debates_spec.rb +++ b/spec/features/debates_spec.rb @@ -11,6 +11,11 @@ describe "Debates" do context "Concerns" do it_behaves_like "notifiable in-app", Debate it_behaves_like "relationable", Debate + it_behaves_like "new_translatable", + "debate", + "new_debate_path", + %w[title], + { "description" => :ckeditor } it_behaves_like "translatable", "debate", "edit_debate_path", From d0bf0f88574e218900cac1aeec2528a47ac5f8cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 25 Apr 2019 15:34:47 +0200 Subject: [PATCH 099/183] Add "new_translatable" shared example to proposals feature specs --- spec/features/proposals_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index 0b2e6f4d1..05d7c8b1f 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -15,6 +15,11 @@ describe "Proposals" do context "Concerns" do it_behaves_like "notifiable in-app", Proposal it_behaves_like "relationable", Proposal + it_behaves_like "new_translatable", + "proposal", + "new_proposal_path", + %w[title summary], + { "description" => :ckeditor } it_behaves_like "translatable", "proposal", "edit_proposal_path", From 64bfab9c9c4e327d3e3725bfae9ad086d36f8962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 25 Apr 2019 15:50:05 +0200 Subject: [PATCH 100/183] Extract spec methods to commons module to avoid code duplication Because "translatable" and "new_translatable" shared examples needs same methods to manipulate translations. --- spec/shared/features/translatable.rb | 60 -------------------- spec/support/common_actions.rb | 1 + spec/support/common_actions/translations.rb | 63 +++++++++++++++++++++ 3 files changed, 64 insertions(+), 60 deletions(-) create mode 100644 spec/support/common_actions/translations.rb diff --git a/spec/shared/features/translatable.rb b/spec/shared/features/translatable.rb index 9e13643dd..1973256c4 100644 --- a/spec/shared/features/translatable.rb +++ b/spec/shared/features/translatable.rb @@ -338,62 +338,6 @@ def updated_path_for(resource) send(path_name, *resource_hierarchy_for(resource.reload)) end -def text_for(field, locale) - I18n.with_locale(locale) do - "#{translatable_class.human_attribute_name(field)} #{language_texts[locale]}" - end -end - -def field_for(field, locale, visible: true) - if translatable_class.name == "I18nContent" - "contents_content_#{translatable.key}values_#{field}_#{locale}" - else - within(".translatable-fields[data-locale='#{locale}']") do - find("input[id$='_#{field}'], textarea[id$='_#{field}']", visible: visible)[:id] - end - end -end - -def fill_in_field(field, locale, with:) - if input_fields.include?(field) - fill_in field_for(field, locale), with: with - else - fill_in_textarea(field, textarea_fields[field], locale, with: with) - end -end - -def fill_in_textarea(field, textarea_type, locale, with:) - if textarea_type == :markdownit - click_link class: "fullscreen-toggle" - fill_in field_for(field, locale), with: with - click_link class: "fullscreen-toggle" - elsif textarea_type == :ckeditor - fill_in_ckeditor field_for(field, locale, visible: false), with: with - end -end - -def expect_page_to_have_translatable_field(field, locale, with:) - if input_fields.include?(field) - if translatable_class.name == "I18nContent" && with.blank? - expect(page).to have_field field_for(field, locale) - else - expect(page).to have_field field_for(field, locale), with: with - end - else - textarea_type = textarea_fields[field] - - if textarea_type == :markdownit - click_link class: "fullscreen-toggle" - expect(page).to have_field field_for(field, locale), with: with - click_link class: "fullscreen-toggle" - elsif textarea_type == :ckeditor - within("div.js-globalize-attribute[data-locale='#{locale}'] .ckeditor [id$='#{field}']") do - within_frame(textarea_fields.keys.index(field)) { expect(page).to have_content with } - end - end - end -end - # FIXME: button texts should be consistent. Right now, buttons don't # even share the same colour. def update_button_text @@ -422,7 +366,3 @@ def update_button_text "Save changes" end end - -def front_end_path_to_visit?(path) - path[/admin|managment|valuation/].blank? -end diff --git a/spec/support/common_actions.rb b/spec/support/common_actions.rb index 2a2d2e3b7..7d23bb2e4 100644 --- a/spec/support/common_actions.rb +++ b/spec/support/common_actions.rb @@ -9,6 +9,7 @@ module CommonActions include Polls include Proposals include Tags + include Translations include Users include Verifications include Votes diff --git a/spec/support/common_actions/translations.rb b/spec/support/common_actions/translations.rb new file mode 100644 index 000000000..e45ae346a --- /dev/null +++ b/spec/support/common_actions/translations.rb @@ -0,0 +1,63 @@ +module Translations + def text_for(field, locale) + I18n.with_locale(locale) do + "#{translatable_class.human_attribute_name(field)} #{language_texts[locale]}" + end + end + + def field_for(field, locale, visible: true) + if translatable_class.name == "I18nContent" + "contents_content_#{translatable.key}values_#{field}_#{locale}" + else + within(".translatable-fields[data-locale='#{locale}']") do + find("input[id$='_#{field}'], textarea[id$='_#{field}']", visible: visible)[:id] + end + end + end + + def fill_in_field(field, locale, with:) + if input_fields.include?(field) + fill_in field_for(field, locale), with: with + else + fill_in_textarea(field, textarea_fields[field], locale, with: with) + end + end + + def fill_in_textarea(field, textarea_type, locale, with:) + if textarea_type == :markdownit + click_link class: "fullscreen-toggle" + fill_in field_for(field, locale), with: with + click_link class: "fullscreen-toggle" + elsif textarea_type == :ckeditor + fill_in_ckeditor field_for(field, locale, visible: false), with: with + end + end + + def expect_page_to_have_translatable_field(field, locale, with:) + if input_fields.include?(field) + if translatable_class.name == "I18nContent" && with.blank? + expect(page).to have_field field_for(field, locale) + else + expect(page).to have_field field_for(field, locale), with: with + end + else + textarea_type = textarea_fields[field] + + if textarea_type == :markdownit + click_link class: "fullscreen-toggle" + expect(page).to have_field field_for(field, locale), with: with + click_link class: "fullscreen-toggle" + elsif textarea_type == :ckeditor + within("div.js-globalize-attribute[data-locale='#{locale}'] .ckeditor [id$='#{field}']") do + # Wait longer for iframe initialization + expect(page).to have_selector "iframe.cke_wysiwyg_frame", wait: 5 + within_frame(textarea_fields.keys.index(field)) { expect(page).to have_content with } + end + end + end + end + + def front_end_path_to_visit?(path) + path[/admin|managment|valuation/].blank? + end +end From 3176be43d9991a99dfb0246e8e98fd01d504df19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 25 Apr 2019 15:52:09 +0200 Subject: [PATCH 101/183] Rename "translatable" shared example to "edit_translatable" Also rename all specs calls --- spec/features/admin/admin_notifications_spec.rb | 2 +- spec/features/admin/banners_spec.rb | 2 +- spec/features/admin/budget_groups_spec.rb | 2 +- spec/features/admin/budget_headings_spec.rb | 2 +- spec/features/admin/budget_investment_milestones_spec.rb | 2 +- spec/features/admin/budget_investments_spec.rb | 2 +- spec/features/admin/budget_phases_spec.rb | 2 +- spec/features/admin/budgets_spec.rb | 2 +- spec/features/admin/legislation/draft_versions_spec.rb | 2 +- spec/features/admin/legislation/processes_spec.rb | 2 +- spec/features/admin/legislation/questions_spec.rb | 2 +- spec/features/admin/poll/active_polls_spec.rb | 2 +- spec/features/admin/poll/polls_spec.rb | 2 +- spec/features/admin/poll/questions/answers/answers_spec.rb | 2 +- spec/features/admin/poll/questions_spec.rb | 2 +- .../features/admin/site_customization/information_texts_spec.rb | 2 +- spec/features/admin/site_customization/pages_spec.rb | 2 +- spec/features/admin/widgets/cards_spec.rb | 2 +- spec/features/debates_spec.rb | 2 +- spec/features/proposals_spec.rb | 2 +- spec/shared/features/{translatable.rb => edit_translatable.rb} | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) rename spec/shared/features/{translatable.rb => edit_translatable.rb} (99%) diff --git a/spec/features/admin/admin_notifications_spec.rb b/spec/features/admin/admin_notifications_spec.rb index 75f142f62..a9df505dc 100644 --- a/spec/features/admin/admin_notifications_spec.rb +++ b/spec/features/admin/admin_notifications_spec.rb @@ -8,7 +8,7 @@ describe "Admin Notifications" do create(:budget) end - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "admin_notification", "edit_admin_admin_notification_path", %w[title body] diff --git a/spec/features/admin/banners_spec.rb b/spec/features/admin/banners_spec.rb index 5c7a3e066..c5b8b376c 100644 --- a/spec/features/admin/banners_spec.rb +++ b/spec/features/admin/banners_spec.rb @@ -6,7 +6,7 @@ describe "Admin banners magement" do login_as(create(:administrator).user) end - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "banner", "edit_admin_banner_path", %w[title description] diff --git a/spec/features/admin/budget_groups_spec.rb b/spec/features/admin/budget_groups_spec.rb index cc0c75d62..92ba4de94 100644 --- a/spec/features/admin/budget_groups_spec.rb +++ b/spec/features/admin/budget_groups_spec.rb @@ -9,7 +9,7 @@ describe "Admin budget groups" do login_as(admin.user) end - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "budget_group", "edit_admin_budget_group_path", %w[name] diff --git a/spec/features/admin/budget_headings_spec.rb b/spec/features/admin/budget_headings_spec.rb index 6b633058d..2245ebbd7 100644 --- a/spec/features/admin/budget_headings_spec.rb +++ b/spec/features/admin/budget_headings_spec.rb @@ -10,7 +10,7 @@ describe "Admin budget headings" do login_as(admin.user) end - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "budget_heading", "edit_admin_budget_group_heading_path", %w[name] diff --git a/spec/features/admin/budget_investment_milestones_spec.rb b/spec/features/admin/budget_investment_milestones_spec.rb index 17403a038..d33a672e5 100644 --- a/spec/features/admin/budget_investment_milestones_spec.rb +++ b/spec/features/admin/budget_investment_milestones_spec.rb @@ -2,7 +2,7 @@ require "rails_helper" describe "Admin budget investment milestones" do - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "milestone", "edit_tracking_budget_budget_investment_milestone_path", %w[description] diff --git a/spec/features/admin/budget_investments_spec.rb b/spec/features/admin/budget_investments_spec.rb index 8a45ac44f..3ba82fdaa 100644 --- a/spec/features/admin/budget_investments_spec.rb +++ b/spec/features/admin/budget_investments_spec.rb @@ -11,7 +11,7 @@ describe "Admin budget investments" do :budget_investment, "admin_budget_budget_investment_path" - it_behaves_like "translatable", + it_behaves_like "edit_translatable", :budget_investment, "edit_admin_budget_budget_investment_path", %w[title], diff --git a/spec/features/admin/budget_phases_spec.rb b/spec/features/admin/budget_phases_spec.rb index 81f178470..142bc7f02 100644 --- a/spec/features/admin/budget_phases_spec.rb +++ b/spec/features/admin/budget_phases_spec.rb @@ -10,7 +10,7 @@ describe "Admin budget phases" do login_as(admin.user) end - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "budget_phase", "edit_admin_budget_budget_phase_path", [], diff --git a/spec/features/admin/budgets_spec.rb b/spec/features/admin/budgets_spec.rb index 912262afc..2b214314c 100644 --- a/spec/features/admin/budgets_spec.rb +++ b/spec/features/admin/budgets_spec.rb @@ -7,7 +7,7 @@ describe "Admin budgets" do login_as(admin.user) end - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "budget", "edit_admin_budget_path", %w[name] diff --git a/spec/features/admin/legislation/draft_versions_spec.rb b/spec/features/admin/legislation/draft_versions_spec.rb index f930fec01..701b0b776 100644 --- a/spec/features/admin/legislation/draft_versions_spec.rb +++ b/spec/features/admin/legislation/draft_versions_spec.rb @@ -7,7 +7,7 @@ describe "Admin legislation draft versions" do login_as(admin.user) end - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "legislation_draft_version", "edit_admin_legislation_process_draft_version_path", %w[title changelog], diff --git a/spec/features/admin/legislation/processes_spec.rb b/spec/features/admin/legislation/processes_spec.rb index 2da2ca0c5..3b233717b 100644 --- a/spec/features/admin/legislation/processes_spec.rb +++ b/spec/features/admin/legislation/processes_spec.rb @@ -7,7 +7,7 @@ describe "Admin collaborative legislation" do login_as(admin.user) end - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "legislation_process", "edit_admin_legislation_process_path", %w[title summary description additional_info] diff --git a/spec/features/admin/legislation/questions_spec.rb b/spec/features/admin/legislation/questions_spec.rb index bc1cf7ba0..c4ac2da26 100644 --- a/spec/features/admin/legislation/questions_spec.rb +++ b/spec/features/admin/legislation/questions_spec.rb @@ -9,7 +9,7 @@ describe "Admin legislation questions" do let!(:process) { create(:legislation_process, title: "An example legislation process") } - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "legislation_question", "edit_admin_legislation_process_question_path", %w[title] diff --git a/spec/features/admin/poll/active_polls_spec.rb b/spec/features/admin/poll/active_polls_spec.rb index 48eff3ea7..ecc3f1490 100644 --- a/spec/features/admin/poll/active_polls_spec.rb +++ b/spec/features/admin/poll/active_polls_spec.rb @@ -7,7 +7,7 @@ describe "Admin Active polls" do login_as(admin.user) end - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "active_poll", "edit_admin_active_polls_path", [], diff --git a/spec/features/admin/poll/polls_spec.rb b/spec/features/admin/poll/polls_spec.rb index 536e45858..0f2dacfbb 100644 --- a/spec/features/admin/poll/polls_spec.rb +++ b/spec/features/admin/poll/polls_spec.rb @@ -7,7 +7,7 @@ describe "Admin polls" do login_as(admin.user) end - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "poll", "edit_admin_poll_path", %w[name summary description] diff --git a/spec/features/admin/poll/questions/answers/answers_spec.rb b/spec/features/admin/poll/questions/answers/answers_spec.rb index 6efc76fb6..149c7532e 100644 --- a/spec/features/admin/poll/questions/answers/answers_spec.rb +++ b/spec/features/admin/poll/questions/answers/answers_spec.rb @@ -7,7 +7,7 @@ describe "Answers" do login_as admin.user end - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "poll_question_answer", "edit_admin_answer_path", %w[title], diff --git a/spec/features/admin/poll/questions_spec.rb b/spec/features/admin/poll/questions_spec.rb index c1906e4dd..d516ca361 100644 --- a/spec/features/admin/poll/questions_spec.rb +++ b/spec/features/admin/poll/questions_spec.rb @@ -6,7 +6,7 @@ describe "Admin poll questions" do login_as(create(:administrator).user) end - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "poll_question", "edit_admin_question_path", %w[title] diff --git a/spec/features/admin/site_customization/information_texts_spec.rb b/spec/features/admin/site_customization/information_texts_spec.rb index c4aa9ad37..2d73e67c8 100644 --- a/spec/features/admin/site_customization/information_texts_spec.rb +++ b/spec/features/admin/site_customization/information_texts_spec.rb @@ -7,7 +7,7 @@ describe "Admin custom information texts" do login_as(admin.user) end - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "i18n_content", "admin_site_customization_information_texts_path", %w[value] diff --git a/spec/features/admin/site_customization/pages_spec.rb b/spec/features/admin/site_customization/pages_spec.rb index 9a6cf35ea..9147acfe9 100644 --- a/spec/features/admin/site_customization/pages_spec.rb +++ b/spec/features/admin/site_customization/pages_spec.rb @@ -7,7 +7,7 @@ describe "Admin custom pages" do login_as(admin.user) end - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "site_customization_page", "edit_admin_site_customization_page_path", %w[title subtitle], diff --git a/spec/features/admin/widgets/cards_spec.rb b/spec/features/admin/widgets/cards_spec.rb index 2f4d9bbd4..fed8e88a8 100644 --- a/spec/features/admin/widgets/cards_spec.rb +++ b/spec/features/admin/widgets/cards_spec.rb @@ -7,7 +7,7 @@ describe "Cards" do login_as(admin) end - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "widget_card", "edit_admin_widget_card_path", %w[title description link_text label] diff --git a/spec/features/debates_spec.rb b/spec/features/debates_spec.rb index 503898150..8c58682f5 100644 --- a/spec/features/debates_spec.rb +++ b/spec/features/debates_spec.rb @@ -16,7 +16,7 @@ describe "Debates" do "new_debate_path", %w[title], { "description" => :ckeditor } - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "debate", "edit_debate_path", %w[title], diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index 05d7c8b1f..bfaef572c 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -20,7 +20,7 @@ describe "Proposals" do "new_proposal_path", %w[title summary], { "description" => :ckeditor } - it_behaves_like "translatable", + it_behaves_like "edit_translatable", "proposal", "edit_proposal_path", %w[title summary], diff --git a/spec/shared/features/translatable.rb b/spec/shared/features/edit_translatable.rb similarity index 99% rename from spec/shared/features/translatable.rb rename to spec/shared/features/edit_translatable.rb index 1973256c4..245d1abee 100644 --- a/spec/shared/features/translatable.rb +++ b/spec/shared/features/edit_translatable.rb @@ -1,4 +1,4 @@ -shared_examples "translatable" do |factory_name, path_name, input_fields, textarea_fields = {}| +shared_examples "edit_translatable" do |factory_name, path_name, input_fields, textarea_fields = {}| let(:language_texts) do { es: "en español", From 7e3f0b5c18102f9ebba41bc848ff3608e4787229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sun, 23 Dec 2018 19:19:36 +0100 Subject: [PATCH 102/183] Add translation interface feature setting Allow to enable/disable translation interface at frontend --- app/helpers/translatable_form_helper.rb | 8 ++++++++ config/locales/en/settings.yml | 2 ++ config/locales/es/settings.yml | 2 ++ spec/features/budgets/investments_spec.rb | 15 +++++++++----- spec/features/debates_spec.rb | 25 ++++++++++++++--------- spec/features/proposals_spec.rb | 25 ++++++++++++++--------- 6 files changed, 52 insertions(+), 25 deletions(-) diff --git a/app/helpers/translatable_form_helper.rb b/app/helpers/translatable_form_helper.rb index fdee3bf34..43f8cef59 100644 --- a/app/helpers/translatable_form_helper.rb +++ b/app/helpers/translatable_form_helper.rb @@ -6,6 +6,14 @@ module TranslatableFormHelper end end + def translations_interface_enabled? + Setting["feature.translation_interface"].present? || backend_translations_enabled? + end + + def backend_translations_enabled? + (controller.class.parents & [Admin, Management, Valuation]).any? + end + class TranslatableFormBuilder < FoundationRailsHelper::FormBuilder attr_accessor :translations diff --git a/config/locales/en/settings.yml b/config/locales/en/settings.yml index 7af06fdad..0f497a1cf 100644 --- a/config/locales/en/settings.yml +++ b/config/locales/en/settings.yml @@ -116,6 +116,8 @@ en: public_stats_description: "Display public stats in the Administration panel" help_page: "Help page" help_page_description: 'Displays a Help menu that contains a page with an info section about each enabled feature. Also custom pages and menus can be created in the "Custom pages" and "Custom content blocks" sections' + translation_interface: "Translation interface" + translation_interface_description: "Displays the manual translation interface that allows users to enter their content in all application available languages. This option only affects user application forms and independently will always be active in the administration panel." valuation_comment_notification: "Valuation comment notification" valuation_comment_notification_description: "Send an email to all associated users except valuation commenter to budget investment when a new valuation comment is created" map: diff --git a/config/locales/es/settings.yml b/config/locales/es/settings.yml index 352e4f30d..90eda0ae4 100644 --- a/config/locales/es/settings.yml +++ b/config/locales/es/settings.yml @@ -116,6 +116,8 @@ es: public_stats_description: "Muestra las estadísticas públicas en el panel de Administración" help_page: "Página de ayuda" help_page_description: 'Muestra un menú Ayuda que contiene una página con una sección de información sobre cada funcionalidad habilitada. También se pueden crear páginas y menús personalizados en las secciones "Personalizar páginas" y "Personalizar bloques"' + translation_interface: "Interfaz de traducción" + translation_interface_description: "Muestra la interfaz de traducción manual permitiendo a los usuarios introducir sus contenidos en todos los idiomas disponibles de la aplicación si así lo desean. Esta opción solo afecta a las vistas de usuarios de la aplicación, en el panel de administración está activa siempre." valuation_comment_notification: "Notificar comentarios de evaluación" valuation_comment_notification_description: "Envía un email a todos los usuarios menos al que haya comentado asociados a un presupuesto participativo cuando se cree un nuevo comentario de evaluación" map: diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb index 2e136e041..3da6a4571 100644 --- a/spec/features/budgets/investments_spec.rb +++ b/spec/features/budgets/investments_spec.rb @@ -24,11 +24,16 @@ describe "Budget Investments" do context "Concerns" do it_behaves_like "notifiable in-app", Budget::Investment it_behaves_like "relationable", Budget::Investment - it_behaves_like "new_translatable", - "budget_investment", - "new_budget_investment_path", - %w[title], - { "description" => :ckeditor } + context "Translatable at front end" do + before do + Setting["feature.translation_interface"] = true + end + it_behaves_like "new_translatable", + "budget_investment", + "new_budget_investment_path", + %w[title], + { "description" => :ckeditor } + end end context "Load" do diff --git a/spec/features/debates_spec.rb b/spec/features/debates_spec.rb index 8c58682f5..74c88f758 100644 --- a/spec/features/debates_spec.rb +++ b/spec/features/debates_spec.rb @@ -11,16 +11,21 @@ describe "Debates" do context "Concerns" do it_behaves_like "notifiable in-app", Debate it_behaves_like "relationable", Debate - it_behaves_like "new_translatable", - "debate", - "new_debate_path", - %w[title], - { "description" => :ckeditor } - it_behaves_like "edit_translatable", - "debate", - "edit_debate_path", - %w[title], - { "description" => :ckeditor } + context "Translatable at front end" do + before do + Setting["feature.translation_interface"] = true + end + it_behaves_like "new_translatable", + "debate", + "new_debate_path", + %w[title], + { "description" => :ckeditor } + it_behaves_like "edit_translatable", + "debate", + "edit_debate_path", + %w[title], + { "description" => :ckeditor } + end end scenario "Index" do diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index bfaef572c..8a8d56e8c 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -15,16 +15,21 @@ describe "Proposals" do context "Concerns" do it_behaves_like "notifiable in-app", Proposal it_behaves_like "relationable", Proposal - it_behaves_like "new_translatable", - "proposal", - "new_proposal_path", - %w[title summary], - { "description" => :ckeditor } - it_behaves_like "edit_translatable", - "proposal", - "edit_proposal_path", - %w[title summary], - { "description" => :ckeditor } + context "Translatable at front end" do + before do + Setting["feature.translation_interface"] = true + end + it_behaves_like "new_translatable", + "proposal", + "new_proposal_path", + %w[title summary], + { "description" => :ckeditor } + it_behaves_like "edit_translatable", + "proposal", + "edit_proposal_path", + %w[title summary], + { "description" => :ckeditor } + end end context "Index" do From b5663a7c177717869d3110a9fcb7790662208776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sun, 23 Dec 2018 19:26:09 +0100 Subject: [PATCH 103/183] Add translation interface setting values * Disable translation interface by default * Also add rake task to enable translations interface through rake command --- app/models/setting.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/setting.rb b/app/models/setting.rb index 6e87816dc..d20d515d2 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -93,6 +93,7 @@ class Setting < ApplicationRecord "feature.allow_attached_documents": true, "feature.allow_images": true, "feature.help_page": true, + "feature.translation_interface": nil, "feature.valuation_comment_notification": true, "homepage.widgets.feeds.debates": true, "homepage.widgets.feeds.processes": true, From 73563e5d86c57bce4635b7b16652c799a402a1a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Sun, 23 Dec 2018 19:28:06 +0100 Subject: [PATCH 104/183] Display needed translations when translation interface is disabled Display only current locale translation when translation interface is disabled. Co-Authored-By: javierm --- app/helpers/translatable_form_helper.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/helpers/translatable_form_helper.rb b/app/helpers/translatable_form_helper.rb index 43f8cef59..934ab19b0 100644 --- a/app/helpers/translatable_form_helper.rb +++ b/app/helpers/translatable_form_helper.rb @@ -19,10 +19,10 @@ module TranslatableFormHelper def translatable_fields(&block) @translations = {} - @object.globalize_locales.map do |locale| + visible_locales.map do |locale| @translations[locale] = translation_for(locale) end - @object.globalize_locales.map do |locale| + visible_locales.map do |locale| Globalize.with_locale(locale) { fields_for_locale(locale, &block) } end.join.html_safe end @@ -77,6 +77,14 @@ module TranslatableFormHelper def no_other_translations?(translation) (@object.translations - [translation]).reject(&:_destroy).empty? end + + def visible_locales + if @template.translations_interface_enabled? + @object.globalize_locales + else + [I18n.locale] + end + end end class TranslationsFieldsBuilder < FoundationRailsHelper::FormBuilder From 264b3f0f821f9caff62385ce1213666b05c7a33d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 9 May 2019 19:24:52 +0200 Subject: [PATCH 105/183] Simpler calls to *_translatable shared specs Enable translations interface setting inside shared specs when needed. Co-Authored-By: javierm --- spec/features/budgets/investments_spec.rb | 15 +++++--------- spec/features/debates_spec.rb | 25 +++++++++-------------- spec/features/proposals_spec.rb | 25 +++++++++-------------- spec/shared/features/edit_translatable.rb | 6 +++++- spec/shared/features/new_translatable.rb | 1 + 5 files changed, 31 insertions(+), 41 deletions(-) diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb index 3da6a4571..2e136e041 100644 --- a/spec/features/budgets/investments_spec.rb +++ b/spec/features/budgets/investments_spec.rb @@ -24,16 +24,11 @@ describe "Budget Investments" do context "Concerns" do it_behaves_like "notifiable in-app", Budget::Investment it_behaves_like "relationable", Budget::Investment - context "Translatable at front end" do - before do - Setting["feature.translation_interface"] = true - end - it_behaves_like "new_translatable", - "budget_investment", - "new_budget_investment_path", - %w[title], - { "description" => :ckeditor } - end + it_behaves_like "new_translatable", + "budget_investment", + "new_budget_investment_path", + %w[title], + { "description" => :ckeditor } end context "Load" do diff --git a/spec/features/debates_spec.rb b/spec/features/debates_spec.rb index 74c88f758..8c58682f5 100644 --- a/spec/features/debates_spec.rb +++ b/spec/features/debates_spec.rb @@ -11,21 +11,16 @@ describe "Debates" do context "Concerns" do it_behaves_like "notifiable in-app", Debate it_behaves_like "relationable", Debate - context "Translatable at front end" do - before do - Setting["feature.translation_interface"] = true - end - it_behaves_like "new_translatable", - "debate", - "new_debate_path", - %w[title], - { "description" => :ckeditor } - it_behaves_like "edit_translatable", - "debate", - "edit_debate_path", - %w[title], - { "description" => :ckeditor } - end + it_behaves_like "new_translatable", + "debate", + "new_debate_path", + %w[title], + { "description" => :ckeditor } + it_behaves_like "edit_translatable", + "debate", + "edit_debate_path", + %w[title], + { "description" => :ckeditor } end scenario "Index" do diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index 8a8d56e8c..bfaef572c 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -15,21 +15,16 @@ describe "Proposals" do context "Concerns" do it_behaves_like "notifiable in-app", Proposal it_behaves_like "relationable", Proposal - context "Translatable at front end" do - before do - Setting["feature.translation_interface"] = true - end - it_behaves_like "new_translatable", - "proposal", - "new_proposal_path", - %w[title summary], - { "description" => :ckeditor } - it_behaves_like "edit_translatable", - "proposal", - "edit_proposal_path", - %w[title summary], - { "description" => :ckeditor } - end + it_behaves_like "new_translatable", + "proposal", + "new_proposal_path", + %w[title summary], + { "description" => :ckeditor } + it_behaves_like "edit_translatable", + "proposal", + "edit_proposal_path", + %w[title summary], + { "description" => :ckeditor } end context "Index" do diff --git a/spec/shared/features/edit_translatable.rb b/spec/shared/features/edit_translatable.rb index 245d1abee..54af5794a 100644 --- a/spec/shared/features/edit_translatable.rb +++ b/spec/shared/features/edit_translatable.rb @@ -46,7 +46,11 @@ shared_examples "edit_translatable" do |factory_name, path_name, input_fields, t before do login_as(user) - translatable.update(author: user) if front_end_path_to_visit?(path_name) + + if front_end_path_to_visit?(path_name) + Setting["feature.translation_interface"] = true + translatable.update(author: user) + end end context "Manage translations" do diff --git a/spec/shared/features/new_translatable.rb b/spec/shared/features/new_translatable.rb index c66a9770e..56fb6a028 100644 --- a/spec/shared/features/new_translatable.rb +++ b/spec/shared/features/new_translatable.rb @@ -43,6 +43,7 @@ shared_examples "new_translatable" do |factory_name, path_name, input_fields, te end before do + Setting["feature.translation_interface"] = true login_as(user) end From 25e9c358ad37727fa2e95745de7784cd002a0450 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 25 Jan 2019 14:51:30 +0100 Subject: [PATCH 106/183] Create RemotelyTranslatable concern controller - Create concern to reuse the logic of detection of non-existent translations in Controllers. - Add detect_remote_translation method: * This method will be called from controllers to recover resources without translation. * Receive arrays of resources. * Return an array with hashes of remote_translations values for every resources that have not translations. * This array will be the param that will be sent from view to RemoteTranslationController for create remote translations instances. --- .../concerns/remotely_translatable.rb | 29 ++++++++ .../concerns/remotely_translatable_spec.rb | 66 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 app/controllers/concerns/remotely_translatable.rb create mode 100644 spec/controllers/concerns/remotely_translatable_spec.rb diff --git a/app/controllers/concerns/remotely_translatable.rb b/app/controllers/concerns/remotely_translatable.rb new file mode 100644 index 000000000..600c8a86f --- /dev/null +++ b/app/controllers/concerns/remotely_translatable.rb @@ -0,0 +1,29 @@ +module RemotelyTranslatable + + private + + def detect_remote_translations(*args) + return [] unless Setting["feature.remote_translations"].present? + + resources_groups(*args).flatten.select { |resource| translation_empty?(resource) }.map do |resource| + remote_translation_for(resource) + end + end + + def remote_translation_for(resource) + { 'remote_translatable_id' => resource.id.to_s, + 'remote_translatable_type' => resource.class.to_s, + 'locale' => I18n.locale } + end + + def translation_empty?(resource) + resource.translations.where(locale: I18n.locale).empty? + end + + def resources_groups(*args) + feeds = args.detect { |arg| arg&.first.class == Widget::Feed } || [] + + args.compact - [feeds] + feeds.map(&:items) + end + +end diff --git a/spec/controllers/concerns/remotely_translatable_spec.rb b/spec/controllers/concerns/remotely_translatable_spec.rb new file mode 100644 index 000000000..92ab5c8f6 --- /dev/null +++ b/spec/controllers/concerns/remotely_translatable_spec.rb @@ -0,0 +1,66 @@ +require "rails_helper" +include RemotelyTranslatable + +describe RemotelyTranslatable do + + before do + Setting["feature.remote_translations"] = true + end + + after do + Setting["feature.remote_translations"] = nil + end + + describe "#detect_remote_translations" do + + describe "Should detect remote_translations" do + + it "When collections and featured_proposals are not defined in current locale" do + proposals = create_list(:proposal, 3) + featured_proposals = create_featured_proposals + + I18n.with_locale(:es) do + expect(detect_remote_translations(proposals, featured_proposals).count).to eq 6 + end + end + + it "When we have nil as argument and collections are not defined in current locale" do + proposals = create_list(:proposal, 3) + + I18n.with_locale(:es) do + expect(detect_remote_translations(proposals, nil).count).to eq 3 + end + end + + it "When we have [] as argument and collections are not defined in current locale" do + proposals = create_list(:proposal, 3) + + I18n.with_locale(:es) do + expect(detect_remote_translations(proposals, []).count).to eq 3 + end + end + + it "When widget feeds are not defined in current locale" do + create_list(:proposal, 3) + create_list(:debate, 3) + create_list(:legislation_process, 3) + create(:widget_feed, kind: "proposals") + create(:widget_feed, kind: "debates") + create(:widget_feed, kind: "processes") + widget_feeds = Widget::Feed.active + + I18n.with_locale(:es) do + expect(detect_remote_translations(widget_feeds).count).to eq 9 + end + end + + end + + it "When defined in current locale should not detect remote_translations" do + proposal = create(:proposal) + comment = create(:comment, commentable: proposal) + + expect(detect_remote_translations([proposal, comment])).to eq [] + end + end +end From 04810f508033703f31f4b5d197eb260610b00929 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 25 Jan 2019 15:00:52 +0100 Subject: [PATCH 107/183] Create RemoteTranslation model - Each RemoteTranslation is associated with a resource (through polymorphic) and has the locale to we want translate. - After create a RemoteTranslation we create a enqueue_remote_translation method that will be send remote translation instance to remote translation client --- app/models/remote_translation.rb | 14 ++++++++ ...181205191300_create_remote_translations.rb | 12 +++++++ db/schema.rb | 9 ++++++ spec/factories/remote_translations.rb | 5 +++ spec/models/remote_translation_spec.rb | 32 +++++++++++++++++++ 5 files changed, 72 insertions(+) create mode 100644 app/models/remote_translation.rb create mode 100644 db/migrate/20181205191300_create_remote_translations.rb create mode 100644 spec/factories/remote_translations.rb create mode 100644 spec/models/remote_translation_spec.rb diff --git a/app/models/remote_translation.rb b/app/models/remote_translation.rb new file mode 100644 index 000000000..62e6a14c6 --- /dev/null +++ b/app/models/remote_translation.rb @@ -0,0 +1,14 @@ +class RemoteTranslation < ApplicationRecord + + belongs_to :remote_translatable, polymorphic: true + + validates :remote_translatable_id, presence: true + validates :remote_translatable_type, presence: true + validates :locale, presence: true + + after_create :enqueue_remote_translation + + def enqueue_remote_translation + end + +end diff --git a/db/migrate/20181205191300_create_remote_translations.rb b/db/migrate/20181205191300_create_remote_translations.rb new file mode 100644 index 000000000..0abe08464 --- /dev/null +++ b/db/migrate/20181205191300_create_remote_translations.rb @@ -0,0 +1,12 @@ +class CreateRemoteTranslations < ActiveRecord::Migration[4.2] + def change + create_table :remote_translations do |t| + t.string :locale + t.integer :remote_translatable_id + t.string :remote_translatable_type + t.text :error_message + + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 6680cbe2c..aa7cce9aa 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1400,6 +1400,15 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.index ["related_content_id"], name: "opposite_related_content", using: :btree end + create_table "remote_translations", force: :cascade do |t| + t.string "locale" + t.integer "remote_translatable_id" + t.string "remote_translatable_type" + t.text "error_message" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "reports", force: :cascade do |t| t.boolean "stats" t.boolean "results" diff --git a/spec/factories/remote_translations.rb b/spec/factories/remote_translations.rb new file mode 100644 index 000000000..59aacb379 --- /dev/null +++ b/spec/factories/remote_translations.rb @@ -0,0 +1,5 @@ +FactoryBot.define do + factory :remote_translation do + association :remote_translatable, factory: :debate + end +end diff --git a/spec/models/remote_translation_spec.rb b/spec/models/remote_translation_spec.rb new file mode 100644 index 000000000..e1a8e3616 --- /dev/null +++ b/spec/models/remote_translation_spec.rb @@ -0,0 +1,32 @@ +require "rails_helper" + +describe RemoteTranslation do + + let(:remote_translation) { build(:remote_translation, locale: :es) } + + it "is valid" do + expect(remote_translation).to be_valid + end + + it "is valid without error_message" do + remote_translation.error_message = nil + expect(remote_translation).to be_valid + end + + it "is not valid without to" do + remote_translation.locale = nil + expect(remote_translation).not_to be_valid + end + + it "is not valid without a remote_translatable_id" do + remote_translation.remote_translatable_id = nil + expect(remote_translation).not_to be_valid + end + + it "is not valid without a remote_translatable_type" do + remote_translation.remote_translatable_type = nil + expect(remote_translation).not_to be_valid + end + end + +end From 744a3d48fd48989b5dd628f6652d8ec428dcaa4d Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 25 Jan 2019 15:22:33 +0100 Subject: [PATCH 108/183] Create RemoteTranslations Controller - Create RemoteTranslations Controller to receive resources without translations and create RemoteTranslation instances when theirs translations are not enqueued. - Create remote_translation_enqueued? class method on RemoteTranslation model to check if exists same remote translations without errors pending to translate. --- .../remote_translations_controller.rb | 32 +++++++++++++ app/models/remote_translation.rb | 6 +++ config/locales/en/general.yml | 3 ++ config/locales/es/general.yml | 3 ++ config/routes.rb | 1 + .../remote_translation_controller_spec.rb | 48 +++++++++++++++++++ 6 files changed, 93 insertions(+) create mode 100644 app/controllers/remote_translations_controller.rb create mode 100644 spec/controllers/remote_translation_controller_spec.rb diff --git a/app/controllers/remote_translations_controller.rb b/app/controllers/remote_translations_controller.rb new file mode 100644 index 000000000..2ee5fc7a9 --- /dev/null +++ b/app/controllers/remote_translations_controller.rb @@ -0,0 +1,32 @@ +class RemoteTranslationsController < ApplicationController + skip_authorization_check + respond_to :html, :js + + before_action :set_remote_translations, only: :create + + def create + @remote_translations.each do |remote_translation| + RemoteTranslation.create(remote_translation) unless translations_enqueued?(remote_translation) + end + redirect_to request.referer, notice: t('remote_translations.create.enqueue_remote_translation') + end + + private + + def remote_translations_params + params.permit(:remote_translations) + end + + def set_remote_translations + decoded_remote_translations = ActiveSupport::JSON.decode(remote_translations_params["remote_translations"]) + @remote_translations = decoded_remote_translations.map{ |remote_translation| + remote_translation.slice("remote_translatable_id","remote_translatable_type","locale") + } + end + + + def translations_enqueued?(remote_translation) + RemoteTranslation.remote_translation_enqueued?(remote_translation) + end + +end diff --git a/app/models/remote_translation.rb b/app/models/remote_translation.rb index 62e6a14c6..07be39193 100644 --- a/app/models/remote_translation.rb +++ b/app/models/remote_translation.rb @@ -11,4 +11,10 @@ class RemoteTranslation < ApplicationRecord def enqueue_remote_translation end + def self.remote_translation_enqueued?(remote_translation) + where(remote_translatable_id: remote_translation["remote_translatable_id"], + remote_translatable_type: remote_translation["remote_translatable_type"], + locale: remote_translation["locale"], + error_message: nil).any? + end end diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index 74b793bfd..650849ca3 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -1033,3 +1033,6 @@ en: title: Prioritization type borda: Borda votation dowdall: Dowdall votation + remote_translations: + create: + enqueue_remote_translation: Translations have been correctly requested. diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index 5f7e106de..435ce7a10 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -1030,3 +1030,6 @@ es: title: Tipo de priorizacion borda: Votación con recuento Borda dowdall: Votación con recuento Dowdall + remote_translations: + create: + enqueue_remote_translation: Se han solicitado correctamente las traducciones. diff --git a/config/routes.rb b/config/routes.rb index be3e8e0ec..4a380a23c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -42,6 +42,7 @@ Rails.application.routes.draw do resources :images, only: [:destroy] resources :documents, only: [:destroy] resources :follows, only: [:create, :destroy] + resources :remote_translations, only: [:create] # More info pages get "help", to: "pages#show", id: "help/index", as: "help" diff --git a/spec/controllers/remote_translation_controller_spec.rb b/spec/controllers/remote_translation_controller_spec.rb new file mode 100644 index 000000000..97e6ebaf9 --- /dev/null +++ b/spec/controllers/remote_translation_controller_spec.rb @@ -0,0 +1,48 @@ +require "rails_helper" + +describe RemoteTranslationsController do + + describe "POST create" do + before do + @debate = create(:debate) + @remote_translations_params = [{ remote_translatable_id: @debate.id.to_s, + remote_translatable_type: @debate.class.to_s, + locale: :es }].to_json + allow(controller.request).to receive(:referer).and_return("any_path") + Delayed::Worker.delay_jobs = true + end + + after do + Delayed::Worker.delay_jobs = false + end + + it "create correctly remote translation" do + post :create, remote_translations: @remote_translations_params + + expect(RemoteTranslation.count).to eq(1) + end + + it "create remote translation when same remote translation with error_message is enqueued" do + create(:remote_translation, remote_translatable: @debate, locale: :es, error_message: "Has errors") + + post :create, remote_translations: @remote_translations_params + + expect(RemoteTranslation.count).to eq(2) + end + + it "not create remote translation when same remote translation is enqueued" do + create(:remote_translation, remote_translatable: @debate, locale: :es) + + post :create, remote_translations: @remote_translations_params + + expect(RemoteTranslation.count).to eq(1) + end + + it "redirect_to request referer after create" do + post :create, remote_translations: @remote_translations_params + + expect(subject).to redirect_to("any_path") + end + + end +end From 4272b6033930581ccdec5e5eb59c450a96775975 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 25 Jan 2019 15:30:13 +0100 Subject: [PATCH 109/183] Create Remote Translations Caller This module is used in a callback model and in charge of - extracting resources associated from RemoteTranslation and preparing its fields to be sent to the MicrosoftTranslateClient thought DelayedJobs - receive the response from MicrosoftTranslateClient and update resource with his translates Co-authored-by: javierm --- app/models/remote_translation.rb | 1 + lib/remote_translations_caller.rb | 49 +++++ spec/lib/remote_translations_caller_spec.rb | 206 ++++++++++++++++++++ spec/models/remote_translation_spec.rb | 11 ++ 4 files changed, 267 insertions(+) create mode 100644 lib/remote_translations_caller.rb create mode 100644 spec/lib/remote_translations_caller_spec.rb diff --git a/app/models/remote_translation.rb b/app/models/remote_translation.rb index 07be39193..51851267d 100644 --- a/app/models/remote_translation.rb +++ b/app/models/remote_translation.rb @@ -9,6 +9,7 @@ class RemoteTranslation < ApplicationRecord after_create :enqueue_remote_translation def enqueue_remote_translation + RemoteTranslationsCaller.new(self).delay.call end def self.remote_translation_enqueued?(remote_translation) diff --git a/lib/remote_translations_caller.rb b/lib/remote_translations_caller.rb new file mode 100644 index 000000000..8cc2da961 --- /dev/null +++ b/lib/remote_translations_caller.rb @@ -0,0 +1,49 @@ +class RemoteTranslationsCaller + attr_reader :remote_translation + + def initialize(remote_translation) + @remote_translation = remote_translation + end + + def call + update_resource + destroy_remote_translation + end + + private + + def update_resource + Globalize.with_locale(locale) do + resource.translated_attribute_names.each_with_index do |field, index| + resource.send(:"#{field}=", translations[index]) + end + end + resource.save + end + + def destroy_remote_translation + if resource.valid? + remote_translation.destroy + else + remote_translation.update(error_message: resource.errors.messages) + end + end + + def resource + @resource ||= remote_translation.remote_translatable + end + + def translations + @translations ||= MicrosoftTranslateClient.new.call(fields_values, locale) + end + + def fields_values + resource.translated_attribute_names.map do |field| + resource.send(field) + end + end + + def locale + remote_translation.locale + end +end diff --git a/spec/lib/remote_translations_caller_spec.rb b/spec/lib/remote_translations_caller_spec.rb new file mode 100644 index 000000000..796fac6d2 --- /dev/null +++ b/spec/lib/remote_translations_caller_spec.rb @@ -0,0 +1,206 @@ +require 'rails_helper' + +describe RemoteTranslationsCaller do + + before do + RemoteTranslation.skip_callback(:create, :after, :enqueue_remote_translation) + end + + describe '#call' do + + context 'Debates' do + + let(:debate) { create(:debate) } + let(:remote_translation) { create(:remote_translation, + remote_translatable: debate, locale: :es) } + let(:remote_translation_caller) { described_class.new(remote_translation) } + + it 'returns the resource with new translation persisted' do + microsoft_translate_client_response = ["Título traducido", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(debate.translations.count).to eq(2) + end + + it "when new translation locale is distinct to default_locale skip length validations" do + microsoft_translate_client_response = ["TT", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(remote_translation.error_message).to eq nil + expect(debate.translations.count).to eq(2) + expect(debate.valid?).to eq true + end + + it "when new translation locale is distinct to default_locale not skip presence validations" do + microsoft_translate_client_response = ["", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(remote_translation.error_message).to include("can't be blank") + expect(debate.translations.count).to eq(1) + expect(debate.valid?).to eq false + end + + it "destroy remote translation instance" do + microsoft_translate_client_response = ["Título traducido", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(RemoteTranslation.count).to eq(0) + end + end + + context 'Proposals' do + + let!(:proposal) { create(:proposal) } + let(:remote_translation) { create(:remote_translation, + remote_translatable: proposal, locale: :es) } + let(:remote_translation_caller) { described_class.new(remote_translation) } + + it 'returns the resource with new translation persisted' do + microsoft_translate_client_response = ["Título traducido", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(proposal.translations.count).to eq(2) + end + + it "when new translation locale is distinct to default_locale skip lenght validations" do + microsoft_translate_client_response = ["TT", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(remote_translation.error_message).to eq nil + expect(proposal.translations.count).to eq(2) + expect(proposal.valid?).to eq true + end + + it "when new translation locale is distinct to default_locale do not skip presence validations" do + microsoft_translate_client_response = ["", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(remote_translation.error_message).to include("can't be blank") + expect(proposal.translations.count).to eq(1) + expect(proposal.valid?).to eq false + end + + it "destroy remote translation instance" do + microsoft_translate_client_response = ["Título traducido", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(RemoteTranslation.count).to eq(0) + end + end + + context 'Budget Investments' do + + let(:budget_investment) { create(:budget_investment) } + let(:remote_translation) { create(:remote_translation, + remote_translatable: budget_investment, + locale: :es) } + let(:remote_translation_caller) { described_class.new(remote_translation) } + + it 'returns the resource with new translation persisted' do + microsoft_translate_client_response = ["Título traducido", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(budget_investment.translations.count).to eq(2) + end + + it "when new translation locale is distinct to default_locale skip lenght validations" do + microsoft_translate_client_response = ["TT", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(remote_translation.error_message).to eq nil + expect(budget_investment.translations.count).to eq(2) + expect(budget_investment.valid?).to eq true + end + + it "when new translation locale is distinct to default_locale not skip presence validations" do + microsoft_translate_client_response = ["", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(remote_translation.error_message).to include("can't be blank") + expect(budget_investment.translations.count).to eq(1) + expect(budget_investment.valid?).to eq false + end + + it "destroy remote translation instance" do + microsoft_translate_client_response = ["Título traducido", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(RemoteTranslation.count).to eq(0) + end + end + + context 'Comments' do + + let(:comment) { create(:comment) } + let(:remote_translation) { create(:remote_translation, + remote_translatable: comment, locale: :es) } + let(:remote_translation_caller) { described_class.new(remote_translation) } + + it 'returns the resource with new translation persisted' do + microsoft_translate_client_response = ["Body traducido"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(comment.translations.count).to eq(2) + end + + it "when new translation locale is distinct to default_locale skip lenght validations" do + microsoft_translate_client_response = ["BT"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(remote_translation.error_message).to eq nil + expect(comment.translations.count).to eq(2) + expect(comment.valid?).to eq true + end + + it "when new translation locale is distinct to default_locale not skip presence validations" do + microsoft_translate_client_response = [""] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(remote_translation.error_message).to include("can't be blank") + expect(comment.translations.count).to eq(1) + expect(comment.valid?).to eq false + end + + it "destroy remote translation instance" do + microsoft_translate_client_response = ["Body traducido"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + + remote_translation_caller.call + + expect(RemoteTranslation.count).to eq(0) + end + end + + end + +end diff --git a/spec/models/remote_translation_spec.rb b/spec/models/remote_translation_spec.rb index e1a8e3616..c2707fd0b 100644 --- a/spec/models/remote_translation_spec.rb +++ b/spec/models/remote_translation_spec.rb @@ -27,6 +27,17 @@ describe RemoteTranslation do remote_translation.remote_translatable_type = nil expect(remote_translation).not_to be_valid end + + describe '#enqueue_remote_translation' do + + it 'after create enqueue Delayed Job' do + Delayed::Worker.delay_jobs = true + + expect { remote_translation.save }.to change { Delayed::Job.count }.by(1) + + Delayed::Worker.delay_jobs = false + end + end end From 21f347778bf5062e86d119ced1e865e8ca79c15f Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 25 Jan 2019 17:24:35 +0100 Subject: [PATCH 110/183] Add Remote Translations Settings - Add to seeds and dev_seeds - Add locales --- app/models/setting.rb | 1 + config/locales/en/settings.yml | 2 ++ config/locales/es/settings.yml | 2 ++ 3 files changed, 5 insertions(+) diff --git a/app/models/setting.rb b/app/models/setting.rb index d20d515d2..a59e38651 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -93,6 +93,7 @@ class Setting < ApplicationRecord "feature.allow_attached_documents": true, "feature.allow_images": true, "feature.help_page": true, + "feature.remote_translations": nil, "feature.translation_interface": nil, "feature.valuation_comment_notification": true, "homepage.widgets.feeds.debates": true, diff --git a/config/locales/en/settings.yml b/config/locales/en/settings.yml index 0f497a1cf..998451a62 100644 --- a/config/locales/en/settings.yml +++ b/config/locales/en/settings.yml @@ -116,6 +116,8 @@ en: public_stats_description: "Display public stats in the Administration panel" help_page: "Help page" help_page_description: 'Displays a Help menu that contains a page with an info section about each enabled feature. Also custom pages and menus can be created in the "Custom pages" and "Custom content blocks" sections' + remote_translations: "Remote translation" + remote_translations_description: "Displays a button that allows users to request a translation when there are not contents in their language." translation_interface: "Translation interface" translation_interface_description: "Displays the manual translation interface that allows users to enter their content in all application available languages. This option only affects user application forms and independently will always be active in the administration panel." valuation_comment_notification: "Valuation comment notification" diff --git a/config/locales/es/settings.yml b/config/locales/es/settings.yml index 90eda0ae4..7a190bf00 100644 --- a/config/locales/es/settings.yml +++ b/config/locales/es/settings.yml @@ -116,6 +116,8 @@ es: public_stats_description: "Muestra las estadísticas públicas en el panel de Administración" help_page: "Página de ayuda" help_page_description: 'Muestra un menú Ayuda que contiene una página con una sección de información sobre cada funcionalidad habilitada. También se pueden crear páginas y menús personalizados en las secciones "Personalizar páginas" y "Personalizar bloques"' + remote_translations: "Traducciones remotas" + remote_translations_description: "Muestra un botón que permite a los usuarios solicitar una traducción de una página no traducida en su idioma." translation_interface: "Interfaz de traducción" translation_interface_description: "Muestra la interfaz de traducción manual permitiendo a los usuarios introducir sus contenidos en todos los idiomas disponibles de la aplicación si así lo desean. Esta opción solo afecta a las vistas de usuarios de la aplicación, en el panel de administración está activa siempre." valuation_comment_notification: "Notificar comentarios de evaluación" From abb81fccf41ef9d2f49bd1fa13b77ed705c78cbf Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 25 Jan 2019 17:12:41 +0100 Subject: [PATCH 111/183] Allow create translations without length validation We have changed validate_translation method on Globalize concern. The objective is skip length validations when locale is distinct to default_locale. First we force apply :length validations when locale is equal to default_locale. After we reject :length from options and apply rest of validation options only when we have more than 1 options. Ej: options = { length: "maximum: 10" } When reject :length option in this example, options is equal to a empty hash and we cant execute validations. --- app/models/concerns/globalizable.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/models/concerns/globalizable.rb b/app/models/concerns/globalizable.rb index e511e5cd5..3523f1c29 100644 --- a/app/models/concerns/globalizable.rb +++ b/app/models/concerns/globalizable.rb @@ -35,7 +35,19 @@ module Globalizable class_methods do def validates_translation(method, options = {}) validates(method, options.merge(if: lambda { |resource| resource.translations.blank? })) - translation_class.instance_eval { validates method, options } + if options.include?(:length) + lenght_validate = { length: options[:length] } + translation_class.instance_eval do + validates method, lenght_validate.merge(if: lambda { |translation| translation.locale == I18n.default_locale }) + end + if options.count > 1 + translation_class.instance_eval do + validates method, options.reject { |key| key == :length } + end + end + else + translation_class.instance_eval { validates method, options } + end end def translation_class_delegate(method) From d2506358ef2cc8ffe392ce082ef4dc346f5f389c Mon Sep 17 00:00:00 2001 From: taitus Date: Tue, 23 Apr 2019 16:56:18 +0200 Subject: [PATCH 112/183] Fix found Hound violations --- .../concerns/remotely_translatable.rb | 6 +- .../remote_translations_controller.rb | 30 ++++--- lib/remote_translations_caller.rb | 1 + .../remote_translation_controller_spec.rb | 13 +-- spec/lib/remote_translations_caller_spec.rb | 86 ++++++++++--------- spec/models/remote_translation_spec.rb | 4 +- 6 files changed, 73 insertions(+), 67 deletions(-) diff --git a/app/controllers/concerns/remotely_translatable.rb b/app/controllers/concerns/remotely_translatable.rb index 600c8a86f..4f030ff6c 100644 --- a/app/controllers/concerns/remotely_translatable.rb +++ b/app/controllers/concerns/remotely_translatable.rb @@ -11,9 +11,9 @@ module RemotelyTranslatable end def remote_translation_for(resource) - { 'remote_translatable_id' => resource.id.to_s, - 'remote_translatable_type' => resource.class.to_s, - 'locale' => I18n.locale } + { "remote_translatable_id" => resource.id.to_s, + "remote_translatable_type" => resource.class.to_s, + "locale" => I18n.locale } end def translation_empty?(resource) diff --git a/app/controllers/remote_translations_controller.rb b/app/controllers/remote_translations_controller.rb index 2ee5fc7a9..d811d2f5c 100644 --- a/app/controllers/remote_translations_controller.rb +++ b/app/controllers/remote_translations_controller.rb @@ -8,25 +8,27 @@ class RemoteTranslationsController < ApplicationController @remote_translations.each do |remote_translation| RemoteTranslation.create(remote_translation) unless translations_enqueued?(remote_translation) end - redirect_to request.referer, notice: t('remote_translations.create.enqueue_remote_translation') + redirect_to request.referer, notice: t("remote_translations.create.enqueue_remote_translation") end private - def remote_translations_params - params.permit(:remote_translations) - end + def remote_translations_params + params.permit(:remote_translations) + end - def set_remote_translations - decoded_remote_translations = ActiveSupport::JSON.decode(remote_translations_params["remote_translations"]) - @remote_translations = decoded_remote_translations.map{ |remote_translation| - remote_translation.slice("remote_translatable_id","remote_translatable_type","locale") - } - end + def set_remote_translations + remote_translations = remote_translations_params["remote_translations"] + decoded_remote_translations = ActiveSupport::JSON.decode(remote_translations) + @remote_translations = decoded_remote_translations.map{ |remote_translation| + remote_translation.slice("remote_translatable_id", + "remote_translatable_type", + "locale") + } + end - - def translations_enqueued?(remote_translation) - RemoteTranslation.remote_translation_enqueued?(remote_translation) - end + def translations_enqueued?(remote_translation) + RemoteTranslation.remote_translation_enqueued?(remote_translation) + end end diff --git a/lib/remote_translations_caller.rb b/lib/remote_translations_caller.rb index 8cc2da961..a73aafe4b 100644 --- a/lib/remote_translations_caller.rb +++ b/lib/remote_translations_caller.rb @@ -27,6 +27,7 @@ class RemoteTranslationsCaller else remote_translation.update(error_message: resource.errors.messages) end + resource.save end def resource diff --git a/spec/controllers/remote_translation_controller_spec.rb b/spec/controllers/remote_translation_controller_spec.rb index 97e6ebaf9..47a85a5bf 100644 --- a/spec/controllers/remote_translation_controller_spec.rb +++ b/spec/controllers/remote_translation_controller_spec.rb @@ -3,11 +3,12 @@ require "rails_helper" describe RemoteTranslationsController do describe "POST create" do + let(:debate) { create(:debate) } + before do - @debate = create(:debate) - @remote_translations_params = [{ remote_translatable_id: @debate.id.to_s, - remote_translatable_type: @debate.class.to_s, - locale: :es }].to_json + @remote_translations_params = [{ remote_translatable_id: debate.id.to_s, + remote_translatable_type: debate.class.to_s, + locale: :es }].to_json allow(controller.request).to receive(:referer).and_return("any_path") Delayed::Worker.delay_jobs = true end @@ -23,7 +24,7 @@ describe RemoteTranslationsController do end it "create remote translation when same remote translation with error_message is enqueued" do - create(:remote_translation, remote_translatable: @debate, locale: :es, error_message: "Has errors") + create(:remote_translation, remote_translatable: debate, locale: :es, error_message: "Has errors") post :create, remote_translations: @remote_translations_params @@ -31,7 +32,7 @@ describe RemoteTranslationsController do end it "not create remote translation when same remote translation is enqueued" do - create(:remote_translation, remote_translatable: @debate, locale: :es) + create(:remote_translation, remote_translatable: debate, locale: :es) post :create, remote_translations: @remote_translations_params diff --git a/spec/lib/remote_translations_caller_spec.rb b/spec/lib/remote_translations_caller_spec.rb index 796fac6d2..537ea3c56 100644 --- a/spec/lib/remote_translations_caller_spec.rb +++ b/spec/lib/remote_translations_caller_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" describe RemoteTranslationsCaller do @@ -6,18 +6,18 @@ describe RemoteTranslationsCaller do RemoteTranslation.skip_callback(:create, :after, :enqueue_remote_translation) end - describe '#call' do + describe "#call" do - context 'Debates' do + context "Debates" do let(:debate) { create(:debate) } let(:remote_translation) { create(:remote_translation, remote_translatable: debate, locale: :es) } let(:remote_translation_caller) { described_class.new(remote_translation) } - it 'returns the resource with new translation persisted' do - microsoft_translate_client_response = ["Título traducido", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + it "returns the resource with new translation persisted" do + response = ["Título traducido", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call @@ -25,8 +25,8 @@ describe RemoteTranslationsCaller do end it "when new translation locale is distinct to default_locale skip length validations" do - microsoft_translate_client_response = ["TT", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + response = ["TT", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call @@ -36,8 +36,8 @@ describe RemoteTranslationsCaller do end it "when new translation locale is distinct to default_locale not skip presence validations" do - microsoft_translate_client_response = ["", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + response = ["", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call @@ -47,8 +47,8 @@ describe RemoteTranslationsCaller do end it "destroy remote translation instance" do - microsoft_translate_client_response = ["Título traducido", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + response = ["Título traducido", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call @@ -56,16 +56,17 @@ describe RemoteTranslationsCaller do end end - context 'Proposals' do + context "Proposals" do let!(:proposal) { create(:proposal) } let(:remote_translation) { create(:remote_translation, remote_translatable: proposal, locale: :es) } let(:remote_translation_caller) { described_class.new(remote_translation) } - it 'returns the resource with new translation persisted' do - microsoft_translate_client_response = ["Título traducido", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + it "returns the resource with new translation persisted" do + response = ["Título traducido", "Descripción traducida", "Pregunta traducida", + "Resumen traducido", nil] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call @@ -73,8 +74,8 @@ describe RemoteTranslationsCaller do end it "when new translation locale is distinct to default_locale skip lenght validations" do - microsoft_translate_client_response = ["TT", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + response = ["TT", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call @@ -84,8 +85,8 @@ describe RemoteTranslationsCaller do end it "when new translation locale is distinct to default_locale do not skip presence validations" do - microsoft_translate_client_response = ["", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + response = ["", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call @@ -95,8 +96,9 @@ describe RemoteTranslationsCaller do end it "destroy remote translation instance" do - microsoft_translate_client_response = ["Título traducido", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + response = ["Título traducido", "Descripción traducida", "Pregunta traducida", + "Resumen traducido", nil] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call @@ -104,7 +106,7 @@ describe RemoteTranslationsCaller do end end - context 'Budget Investments' do + context "Budget Investments" do let(:budget_investment) { create(:budget_investment) } let(:remote_translation) { create(:remote_translation, @@ -112,9 +114,9 @@ describe RemoteTranslationsCaller do locale: :es) } let(:remote_translation_caller) { described_class.new(remote_translation) } - it 'returns the resource with new translation persisted' do - microsoft_translate_client_response = ["Título traducido", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + it "returns the resource with new translation persisted" do + response = ["Título traducido", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call @@ -122,8 +124,8 @@ describe RemoteTranslationsCaller do end it "when new translation locale is distinct to default_locale skip lenght validations" do - microsoft_translate_client_response = ["TT", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + response = ["TT", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call @@ -133,8 +135,8 @@ describe RemoteTranslationsCaller do end it "when new translation locale is distinct to default_locale not skip presence validations" do - microsoft_translate_client_response = ["", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + response = ["", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call @@ -144,8 +146,8 @@ describe RemoteTranslationsCaller do end it "destroy remote translation instance" do - microsoft_translate_client_response = ["Título traducido", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + response = ["Título traducido", "Descripción traducida"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call @@ -153,16 +155,16 @@ describe RemoteTranslationsCaller do end end - context 'Comments' do + context "Comments" do let(:comment) { create(:comment) } let(:remote_translation) { create(:remote_translation, remote_translatable: comment, locale: :es) } let(:remote_translation_caller) { described_class.new(remote_translation) } - it 'returns the resource with new translation persisted' do - microsoft_translate_client_response = ["Body traducido"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + it "returns the resource with new translation persisted" do + response = ["Body traducido"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call @@ -170,8 +172,8 @@ describe RemoteTranslationsCaller do end it "when new translation locale is distinct to default_locale skip lenght validations" do - microsoft_translate_client_response = ["BT"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + response = ["BT"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call @@ -181,8 +183,8 @@ describe RemoteTranslationsCaller do end it "when new translation locale is distinct to default_locale not skip presence validations" do - microsoft_translate_client_response = [""] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + response = [""] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call @@ -192,8 +194,8 @@ describe RemoteTranslationsCaller do end it "destroy remote translation instance" do - microsoft_translate_client_response = ["Body traducido"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(microsoft_translate_client_response) + response = ["Body traducido"] + expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) remote_translation_caller.call diff --git a/spec/models/remote_translation_spec.rb b/spec/models/remote_translation_spec.rb index c2707fd0b..8fefe9000 100644 --- a/spec/models/remote_translation_spec.rb +++ b/spec/models/remote_translation_spec.rb @@ -28,9 +28,9 @@ describe RemoteTranslation do expect(remote_translation).not_to be_valid end - describe '#enqueue_remote_translation' do + describe "#enqueue_remote_translation" do - it 'after create enqueue Delayed Job' do + it "after create enqueue Delayed Job" do Delayed::Worker.delay_jobs = true expect { remote_translation.save }.to change { Delayed::Job.count }.by(1) From 91ba5ff8796384a26510d08158f2ba316ef9080f Mon Sep 17 00:00:00 2001 From: taitus Date: Wed, 24 Apr 2019 16:23:09 +0200 Subject: [PATCH 113/183] Fix flakys specs --- spec/lib/remote_translations_caller_spec.rb | 4 ++++ spec/models/remote_translation_spec.rb | 10 +++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/spec/lib/remote_translations_caller_spec.rb b/spec/lib/remote_translations_caller_spec.rb index 537ea3c56..3aef505c7 100644 --- a/spec/lib/remote_translations_caller_spec.rb +++ b/spec/lib/remote_translations_caller_spec.rb @@ -6,6 +6,10 @@ describe RemoteTranslationsCaller do RemoteTranslation.skip_callback(:create, :after, :enqueue_remote_translation) end + after do + RemoteTranslation.set_callback(:create, :after, :enqueue_remote_translation) + end + describe "#call" do context "Debates" do diff --git a/spec/models/remote_translation_spec.rb b/spec/models/remote_translation_spec.rb index 8fefe9000..a21b59e84 100644 --- a/spec/models/remote_translation_spec.rb +++ b/spec/models/remote_translation_spec.rb @@ -30,14 +30,18 @@ describe RemoteTranslation do describe "#enqueue_remote_translation" do - it "after create enqueue Delayed Job" do + before do Delayed::Worker.delay_jobs = true + end - expect { remote_translation.save }.to change { Delayed::Job.count }.by(1) - + after do Delayed::Worker.delay_jobs = false end + it "after create enqueue Delayed Job" do + expect { remote_translation.save }.to change { Delayed::Job.count }.by(1) + end + end end From d29656d78fee06f49318e40bbfe8afcbf6b5c43f Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 24 May 2019 15:13:15 +0200 Subject: [PATCH 114/183] Add MicrososftTranslateClient to new namespace - Rename to Client - Add to new namespace RemoteTranslations::Microsoft - Update references to new namespace --- .../microsoft/client.rb} | 2 +- lib/remote_translations_caller.rb | 2 +- lib/sentences_parser.rb | 2 +- .../microsoft/client_spec.rb} | 32 +++++++++---------- spec/lib/remote_translations_caller_spec.rb | 32 +++++++++---------- 5 files changed, 35 insertions(+), 35 deletions(-) rename lib/{microsoft_translate_client.rb => remote_translations/microsoft/client.rb} (97%) rename spec/lib/{microsoft_translate_client_spec.rb => remote_translations/microsoft/client_spec.rb} (86%) diff --git a/lib/microsoft_translate_client.rb b/lib/remote_translations/microsoft/client.rb similarity index 97% rename from lib/microsoft_translate_client.rb rename to lib/remote_translations/microsoft/client.rb index 45c8845c8..c68447192 100644 --- a/lib/microsoft_translate_client.rb +++ b/lib/remote_translations/microsoft/client.rb @@ -2,7 +2,7 @@ require "translator-text" include SentencesParser include RemoteAvailableLocales -class MicrosoftTranslateClient +class RemoteTranslations::Microsoft::Client CHARACTERS_LIMIT_PER_REQUEST = 5000 PREVENTING_TRANSLATION_KEY = "notranslate" diff --git a/lib/remote_translations_caller.rb b/lib/remote_translations_caller.rb index a73aafe4b..75d8a6e50 100644 --- a/lib/remote_translations_caller.rb +++ b/lib/remote_translations_caller.rb @@ -35,7 +35,7 @@ class RemoteTranslationsCaller end def translations - @translations ||= MicrosoftTranslateClient.new.call(fields_values, locale) + @translations ||= RemoteTranslations::Microsoft::Client.new.call(fields_values, locale) end def fields_values diff --git a/lib/sentences_parser.rb b/lib/sentences_parser.rb index 890a6eb57..1403b0698 100644 --- a/lib/sentences_parser.rb +++ b/lib/sentences_parser.rb @@ -1,7 +1,7 @@ module SentencesParser def detect_split_position(text) - minimum_valid_index = text.size - MicrosoftTranslateClient::CHARACTERS_LIMIT_PER_REQUEST + minimum_valid_index = text.size - RemoteTranslations::Microsoft::Client::CHARACTERS_LIMIT_PER_REQUEST valid_point = text[minimum_valid_index..text.size].index(".") valid_whitespace = text[minimum_valid_index..text.size].index(" ") diff --git a/spec/lib/microsoft_translate_client_spec.rb b/spec/lib/remote_translations/microsoft/client_spec.rb similarity index 86% rename from spec/lib/microsoft_translate_client_spec.rb rename to spec/lib/remote_translations/microsoft/client_spec.rb index e93203502..fcabb5c1d 100644 --- a/spec/lib/microsoft_translate_client_spec.rb +++ b/spec/lib/remote_translations/microsoft/client_spec.rb @@ -1,8 +1,8 @@ require "rails_helper" -describe MicrosoftTranslateClient do +describe RemoteTranslations::Microsoft::Client do - let(:microsoft_client) { described_class.new } + let(:client) { described_class.new } describe "#call" do @@ -12,7 +12,7 @@ describe MicrosoftTranslateClient do expect_any_instance_of(TranslatorText::Client).to receive(:translate).and_return(response) - result = microsoft_client.call([ "New title", "New description"], :es) + result = client.call([ "New title", "New description"], :es) expect(result).to eq(["Nuevo título", "Nueva descripción"]) end @@ -22,7 +22,7 @@ describe MicrosoftTranslateClient do expect_any_instance_of(TranslatorText::Client).to receive(:translate).and_return(response) - result = microsoft_client.call([nil, "New description"], :es) + result = client.call([nil, "New description"], :es) expect(result).to eq([nil, "Nueva descripción"]) end @@ -31,7 +31,7 @@ describe MicrosoftTranslateClient do context "when characters from request are greater than characters limit" do it "response has the expected result when the request has 2 texts, where both less than CHARACTERS_LIMIT_PER_REQUEST" do - stub_const("MicrosoftTranslateClient::CHARACTERS_LIMIT_PER_REQUEST", 20) + stub_const("RemoteTranslations::Microsoft::Client::CHARACTERS_LIMIT_PER_REQUEST", 20) text_en = Faker::Lorem.characters(11) another_text_en = Faker::Lorem.characters(11) @@ -47,13 +47,13 @@ describe MicrosoftTranslateClient do .times .and_return(response_another_text) - result = microsoft_client.call([text_en, another_text_en], :es) + result = client.call([text_en, another_text_en], :es) expect(result).to eq([translated_text_es, another_translated_text_es]) end it "response has the expected result when the request has 2 texts and both are greater than CHARACTERS_LIMIT_PER_REQUEST" do - stub_const("MicrosoftTranslateClient::CHARACTERS_LIMIT_PER_REQUEST", 20) + stub_const("RemoteTranslations::Microsoft::Client::CHARACTERS_LIMIT_PER_REQUEST", 20) start_text_en = Faker::Lorem.characters(10) + " " end_text_en = Faker::Lorem.characters(10) text_en = start_text_en + end_text_en @@ -92,7 +92,7 @@ describe MicrosoftTranslateClient do .times .and_return(response_another_end_text) - result = microsoft_client.call([text_en, another_text_en], :es) + result = client.call([text_en, another_text_en], :es) expect(result).to eq([translated_text_es, another_translated_text_es]) end @@ -105,10 +105,10 @@ describe MicrosoftTranslateClient do context "text has less characters than characters limit" do it "does not split the text" do - stub_const("MicrosoftTranslateClient::CHARACTERS_LIMIT_PER_REQUEST", 20) + stub_const("RemoteTranslations::Microsoft::Client::CHARACTERS_LIMIT_PER_REQUEST", 20) text_to_translate = Faker::Lorem.characters(10) - result = microsoft_client.fragments_for(text_to_translate) + result = client.fragments_for(text_to_translate) expect(result).to eq [text_to_translate] end @@ -116,36 +116,36 @@ describe MicrosoftTranslateClient do context "text has more characters than characters limit" do it "to split text by first valid dot when there is a dot for split" do - stub_const("MicrosoftTranslateClient::CHARACTERS_LIMIT_PER_REQUEST", 20) + stub_const("RemoteTranslations::Microsoft::Client::CHARACTERS_LIMIT_PER_REQUEST", 20) start_text = Faker::Lorem.characters(10) + "." end_text = Faker::Lorem.characters(10) text_to_translate = start_text + end_text - result = microsoft_client.fragments_for(text_to_translate) + result = client.fragments_for(text_to_translate) expect(result).to eq([start_text, end_text]) end it "to split text by first valid space when there is not a dot for split but there is a space" do - stub_const("MicrosoftTranslateClient::CHARACTERS_LIMIT_PER_REQUEST", 20) + stub_const("RemoteTranslations::Microsoft::Client::CHARACTERS_LIMIT_PER_REQUEST", 20) start_text = Faker::Lorem.characters(10) + " " end_text = Faker::Lorem.characters(10) text_to_translate = start_text + end_text - result = microsoft_client.fragments_for(text_to_translate) + result = client.fragments_for(text_to_translate) expect(result).to eq([start_text, end_text]) end it "to split text in the middle of a word when there are not valid dots and spaces" do - stub_const("MicrosoftTranslateClient::CHARACTERS_LIMIT_PER_REQUEST", 40) + stub_const("RemoteTranslations::Microsoft::Client::CHARACTERS_LIMIT_PER_REQUEST", 40) sub_part_text_1 = Faker::Lorem.characters(5) + " ." sub_part_text_2 = Faker::Lorem.characters(5) sub_part_text_3 = Faker::Lorem.characters(9) sub_part_text_4 = Faker::Lorem.characters(30) text_to_translate = sub_part_text_1 + sub_part_text_2 + sub_part_text_3 + sub_part_text_4 - result = microsoft_client.fragments_for(text_to_translate) + result = client.fragments_for(text_to_translate) expect(result).to eq([sub_part_text_1 + sub_part_text_2, sub_part_text_3 + sub_part_text_4]) end diff --git a/spec/lib/remote_translations_caller_spec.rb b/spec/lib/remote_translations_caller_spec.rb index 3aef505c7..25b64005f 100644 --- a/spec/lib/remote_translations_caller_spec.rb +++ b/spec/lib/remote_translations_caller_spec.rb @@ -21,7 +21,7 @@ describe RemoteTranslationsCaller do it "returns the resource with new translation persisted" do response = ["Título traducido", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call @@ -30,7 +30,7 @@ describe RemoteTranslationsCaller do it "when new translation locale is distinct to default_locale skip length validations" do response = ["TT", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call @@ -41,7 +41,7 @@ describe RemoteTranslationsCaller do it "when new translation locale is distinct to default_locale not skip presence validations" do response = ["", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call @@ -52,7 +52,7 @@ describe RemoteTranslationsCaller do it "destroy remote translation instance" do response = ["Título traducido", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call @@ -70,7 +70,7 @@ describe RemoteTranslationsCaller do it "returns the resource with new translation persisted" do response = ["Título traducido", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call @@ -79,7 +79,7 @@ describe RemoteTranslationsCaller do it "when new translation locale is distinct to default_locale skip lenght validations" do response = ["TT", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call @@ -90,7 +90,7 @@ describe RemoteTranslationsCaller do it "when new translation locale is distinct to default_locale do not skip presence validations" do response = ["", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call @@ -102,7 +102,7 @@ describe RemoteTranslationsCaller do it "destroy remote translation instance" do response = ["Título traducido", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call @@ -120,7 +120,7 @@ describe RemoteTranslationsCaller do it "returns the resource with new translation persisted" do response = ["Título traducido", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call @@ -129,7 +129,7 @@ describe RemoteTranslationsCaller do it "when new translation locale is distinct to default_locale skip lenght validations" do response = ["TT", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call @@ -140,7 +140,7 @@ describe RemoteTranslationsCaller do it "when new translation locale is distinct to default_locale not skip presence validations" do response = ["", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call @@ -151,7 +151,7 @@ describe RemoteTranslationsCaller do it "destroy remote translation instance" do response = ["Título traducido", "Descripción traducida"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call @@ -168,7 +168,7 @@ describe RemoteTranslationsCaller do it "returns the resource with new translation persisted" do response = ["Body traducido"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call @@ -177,7 +177,7 @@ describe RemoteTranslationsCaller do it "when new translation locale is distinct to default_locale skip lenght validations" do response = ["BT"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call @@ -188,7 +188,7 @@ describe RemoteTranslationsCaller do it "when new translation locale is distinct to default_locale not skip presence validations" do response = [""] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call @@ -199,7 +199,7 @@ describe RemoteTranslationsCaller do it "destroy remote translation instance" do response = ["Body traducido"] - expect_any_instance_of(MicrosoftTranslateClient).to receive(:call).and_return(response) + expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) remote_translation_caller.call From 4c1704a5a358e6167d6224bb81ff4296f24db21c Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 24 May 2019 15:22:14 +0200 Subject: [PATCH 115/183] Add RemoteAvailableLocales to new namespace Add to new name space RemoteTranslations::Microsoft and rename to AvailableLocales. --- .../microsoft/available_locales.rb} | 2 +- lib/remote_translations/microsoft/client.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename lib/{remote_available_locales.rb => remote_translations/microsoft/available_locales.rb} (94%) diff --git a/lib/remote_available_locales.rb b/lib/remote_translations/microsoft/available_locales.rb similarity index 94% rename from lib/remote_available_locales.rb rename to lib/remote_translations/microsoft/available_locales.rb index a7e66437a..2b5f506f3 100644 --- a/lib/remote_available_locales.rb +++ b/lib/remote_translations/microsoft/available_locales.rb @@ -3,7 +3,7 @@ require "uri" require "cgi" require "json" -module RemoteAvailableLocales +module RemoteTranslations::Microsoft::AvailableLocales def load_remote_locales remote_available_locales.map { |locale| locale.first } diff --git a/lib/remote_translations/microsoft/client.rb b/lib/remote_translations/microsoft/client.rb index c68447192..c9808595c 100644 --- a/lib/remote_translations/microsoft/client.rb +++ b/lib/remote_translations/microsoft/client.rb @@ -1,6 +1,6 @@ require "translator-text" include SentencesParser -include RemoteAvailableLocales +include RemoteTranslations::Microsoft::AvailableLocales class RemoteTranslations::Microsoft::Client CHARACTERS_LIMIT_PER_REQUEST = 5000 From 510307b0bd96e283fae8e5ca79b7c78c788bd8ce Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 24 May 2019 15:24:16 +0200 Subject: [PATCH 116/183] Add SentencesParser to new namespace Add to new name space RemoteTranslations::Microsoft --- lib/remote_translations/microsoft/client.rb | 2 +- lib/{ => remote_translations/microsoft}/sentences_parser.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename lib/{ => remote_translations/microsoft}/sentences_parser.rb (93%) diff --git a/lib/remote_translations/microsoft/client.rb b/lib/remote_translations/microsoft/client.rb index c9808595c..22f4906b3 100644 --- a/lib/remote_translations/microsoft/client.rb +++ b/lib/remote_translations/microsoft/client.rb @@ -1,5 +1,5 @@ require "translator-text" -include SentencesParser +include RemoteTranslations::Microsoft::SentencesParser include RemoteTranslations::Microsoft::AvailableLocales class RemoteTranslations::Microsoft::Client diff --git a/lib/sentences_parser.rb b/lib/remote_translations/microsoft/sentences_parser.rb similarity index 93% rename from lib/sentences_parser.rb rename to lib/remote_translations/microsoft/sentences_parser.rb index 1403b0698..792d5e75f 100644 --- a/lib/sentences_parser.rb +++ b/lib/remote_translations/microsoft/sentences_parser.rb @@ -1,4 +1,4 @@ -module SentencesParser +module RemoteTranslations::Microsoft::SentencesParser def detect_split_position(text) minimum_valid_index = text.size - RemoteTranslations::Microsoft::Client::CHARACTERS_LIMIT_PER_REQUEST From 1d3dd6f7277da2b3827b61e878156cbf91ff7d77 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 24 May 2019 15:32:10 +0200 Subject: [PATCH 117/183] Add RemoteTranslationsCaller to new namespace - Rename to Caller - Add to new namespace RemoteTranslations - Update references to new namespace --- app/models/remote_translation.rb | 2 +- .../caller.rb} | 2 +- .../caller_spec.rb} | 42 +++++++++---------- 3 files changed, 23 insertions(+), 23 deletions(-) rename lib/{remote_translations_caller.rb => remote_translations/caller.rb} (97%) rename spec/lib/{remote_translations_caller_spec.rb => remote_translations/caller_spec.rb} (88%) diff --git a/app/models/remote_translation.rb b/app/models/remote_translation.rb index 51851267d..d669f9083 100644 --- a/app/models/remote_translation.rb +++ b/app/models/remote_translation.rb @@ -9,7 +9,7 @@ class RemoteTranslation < ApplicationRecord after_create :enqueue_remote_translation def enqueue_remote_translation - RemoteTranslationsCaller.new(self).delay.call + RemoteTranslations::Caller.new(self).delay.call end def self.remote_translation_enqueued?(remote_translation) diff --git a/lib/remote_translations_caller.rb b/lib/remote_translations/caller.rb similarity index 97% rename from lib/remote_translations_caller.rb rename to lib/remote_translations/caller.rb index 75d8a6e50..ed49601e1 100644 --- a/lib/remote_translations_caller.rb +++ b/lib/remote_translations/caller.rb @@ -1,4 +1,4 @@ -class RemoteTranslationsCaller +class RemoteTranslations::Caller attr_reader :remote_translation def initialize(remote_translation) diff --git a/spec/lib/remote_translations_caller_spec.rb b/spec/lib/remote_translations/caller_spec.rb similarity index 88% rename from spec/lib/remote_translations_caller_spec.rb rename to spec/lib/remote_translations/caller_spec.rb index 25b64005f..4b55c2fde 100644 --- a/spec/lib/remote_translations_caller_spec.rb +++ b/spec/lib/remote_translations/caller_spec.rb @@ -1,6 +1,6 @@ require "rails_helper" -describe RemoteTranslationsCaller do +describe RemoteTranslations::Caller do before do RemoteTranslation.skip_callback(:create, :after, :enqueue_remote_translation) @@ -17,13 +17,13 @@ describe RemoteTranslationsCaller do let(:debate) { create(:debate) } let(:remote_translation) { create(:remote_translation, remote_translatable: debate, locale: :es) } - let(:remote_translation_caller) { described_class.new(remote_translation) } + let(:caller) { described_class.new(remote_translation) } it "returns the resource with new translation persisted" do response = ["Título traducido", "Descripción traducida"] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(debate.translations.count).to eq(2) end @@ -32,7 +32,7 @@ describe RemoteTranslationsCaller do response = ["TT", "Descripción traducida"] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(remote_translation.error_message).to eq nil expect(debate.translations.count).to eq(2) @@ -43,7 +43,7 @@ describe RemoteTranslationsCaller do response = ["", "Descripción traducida"] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(remote_translation.error_message).to include("can't be blank") expect(debate.translations.count).to eq(1) @@ -54,7 +54,7 @@ describe RemoteTranslationsCaller do response = ["Título traducido", "Descripción traducida"] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(RemoteTranslation.count).to eq(0) end @@ -65,14 +65,14 @@ describe RemoteTranslationsCaller do let!(:proposal) { create(:proposal) } let(:remote_translation) { create(:remote_translation, remote_translatable: proposal, locale: :es) } - let(:remote_translation_caller) { described_class.new(remote_translation) } + let(:caller) { described_class.new(remote_translation) } it "returns the resource with new translation persisted" do response = ["Título traducido", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(proposal.translations.count).to eq(2) end @@ -81,7 +81,7 @@ describe RemoteTranslationsCaller do response = ["TT", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(remote_translation.error_message).to eq nil expect(proposal.translations.count).to eq(2) @@ -92,7 +92,7 @@ describe RemoteTranslationsCaller do response = ["", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(remote_translation.error_message).to include("can't be blank") expect(proposal.translations.count).to eq(1) @@ -104,7 +104,7 @@ describe RemoteTranslationsCaller do "Resumen traducido", nil] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(RemoteTranslation.count).to eq(0) end @@ -116,13 +116,13 @@ describe RemoteTranslationsCaller do let(:remote_translation) { create(:remote_translation, remote_translatable: budget_investment, locale: :es) } - let(:remote_translation_caller) { described_class.new(remote_translation) } + let(:caller) { described_class.new(remote_translation) } it "returns the resource with new translation persisted" do response = ["Título traducido", "Descripción traducida"] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(budget_investment.translations.count).to eq(2) end @@ -131,7 +131,7 @@ describe RemoteTranslationsCaller do response = ["TT", "Descripción traducida"] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(remote_translation.error_message).to eq nil expect(budget_investment.translations.count).to eq(2) @@ -142,7 +142,7 @@ describe RemoteTranslationsCaller do response = ["", "Descripción traducida"] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(remote_translation.error_message).to include("can't be blank") expect(budget_investment.translations.count).to eq(1) @@ -153,7 +153,7 @@ describe RemoteTranslationsCaller do response = ["Título traducido", "Descripción traducida"] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(RemoteTranslation.count).to eq(0) end @@ -164,13 +164,13 @@ describe RemoteTranslationsCaller do let(:comment) { create(:comment) } let(:remote_translation) { create(:remote_translation, remote_translatable: comment, locale: :es) } - let(:remote_translation_caller) { described_class.new(remote_translation) } + let(:caller) { described_class.new(remote_translation) } it "returns the resource with new translation persisted" do response = ["Body traducido"] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(comment.translations.count).to eq(2) end @@ -179,7 +179,7 @@ describe RemoteTranslationsCaller do response = ["BT"] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(remote_translation.error_message).to eq nil expect(comment.translations.count).to eq(2) @@ -190,7 +190,7 @@ describe RemoteTranslationsCaller do response = [""] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(remote_translation.error_message).to include("can't be blank") expect(comment.translations.count).to eq(1) @@ -201,7 +201,7 @@ describe RemoteTranslationsCaller do response = ["Body traducido"] expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) - remote_translation_caller.call + caller.call expect(RemoteTranslation.count).to eq(0) end From 6ad294e71f96086e9d369fcf4f1514bb8b6c79b8 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 24 May 2019 18:22:24 +0200 Subject: [PATCH 118/183] Fix houncibot offenses. --- .../microsoft/available_locales.rb | 26 +++++++------- .../microsoft/sentences_parser.rb | 3 +- spec/lib/remote_translations/caller_spec.rb | 34 ++++++++++--------- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/lib/remote_translations/microsoft/available_locales.rb b/lib/remote_translations/microsoft/available_locales.rb index 2b5f506f3..5a9d0fcb8 100644 --- a/lib/remote_translations/microsoft/available_locales.rb +++ b/lib/remote_translations/microsoft/available_locales.rb @@ -24,22 +24,22 @@ module RemoteTranslations::Microsoft::AvailableLocales private - def remote_available_locales - host = "https://api.cognitive.microsofttranslator.com" - path = "/languages?api-version=3.0" + def remote_available_locales + host = "https://api.cognitive.microsofttranslator.com" + path = "/languages?api-version=3.0" - uri = URI (host + path) + uri = URI (host + path) - request = Net::HTTP::Get.new(uri) - request["Ocp-Apim-Subscription-Key"] = Rails.application.secrets.microsoft_api_key + request = Net::HTTP::Get.new(uri) + request["Ocp-Apim-Subscription-Key"] = Rails.application.secrets.microsoft_api_key - response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == "https") do |http| - http.request (request) + response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == "https") do |http| + http.request (request) + end + + result = response.body.force_encoding("utf-8") + + JSON.parse(result)["translation"] end - result = response.body.force_encoding("utf-8") - - JSON.parse(result)["translation"] - end - end diff --git a/lib/remote_translations/microsoft/sentences_parser.rb b/lib/remote_translations/microsoft/sentences_parser.rb index 792d5e75f..d6f026288 100644 --- a/lib/remote_translations/microsoft/sentences_parser.rb +++ b/lib/remote_translations/microsoft/sentences_parser.rb @@ -1,7 +1,8 @@ module RemoteTranslations::Microsoft::SentencesParser def detect_split_position(text) - minimum_valid_index = text.size - RemoteTranslations::Microsoft::Client::CHARACTERS_LIMIT_PER_REQUEST + limit = RemoteTranslations::Microsoft::Client::CHARACTERS_LIMIT_PER_REQUEST + minimum_valid_index = text.size - limit valid_point = text[minimum_valid_index..text.size].index(".") valid_whitespace = text[minimum_valid_index..text.size].index(" ") diff --git a/spec/lib/remote_translations/caller_spec.rb b/spec/lib/remote_translations/caller_spec.rb index 4b55c2fde..94ac7ebc3 100644 --- a/spec/lib/remote_translations/caller_spec.rb +++ b/spec/lib/remote_translations/caller_spec.rb @@ -12,6 +12,8 @@ describe RemoteTranslations::Caller do describe "#call" do + let(:client) { RemoteTranslations::Microsoft::Client } + context "Debates" do let(:debate) { create(:debate) } @@ -21,7 +23,7 @@ describe RemoteTranslations::Caller do it "returns the resource with new translation persisted" do response = ["Título traducido", "Descripción traducida"] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call @@ -30,7 +32,7 @@ describe RemoteTranslations::Caller do it "when new translation locale is distinct to default_locale skip length validations" do response = ["TT", "Descripción traducida"] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call @@ -41,7 +43,7 @@ describe RemoteTranslations::Caller do it "when new translation locale is distinct to default_locale not skip presence validations" do response = ["", "Descripción traducida"] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call @@ -52,7 +54,7 @@ describe RemoteTranslations::Caller do it "destroy remote translation instance" do response = ["Título traducido", "Descripción traducida"] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call @@ -70,7 +72,7 @@ describe RemoteTranslations::Caller do it "returns the resource with new translation persisted" do response = ["Título traducido", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call @@ -79,7 +81,7 @@ describe RemoteTranslations::Caller do it "when new translation locale is distinct to default_locale skip lenght validations" do response = ["TT", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call @@ -90,7 +92,7 @@ describe RemoteTranslations::Caller do it "when new translation locale is distinct to default_locale do not skip presence validations" do response = ["", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call @@ -102,7 +104,7 @@ describe RemoteTranslations::Caller do it "destroy remote translation instance" do response = ["Título traducido", "Descripción traducida", "Pregunta traducida", "Resumen traducido", nil] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call @@ -120,7 +122,7 @@ describe RemoteTranslations::Caller do it "returns the resource with new translation persisted" do response = ["Título traducido", "Descripción traducida"] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call @@ -129,7 +131,7 @@ describe RemoteTranslations::Caller do it "when new translation locale is distinct to default_locale skip lenght validations" do response = ["TT", "Descripción traducida"] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call @@ -140,7 +142,7 @@ describe RemoteTranslations::Caller do it "when new translation locale is distinct to default_locale not skip presence validations" do response = ["", "Descripción traducida"] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call @@ -151,7 +153,7 @@ describe RemoteTranslations::Caller do it "destroy remote translation instance" do response = ["Título traducido", "Descripción traducida"] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call @@ -168,7 +170,7 @@ describe RemoteTranslations::Caller do it "returns the resource with new translation persisted" do response = ["Body traducido"] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call @@ -177,7 +179,7 @@ describe RemoteTranslations::Caller do it "when new translation locale is distinct to default_locale skip lenght validations" do response = ["BT"] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call @@ -188,7 +190,7 @@ describe RemoteTranslations::Caller do it "when new translation locale is distinct to default_locale not skip presence validations" do response = [""] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call @@ -199,7 +201,7 @@ describe RemoteTranslations::Caller do it "destroy remote translation instance" do response = ["Body traducido"] - expect_any_instance_of(RemoteTranslations::Microsoft::Client).to receive(:call).and_return(response) + expect_any_instance_of(client).to receive(:call).and_return(response) caller.call From cbd7ab7179afdaf6d3aed35b95723d48def4967d Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 25 Jan 2019 16:12:59 +0100 Subject: [PATCH 119/183] Add remote translation button - Create partial to render remote translation button. This button will send remote_translations as json to remote translations controller. - Add locales - Add styles Co-Authored-By: alessandro --- app/assets/stylesheets/layout.scss | 20 +++++++++++++++++++ .../_remote_translations_button.html.erb | 11 ++++++++++ config/locales/en/general.yml | 2 ++ config/locales/es/general.yml | 2 ++ 4 files changed, 35 insertions(+) create mode 100644 app/views/shared/_remote_translations_button.html.erb diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss index 8e7334935..24b97f9e1 100644 --- a/app/assets/stylesheets/layout.scss +++ b/app/assets/stylesheets/layout.scss @@ -474,6 +474,26 @@ header { } } + .remote-translations-button { + + .callout { + margin: 0; + padding: rem-calc(6); + + [type="submit"] { + background: none; + border: 0; + cursor: pointer; + font-weight: bold; + color: $brand; + + &:hover { + text-decoration: underline; + } + } + } + } + .external-links { float: none; padding: rem-calc(6) 0; diff --git a/app/views/shared/_remote_translations_button.html.erb b/app/views/shared/_remote_translations_button.html.erb new file mode 100644 index 000000000..83f805fce --- /dev/null +++ b/app/views/shared/_remote_translations_button.html.erb @@ -0,0 +1,11 @@ +
+ <% if display_remote_translation_button?(remote_translations) %> + <%= form_tag remote_translations_path do %> + <%= hidden_field_tag :remote_translations, remote_translations.to_json %> + <%= t("remote_translations.text") %> + <%= submit_tag t("remote_translations.button") %> + <% end %> + <% else %> + <%= t("remote_translations.all_remote_translations_enqueued_text") %> + <% end %> +
diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index 650849ca3..472fd60f8 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -1034,5 +1034,7 @@ en: borda: Borda votation dowdall: Dowdall votation remote_translations: + text: The content of this page is not available in your language create: enqueue_remote_translation: Translations have been correctly requested. + button: Translate page diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index 435ce7a10..f2776a5c9 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -1031,5 +1031,7 @@ es: borda: Votación con recuento Borda dowdall: Votación con recuento Dowdall remote_translations: + text: El contenido de esta página no está disponible en tu idioma create: enqueue_remote_translation: Se han solicitado correctamente las traducciones. + button: Traducir página From 72d1893703e6f109c27a8343fb883ca7e2c66eb8 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 25 Jan 2019 16:32:46 +0100 Subject: [PATCH 120/183] Manage the remote translation button display - Add remote_translation_button partial to layout - Only display button when we have remote_translations and if current locale is include on available locales from remote translations service. - Recover available locales from remote translations service. Use daily_cache to detect every day if remote translation service has added new available locale. Co-Authored-By: alessandro --- app/helpers/remote_translations_helper.rb | 6 ++ app/views/layouts/_header.html.erb | 3 + .../microsoft/available_locales.rb | 14 +++- spec/features/remote_translations_spec.rb | 83 +++++++++++++++++++ 4 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 app/helpers/remote_translations_helper.rb create mode 100644 spec/features/remote_translations_spec.rb diff --git a/app/helpers/remote_translations_helper.rb b/app/helpers/remote_translations_helper.rb new file mode 100644 index 000000000..d81fb64f8 --- /dev/null +++ b/app/helpers/remote_translations_helper.rb @@ -0,0 +1,6 @@ +module RemoteTranslationsHelper + + def display_remote_translation_info?(remote_translations, locale) + remote_translations.present? && RemoteTranslations::Microsoft::AvailableLocales.include_locale?(locale) + end +end diff --git a/app/views/layouts/_header.html.erb b/app/views/layouts/_header.html.erb index 03014f740..e93075833 100644 --- a/app/views/layouts/_header.html.erb +++ b/app/views/layouts/_header.html.erb @@ -1,4 +1,7 @@
+ <% if display_remote_translation_info?(@remote_translations, I18n.locale) %> + <%= render "shared/remote_translations_button", remote_translations: @remote_translations %> + <% end %>