Merge pull request #2206 from consul/related-contents-score
Related contents score
This commit is contained in:
@@ -2424,11 +2424,28 @@ table {
|
||||
|
||||
li {
|
||||
border-bottom: 1px solid $border;
|
||||
padding: $line-height / 4;
|
||||
margin-bottom: 0 !important;
|
||||
padding: $line-height / 2;
|
||||
|
||||
&:first-child {
|
||||
border-top: 1px solid $border;
|
||||
}
|
||||
|
||||
@include breakpoint(medium) {
|
||||
|
||||
.score-actions {
|
||||
display: none;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #f9f9f9;
|
||||
|
||||
.score-actions {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
@@ -2436,7 +2453,7 @@ table {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
span:not(.icon-flag) {
|
||||
.related-content-title {
|
||||
color: #4f4f4f;
|
||||
font-size: rem-calc(12);
|
||||
text-transform: uppercase;
|
||||
@@ -2447,6 +2464,47 @@ table {
|
||||
}
|
||||
}
|
||||
|
||||
.relate-content-score {
|
||||
display: block;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
margin-right: $line-height;
|
||||
padding-left: rem-calc(20);
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
|
||||
&.score-positive:before,
|
||||
&.score-negative:before {
|
||||
font-family: 'icons';
|
||||
left: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
&.score-positive {
|
||||
color: $color-success;
|
||||
|
||||
&:before {
|
||||
color: $color-success;
|
||||
content: '\6c';
|
||||
}
|
||||
}
|
||||
|
||||
&.score-negative {
|
||||
color: $color-alert;
|
||||
|
||||
&:before {
|
||||
color: $color-alert;
|
||||
content: '\76';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 22. Images
|
||||
// -----------------
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
class RelatedContentsController < ApplicationController
|
||||
VALID_URL = /#{Setting['url']}\/.*\/.*/
|
||||
|
||||
skip_authorization_check
|
||||
|
||||
respond_to :html, :js
|
||||
|
||||
def create
|
||||
if relationable_object && related_object
|
||||
@relationable.relate_content(@related)
|
||||
RelatedContent.create(parent_relationable: @relationable, child_relationable: @related, author: current_user)
|
||||
|
||||
flash[:success] = t('related_content.success')
|
||||
else
|
||||
@@ -17,28 +15,25 @@ class RelatedContentsController < ApplicationController
|
||||
redirect_to @relationable
|
||||
end
|
||||
|
||||
def flag
|
||||
@related = RelatedContent.find_by(id: params[:id])
|
||||
|
||||
Flag.flag(current_user, @related)
|
||||
Flag.flag(current_user, @related.opposite_related_content)
|
||||
|
||||
render template: 'relationable/_refresh_flag_actions'
|
||||
def score_positive
|
||||
score(:positive)
|
||||
end
|
||||
|
||||
def unflag
|
||||
@related = RelatedContent.find_by(id: params[:id])
|
||||
|
||||
Flag.unflag(current_user, @related)
|
||||
Flag.unflag(current_user, @related.opposite_related_content)
|
||||
|
||||
render template: 'relationable/_refresh_flag_actions'
|
||||
def score_negative
|
||||
score(:negative)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def score(action)
|
||||
@related = RelatedContent.find_by(id: params[:id])
|
||||
@related.send("score_#{action}", current_user)
|
||||
|
||||
render template: 'relationable/_refresh_score_actions'
|
||||
end
|
||||
|
||||
def valid_url?
|
||||
params[:url].match(VALID_URL)
|
||||
params[:url].start_with?(Setting['url'])
|
||||
end
|
||||
|
||||
def relationable_object
|
||||
|
||||
@@ -21,8 +21,6 @@ module FlagsHelper
|
||||
def own_flaggable?(flaggable)
|
||||
if flaggable.is_a? Comment
|
||||
flaggable.user_id == current_user.id
|
||||
elsif flaggable.is_a? RelatedContent
|
||||
false
|
||||
else
|
||||
flaggable.author_id == current_user.id
|
||||
end
|
||||
|
||||
@@ -5,19 +5,11 @@ module Relationable
|
||||
has_many :related_contents, as: :parent_relationable, dependent: :destroy
|
||||
end
|
||||
|
||||
def relate_content(relationable)
|
||||
RelatedContent.find_or_create_by(parent_relationable: self, child_relationable: relationable)
|
||||
def find_related_content(relationable)
|
||||
RelatedContent.where(parent_relationable: self, child_relationable: relationable).first
|
||||
end
|
||||
|
||||
def relationed_contents
|
||||
related_contents.not_hidden.map { |related_content| related_content.child_relationable }
|
||||
end
|
||||
|
||||
def report_related_content(relationable)
|
||||
related_content = related_contents.find_by(child_relationable: relationable)
|
||||
if related_content.present?
|
||||
related_content.increment!(:flags_count)
|
||||
related_content.opposite_related_content.increment!(:flags_count)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
class RelatedContent < ActiveRecord::Base
|
||||
include Flaggable
|
||||
|
||||
RELATED_CONTENTS_REPORT_THRESHOLD = Setting['related_contents_report_threshold'].to_i
|
||||
RELATED_CONTENT_SCORE_THRESHOLD = Setting['related_content_score_threshold'].to_f
|
||||
RELATIONABLE_MODELS = %w{proposals debates}.freeze
|
||||
|
||||
acts_as_paranoid column: :hidden_at
|
||||
include ActsAsParanoidAliases
|
||||
|
||||
belongs_to :author, class_name: 'User', foreign_key: 'author_id'
|
||||
belongs_to :parent_relationable, polymorphic: true, touch: true
|
||||
belongs_to :child_relationable, polymorphic: true, touch: true
|
||||
has_one :opposite_related_content, class_name: 'RelatedContent', foreign_key: :related_content_id
|
||||
has_many :related_content_scores
|
||||
|
||||
validates :parent_relationable_id, presence: true
|
||||
validates :parent_relationable_type, presence: true
|
||||
@@ -15,22 +18,46 @@ class RelatedContent < ActiveRecord::Base
|
||||
validates :parent_relationable_id, uniqueness: { scope: [:parent_relationable_type, :child_relationable_id, :child_relationable_type] }
|
||||
|
||||
after_create :create_opposite_related_content, unless: proc { opposite_related_content.present? }
|
||||
after_destroy :destroy_opposite_related_content, if: proc { opposite_related_content.present? }
|
||||
after_create :create_author_score
|
||||
|
||||
scope :not_hidden, -> { where('flags_count <= ?', RELATED_CONTENTS_REPORT_THRESHOLD) }
|
||||
scope :not_hidden, -> { where(hidden_at: nil) }
|
||||
|
||||
def hidden_by_reports?
|
||||
flags_count > RELATED_CONTENTS_REPORT_THRESHOLD
|
||||
def score_positive(user)
|
||||
score(RelatedContentScore::SCORES[:POSITIVE], user)
|
||||
end
|
||||
|
||||
def score_negative(user)
|
||||
score(RelatedContentScore::SCORES[:NEGATIVE], user)
|
||||
end
|
||||
|
||||
def scored_by_user?(user)
|
||||
related_content_scores.exists?(user: user)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_opposite_related_content
|
||||
related_content = RelatedContent.create!(opposite_related_content: self, parent_relationable: child_relationable, child_relationable: parent_relationable)
|
||||
related_content = RelatedContent.create!(opposite_related_content: self, parent_relationable: child_relationable,
|
||||
child_relationable: parent_relationable, author: author)
|
||||
self.opposite_related_content = related_content
|
||||
end
|
||||
|
||||
def destroy_opposite_related_content
|
||||
opposite_related_content.destroy
|
||||
def score(value, user)
|
||||
score_with_opposite(value, user)
|
||||
hide_with_opposite if (related_content_scores.sum(:value) / related_content_scores_count) < RELATED_CONTENT_SCORE_THRESHOLD
|
||||
end
|
||||
|
||||
def hide_with_opposite
|
||||
hide
|
||||
opposite_related_content.hide
|
||||
end
|
||||
|
||||
def create_author_score
|
||||
score_positive(author)
|
||||
end
|
||||
|
||||
def score_with_opposite(value, user)
|
||||
RelatedContentScore.create(user: user, related_content: self, value: value)
|
||||
RelatedContentScore.create(user: user, related_content: opposite_related_content, value: value)
|
||||
end
|
||||
end
|
||||
|
||||
13
app/models/related_content_score.rb
Normal file
13
app/models/related_content_score.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
class RelatedContentScore < ActiveRecord::Base
|
||||
SCORES = {
|
||||
POSITIVE: 1,
|
||||
NEGATIVE: -1
|
||||
}.freeze
|
||||
|
||||
belongs_to :related_content, touch: true, counter_cache: :related_content_scores_count
|
||||
belongs_to :user
|
||||
|
||||
validates :user, presence: true
|
||||
validates :related_content, presence: true
|
||||
validates :related_content_id, uniqueness: { scope: [:user_id] }
|
||||
end
|
||||
@@ -1,19 +0,0 @@
|
||||
<span class="flag-content">
|
||||
<% if show_flag_action? related %>
|
||||
<a id="flag-expand-related-<%= related.id %>" data-toggle="flag-drop-related-<%= related.id %>" title="<%= t('shared.flag') %>" class="float-right flag">
|
||||
<span class="icon-flag flag-disable"></span>
|
||||
</a>
|
||||
<span class="dropdown-pane" id="flag-drop-related-<%= related.id %>" data-dropdown data-auto-focus="true">
|
||||
<%= link_to t('shared.flag'), flag_related_content_path(related), method: :put, remote: true, id: "flag-related-#{ related.id }" %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<% if show_unflag_action? related %>
|
||||
<a id="unflag-expand-related-<%= related.id %>" data-toggle="unflag-drop-related-<%= related.id %>" title="<%= t('shared.unflag') %>" class="float-right flag">
|
||||
<span class="icon-flag flag-active"></span>
|
||||
</a>
|
||||
<span class="dropdown-pane" id="unflag-drop-related-<%= related.id %>" data-dropdown data-auto-focus="true">
|
||||
<%= link_to t('shared.unflag'), unflag_related_content_path(related), method: :put, remote: true, id: "unflag-related-#{ related.id }" %>
|
||||
</span>
|
||||
<% end %>
|
||||
</span>
|
||||
@@ -1 +0,0 @@
|
||||
$("#<%= dom_id(@related) %>.js-flag-actions").html('<%= j render("relationable/flag_actions", related: @related) %>');
|
||||
1
app/views/relationable/_refresh_score_actions.js.erb
Normal file
1
app/views/relationable/_refresh_score_actions.js.erb
Normal file
@@ -0,0 +1 @@
|
||||
$("#<%= dom_id(@related) %>.js-score-actions").html('');
|
||||
@@ -4,11 +4,13 @@
|
||||
<h2 class="inline-block">
|
||||
<%= t("related_content.title") %> <span>(<%= relationable.relationed_contents.count %>)</span>
|
||||
</h2>
|
||||
<a>
|
||||
<button type="button" data-toggle="related_content" class="add-related-content" id="add-related-content">
|
||||
<%= t("related_content.add") %>
|
||||
</button>
|
||||
</a>
|
||||
<% if current_user %>
|
||||
<a>
|
||||
<button type="button" data-toggle="related_content" class="add-related-content" id="add-related-content">
|
||||
<%= t("related_content.add") %>
|
||||
</button>
|
||||
</a>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<%= render 'relationable/form', relationable: relationable %>
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
<ul class="related-content-list" id="related-content-list">
|
||||
<% @related_contents.each do |related| %>
|
||||
<li>
|
||||
<span id="<%= dom_id(related.relate_content(relationable)) %>" class="js-flag-actions">
|
||||
<%= render 'relationable/flag_actions', related: related.relate_content(relationable) %>
|
||||
</span>
|
||||
<li id="related-content-<%= related.find_related_content(relationable).id %>">
|
||||
<% related_content = related.find_related_content(relationable) %>
|
||||
<% if current_user && related_content.author != current_user && !related_content.scored_by_user?(current_user)%>
|
||||
<span id="<%= dom_id(related.find_related_content(relationable)) %>" class="js-score-actions score-actions">
|
||||
<%= render 'relationable/score', related: related_content %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<span><%= t("related_content.content_title.#{related.class.name.downcase}") %></span><br>
|
||||
<span class="related-content-title"><%= t("related_content.content_title.#{related.class.name.downcase}") %></span><br>
|
||||
<h3 class="inline-block">
|
||||
<%= link_to related.title, eval("#{related.class.name.downcase}_path(related)") %>
|
||||
</h3>
|
||||
|
||||
17
app/views/relationable/_score.html.erb
Normal file
17
app/views/relationable/_score.html.erb
Normal file
@@ -0,0 +1,17 @@
|
||||
<small><%= t("related_content.is_related") %></small>
|
||||
|
||||
<span class="relate-content-score">
|
||||
<%= link_to t("related_content.score_positive"),
|
||||
score_positive_related_content_path(related),
|
||||
method: :put,
|
||||
remote: true,
|
||||
id: "score-positive-related-#{ related.id }",
|
||||
class: "score-positive" %>
|
||||
|
||||
<%= link_to t("related_content.score_negative"),
|
||||
score_negative_related_content_path(related),
|
||||
method: :put,
|
||||
remote: true,
|
||||
id: "score-negative-related-#{ related.id }",
|
||||
class: "score-negative" %>
|
||||
</span>
|
||||
@@ -820,6 +820,9 @@ en:
|
||||
submit: "Add"
|
||||
error: "Link not valid. Remember to start with %{url}."
|
||||
success: "You added a new related content"
|
||||
is_related: "¿Is it related content?"
|
||||
score_positive: "Yes"
|
||||
score_negative: "No"
|
||||
content_title:
|
||||
proposal: "Proposal"
|
||||
debate: "Debate"
|
||||
|
||||
@@ -819,6 +819,9 @@ es:
|
||||
submit: "Añadir"
|
||||
error: "Enlace no válido. Recuerda que debe empezar por %{url}."
|
||||
success: "Has añadido un nuevo contenido relacionado"
|
||||
is_related: "¿Es contenido relacionado?"
|
||||
score_positive: "Sí"
|
||||
score_negative: "No"
|
||||
content_title:
|
||||
proposal: "Propuesta"
|
||||
debate: "Debate"
|
||||
|
||||
@@ -464,8 +464,8 @@ Rails.application.routes.draw do
|
||||
|
||||
resources :related_contents, only: [:create] do
|
||||
member do
|
||||
put :flag
|
||||
put :unflag
|
||||
put :score_positive
|
||||
put :score_negative
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ section "Creating Settings" do
|
||||
Setting.create(key: 'map_latitude', value: 51.48)
|
||||
Setting.create(key: 'map_longitude', value: 0.0)
|
||||
Setting.create(key: 'map_zoom', value: 10)
|
||||
Setting.create(key: 'related_contents_report_threshold', value: 2)
|
||||
Setting.create(key: 'related_content_score_threshold', value: -0.3)
|
||||
end
|
||||
|
||||
section "Creating Geozones" do
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class RemoveRelatedContentsFlagsCount < ActiveRecord::Migration
|
||||
def change
|
||||
remove_column :related_contents, :flags_count
|
||||
end
|
||||
end
|
||||
11
db/migrate/20171219184209_create_related_content_scores.rb
Normal file
11
db/migrate/20171219184209_create_related_content_scores.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
class CreateRelatedContentScores < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :related_content_scores do |t|
|
||||
t.references :user, index: true, foreign_key: true
|
||||
t.references :related_content, index: true, foreign_key: true
|
||||
t.integer :value
|
||||
end
|
||||
|
||||
add_index :related_content_scores, [:user_id, :related_content_id], name: "unique_user_related_content_scoring", unique: true, using: :btree
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
class AddHiddenAtToRelatedContents < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :related_contents, :hidden_at, :datetime
|
||||
add_index :related_contents, :hidden_at
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddRelatedContentScoresCounterToRelatedContent < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :related_contents, :related_content_scores_count, :integer, default: 0
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddAuthorToRelatedContent < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :related_contents, :author_id, :integer
|
||||
end
|
||||
end
|
||||
19
db/schema.rb
19
db/schema.rb
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20171215152244) do
|
||||
ActiveRecord::Schema.define(version: 20171220010000) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
@@ -854,6 +854,16 @@ ActiveRecord::Schema.define(version: 20171215152244) do
|
||||
add_index "proposals", ["title"], name: "index_proposals_on_title", using: :btree
|
||||
add_index "proposals", ["tsv"], name: "index_proposals_on_tsv", using: :gin
|
||||
|
||||
create_table "related_content_scores", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
t.integer "related_content_id"
|
||||
t.integer "value"
|
||||
end
|
||||
|
||||
add_index "related_content_scores", ["related_content_id"], name: "index_related_content_scores_on_related_content_id", using: :btree
|
||||
add_index "related_content_scores", ["user_id", "related_content_id"], name: "unique_user_related_content_scoring", unique: true, using: :btree
|
||||
add_index "related_content_scores", ["user_id"], name: "index_related_content_scores_on_user_id", using: :btree
|
||||
|
||||
create_table "related_contents", force: :cascade do |t|
|
||||
t.integer "parent_relationable_id"
|
||||
t.string "parent_relationable_type"
|
||||
@@ -862,10 +872,13 @@ ActiveRecord::Schema.define(version: 20171215152244) do
|
||||
t.integer "related_content_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "flags_count", default: 0
|
||||
t.datetime "hidden_at"
|
||||
t.integer "related_content_scores_count", default: 0
|
||||
t.integer "author_id"
|
||||
end
|
||||
|
||||
add_index "related_contents", ["child_relationable_type", "child_relationable_id"], name: "index_related_contents_on_child_relationable", using: :btree
|
||||
add_index "related_contents", ["hidden_at"], name: "index_related_contents_on_hidden_at", using: :btree
|
||||
add_index "related_contents", ["parent_relationable_id", "parent_relationable_type", "child_relationable_id", "child_relationable_type"], name: "unique_parent_child_related_content", unique: true, using: :btree
|
||||
add_index "related_contents", ["parent_relationable_type", "parent_relationable_id"], name: "index_related_contents_on_parent_relationable", using: :btree
|
||||
add_index "related_contents", ["related_content_id"], name: "opposite_related_content", using: :btree
|
||||
@@ -1189,6 +1202,8 @@ ActiveRecord::Schema.define(version: 20171215152244) do
|
||||
add_foreign_key "poll_recounts", "poll_officer_assignments", column: "officer_assignment_id"
|
||||
add_foreign_key "poll_voters", "polls"
|
||||
add_foreign_key "proposals", "communities"
|
||||
add_foreign_key "related_content_scores", "related_contents"
|
||||
add_foreign_key "related_content_scores", "users"
|
||||
add_foreign_key "users", "geozones"
|
||||
add_foreign_key "valuators", "users"
|
||||
end
|
||||
|
||||
@@ -120,4 +120,4 @@ Setting['map_longitude'] = 0.0
|
||||
Setting['map_zoom'] = 10
|
||||
|
||||
# Related content
|
||||
Setting['related_contents_report_threshold'] = 5
|
||||
Setting['related_content_score_threshold'] = -0.3
|
||||
|
||||
@@ -18,7 +18,7 @@ describe RelatedContent do
|
||||
end
|
||||
|
||||
it "should not allow repeated related contents" do
|
||||
related_content = create(:related_content, parent_relationable: parent_relationable, child_relationable: child_relationable)
|
||||
related_content = create(:related_content, parent_relationable: parent_relationable, child_relationable: child_relationable, author: build(:user))
|
||||
new_related_content = build(:related_content, parent_relationable: related_content.parent_relationable, child_relationable: related_content.child_relationable)
|
||||
expect(new_related_content).not_to be_valid
|
||||
end
|
||||
@@ -26,7 +26,7 @@ describe RelatedContent do
|
||||
describe 'create_opposite_related_content' do
|
||||
let(:parent_relationable) { create(:proposal) }
|
||||
let(:child_relationable) { create(:debate) }
|
||||
let(:related_content) { build(:related_content, parent_relationable: parent_relationable, child_relationable: child_relationable) }
|
||||
let(:related_content) { build(:related_content, parent_relationable: parent_relationable, child_relationable: child_relationable, author: build(:user)) }
|
||||
|
||||
it 'creates an opposite related_content' do
|
||||
expect { related_content.save }.to change { RelatedContent.count }.by(2)
|
||||
@@ -38,32 +38,18 @@ describe RelatedContent do
|
||||
end
|
||||
end
|
||||
|
||||
describe 'relationable destroy' do
|
||||
let(:parent_relationable) { create(:proposal) }
|
||||
let(:child_relationable) { create(:debate) }
|
||||
|
||||
it 'destroys both related contents involved' do
|
||||
related_content = create(:related_content, parent_relationable: parent_relationable, child_relationable: child_relationable)
|
||||
expect { related_content.parent_relationable.destroy }.to change { RelatedContent.all.count }.by(-2)
|
||||
expect(child_relationable.related_contents).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: Move this into a Relationable shared context
|
||||
describe '#report_related_content' do
|
||||
it 'increments both relation and opposite relation flags_count counters' do
|
||||
related_content = create(:related_content, parent_relationable: parent_relationable, child_relationable: child_relationable)
|
||||
parent_relationable.report_related_content(child_relationable)
|
||||
|
||||
expect(related_content.reload.flags_count).to eq(1)
|
||||
expect(related_content.reload.opposite_related_content.flags_count).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#relationed_contents' do
|
||||
before do
|
||||
create(:related_content, parent_relationable: parent_relationable, child_relationable: create(:proposal), flags_count: 6)
|
||||
create(:related_content, parent_relationable: parent_relationable, child_relationable: child_relationable)
|
||||
related_content = create(:related_content, parent_relationable: parent_relationable, child_relationable: create(:proposal), author: build(:user))
|
||||
create(:related_content, parent_relationable: parent_relationable, child_relationable: child_relationable, author: build(:user))
|
||||
|
||||
2.times do
|
||||
related_content.send("score_positive", build(:user))
|
||||
end
|
||||
|
||||
6.times do
|
||||
related_content.send("score_negative", build(:user))
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns not hidden by reports related contents' do
|
||||
|
||||
@@ -6,7 +6,7 @@ shared_examples "relationable" do |relationable_model_name|
|
||||
let(:user) { create(:user) }
|
||||
|
||||
scenario 'related contents are listed' do
|
||||
related_content = create(:related_content, parent_relationable: relationable, child_relationable: related1)
|
||||
related_content = create(:related_content, parent_relationable: relationable, child_relationable: related1, author: build(:user))
|
||||
|
||||
visit eval("#{relationable.class.name.downcase}_path(relationable)")
|
||||
within("#related-content-list") do
|
||||
@@ -25,6 +25,7 @@ shared_examples "relationable" do |relationable_model_name|
|
||||
end
|
||||
|
||||
scenario 'related contents can be added' do
|
||||
login_as(user)
|
||||
visit eval("#{relationable.class.name.downcase}_path(relationable)")
|
||||
|
||||
expect(page).to have_selector('#related_content', visible: false)
|
||||
@@ -57,6 +58,7 @@ shared_examples "relationable" do |relationable_model_name|
|
||||
end
|
||||
|
||||
scenario 'if related content URL is invalid returns error' do
|
||||
login_as(user)
|
||||
visit eval("#{relationable.class.name.downcase}_path(relationable)")
|
||||
|
||||
click_on("Add related content")
|
||||
@@ -69,37 +71,54 @@ shared_examples "relationable" do |relationable_model_name|
|
||||
expect(page).to have_content("Link not valid. Remember to start with #{Setting[:url]}.")
|
||||
end
|
||||
|
||||
scenario 'related content can be flagged', :js do
|
||||
related_content = create(:related_content, parent_relationable: relationable, child_relationable: related1)
|
||||
scenario 'related content can be scored positively', :js do
|
||||
related_content = create(:related_content, parent_relationable: relationable, child_relationable: related1, author: build(:user))
|
||||
|
||||
login_as(user)
|
||||
visit eval("#{relationable.class.name.downcase}_path(relationable)")
|
||||
|
||||
within("#related-content-list") do
|
||||
expect(page).to have_css("#flag-expand-related-#{related_content.opposite_related_content.id}")
|
||||
find("#flag-expand-related-#{related_content.opposite_related_content.id}").click
|
||||
expect(page).to have_css("#flag-drop-related-#{related_content.opposite_related_content.id}", visible: true)
|
||||
click_link("flag-related-#{related_content.opposite_related_content.id}")
|
||||
|
||||
expect(page).to have_css("#unflag-expand-related-#{related_content.opposite_related_content.id}")
|
||||
find("#related-content-#{related_content.opposite_related_content.id}").hover
|
||||
find("#score-positive-related-#{related_content.opposite_related_content.id}").click
|
||||
expect(page).to_not have_css("#score-positive-related-#{related_content.opposite_related_content.id}")
|
||||
end
|
||||
|
||||
expect(related_content.reload.flags_count).to eq(1)
|
||||
expect(related_content.opposite_related_content.flags_count).to eq(1)
|
||||
expect(related_content.related_content_scores.find_by(user_id: user.id, related_content_id: related_content.id).value).to eq(1)
|
||||
expect(related_content.opposite_related_content.related_content_scores.find_by(user_id: user.id, related_content_id: related_content.opposite_related_content.id).value).to eq(1)
|
||||
|
||||
end
|
||||
|
||||
scenario 'if related content has been flagged more than 5 times it will be hidden', :js do
|
||||
related_content = create(:related_content, parent_relationable: relationable, child_relationable: related1)
|
||||
|
||||
related_content.flags_count = Setting['related_contents_report_threshold'].to_i + 1
|
||||
related_content.opposite_related_content.flags_count = related_content.flags_count
|
||||
|
||||
related_content.save
|
||||
related_content.opposite_related_content.save
|
||||
scenario 'related content can be scored negatively', :js do
|
||||
related_content = create(:related_content, parent_relationable: relationable, child_relationable: related1, author: build(:user))
|
||||
|
||||
login_as(user)
|
||||
visit eval("#{relationable.class.name.downcase}_path(relationable)")
|
||||
|
||||
within("#related-content-list") do
|
||||
find("#related-content-#{related_content.opposite_related_content.id}").hover
|
||||
find("#score-negative-related-#{related_content.opposite_related_content.id}").click
|
||||
expect(page).to_not have_css("#score-negative-related-#{related_content.opposite_related_content.id}")
|
||||
end
|
||||
|
||||
expect(related_content.related_content_scores.find_by(user_id: user.id, related_content_id: related_content.id).value).to eq(-1)
|
||||
expect(related_content.opposite_related_content.related_content_scores.find_by(user_id: user.id, related_content_id: related_content.opposite_related_content.id).value).to eq(-1)
|
||||
end
|
||||
|
||||
scenario 'if related content has negative score it will be hidden' do
|
||||
related_content = create(:related_content, parent_relationable: relationable, child_relationable: related1, author: build(:user))
|
||||
|
||||
2.times do
|
||||
related_content.send("score_positive", build(:user))
|
||||
end
|
||||
|
||||
6.times do
|
||||
related_content.send("score_negative", build(:user))
|
||||
end
|
||||
|
||||
login_as(user)
|
||||
|
||||
visit eval("#{relationable.class.name.downcase}_path(relationable)")
|
||||
|
||||
expect(page).to_not have_css("#related-content-list")
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user