diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 443782795..8258cf9c9 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -461,7 +461,7 @@ Style/Lambda:
# Offense count: 1
# Cop supports --auto-correct.
-Style/MethodCallParentheses:
+Style/MethodCallWithoutArgsParentheses:
Exclude:
- 'app/controllers/management/document_verifications_controller.rb'
diff --git a/Gemfile b/Gemfile
index a5ec32008..8dc4cc5ff 100644
--- a/Gemfile
+++ b/Gemfile
@@ -64,6 +64,7 @@ gem 'tolk', '~> 2.0.0' # Web interface for translations
gem 'browser'
gem 'turnout', '~> 2.4.0'
gem 'redcarpet', '~> 3.4.0'
+gem 'rubyzip', '~> 1.2.0'
gem 'paperclip'
gem 'rails-assets-markdown-it', source: 'https://rails-assets.org'
diff --git a/Gemfile.lock b/Gemfile.lock
index b1540cfe1..77386e543 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -371,6 +371,7 @@ GEM
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.8.1)
+ rubyzip (1.2.1)
rvm1-capistrano3 (1.4.0)
capistrano (~> 3.0)
sshkit (>= 1.2)
@@ -530,6 +531,7 @@ DEPENDENCIES
rollbar (~> 2.14.1)
rspec-rails (~> 3.6)
rubocop (~> 0.48.1)
+ rubyzip (~> 1.2.0)
rvm1-capistrano3
sass-rails (~> 5.0, >= 5.0.4)
savon
@@ -547,4 +549,4 @@ DEPENDENCIES
whenever
BUNDLED WITH
- 1.14.6
+ 1.15.0
diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss
index e9f6c23ae..06d3e1983 100644
--- a/app/assets/stylesheets/admin.scss
+++ b/app/assets/stylesheets/admin.scss
@@ -97,6 +97,10 @@ body.admin {
}
}
+ td.break {
+ word-break: break-word;
+ }
+
&.fixed {
table-layout: fixed;
}
diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss
index e55d83f12..d232ae0d3 100644
--- a/app/assets/stylesheets/layout.scss
+++ b/app/assets/stylesheets/layout.scss
@@ -1141,10 +1141,8 @@ img.avatar, img.admin-avatar, img.moderator-avatar, img.initialjs-avatar {
// 10. Officials levels
// --------------------
-[class^="level-"] {
- color: black;
-}
-
+.level-1, .level-2, .level-3,
+.level-4, .level-5,
.is-author, .is-association {
color: black;
}
diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss
index 5658a4e6b..4c0925659 100644
--- a/app/assets/stylesheets/participation.scss
+++ b/app/assets/stylesheets/participation.scss
@@ -206,9 +206,9 @@
.participation-not-allowed {
background: $warning-bg;
color: $color-warning;
- height: 100%;
left: 0;
line-height: $line-height;
+ min-height: 100%;
padding: $line-height $line-height/2;
position: absolute;
text-align: center;
diff --git a/app/controllers/admin/administrators_controller.rb b/app/controllers/admin/administrators_controller.rb
new file mode 100644
index 000000000..938a7570d
--- /dev/null
+++ b/app/controllers/admin/administrators_controller.rb
@@ -0,0 +1,37 @@
+class Admin::AdministratorsController < Admin::BaseController
+ load_and_authorize_resource
+
+ def index
+ @administrators = @administrators.page(params[:page])
+ end
+
+ def search
+ @user = User.find_by(email: params[:email])
+
+ respond_to do |format|
+ if @user
+ @administrator = Administrator.find_or_initialize_by(user: @user)
+ format.js
+ else
+ format.js { render "user_not_found" }
+ end
+ end
+ end
+
+ def create
+ @administrator.user_id = params[:user_id]
+ @administrator.save
+
+ redirect_to admin_administrators_path
+ end
+
+ def destroy
+ if current_user.id == @administrator.user_id
+ flash[:error] = I18n.t("admin.administrators.administrator.restricted_removal")
+ else
+ @administrator.destroy
+ end
+
+ redirect_to admin_administrators_path
+ end
+end
diff --git a/app/controllers/admin/newsletters_controller.rb b/app/controllers/admin/newsletters_controller.rb
new file mode 100644
index 000000000..60895dc0c
--- /dev/null
+++ b/app/controllers/admin/newsletters_controller.rb
@@ -0,0 +1,12 @@
+class Admin::NewslettersController < Admin::BaseController
+
+ def index
+ end
+
+ def users
+ zip = NewsletterZip.new('emails')
+ zip.create
+ send_file(File.join(zip.path), type: 'application/zip')
+ end
+
+end
\ No newline at end of file
diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb
index 3f0d4db4b..8ca439a1c 100644
--- a/app/helpers/admin_helper.rb
+++ b/app/helpers/admin_helper.rb
@@ -29,7 +29,7 @@ module AdminHelper
end
def menu_profiles?
- ["organizations", "officials", "moderators", "valuators", "managers"].include? controller_name
+ ["administrators", "organizations", "officials", "moderators", "valuators", "managers"].include? controller_name
end
def menu_banners?
diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb
index f09333ff0..af44066be 100644
--- a/app/models/abilities/administrator.rb
+++ b/app/models/abilities/administrator.rb
@@ -34,6 +34,7 @@ module Abilities
can :comment_as_administrator, [Debate, Comment, Proposal, Poll::Question, Budget::Investment, Legislation::Question, Legislation::Annotation]
+ can [:search, :create, :index, :destroy], ::Administrator
can [:search, :create, :index, :destroy], ::Moderator
can [:search, :create, :index, :summary], ::Valuator
can [:search, :create, :index, :destroy], ::Manager
diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb
index 56a50deec..7aabf7093 100644
--- a/app/models/budget/investment.rb
+++ b/app/models/budget/investment.rb
@@ -145,7 +145,7 @@ class Budget
return :not_selected unless selected?
return :no_ballots_allowed unless budget.balloting?
return :different_heading_assigned unless ballot.valid_heading?(heading)
- return :not_enough_money if ballot.present? && !enough_money?(ballot)
+ return :not_enough_money_html if ballot.present? && !enough_money?(ballot)
end
def permission_problem(user)
diff --git a/app/models/poll/voter.rb b/app/models/poll/voter.rb
index 8fe612151..b05839501 100644
--- a/app/models/poll/voter.rb
+++ b/app/models/poll/voter.rb
@@ -50,10 +50,10 @@ class Poll
if dob.blank?
nil
else
- now = Time.now.utc.to_date
+ now = Time.current.to_date
now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
end
end
end
-end
\ No newline at end of file
+end
diff --git a/app/models/user.rb b/app/models/user.rb
index 89bc4ce87..e55bd00e5 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -53,6 +53,7 @@ class User < ActiveRecord::Base
scope :moderators, -> { joins(:moderator) }
scope :organizations, -> { joins(:organization) }
scope :officials, -> { where("official_level > 0") }
+ scope :newsletter, -> { where(newsletter: true) }
scope :for_render, -> { includes(:organization) }
scope :by_document, -> (document_type, document_number) { where(document_type: document_type, document_number: document_number) }
scope :email_digest, -> { where(email_digest: true) }
diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb
index 56543ba28..5d454fcd8 100644
--- a/app/views/admin/_menu.html.erb
+++ b/app/views/admin/_menu.html.erb
@@ -95,6 +95,10 @@
<%= t("admin.menu.title_profiles") %>
>
+ >
+ <%= link_to t("admin.menu.administrators"), admin_administrators_path %>
+
+
>
<%= link_to t("admin.menu.organizations"), admin_organizations_path %>
@@ -171,5 +175,12 @@
<% end %>
<% end %>
+
+ >
+ <%= link_to admin_newsletters_path do %>
+
+ <%= t("admin.menu.newsletter") %>
+ <% end %>
+
diff --git a/app/views/admin/administrators/_administrator.html.erb b/app/views/admin/administrators/_administrator.html.erb
new file mode 100644
index 000000000..d948e1eed
--- /dev/null
+++ b/app/views/admin/administrators/_administrator.html.erb
@@ -0,0 +1,26 @@
+
+
+
+
+
+ <%= administrator.name %>
+
+
+ <%= administrator.email %>
+
+
+ <% if administrator.persisted? %>
+ <%= link_to t('admin.administrators.administrator.delete'),
+ admin_administrator_path(administrator),
+ method: :delete,
+ class: "button hollow alert" %>
+ <% else %>
+ <%= link_to t('admin.administrators.administrator.add'),{ controller: "admin/administrators", action: :create, user_id: administrator.user_id },
+ method: :post,
+ class: "button success" %>
+ <% end %>
+
+
+
+
+
diff --git a/app/views/admin/administrators/index.html.erb b/app/views/admin/administrators/index.html.erb
new file mode 100644
index 000000000..1cfbf5079
--- /dev/null
+++ b/app/views/admin/administrators/index.html.erb
@@ -0,0 +1,46 @@
+<%= t("admin.administrators.index.title") %>
+
+
+ <%= form_tag search_admin_administrators_path, method: :get, remote: true do %>
+
+ <%= text_field_tag :email, '', placeholder: t('admin.administrators.search.email_placeholder') %>
+
+
+ <%= submit_tag t('admin.administrators.search.search'), class: 'button' %>
+
+ <% end %>
+
+
+
+
+<%= page_entries_info @administrators %>
+
+
+ <% @administrators.each do |administrator| %>
+
+
+ <%= administrator.name %>
+
+
+ <%= administrator.email %>
+
+
+ <% if administrator.persisted? %>
+ <%= link_to t('admin.administrators.administrator.delete'),
+ admin_administrator_path(administrator),
+ method: :delete,
+ class: "button hollow alert"
+ %>
+ <% else %>
+ <%= link_to t('admin.administrators.administrator.add'),
+ { controller: "admin/administrators", action: :create,
+ user_id: administrator.user_id },
+ method: :post,
+ class: "button success" %>
+ <% end %>
+
+
+ <% end %>
+
+
+<%= paginate @administrators %>
diff --git a/app/views/admin/administrators/search.js.erb b/app/views/admin/administrators/search.js.erb
new file mode 100644
index 000000000..1c30d9595
--- /dev/null
+++ b/app/views/admin/administrators/search.js.erb
@@ -0,0 +1 @@
+$("#search-result").html("<%= j render 'administrator', administrator: @administrator %>");
diff --git a/app/views/admin/administrators/user_not_found.js.erb b/app/views/admin/administrators/user_not_found.js.erb
new file mode 100644
index 000000000..ba707fc9d
--- /dev/null
+++ b/app/views/admin/administrators/user_not_found.js.erb
@@ -0,0 +1 @@
+$("#search-result").html("<%= j t('admin.administrators.search.user_not_found') %>
");
diff --git a/app/views/admin/geozones/index.html.erb b/app/views/admin/geozones/index.html.erb
index 5a524e46e..555d00ebe 100644
--- a/app/views/admin/geozones/index.html.erb
+++ b/app/views/admin/geozones/index.html.erb
@@ -20,7 +20,7 @@
<%= geozone.name %>
<%= geozone.external_code %>
<%= geozone.census_code %>
- <%= geozone.html_map_coordinates %>
+ <%= geozone.html_map_coordinates %>
<%= link_to t("admin.geozones.index.edit"), edit_admin_geozone_path(geozone), class: 'edit-banner button hollow' %>
diff --git a/app/views/admin/newsletters/index.html.erb b/app/views/admin/newsletters/index.html.erb
new file mode 100644
index 000000000..b7b43c6fc
--- /dev/null
+++ b/app/views/admin/newsletters/index.html.erb
@@ -0,0 +1,3 @@
+<%= t("admin.newsletters.index.title") %>
+
+<%= link_to t("admin.newsletters.index.button"), users_admin_newsletters_path, class: "button" %>
\ No newline at end of file
diff --git a/app/views/admin/stats/show.html.erb b/app/views/admin/stats/show.html.erb
index 137f3ce81..5df7b5df2 100644
--- a/app/views/admin/stats/show.html.erb
+++ b/app/views/admin/stats/show.html.erb
@@ -20,29 +20,29 @@
- <%= t "admin.stats.show.summary.visits" %>
+ <%= t "admin.stats.show.summary.visits" %>
<%= number_with_delimiter(@visits) %>
- <%= t "admin.stats.show.summary.debates" %>
+ <%= t "admin.stats.show.summary.debates" %>
<%= number_with_delimiter(@debates) %>
- <%= t "admin.stats.show.summary.proposals" %>
+ <%= t "admin.stats.show.summary.proposals" %>
<%= number_with_delimiter(@proposals) %>
- <%= t "admin.stats.show.summary.comments" %>
+ <%= t "admin.stats.show.summary.comments" %>
<%= number_with_delimiter(@comments) %>
<% if feature?(:budgets) %>
- <%= t "admin.stats.show.summary.budgets" %>
+ <%= t "admin.stats.show.summary.budgets" %>
<%= number_with_delimiter(@budgets) %>
- <%= t "admin.stats.show.summary.budget_investments" %>
+ <%= t "admin.stats.show.summary.budget_investments" %>
<%= number_with_delimiter(@investments) %>
<% end %>
@@ -50,56 +50,56 @@
- <%= t "admin.stats.show.summary.proposal_votes" %>
- <%= number_with_delimiter(@proposal_votes) %>
+ <%= t "admin.stats.show.summary.proposal_votes" %>
+ <%= number_with_delimiter(@proposal_votes) %>
- <%= t "admin.stats.show.summary.debate_votes" %>
+ <%= t "admin.stats.show.summary.debate_votes" %>
<%= number_with_delimiter(@debate_votes) %>
- <%= t "admin.stats.show.summary.comment_votes" %>
+ <%= t "admin.stats.show.summary.comment_votes" %>
<%= number_with_delimiter(@comment_votes) %>
- <%= t "admin.stats.show.summary.votes" %>
+ <%= t "admin.stats.show.summary.votes" %>
<%= number_with_delimiter(@votes) %>
- <%= t "admin.stats.show.summary.verified_users" %>
+ <%= t "admin.stats.show.summary.verified_users" %>
<%= number_with_delimiter(@verified_users) %>
- <%= t "admin.stats.show.summary.unverified_users" %>
+ <%= t "admin.stats.show.summary.unverified_users" %>
<%= number_with_delimiter(@unverified_users) %>
- <%= t "admin.stats.show.summary.users" %>
+ <%= t "admin.stats.show.summary.users" %>
<%= number_with_delimiter(@users) %>
- <%= t "admin.stats.show.summary.user_level_two" %>
+ <%= t "admin.stats.show.summary.user_level_two" %>
<%= number_with_delimiter(@user_level_two) %>
- <%= t "admin.stats.show.summary.user_level_three" %>
+ <%= t "admin.stats.show.summary.user_level_three" %>
<%= number_with_delimiter(@user_level_three) %>
- <%= t "admin.stats.show.summary.verified_users_who_didnt_vote_proposals" %>
+ <%= t "admin.stats.show.summary.verified_users_who_didnt_vote_proposals" %>
<%=number_with_delimiter(@user_ids_who_didnt_vote_proposals)%>
@@ -109,7 +109,7 @@
<% if feature?(:spending_proposals) %>
- <%= t "admin.stats.show.summary.spending_proposals" %>
+ <%= t "admin.stats.show.summary.spending_proposals" %>
<%= number_with_delimiter(@spending_proposals) %>
diff --git a/app/views/budgets/investments/_ballot.html.erb b/app/views/budgets/investments/_ballot.html.erb
index 0ad43ab43..605caebc7 100644
--- a/app/views/budgets/investments/_ballot.html.erb
+++ b/app/views/budgets/investments/_ballot.html.erb
@@ -50,8 +50,9 @@
signup: link_to(t("votes.signup"), new_user_registration_path),
my_heading: link_to(investment.heading.name,
budget_investments_path(budget_id: investment.budget_id,
- heading_id: investment.heading_id))
- ).html_safe %>
+ heading_id: investment.heading_id)),
+ change_ballot: link_to(t("budgets.ballots.reasons_for_not_balloting.change_ballot"),
+ budget_ballot_path(@budget))).html_safe %>
diff --git a/app/views/budgets/investments/_header.html.erb b/app/views/budgets/investments/_header.html.erb
index 2ed01d989..42e133d5a 100644
--- a/app/views/budgets/investments/_header.html.erb
+++ b/app/views/budgets/investments/_header.html.erb
@@ -42,6 +42,12 @@
@assigned_heading.name,
budget_investments_path(@budget, heading_id: @assigned_heading.try(:id)))
) %>
+
+
+ <%= t("budgets.investments.header.change_ballot",
+ check_ballot: link_to(t("budgets.investments.header.check_ballot_link"),
+ budget_ballot_path(@budget))).html_safe %>
+
<% end %>
diff --git a/app/views/budgets/investments/_investment_show.html.erb b/app/views/budgets/investments/_investment_show.html.erb
index f9a371585..a6a4fe8cb 100644
--- a/app/views/budgets/investments/_investment_show.html.erb
+++ b/app/views/budgets/investments/_investment_show.html.erb
@@ -2,7 +2,7 @@
- <%= back_link_to budget_investments_path(investment.budget) %>
+ <%= back_link_to budget_investments_path(investment.budget, heading_id: investment.heading) %>
<%= investment.title %>
diff --git a/app/views/budgets/investments/_sidebar.html.erb b/app/views/budgets/investments/_sidebar.html.erb
index 06d3b9d81..4ae9104d5 100644
--- a/app/views/budgets/investments/_sidebar.html.erb
+++ b/app/views/budgets/investments/_sidebar.html.erb
@@ -41,11 +41,19 @@
<% elsif @assigned_heading.present? %>
-
<%= t("budgets.investments.index.sidebar.different_heading_assigned_html",
+
+ <%= t("budgets.investments.index.sidebar.different_heading_assigned_html",
heading_link: link_to(
@assigned_heading.name,
budget_investments_path(@budget, heading_id: @assigned_heading.try(:id)))
- ) %>
+ ) %>
+
+
+ <%= t("budgets.investments.index.sidebar.change_ballot",
+ check_ballot: link_to(t("budgets.investments.index.sidebar.check_ballot_link"),
+ budget_ballot_path(@budget))).html_safe %>
+
+
<% else %>
<%= t("budgets.investments.index.sidebar.zero") %>
<% end %>
diff --git a/app/views/layouts/admin.html.erb b/app/views/layouts/admin.html.erb
index 2352c5181..c618de6c4 100644
--- a/app/views/layouts/admin.html.erb
+++ b/app/views/layouts/admin.html.erb
@@ -31,7 +31,7 @@
<%= render 'layouts/admin_header' %>
-
+
<%= t("admin.menu.admin") %>
diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml
index 04efd6464..49cb23ff0 100755
--- a/config/locales/admin.en.yml
+++ b/config/locales/admin.en.yml
@@ -340,8 +340,10 @@ en:
hidden_debates: Hidden debates
hidden_proposals: Hidden proposals
hidden_users: Hidden users
+ administrators: Administrators
managers: Managers
moderators: Moderators
+ newsletter: Newsletters
valuators: Valuators
poll_officers: Poll officers
polls: Polls
@@ -364,6 +366,17 @@ en:
title_banners: Banners
title_site_customization: Site customization
legislation: Collaborative Legislation
+ administrators:
+ index:
+ title: Administrators
+ administrator:
+ add: Add
+ delete: Delete
+ restricted_removal: "Sorry, you can't remove yourself from the administrators"
+ search:
+ email_placeholder: Search user by email
+ search: Search
+ user_not_found: User not found
moderators:
index:
title: Moderators
@@ -374,6 +387,10 @@ en:
email_placeholder: Search user by email
search: Search
user_not_found: User not found
+ newsletters:
+ index:
+ title: Newsletters
+ button: Download zip with users list
valuators:
index:
title: Valuators
@@ -629,7 +646,7 @@ en:
placeholder: Search spending proposals by title or description
user_search:
button: Search
- placeholder: Search user by name or email'
+ placeholder: Search user by name or email
search_results: "Search results"
no_search_results: "No results found."
spending_proposals:
diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml
index bf2300d36..64e899312 100644
--- a/config/locales/admin.es.yml
+++ b/config/locales/admin.es.yml
@@ -318,6 +318,17 @@ es:
comments_count: Número de comentarios
question_option_fields:
remove_option: Eliminar
+ administrators:
+ index:
+ title: Administradores
+ administrator:
+ add: Añadir como Administrador
+ delete: Borrar
+ restricted_removal: "Lo sentimos, no puedes eliminarte a ti mismo de la lista"
+ search:
+ email_placeholder: Buscar usuario por email
+ search: Buscar
+ user_not_found: Usuario no encontrado
managers:
index:
title: Gestores
@@ -341,7 +352,9 @@ es:
hidden_proposals: Propuestas ocultas
hidden_users: Usuarios bloqueados
managers: Gestores
+ administrators: Administradores
moderators: Moderadores
+ newsletter: Envío de Newsletters
valuators: Evaluadores
poll_officers: Presidentes de mesa
polls: Votaciones
@@ -374,6 +387,10 @@ es:
email_placeholder: Buscar usuario por email
search: Buscar
user_not_found: Usuario no encontrado
+ newsletters:
+ index:
+ title: Envío de newsletters
+ button: Descargar zip con lista de usuarios
valuators:
index:
title: Evaluadores
diff --git a/config/locales/budgets.en.yml b/config/locales/budgets.en.yml
index 570f9da35..6fba08534 100644
--- a/config/locales/budgets.en.yml
+++ b/config/locales/budgets.en.yml
@@ -17,9 +17,10 @@ en:
not_verified: Only verified users can vote on investments; %{verify_account}.
organization: Organizations are not permitted to vote
not_selected: Unselected investment projects can not be supported
- not_enough_money: "Price is higher than the available amount left."
+ not_enough_money_html: "You have already assigned the available budget.
Remember you can %{change_ballot} at any time "
no_ballots_allowed: Selecting phase is closed
different_heading_assigned: You have already voted a different heading
+ change_ballot: change your votes
groups:
show:
title: Select an option
@@ -64,6 +65,8 @@ en:
voted_info: You can %{link} at any time until the close of this phase. No need to spend all the money available.
voted_info_link: change your vote
different_heading_assigned_html: "You have active votes in another heading: %{heading_link}"
+ change_ballot: "If your change your mind you can remove your votes in %{check_ballot} and start again."
+ check_ballot_link: "check my ballot"
zero: You have not voted any investment project in this group.
verified_only: "To create a new budget investment %{verify}."
verify_account: "verify your account"
@@ -106,6 +109,8 @@ en:
header:
check_ballot: Check my ballot
different_heading_assigned_html: "You have active votes in another heading: %{heading_link}"
+ change_ballot: "If your change your mind you can remove your votes in %{check_ballot} and start again."
+ check_ballot_link: "check my ballot"
progress_bar:
available: "Available: "
show:
diff --git a/config/locales/budgets.es.yml b/config/locales/budgets.es.yml
index a8e7fa5fa..1cb308472 100644
--- a/config/locales/budgets.es.yml
+++ b/config/locales/budgets.es.yml
@@ -17,9 +17,10 @@ es:
not_verified: Las propuestas de inversión sólo pueden ser apoyadas por usuarios verificados, %{verify_account}.
organization: Las organizaciones no pueden votar.
not_selected: No se pueden votar propuestas inviables.
- not_enough_money: No hay fondos suficientes.
+ not_enough_money_html: "Ya has asignado el presupuesto disponible.
Recuerda que puedes %{change_ballot} en cualquier momento "
no_ballots_allowed: El periodo de votación está cerrado.
different_heading_assigned: Ya votaste en una sección distinta del presupuesto.
+ change_ballot: cambiar tus votos
groups:
show:
title: Selecciona una opción
@@ -64,6 +65,8 @@ es:
voted_info: Puedes %{link} en cualquier momento hasta el cierre de esta fase. No hace falta que gastes todo el dinero disponible.
voted_info_link: cambiar tus votos
different_heading_assigned_html: "Ya apoyaste propuestas de otra sección del presupuesto: %{heading_link}"
+ change_ballot: "Si cambias de opinión puedes borrar tus votos en %{check_ballot} y volver a empezar."
+ check_ballot_link: "revisar mis votos"
zero: "Todavía no has votado ninguna propuesta de inversión en este ámbito del presupuesto."
verified_only: "Para crear una nueva propuesta de inversión %{verify}."
verify_account: "verifica tu cuenta"
@@ -106,6 +109,8 @@ es:
header:
check_ballot: Revisar mis votos
different_heading_assigned_html: "Ya apoyaste propuestas de otra sección del presupuesto: %{heading_link}"
+ change_ballot: "Si cambias de opinión puedes borrar tus votos en %{check_ballot} y volver a empezar."
+ check_ballot_link: "revisar mis votos"
progress_bar:
available: "Disponible: "
show:
diff --git a/config/routes.rb b/config/routes.rb
index a7d3affdd..e5480a136 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -233,6 +233,10 @@ Rails.application.routes.draw do
get :search, on: :collection
end
+ resources :administrators, only: [:index, :create, :destroy] do
+ get :search, on: :collection
+ end
+
scope module: :poll do
resources :polls do
get :search_questions, on: :member
@@ -265,6 +269,9 @@ Rails.application.routes.draw do
end
resource :activity, controller: :activity, only: :show
+ resources :newsletters, only: :index do
+ get :users, on: :collection
+ end
resource :stats, only: :show do
get :proposal_notifications, on: :collection
get :direct_messages, on: :collection
diff --git a/db/dev_seeds.rb b/db/dev_seeds.rb
index 2753fe85f..a84f58219 100644
--- a/db/dev_seeds.rb
+++ b/db/dev_seeds.rb
@@ -408,7 +408,7 @@ tags = Faker::Lorem.words(10)
title: Faker::Lorem.sentence(3).truncate(60),
external_url: Faker::Internet.url,
description: "
#{Faker::Lorem.paragraphs.join('
')}
",
- created_at: rand((Time.now - 1.week) .. Time.now),
+ created_at: rand((Time.current - 1.week) .. Time.current),
feasibility: %w{undecided unfeasible feasible feasible feasible feasible}.sample,
unfeasibility_explanation: Faker::Lorem.paragraph,
valuation_finished: [false, true].sample,
@@ -437,7 +437,7 @@ budget = Budget.where(phase: "finished").last
title: Faker::Lorem.sentence(3).truncate(60),
external_url: Faker::Internet.url,
description: "
#{Faker::Lorem.paragraphs.join('
')}
",
- created_at: rand((Time.now - 1.week) .. Time.now),
+ created_at: rand((Time.current - 1.week) .. Time.current),
feasibility: "feasible",
valuation_finished: true,
selected: true,
diff --git a/doc/en/dev_test_setup_osx.md b/doc/en/dev_test_setup_osx.md
index 67845510f..b579ce4a6 100644
--- a/doc/en/dev_test_setup_osx.md
+++ b/doc/en/dev_test_setup_osx.md
@@ -98,6 +98,12 @@ brew install ghostscript
brew install phantomjs
```
+## Imagemagick
+
+```
+brew install imagemagick
+```
+
## Cloning the repository
Now that we have all the dependencies installed we can download the repository:
diff --git a/doc/es/dev_test_setup.md b/doc/es/dev_test_setup.md
index 30f5d12d3..cda2613e7 100644
--- a/doc/es/dev_test_setup.md
+++ b/doc/es/dev_test_setup.md
@@ -2,6 +2,8 @@
## Linux
+Consultar [aqui](dev_test_setup_linux.md)
+
## Mac OS X
Consultar [aquí](dev_test_setup_osx.md)
diff --git a/doc/es/dev_test_setup_linux.md b/doc/es/dev_test_setup_linux.md
new file mode 100644
index 000000000..170871913
--- /dev/null
+++ b/doc/es/dev_test_setup_linux.md
@@ -0,0 +1,146 @@
+# Configuración para los entornos de desarrollo y pruebas (GNU/Linux)
+
+## Git
+
+Git es mantenido oficialmente en Debian/Ubuntu:
+
+```
+sudo apt-get install git
+```
+
+## Ruby
+
+Las versiones de Ruby versions empaquetadas en repositorios oficiales no son aptas para trabajar con consul (al menos Debian 7 y 8), así que debemos instalar manualmente.
+
+El método recomendado es via rvm:
+
+(sólo la opción multiusuario instala todas las dependencias automáticamente, al usar 'sudo'.)
+
+###como usuario local:
+
+```
+curl -L https://get.rvm.io | bash -s stable
+```
+###para todos los usuarios del sistema:
+
+```
+curl -L https://get.rvm.io | sudo bash -s stable
+```
+
+añadismos nuestro usuario al grupo de rvm
+
+```
+sudo usermod -a -G rvm
+```
+
+y finalmente, añadimos el script rvm a nuestro bash (~/.bashrc) (este paso sólo es necesario si no puedes ejecutar el comando rvm)
+
+```
+[[ -s /usr/local/rvm/scripts/rvm ]] && source /usr/local/rvm/scripts/rvm
+```
+
+con todo esto, deberías poder instalar la versión de ruby con rvm, por ejemplo la 2.3.2:
+
+```
+sudo rvm install 2.3.2
+```
+
+## Bundler
+
+usando
+
+```
+gem install bundler
+```
+
+hay varios métodos alternativos [aquí](https://rvm.io/integration/bundler) que podrían ser mejores como:
+
+```
+gem install rubygems-bundler
+```
+
+## PostgreSQL (>=9.4)
+
+La versión 9.4 de PostgreSQL no es oficial en Debian 7 (wheezy), pero en Debian 8 parece ser mantenida oficialmente.
+
+Así que debemos añadir el respositorio oficial de postgresql a apt, por ejemplo creando el fichero */etc/apt/sources.list.d/pgdg.list* con:
+
+```
+deb http://apt.postgresql.org/pub/repos/apt/ wheezy-pgdg main
+```
+
+después deberás descargar la key e instalarla:
+
+```
+wget https://www.postgresql.org/media/keys/ACCC4CF8.asc
+apt-key add ACCC4CF8.asc
+```
+
+y finalmente instalar postgresql
+
+```
+apt-get update
+apt-get install postgresql-9.4
+```
+
+## Ghostscript
+
+```
+apt-get install ghostscript
+```
+
+## Clonar el repositorio
+
+Ahora que ya tenemos todas las dependencias instalado podemos bajarnos el proyecto:
+
+```
+git clone https://github.com/consul/consul.git
+cd consul
+bundle install
+cp config/database.yml.example config/database.yml
+cp config/secrets.yml.example config/secrets.yml
+```
+
+Ahora copia en `database.yml` el usuario y la contraseña que pusiste para *consul*. Cuando ya lo hayas hecho:
+
+```
+rake db:create
+rake db:setup
+rake db:dev_seed
+RAILS_ENV=test bin/rake db:setup
+```
+
+Para ejecutar los tests:
+
+```
+bundle exec rspec
+```
+
+Quizás necesites crear un rol de superusuario en postgresql, y completar en el fichero*/config/database.yml* los campos 'user:' y 'password:'.
+
+Además, parece que postgresql usa un socket unix por defecto para las comunicaciones en local. Si te encuentras este problema creando la base de datos, cambia en */config/database.yml* la linea:
+
+```
+host: localhost
+```
+
+por:
+
+```
+host: /var/run/postgresql
+```
+
+Tras esto en el terminal ejecutaremos:
+
+```
+rake db:create
+rake db:setup
+rake db:dev_seed
+RAILS_ENV=test bin/rake db:setup
+```
+
+Y por último para comprobar que todo esta bien, lanza los tests:
+
+```
+bundle exec rspec
+```
diff --git a/doc/es/dev_test_setup_osx.md b/doc/es/dev_test_setup_osx.md
index 01ad29a2b..5fb251a0c 100644
--- a/doc/es/dev_test_setup_osx.md
+++ b/doc/es/dev_test_setup_osx.md
@@ -100,6 +100,12 @@ brew install ghostscript
brew install phantomjs
```
+## Imagemagick
+
+```
+brew install imagemagick
+```
+
## Clonar el repositorio
Ahora que ya tenemos todas las dependencias instalado podemos bajarnos el proyecto:
diff --git a/lib/age.rb b/lib/age.rb
index c6ae6fe18..f0ca9abe0 100644
--- a/lib/age.rb
+++ b/lib/age.rb
@@ -1,5 +1,5 @@
module Age
- def self.in_years(dob, now = Time.now.utc.to_date)
+ def self.in_years(dob, now = Time.current.to_date)
return nil unless dob.present?
# reference: http://stackoverflow.com/questions/819263/get-persons-age-in-ruby#comment21200772_819263
now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
diff --git a/lib/newsletter_zip.rb b/lib/newsletter_zip.rb
new file mode 100644
index 000000000..dead7cf82
--- /dev/null
+++ b/lib/newsletter_zip.rb
@@ -0,0 +1,25 @@
+require 'zip'
+class NewsletterZip
+ attr_accessor :filename
+
+ def initialize(filename)
+ @filename = filename
+ end
+
+ def emails
+ User.newsletter.pluck(:email).join("\n")
+ end
+
+ def path
+ Rails.root + "/tmp/#{filename}.zip"
+ end
+
+ def create
+ Zip::File.open(path, Zip::File::CREATE) do |zipfile|
+ zipfile.get_output_stream("#{filename}.txt") do |file|
+ file.write emails
+ end
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/spec/factories.rb b/spec/factories.rb
index 8893879dd..af1120089 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -388,7 +388,7 @@ FactoryGirl.define do
end
factory :poll do
- sequence(:name) { |n| "Poll #{n}" }
+ sequence(:name) { |n| "Poll #{SecureRandom.hex}" }
starts_at { 1.month.ago }
ends_at { 1.month.from_now }
diff --git a/spec/features/admin/administrators_spec.rb b/spec/features/admin/administrators_spec.rb
new file mode 100644
index 000000000..bef57b75d
--- /dev/null
+++ b/spec/features/admin/administrators_spec.rb
@@ -0,0 +1,45 @@
+require 'rails_helper'
+
+feature 'Admin administrators' do
+ background do
+ @admin = create(:administrator)
+ @user = create(:user, username: 'Jose Luis Balbin')
+ @administrator = create(:administrator)
+ login_as(@admin.user)
+ visit admin_administrators_path
+ end
+
+ scenario 'Index' do
+ expect(page).to have_content @administrator.name
+ expect(page).to have_content @administrator.email
+ expect(page).to_not have_content @user.name
+ end
+
+ scenario 'Create Administrator', :js do
+ fill_in 'email', with: @user.email
+ click_button 'Search'
+
+ expect(page).to have_content @user.name
+ click_link 'Add'
+ within("#administrators") do
+ expect(page).to have_content @user.name
+ end
+ end
+
+ scenario 'Delete Administrator' do
+ find(:xpath, "//tr[contains(.,'#{@administrator.name}')]/td/a", text: 'Delete').click
+
+ within("#administrators") do
+ expect(page).to_not have_content @administrator.name
+ end
+ end
+
+ scenario 'Delete Administrator when its the current user' do
+ find(:xpath, "//tr[contains(.,'#{@admin.name}')]/td/a", text: 'Delete').click
+
+ within("#error") do
+ expect(page).to have_content I18n.t("admin.administrators.administrator.restricted_removal")
+ end
+ end
+end
+
diff --git a/spec/features/admin/newsletters_spec.rb b/spec/features/admin/newsletters_spec.rb
new file mode 100644
index 000000000..fccb63dc8
--- /dev/null
+++ b/spec/features/admin/newsletters_spec.rb
@@ -0,0 +1,26 @@
+require 'rails_helper'
+
+feature 'Admin newsletters emails' do
+
+ let(:download_button_text) { 'Download zip with users list' }
+
+ background do
+ @admin = create(:administrator)
+ @newsletter_user = create(:user, newsletter: true)
+ @non_newsletter_user = create(:user, newsletter: false)
+ login_as(@admin.user)
+ visit admin_newsletters_path
+ end
+
+ scenario 'Index' do
+ expect(page).to have_content download_button_text
+ end
+
+ scenario 'Download newsletter email zip' do
+ click_link download_button_text
+ downloaded_file_content = Zip::InputStream.open(StringIO.new(page.body)).get_next_entry.get_input_stream {|is| is.read }
+ expect(downloaded_file_content).to include(@admin.user.email, @newsletter_user.email)
+ expect(downloaded_file_content).not_to include(@non_newsletter_user.email)
+ end
+end
+
diff --git a/spec/features/budgets/ballots_spec.rb b/spec/features/budgets/ballots_spec.rb
index b8f40acf0..35e74a9a6 100644
--- a/spec/features/budgets/ballots_spec.rb
+++ b/spec/features/budgets/ballots_spec.rb
@@ -536,7 +536,7 @@ feature 'Ballots' do
within("#budget_investment_#{bi2.id}") do
find("div.ballot").hover
- expect(page).to have_content('Price is higher than the available amount left')
+ expect(page).to have_content('You have already assigned the available budget')
expect(page).to have_selector('.in-favor a', visible: false)
end
end
@@ -550,7 +550,7 @@ feature 'Ballots' do
within("#budget_investment_#{bi1.id}") do
find("div.ballot").hover
- expect(page).to_not have_content('Price is higher than the available amount left')
+ expect(page).to_not have_content('You have already assigned the available budget')
expect(page).to have_selector('.in-favor a', visible: true)
end
@@ -558,7 +558,7 @@ feature 'Ballots' do
within("#budget_investment_#{bi2.id}") do
find("div.ballot").trigger("mouseover")
- expect(page).to have_content('Price is higher than the available amount left')
+ expect(page).to have_content('You have already assigned the available budget')
expect(page).to have_selector('.in-favor a', visible: false)
end
@@ -576,7 +576,7 @@ feature 'Ballots' do
within("#budget_investment_#{bi2.id}") do
find("div.ballot").hover
- expect(page).to have_content('Price is higher than the available amount left')
+ expect(page).to have_content('You have already assigned the available budget')
expect(page).to have_selector('.in-favor a', visible: false)
end
@@ -587,7 +587,7 @@ feature 'Ballots' do
within("#budget_investment_#{bi2.id}") do
find("div.ballot").hover
- expect(page).to_not have_content('Price is higher than the available amount left')
+ expect(page).to_not have_content('You have already assigned the available budget')
expect(page).to have_selector('.in-favor a', visible: true)
end
end
@@ -604,7 +604,7 @@ feature 'Ballots' do
within("#budget_investment_#{bi2.id}") do
find("div.ballot").hover
- expect(page).to have_content('Price is higher than the available amount left')
+ expect(page).to have_content('You have already assigned the available budget')
expect(page).to have_selector('.in-favor a', visible: false)
end
@@ -616,7 +616,7 @@ feature 'Ballots' do
within("#budget_investment_#{bi2.id}") do
find("div.ballot").hover
- expect(page).to_not have_content('Price is higher than the available amount left')
+ expect(page).to_not have_content('You have already assigned the available budget')
expect(page).to have_selector('.in-favor a', visible: true)
end
end
diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb
index a0f65a012..ef84cc6fc 100644
--- a/spec/features/budgets/investments_spec.rb
+++ b/spec/features/budgets/investments_spec.rb
@@ -278,6 +278,13 @@ feature 'Budget Investments' do
end
end
+ scenario "Show back link contains heading id" do
+ investment = create(:budget_investment, heading: heading)
+ visit budget_investment_path(budget, investment)
+
+ expect(page).to have_link "Go back", href: budget_investments_path(budget, heading_id: investment.heading)
+ end
+
context "Show (feasible budget investment)" do
let(:investment) { create(:budget_investment,
:feasible,
diff --git a/spec/features/budgets/votes_spec.rb b/spec/features/budgets/votes_spec.rb
index 497046891..95f040bb3 100644
--- a/spec/features/budgets/votes_spec.rb
+++ b/spec/features/budgets/votes_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
feature 'Votes' do
background do
- @manuela = create(:user, verified_at: Time.now)
+ @manuela = create(:user, verified_at: Time.current)
end
feature 'Investments' do
diff --git a/spec/models/budget/investment_spec.rb b/spec/models/budget/investment_spec.rb
index b811e8061..2290abba9 100644
--- a/spec/models/budget/investment_spec.rb
+++ b/spec/models/budget/investment_spec.rb
@@ -712,7 +712,7 @@ describe Budget::Investment do
ballot = create(:budget_ballot, user: user, budget: budget)
ballot.investments << inv1
- expect(inv2.reason_for_not_being_ballotable_by(user, ballot)).to eq(:not_enough_money)
+ expect(inv2.reason_for_not_being_ballotable_by(user, ballot)).to eq(:not_enough_money_html)
end
end
diff --git a/spec/models/direct_message_spec.rb b/spec/models/direct_message_spec.rb
index e982f9e56..05c3f75cd 100644
--- a/spec/models/direct_message_spec.rb
+++ b/spec/models/direct_message_spec.rb
@@ -65,9 +65,9 @@ describe DirectMessage do
describe "today" do
it "should return direct messages created today" do
- direct_message1 = create(:direct_message, created_at: Time.zone.now.beginning_of_day + 3.hours)
- direct_message2 = create(:direct_message, created_at: Time.zone.now)
- direct_message3 = create(:direct_message, created_at: Time.zone.now.end_of_day)
+ direct_message1 = create(:direct_message, created_at: Time.current.beginning_of_day + 3.hours)
+ direct_message2 = create(:direct_message, created_at: Time.current)
+ direct_message3 = create(:direct_message, created_at: Time.current.end_of_day)
expect(DirectMessage.today.count).to eq 3
end
@@ -82,4 +82,4 @@ describe DirectMessage do
end
-end
\ No newline at end of file
+end
diff --git a/spec/models/poll/recount_spec.rb b/spec/models/poll/recount_spec.rb
index fb2c80704..2469354c2 100644
--- a/spec/models/poll/recount_spec.rb
+++ b/spec/models/poll/recount_spec.rb
@@ -23,18 +23,21 @@ describe :recount do
expect(recount.count_log).to eq("")
recount.count = 33
- recount.officer_assignment = create(:poll_officer_assignment, id: 11)
+ poll_officer_assignment_1 = create(:poll_officer_assignment)
+ recount.officer_assignment = poll_officer_assignment_1
recount.save
recount.count = 32
- recount.officer_assignment = create(:poll_officer_assignment, id: 12)
+ poll_officer_assignment_2 = create(:poll_officer_assignment)
+ recount.officer_assignment = poll_officer_assignment_2
recount.save
recount.count = 34
- recount.officer_assignment = create(:poll_officer_assignment, id: 13)
+ poll_officer_assignment_3 = create(:poll_officer_assignment)
+ recount.officer_assignment = poll_officer_assignment_3
recount.save
- expect(recount.officer_assignment_id_log).to eq(":11:12")
+ expect(recount.officer_assignment_id_log).to eq(":#{poll_officer_assignment_1.id}:#{poll_officer_assignment_2.id}")
end
-end
\ No newline at end of file
+end