diff --git a/.travis.yml b/.travis.yml index 0aa683c04..f9222fdb3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,10 +22,11 @@ env: global: - KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true - KNAPSACK_PRO_LOG_LEVEL=info - - KNAPSACK_PRO_CI_NODE_TOTAL=2 + - KNAPSACK_PRO_CI_NODE_TOTAL=3 matrix: - KNAPSACK_PRO_CI_NODE_INDEX=0 - KNAPSACK_PRO_CI_NODE_INDEX=1 + - KNAPSACK_PRO_CI_NODE_INDEX=2 notifications: slack: secure: 18E9SU0SR/9knRvCMYwVqFCqVTBT6qJtZQ/gadpheqUPPlcLoQfnlIzJkLIYqkE0sn1nkBE5Bt2I90FU53p0NkrTEmSGlQXcN1vEXM8EXMaoVf3NBsIJeleMwt9VTojzo81EgIi6x7q3fDiFORJ4rqOGd9XkeLn5yrAtIkdaenVs0bhS5s24FP76hKqO37IFLG2v3EEqxg5k31oW6yhyP35Mxns+AGbfaZbxEy4XbCoU65KFuYhBsVZ/y1evOl/wcre2fCAoT2uKeqUWGEcDzH7oSCz7vfk7iO9BZnO++v7oj8mr/nrZL1KMFt77eqtdT51XQoJcchgJC/R9km5hRGkQqFCHhqPcBxo5c3p+jauL0kLaqTggeLDv2FQ2huJ8FSJ4ADac+n3g7wT7BX7HJlCvK0nbooY1JtBlk7+6/pw6ksSFIOo0FHg5gXN9IlG1tQQuENzzsXULNc6s4nPeT+n78uOp1b0N/Gn06moEBaKgXqqx1yV1XeJ02X8n3uDZxPuX3n2bJ4DMIrBjeWApxHAgyOraOzQHNQgJoj4tHlWutF33ApV2tcIMefIzvjM4tIYwIkpfGgohGaTf8eU5X9pqiMgwlDpJHVBsSvpk/Z/Nj7evYznjBiDYqOcXoztsqHrS0C91MaT+eExDfd9HDmThsE07RT7zcP9aElFZA/k= diff --git a/README.md b/README.md index 9cb539e31..37adc5791 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ + +  # CONSUL @@ -19,13 +25,17 @@ Citizen Participation and Open Government Application This is the opensource code repository of the eParticipation website CONSUL, originally developed for the Madrid City government eParticipation website -## Current state +## Documentation -Development started on [2015 July 15th](https://github.com/consul/consul/commit/8db36308379accd44b5de4f680a54c41a0cc6fc6). Code was deployed to production on 2015 september 7th to [decide.madrid.es](https://decide.madrid.es). Since then new features are added often. You can take a look at the current features at the [project's website](http://consulproject.org/) and future features at the [Roadmap](https://github.com/consul/consul/projects/6) and [open issues list](https://github.com/consul/consul/issues). +Check the ongoing documentation at [https://docs.consulproject.org](https://docs.consulproject.org) to learn more about how to start your own CONSUL fork, install it, customize it and learn to use it from an administrator/maintainer perspective. + +## CONSUL Project main website + +You can access the main website of the project at [http://consulproject.org](http://consulproject.org) where you can find documentation about the use of the platform, videos, and links to the community space. ## Configuration for development and test environments -**NOTE**: For more detailed instructions check the [docs](https://consul_docs.gitbooks.io/docs/) +**NOTE**: For more detailed instructions check the [docs](https://docs.consulproject.org) Prerequisites: install git, Ruby 2.3.2, `bundler` gem, Node.js and PostgreSQL (>=9.4). @@ -69,9 +79,9 @@ But for some actions like voting, you will need a verified user, the seeds file See [installer](https://github.com/consul/installer) -## Documentation +## Current state -Check the ongoing documentation at [https://consul_docs.gitbooks.io/docs/content/](https://consul_docs.gitbooks.io/docs/content/) to learn more about how to start your own CONSUL fork, install it, customize it and learn to use it from an administrator/maintainer perspective. You can contribute to it at [https://github.com/consul/docs](https://github.com/consul/docs) +Development started on [2015 July 15th](https://github.com/consul/consul/commit/8db36308379accd44b5de4f680a54c41a0cc6fc6). Code was deployed to production on 2015 september 7th to [decide.madrid.es](https://decide.madrid.es). Since then new features are added often. You can take a look at the current features at the [project's website](http://consulproject.org/) and future features at the [Roadmap](https://github.com/consul/consul/projects/6) and [open issues list](https://github.com/consul/consul/issues). ## License diff --git a/README_ES.md b/README_ES.md index ee5f6d16b..052b4ee85 100644 --- a/README_ES.md +++ b/README_ES.md @@ -1,3 +1,9 @@ + +  # CONSUL @@ -18,13 +24,17 @@ Aplicación de Participación Ciudadana y Gobierno Abierto Este es el repositorio de código abierto de la Aplicación de Participación Ciudadana CONSUL, creada originariamente por el Ayuntamiento de Madrid. -## Estado del proyecto +## Documentación -El desarrollo de esta aplicación comenzó el [15 de Julio de 2015](https://github.com/consul/consul/commit/8db36308379accd44b5de4f680a54c41a0cc6fc6) y el código fue puesto en producción el día 7 de Septiembre de 2015 en [decide.madrid.es](https://decide.madrid.es). Desde entonces se le añaden mejoras y funcionalidades constantemente. Las funcionalidades actuales se pueden consultar en la [la página del projecto](http://consulproject.org/es) y las futuras funcionalidades en el [Roadmap](https://github.com/consul/consul/projects/6) y [el listado de issues](https://github.com/consul/consul/issues). +Por favor visita la documentación que está siendo completada en [https://docs.consulproject.org](https://docs.consulproject.org) para conocer más sobre este proyecto, cómo comenzar tu propio fork, instalarlo, personalizarlo y usarlo como administrador/mantenedor. + +## Web CONSUL Project + +Puedes acceder a la página principal del proyecto en [http://consulproject.org](http://consulproject.org) donde puedes encontrar documentación sobre el uso de la plataforma, videos y enlaces al espacio de la comunidad. ## Configuración para desarrollo y tests -**NOTA**: para unas instrucciones más detalladas consulta la [documentación](https://github.com/consul/docs/tree/master/es/getting_started/prerequisites) +**NOTA**: para unas instrucciones más detalladas consulta la [documentación](https://docs.consulproject.org) Prerequisitos: tener instalado git, Ruby 2.3.2, la gema `bundler`, Node.js y PostgreSQL (9.4 o superior). @@ -64,9 +74,9 @@ Pero para ciertas acciones, como apoyar, necesitarás un usuario verificado, el **user:** verified@consul.dev **pass:** 12345678 -## Documentación +## Estado del proyecto -Por favor visita la documentación que está siendo completada en [https://consul_docs.gitbooks.io/docs/content/](https://consul_docs.gitbooks.io/docs/content/) para conocer más sobre este proyecto, como comenzar tu propio fork, instalarlo, customizarlo y usarlo como administrador/mantenedor. Puedes colaborar en ella en [https://github.com/consul/docs](https://github.com/consul/docs) +El desarrollo de esta aplicación comenzó el [15 de Julio de 2015](https://github.com/consul/consul/commit/8db36308379accd44b5de4f680a54c41a0cc6fc6) y el código fue puesto en producción el día 7 de Septiembre de 2015 en [decide.madrid.es](https://decide.madrid.es). Desde entonces se le añaden mejoras y funcionalidades constantemente. Las funcionalidades actuales se pueden consultar en la [la página del projecto](http://consulproject.org/es) y las futuras funcionalidades en el [Roadmap](https://github.com/consul/consul/projects/6) y [el listado de issues](https://github.com/consul/consul/issues). ## Licencia diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index 17ea18b9d..9c95f400f 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -1205,6 +1205,11 @@ table { .filter { display: inline-block; margin: 0 $line-height / 2; + + label { + font-weight: normal; + margin: 0; + } } .button { diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index acbe5895b..2e35b8256 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -1168,6 +1168,11 @@ text-decoration: none; } + .confirmed { + font-size: rem-calc(24); + font-weight: bold; + } + .info { background: #6a2a72; diff --git a/app/controllers/admin/budget_investments_controller.rb b/app/controllers/admin/budget_investments_controller.rb index 1a213c2f2..a451d67a5 100644 --- a/app/controllers/admin/budget_investments_controller.rb +++ b/app/controllers/admin/budget_investments_controller.rb @@ -4,10 +4,8 @@ class Admin::BudgetInvestmentsController < Admin::BaseController feature_flag :budgets - has_orders %w{oldest}, only: [:show, :edit] - has_filters(%w{all without_admin without_valuator under_valuation - valuation_finished winners}, - only: [:index, :toggle_selection]) + has_orders %w[oldest], only: [:show, :edit] + has_filters %w[all], only: [:index, :toggle_selection] before_action :load_budget before_action :load_investment, only: [:show, :edit, :update, :toggle_selection] diff --git a/app/controllers/admin/budgets_controller.rb b/app/controllers/admin/budgets_controller.rb index 252e48134..955da3f1d 100644 --- a/app/controllers/admin/budgets_controller.rb +++ b/app/controllers/admin/budgets_controller.rb @@ -23,7 +23,9 @@ class Admin::BudgetsController < Admin::BaseController def calculate_winners return unless @budget.balloting_process? @budget.headings.each { |heading| Budget::Result.new(@budget, heading).delay.calculate_winners } - redirect_to admin_budget_budget_investments_path(budget_id: @budget.id, filter: "winners"), + redirect_to admin_budget_budget_investments_path( + budget_id: @budget.id, + advanced_filters: ["winners"]), notice: I18n.t("admin.budgets.winners.calculated") end diff --git a/app/controllers/officing/base_controller.rb b/app/controllers/officing/base_controller.rb index 48054ce6a..58ba3c8b2 100644 --- a/app/controllers/officing/base_controller.rb +++ b/app/controllers/officing/base_controller.rb @@ -1,12 +1,46 @@ class Officing::BaseController < ApplicationController layout "admin" + helper_method :current_booth before_action :authenticate_user! before_action :verify_officer skip_authorization_check - def verify_officer - raise CanCan::AccessDenied unless current_user.try(:poll_officer?) - end + private + + def verify_officer + raise CanCan::AccessDenied unless current_user.try(:poll_officer?) + end + + def load_officer_assignment + @officer_assignments ||= current_user.poll_officer. + officer_assignments. + voting_days. + where(date: Time.current.to_date) + end + + def verify_officer_assignment + if @officer_assignments.blank? + redirect_to officing_root_path, notice: t("officing.residence.flash.not_allowed") + end + end + + def verify_booth + return unless current_booth.blank? + booths = current_user.poll_officer.todays_booths + case booths.count + when 0 + redirect_to officing_root_path + when 1 + session[:booth_id] = booths.first.id + else + redirect_to new_officing_booth_path + end + end + + def current_booth + Poll::Booth.where(id: session[:booth_id]).first + end + end diff --git a/app/controllers/officing/booth_controller.rb b/app/controllers/officing/booth_controller.rb new file mode 100644 index 000000000..584c92de0 --- /dev/null +++ b/app/controllers/officing/booth_controller.rb @@ -0,0 +1,24 @@ +class Officing::BoothController < Officing::BaseController + before_action :load_officer_assignment + before_action :verify_officer_assignment + + def new + @booths = current_user.poll_officer.todays_booths + end + + def create + set_booth(Poll::Booth.find(booth_params[:id])) + redirect_to officing_root_path + end + + private + + def booth_params + params.require(:booth).permit(:id) + end + + def set_booth(booth) + session[:booth_id] = booth.id + end + +end diff --git a/app/controllers/officing/polls_controller.rb b/app/controllers/officing/polls_controller.rb index 69b65ad23..dc806d35f 100644 --- a/app/controllers/officing/polls_controller.rb +++ b/app/controllers/officing/polls_controller.rb @@ -1,4 +1,5 @@ class Officing::PollsController < Officing::BaseController + before_action :verify_booth def index @polls = current_user.poll_officer? ? current_user.poll_officer.voting_days_assigned_polls : [] diff --git a/app/controllers/officing/residence_controller.rb b/app/controllers/officing/residence_controller.rb index ef76162ea..cb7b96a64 100644 --- a/app/controllers/officing/residence_controller.rb +++ b/app/controllers/officing/residence_controller.rb @@ -1,7 +1,8 @@ class Officing::ResidenceController < Officing::BaseController before_action :load_officer_assignment - before_action :validate_officer_assignment, only: :create + before_action :verify_officer_assignment + before_action :verify_booth def new @residence = Officing::Residence.new @@ -22,16 +23,4 @@ class Officing::ResidenceController < Officing::BaseController params.require(:residence).permit(:document_number, :document_type, :year_of_birth) end - def load_officer_assignment - @officer_assignments = current_user.poll_officer. - officer_assignments. - voting_days. - where(date: Date.current) - end - - def validate_officer_assignment - if @officer_assignments.blank? - redirect_to officing_root_path, notice: t("officing.residence.flash.not_allowed") - end - end end diff --git a/app/controllers/officing/results_controller.rb b/app/controllers/officing/results_controller.rb index 54bb1076c..ff9bf3925 100644 --- a/app/controllers/officing/results_controller.rb +++ b/app/controllers/officing/results_controller.rb @@ -7,6 +7,7 @@ class Officing::ResultsController < Officing::BaseController before_action :load_officer_assignment, only: :create before_action :check_officer_assignment, only: :create before_action :build_results, only: :create + before_action :verify_booth def new end diff --git a/app/controllers/officing/voters_controller.rb b/app/controllers/officing/voters_controller.rb index 2b7ed329f..78233d41c 100644 --- a/app/controllers/officing/voters_controller.rb +++ b/app/controllers/officing/voters_controller.rb @@ -1,6 +1,10 @@ class Officing::VotersController < Officing::BaseController respond_to :html, :js + before_action :load_officer_assignment + before_action :verify_officer_assignment + before_action :verify_booth + def new @user = User.find(params[:id]) booths = current_user.poll_officer.shifts.current.vote_collection.pluck(:booth_id).uniq @@ -15,7 +19,9 @@ class Officing::VotersController < Officing::BaseController user: @user, poll: @poll, origin: "booth", - officer: current_user.poll_officer) + officer: current_user.poll_officer, + booth_assignment: Poll::BoothAssignment.where(poll: @poll, booth: current_booth).first, + officer_assignment: officer_assignment(@poll)) @voter.save! end @@ -25,4 +31,13 @@ class Officing::VotersController < Officing::BaseController params.require(:voter).permit(:poll_id, :user_id) end + def officer_assignment(poll) + Poll::OfficerAssignment.by_officer(current_user.poll_officer) + .by_poll(poll) + .by_booth(current_booth) + .by_date(Date.current) + .where(final: false) + .first + end + end diff --git a/app/controllers/users/sessions_controller.rb b/app/controllers/users/sessions_controller.rb index d16f9c87e..0409a9d5e 100644 --- a/app/controllers/users/sessions_controller.rb +++ b/app/controllers/users/sessions_controller.rb @@ -3,7 +3,9 @@ class Users::SessionsController < Devise::SessionsController private def after_sign_in_path_for(resource) - if !verifying_via_email? && resource.show_welcome_screen? + if current_user.poll_officer? + new_officing_booth_path + elsif !verifying_via_email? && resource.show_welcome_screen? welcome_path else super diff --git a/app/helpers/admin_budget_investments_helper.rb b/app/helpers/admin_budget_investments_helper.rb index 5c2dc479e..aa33961aa 100644 --- a/app/helpers/admin_budget_investments_helper.rb +++ b/app/helpers/admin_budget_investments_helper.rb @@ -1,7 +1,13 @@ module AdminBudgetInvestmentsHelper def advanced_menu_visibility - (params[:advanced_filters].empty? && params["min_total_supports"].blank?) ? "hide" : "" + if params[:advanced_filters].empty? && + params["min_total_supports"].blank? && + params["max_total_supports"].blank? + "hide" + else + "" + end end def init_advanced_menu diff --git a/app/helpers/officers_helper.rb b/app/helpers/officers_helper.rb index e069cb9aa..1218af80e 100644 --- a/app/helpers/officers_helper.rb +++ b/app/helpers/officers_helper.rb @@ -5,11 +5,15 @@ module OfficersHelper end def vote_collection_shift? - current_user.poll_officer.officer_assignments.where(date: Time.current.to_date).any? + current_user.poll_officer.officer_assignments.voting_days.where(date: Time.current.to_date).any? end def final_recount_shift? current_user.poll_officer.officer_assignments.final.where(date: Time.current.to_date).any? end + def no_shifts? + current_user.poll_officer.officer_assignments.where(date: Time.current.to_date).blank? + end + end diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index f2095c746..b033d7404 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -117,7 +117,9 @@ class Budget results = Investment.by_budget(budget) results = results.where("cached_votes_up + physical_votes >= ?", - params[:min_total_supports]) if params[:min_total_supports].present? + params[:min_total_supports]) if params[:min_total_supports].present? + results = results.where("cached_votes_up + physical_votes <= ?", + params[:max_total_supports]) if params[:max_total_supports].present? results = results.where(group_id: params[:group_id]) if params[:group_id].present? results = results.by_tag(params[:tag_name]) if params[:tag_name].present? results = results.by_heading(params[:heading_id]) if params[:heading_id].present? @@ -132,12 +134,19 @@ class Budget end def self.advanced_filters(params, results) + results = results.without_admin if params[:advanced_filters].include?("without_admin") + results = results.without_valuator if params[:advanced_filters].include?("without_valuator") + results = results.under_valuation if params[:advanced_filters].include?("under_valuation") + results = results.valuation_finished if params[:advanced_filters].include?("valuation_finished") + results = results.winners if params[:advanced_filters].include?("winners") + ids = [] ids += results.valuation_finished_feasible.pluck(:id) if params[:advanced_filters].include?("feasible") ids += results.where(selected: true).pluck(:id) if params[:advanced_filters].include?("selected") ids += results.undecided.pluck(:id) if params[:advanced_filters].include?("undecided") ids += results.unfeasible.pluck(:id) if params[:advanced_filters].include?("unfeasible") - results.where("budget_investments.id IN (?)", ids) + results = results.where("budget_investments.id IN (?)", ids) if ids.any? + results end def self.order_filter(params) diff --git a/app/models/budget/investment/exporter.rb b/app/models/budget/investment/exporter.rb index ec5b6abf4..e355600f3 100644 --- a/app/models/budget/investment/exporter.rb +++ b/app/models/budget/investment/exporter.rb @@ -58,6 +58,10 @@ class Budget::Investment::Exporter def price(investment) price_string = "admin.budget_investments.index.feasibility.#{investment.feasibility}" - I18n.t(price_string, price: investment.formatted_price) + if investment.feasible? + "#{I18n.t(price_string)} (#{investment.formatted_price})" + else + I18n.t(price_string) + end end end diff --git a/app/models/poll/officer.rb b/app/models/poll/officer.rb index 384202455..ef96cfa91 100644 --- a/app/models/poll/officer.rb +++ b/app/models/poll/officer.rb @@ -23,5 +23,9 @@ class Poll sort {|x, y| y.ends_at <=> x.ends_at} end + def todays_booths + officer_assignments.by_date(Date.current).map(&:booth).uniq + end + end end diff --git a/app/models/poll/officer_assignment.rb b/app/models/poll/officer_assignment.rb index bdd074995..7de4f98b3 100644 --- a/app/models/poll/officer_assignment.rb +++ b/app/models/poll/officer_assignment.rb @@ -17,11 +17,20 @@ class Poll scope :by_officer_and_poll, ->(officer_id, poll_id) do where("officer_id = ? AND poll_booth_assignments.poll_id = ?", officer_id, poll_id) end + scope :by_officer, ->(officer){ where(officer_id: officer.id) } + scope :by_poll, ->(poll){ joins(:booth_assignment).where("poll_booth_assignments.poll_id" => poll.id) } + scope :by_booth, ->(booth){ joins(:booth_assignment).where("poll_booth_assignments.booth_id" => booth.id) } + scope :by_date, ->(date){ where(date: date) } before_create :log_user_data def log_user_data self.user_data_log = "#{officer.user_id} - #{officer.user.name_and_email}" end + + def booth + booth_assignment.booth + end + end end diff --git a/app/models/poll/voter.rb b/app/models/poll/voter.rb index 0826092d2..1e4a0d204 100644 --- a/app/models/poll/voter.rb +++ b/app/models/poll/voter.rb @@ -12,11 +12,13 @@ class Poll validates :poll_id, presence: true validates :user_id, presence: true + validates :booth_assignment_id, presence: true, if: ->(voter) { voter.origin == "booth" } + validates :officer_assignment_id, presence: true, if: ->(voter) { voter.origin == "booth" } validates :document_number, presence: true, uniqueness: { scope: [:poll_id, :document_type], message: :has_voted } validates :origin, inclusion: { in: VALID_ORIGINS } - before_validation :set_demographic_info, :set_document_info + before_validation :set_demographic_info, :set_document_info, :set_denormalized_booth_assignment_id scope :web, -> { where(origin: "web") } scope :booth, -> { where(origin: "booth") } @@ -38,6 +40,10 @@ class Poll private + def set_denormalized_booth_assignment_id + self.booth_assignment_id ||= officer_assignment.try(:booth_assignment_id) + end + def in_census? census_api_response.valid? end diff --git a/app/views/admin/budget_investments/_investments.html.erb b/app/views/admin/budget_investments/_investments.html.erb index 0be6f5e10..55603bbcd 100644 --- a/app/views/admin/budget_investments/_investments.html.erb +++ b/app/views/admin/budget_investments/_investments.html.erb @@ -2,7 +2,7 @@ admin_budget_budget_investments_path(csv_params), class: "float-right small clear" %> -<% if params[:filter] == "winners" %> +<% if params[:advanced_filters].include?("winners") %> <% if display_calculate_winners_button?(@budget) %> <%= link_to calculate_winner_button_text(@budget), calculate_winners_admin_budget_path(@budget), @@ -36,6 +36,7 @@