From 428644cd3e445eb57908053b476c627ed8a846b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Wed, 11 Nov 2020 11:39:10 +0100 Subject: [PATCH 1/7] Add SDG goal model Since data for this model (title and description) is not generated in CONSUL but by the United Nations, we aren't storing it in the database but in our YAML translation files. The reasoning is as follows. Suppose that, a few months after CONSUL gets SDG support, a new language is added to CONSUL. With YAML files, getting the texts in the new language would mean updating CONSUL to include the new language. But if we store these texts in the database, it means we have to update the databases of all existing CONSUL installations, either each installation by themselves (duplicating efforts) or running a rake task (which we would have to write each time). So we believe using translations works better in this case. We're still storing records in the database with the code, so they can be easily referenced via `has_many` or `has_many :through` associations. --- app/models/sdg.rb | 5 +++ app/models/sdg/goal.rb | 11 +++++++ config/initializers/inflections.rb | 1 + config/locales/en/sdg.yml | 6 ++++ config/locales/es/sdg.yml | 6 ++++ db/migrate/20201111095452_create_sdg_goals.rb | 10 ++++++ db/schema.rb | 9 +++++- spec/factories/sdg.rb | 5 +++ spec/models/sdg/goal_spec.rb | 31 +++++++++++++++++++ 9 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 app/models/sdg.rb create mode 100644 app/models/sdg/goal.rb create mode 100644 config/locales/en/sdg.yml create mode 100644 config/locales/es/sdg.yml create mode 100644 db/migrate/20201111095452_create_sdg_goals.rb create mode 100644 spec/factories/sdg.rb create mode 100644 spec/models/sdg/goal_spec.rb diff --git a/app/models/sdg.rb b/app/models/sdg.rb new file mode 100644 index 000000000..67c0b0fcd --- /dev/null +++ b/app/models/sdg.rb @@ -0,0 +1,5 @@ +module SDG + def self.table_name_prefix + "sdg_" + end +end diff --git a/app/models/sdg/goal.rb b/app/models/sdg/goal.rb new file mode 100644 index 000000000..7ff570cc8 --- /dev/null +++ b/app/models/sdg/goal.rb @@ -0,0 +1,11 @@ +class SDG::Goal < ApplicationRecord + validates :code, presence: true, uniqueness: true + + def title + I18n.t("sdg.goals.goal_#{code}.title") + end + + def description + I18n.t("sdg.goals.goal_#{code}.description") + end +end diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index f17a84b39..e95cdbca7 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -17,5 +17,6 @@ ActiveSupport::Inflector.inflections(:en) do |inflect| inflect.plural(/^(\d+)$/i, '\1') + inflect.acronym "SDG" inflect.irregular "organización", "organizaciones" end diff --git a/config/locales/en/sdg.yml b/config/locales/en/sdg.yml new file mode 100644 index 000000000..44eb51fee --- /dev/null +++ b/config/locales/en/sdg.yml @@ -0,0 +1,6 @@ +en: + sdg: + goals: + goal_1: + title: "No Poverty" + description: "End poverty in all its forms, everywhere." diff --git a/config/locales/es/sdg.yml b/config/locales/es/sdg.yml new file mode 100644 index 000000000..4f13d07ab --- /dev/null +++ b/config/locales/es/sdg.yml @@ -0,0 +1,6 @@ +es: + sdg: + goals: + goal_1: + title: "Fin de la pobreza" + description: "Poner fin a la pobreza en todas sus formas en todo el mundo." diff --git a/db/migrate/20201111095452_create_sdg_goals.rb b/db/migrate/20201111095452_create_sdg_goals.rb new file mode 100644 index 000000000..8079de4cb --- /dev/null +++ b/db/migrate/20201111095452_create_sdg_goals.rb @@ -0,0 +1,10 @@ +class CreateSDGGoals < ActiveRecord::Migration[5.2] + def change + create_table :sdg_goals do |t| + t.integer :code, null: false + t.timestamps + + t.index :code, unique: true + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 31ebc6540..6d7a9a4a1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_09_08_084257) do +ActiveRecord::Schema.define(version: 2020_11_11_095452) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" @@ -1297,6 +1297,13 @@ ActiveRecord::Schema.define(version: 2020_09_08_084257) do t.index ["process_type", "process_id"], name: "index_reports_on_process_type_and_process_id" end + create_table "sdg_goals", force: :cascade do |t| + t.integer "code", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["code"], name: "index_sdg_goals_on_code", unique: true + end + create_table "settings", id: :serial, force: :cascade do |t| t.string "key" t.string "value" diff --git a/spec/factories/sdg.rb b/spec/factories/sdg.rb new file mode 100644 index 000000000..75d911a62 --- /dev/null +++ b/spec/factories/sdg.rb @@ -0,0 +1,5 @@ +FactoryBot.define do + factory :sdg_goal, class: "SDG::Goal" do + sequence(:code) { |n| n } + end +end diff --git a/spec/models/sdg/goal_spec.rb b/spec/models/sdg/goal_spec.rb new file mode 100644 index 000000000..e9693e5a4 --- /dev/null +++ b/spec/models/sdg/goal_spec.rb @@ -0,0 +1,31 @@ +require "rails_helper" + +describe SDG::Goal do + it "is valid" do + expect(build(:sdg_goal)).to be_valid + end + + it "is not valid without a code" do + expect(build(:sdg_goal, code: nil)).not_to be_valid + end + + it "translates title" do + goal = SDG::Goal.where(code: "1").first_or_create! + + expect(goal.title).to eq "No Poverty" + + I18n.with_locale(:es) do + expect(goal.title).to eq "Fin de la pobreza" + end + end + + it "translates description" do + goal = SDG::Goal.where(code: "1").first_or_create! + + expect(goal.description).to eq "End poverty in all its forms, everywhere." + + I18n.with_locale(:es) do + expect(goal.description).to eq "Poner fin a la pobreza en todas sus formas en todo el mundo." + end + end +end From 2b6c9914ddf460adbfe5d9e35c189180f7471349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Wed, 2 Dec 2020 12:34:13 +0100 Subject: [PATCH 2/7] Extract selector for admin menu icon This way we'll be able to apply it to the SDG icon, which is not included in font-awesome. Note we're adding a font-icon selector so it's defined before the admin-menu-icon selector and so in case of conflicting rules the ones in the admin-menu-icon selector are used. --- app/assets/stylesheets/admin/menu.scss | 4 +--- app/assets/stylesheets/mixins.scss | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/app/assets/stylesheets/admin/menu.scss b/app/assets/stylesheets/admin/menu.scss index 076a1f291..a3ea2801d 100644 --- a/app/assets/stylesheets/admin/menu.scss +++ b/app/assets/stylesheets/admin/menu.scss @@ -17,9 +17,7 @@ @include has-fa-icon($name, $style); &::before { - font-size: rem-calc(20); - margin-left: rem-calc(8); - margin-right: rem-calc(10); + @extend %admin-menu-icon; } } diff --git a/app/assets/stylesheets/mixins.scss b/app/assets/stylesheets/mixins.scss index 47ab61b2e..060e31d83 100644 --- a/app/assets/stylesheets/mixins.scss +++ b/app/assets/stylesheets/mixins.scss @@ -141,6 +141,13 @@ } } +%font-icon { + @extend %fa-icon; + font-family: "Font Awesome 5 Free"; + margin-right: rem-calc(4); + vertical-align: middle; +} + %svg-icon { background: currentcolor; content: ""; @@ -150,14 +157,17 @@ width: 1em; } +%admin-menu-icon { + font-size: rem-calc(20); + margin-left: rem-calc(8); + margin-right: rem-calc(10); +} + @mixin has-fa-icon($icon, $style) { @extend .fa-#{$icon}; &::before { - @extend %fa-icon; - font-family: "Font Awesome 5 Free"; - margin-right: rem-calc(4); - vertical-align: middle; + @extend %font-icon; @if $style == "regular" { font-weight: normal; From a42cb050a723fc34cb9f54bb01c36b6a87a8a38c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Wed, 11 Nov 2020 13:16:37 +0100 Subject: [PATCH 3/7] Add SDG content section --- app/assets/stylesheets/application.scss | 1 + .../stylesheets/sdg_management/menu.scss | 10 ++++++++ .../goals/index_component.html.erb | 25 +++++++++++++++++++ .../sdg_management/goals/index_component.rb | 17 +++++++++++++ .../sdg_management/menu_component.html.erb | 5 ++++ .../sdg_management/menu_component.rb | 7 ++++++ .../sdg_management/base_controller.rb | 14 +++++++++++ .../sdg_management/goals_controller.rb | 5 ++++ app/helpers/admin_helper.rb | 2 +- app/views/layouts/admin.html.erb | 2 ++ app/views/sdg_management/goals/index.html.erb | 1 + app/views/shared/_admin_login_items.html.erb | 6 +++++ config/i18n-tasks.yml | 1 + config/locales/en/activerecord.yml | 7 ++++++ config/locales/en/sdg_management.yml | 6 +++++ config/locales/es/activerecord.yml | 7 ++++++ config/locales/es/sdg_management.yml | 6 +++++ config/routes.rb | 1 + config/routes/sdg_management.rb | 5 ++++ spec/system/sdg_management/goals_spec.rb | 20 +++++++++++++++ vendor/assets/images/sdg.svg | 19 ++++++++++++++ 21 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 app/assets/stylesheets/sdg_management/menu.scss create mode 100644 app/components/sdg_management/goals/index_component.html.erb create mode 100644 app/components/sdg_management/goals/index_component.rb create mode 100644 app/components/sdg_management/menu_component.html.erb create mode 100644 app/components/sdg_management/menu_component.rb create mode 100644 app/controllers/sdg_management/base_controller.rb create mode 100644 app/controllers/sdg_management/goals_controller.rb create mode 100644 app/views/sdg_management/goals/index.html.erb create mode 100644 config/locales/en/sdg_management.yml create mode 100644 config/locales/es/sdg_management.yml create mode 100644 config/routes/sdg_management.rb create mode 100644 spec/system/sdg_management/goals_spec.rb create mode 100644 vendor/assets/images/sdg.svg diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 0e4d08318..daa8ffc81 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -28,3 +28,4 @@ @import "leaflet"; @import "sticky_overrides"; @import "admin/*"; +@import "sdg_management/*"; diff --git a/app/assets/stylesheets/sdg_management/menu.scss b/app/assets/stylesheets/sdg_management/menu.scss new file mode 100644 index 000000000..744234610 --- /dev/null +++ b/app/assets/stylesheets/sdg_management/menu.scss @@ -0,0 +1,10 @@ +.sdg-content-menu { + + .goals-link::before { + @extend %font-icon; + @extend %svg-icon; + @extend %admin-menu-icon; + + mask-image: image-url("sdg.svg"); + } +} diff --git a/app/components/sdg_management/goals/index_component.html.erb b/app/components/sdg_management/goals/index_component.html.erb new file mode 100644 index 000000000..2564b8dec --- /dev/null +++ b/app/components/sdg_management/goals/index_component.html.erb @@ -0,0 +1,25 @@ +<% provide(:title) do %> + <%= t("sdg_management.header.title") %> - <%= title %> +<% end %> + +

<%= title %>

+ + + + + + + + + + + + <% goals.each do |goal| %> + + + + + + <% end %> + +
<%= attribute_name(:code) %><%= attribute_name(:title) %><%= attribute_name(:description) %>
<%= goal.code %><%= goal.title %><%= goal.description %>
diff --git a/app/components/sdg_management/goals/index_component.rb b/app/components/sdg_management/goals/index_component.rb new file mode 100644 index 000000000..9c7517861 --- /dev/null +++ b/app/components/sdg_management/goals/index_component.rb @@ -0,0 +1,17 @@ +class SDGManagement::Goals::IndexComponent < ApplicationComponent + attr_reader :goals + + def initialize(goals) + @goals = goals + end + + private + + def title + SDG::Goal.model_name.human(count: 2).titleize + end + + def attribute_name(attribute) + SDG::Goal.human_attribute_name(attribute) + end +end diff --git a/app/components/sdg_management/menu_component.html.erb b/app/components/sdg_management/menu_component.html.erb new file mode 100644 index 000000000..bd5783962 --- /dev/null +++ b/app/components/sdg_management/menu_component.html.erb @@ -0,0 +1,5 @@ +
    +
  • "> + <%= link_to t("sdg_management.menu.sdg_content"), sdg_management_goals_path, class: "goals-link" %> +
  • +
diff --git a/app/components/sdg_management/menu_component.rb b/app/components/sdg_management/menu_component.rb new file mode 100644 index 000000000..a4dfcb7a4 --- /dev/null +++ b/app/components/sdg_management/menu_component.rb @@ -0,0 +1,7 @@ +class SDGManagement::MenuComponent < ApplicationComponent + private + + def sdg? + controller_name == "goals" + end +end diff --git a/app/controllers/sdg_management/base_controller.rb b/app/controllers/sdg_management/base_controller.rb new file mode 100644 index 000000000..a5028f7d0 --- /dev/null +++ b/app/controllers/sdg_management/base_controller.rb @@ -0,0 +1,14 @@ +class SDGManagement::BaseController < ApplicationController + layout "admin" + + before_action :authenticate_user! + before_action :verify_sdg_manager + + skip_authorization_check + + private + + def verify_sdg_manager + raise CanCan::AccessDenied unless current_user&.administrator? + end +end diff --git a/app/controllers/sdg_management/goals_controller.rb b/app/controllers/sdg_management/goals_controller.rb new file mode 100644 index 000000000..1eb68c6f3 --- /dev/null +++ b/app/controllers/sdg_management/goals_controller.rb @@ -0,0 +1,5 @@ +class SDGManagement::GoalsController < SDGManagement::BaseController + def index + @goals = SDG::Goal.order(:code) + end +end diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb index b531bf82a..dd5d9c6d4 100644 --- a/app/helpers/admin_helper.rb +++ b/app/helpers/admin_helper.rb @@ -42,6 +42,6 @@ module AdminHelper private def namespace - controller.class.name.downcase.split("::").first + controller.class.name.split("::").first.underscore end end diff --git a/app/views/layouts/admin.html.erb b/app/views/layouts/admin.html.erb index ff29aa5d5..8c3176b12 100644 --- a/app/views/layouts/admin.html.erb +++ b/app/views/layouts/admin.html.erb @@ -15,6 +15,8 @@