diff --git a/app/assets/javascripts/embed_video.js.coffee b/app/assets/javascripts/embed_video.js.coffee
index 85c18ac8e..0825d1b80 100644
--- a/app/assets/javascripts/embed_video.js.coffee
+++ b/app/assets/javascripts/embed_video.js.coffee
@@ -1,7 +1,6 @@
App.EmbedVideo =
-
+
initialize: ->
$('#js-embedded-video').each ->
- code = $(this).data("video-code")
+ code = $(this).data("video-code")
$('#js-embedded-video').html(code)
-
\ No newline at end of file
diff --git a/app/controllers/admin/budget_investment_milestones_controller.rb b/app/controllers/admin/budget_investment_milestones_controller.rb
index a4b8acc5d..fb5f42384 100644
--- a/app/controllers/admin/budget_investment_milestones_controller.rb
+++ b/app/controllers/admin/budget_investment_milestones_controller.rb
@@ -48,7 +48,7 @@ class Admin::BudgetInvestmentMilestonesController < Admin::BaseController
end
def load_budget_investment_milestone
- @milestone = Budget::Investment::Milestone.find params[:id]
+ @milestone = Budget::Investment::Milestone.find params[:id]
end
diff --git a/app/controllers/communities_controller.rb b/app/controllers/communities_controller.rb
index 3462c8425..ff74f208b 100644
--- a/app/controllers/communities_controller.rb
+++ b/app/controllers/communities_controller.rb
@@ -1,8 +1,8 @@
class CommunitiesController < ApplicationController
+ TOPIC_ORDERS = %w{newest most_commented oldest}.freeze
+ before_action :set_order, :set_community, :load_topics, :load_participants
- before_action :set_order, :set_community, :load_topics, :load_participants, only: :show
-
- has_orders %w{newest most_commented oldest}, only: :show
+ has_orders TOPIC_ORDERS
skip_authorization_check
@@ -13,7 +13,7 @@ class CommunitiesController < ApplicationController
private
def set_order
- @order = params[:order].present? ? params[:order] : "newest"
+ @order = valid_order? ? params[:order] : "newest"
end
def set_community
@@ -27,4 +27,8 @@ class CommunitiesController < ApplicationController
def load_participants
@participants = @community.participants
end
+
+ def valid_order?
+ params[:order].present? && TOPIC_ORDERS.include?(params[:order])
+ end
end
diff --git a/app/controllers/management/sessions_controller.rb b/app/controllers/management/sessions_controller.rb
index 85ed59eae..6db303a39 100644
--- a/app/controllers/management/sessions_controller.rb
+++ b/app/controllers/management/sessions_controller.rb
@@ -20,7 +20,7 @@ class Management::SessionsController < ActionController::Base
def destroy_session
session[:manager] = nil
- session[:document_type] = nil
+ session[:document_type] = nil
session[:document_number] = nil
end
diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb
index f0e57a383..0e63685bd 100644
--- a/app/controllers/topics_controller.rb
+++ b/app/controllers/topics_controller.rb
@@ -1,13 +1,13 @@
class TopicsController < ApplicationController
include CommentableActions
- include FlagActions
before_action :load_community
- before_action :load_topic, only: [:show, :edit, :update]
+ before_action :load_topic, only: [:show, :edit, :update, :destroy]
has_orders %w{most_voted newest oldest}, only: :show
- skip_authorization_check
+ skip_authorization_check only: :show
+ load_and_authorize_resource except: :show
def new
@topic = Topic.new
@@ -39,6 +39,11 @@ class TopicsController < ApplicationController
end
end
+ def destroy
+ @topic.destroy
+ redirect_to community_path(@community), notice: I18n.t('flash.actions.destroy.topic')
+ end
+
private
def topic_params
diff --git a/app/helpers/comments_helper.rb b/app/helpers/comments_helper.rb
index 1ab6c9826..bdd2ccb68 100644
--- a/app/helpers/comments_helper.rb
+++ b/app/helpers/comments_helper.rb
@@ -42,7 +42,7 @@ module CommentsHelper
def commentable_path(comment)
commentable = comment.commentable
-
+
case comment.commentable_type
when "Budget::Investment"
budget_investment_path(commentable.budget_id, commentable)
@@ -51,7 +51,7 @@ module CommentsHelper
when "Legislation::Annotation"
legislation_process_draft_version_annotation_path(commentable.draft_version.process, commentable.draft_version, commentable)
when "Topic"
- community_topic_path(comment.commentable.community, comment.commentable)
+ community_topic_path(commentable.community, commentable)
else
commentable
end
diff --git a/app/helpers/communities_helper.rb b/app/helpers/communities_helper.rb
index 1d50c5388..bb770a948 100644
--- a/app/helpers/communities_helper.rb
+++ b/app/helpers/communities_helper.rb
@@ -1,12 +1,7 @@
module CommunitiesHelper
def community_title(community)
- if community.from_proposal?
- community.proposal.title
- else
- investment = Budget::Investment.where(community_id: community.id).first
- investment.title
- end
+ community.from_proposal? ? community.proposal.title : community.investment.title
end
def community_text(community)
@@ -21,8 +16,7 @@ module CommunitiesHelper
if community.from_proposal?
community.proposal.author_id == participant.id
else
- investment = Budget::Investment.where(community_id: community.id).first
- investment.author_id == participant.id
+ community.investment.author_id == participant.id
end
end
@@ -30,8 +24,7 @@ module CommunitiesHelper
if community.from_proposal?
proposal_path(community.proposal)
else
- investment = Budget::Investment.where(community_id: community.id).first
- budget_investment_path(investment.budget_id, investment)
+ budget_investment_path(community.investment.budget_id, community.investment)
end
end
diff --git a/app/models/abilities/common.rb b/app/models/abilities/common.rb
index 311b0dade..620cfb212 100644
--- a/app/models/abilities/common.rb
+++ b/app/models/abilities/common.rb
@@ -71,6 +71,9 @@ module Abilities
can :create, Annotation
can [:update, :destroy], Annotation, user_id: user.id
+
+ can [:create], Topic
+ can [:update, :destroy], Topic, author_id: user.id
end
end
end
diff --git a/app/models/community.rb b/app/models/community.rb
index 710982200..3fa1cebaa 100644
--- a/app/models/community.rb
+++ b/app/models/community.rb
@@ -1,11 +1,11 @@
class Community < ActiveRecord::Base
has_one :proposal
- has_one :investment
+ has_one :investment, class_name: Budget::Investment
has_many :topics
def participants
- users_participants = users_who_commented_by +
- users_who_topics_author_by +
+ users_participants = users_who_commented +
+ users_who_topics_author +
author_from_community
users_participants.uniq
end
@@ -16,24 +16,19 @@ class Community < ActiveRecord::Base
private
- def users_who_commented_by
+ def users_who_commented
topics_ids = topics.pluck(:id)
query = "comments.commentable_id IN (?)and comments.commentable_type = 'Topic'"
User.by_comments(query, topics_ids)
end
- def users_who_topics_author_by
+ def users_who_topics_author
author_ids = topics.pluck(:author_id)
User.by_authors(author_ids)
end
def author_from_community
- if from_proposal?
- User.where(id: proposal.author_id)
- else
- investment = Budget::Investment.where(community_id: id).first
- User.where(id: investment.author_id)
- end
+ from_proposal? ? User.where(id: proposal.author_id) : User.where(id: investment.author_id)
end
end
diff --git a/app/models/concerns/communitable.rb b/app/models/concerns/communitable.rb
index 6f0a10f43..415a7a3f0 100644
--- a/app/models/concerns/communitable.rb
+++ b/app/models/concerns/communitable.rb
@@ -7,8 +7,8 @@ module Communitable
end
def associate_community
- community = Community.create
- self.community_id = community.id
+ community = Community.create
+ self.community_id = community.id
end
end
diff --git a/app/models/topic.rb b/app/models/topic.rb
index 8c8f3f6c9..34abed0e3 100644
--- a/app/models/topic.rb
+++ b/app/models/topic.rb
@@ -1,6 +1,4 @@
class Topic < ActiveRecord::Base
- include Flaggable
-
acts_as_paranoid column: :hidden_at
include ActsAsParanoidAliases
diff --git a/app/views/admin/site_customization/pages/index.html.erb b/app/views/admin/site_customization/pages/index.html.erb
index dd9cfd3ad..897549caf 100644
--- a/app/views/admin/site_customization/pages/index.html.erb
+++ b/app/views/admin/site_customization/pages/index.html.erb
@@ -34,7 +34,7 @@
<% if page.status == "published" %>
<%= link_to t("admin.site_customization.pages.index.see_page"), page.url, target: "_blank" %>
<% else %>
- <%= t("admin.site_customization.pages.index.see_page") %>
+ <%= t("admin.site_customization.pages.index.see_page") %>
<% end %>
diff --git a/app/views/communities/_participant.html.erb b/app/views/communities/_participant.html.erb
new file mode 100644
index 000000000..5e4f02900
--- /dev/null
+++ b/app/views/communities/_participant.html.erb
@@ -0,0 +1,22 @@
+
+
+
diff --git a/app/views/communities/_participants.html.erb b/app/views/communities/_participants.html.erb
index 931ebf105..a153ec624 100644
--- a/app/views/communities/_participants.html.erb
+++ b/app/views/communities/_participants.html.erb
@@ -14,28 +14,7 @@
<% @participants.each do |participant| %>
-
-
-
+ <%= render 'participant', participant: participant %>
<% end %>
diff --git a/app/views/polls/_poll_group.html.erb b/app/views/polls/_poll_group.html.erb
index 6e0b85f16..e3e5c5976 100644
--- a/app/views/polls/_poll_group.html.erb
+++ b/app/views/polls/_poll_group.html.erb
@@ -64,7 +64,7 @@
<% if poll.expired? %>
<%= t("polls.index.participate_button_expired") %>
<% elsif poll.incoming? %>
- <%= t("polls.index.participate_button_incoming") %>
+ <%= t("polls.index.participate_button_incoming") %>
<% else %>
<%= t("polls.index.participate_button") %>
<% end %>
diff --git a/app/views/topics/_informative_text.html.erb b/app/views/topics/_informative_text.html.erb
new file mode 100644
index 000000000..aeb5ad773
--- /dev/null
+++ b/app/views/topics/_informative_text.html.erb
@@ -0,0 +1,11 @@
+<%= t("community.show.create_first_community_topic.first_theme") %>
+
+<% if user_signed_in? %>
+ <%= t("community.show.create_first_community_topic.first_theme_not_logged_in") %>
+<% else %>
+
+ <%= t("community.show.create_first_community_topic.sub_first_theme",
+ link: link_to(t("community.show.create_first_community_topic.sign_link",
+ org_name: setting['org_name']), new_user_session_path)).html_safe %>
+
+<% end %>
diff --git a/app/views/topics/_topic.html.erb b/app/views/topics/_topic.html.erb
new file mode 100644
index 000000000..fe225d501
--- /dev/null
+++ b/app/views/topics/_topic.html.erb
@@ -0,0 +1,25 @@
+
+
+
+
+ <%= link_to topic.title, community_topic_path(@community, topic) %>
+
+
+
+ <%= link_to t("community.show.topic.comments", count: topic.comments_count), community_topic_path(@community, topic, anchor: "comments") %>
+ •
+ <%= I18n.l topic.created_at.to_date %>
+ •
+ <%= topic.author.name %>
+
+
+
+
+
+ <% if topic.author == current_user %>
+ <%= link_to t("community.show.topic.edit_button"), edit_community_topic_path(@community.id, topic), class: 'button small hollow' %>
+ <%= link_to t("community.show.topic.destroy_button"), community_topic_path(@community.id, topic), method: :delete, class: 'button hollow alert small' %>
+ <% end %>
+
+
+
diff --git a/app/views/topics/_topics.html.erb b/app/views/topics/_topics.html.erb
index f74fa573f..42fa4f319 100644
--- a/app/views/topics/_topics.html.erb
+++ b/app/views/topics/_topics.html.erb
@@ -1,48 +1,13 @@
<% if topics.any? %>
-
<%= render 'shared/wide_order_selector', i18n_namespace: "comments" %>
-
- <% topics.each do |topic| %>
-
-
-
-
- <%= link_to topic.title, community_topic_path(@community, topic) %>
-
-
-
- <%= link_to t("community.show.topic.comments", count: topic.comments_count), community_topic_path(@community, topic, anchor: "comments") %>
- •
- <%= I18n.l topic.created_at.to_date %>
- •
- <%= topic.author.name %>
-
-
-
-
-
- <% if topic.author == current_user %>
- <%= link_to t("community.show.topic.edit_button"), edit_community_topic_path(@community.id, topic), class: 'button small hollow' %>
- <% end %>
-
-
-
-
- <% end %>
-
<% else %>
- <%= t("community.show.create_first_community_topic.first_theme") %>
- <% if user_signed_in? %>
- <%= t("community.show.create_first_community_topic.first_theme_not_logged_in") %>
- <% else %>
-
- <%= t("community.show.create_first_community_topic.sub_first_theme",
- link: link_to(t("community.show.create_first_community_topic.sign_link",
- org_name: setting['org_name']), new_user_session_path)).html_safe %>
-
- <% end %>
+ <%= render 'topics/informative_text', topics: topics %>
+<% end %>
+
+<% topics.each do |topic| %>
+ <%= render 'topics/topic', topic: topic %>
<% end %>
diff --git a/config/locales/en/community.yml b/config/locales/en/community.yml
index 37b7ea74f..068c98998 100644
--- a/config/locales/en/community.yml
+++ b/config/locales/en/community.yml
@@ -26,6 +26,7 @@ en:
disabled_info_title: You need to be logged to create a new topic
topic:
edit_button: Edit
+ destroy_button: Destroy
comments:
one: 1 comment
other: "%{count} comments"
diff --git a/config/locales/en/responders.yml b/config/locales/en/responders.yml
index 17de27b74..203d5700e 100644
--- a/config/locales/en/responders.yml
+++ b/config/locales/en/responders.yml
@@ -29,3 +29,4 @@ en:
spending_proposal: "Spending proposal deleted succesfully."
budget_investment: "Investment project deleted succesfully."
error: "Could not delete"
+ topic: "Topic deleted successfully."
diff --git a/config/locales/es/community.yml b/config/locales/es/community.yml
index 196cd4c50..8013c116c 100644
--- a/config/locales/es/community.yml
+++ b/config/locales/es/community.yml
@@ -26,6 +26,7 @@ es:
disabled_info_title: Necesitas estar logueado para crear un nuevo tema
topic:
edit_button: Editar
+ destroy_button: Eliminar
comments:
one: 1 Comentario
other: "%{count} Comentarios"
diff --git a/config/locales/es/responders.yml b/config/locales/es/responders.yml
index d3d4ff163..74e3ea20a 100644
--- a/config/locales/es/responders.yml
+++ b/config/locales/es/responders.yml
@@ -29,3 +29,4 @@ es:
spending_proposal: "Propuesta de inversión eliminada."
budget_investment: "Propuesta de inversión eliminada."
error: "No se pudo borrar"
+ topic: "Tema eliminado."
diff --git a/db/seeds.rb b/db/seeds.rb
index 90665fdb8..96916f29a 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -39,10 +39,10 @@ Setting["months_to_archive_proposals"] = 12
Setting["email_domain_for_officials"] = ''
# Code to be included at the top (inside ) of every page (useful for tracking)
-Setting['per_page_code_head'] = ''
+Setting['per_page_code_head'] = ''
# Code to be included at the top (inside ) of every page
-Setting['per_page_code_body'] = ''
+Setting['per_page_code_body'] = ''
# Social settings
Setting["twitter_handle"] = nil
@@ -79,7 +79,7 @@ Setting['feature.public_stats'] = true
Setting['feature.budgets'] = true
Setting['feature.signature_sheets'] = true
Setting['feature.legislation'] = true
-Setting['feature.community'] = nil
+Setting['feature.community'] = true
# Spending proposals feature flags
Setting['feature.spending_proposal_features.voting_allowed'] = nil
diff --git a/lib/tasks/communities.rake b/lib/tasks/communities.rake
index ad08e4bd9..261f4dbee 100644
--- a/lib/tasks/communities.rake
+++ b/lib/tasks/communities.rake
@@ -5,14 +5,14 @@ namespace :communities do
Proposal.all.each do |proposal|
if proposal.community.blank?
- community = Community.create
+ community = Community.create
proposal.update(community_id: community.id)
end
end
Budget::Investment.all.each do |investment|
if investment.community.blank?
- community = Community.create
+ community = Community.create
investment.update(community_id: community.id)
end
end
diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb
index ef2c1bf5b..4040717f1 100644
--- a/spec/features/budgets/investments_spec.rb
+++ b/spec/features/budgets/investments_spec.rb
@@ -340,6 +340,8 @@ feature 'Budget Investments' do
end
scenario 'Can not access the community' do
+ Setting['feature.community'] = false
+
investment = create(:budget_investment, heading: heading)
visit budget_investment_path(budget_id: budget.id, id: investment.id)
expect(page).not_to have_content "Access the community"
diff --git a/spec/features/comments/topics_spec.rb b/spec/features/comments/topics_spec.rb
index c72e8028d..38971fcff 100644
--- a/spec/features/comments/topics_spec.rb
+++ b/spec/features/comments/topics_spec.rb
@@ -1,7 +1,7 @@
require 'rails_helper'
include ActionView::Helpers::DateHelper
-feature 'Commenting topics' do
+feature 'Commenting topics from proposals' do
let(:user) { create :user }
let(:proposal) { create :proposal }
@@ -319,7 +319,7 @@ feature 'Commenting topics' do
page.find("#flag-expand-comment-#{comment.id}").click
expect(page).to have_selector("#flag-comment-#{comment.id}")
end
-
+
Setting['feature.community'] = nil
end
@@ -550,3 +550,553 @@ feature 'Commenting topics' do
end
end
+
+feature 'Commenting topics from budget investments' do
+ let(:user) { create :user }
+ let(:investment) { create :budget_investment }
+
+ scenario 'Index', :js do
+
+ community = investment.community
+ topic = create(:topic, community: community)
+ 3.times { create(:comment, commentable: topic) }
+
+ visit community_topic_path(community, topic)
+
+ expect(page).to have_css('.comment', count: 3)
+
+ comment = Comment.last
+ within first('.comment') do
+ expect(page).to have_content comment.user.name
+ expect(page).to have_content I18n.l(comment.created_at, format: :datetime)
+ expect(page).to have_content comment.body
+ end
+ end
+
+ scenario 'Show', :js do
+ community = investment.community
+ topic = create(:topic, community: community)
+ parent_comment = create(:comment, commentable: topic)
+ first_child = create(:comment, commentable: topic, parent: parent_comment)
+ second_child = create(:comment, commentable: topic, parent: parent_comment)
+
+ visit comment_path(parent_comment)
+
+ expect(page).to have_css(".comment", count: 3)
+ expect(page).to have_content parent_comment.body
+ expect(page).to have_content first_child.body
+ expect(page).to have_content second_child.body
+
+ expect(page).to have_link "Go back to #{topic.title}", href: community_topic_path(community, topic)
+ end
+
+ scenario 'Collapsable comments', :js do
+ community = investment.community
+ topic = create(:topic, community: community)
+ parent_comment = create(:comment, body: "Main comment", commentable: topic)
+ child_comment = create(:comment, body: "First subcomment", commentable: topic, parent: parent_comment)
+ grandchild_comment = create(:comment, body: "Last subcomment", commentable: topic, parent: child_comment)
+
+ visit community_topic_path(community, topic)
+
+ expect(page).to have_css('.comment', count: 3)
+
+ find("#comment_#{child_comment.id}_children_arrow").trigger('click')
+
+ expect(page).to have_css('.comment', count: 2)
+ expect(page).to_not have_content grandchild_comment.body
+
+ find("#comment_#{child_comment.id}_children_arrow").trigger('click')
+
+ expect(page).to have_css('.comment', count: 3)
+ expect(page).to have_content grandchild_comment.body
+
+ find("#comment_#{parent_comment.id}_children_arrow").trigger('click')
+
+ expect(page).to have_css('.comment', count: 1)
+ expect(page).to_not have_content child_comment.body
+ expect(page).to_not have_content grandchild_comment.body
+ end
+
+ scenario 'Comment order' do
+ community = investment.community
+ topic = create(:topic, community: community)
+ c1 = create(:comment, :with_confidence_score, commentable: topic, cached_votes_up: 100,
+ cached_votes_total: 120, created_at: Time.current - 2)
+ c2 = create(:comment, :with_confidence_score, commentable: topic, cached_votes_up: 10,
+ cached_votes_total: 12, created_at: Time.current - 1)
+ c3 = create(:comment, :with_confidence_score, commentable: topic, cached_votes_up: 1,
+ cached_votes_total: 2, created_at: Time.current)
+
+ visit community_topic_path(community, topic, order: :most_voted)
+
+ expect(c1.body).to appear_before(c2.body)
+ expect(c2.body).to appear_before(c3.body)
+
+ visit community_topic_path(community, topic, order: :newest)
+
+ expect(c3.body).to appear_before(c2.body)
+ expect(c2.body).to appear_before(c1.body)
+
+ visit community_topic_path(community, topic, order: :oldest)
+
+ expect(c1.body).to appear_before(c2.body)
+ expect(c2.body).to appear_before(c3.body)
+ end
+
+ scenario 'Creation date works differently in roots and in child comments, when sorting by confidence_score' do
+ community = investment.community
+ topic = create(:topic, community: community)
+ old_root = create(:comment, commentable: topic, created_at: Time.current - 10)
+ new_root = create(:comment, commentable: topic, created_at: Time.current)
+ old_child = create(:comment, commentable: topic, parent_id: new_root.id, created_at: Time.current - 10)
+ new_child = create(:comment, commentable: topic, parent_id: new_root.id, created_at: Time.current)
+
+ visit community_topic_path(community, topic, order: :most_voted)
+
+ expect(new_root.body).to appear_before(old_root.body)
+ expect(old_child.body).to appear_before(new_child.body)
+
+ visit community_topic_path(community, topic, order: :newest)
+
+ expect(new_root.body).to appear_before(old_root.body)
+ expect(new_child.body).to appear_before(old_child.body)
+
+ visit community_topic_path(community, topic, order: :oldest)
+
+ expect(old_root.body).to appear_before(new_root.body)
+ expect(old_child.body).to appear_before(new_child.body)
+ end
+
+ scenario 'Turns links into html links' do
+ community = investment.community
+ topic = create(:topic, community: community)
+ create :comment, commentable: topic, body: 'Built with http://rubyonrails.org/'
+
+ visit community_topic_path(community, topic)
+
+ within first('.comment') do
+ expect(page).to have_content 'Built with http://rubyonrails.org/'
+ expect(page).to have_link('http://rubyonrails.org/', href: 'http://rubyonrails.org/')
+ expect(find_link('http://rubyonrails.org/')[:rel]).to eq('nofollow')
+ expect(find_link('http://rubyonrails.org/')[:target]).to eq('_blank')
+ end
+ end
+
+ scenario 'Sanitizes comment body for security' do
+ community = investment.community
+ topic = create(:topic, community: community)
+ create :comment, commentable: topic,
+ body: " click me http://www.url.com"
+
+ visit community_topic_path(community, topic)
+
+ within first('.comment') do
+ expect(page).to have_content "click me http://www.url.com"
+ expect(page).to have_link('http://www.url.com', href: 'http://www.url.com')
+ expect(page).not_to have_link('click me')
+ end
+ end
+
+ scenario 'Paginated comments' do
+ community = investment.community
+ topic = create(:topic, community: community)
+ per_page = 10
+ (per_page + 2).times { create(:comment, commentable: topic)}
+
+ visit community_topic_path(community, topic)
+
+ expect(page).to have_css('.comment', count: per_page)
+ within("ul.pagination") do
+ expect(page).to have_content("1")
+ expect(page).to have_content("2")
+ expect(page).to_not have_content("3")
+ click_link "Next", exact: false
+ end
+
+ expect(page).to have_css('.comment', count: 2)
+ end
+
+ feature 'Not logged user' do
+ scenario 'can not see comments forms' do
+ community = investment.community
+ topic = create(:topic, community: community)
+ create(:comment, commentable: topic)
+
+ visit community_topic_path(community, topic)
+
+ expect(page).to have_content 'You must Sign in or Sign up to leave a comment'
+ within('#comments') do
+ expect(page).to_not have_content 'Write a comment'
+ expect(page).to_not have_content 'Reply'
+ end
+ end
+ end
+
+ scenario 'Create', :js do
+ login_as(user)
+ community = investment.community
+ topic = create(:topic, community: community)
+ visit community_topic_path(community, topic)
+
+ fill_in "comment-body-topic_#{topic.id}", with: 'Have you thought about...?'
+ click_button 'Publish comment'
+
+ within "#comments" do
+ expect(page).to have_content 'Have you thought about...?'
+ end
+
+ within "#tab-comments-label" do
+ expect(page).to have_content 'Comments (1)'
+ end
+ end
+
+ scenario 'Errors on create', :js do
+ login_as(user)
+ community = investment.community
+ topic = create(:topic, community: community)
+ visit community_topic_path(community, topic)
+
+ click_button 'Publish comment'
+
+ expect(page).to have_content "Can't be blank"
+ end
+
+ scenario 'Reply', :js do
+ community = investment.community
+ topic = create(:topic, community: community)
+ citizen = create(:user, username: 'Ana')
+ manuela = create(:user, username: 'Manuela')
+ comment = create(:comment, commentable: topic, user: citizen)
+
+ login_as(manuela)
+ visit community_topic_path(community, topic)
+
+ click_link "Reply"
+
+ within "#js-comment-form-comment_#{comment.id}" do
+ fill_in "comment-body-comment_#{comment.id}", with: 'It will be done next week.'
+ click_button 'Publish reply'
+ end
+
+ within "#comment_#{comment.id}" do
+ expect(page).to have_content 'It will be done next week.'
+ end
+
+ expect(page).to_not have_selector("#js-comment-form-comment_#{comment.id}", visible: true)
+ end
+
+ scenario 'Errors on reply', :js do
+ community = investment.community
+ topic = create(:topic, community: community)
+ comment = create(:comment, commentable: topic, user: user)
+
+ login_as(user)
+ visit community_topic_path(community, topic)
+
+ click_link "Reply"
+
+ within "#js-comment-form-comment_#{comment.id}" do
+ click_button 'Publish reply'
+ expect(page).to have_content "Can't be blank"
+ end
+
+ end
+
+ scenario "N replies", :js do
+ community = investment.community
+ topic = create(:topic, community: community)
+ parent = create(:comment, commentable: topic)
+
+ 7.times do
+ create(:comment, commentable: topic, parent: parent)
+ parent = parent.children.first
+ end
+
+ visit community_topic_path(community, topic)
+ expect(page).to have_css(".comment.comment.comment.comment.comment.comment.comment.comment")
+ end
+
+ scenario "Flagging as inappropriate", :js do
+ community = investment.community
+ topic = create(:topic, community: community)
+ comment = create(:comment, commentable: topic)
+
+ login_as(user)
+ visit community_topic_path(community, topic)
+
+ within "#comment_#{comment.id}" do
+ page.find("#flag-expand-comment-#{comment.id}").click
+ page.find("#flag-comment-#{comment.id}").click
+
+ expect(page).to have_css("#unflag-expand-comment-#{comment.id}")
+ end
+
+ expect(Flag.flagged?(user, comment)).to be
+ end
+
+ scenario "Undoing flagging as inappropriate", :js do
+ community = investment.community
+ topic = create(:topic, community: community)
+ comment = create(:comment, commentable: topic)
+ Flag.flag(user, comment)
+
+ login_as(user)
+ visit community_topic_path(community, topic)
+
+ within "#comment_#{comment.id}" do
+ page.find("#unflag-expand-comment-#{comment.id}").click
+ page.find("#unflag-comment-#{comment.id}").click
+
+ expect(page).to have_css("#flag-expand-comment-#{comment.id}")
+ end
+
+ expect(Flag.flagged?(user, comment)).to_not be
+ end
+
+ scenario "Flagging turbolinks sanity check", :js do
+ Setting['feature.community'] = true
+
+ community = investment.community
+ topic = create(:topic, community: community, title: "Should we change the world?")
+ comment = create(:comment, commentable: topic)
+
+ login_as(user)
+ visit community_path(community)
+ click_link "Should we change the world?"
+
+ within "#comment_#{comment.id}" do
+ page.find("#flag-expand-comment-#{comment.id}").click
+ expect(page).to have_selector("#flag-comment-#{comment.id}")
+ end
+
+ Setting['feature.community'] = nil
+ end
+
+ scenario "Erasing a comment's author" do
+ community = investment.community
+ topic = create(:topic, community: community)
+ comment = create(:comment, commentable: topic, body: "this should be visible")
+ comment.user.erase
+
+ visit community_topic_path(community, topic)
+
+ within "#comment_#{comment.id}" do
+ expect(page).to have_content('User deleted')
+ expect(page).to have_content('this should be visible')
+ end
+ end
+
+ feature "Moderators" do
+ scenario "can create comment as a moderator", :js do
+ community = investment.community
+ topic = create(:topic, community: community)
+ moderator = create(:moderator)
+
+ login_as(moderator.user)
+ visit community_topic_path(community, topic)
+
+ fill_in "comment-body-topic_#{topic.id}", with: "I am moderating!"
+ check "comment-as-moderator-topic_#{topic.id}"
+ click_button "Publish comment"
+
+ within "#comments" do
+ expect(page).to have_content "I am moderating!"
+ expect(page).to have_content "Moderator ##{moderator.id}"
+ expect(page).to have_css "div.is-moderator"
+ expect(page).to have_css "img.moderator-avatar"
+ end
+ end
+
+ scenario "can create reply as a moderator", :js do
+ community = investment.community
+ topic = create(:topic, community: community)
+ citizen = create(:user, username: "Ana")
+ manuela = create(:user, username: "Manuela")
+ moderator = create(:moderator, user: manuela)
+ comment = create(:comment, commentable: topic, user: citizen)
+
+ login_as(manuela)
+ visit community_topic_path(community, topic)
+
+ click_link "Reply"
+
+ within "#js-comment-form-comment_#{comment.id}" do
+ fill_in "comment-body-comment_#{comment.id}", with: "I am moderating!"
+ check "comment-as-moderator-comment_#{comment.id}"
+ click_button 'Publish reply'
+ end
+
+ within "#comment_#{comment.id}" do
+ expect(page).to have_content "I am moderating!"
+ expect(page).to have_content "Moderator ##{moderator.id}"
+ expect(page).to have_css "div.is-moderator"
+ expect(page).to have_css "img.moderator-avatar"
+ end
+
+ expect(page).to_not have_selector("#js-comment-form-comment_#{comment.id}", visible: true)
+ end
+
+ scenario "can not comment as an administrator" do
+ community = investment.community
+ topic = create(:topic, community: community)
+ moderator = create(:moderator)
+
+ login_as(moderator.user)
+ visit community_topic_path(community, topic)
+
+ expect(page).to_not have_content "Comment as administrator"
+ end
+ end
+
+ feature "Administrators" do
+ scenario "can create comment as an administrator", :js do
+ community = investment.community
+ topic = create(:topic, community: community)
+ admin = create(:administrator)
+
+ login_as(admin.user)
+ visit community_topic_path(community, topic)
+
+ fill_in "comment-body-topic_#{topic.id}", with: "I am your Admin!"
+ check "comment-as-administrator-topic_#{topic.id}"
+ click_button "Publish comment"
+
+ within "#comments" do
+ expect(page).to have_content "I am your Admin!"
+ expect(page).to have_content "Administrator ##{admin.id}"
+ expect(page).to have_css "div.is-admin"
+ expect(page).to have_css "img.admin-avatar"
+ end
+ end
+
+ scenario "can create reply as an administrator", :js do
+ community = investment.community
+ topic = create(:topic, community: community)
+ citizen = create(:user, username: "Ana")
+ manuela = create(:user, username: "Manuela")
+ admin = create(:administrator, user: manuela)
+ comment = create(:comment, commentable: topic, user: citizen)
+
+ login_as(manuela)
+ visit community_topic_path(community, topic)
+
+ click_link "Reply"
+
+ within "#js-comment-form-comment_#{comment.id}" do
+ fill_in "comment-body-comment_#{comment.id}", with: "Top of the world!"
+ check "comment-as-administrator-comment_#{comment.id}"
+ click_button 'Publish reply'
+ end
+
+ within "#comment_#{comment.id}" do
+ expect(page).to have_content "Top of the world!"
+ expect(page).to have_content "Administrator ##{admin.id}"
+ expect(page).to have_css "div.is-admin"
+ expect(page).to have_css "img.admin-avatar"
+ end
+
+ expect(page).to_not have_selector("#js-comment-form-comment_#{comment.id}", visible: true)
+ end
+
+ scenario "can not comment as a moderator" do
+ community = investment.community
+ topic = create(:topic, community: community)
+ admin = create(:administrator)
+
+ login_as(admin.user)
+ visit community_topic_path(community, topic)
+
+ expect(page).to_not have_content "Comment as moderator"
+ end
+ end
+
+ feature 'Voting comments' do
+
+ background do
+ @manuela = create(:user, verified_at: Time.current)
+ @pablo = create(:user)
+ @investment = create(:budget_investment)
+ @topic = create(:topic, community: @investment.community)
+ @comment = create(:comment, commentable: @topic)
+
+ login_as(@manuela)
+ end
+
+ scenario 'Show' do
+ create(:vote, voter: @manuela, votable: @comment, vote_flag: true)
+ create(:vote, voter: @pablo, votable: @comment, vote_flag: false)
+
+ visit community_topic_path(@investment.community, @topic)
+
+ within("#comment_#{@comment.id}_votes") do
+ within(".in_favor") do
+ expect(page).to have_content "1"
+ end
+
+ within(".against") do
+ expect(page).to have_content "1"
+ end
+
+ expect(page).to have_content "2 votes"
+ end
+ end
+
+ scenario 'Create', :js do
+ visit community_topic_path(@investment.community, @topic)
+
+ within("#comment_#{@comment.id}_votes") do
+ find(".in_favor a").click
+
+ within(".in_favor") do
+ expect(page).to have_content "1"
+ end
+
+ within(".against") do
+ expect(page).to have_content "0"
+ end
+
+ expect(page).to have_content "1 vote"
+ end
+ end
+
+ scenario 'Update', :js do
+ visit community_topic_path(@investment.community, @topic)
+
+ within("#comment_#{@comment.id}_votes") do
+ find('.in_favor a').click
+ find('.against a').click
+
+ within('.in_favor') do
+ expect(page).to have_content "0"
+ end
+
+ within('.against') do
+ expect(page).to have_content "1"
+ end
+
+ expect(page).to have_content "1 vote"
+ end
+ end
+
+ scenario 'Trying to vote multiple times', :js do
+ visit community_topic_path(@investment.community, @topic)
+
+ within("#comment_#{@comment.id}_votes") do
+ find('.in_favor a').click
+ find('.in_favor a').click
+
+ within('.in_favor') do
+ expect(page).to have_content "1"
+ end
+
+ within('.against') do
+ expect(page).to have_content "0"
+ end
+
+ expect(page).to have_content "1 vote"
+ end
+ end
+ end
+
+end
diff --git a/spec/features/communities_spec.rb b/spec/features/communities_spec.rb
index b9d14c790..2909f416e 100644
--- a/spec/features/communities_spec.rb
+++ b/spec/features/communities_spec.rb
@@ -15,7 +15,7 @@ feature 'Communities' do
scenario 'Should display default content' do
proposal = create(:proposal)
community = proposal.community
- user = create(:user)
+ user = create(:user)
login_as(user)
visit community_path(community)
@@ -63,10 +63,47 @@ feature 'Communities' do
end
end
+ scenario "Topic order" do
+ proposal = create(:proposal)
+ community = proposal.community
+ topic1 = create(:topic, community: community)
+ topic2 = create(:topic, community: community)
+ topic2_comment = create(:comment, :with_confidence_score, commentable: topic2)
+ topic3 = create(:topic, community: community)
+ topic3_comment = create(:comment, :with_confidence_score, commentable: topic3)
+ topic3_comment = create(:comment, :with_confidence_score, commentable: topic3)
+
+ visit community_path(community, order: :most_commented)
+
+ expect(topic3.title).to appear_before(topic2.title)
+ expect(topic2.title).to appear_before(topic1.title)
+
+ visit community_path(community, order: :oldest)
+
+ expect(topic1.title).to appear_before(topic2.title)
+ expect(topic2.title).to appear_before(topic3.title)
+
+ visit community_path(community, order: :newest)
+
+ expect(topic3.title).to appear_before(topic2.title)
+ expect(topic2.title).to appear_before(topic1.title)
+ end
+
+ scenario "Should order by newest when order param is invalid" do
+ proposal = create(:proposal)
+ community = proposal.community
+ topic1 = create(:topic, community: community)
+ topic2 = create(:topic, community: community)
+
+ visit community_path(community, order: "invalid_param")
+
+ expect(topic2.title).to appear_before(topic1.title)
+ end
+
scenario 'Should display topic edit button when author is logged' do
proposal = create(:proposal)
community = proposal.community
- user = create(:user)
+ user = create(:user)
topic1 = create(:topic, community: community, author: user)
topic2 = create(:topic, community: community)
login_as(user)
diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb
index 63050c43f..0c69eee3e 100644
--- a/spec/features/proposals_spec.rb
+++ b/spec/features/proposals_spec.rb
@@ -101,6 +101,8 @@ feature 'Proposals' do
end
scenario 'Can not access the community' do
+ Setting['feature.community'] = false
+
proposal = create(:proposal)
visit proposal_path(proposal)
expect(page).not_to have_content "Access the community"
diff --git a/spec/features/topics_specs.rb b/spec/features/topics_specs.rb
index 0d668d44b..0ba674844 100644
--- a/spec/features/topics_specs.rb
+++ b/spec/features/topics_specs.rb
@@ -13,10 +13,10 @@ feature 'Topics' do
expect(page).to have_selector(".button.expanded.disabled")
end
- scenario 'Should can access to new topic page with user logged', :js do
+ scenario 'Can access to new topic page with user logged', :js do
proposal = create(:proposal)
community = proposal.community
- user = create(:user)
+ user = create(:user)
login_as(user)
visit community_path(community)
@@ -28,7 +28,7 @@ feature 'Topics' do
scenario 'Should have content on new topic page', :js do
proposal = create(:proposal)
community = proposal.community
- user = create(:user)
+ user = create(:user)
login_as(user)
visit community_path(community)
@@ -47,10 +47,10 @@ feature 'Topics' do
context 'Create' do
- scenario 'Should can create a new topic', :js do
+ scenario 'Can create a new topic', :js do
proposal = create(:proposal)
community = proposal.community
- user = create(:user)
+ user = create(:user)
login_as(user)
visit new_community_topic_path(community)
@@ -62,14 +62,23 @@ feature 'Topics' do
expect(current_path).to eq(community_path(community))
end
+ scenario 'Can not create a new topic when user not logged', :js do
+ proposal = create(:proposal)
+ community = proposal.community
+
+ visit new_community_topic_path(community)
+
+ expect(page).to have_content "You do not have permission to carry out the action 'new' on topic."
+ end
+
end
context 'Edit' do
- scenario 'Should can edit a topic' do
+ scenario 'Can edit a topic' do
proposal = create(:proposal)
community = proposal.community
- user = create(:user)
+ user = create(:user)
topic = create(:topic, community: community, author: user)
login_as(user)
visit edit_community_topic_path(community, topic)
@@ -82,11 +91,23 @@ feature 'Topics' do
expect(current_path).to eq(community_path(community))
end
+ scenario 'Can not edit a topic when user logged is not an author' do
+ proposal = create(:proposal)
+ community = proposal.community
+ topic = create(:topic, community: community)
+ user = create(:user)
+ login_as(user)
+
+ visit edit_community_topic_path(community, topic)
+
+ expect(page).to have_content "You do not have permission to carry out the action 'edit' on topic."
+ end
+
end
context 'Show' do
- scenario 'Should can show topic' do
+ scenario 'Can show topic' do
proposal = create(:proposal)
community = proposal.community
topic = create(:topic, community: community)
@@ -99,4 +120,35 @@ feature 'Topics' do
end
+ context 'Destroy' do
+
+ scenario 'Can destroy a topic' do
+ proposal = create(:proposal)
+ community = proposal.community
+ user = create(:user)
+ topic = create(:topic, community: community, author: user)
+ login_as(user)
+ visit community_path(community)
+
+ click_link "Destroy"
+
+ expect(page).to have_content "Topic deleted successfully."
+ expect(page).not_to have_content topic.title
+ expect(current_path).to eq(community_path(community))
+ end
+
+ scenario 'Can not destroy a topic when user logged is not an author' do
+ proposal = create(:proposal)
+ community = proposal.community
+ topic = create(:topic, community: community)
+ user = create(:user)
+ login_as(user)
+
+ visit community_path(community)
+
+ expect(page).not_to have_link "Destroy"
+ end
+
+ end
+
end
diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb
index bd2aefa17..ae2bac6d1 100644
--- a/spec/features/users_spec.rb
+++ b/spec/features/users_spec.rb
@@ -235,7 +235,7 @@ feature 'Users' do
end
scenario 'Not display interests when proposal has been destroyed' do
- proposal = create(:proposal, tag_list: "Sport")
+ proposal = create(:proposal, tag_list: "Sport")
create(:follow, :followed_proposal, followable: proposal, user: @user)
proposal.destroy
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 6db1a2a25..3d4217ea3 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -668,8 +668,8 @@ describe User do
end
it "should discard followed objects duplicated tags" do
- proposal1 = create(:proposal, tag_list: "Sport")
- proposal2 = create(:proposal, tag_list: "Sport")
+ proposal1 = create(:proposal, tag_list: "Sport")
+ proposal2 = create(:proposal, tag_list: "Sport")
budget_investment = create(:budget_investment, tag_list: "Sport")
create(:follow, followable: proposal1, user: user)
diff --git a/vendor/assets/javascripts/annotator.js b/vendor/assets/javascripts/annotator.js
index b9019a6b2..dfbc0a0bf 100644
--- a/vendor/assets/javascripts/annotator.js
+++ b/vendor/assets/javascripts/annotator.js
@@ -2054,7 +2054,7 @@ setDocument = Sizzle.setDocument = function( node ) {
// getElementById is not reliable as a find shortcut
delete Expr.find["ID"];
- Expr.filter["ID"] = function( id ) {
+ Expr.filter["ID"] = function( id ) {
var attrId = id.replace( runescape, funescape );
return function( elem ) {
var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
|