Merge pull request #4269 from consul/sdg_management
Add SDG content management section
This commit is contained in:
@@ -36,7 +36,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.budgets-link,
|
&.budgets-link,
|
||||||
&.investments-link {
|
&.investments-link,
|
||||||
|
&.budget-investments-link {
|
||||||
@include icon(chart-pie, solid);
|
@include icon(chart-pie, solid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +57,8 @@
|
|||||||
@include icon(envelope, regular);
|
@include icon(envelope, regular);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.legislation-link {
|
&.legislation-link,
|
||||||
|
&.legislation-processes-link {
|
||||||
@include icon(file-alt, solid);
|
@include icon(file-alt, solid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,25 @@
|
|||||||
.admin [role=search] {
|
.admin [role=search] {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
|
&.complex {
|
||||||
|
@include breakpoint(small only) {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include breakpoint(medium) {
|
||||||
|
select {
|
||||||
|
height: $line-height * 2;
|
||||||
|
margin: 0 rem-calc(12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.complex) {
|
||||||
|
@include breakpoint(medium) {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[type="submit"] {
|
[type="submit"] {
|
||||||
@include button($background: $link);
|
@include button($background: $link);
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
@@ -10,8 +29,4 @@
|
|||||||
@include button-disabled;
|
@include button-disabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include breakpoint(medium) {
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<%= form_tag(url, options) do |f| %>
|
<%= form_tag(url, options) do |f| %>
|
||||||
<%= text_field_tag :search, search_terms.to_s, placeholder: label, "aria-label": label %>
|
<%= text_field_tag :search, search_terms.to_s, placeholder: label, "aria-label": label %>
|
||||||
|
<%= content %>
|
||||||
<%= submit_tag t("admin.shared.search.search") %>
|
<%= submit_tag t("admin.shared.search.search") %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,9 +1 @@
|
|||||||
<%= link_list(
|
<%= link_list(*links, class: "sdg-content-menu") %>
|
||||||
[
|
|
||||||
t("sdg_management.menu.sdg_content"),
|
|
||||||
sdg_management_goals_path,
|
|
||||||
sdg?,
|
|
||||||
class: "goals-link"
|
|
||||||
],
|
|
||||||
class: "sdg-content-menu"
|
|
||||||
) %>
|
|
||||||
|
|||||||
@@ -3,7 +3,50 @@ class SDGManagement::MenuComponent < ApplicationComponent
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def links
|
||||||
|
[goals_link, *relatable_links]
|
||||||
|
end
|
||||||
|
|
||||||
|
def goals_link
|
||||||
|
[t("sdg_management.menu.sdg_content"), sdg_management_goals_path, sdg?, class: "goals-link"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def relatable_links
|
||||||
|
SDG::Related::RELATABLE_TYPES.map do |type|
|
||||||
|
next unless setting["process.#{process_name(type)}"] && setting["sdg.process.#{process_name(type)}"]
|
||||||
|
|
||||||
|
[
|
||||||
|
t("sdg_management.menu.#{table_name(type)}"),
|
||||||
|
relatable_type_path(type),
|
||||||
|
controller_name == "relations" && params[:relatable_type] == type.tableize,
|
||||||
|
class: "#{table_name(type).tr("_", "-")}-link"
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def sdg?
|
def sdg?
|
||||||
%w[goals targets local_targets].include?(controller_name)
|
%w[goals targets local_targets].include?(controller_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def relatable_type_path(type)
|
||||||
|
{
|
||||||
|
controller: "sdg_management/relations",
|
||||||
|
action: :index,
|
||||||
|
relatable_type: type.tableize
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def table_name(type)
|
||||||
|
type.constantize.table_name
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_name(type)
|
||||||
|
process_name = type.split("::").first
|
||||||
|
|
||||||
|
if process_name == "Legislation"
|
||||||
|
"legislation"
|
||||||
|
else
|
||||||
|
process_name.constantize.table_name
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<%= header %>
|
||||||
|
|
||||||
|
<%= form_for record, url: update_path do |f| %>
|
||||||
|
<%= f.text_field :sdg_target_list %>
|
||||||
|
|
||||||
|
<%= f.submit %>
|
||||||
|
<% end %>
|
||||||
24
app/components/sdg_management/relations/edit_component.rb
Normal file
24
app/components/sdg_management/relations/edit_component.rb
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
class SDGManagement::Relations::EditComponent < ApplicationComponent
|
||||||
|
include Header
|
||||||
|
|
||||||
|
attr_reader :record
|
||||||
|
|
||||||
|
def initialize(record)
|
||||||
|
@record = record
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def title
|
||||||
|
@record.title
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_path
|
||||||
|
{
|
||||||
|
controller: "sdg_management/relations",
|
||||||
|
action: :update,
|
||||||
|
relatable_type: record.class.name.tableize,
|
||||||
|
id: record
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<%= header %>
|
||||||
|
|
||||||
|
<%= render Admin::SearchComponent.new(label: search_label, class: "complex") do |component| %>
|
||||||
|
<%= component.select_tag :goal_code, goal_options,
|
||||||
|
include_blank: goal_blank_option,
|
||||||
|
"aria-label": goal_label %>
|
||||||
|
<%= component.select_tag :target_code, target_options,
|
||||||
|
include_blank: target_blank_option,
|
||||||
|
"aria-label": target_label %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><%= model_class.human_attribute_name(:title) %></th>
|
||||||
|
<th><%= SDG::Goal.model_name.human(count: 2).upcase_first %></th>
|
||||||
|
<th><%= SDG::Target.model_name.human(count: 2).upcase_first %></th>
|
||||||
|
<th><%= t("admin.actions.actions") %></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<% @records.each do |record| %>
|
||||||
|
<tr>
|
||||||
|
<td><%= record.title %></td>
|
||||||
|
<td><%= record.sdg_goal_list %></td>
|
||||||
|
<td><%= record.sdg_target_list %></td>
|
||||||
|
<td>
|
||||||
|
<%= render Admin::TableActionsComponent.new(
|
||||||
|
record,
|
||||||
|
actions: [:edit],
|
||||||
|
edit_text: t("sdg_management.actions.edit"),
|
||||||
|
edit_path: edit_path_for(record)
|
||||||
|
) %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<%= paginate(@records) %>
|
||||||
56
app/components/sdg_management/relations/index_component.rb
Normal file
56
app/components/sdg_management/relations/index_component.rb
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
class SDGManagement::Relations::IndexComponent < ApplicationComponent
|
||||||
|
include Header
|
||||||
|
|
||||||
|
attr_reader :records
|
||||||
|
|
||||||
|
def initialize(records)
|
||||||
|
@records = records
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def title
|
||||||
|
t("sdg_management.menu.#{model_class.table_name}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def model_class
|
||||||
|
records.model
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit_path_for(record)
|
||||||
|
{
|
||||||
|
controller: "sdg_management/relations",
|
||||||
|
action: :edit,
|
||||||
|
relatable_type: record.class.name.tableize,
|
||||||
|
id: record
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def search_label
|
||||||
|
t("admin.shared.search.label.#{model_class.table_name}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def goal_label
|
||||||
|
t("admin.shared.search.advanced_filters.sdg_goals.label")
|
||||||
|
end
|
||||||
|
|
||||||
|
def goal_blank_option
|
||||||
|
t("admin.shared.search.advanced_filters.sdg_goals.all")
|
||||||
|
end
|
||||||
|
|
||||||
|
def target_label
|
||||||
|
t("admin.shared.search.advanced_filters.sdg_targets.label")
|
||||||
|
end
|
||||||
|
|
||||||
|
def target_blank_option
|
||||||
|
t("admin.shared.search.advanced_filters.sdg_targets.all")
|
||||||
|
end
|
||||||
|
|
||||||
|
def goal_options
|
||||||
|
options_from_collection_for_select(SDG::Goal.all, :code, :code_and_title, params[:goal_code])
|
||||||
|
end
|
||||||
|
|
||||||
|
def target_options
|
||||||
|
options_from_collection_for_select(SDG::Target.all.sort, :code, :code, params[:target_code])
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
<% targets.group_by(&:goal).map do |goal, targets| %>
|
<% targets.group_by(&:goal).map do |goal, targets| %>
|
||||||
<tr class="goal-header">
|
<tr class="goal-header">
|
||||||
<th id="<%= header_id(goal) %>" colspan="2" scope="colgroup">
|
<th id="<%= header_id(goal) %>" colspan="2" scope="colgroup">
|
||||||
<%= goal.code %>. <%= goal.title %>
|
<%= goal.code_and_title %>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
|||||||
42
app/controllers/sdg_management/relations_controller.rb
Normal file
42
app/controllers/sdg_management/relations_controller.rb
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
class SDGManagement::RelationsController < SDGManagement::BaseController
|
||||||
|
before_action :check_feature_flags
|
||||||
|
before_action :load_record, only: [:edit, :update]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@records = relatable_class
|
||||||
|
.accessible_by(current_ability)
|
||||||
|
.by_goal(params[:goal_code])
|
||||||
|
.by_target(params[:target_code])
|
||||||
|
.order(:id)
|
||||||
|
.page(params[:page])
|
||||||
|
|
||||||
|
@records = @records.search(params[:search]) if params[:search].present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@record.sdg_target_list = params[@record.class.table_name.singularize][:sdg_target_list]
|
||||||
|
|
||||||
|
redirect_to action: :index
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_record
|
||||||
|
@record = relatable_class.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def relatable_class
|
||||||
|
params[:relatable_type].classify.constantize
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_feature_flags
|
||||||
|
process_name = params[:relatable_type].split("/").first
|
||||||
|
process_name = process_name.pluralize unless process_name == "legislation"
|
||||||
|
|
||||||
|
check_feature_flag(process_name)
|
||||||
|
raise FeatureDisabled, process_name unless Setting["sdg.process.#{process_name}"]
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -12,7 +12,40 @@ module SDG::Relatable
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class_methods do
|
||||||
|
def by_goal(code)
|
||||||
|
by_sdg_related(SDG::Goal, code)
|
||||||
|
end
|
||||||
|
|
||||||
|
def by_target(code)
|
||||||
|
by_sdg_related(SDG::Target, code)
|
||||||
|
end
|
||||||
|
|
||||||
|
def by_sdg_related(sdg_class, code)
|
||||||
|
return all if code.blank?
|
||||||
|
|
||||||
|
joins(sdg_class.table_name.to_sym).merge(sdg_class.where(code: code))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def related_sdgs
|
def related_sdgs
|
||||||
sdg_relations.map(&:related_sdg)
|
sdg_relations.map(&:related_sdg)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def sdg_goal_list
|
||||||
|
sdg_goals.order(:code).map(&:code).join(", ")
|
||||||
|
end
|
||||||
|
|
||||||
|
def sdg_target_list
|
||||||
|
sdg_targets.sort.map(&:code).join(", ")
|
||||||
|
end
|
||||||
|
|
||||||
|
def sdg_target_list=(codes)
|
||||||
|
targets = codes.tr(" ", "").split(",").map { |code| SDG::Target[code] }
|
||||||
|
|
||||||
|
transaction do
|
||||||
|
self.sdg_targets = targets
|
||||||
|
self.sdg_goals = targets.map(&:goal).uniq
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ class Legislation::Process < ApplicationRecord
|
|||||||
include Imageable
|
include Imageable
|
||||||
include Documentable
|
include Documentable
|
||||||
include SDG::Relatable
|
include SDG::Relatable
|
||||||
|
include Searchable
|
||||||
|
|
||||||
acts_as_paranoid column: :hidden_at
|
acts_as_paranoid column: :hidden_at
|
||||||
acts_as_taggable_on :customs
|
acts_as_taggable_on :customs
|
||||||
@@ -123,6 +124,22 @@ class Legislation::Process < ApplicationRecord
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def searchable_translations_definitions
|
||||||
|
{
|
||||||
|
title => "A",
|
||||||
|
summary => "C",
|
||||||
|
description => "D"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def searchable_values
|
||||||
|
searchable_globalized_values
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.search(terms)
|
||||||
|
pg_search(terms)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def valid_date_ranges
|
def valid_date_ranges
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ class Poll < ApplicationRecord
|
|||||||
acts_as_paranoid column: :hidden_at
|
acts_as_paranoid column: :hidden_at
|
||||||
include ActsAsParanoidAliases
|
include ActsAsParanoidAliases
|
||||||
include Notifiable
|
include Notifiable
|
||||||
|
include Searchable
|
||||||
include Sluggable
|
include Sluggable
|
||||||
include StatsVersionable
|
include StatsVersionable
|
||||||
include Reportable
|
include Reportable
|
||||||
@@ -175,4 +176,20 @@ class Poll < ApplicationRecord
|
|||||||
def budget_poll?
|
def budget_poll?
|
||||||
budget.present?
|
budget.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def searchable_translations_definitions
|
||||||
|
{
|
||||||
|
name => "A",
|
||||||
|
summary => "C",
|
||||||
|
description => "D"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def searchable_values
|
||||||
|
searchable_globalized_values
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.search(terms)
|
||||||
|
pg_search(terms)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -16,4 +16,8 @@ class SDG::Goal < ApplicationRecord
|
|||||||
def self.[](code)
|
def self.[](code)
|
||||||
find_by!(code: code)
|
find_by!(code: code)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def code_and_title
|
||||||
|
"#{code}. #{title}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<h2><%= t("admin.debates.index.title") %></h2>
|
<h2><%= t("admin.debates.index.title") %></h2>
|
||||||
|
|
||||||
<% if @debates.any? %>
|
<% if @debates.any? %>
|
||||||
<%= render Admin::SearchComponent.new(label: t("admin.shared.debate_search.placeholder")) %>
|
<%= render Admin::SearchComponent.new(label: t("admin.shared.search.label.debates")) %>
|
||||||
|
|
||||||
<h3 class="inline-block"><%= page_entries_info @debates %></h3>
|
<h3 class="inline-block"><%= page_entries_info @debates %></h3>
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
class: "button float-right hollow" %>
|
class: "button float-right hollow" %>
|
||||||
|
|
||||||
<%= render Admin::SearchComponent.new(
|
<%= render Admin::SearchComponent.new(
|
||||||
label: t("admin.local_census_records.index.search.placeholder"),
|
label: t("admin.shared.search.label.local_census_records"),
|
||||||
remote: true
|
remote: true
|
||||||
) %>
|
) %>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<%= render Admin::SearchComponent.new(
|
<%= render Admin::SearchComponent.new(
|
||||||
url: search_admin_organizations_path,
|
url: search_admin_organizations_path,
|
||||||
label: t("admin.organizations.index.search_placeholder")
|
label: t("admin.shared.search.label.organizations")
|
||||||
) %>
|
) %>
|
||||||
|
|
||||||
<%= render "shared/filter_subnav", i18n_namespace: "admin.organizations.index" %>
|
<%= render "shared/filter_subnav", i18n_namespace: "admin.organizations.index" %>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<h2><%= t("admin.organizations.search.title") %></h2>
|
<h2><%= t("admin.organizations.search.title") %></h2>
|
||||||
|
|
||||||
<%= render Admin::SearchComponent.new(label: t("admin.organizations.index.search_placeholder")) %>
|
<%= render Admin::SearchComponent.new(label: t("admin.shared.search.label.organizations")) %>
|
||||||
|
|
||||||
<div id="search-results">
|
<div id="search-results">
|
||||||
<% if @organizations.any? %>
|
<% if @organizations.any? %>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<%= text_field_tag :search,
|
<%= text_field_tag :search,
|
||||||
@search,
|
@search,
|
||||||
placeholder: t("admin.shared.booths_search.placeholder"), id: "search-booths" %>
|
placeholder: t("admin.shared.search.label.booths"), id: "search-booths" %>
|
||||||
<div class="input-group-button">
|
<div class="input-group-button">
|
||||||
<%= submit_tag t("admin.shared.search.search"), class: "button" %>
|
<%= submit_tag t("admin.shared.search.search"), class: "button" %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<%= link_to t("admin.booths.index.add_booth"), new_admin_booth_path, class: "button float-right" %>
|
<%= link_to t("admin.booths.index.add_booth"), new_admin_booth_path, class: "button float-right" %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= render Admin::SearchComponent.new(label: t("admin.shared.booths_search.placeholder")) %>
|
<%= render Admin::SearchComponent.new(label: t("admin.shared.search.label.booths")) %>
|
||||||
|
|
||||||
<% if @booths.empty? %>
|
<% if @booths.empty? %>
|
||||||
<div class="callout primary">
|
<div class="callout primary">
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<%= text_field_tag :search,
|
<%= text_field_tag :search,
|
||||||
@search,
|
@search,
|
||||||
placeholder: t("admin.shared.poll_officers_search.placeholder"), id: "search-officers" %>
|
placeholder: t("admin.shared.search.label.poll_officers"), id: "search-officers" %>
|
||||||
<div class="input-group-button">
|
<div class="input-group-button">
|
||||||
<%= submit_tag t("admin.shared.search.search"), class: "button" %>
|
<%= submit_tag t("admin.shared.search.search"), class: "button" %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<%= render Admin::SearchComponent.new(label: t("admin.shared.poll_questions_search.placeholder")) %>
|
<%= render Admin::SearchComponent.new(label: t("admin.shared.search.label.poll_questions")) %>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<h2><%= t("admin.proposals.index.title") %></h2>
|
<h2><%= t("admin.proposals.index.title") %></h2>
|
||||||
|
|
||||||
<% if @proposals.any? %>
|
<% if @proposals.any? %>
|
||||||
<%= render Admin::SearchComponent.new(label: t("admin.shared.proposal_search.placeholder")) %>
|
<%= render Admin::SearchComponent.new(label: t("admin.shared.search.label.proposals")) %>
|
||||||
|
|
||||||
<h3><%= page_entries_info @proposals %></h3>
|
<h3><%= page_entries_info @proposals %></h3>
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<%= render Admin::SearchComponent.new(url: url, label: t("admin.shared.user_search.placeholder")) %>
|
<%= render Admin::SearchComponent.new(url: url, label: t("admin.shared.search.label.users")) %>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<main>
|
<main>
|
||||||
<h2><%= t("management.proposals.index.title") %></h2>
|
<h2><%= t("management.proposals.index.title") %></h2>
|
||||||
|
|
||||||
<%= render Admin::SearchComponent.new(label: t("admin.shared.proposal_search.placeholder")) %>
|
<%= render Admin::SearchComponent.new(label: t("admin.shared.search.label.proposals")) %>
|
||||||
|
|
||||||
<div class="management-list">
|
<div class="management-list">
|
||||||
<div class="proposals-list">
|
<div class="proposals-list">
|
||||||
|
|||||||
1
app/views/sdg_management/relations/edit.html.erb
Normal file
1
app/views/sdg_management/relations/edit.html.erb
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<%= render SDGManagement::Relations::EditComponent.new(@record) %>
|
||||||
1
app/views/sdg_management/relations/index.html.erb
Normal file
1
app/views/sdg_management/relations/index.html.erb
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<%= render SDGManagement::Relations::IndexComponent.new(@records) %>
|
||||||
@@ -2,6 +2,7 @@ en:
|
|||||||
attributes:
|
attributes:
|
||||||
geozone_id: "Scope of operation"
|
geozone_id: "Scope of operation"
|
||||||
results_enabled: "Show results"
|
results_enabled: "Show results"
|
||||||
|
sdg_target_list: "Targets"
|
||||||
stats_enabled: "Show stats"
|
stats_enabled: "Show stats"
|
||||||
advanced_stats_enabled: "Show advanced stats"
|
advanced_stats_enabled: "Show advanced stats"
|
||||||
name: Name
|
name: Name
|
||||||
@@ -287,6 +288,7 @@ en:
|
|||||||
responsible_name: "Person responsible for the group"
|
responsible_name: "Person responsible for the group"
|
||||||
poll:
|
poll:
|
||||||
name: "Name"
|
name: "Name"
|
||||||
|
title: "Name"
|
||||||
starts_at: "Start Date"
|
starts_at: "Start Date"
|
||||||
ends_at: "Closing Date"
|
ends_at: "Closing Date"
|
||||||
geozone_restricted: "Restricted by geozone"
|
geozone_restricted: "Restricted by geozone"
|
||||||
|
|||||||
@@ -1169,7 +1169,6 @@ en:
|
|||||||
no_organizations: There are no organizations.
|
no_organizations: There are no organizations.
|
||||||
reject: Reject
|
reject: Reject
|
||||||
rejected: Rejected
|
rejected: Rejected
|
||||||
search_placeholder: Name, email or phone number
|
|
||||||
title: Organisations
|
title: Organisations
|
||||||
verified: Verified
|
verified: Verified
|
||||||
verify: Verify
|
verify: Verify
|
||||||
@@ -1254,19 +1253,26 @@ en:
|
|||||||
true_value: "Yes"
|
true_value: "Yes"
|
||||||
false_value: "No"
|
false_value: "No"
|
||||||
search:
|
search:
|
||||||
|
advanced_filters:
|
||||||
|
sdg_goals:
|
||||||
|
all: "All goals"
|
||||||
|
label: "By goal"
|
||||||
|
sdg_targets:
|
||||||
|
all: "All targets"
|
||||||
|
label: "By target"
|
||||||
|
label:
|
||||||
|
booths: "Search booth by name or location"
|
||||||
|
budget_investments: "Search investments by title, description or heading"
|
||||||
|
debates: "Search debates by title or description"
|
||||||
|
legislation_processes: "Search processes by title or description"
|
||||||
|
local_census_records: "Search by document number"
|
||||||
|
organizations: "Name, email or phone number"
|
||||||
|
poll_officers: "Search poll officers"
|
||||||
|
poll_questions: "Search poll questions"
|
||||||
|
polls: "Search polls by name or description"
|
||||||
|
proposals: "Search proposals by title, code, description or question"
|
||||||
|
users: "Search user by name or email"
|
||||||
search: "Search"
|
search: "Search"
|
||||||
booths_search:
|
|
||||||
placeholder: Search booth by name or location
|
|
||||||
poll_officers_search:
|
|
||||||
placeholder: Search poll officers
|
|
||||||
poll_questions_search:
|
|
||||||
placeholder: Search poll questions
|
|
||||||
proposal_search:
|
|
||||||
placeholder: Search proposals by title, code, description or question
|
|
||||||
debate_search:
|
|
||||||
placeholder: Search debates by title or description
|
|
||||||
user_search:
|
|
||||||
placeholder: Search user by name or email
|
|
||||||
search_results: "Search results"
|
search_results: "Search results"
|
||||||
no_search_results: "No results found."
|
no_search_results: "No results found."
|
||||||
actions: Actions
|
actions: Actions
|
||||||
@@ -1572,8 +1578,6 @@ en:
|
|||||||
document_number: Document number
|
document_number: Document number
|
||||||
date_of_birth: Date of birth
|
date_of_birth: Date of birth
|
||||||
postal_code: Postal code
|
postal_code: Postal code
|
||||||
search:
|
|
||||||
placeholder: Search by document number
|
|
||||||
import: Import CSV
|
import: Import CSV
|
||||||
new:
|
new:
|
||||||
creating: Creating new local census record
|
creating: Creating new local census record
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
en:
|
en:
|
||||||
sdg_management:
|
sdg_management:
|
||||||
|
actions:
|
||||||
|
edit: "Manage goals and targets"
|
||||||
header:
|
header:
|
||||||
title: "SDG content"
|
title: "SDG content"
|
||||||
menu:
|
menu:
|
||||||
|
budget_investments: "Participatory budgets"
|
||||||
|
debates: "Debates"
|
||||||
|
legislation_processes: "Collaborative legislation"
|
||||||
|
polls: "Polls"
|
||||||
|
proposals: "Proposals"
|
||||||
sdg_content: "Goals and Targets"
|
sdg_content: "Goals and Targets"
|
||||||
local_targets:
|
local_targets:
|
||||||
create:
|
create:
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ es:
|
|||||||
attributes:
|
attributes:
|
||||||
geozone_id: "Ámbito de actuación"
|
geozone_id: "Ámbito de actuación"
|
||||||
results_enabled: "Mostrar resultados"
|
results_enabled: "Mostrar resultados"
|
||||||
|
sdg_target_list: "Metas"
|
||||||
stats_enabled: "Mostrar estadísticas"
|
stats_enabled: "Mostrar estadísticas"
|
||||||
advanced_stats_enabled: "Mostrar estadísticas avanzadas"
|
advanced_stats_enabled: "Mostrar estadísticas avanzadas"
|
||||||
name: Nombre
|
name: Nombre
|
||||||
@@ -287,6 +288,7 @@ es:
|
|||||||
responsible_name: "Persona responsable del colectivo"
|
responsible_name: "Persona responsable del colectivo"
|
||||||
poll:
|
poll:
|
||||||
name: "Nombre"
|
name: "Nombre"
|
||||||
|
title: "Nombre"
|
||||||
starts_at: "Fecha de apertura"
|
starts_at: "Fecha de apertura"
|
||||||
ends_at: "Fecha de cierre"
|
ends_at: "Fecha de cierre"
|
||||||
geozone_restricted: "Restringida por zonas"
|
geozone_restricted: "Restringida por zonas"
|
||||||
|
|||||||
@@ -1168,7 +1168,6 @@ es:
|
|||||||
no_organizations: No hay organizaciones.
|
no_organizations: No hay organizaciones.
|
||||||
reject: Rechazar
|
reject: Rechazar
|
||||||
rejected: Rechazada
|
rejected: Rechazada
|
||||||
search_placeholder: Nombre, email o teléfono
|
|
||||||
title: Organizaciones
|
title: Organizaciones
|
||||||
verified: Verificada
|
verified: Verificada
|
||||||
verify: Verificar
|
verify: Verificar
|
||||||
@@ -1253,19 +1252,26 @@ es:
|
|||||||
true_value: "Sí"
|
true_value: "Sí"
|
||||||
false_value: "No"
|
false_value: "No"
|
||||||
search:
|
search:
|
||||||
|
advanced_filters:
|
||||||
|
sdg_goals:
|
||||||
|
all: "Todos los objetivos"
|
||||||
|
label: "Por objetivo"
|
||||||
|
sdg_targets:
|
||||||
|
all: "Todas las metas"
|
||||||
|
label: "Por meta"
|
||||||
|
label:
|
||||||
|
booths: "Buscar urna por nombre"
|
||||||
|
budget_investments: "Buscar proyectos por título, descripción o partida"
|
||||||
|
debates: "Buscar debates por título o descripción"
|
||||||
|
legislation_processes: "Buscar procesos por título o descripción"
|
||||||
|
local_census_records: "Búsqueda por número de documento"
|
||||||
|
organizations: "Nombre, email o teléfono"
|
||||||
|
poll_officers: "Buscar presidentes de mesa"
|
||||||
|
poll_questions: "Buscar preguntas"
|
||||||
|
polls: "Buscar votaciones por nombre o descripción"
|
||||||
|
proposals: "Buscar propuestas por título, código, descripción o pregunta"
|
||||||
|
users: "Buscar usuario por nombre o email"
|
||||||
search: "Buscar"
|
search: "Buscar"
|
||||||
booths_search:
|
|
||||||
placeholder: Buscar urna por nombre
|
|
||||||
poll_officers_search:
|
|
||||||
placeholder: Buscar presidentes de mesa
|
|
||||||
poll_questions_search:
|
|
||||||
placeholder: Buscar preguntas
|
|
||||||
proposal_search:
|
|
||||||
placeholder: Buscar propuestas por título, código, descripción o pregunta
|
|
||||||
debate_search:
|
|
||||||
placeholder: Buscar debates por título o descripción
|
|
||||||
user_search:
|
|
||||||
placeholder: Buscar usuario por nombre o email
|
|
||||||
search_results: "Resultados de la búsqueda"
|
search_results: "Resultados de la búsqueda"
|
||||||
no_search_results: "No se han encontrado resultados."
|
no_search_results: "No se han encontrado resultados."
|
||||||
actions: Acciones
|
actions: Acciones
|
||||||
@@ -1571,8 +1577,6 @@ es:
|
|||||||
document_number: Número de documento
|
document_number: Número de documento
|
||||||
date_of_birth: Fecha de nacimiento
|
date_of_birth: Fecha de nacimiento
|
||||||
postal_code: Código postal
|
postal_code: Código postal
|
||||||
search:
|
|
||||||
placeholder: Búsqueda por número de documento
|
|
||||||
import: Importar CSV
|
import: Importar CSV
|
||||||
new:
|
new:
|
||||||
creating: Creando nuevo registro de censo local
|
creating: Creando nuevo registro de censo local
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
es:
|
es:
|
||||||
sdg_management:
|
sdg_management:
|
||||||
|
actions:
|
||||||
|
edit: "Asignar objetivos y metas"
|
||||||
header:
|
header:
|
||||||
title: "Contenido ODS"
|
title: "Contenido ODS"
|
||||||
menu:
|
menu:
|
||||||
|
budget_investments: "Presupuestos participativos"
|
||||||
|
debates: "Debates"
|
||||||
|
legislation_processes: "Legislación colaborativa"
|
||||||
|
polls: "Votaciones"
|
||||||
|
proposals: "Propuestas"
|
||||||
sdg_content: "Objetivos y Metas"
|
sdg_content: "Objetivos y Metas"
|
||||||
local_targets:
|
local_targets:
|
||||||
create:
|
create:
|
||||||
|
|||||||
@@ -4,4 +4,16 @@ namespace :sdg_management do
|
|||||||
resources :goals, only: [:index]
|
resources :goals, only: [:index]
|
||||||
resources :targets, only: [:index]
|
resources :targets, only: [:index]
|
||||||
resources :local_targets, except: [:show]
|
resources :local_targets, except: [:show]
|
||||||
|
|
||||||
|
types = SDG::Related::RELATABLE_TYPES.map(&:tableize)
|
||||||
|
types_constraint = /#{types.join("|")}/
|
||||||
|
|
||||||
|
get "*relatable_type", to: "relations#index", as: "relations", relatable_type: types_constraint
|
||||||
|
get "*relatable_type/:id/edit", to: "relations#edit", as: "edit_relation", relatable_type: types_constraint
|
||||||
|
patch "*relatable_type/:id", to: "relations#update", as: "relation", relatable_type: types_constraint
|
||||||
|
|
||||||
|
types.each do |type|
|
||||||
|
get type, to: "relations#index", as: type
|
||||||
|
get "#{type}/:id/edit", to: "relations#edit", as: "edit_#{type.singularize}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
5
db/migrate/20201216132234_add_tsv_to_polls.rb
Normal file
5
db/migrate/20201216132234_add_tsv_to_polls.rb
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
class AddTsvToPolls < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
add_column :polls, :tsv, :tsvector
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class AddTsvToLegislationProcesses < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
add_column :legislation_processes, :tsv, :tsvector
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2020_11_24_145559) do
|
ActiveRecord::Schema.define(version: 2020_12_16_132642) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "pg_trgm"
|
enable_extension "pg_trgm"
|
||||||
@@ -747,6 +747,7 @@ ActiveRecord::Schema.define(version: 2020_11_24_145559) do
|
|||||||
t.boolean "homepage_enabled", default: false
|
t.boolean "homepage_enabled", default: false
|
||||||
t.text "background_color"
|
t.text "background_color"
|
||||||
t.text "font_color"
|
t.text "font_color"
|
||||||
|
t.tsvector "tsv"
|
||||||
t.index ["allegations_end_date"], name: "index_legislation_processes_on_allegations_end_date"
|
t.index ["allegations_end_date"], name: "index_legislation_processes_on_allegations_end_date"
|
||||||
t.index ["allegations_start_date"], name: "index_legislation_processes_on_allegations_start_date"
|
t.index ["allegations_start_date"], name: "index_legislation_processes_on_allegations_start_date"
|
||||||
t.index ["debate_end_date"], name: "index_legislation_processes_on_debate_end_date"
|
t.index ["debate_end_date"], name: "index_legislation_processes_on_debate_end_date"
|
||||||
@@ -1166,6 +1167,7 @@ ActiveRecord::Schema.define(version: 2020_11_24_145559) do
|
|||||||
t.integer "budget_id"
|
t.integer "budget_id"
|
||||||
t.string "related_type"
|
t.string "related_type"
|
||||||
t.integer "related_id"
|
t.integer "related_id"
|
||||||
|
t.tsvector "tsv"
|
||||||
t.index ["budget_id"], name: "index_polls_on_budget_id", unique: true
|
t.index ["budget_id"], name: "index_polls_on_budget_id", unique: true
|
||||||
t.index ["related_type", "related_id"], name: "index_polls_on_related_type_and_related_id"
|
t.index ["related_type", "related_id"], name: "index_polls_on_related_type_and_related_id"
|
||||||
t.index ["starts_at", "ends_at"], name: "index_polls_on_starts_at_and_ends_at"
|
t.index ["starts_at", "ends_at"], name: "index_polls_on_starts_at_and_ends_at"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace :consul do
|
|||||||
|
|
||||||
desc "Runs tasks needed to upgrade from 1.2.0 to 1.3.0"
|
desc "Runs tasks needed to upgrade from 1.2.0 to 1.3.0"
|
||||||
task "execute_release_1.3.0_tasks": [
|
task "execute_release_1.3.0_tasks": [
|
||||||
"db:load_sdg"
|
"db:load_sdg",
|
||||||
|
"db:calculate_tsv"
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,4 +10,10 @@ namespace :db do
|
|||||||
ApplicationLogger.new.info "Adding Sustainable Development Goals content"
|
ApplicationLogger.new.info "Adding Sustainable Development Goals content"
|
||||||
load(Rails.root.join("db", "sdg.rb"))
|
load(Rails.root.join("db", "sdg.rb"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "Calculates the TSV column for all polls and legislation processes"
|
||||||
|
task calculate_tsv: :environment do
|
||||||
|
Poll.find_each(&:calculate_tsvector)
|
||||||
|
Legislation::Process.find_each(&:calculate_tsvector)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
92
spec/components/sdg_management/menu_component_spec.rb
Normal file
92
spec/components/sdg_management/menu_component_spec.rb
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
describe SDGManagement::MenuComponent, type: :component do
|
||||||
|
let(:component) { SDGManagement::MenuComponent.new }
|
||||||
|
|
||||||
|
before do
|
||||||
|
Setting["sdg.process.budgets"] = true
|
||||||
|
Setting["sdg.process.debates"] = true
|
||||||
|
Setting["sdg.process.legislation"] = true
|
||||||
|
Setting["sdg.process.polls"] = true
|
||||||
|
Setting["sdg.process.proposals"] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
context "processes enabled" do
|
||||||
|
it "generates links to all processes" do
|
||||||
|
render_inline component
|
||||||
|
|
||||||
|
expect(page).to have_link "Goals and Targets"
|
||||||
|
expect(page).to have_link "Participatory budgets"
|
||||||
|
expect(page).to have_link "Debates"
|
||||||
|
expect(page).to have_link "Collaborative legislation"
|
||||||
|
expect(page).to have_link "Polls"
|
||||||
|
expect(page).to have_link "Proposals"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "processes disabled" do
|
||||||
|
before do
|
||||||
|
Setting["process.budgets"] = false
|
||||||
|
Setting["process.debates"] = false
|
||||||
|
Setting["process.legislation"] = false
|
||||||
|
Setting["process.polls"] = false
|
||||||
|
Setting["process.proposals"] = false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not generate links to any processes" do
|
||||||
|
render_inline component
|
||||||
|
|
||||||
|
expect(page).to have_css "a", count: 1
|
||||||
|
expect(page).to have_link "Goals and Targets"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "SDG processes disabled" do
|
||||||
|
before do
|
||||||
|
Setting["sdg.process.budgets"] = false
|
||||||
|
Setting["sdg.process.debates"] = false
|
||||||
|
Setting["sdg.process.legislation"] = false
|
||||||
|
Setting["sdg.process.polls"] = false
|
||||||
|
Setting["sdg.process.proposals"] = false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not generate links to any processes" do
|
||||||
|
render_inline component
|
||||||
|
|
||||||
|
expect(page).to have_css "a", count: 1
|
||||||
|
expect(page).to have_link "Goals and Targets"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "one process disabled" do
|
||||||
|
before { Setting["process.debates"] = false }
|
||||||
|
|
||||||
|
it "generates links to the enabled processes" do
|
||||||
|
render_inline component
|
||||||
|
|
||||||
|
expect(page).to have_link "Goals and Targets"
|
||||||
|
expect(page).to have_link "Participatory budgets"
|
||||||
|
expect(page).to have_link "Collaborative legislation"
|
||||||
|
expect(page).to have_link "Polls"
|
||||||
|
expect(page).to have_link "Proposals"
|
||||||
|
|
||||||
|
expect(page).not_to have_link "Debates"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "one SDG process disabled" do
|
||||||
|
before { Setting["sdg.process.legislation"] = false }
|
||||||
|
|
||||||
|
it "generates links to the enabled processes" do
|
||||||
|
render_inline component
|
||||||
|
|
||||||
|
expect(page).to have_link "Goals and Targets"
|
||||||
|
expect(page).to have_link "Debates"
|
||||||
|
expect(page).to have_link "Participatory budgets"
|
||||||
|
expect(page).to have_link "Polls"
|
||||||
|
expect(page).to have_link "Proposals"
|
||||||
|
|
||||||
|
expect(page).not_to have_link "Collaborative legislation"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
98
spec/controllers/sdg_management/relations_spec.rb
Normal file
98
spec/controllers/sdg_management/relations_spec.rb
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
describe SDGManagement::RelationsController do
|
||||||
|
before do
|
||||||
|
sign_in create(:administrator).user
|
||||||
|
|
||||||
|
Setting["feature.sdg"] = true
|
||||||
|
Setting["sdg.process.budgets"] = true
|
||||||
|
Setting["sdg.process.debates"] = true
|
||||||
|
Setting["sdg.process.legislation"] = true
|
||||||
|
Setting["sdg.process.polls"] = true
|
||||||
|
Setting["sdg.process.proposals"] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
context "processes disabled" do
|
||||||
|
it "raises feature disabled for budgets" do
|
||||||
|
Setting["process.budgets"] = false
|
||||||
|
|
||||||
|
expect do
|
||||||
|
get :index, params: { relatable_type: "budget/investments" }
|
||||||
|
end.to raise_exception(FeatureFlags::FeatureDisabled)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises feature disabled for debates" do
|
||||||
|
Setting["process.debates"] = false
|
||||||
|
|
||||||
|
expect do
|
||||||
|
get :index, params: { relatable_type: "debates" }
|
||||||
|
end.to raise_exception(FeatureFlags::FeatureDisabled)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises feature disabled for legislation processes" do
|
||||||
|
Setting["process.legislation"] = false
|
||||||
|
|
||||||
|
expect do
|
||||||
|
get :index, params: { relatable_type: "legislation/processes" }
|
||||||
|
end.to raise_exception(FeatureFlags::FeatureDisabled)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises feature disabled for polls" do
|
||||||
|
Setting["process.polls"] = false
|
||||||
|
|
||||||
|
expect do
|
||||||
|
get :index, params: { relatable_type: "polls" }
|
||||||
|
end.to raise_exception(FeatureFlags::FeatureDisabled)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises feature disabled for proposals" do
|
||||||
|
Setting["process.proposals"] = false
|
||||||
|
|
||||||
|
expect do
|
||||||
|
get :index, params: { relatable_type: "proposals" }
|
||||||
|
end.to raise_exception(FeatureFlags::FeatureDisabled)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "SDG processes disabled" do
|
||||||
|
it "raises feature disabled for budgets" do
|
||||||
|
Setting["sdg.process.budgets"] = false
|
||||||
|
|
||||||
|
expect do
|
||||||
|
get :index, params: { relatable_type: "budget/investments" }
|
||||||
|
end.to raise_exception(FeatureFlags::FeatureDisabled)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises feature disabled for debates" do
|
||||||
|
Setting["sdg.process.debates"] = false
|
||||||
|
|
||||||
|
expect do
|
||||||
|
get :index, params: { relatable_type: "debates" }
|
||||||
|
end.to raise_exception(FeatureFlags::FeatureDisabled)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises feature disabled for legislation processes" do
|
||||||
|
Setting["sdg.process.legislation"] = false
|
||||||
|
|
||||||
|
expect do
|
||||||
|
get :index, params: { relatable_type: "legislation/processes" }
|
||||||
|
end.to raise_exception(FeatureFlags::FeatureDisabled)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises feature disabled for polls" do
|
||||||
|
Setting["sdg.process.polls"] = false
|
||||||
|
|
||||||
|
expect do
|
||||||
|
get :index, params: { relatable_type: "polls" }
|
||||||
|
end.to raise_exception(FeatureFlags::FeatureDisabled)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises feature disabled for proposals" do
|
||||||
|
Setting["sdg.process.proposals"] = false
|
||||||
|
|
||||||
|
expect do
|
||||||
|
get :index, params: { relatable_type: "proposals" }
|
||||||
|
end.to raise_exception(FeatureFlags::FeatureDisabled)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -32,3 +32,33 @@ describe "rake db:load_sdg" do
|
|||||||
expect(SDG::Target.last.id).to eq target_id
|
expect(SDG::Target.last.id).to eq target_id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "rake db:calculate_tsv" do
|
||||||
|
before { Rake::Task["db:calculate_tsv"].reenable }
|
||||||
|
|
||||||
|
let :run_rake_task do
|
||||||
|
Rake.application.invoke_task("db:calculate_tsv")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "calculates the tsvector for polls" do
|
||||||
|
poll = create(:poll)
|
||||||
|
poll.update_column(:tsv, nil)
|
||||||
|
|
||||||
|
expect(poll.reload.tsv).to be nil
|
||||||
|
|
||||||
|
run_rake_task
|
||||||
|
|
||||||
|
expect(poll.reload.tsv).not_to be nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "calculates the tsvector for legislation processes" do
|
||||||
|
process = create(:legislation_process)
|
||||||
|
process.update_column(:tsv, nil)
|
||||||
|
|
||||||
|
expect(process.reload.tsv).to be nil
|
||||||
|
|
||||||
|
run_rake_task
|
||||||
|
|
||||||
|
expect(process.reload.tsv).not_to be nil
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -229,4 +229,35 @@ describe Legislation::Process do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".search" do
|
||||||
|
let!(:traffic) do
|
||||||
|
create(:legislation_process,
|
||||||
|
title: "Traffic regulation",
|
||||||
|
summary: "Lane structure",
|
||||||
|
description: "From top to bottom")
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:animal_farm) do
|
||||||
|
create(:legislation_process,
|
||||||
|
title: "Hierarchy structure",
|
||||||
|
summary: "Pigs at the top",
|
||||||
|
description: "Napoleon in charge of the traffic")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns only matching polls" do
|
||||||
|
expect(Legislation::Process.search("lane")).to eq [traffic]
|
||||||
|
expect(Legislation::Process.search("pigs")).to eq [animal_farm]
|
||||||
|
expect(Legislation::Process.search("nothing here")).to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
it "gives more weight to name" do
|
||||||
|
expect(Legislation::Process.search("traffic")).to eq [traffic, animal_farm]
|
||||||
|
expect(Legislation::Process.search("structure")).to eq [animal_farm, traffic]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "gives more weight to summary than description" do
|
||||||
|
expect(Legislation::Process.search("top")).to eq [animal_farm, traffic]
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -433,4 +433,29 @@ describe Poll do
|
|||||||
expect(poll.recounts_confirmed?).to be true
|
expect(poll.recounts_confirmed?).to be true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".search" do
|
||||||
|
let!(:square) do
|
||||||
|
create(:poll, name: "Square reform", summary: "Next to the park", description: "Give it more space")
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:park) do
|
||||||
|
create(:poll, name: "New park", summary: "Green spaces", description: "Next to the square")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns only matching polls" do
|
||||||
|
expect(Poll.search("reform")).to eq [square]
|
||||||
|
expect(Poll.search("green")).to eq [park]
|
||||||
|
expect(Poll.search("nothing here")).to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
it "gives more weight to name" do
|
||||||
|
expect(Poll.search("square")).to eq [square, park]
|
||||||
|
expect(Poll.search("park")).to eq [park, square]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "gives more weight to summary than description" do
|
||||||
|
expect(Poll.search("space")).to eq [park, square]
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -28,6 +28,14 @@ describe SDG::Relatable do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#sdg_goal_list" do
|
||||||
|
it "orders goals by code" do
|
||||||
|
relatable.sdg_goals = [SDG::Goal[1], SDG::Goal[3], SDG::Goal[2]]
|
||||||
|
|
||||||
|
expect(relatable.sdg_goal_list).to eq "1, 2, 3"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "#sdg_targets" do
|
describe "#sdg_targets" do
|
||||||
it "can assign targets to a model" do
|
it "can assign targets to a model" do
|
||||||
relatable.sdg_targets = [target, another_target]
|
relatable.sdg_targets = [target, another_target]
|
||||||
@@ -46,6 +54,14 @@ describe SDG::Relatable do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#sdg_target_list" do
|
||||||
|
it "orders targets by code" do
|
||||||
|
relatable.sdg_targets = [SDG::Target[2.2], SDG::Target[1.2], SDG::Target[2.1]]
|
||||||
|
|
||||||
|
expect(relatable.sdg_target_list).to eq "1.2, 2.1, 2.2"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "#sdg_local_targets" do
|
describe "#sdg_local_targets" do
|
||||||
it "can assign local targets to a model" do
|
it "can assign local targets to a model" do
|
||||||
relatable.sdg_local_targets = [local_target, another_local_target]
|
relatable.sdg_local_targets = [local_target, another_local_target]
|
||||||
@@ -74,4 +90,72 @@ describe SDG::Relatable do
|
|||||||
expect(relatable.reload.related_sdgs).to match_array related_sdgs
|
expect(relatable.reload.related_sdgs).to match_array related_sdgs
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#sdg_target_list=" do
|
||||||
|
it "assigns a single target" do
|
||||||
|
relatable.sdg_target_list = "1.1"
|
||||||
|
|
||||||
|
expect(relatable.reload.sdg_targets).to match_array [SDG::Target["1.1"]]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "assigns multiple targets" do
|
||||||
|
relatable.sdg_target_list = "1.1,2.3"
|
||||||
|
|
||||||
|
expect(relatable.reload.sdg_targets).to match_array [SDG::Target["1.1"], SDG::Target["2.3"]]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ignores trailing spaces and spaces between commas" do
|
||||||
|
relatable.sdg_target_list = " 1.1, 2.3 "
|
||||||
|
|
||||||
|
expect(relatable.reload.sdg_targets).to match_array [SDG::Target["1.1"], SDG::Target["2.3"]]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "assigns goals" do
|
||||||
|
relatable.sdg_target_list = "1.1,1.2,2.3"
|
||||||
|
|
||||||
|
expect(relatable.reload.sdg_goals).to match_array [SDG::Goal[1], SDG::Goal[2]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe ".by_goal" do
|
||||||
|
it "returns everything if no code is provided" do
|
||||||
|
expect(relatable.class.by_goal("")).to eq [relatable]
|
||||||
|
expect(relatable.class.by_goal(nil)).to eq [relatable]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns records associated with that goal" do
|
||||||
|
same_association = create(:proposal, sdg_goals: [goal])
|
||||||
|
both_associations = create(:proposal, sdg_goals: [goal, another_goal])
|
||||||
|
|
||||||
|
expect(relatable.class.by_goal(goal.code)).to match_array [same_association, both_associations]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not return records not associated with that goal" do
|
||||||
|
create(:proposal)
|
||||||
|
create(:proposal, sdg_goals: [another_goal])
|
||||||
|
|
||||||
|
expect(relatable.class.by_goal(goal.code)).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe ".by_target" do
|
||||||
|
it "returns everything if no code is provided" do
|
||||||
|
expect(relatable.class.by_target("")).to eq [relatable]
|
||||||
|
expect(relatable.class.by_target(nil)).to eq [relatable]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns records associated with that target" do
|
||||||
|
same_association = create(:proposal, sdg_targets: [target])
|
||||||
|
both_associations = create(:proposal, sdg_targets: [target, another_target])
|
||||||
|
|
||||||
|
expect(relatable.class.by_target(target.code)).to match_array [same_association, both_associations]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not return records not associated with that target" do
|
||||||
|
create(:proposal)
|
||||||
|
create(:proposal, sdg_targets: [another_target])
|
||||||
|
|
||||||
|
expect(relatable.class.by_target(target.code)).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
32
spec/routing/sdg_management_routes_spec.rb
Normal file
32
spec/routing/sdg_management_routes_spec.rb
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
describe "SDG Management routes" do
|
||||||
|
it "maps routes for relatable classes" do
|
||||||
|
expect(get("/sdg_management/proposals")).to route_to(
|
||||||
|
controller: "sdg_management/relations",
|
||||||
|
action: "index",
|
||||||
|
relatable_type: "proposals"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "admits named routes" do
|
||||||
|
expect(get(sdg_management_polls_path)).to route_to(
|
||||||
|
controller: "sdg_management/relations",
|
||||||
|
action: "index",
|
||||||
|
relatable_type: "polls"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "routes relatable types containing a slash" do
|
||||||
|
expect(url_for(
|
||||||
|
controller: "sdg_management/relations",
|
||||||
|
action: "index",
|
||||||
|
relatable_type: "legislation/processes",
|
||||||
|
only_path: true
|
||||||
|
)).to eq "/sdg_management/legislation/processes"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not accept non-relatable classes" do
|
||||||
|
expect(get("/sdg_management/tags")).not_to be_routable
|
||||||
|
end
|
||||||
|
end
|
||||||
145
spec/system/sdg_management/relations_spec.rb
Normal file
145
spec/system/sdg_management/relations_spec.rb
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
describe "SDG Relations", :js do
|
||||||
|
before do
|
||||||
|
login_as(create(:administrator).user)
|
||||||
|
Setting["feature.sdg"] = true
|
||||||
|
Setting["sdg.process.budgets"] = true
|
||||||
|
Setting["sdg.process.debates"] = true
|
||||||
|
Setting["sdg.process.legislation"] = true
|
||||||
|
Setting["sdg.process.polls"] = true
|
||||||
|
Setting["sdg.process.proposals"] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "navigation" do
|
||||||
|
visit sdg_management_root_path
|
||||||
|
|
||||||
|
within("#side_menu") { click_link "Participatory budgets" }
|
||||||
|
|
||||||
|
expect(page).to have_current_path "/sdg_management/budget/investments"
|
||||||
|
expect(page).to have_css "h2", exact_text: "Participatory budgets"
|
||||||
|
|
||||||
|
within("#side_menu") { click_link "Debates" }
|
||||||
|
|
||||||
|
expect(page).to have_current_path "/sdg_management/debates"
|
||||||
|
expect(page).to have_css "h2", exact_text: "Debates"
|
||||||
|
|
||||||
|
within("#side_menu") { click_link "Collaborative legislation" }
|
||||||
|
|
||||||
|
expect(page).to have_current_path "/sdg_management/legislation/processes"
|
||||||
|
expect(page).to have_css "h2", exact_text: "Collaborative legislation"
|
||||||
|
|
||||||
|
within("#side_menu") { click_link "Polls" }
|
||||||
|
|
||||||
|
expect(page).to have_current_path "/sdg_management/polls"
|
||||||
|
expect(page).to have_css "h2", exact_text: "Polls"
|
||||||
|
|
||||||
|
within("#side_menu") { click_link "Proposals" }
|
||||||
|
|
||||||
|
expect(page).to have_current_path "/sdg_management/proposals"
|
||||||
|
expect(page).to have_css "h2", exact_text: "Proposals"
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Index" do
|
||||||
|
scenario "list records for the current model" do
|
||||||
|
create(:debate, title: "I'm a debate")
|
||||||
|
create(:proposal, title: "And I'm a proposal")
|
||||||
|
|
||||||
|
visit sdg_management_debates_path
|
||||||
|
|
||||||
|
expect(page).to have_text "I'm a debate"
|
||||||
|
expect(page).not_to have_text "I'm a proposal"
|
||||||
|
|
||||||
|
visit sdg_management_proposals_path
|
||||||
|
|
||||||
|
expect(page).to have_text "I'm a proposal"
|
||||||
|
expect(page).not_to have_text "I'm a debate"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "list goals and target for all records" do
|
||||||
|
redistribute = create(:proposal, title: "Resources distribution")
|
||||||
|
redistribute.sdg_goals = [SDG::Goal[1]]
|
||||||
|
redistribute.sdg_targets = [SDG::Target["1.1"]]
|
||||||
|
|
||||||
|
treatment = create(:proposal, title: "Treatment system")
|
||||||
|
treatment.sdg_goals = [SDG::Goal[6]]
|
||||||
|
treatment.sdg_targets = [SDG::Target["6.1"], SDG::Target["6.2"]]
|
||||||
|
|
||||||
|
visit sdg_management_proposals_path
|
||||||
|
|
||||||
|
within("tr", text: "Resources distribution") do
|
||||||
|
expect(page).to have_content "1.1"
|
||||||
|
end
|
||||||
|
|
||||||
|
within("tr", text: "Treatment system") do
|
||||||
|
expect(page).to have_content "6.1, 6.2"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "shows link to edit a record" do
|
||||||
|
create(:budget_investment, title: "Build a hospital")
|
||||||
|
|
||||||
|
visit sdg_management_budget_investments_path
|
||||||
|
|
||||||
|
within("tr", text: "Build a hospital") do
|
||||||
|
click_link "Manage goals and targets"
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(page).to have_css "h2", exact_text: "Build a hospital"
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "search" do
|
||||||
|
scenario "search by terms" do
|
||||||
|
create(:poll, name: "Internet speech freedom")
|
||||||
|
create(:poll, name: "SDG interest")
|
||||||
|
|
||||||
|
visit sdg_management_polls_path
|
||||||
|
|
||||||
|
fill_in "search", with: "speech"
|
||||||
|
click_button "Search"
|
||||||
|
|
||||||
|
expect(page).to have_content "Internet speech freedom"
|
||||||
|
expect(page).not_to have_content "SDG interest"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "goal filter" do
|
||||||
|
create(:budget_investment, title: "School", sdg_goals: [SDG::Goal[4]])
|
||||||
|
create(:budget_investment, title: "Hospital", sdg_goals: [SDG::Goal[3]])
|
||||||
|
|
||||||
|
visit sdg_management_budget_investments_path
|
||||||
|
select "4. Quality Education", from: "goal_code"
|
||||||
|
click_button "Search"
|
||||||
|
|
||||||
|
expect(page).to have_content "School"
|
||||||
|
expect(page).not_to have_content "Hospital"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "target filter" do
|
||||||
|
create(:budget_investment, title: "School", sdg_targets: [SDG::Target[4.1]])
|
||||||
|
create(:budget_investment, title: "Preschool", sdg_targets: [SDG::Target[4.2]])
|
||||||
|
|
||||||
|
visit sdg_management_budget_investments_path
|
||||||
|
select "4.1", from: "target_code"
|
||||||
|
click_button "Search"
|
||||||
|
|
||||||
|
expect(page).to have_content "School"
|
||||||
|
expect(page).not_to have_content "Preschool"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Edit" do
|
||||||
|
scenario "allows changing the targets" do
|
||||||
|
process = create(:legislation_process, title: "SDG process")
|
||||||
|
process.sdg_targets = [SDG::Target["3.3"]]
|
||||||
|
|
||||||
|
visit sdg_management_edit_legislation_process_path(process)
|
||||||
|
fill_in "Targets", with: "1.2, 2.1"
|
||||||
|
click_button "Update Process"
|
||||||
|
|
||||||
|
within("tr", text: "SDG process") do
|
||||||
|
expect(page).to have_css "td", exact_text: "1.2, 2.1"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user