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/system/
#Netbeans projects files
/nbproject

View File

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

View File

@@ -24,6 +24,7 @@ gem 'graphql', '~> 1.6.3'
gem 'groupdate', '~> 3.2.0'
gem 'initialjs-rails', '~> 0.2.0.5'
gem 'invisible_captcha', '~> 0.9.2'
gem 'jquery-fileupload-rails'
gem 'jquery-rails', '~> 4.3.1'
gem 'jquery-ui-rails', '~> 6.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-twitter', '~> 1.4.0'
gem 'paperclip', '~> 5.1.0'
gem 'jquery-fileupload-rails'
gem 'paranoia', '~> 2.3.1'
gem 'pg', '~> 0.21.0'
gem 'pg_search', '~> 2.0.1'

View File

@@ -32,22 +32,30 @@
padding: 0;
z-index: 4 !important;
.ui-datepicker-prev {
left: 12px;
}
.ui-datepicker-next {
right: 12px;
}
.ui-datepicker-prev,
.ui-datepicker-next {
color: #fff;
cursor: pointer;
font-family: "icons" !important;
font-size: rem-calc(24);
font-weight: normal;
font-size: $small-font-size;
height: rem-calc(30);
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 {

View File

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

View File

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

View File

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

View File

@@ -7,7 +7,7 @@ class Officing::PollsController < Officing::BaseController
def final
@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
[]
end

View File

@@ -36,6 +36,10 @@ module AdminHelper
["banners"].include? controller_name
end
def menu_customization?
["pages", "images", "content_blocks"].include? controller_name
end
def official_level_options
options = [["", 0]]
(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")
end
def is_author?(community, participant)
def author?(community, participant)
if community.from_proposal?
community.proposal.author_id == participant.id
else

View File

@@ -9,7 +9,7 @@ module DocumentablesHelper
end
def max_file_size(documentable)
bytesToMeg(documentable.class.max_file_size)
bytes_to_mega(documentable.class.max_file_size)
end
def accepted_content_types(documentable)
@@ -18,7 +18,7 @@ module DocumentablesHelper
def accepted_content_types_extensions(documentable_class)
documentable_class.accepted_content_types
.collect{ |content_type| ".#{content_type.split("/").last}" }
.collect{ |content_type| ".#{content_type.split('/').last}" }
.join(",")
end

View File

@@ -8,7 +8,7 @@ module DocumentsHelper
document.errors[:attachment].join(', ') if document.errors.key?(:attachment)
end
def bytesToMeg(bytes)
def bytes_to_mega(bytes)
bytes / Numeric::MEGABYTE
end

View File

@@ -40,4 +40,17 @@ module ProposalsHelper
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

View File

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

View File

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

View File

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

View File

@@ -60,12 +60,12 @@
<span class="icon-checkmark-circle"></span>
<strong><%= t("admin.menu.title_polls") %></strong>
</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 %>>
<%= link_to t('admin.menu.polls'), admin_polls_path %>
</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 %>
</li>
@@ -158,7 +158,7 @@
<span class="icon-settings"></span>
<strong><%= t("admin.menu.title_site_customization") %></strong>
</a>
<ul <%= "class=is-active" if menu_profiles? %>>
<ul <%= "class=is-active" if menu_customization? %>>
<li <%= "class=active" if controller_name == "pages" %>>
<%= link_to t("admin.menu.site_customization.pages"), admin_site_customization_pages_path %>
</li>

View File

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

View File

@@ -16,24 +16,6 @@
<div class="small-12 medium-9 column">
<%= 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>
<% if @proposal.retired? %>
<div data-alert class="callout alert margin-top proposal-retired">
@@ -122,6 +104,35 @@
</div>
<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>
<h2><%= t("votes.supports") %></h2>
<div id="<%= dom_id(@proposal) %>_votes">

View File

@@ -21,7 +21,7 @@ data:
# - config/locales/**/*.%{locale}.yml
## Another gem (replace %#= with %=):
# - "<%#= %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}/activerecord.yml
- config/locales/%{locale}/activemodel.yml

View File

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

View File

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

View File

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

View File

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

View File

@@ -183,7 +183,7 @@ feature 'Admin polls' do
scenario 'Add question to poll', :js do
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)

View File

@@ -14,19 +14,19 @@ feature 'Admin shifts' do
booth1 = create(:poll_booth)
booth2 = create(:poll_booth)
shift1 = create(:poll_shift, officer: officer, booth: booth1, date: Date.today)
shift2 = create(:poll_shift, officer: officer, booth: booth2, date: Date.tomorrow)
shift1 = create(:poll_shift, officer: officer, booth: booth1, date: Time.zone.today)
shift2 = create(:poll_shift, officer: officer, booth: booth2, date: Time.zone.tomorrow)
visit new_admin_booth_shift_path(booth1)
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
visit new_admin_booth_shift_path(booth2)
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
end

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)
comment = create(:comment, commentable: debate)
visit comment_path(debate)
visit comment_path(comment)
within("#comment_#{comment.id}") do
find("div.votes").hover
expect_message_you_need_to_sign_in_to_vote_comments

View File

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

View File

@@ -1,11 +1,24 @@
require 'rails_helper'
RSpec.describe Poll::Question, type: :model do
let(:poll_question) { build(:poll_question) }
describe "#valid_answers" do
it "gets a comma-separated string, but returns an array" do
q = create(:poll_question, valid_answers: "Yes, No")
expect(q.valid_answers).to eq(["Yes", "No"])
poll_question.valid_answers = "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
@@ -13,13 +26,12 @@ RSpec.describe Poll::Question, type: :model do
it "copies the attributes from the proposal" do
create_list(:geozone, 3)
p = create(:proposal)
q = create(:poll_question)
q.copy_attributes_from_proposal(p)
expect(q.valid_answers).to eq(['Yes', 'No'])
expect(q.author).to eq(p.author)
expect(q.author_visible_name).to eq(p.author.name)
expect(q.proposal_id).to eq(p.id)
expect(q.title).to eq(p.title)
poll_question.copy_attributes_from_proposal(p)
expect(poll_question.valid_answers).to eq(['Yes', 'No'])
expect(poll_question.author).to eq(p.author)
expect(poll_question.author_visible_name).to eq(p.author.name)
expect(poll_question.proposal_id).to eq(p.id)
expect(poll_question.title).to eq(p.title)
end
end

View File

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

View File

@@ -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")
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
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,

View File

@@ -11,12 +11,10 @@ shared_examples "nested documentable" do |documentable_factory_name, path, docum
before do
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))
end
end
end
describe "at #{path}" do
@@ -250,7 +248,7 @@ def attach_new_file(documentable_factory_name, index, path)
end
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_question, with: "Proposal question?"
check :proposal_terms_of_service