diff --git a/app/controllers/admin/geozones_controller.rb b/app/controllers/admin/geozones_controller.rb
new file mode 100644
index 000000000..b73c13422
--- /dev/null
+++ b/app/controllers/admin/geozones_controller.rb
@@ -0,0 +1,49 @@
+class Admin::GeozonesController < Admin::BaseController
+
+ respond_to :html
+
+ load_and_authorize_resource
+
+ def index
+ @geozones = Geozone.all.order("LOWER(name)")
+ end
+
+ def new
+ end
+
+ def edit
+ end
+
+ def create
+ @geozone = Geozone.new(geozone_params)
+
+ if @geozone.save
+ redirect_to admin_geozones_path
+ else
+ render :new
+ end
+ end
+
+ def update
+ if @geozone.update(geozone_params)
+ redirect_to admin_geozones_path
+ else
+ render :edit
+ end
+ end
+
+ def destroy
+ if @geozone.safe_to_destroy?
+ @geozone.destroy
+ redirect_to admin_geozones_path, notice: t('admin.geozones.delete.success')
+ else
+ redirect_to admin_geozones_path, flash: { error: t('admin.geozones.delete.error') }
+ end
+ end
+
+ private
+
+ def geozone_params
+ params.require(:geozone).permit(:name, :external_code, :census_code, :html_map_coordinates)
+ end
+end
diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb
index 0dfce6d3e..975ba7a8d 100644
--- a/app/models/abilities/administrator.rb
+++ b/app/models/abilities/administrator.rb
@@ -43,6 +43,7 @@ module Abilities
can [:read, :update, :destroy, :summary], SpendingProposal
can [:search, :edit, :update, :create, :index, :destroy], Banner
+ can [:index, :create, :edit, :update, :destroy], Geozone
end
end
end
diff --git a/app/models/geozone.rb b/app/models/geozone.rb
index 787e2b7e2..7e38ce97d 100644
--- a/app/models/geozone.rb
+++ b/app/models/geozone.rb
@@ -1,9 +1,17 @@
class Geozone < ActiveRecord::Base
+ has_many :proposals
has_many :spending_proposals
+ has_many :debates
+ has_many :users
validates :name, presence: true
def self.names
Geozone.pluck(:name)
end
+ def safe_to_destroy?
+ Geozone.reflect_on_all_associations(:has_many).all? do |association|
+ association.klass.where(geozone: self).empty?
+ end
+ end
end
diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb
index 7ea48b2c6..3d3e807c7 100644
--- a/app/views/admin/_menu.html.erb
+++ b/app/views/admin/_menu.html.erb
@@ -83,6 +83,12 @@
<% end %>
+
>
+ <%= link_to admin_geozones_path do %>
+ <%= t('admin.menu.geozones') %>
+ <% end %>
+
+
>
<%= link_to admin_activity_path do %>
<%= t('admin.menu.activity') %>
diff --git a/app/views/admin/geozones/_errors.html.erb b/app/views/admin/geozones/_errors.html.erb
new file mode 100644
index 000000000..d0f3b849f
--- /dev/null
+++ b/app/views/admin/geozones/_errors.html.erb
@@ -0,0 +1,15 @@
+
+<% if @geozone.errors.any? %>
+
+
+
+
+
+ <%= @geozone.errors.count %>
+ <%= t("admin.geozones.errors.form.error", count: @geozone.errors.count) %>
+
+
+
+<% end %>
diff --git a/app/views/admin/geozones/_form.html.erb b/app/views/admin/geozones/_form.html.erb
new file mode 100644
index 000000000..e92b98c0b
--- /dev/null
+++ b/app/views/admin/geozones/_form.html.erb
@@ -0,0 +1,29 @@
+<%= form_for [:admin, @geozone] do |f| %>
+
+ <%= render 'errors' %>
+
+
+
+ <%= f.label :name, t("admin.geozones.geozone.name") %>
+ <%= f.text_field :name, label: false %>
+
+
+ <%= f.label :html_map_coordinates, t("admin.geozones.geozone.coordinates") %>
+ <%= f.text_field :html_map_coordinates, label: false %>
+
+
+ <%= f.label :external_code, t("admin.geozones.geozone.external_code") %>
+ <%= f.text_field :external_code, label: false %>
+
+
+ <%= f.label :census_code, t("admin.geozones.geozone.census_code") %>
+ <%= f.text_field :census_code, label: false %>
+
+
+
+
+
+ <%= f.submit(class: "button expanded", value: t("admin.geozones.edit.form.submit_button")) %>
+
+
+<% end %>
diff --git a/app/views/admin/geozones/edit.html.erb b/app/views/admin/geozones/edit.html.erb
new file mode 100644
index 000000000..b6b8c3fd9
--- /dev/null
+++ b/app/views/admin/geozones/edit.html.erb
@@ -0,0 +1,13 @@
+
+
+
+ <%= link_to admin_geozones_path, class: "back" do %>
+
+ <%= t("admin.geozones.edit.back") %>
+ <% end %>
+
+
<%= t("admin.geozones.edit.editing") %>
+
+ <%= render "form" %>
+
+
diff --git a/app/views/admin/geozones/index.html.erb b/app/views/admin/geozones/index.html.erb
new file mode 100644
index 000000000..5a524e46e
--- /dev/null
+++ b/app/views/admin/geozones/index.html.erb
@@ -0,0 +1,33 @@
+<%= link_to t("admin.geozones.index.create"),
+ new_admin_geozone_path, class: "button success float-right" %>
+
+<%= t("admin.geozones.index.title") %>
+
+
+
+
+ | <%= t("admin.geozones.geozone.name") %> |
+ <%= t("admin.geozones.geozone.external_code") %> |
+ <%= t("admin.geozones.geozone.census_code") %> |
+ <%= t("admin.geozones.geozone.coordinates") %> |
+ |
+
+
+
+
+ <% @geozones.each do |geozone| %>
+
+ | <%= geozone.name %> |
+ <%= geozone.external_code %> |
+ <%= geozone.census_code %> |
+ <%= geozone.html_map_coordinates %> |
+
+ <%= link_to t("admin.geozones.index.edit"), edit_admin_geozone_path(geozone), class: 'edit-banner button hollow' %>
+ |
+
+ <%= link_to t("admin.geozones.index.delete"), admin_geozone_path(geozone), method: :delete, class: 'button hollow alert' %>
+ |
+
+ <% end %>
+
+
diff --git a/app/views/admin/geozones/new.html.erb b/app/views/admin/geozones/new.html.erb
new file mode 100644
index 000000000..0d5080337
--- /dev/null
+++ b/app/views/admin/geozones/new.html.erb
@@ -0,0 +1,13 @@
+
+
+
+ <%= link_to admin_geozones_path, class: "back" do %>
+
+ <%= t("admin.geozones.new.back") %>
+ <% end %>
+
+
<%= t("admin.geozones.new.creating") %>
+
+ <%= render "form" %>
+
+
diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml
index 2f73f64d8..370a06ccc 100755
--- a/config/locales/admin.en.yml
+++ b/config/locales/admin.en.yml
@@ -97,6 +97,7 @@ en:
admin: Admin menu
banner: Manage banners
debate_topics: Debate topics
+ geozones: Manage geozones
hidden_comments: Hidden comments
hidden_debates: Hidden debates
hidden_proposals: Hidden proposals
@@ -267,6 +268,33 @@ en:
in_evaluation_count: In evaluation
total_count: Total
cost_for_geozone: Cost
+ geozones:
+ index:
+ title: Geozone
+ create: Create geozone
+ edit: Edit
+ delete: Delete
+ geozone:
+ name: Name
+ external_code: External code
+ census_code: Census code
+ coordinates: Coordinates
+ errors:
+ form:
+ error:
+ one: "prevented this geozone from being saved"
+ other: 'prevented this geozone from being saved'
+ edit:
+ form:
+ submit_button: Save changes
+ editing: Editing geozone
+ back: Go back
+ new:
+ back: Go back
+ creating: Create district
+ delete:
+ success: Geozone successfully deleted
+ error: This geozone can't be deleted since there are elements attached to it
stats:
show:
stats_title: Stats
diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml
index 5aada1ce1..8819905d8 100644
--- a/config/locales/admin.es.yml
+++ b/config/locales/admin.es.yml
@@ -95,6 +95,7 @@ es:
admin: Menú de administración
banner: Gestionar banners
debate_topics: Temas de debate
+ geozones: Gestionar distritos
hidden_comments: Comentarios ocultos
hidden_debates: Debates ocultos
hidden_proposals: Propuestas ocultas
@@ -265,6 +266,33 @@ es:
in_evaluation_count: En evaluación
total_count: Total
cost_for_geozone: Coste total
+ geozones:
+ index:
+ title: Distritos
+ create: Crear un distrito
+ edit: Editar
+ delete: Borrar
+ geozone:
+ name: Nombre
+ external_code: Código externo
+ census_code: Código del censo
+ coordinates: Coordenadas
+ errors:
+ form:
+ error:
+ one: "error impidió guardar el distrito"
+ other: "errores impidieron guardar el distrito."
+ edit:
+ form:
+ submit_button: Guardar cambios
+ editing: Editando distrito
+ back: Volver
+ new:
+ back: Volver
+ creating: Crear distrito
+ delete:
+ success: Distrito borrado correctamente
+ error: No se puede borrar el distrito porque ya tiene elementos asociados
stats:
show:
stats_title: Estadísticas
diff --git a/config/routes.rb b/config/routes.rb
index df1a7c6fb..885d155db 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -192,6 +192,8 @@ Rails.application.routes.draw do
namespace :api do
resource :stats, only: :show
end
+
+ resources :geozones, only: [:index, :new, :create, :edit, :update, :destroy]
end
namespace :moderation do
diff --git a/db/dev_seeds.rb b/db/dev_seeds.rb
index 87dc94a2e..02e5f9f6d 100644
--- a/db/dev_seeds.rb
+++ b/db/dev_seeds.rb
@@ -34,7 +34,7 @@ Setting.create(key: 'per_page_code', value: "")
Setting.create(key: 'comments_body_max_length', value: '1000')
puts "Creating Geozones"
-('A'..'Z').each{ |i| Geozone.create(name: "District #{i}") }
+('A'..'Z').each { |i| Geozone.create(name: "District #{i}", external_code: i.ord, census_code: i.ord) }
puts "Creating Users"
diff --git a/spec/factories.rb b/spec/factories.rb
index 7b446f3a0..c53f16be6 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -317,7 +317,8 @@ FactoryGirl.define do
factory :geozone do
sequence(:name) { |n| "District #{n}" }
- census_code { '01' }
+ sequence(:external_code) { |n| "#{n}" }
+ sequence(:census_code) { |n| "#{n}" }
end
factory :banner do
diff --git a/spec/features/admin/geozones_spec.rb b/spec/features/admin/geozones_spec.rb
new file mode 100644
index 000000000..44f9b0d03
--- /dev/null
+++ b/spec/features/admin/geozones_spec.rb
@@ -0,0 +1,100 @@
+require 'rails_helper'
+
+feature 'Admin geozones' do
+
+ background do
+ login_as(create(:administrator).user)
+ end
+
+ scenario 'Show list of geozones' do
+ chamberi = create(:geozone, name: 'Chamberí')
+ retiro = create(:geozone, name: 'Retiro')
+
+ visit admin_geozones_path
+
+ expect(page).to have_content(chamberi.name)
+ expect(page).to have_content(retiro.name)
+ end
+
+ scenario 'Create new geozone' do
+ visit admin_root_path
+
+ within('#side_menu') { click_link 'Manage geozones' }
+
+ click_link 'Create geozone'
+
+ fill_in 'geozone_name', with: 'Fancy District'
+ fill_in 'geozone_external_code', with: 123
+ fill_in 'geozone_census_code', with: 44
+
+ click_button 'Save changes'
+
+ expect(page).to have_content 'Fancy District'
+
+ visit admin_geozones_path
+
+ expect(page).to have_content 'Fancy District'
+ end
+
+ scenario 'Edit geozone with no associated elements' do
+ geozone = create(:geozone, name: 'Edit me!', census_code: '012')
+
+ visit admin_geozones_path
+
+ within("#geozone_#{geozone.id}") { click_link 'Edit' }
+
+ fill_in 'geozone_name', with: 'New geozone name'
+ fill_in 'geozone_census_code', with: '333'
+
+ click_button 'Save changes'
+
+ within("#geozone_#{geozone.id}") do
+ expect(page).to have_content 'New geozone name'
+ expect(page).to have_content '333'
+ end
+ end
+
+ scenario 'Edit geozone with associated elements' do
+ geozone = create(:geozone, name: 'Edit me!')
+ create(:proposal, title: 'Proposal with geozone', geozone: geozone)
+
+ visit admin_geozones_path
+
+ within("#geozone_#{geozone.id}") { click_link 'Edit' }
+
+ fill_in 'geozone_name', with: 'New geozone name'
+
+ click_button 'Save changes'
+
+ within("#geozone_#{geozone.id}") do
+ expect(page).to have_content 'New geozone name'
+ end
+ end
+
+ scenario 'Delete geozone with no associated elements' do
+ geozone = create(:geozone, name: 'Delete me!')
+
+ visit admin_geozones_path
+
+ within("#geozone_#{geozone.id}") { click_link 'Delete' }
+
+ expect(page).to have_content 'Geozone successfully deleted'
+ expect(page).not_to have_content('Delete me!')
+ expect(Geozone.where(id: geozone.id)).to be_empty
+ end
+
+ scenario 'Delete geozone with associated element' do
+ geozone = create(:geozone, name: 'Delete me!')
+ create(:proposal, geozone: geozone)
+
+ visit admin_geozones_path
+
+ within("#geozone_#{geozone.id}") { click_link 'Delete' }
+
+ expect(page).to have_content "This geozone can't be deleted since there are elements attached to it"
+
+ within("#geozone_#{geozone.id}") do
+ expect(page).to have_content 'Delete me!'
+ end
+ end
+end
diff --git a/spec/models/geozone_spec.rb b/spec/models/geozone_spec.rb
index a29c4c918..1a7bf6b09 100644
--- a/spec/models/geozone_spec.rb
+++ b/spec/models/geozone_spec.rb
@@ -11,4 +11,30 @@ RSpec.describe Geozone, type: :model do
geozone.name = nil
expect(geozone).to_not be_valid
end
+
+ describe "#safe_to_destroy?" do
+ it "is true when not linked to other models" do
+ expect(geozone.safe_to_destroy?).to be_truthy
+ end
+
+ it "is false when already linked to user" do
+ create(:user, geozone: geozone)
+ expect(geozone.safe_to_destroy?).to be_falsey
+ end
+
+ it "is false when already linked to proposal" do
+ create(:proposal, geozone: geozone)
+ expect(geozone.safe_to_destroy?).to be_falsey
+ end
+
+ it "is false when already linked to spending proposal" do
+ create(:spending_proposal, geozone: geozone)
+ expect(geozone.safe_to_destroy?).to be_falsey
+ end
+
+ it "is false when already linked to debate" do
+ create(:debate, geozone: geozone)
+ expect(geozone.safe_to_destroy?).to be_falsey
+ end
+ end
end