Merge branch 'master' into user-recomendations

This commit is contained in:
BertoCQ
2017-09-19 18:56:12 +02:00
committed by GitHub
46 changed files with 221 additions and 223 deletions

3
.gitignore vendored
View File

@@ -32,6 +32,3 @@
public/sitemap.xml public/sitemap.xml
public/system/ public/system/
#Netbeans projects files
/nbproject

View File

@@ -8,6 +8,7 @@ before_script:
- "for i in config/*.example; do cp \"$i\" \"${i/.example}\"; done" - "for i in config/*.example; do cp \"$i\" \"${i/.example}\"; done"
- bundle exec rake db:setup - bundle exec rake db:setup
script: script:
- "bundle exec rake assets:precompile RAILS_ENV=test"
- "bundle exec rake knapsack:rspec" - "bundle exec rake knapsack:rspec"
env: env:
global: global:

View File

@@ -24,6 +24,7 @@ gem 'graphql', '~> 1.6.3'
gem 'groupdate', '~> 3.2.0' gem 'groupdate', '~> 3.2.0'
gem 'initialjs-rails', '~> 0.2.0.5' gem 'initialjs-rails', '~> 0.2.0.5'
gem 'invisible_captcha', '~> 0.9.2' gem 'invisible_captcha', '~> 0.9.2'
gem 'jquery-fileupload-rails'
gem 'jquery-rails', '~> 4.3.1' gem 'jquery-rails', '~> 4.3.1'
gem 'jquery-ui-rails', '~> 6.0.1' gem 'jquery-ui-rails', '~> 6.0.1'
gem 'kaminari', '~> 1.0.1' gem 'kaminari', '~> 1.0.1'
@@ -33,7 +34,6 @@ gem 'omniauth-facebook', '~> 4.0.0'
gem 'omniauth-google-oauth2', '~> 0.4.0' gem 'omniauth-google-oauth2', '~> 0.4.0'
gem 'omniauth-twitter', '~> 1.4.0' gem 'omniauth-twitter', '~> 1.4.0'
gem 'paperclip', '~> 5.1.0' gem 'paperclip', '~> 5.1.0'
gem 'jquery-fileupload-rails'
gem 'paranoia', '~> 2.3.1' gem 'paranoia', '~> 2.3.1'
gem 'pg', '~> 0.21.0' gem 'pg', '~> 0.21.0'
gem 'pg_search', '~> 2.0.1' gem 'pg_search', '~> 2.0.1'

View File

@@ -32,22 +32,30 @@
padding: 0; padding: 0;
z-index: 4 !important; z-index: 4 !important;
.ui-datepicker-prev {
left: 12px;
}
.ui-datepicker-next {
right: 12px;
}
.ui-datepicker-prev, .ui-datepicker-prev,
.ui-datepicker-next { .ui-datepicker-next {
color: #fff; color: #fff;
cursor: pointer; cursor: pointer;
font-family: "icons" !important;
font-size: rem-calc(24);
font-weight: normal; font-weight: normal;
font-size: $small-font-size; height: rem-calc(30);
line-height: $line-height; line-height: $line-height;
top: 0; position: absolute;
top: 4px;
width: rem-calc(30);
&:hover {
text-decoration: none;
}
}
.ui-datepicker-prev::after {
content: '\62';
}
.ui-datepicker-next::after {
content: '\63';
} }
table { table {

View File

@@ -395,8 +395,8 @@
} }
} }
&.tags, .tags,
&.geozone { .geozone {
li { li {
margin-bottom: 0; margin-bottom: 0;
@@ -478,6 +478,7 @@
.tags { .tags {
display: block; display: block;
margin-bottom: 0;
a { a {
margin-right: rem-calc(6); margin-right: rem-calc(6);
@@ -610,6 +611,14 @@
} }
} }
.show-actions-menu {
[class^="icon-"] {
display: inline-block;
vertical-align: middle;
}
}
// 04. List participation // 04. List participation
// ---------------------- // ----------------------

View File

@@ -1,5 +1,5 @@
class Admin::Poll::ShiftsController < Admin::BaseController class Admin::Poll::ShiftsController < Admin::BaseController
before_action :load_booth before_action :load_booth
before_action :load_polls before_action :load_polls
before_action :load_officer before_action :load_officer

View File

@@ -7,7 +7,7 @@ class CommunitiesController < ApplicationController
skip_authorization_check skip_authorization_check
def show def show
redirect_to root_path unless Setting['feature.community'].present? redirect_to root_path if Setting['feature.community'].blank?
end end
private private

View File

@@ -1,8 +1,8 @@
class DocumentsController < ApplicationController class DocumentsController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
before_filter :find_documentable, except: :destroy before_action :find_documentable, except: :destroy
before_filter :prepare_new_document, only: [:new, :new_nested] before_action :prepare_new_document, only: [:new, :new_nested]
before_filter :prepare_document_for_creation, only: :create before_action :prepare_document_for_creation, only: :create
load_and_authorize_resource except: :upload load_and_authorize_resource except: :upload
skip_authorization_check only: :upload skip_authorization_check only: :upload
@@ -48,6 +48,7 @@ class DocumentsController < ApplicationController
def destroy_upload def destroy_upload
@document = Document.new(cached_attachment: params[:path]) @document = Document.new(cached_attachment: params[:path])
@document.set_attachment_from_cached_attachment @document.set_attachment_from_cached_attachment
@document.cached_attachment = nil
@document.documentable = @documentable @document.documentable = @documentable
if @document.attachment.destroy if @document.attachment.destroy

View File

@@ -7,7 +7,7 @@ class Officing::PollsController < Officing::BaseController
def final def final
@polls = if current_user.poll_officer? @polls = if current_user.poll_officer?
current_user.poll_officer.final_days_assigned_polls.select {|poll| poll.ends_at > 1.week.ago && poll.expired?} current_user.poll_officer.final_days_assigned_polls.select {|poll| poll.ends_at > 2.week.ago && poll.expired?}
else else
[] []
end end

View File

@@ -78,7 +78,7 @@ class ProposalsController < ApplicationController
def proposal_params def proposal_params
params.require(:proposal).permit(:title, :question, :summary, :description, :external_url, :video_url, params.require(:proposal).permit(:title, :question, :summary, :description, :external_url, :video_url,
:responsible_name, :tag_list, :terms_of_service, :geozone_id, :responsible_name, :tag_list, :terms_of_service, :geozone_id,
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id] ) documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id])
end end
def retired_params def retired_params

View File

@@ -36,6 +36,10 @@ module AdminHelper
["banners"].include? controller_name ["banners"].include? controller_name
end end
def menu_customization?
["pages", "images", "content_blocks"].include? controller_name
end
def official_level_options def official_level_options
options = [["", 0]] options = [["", 0]]
(1..5).each do |i| (1..5).each do |i|

View File

@@ -12,7 +12,7 @@ module CommunitiesHelper
community.from_proposal? ? t("community.show.description.proposal") : t("community.show.description.investment") community.from_proposal? ? t("community.show.description.proposal") : t("community.show.description.investment")
end end
def is_author?(community, participant) def author?(community, participant)
if community.from_proposal? if community.from_proposal?
community.proposal.author_id == participant.id community.proposal.author_id == participant.id
else else

View File

@@ -9,7 +9,7 @@ module DocumentablesHelper
end end
def max_file_size(documentable) def max_file_size(documentable)
bytesToMeg(documentable.class.max_file_size) bytes_to_mega(documentable.class.max_file_size)
end end
def accepted_content_types(documentable) def accepted_content_types(documentable)
@@ -18,8 +18,8 @@ module DocumentablesHelper
def accepted_content_types_extensions(documentable_class) def accepted_content_types_extensions(documentable_class)
documentable_class.accepted_content_types documentable_class.accepted_content_types
.collect{ |content_type| ".#{content_type.split("/").last}" } .collect{ |content_type| ".#{content_type.split('/').last}" }
.join(",") .join(",")
end end
def humanized_accepted_content_types(documentable) def humanized_accepted_content_types(documentable)
@@ -38,4 +38,4 @@ module DocumentablesHelper
documentable.documents.count >= documentable.class.max_documents_allowed documentable.documents.count >= documentable.class.max_documents_allowed
end end
end end

View File

@@ -8,7 +8,7 @@ module DocumentsHelper
document.errors[:attachment].join(', ') if document.errors.key?(:attachment) document.errors[:attachment].join(', ') if document.errors.key?(:attachment)
end end
def bytesToMeg(bytes) def bytes_to_mega(bytes)
bytes / Numeric::MEGABYTE bytes / Numeric::MEGABYTE
end end
@@ -80,10 +80,10 @@ module DocumentsHelper
def document_direct_upload_url(document) def document_direct_upload_url(document)
upload_documents_url( upload_documents_url(
documentable_type: document.documentable_type, documentable_type: document.documentable_type,
documentable_id: document.documentable_id, documentable_id: document.documentable_id,
format: :js format: :js
) )
end end
end end

View File

@@ -40,4 +40,17 @@ module ProposalsHelper
end end
end end
def can_create_document?(document, proposal)
can?(:create, document) && proposal.documents.size < Proposal.max_documents_allowed
end
def author_of_proposal?(proposal)
author_of?(proposal, current_user)
end
def current_editable?(proposal)
current_user && proposal.editable_by?(current_user)
end
end end

View File

@@ -11,7 +11,7 @@ class Community < ActiveRecord::Base
end end
def from_proposal? def from_proposal?
self.proposal.present? proposal.present?
end end
private private

View File

@@ -10,7 +10,7 @@ module Documentable
private private
def documentable(options= {}) def documentable(options = {})
@max_documents_allowed = options[:max_documents_allowed] @max_documents_allowed = options[:max_documents_allowed]
@max_file_size = options[:max_file_size] @max_file_size = options[:max_file_size]
@accepted_content_types = options[:accepted_content_types] @accepted_content_types = options[:accepted_content_types]

View File

@@ -40,7 +40,7 @@ class Document < ActiveRecord::Base
attachment.instance.prefix(attachment, style) attachment.instance.prefix(attachment, style)
end end
def prefix(attachment, style) def prefix(attachment, _style)
if !attachment.instance.persisted? if !attachment.instance.persisted?
"cached_attachments/user/#{attachment.instance.user_id}" "cached_attachments/user/#{attachment.instance.user_id}"
else else
@@ -75,7 +75,7 @@ class Document < ActiveRecord::Base
end end
def remove_cached_document def remove_cached_document
File.delete(cached_attachment) if File.exists?(cached_attachment) File.delete(cached_attachment) if File.exist?(cached_attachment)
end end
end end

View File

@@ -5,7 +5,7 @@ class Poll
has_many :shifts has_many :shifts
validates :name, presence: true, uniqueness: true validates :name, presence: true, uniqueness: true
def self.search(terms) def self.search(terms)
return Booth.none if terms.blank? return Booth.none if terms.blank?
Booth.where("name ILIKE ? OR location ILIKE ?", "%#{terms}%", "%#{terms}%") Booth.where("name ILIKE ? OR location ILIKE ?", "%#{terms}%", "%#{terms}%")

View File

@@ -20,6 +20,7 @@ class Poll::Question < ActiveRecord::Base
validates :title, presence: true validates :title, presence: true
validates :author, presence: true validates :author, presence: true
validates :poll_id, presence: true
validates :title, length: { minimum: 4 } validates :title, length: { minimum: 4 }
validates :description, length: { maximum: Poll::Question.description_max_length } validates :description, length: { maximum: Poll::Question.description_max_length }

View File

@@ -1,13 +1,13 @@
class Poll class Poll
class Shift < ActiveRecord::Base class Shift < ActiveRecord::Base
belongs_to :booth belongs_to :booth
belongs_to :officer belongs_to :officer
validates :booth_id, presence: true validates :booth_id, presence: true
validates :officer_id, presence: true validates :officer_id, presence: true
validates :date, presence: true validates :date, presence: true
validates :date, uniqueness: { scope: [:officer_id, :booth_id] } validates :date, uniqueness: { scope: [:officer_id, :booth_id] }
before_create :persist_data before_create :persist_data
after_create :create_officer_assignments after_create :create_officer_assignments
@@ -20,10 +20,10 @@ class Poll
end end
end end
def persist_data def persist_data
self.officer_name = officer.name self.officer_name = officer.name
self.officer_email = officer.email self.officer_email = officer.email
end end
end end
end end

View File

@@ -13,6 +13,6 @@ class Topic < ActiveRecord::Base
scope :sort_by_newest, -> { order(created_at: :desc) } scope :sort_by_newest, -> { order(created_at: :desc) }
scope :sort_by_oldest, -> { order(created_at: :asc) } scope :sort_by_oldest, -> { order(created_at: :asc) }
scope :sort_by_most_commented, -> { reorder(comments_count: :desc) } scope :sort_by_most_commented, -> { reorder(comments_count: :desc) }
end end

View File

@@ -57,13 +57,13 @@ class User < ActiveRecord::Base
scope :officials, -> { where("official_level > 0") } scope :officials, -> { where("official_level > 0") }
scope :newsletter, -> { where(newsletter: true) } scope :newsletter, -> { where(newsletter: true) }
scope :for_render, -> { includes(:organization) } scope :for_render, -> { includes(:organization) }
scope :by_document, -> (document_type, document_number) { where(document_type: document_type, document_number: document_number) } scope :by_document, ->(document_type, document_number) { where(document_type: document_type, document_number: document_number) }
scope :email_digest, -> { where(email_digest: true) } scope :email_digest, -> { where(email_digest: true) }
scope :active, -> { where(erased_at: nil) } scope :active, -> { where(erased_at: nil) }
scope :erased, -> { where.not(erased_at: nil) } scope :erased, -> { where.not(erased_at: nil) }
scope :public_for_api, -> { all } scope :public_for_api, -> { all }
scope :by_comments, -> (query, topics_ids) { joins(:comments).where(query, topics_ids).uniq } scope :by_comments, ->(query, topics_ids) { joins(:comments).where(query, topics_ids).uniq }
scope :by_authors, -> (author_ids) { where("users.id IN (?)", author_ids) } scope :by_authors, ->(author_ids) { where("users.id IN (?)", author_ids) }
before_validation :clean_document_number before_validation :clean_document_number

View File

@@ -60,12 +60,12 @@
<span class="icon-checkmark-circle"></span> <span class="icon-checkmark-circle"></span>
<strong><%= t("admin.menu.title_polls") %></strong> <strong><%= t("admin.menu.title_polls") %></strong>
</a> </a>
<ul id="polls_menu" <%= "class=is-active" if menu_polls? %>> <ul id="polls_menu" <%= "class=is-active" if menu_polls? && controller.class.parent == Admin::Poll::QuestionsController %>>
<li <%= "class=active" if ["polls", "officer_assignments", "booth_assignments", "recounts", "results"].include? controller_name %>> <li <%= "class=active" if ["polls", "officer_assignments", "booth_assignments", "recounts", "results"].include? controller_name %>>
<%= link_to t('admin.menu.polls'), admin_polls_path %> <%= link_to t('admin.menu.polls'), admin_polls_path %>
</li> </li>
<li <%= "class=active" if controller_name == "questions" %>> <li <%= "class=active" if controller_name == "questions" && controller.class.parent == Admin::Poll::QuestionsController %>>
<%= link_to t("admin.menu.poll_questions"), admin_questions_path %> <%= link_to t("admin.menu.poll_questions"), admin_questions_path %>
</li> </li>
@@ -73,13 +73,13 @@
<%= link_to t('admin.menu.poll_officers'), admin_officers_path %> <%= link_to t('admin.menu.poll_officers'), admin_officers_path %>
</li> </li>
<li <%= "class=active" if controller_name == "booths" && <li <%= "class=active" if controller_name == "booths" &&
action_name != "available" %>> action_name != "available" %>>
<%= link_to t('admin.menu.poll_booths'), admin_booths_path %> <%= link_to t('admin.menu.poll_booths'), admin_booths_path %>
</li> </li>
<li <%= "class=active" if controller_name == "shifts" || <li <%= "class=active" if controller_name == "shifts" ||
controller_name == "booths" && controller_name == "booths" &&
action_name == "available" %>> action_name == "available" %>>
<%= link_to t('admin.menu.poll_shifts'), available_admin_booths_path %> <%= link_to t('admin.menu.poll_shifts'), available_admin_booths_path %>
</li> </li>
@@ -158,7 +158,7 @@
<span class="icon-settings"></span> <span class="icon-settings"></span>
<strong><%= t("admin.menu.title_site_customization") %></strong> <strong><%= t("admin.menu.title_site_customization") %></strong>
</a> </a>
<ul <%= "class=is-active" if menu_profiles? %>> <ul <%= "class=is-active" if menu_customization? %>>
<li <%= "class=active" if controller_name == "pages" %>> <li <%= "class=active" if controller_name == "pages" %>>
<%= link_to t("admin.menu.site_customization.pages"), admin_site_customization_pages_path %> <%= link_to t("admin.menu.site_customization.pages"), admin_site_customization_pages_path %>
</li> </li>

View File

@@ -9,7 +9,7 @@
<%= link_to participant.name, user_path(participant)%> <%= link_to participant.name, user_path(participant)%>
</span> </span>
<% if is_author?(@community, participant) %> <% if author?(@community, participant) %>
&nbsp;&bull;&nbsp; &nbsp;&bull;&nbsp;
<span class="label round is-author"> <span class="label round is-author">
<%= t("comments.comment.author") %> <%= t("comments.comment.author") %>

View File

@@ -16,24 +16,6 @@
<div class="small-12 medium-9 column"> <div class="small-12 medium-9 column">
<%= back_link_to %> <%= back_link_to %>
<% if can?(:create, @document) && @proposal.documents.size < Proposal.max_documents_allowed %>
<%= link_to t("documents.upload_document"),
new_document_path(documentable_id: @proposal, documentable_type: @proposal.class.name, from: request.url),
class: 'button hollow float-right' %>
<% end %>
<% if author_of?(@proposal, current_user) %>
<%= link_to t("proposals.show.send_notification"),
new_proposal_notification_path(proposal_id: @proposal.id),
class: 'button hollow float-right' %>
<% end %>
<% if current_user && @proposal.editable_by?(current_user) %>
<%= link_to edit_proposal_path(@proposal), class: 'edit-proposal button hollow float-right' do %>
<%= t("proposals.show.edit_proposal_link") %>
<% end %>
<% end %>
<h1><%= @proposal.title %></h1> <h1><%= @proposal.title %></h1>
<% if @proposal.retired? %> <% if @proposal.retired? %>
<div data-alert class="callout alert margin-top proposal-retired"> <div data-alert class="callout alert margin-top proposal-retired">
@@ -122,6 +104,35 @@
</div> </div>
<aside class="small-12 medium-3 column"> <aside class="small-12 medium-3 column">
<% if can_create_document?(@document, @proposal) || author_of_proposal?(@proposal) || current_editable?(@proposal) %>
<div class="sidebar-divider"></div>
<h2><%= t("proposals.show.author") %></h2>
<div class="show-actions-menu">
<% if can_create_document?(@document, @proposal) %>
<%= link_to new_document_path(documentable_id: @proposal, documentable_type: @proposal.class.name, from: request.url),
class: 'button hollow expanded' do %>
<span class="icon-document"></span>
<%= t("documents.upload_document") %>
<% end %>
<% end %>
<% if author_of_proposal?(@proposal) %>
<%= link_to new_proposal_notification_path(proposal_id: @proposal.id),
class: 'button hollow expanded' do %>
<span class="icon-no-notification"></span>
<%= t("proposals.show.send_notification") %>
<% end %>
<% end %>
<% if current_editable?(@proposal) %>
<%= link_to edit_proposal_path(@proposal), class: 'edit-proposal button hollow expanded' do %>
<span class="icon-edit"></span>
<%= t("proposals.show.edit_proposal_link") %>
<% end %>
<% end %>
</div>
<% end %>
<div class="sidebar-divider"></div> <div class="sidebar-divider"></div>
<h2><%= t("votes.supports") %></h2> <h2><%= t("votes.supports") %></h2>
<div id="<%= dom_id(@proposal) %>_votes"> <div id="<%= dom_id(@proposal) %>_votes">

View File

@@ -21,7 +21,7 @@ data:
# - config/locales/**/*.%{locale}.yml # - config/locales/**/*.%{locale}.yml
## Another gem (replace %#= with %=): ## Another gem (replace %#= with %=):
# - "<%#= %x[bundle show vagrant].chomp %>/templates/locales/%{locale}.yml" # - "<%#= %x[bundle show vagrant].chomp %>/templates/locales/%{locale}.yml"
- config/locales/custom/%{locale}/custom.yml - config/locales/custom/%{locale}/*.yml
- config/locales/%{locale}/general.yml - config/locales/%{locale}/general.yml
- config/locales/%{locale}/activerecord.yml - config/locales/%{locale}/activerecord.yml
- config/locales/%{locale}/activemodel.yml - config/locales/%{locale}/activemodel.yml

View File

@@ -441,6 +441,7 @@ en:
embed_video_title: "Video on %{proposal}" embed_video_title: "Video on %{proposal}"
title_external_url: "Additional documentation" title_external_url: "Additional documentation"
title_video_url: "External video" title_video_url: "External video"
author: Author
update: update:
form: form:
submit_button: Save changes submit_button: Save changes

View File

@@ -441,6 +441,7 @@ es:
embed_video_title: "Vídeo en %{proposal}" embed_video_title: "Vídeo en %{proposal}"
title_external_url: "Documentación adicional" title_external_url: "Documentación adicional"
title_video_url: "Vídeo externo" title_video_url: "Vídeo externo"
author: Autor
update: update:
form: form:
submit_button: Guardar cambios submit_button: Guardar cambios

View File

@@ -390,13 +390,10 @@ feature 'Admin budget investments' do
budget_investment2 = create(:budget_investment) budget_investment2 = create(:budget_investment)
visit admin_budget_budget_investment_path(budget_investment2.budget, budget_investment2) visit edit_admin_budget_budget_investment_path(budget_investment2.budget, budget_investment2)
click_link 'Edit classification'
find('.js-add-tag-link', text: 'Education').click find('.js-add-tag-link', text: 'Education').click
fill_in 'budget_investment_title', with: 'Updated title'
click_button 'Update' click_button 'Update'
expect(page).to have_content 'Investment project updated succesfully.' expect(page).to have_content 'Investment project updated succesfully.'

View File

@@ -9,8 +9,15 @@ feature 'Admin legislation questions' do
context "Feature flag" do context "Feature flag" do
scenario 'Disabled with a feature flag' do background do
Setting['feature.legislation'] = nil Setting['feature.legislation'] = nil
end
after do
Setting['feature.legislation'] = true
end
scenario 'Disabled with a feature flag' do
process = create(:legislation_process) process = create(:legislation_process)
expect{ visit admin_legislation_process_questions_path(process) }.to raise_exception(FeatureFlags::FeatureDisabled) expect{ visit admin_legislation_process_questions_path(process) }.to raise_exception(FeatureFlags::FeatureDisabled)
end end

View File

@@ -44,13 +44,13 @@ feature 'Admin booths' do
current_poll = create(:poll, :current) current_poll = create(:poll, :current)
incoming_poll = create(:poll, :incoming) incoming_poll = create(:poll, :incoming)
expired_poll = create(:poll, :expired) expired_poll = create(:poll, :expired)
create(:poll_booth_assignment, poll: current_poll, booth: booth_for_current_poll) create(:poll_booth_assignment, poll: current_poll, booth: booth_for_current_poll)
create(:poll_booth_assignment, poll: incoming_poll, booth: booth_for_incoming_poll) create(:poll_booth_assignment, poll: incoming_poll, booth: booth_for_incoming_poll)
create(:poll_booth_assignment, poll: expired_poll, booth: booth_for_expired_poll) create(:poll_booth_assignment, poll: expired_poll, booth: booth_for_expired_poll)
visit admin_root_path visit admin_root_path
within('#side_menu') do within('#side_menu') do
click_link "Manage shifts" click_link "Manage shifts"
end end

View File

@@ -183,7 +183,7 @@ feature 'Admin polls' do
scenario 'Add question to poll', :js do scenario 'Add question to poll', :js do
poll = create(:poll) poll = create(:poll)
question = create(:poll_question, poll: nil, title: 'Should we rebuild the city?') question = create(:poll_question, title: 'Should we rebuild the city?')
visit admin_poll_path(poll) visit admin_poll_path(poll)

View File

@@ -8,25 +8,25 @@ feature 'Admin shifts' do
end end
scenario "Show" do scenario "Show" do
poll = create(:poll) poll = create(:poll)
officer = create(:poll_officer) officer = create(:poll_officer)
booth1 = create(:poll_booth) booth1 = create(:poll_booth)
booth2 = create(:poll_booth) booth2 = create(:poll_booth)
shift1 = create(:poll_shift, officer: officer, booth: booth1, date: Date.today) shift1 = create(:poll_shift, officer: officer, booth: booth1, date: Time.zone.today)
shift2 = create(:poll_shift, officer: officer, booth: booth2, date: Date.tomorrow) shift2 = create(:poll_shift, officer: officer, booth: booth2, date: Time.zone.tomorrow)
visit new_admin_booth_shift_path(booth1) visit new_admin_booth_shift_path(booth1)
expect(page).to have_css(".shift", count: 1) expect(page).to have_css(".shift", count: 1)
expect(page).to have_content I18n.l(Date.today, format: :long) expect(page).to have_content I18n.l(Time.zone.today, format: :long)
expect(page).to have_content officer.name expect(page).to have_content officer.name
visit new_admin_booth_shift_path(booth2) visit new_admin_booth_shift_path(booth2)
expect(page).to have_css(".shift", count: 1) expect(page).to have_css(".shift", count: 1)
expect(page).to have_content I18n.l(Date.tomorrow, format: :long) expect(page).to have_content I18n.l(Time.zone.tomorrow, format: :long)
expect(page).to have_content officer.name expect(page).to have_content officer.name
end end
@@ -36,7 +36,7 @@ feature 'Admin shifts' do
officer = create(:poll_officer) officer = create(:poll_officer)
visit admin_booths_path visit admin_booths_path
within("#booth_#{booth.id}") do within("#booth_#{booth.id}") do
click_link "Manage shifts" click_link "Manage shifts"
end end
@@ -47,7 +47,7 @@ feature 'Admin shifts' do
select I18n.l(poll.starts_at.to_date, format: :long), from: 'shift_date' select I18n.l(poll.starts_at.to_date, format: :long), from: 'shift_date'
click_button "Add shift" click_button "Add shift"
expect(page).to have_content "Shift added" expect(page).to have_content "Shift added"
within("#shifts") do within("#shifts") do
@@ -63,7 +63,7 @@ feature 'Admin shifts' do
officer = create(:poll_officer) officer = create(:poll_officer)
visit admin_booths_path visit admin_booths_path
within("#booth_#{booth.id}") do within("#booth_#{booth.id}") do
click_link "Manage shifts" click_link "Manage shifts"
end end
@@ -84,7 +84,7 @@ feature 'Admin shifts' do
shift = create(:poll_shift, officer: officer, booth: booth) shift = create(:poll_shift, officer: officer, booth: booth)
visit admin_booths_path visit admin_booths_path
within("#booth_#{booth.id}") do within("#booth_#{booth.id}") do
click_link "Manage shifts" click_link "Manage shifts"
end end

View File

@@ -341,7 +341,7 @@ feature 'Budget Investments' do
scenario 'Can not access the community' do scenario 'Can not access the community' do
Setting['feature.community'] = false Setting['feature.community'] = false
investment = create(:budget_investment, heading: heading) investment = create(:budget_investment, heading: heading)
visit budget_investment_path(budget_id: budget.id, id: investment.id) visit budget_investment_path(budget_id: budget.id, id: investment.id)
expect(page).not_to have_content "Access the community" expect(page).not_to have_content "Access the community"

View File

@@ -33,7 +33,7 @@ feature 'Commenting debates' do
expect(page).to have_content second_child.body expect(page).to have_content second_child.body
expect(page).to have_link "Go back to #{debate.title}", href: debate_path(debate) expect(page).to have_link "Go back to #{debate.title}", href: debate_path(debate)
expect(page).to have_selector("ul#comment_#{parent_comment.id}>li", count: 2) expect(page).to have_selector("ul#comment_#{parent_comment.id}>li", count: 2)
expect(page).to have_selector("ul#comment_#{first_child.id}>li", count: 1) expect(page).to have_selector("ul#comment_#{first_child.id}>li", count: 1)
expect(page).to have_selector("ul#comment_#{second_child.id}>li", count: 1) expect(page).to have_selector("ul#comment_#{second_child.id}>li", count: 1)

View File

@@ -1,99 +0,0 @@
require 'rails_helper'
feature 'Legacy Legislation' do
scenario 'Show' do
legacy_legislation = create(:legacy_legislation, title: 'Change the world', body: 'To achieve this...')
visit legacy_legislation_path(legacy_legislation)
expect(page).to have_content 'Change the world'
expect(page).to have_content 'To achieve this...'
end
context 'Annotations', :js do
let(:user) { create(:user) }
background { login_as user }
scenario 'Create' do
legacy_legislation = create(:legacy_legislation)
visit legacy_legislation_path(legacy_legislation)
page.find(:css, "#legacy_legislation_body").double_click
page.find(:css, ".annotator-adder button").click
fill_in 'annotator-field-0', with: 'this is my annotation'
page.find(:css, ".annotator-controls a[href='#save']").click
expect(page).to have_css ".annotator-hl"
first(:css, ".annotator-hl").click
expect(page).to have_content "this is my annotation"
visit legacy_legislation_path(legacy_legislation)
expect(page).to have_css ".annotator-hl"
first(:css, ".annotator-hl").click
expect(page).to have_content "this is my annotation"
end
scenario 'Update' do
legacy_legislation = create(:legacy_legislation)
annotation = create(:annotation, legacy_legislation: legacy_legislation, user: user, text: "my annotation")
visit legacy_legislation_path(legacy_legislation)
expect(page).to have_css ".annotator-hl"
page.find(:css, ".annotator-hl").click
page.find(:css, ".annotator-edit").click
fill_in 'annotator-field-0', with: 'edited annotation'
page.find(:css, ".annotator-controls a[href='#save']").click
expect(page).to_not have_css('span', text: 'my annotation')
page.find(:css, ".annotator-hl").click
expect(page).to have_content "edited annotation"
visit legacy_legislation_path(legacy_legislation)
page.find(:css, ".annotator-hl").click
expect(page).to have_content "edited annotation"
end
scenario 'Destroy' do
legacy_legislation = create(:legacy_legislation)
annotation = create(:annotation, legacy_legislation: legacy_legislation, user: user)
visit legacy_legislation_path(legacy_legislation)
expect(page).to have_css ".annotator-hl"
page.find(:css, ".annotator-hl").click
page.find(:css, ".annotator-delete").click
expect(page).to_not have_css ".annotator-hl"
end
scenario 'Search' do
legacy_legislation = create(:legacy_legislation)
annotation1 = create(:annotation, legacy_legislation: legacy_legislation, text: "my annotation",
ranges: [{"start" => "/div[1]", "startOffset" => 5, "end" => "/div[1]", "endOffset" => 10}])
annotation2 = create(:annotation, legacy_legislation: legacy_legislation, text: "my other annotation",
ranges: [{"start" => "/div[1]", "startOffset" => 12, "end" => "/div[1]", "endOffset" => 19}])
visit legacy_legislation_path(legacy_legislation)
expect(page).to have_css ".annotator-hl"
first(:css, ".annotator-hl").click
expect(page).to have_content "my annotation"
all(".annotator-hl")[1].click
expect(page).to have_content "my other annotation"
end
end
end
## Notes logged in and not logged in users

View File

@@ -303,7 +303,7 @@ feature 'Votes' do
debate = create(:debate) debate = create(:debate)
comment = create(:comment, commentable: debate) comment = create(:comment, commentable: debate)
visit comment_path(debate) visit comment_path(comment)
within("#comment_#{comment.id}") do within("#comment_#{comment.id}") do
find("div.votes").hover find("div.votes").hover
expect_message_you_need_to_sign_in_to_vote_comments expect_message_you_need_to_sign_in_to_vote_comments

View File

@@ -41,7 +41,7 @@ describe 'Communities Rake' do
expect(investment.community).to be_present expect(investment.community).to be_present
end end
end end
end end

View File

@@ -1,6 +1,6 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe Geozone, type: :model do describe Geozone do
let(:geozone) { build(:geozone) } let(:geozone) { build(:geozone) }
it "should be valid" do it "should be valid" do
@@ -13,6 +13,8 @@ RSpec.describe Geozone, type: :model do
end end
describe "#safe_to_destroy?" do describe "#safe_to_destroy?" do
let(:geozone) { create(:geozone) }
it "is true when not linked to other models" do it "is true when not linked to other models" do
expect(geozone.safe_to_destroy?).to be_truthy expect(geozone.safe_to_destroy?).to be_truthy
end end

View File

@@ -25,20 +25,20 @@ describe :booth do
end end
describe "#available" do describe "#available" do
it "returns booths associated to current or incoming polls" do it "returns booths associated to current or incoming polls" do
booth_for_current_poll = create(:poll_booth) booth_for_current_poll = create(:poll_booth)
booth_for_incoming_poll = create(:poll_booth) booth_for_incoming_poll = create(:poll_booth)
booth_for_expired_poll = create(:poll_booth) booth_for_expired_poll = create(:poll_booth)
current_poll = create(:poll, :current) current_poll = create(:poll, :current)
incoming_poll = create(:poll, :incoming) incoming_poll = create(:poll, :incoming)
expired_poll = create(:poll, :expired) expired_poll = create(:poll, :expired)
create(:poll_booth_assignment, poll: current_poll, booth: booth_for_current_poll) create(:poll_booth_assignment, poll: current_poll, booth: booth_for_current_poll)
create(:poll_booth_assignment, poll: incoming_poll, booth: booth_for_incoming_poll) create(:poll_booth_assignment, poll: incoming_poll, booth: booth_for_incoming_poll)
create(:poll_booth_assignment, poll: expired_poll, booth: booth_for_expired_poll) create(:poll_booth_assignment, poll: expired_poll, booth: booth_for_expired_poll)
expect(Poll::Booth.available).to include(booth_for_current_poll) expect(Poll::Booth.available).to include(booth_for_current_poll)
expect(Poll::Booth.available).to include(booth_for_incoming_poll) expect(Poll::Booth.available).to include(booth_for_incoming_poll)
expect(Poll::Booth.available).to_not include(booth_for_expired_poll) expect(Poll::Booth.available).to_not include(booth_for_expired_poll)

View File

@@ -1,11 +1,24 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe Poll::Question, type: :model do RSpec.describe Poll::Question, type: :model do
let(:poll_question) { build(:poll_question) }
describe "#valid_answers" do describe "#valid_answers" do
it "gets a comma-separated string, but returns an array" do it "gets a comma-separated string, but returns an array" do
q = create(:poll_question, valid_answers: "Yes, No") poll_question.valid_answers = "Yes, No"
expect(q.valid_answers).to eq(["Yes", "No"]) expect(poll_question.valid_answers).to eq(["Yes", "No"])
end
end
describe "#poll_question_id" do
it "should be invalid if a poll is not selected" do
poll_question.poll_id = nil
expect(poll_question).to_not be_valid
end
it "should be valid if a poll is selected" do
poll_question.poll_id = 1
expect(poll_question).to be_valid
end end
end end
@@ -13,13 +26,12 @@ RSpec.describe Poll::Question, type: :model do
it "copies the attributes from the proposal" do it "copies the attributes from the proposal" do
create_list(:geozone, 3) create_list(:geozone, 3)
p = create(:proposal) p = create(:proposal)
q = create(:poll_question) poll_question.copy_attributes_from_proposal(p)
q.copy_attributes_from_proposal(p) expect(poll_question.valid_answers).to eq(['Yes', 'No'])
expect(q.valid_answers).to eq(['Yes', 'No']) expect(poll_question.author).to eq(p.author)
expect(q.author).to eq(p.author) expect(poll_question.author_visible_name).to eq(p.author.name)
expect(q.author_visible_name).to eq(p.author.name) expect(poll_question.proposal_id).to eq(p.id)
expect(q.proposal_id).to eq(p.id) expect(poll_question.title).to eq(p.title)
expect(q.title).to eq(p.title)
end end
end end

View File

@@ -43,7 +43,7 @@ describe :shift do
officer_assignments = Poll::OfficerAssignment.all officer_assignments = Poll::OfficerAssignment.all
expect(officer_assignments.count).to eq(2) expect(officer_assignments.count).to eq(2)
oa1 = officer_assignments.first oa1 = officer_assignments.first
oa2 = officer_assignments.second oa2 = officer_assignments.second
@@ -59,10 +59,10 @@ describe :shift do
end end
describe "#persist_data" do describe "#persist_data" do
let(:user) { create(:user, username: "Ana", email: "ana@example.com") } let(:user) { create(:user, username: "Ana", email: "ana@example.com") }
let(:officer) { create(:poll_officer, user: user) } let(:officer) { create(:poll_officer, user: user) }
let(:shift) { create(:poll_shift, officer: officer) } let(:shift) { create(:poll_shift, officer: officer) }
it "should maintain officer data after destroying associated user" do it "should maintain officer data after destroying associated user" do
shift.officer.user.destroy shift.officer.user.destroy
@@ -79,5 +79,5 @@ describe :shift do
end end
end end
end end

View File

@@ -71,5 +71,4 @@ describe Topic do
end end
end end

View File

@@ -60,7 +60,7 @@ shared_examples "documentable" do |documentable_factory_name, documentable_path,
login_as(user) login_as(user)
visit send(documentable_path, arguments) visit send(documentable_path, arguments)
click_link "Upload document" click_link "Upload document"
expect(page).to have_selector("h1", text: "Upload document") expect(page).to have_selector("h1", text: "Upload document")
end end
@@ -251,6 +251,41 @@ shared_examples "documentable" do |documentable_factory_name, documentable_path,
expect(find("input[name='document[cached_attachment]']", visible: false).value).to include("empty.pdf") expect(find("input[name='document[cached_attachment]']", visible: false).value).to include("empty.pdf")
end end
scenario "Should not show 'Choose document' button after valid upload", :js do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
attach_file :document_attachment, "spec/fixtures/files/empty.pdf", make_visible: true
sleep 1
expect(page).not_to have_content "Choose document"
end
scenario "Should show 'Remove document' button after valid upload", :js do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
attach_file :document_attachment, "spec/fixtures/files/empty.pdf", make_visible: true
sleep 1
expect(page).to have_link("Remove document")
end
scenario "Should show 'Choose document' button after remove valid upload", :js do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
attach_file :document_attachment, "spec/fixtures/files/empty.pdf", make_visible: true
sleep 1
click_link "Remove document"
sleep 1
expect(page).to have_content "Choose document"
end
scenario "Should not update document cached_attachment field after unvalid file upload", :js do scenario "Should not update document cached_attachment field after unvalid file upload", :js do
login_as documentable.author login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name, visit new_document_path(documentable_type: documentable.class.name,

View File

@@ -11,10 +11,8 @@ shared_examples "nested documentable" do |documentable_factory_name, path, docum
before do before do
create(:administrator, user: administrator) create(:administrator, user: administrator)
if documentable_path_arguments documentable_path_arguments&.each do |argument_name, path_to_value|
documentable_path_arguments.each do |argument_name, path_to_value|
arguments.merge!("#{argument_name}": documentable.send(path_to_value)) arguments.merge!("#{argument_name}": documentable.send(path_to_value))
end
end end
end end
@@ -222,7 +220,7 @@ shared_examples "nested documentable" do |documentable_factory_name, path, docum
send(fill_resource_method_name) if fill_resource_method_name send(fill_resource_method_name) if fill_resource_method_name
documentable.class.max_documents_allowed.times.each do |index| documentable.class.max_documents_allowed.times.each do |index|
attach_new_file(documentable_factory_name, index , "spec/fixtures/files/empty.pdf") attach_new_file(documentable_factory_name, index, "spec/fixtures/files/empty.pdf")
end end
click_on submit_button click_on submit_button
@@ -250,7 +248,7 @@ def attach_new_file(documentable_factory_name, index, path)
end end
def fill_new_valid_proposal def fill_new_valid_proposal
fill_in :proposal_title, with: "Proposal title" fill_in :proposal_title, with: "Proposal title #{rand(9999)}"
fill_in :proposal_summary, with: "Proposal summary" fill_in :proposal_summary, with: "Proposal summary"
fill_in :proposal_question, with: "Proposal question?" fill_in :proposal_question, with: "Proposal question?"
check :proposal_terms_of_service check :proposal_terms_of_service