diff --git a/app/controllers/related_works_controller.rb b/app/controllers/related_works_controller.rb index b7409407343..d189c8544bd 100644 --- a/app/controllers/related_works_controller.rb +++ b/app/controllers/related_works_controller.rb @@ -6,19 +6,16 @@ class RelatedWorksController < ApplicationController def index @page_subtitle = t(".page_title", login: @user.login) - @translations_of_user = @user.related_works.posted.where(translation: true) - @remixes_of_user = @user.related_works.posted.where(translation: false) - @translations_by_user = @user.parent_work_relationships.posted.where(translation: true) - @remixes_by_user = @user.parent_work_relationships.posted.where(translation: false) - return if @user == current_user + related_works = @user.related_works.visible_on_user_page(@user).visible_works + parent_work_relationships = @user.parent_work_relationships.visible_on_user_page(@user) + local_parent_work_relationships = parent_work_relationships.of_visible_local_works + external_parent_work_relationships = parent_work_relationships.of_visible_external_works - # Extra constraints on what we display if someone else is viewing @user's - # related works page: - @translations_of_user = @translations_of_user.merge(Work.revealed.non_anon).where(reciprocal: true) - @remixes_of_user = @remixes_of_user.merge(Work.revealed.non_anon).where(reciprocal: true) - @translations_by_user = @translations_by_user.merge(Work.revealed.non_anon).where(reciprocal: true) - @remixes_by_user = @remixes_by_user.merge(Work.revealed.non_anon).where(reciprocal: true) + @translations_of_user = related_works.translations + @remixes_of_user = related_works.remixes + @translations_by_user = (local_parent_work_relationships.translations + external_parent_work_relationships.translations).sort + @remixes_by_user = (local_parent_work_relationships.remixes + external_parent_work_relationships.remixes).sort end # GET /related_works/1 diff --git a/app/helpers/related_works_helper.rb b/app/helpers/related_works_helper.rb new file mode 100644 index 00000000000..d08df01c198 --- /dev/null +++ b/app/helpers/related_works_helper.rb @@ -0,0 +1,10 @@ +module RelatedWorksHelper + def related_works_count(user) + related_works = user.related_works.visible_on_user_page(user).visible_works + parent_work_relationships = user.parent_work_relationships.visible_on_user_page(user) + local_parent_work_relationships = parent_work_relationships.of_visible_local_works + external_parent_work_relationships = parent_work_relationships.of_visible_external_works + + related_works.count + local_parent_work_relationships.count + external_parent_work_relationships.count + end +end diff --git a/app/models/related_work.rb b/app/models/related_work.rb index 97d7dc4a4d9..064497572e8 100644 --- a/app/models/related_work.rb +++ b/app/models/related_work.rb @@ -7,9 +7,69 @@ class RelatedWork < ActiveRecord::Base attribute :author, :string attribute :language_id, :integer - scope :posted, -> { - joins("INNER JOIN `works` `child_works` ON `child_works`.`id` = `related_works`.`work_id`"). - where("child_works.posted = 1") + scope :translations, -> { where(translation: true) } + scope :remixes, -> { where(translation: false) } + scope :reciprocal, -> { where(reciprocal: true) } + + scope :posted, lambda { + joins("INNER JOIN works child_works ON child_works.id = related_works.work_id") + .where("child_works.posted = 1") + } + + def self.visible_on_user_page(user) + case User.current_user + when user || is_a?(Admin) + posted.merge(Work.unhidden) + when is_a?(User) + posted.reciprocal.merge(Work.unhidden.revealed.non_anon) + else + posted.reciprocal.merge(Work.unhidden.revealed.non_anon.unrestricted) + end + end + + scope :unhidden, lambda { + joins("INNER JOIN works child_works ON child_works.id = related_works.work_id") + .where("child_works.hidden_by_admin = false") + } + + scope :unrestricted, lambda { + joins("INNER JOIN works child_works ON child_works.id = related_works.work_id") + .where("child_works.restricted = false") + } + + scope :visible_works, lambda { + if User.current_user.present? + unhidden + else + unhidden.unrestricted + end + } + + # Separate scopes for local and external parent works to make tests work + # (the join in of_unhidden_local_works gets both local and external works + # in web environments, but only local ones in automated tests) + + scope :of_local_works, -> { where(parent_type: Work) } + scope :of_external_works, -> { where(parent_type: ExternalWork) } + + scope :of_unhidden_local_works, lambda { + of_local_works + .joins("INNER JOIN works parent_works ON parent_works.id = related_works.parent_id") + .where("parent_works.hidden_by_admin = false") + } + + scope :of_visible_local_works, lambda { + if User.current_user.present? + of_unhidden_local_works + else + of_unhidden_local_works.where("parent_works.restricted = false") + end + } + + scope :of_visible_external_works, lambda { + of_external_works + .joins("INNER JOIN external_works parent_works ON parent_works.id = related_works.parent_id") + .where("parent_works.hidden_by_admin = false") } before_validation :set_parent, if: :new_record? diff --git a/app/views/users/_sidebar.html.erb b/app/views/users/_sidebar.html.erb index c5836c303a2..7b23c7b1589 100644 --- a/app/views/users/_sidebar.html.erb +++ b/app/views/users/_sidebar.html.erb @@ -61,7 +61,7 @@
  • <%= span_if_current t(".switch.sign_ups", signup_number: @user.challenge_signups.count), user_signups_path(@user) %>
  • <%= span_if_current t(".switch.assignments", assignment_number: @user.assignments.unposted.undefaulted.count), user_assignments_path(@user) %>
  • <%= span_if_current t(".switch.claims", claim_number: @user.request_claims.unposted.count), user_claims_path(@user) %>
  • -
  • <%= span_if_current t(".switch.related_works", related_works_number: (@user.related_works.posted.count + @user.parent_work_relationships.count)), user_related_works_path(@user) %>
  • +
  • <%= span_if_current t(".switch.related_works", related_works_number: related_works_count(@user)), user_related_works_path(@user) %>
  • <% end %>
  • <%= gifts_link(@user) %>
  • diff --git a/features/works/work_related.feature b/features/works/work_related.feature index b68699c495c..8e783abd52e 100644 --- a/features/works/work_related.feature +++ b/features/works/work_related.feature @@ -349,6 +349,54 @@ Scenario: Restricted works listed as Inspiration show up [Restricted] for guests And I view the work "Followup" Then I should see "Inspired by [Restricted Work] by inspiration" +Scenario: Restricted inspired and inspiring works should not be listed on related work pages for guests + Given I have related works setup + And a related work has been posted and approved + # Restricted inspired work + When I am logged in as "remixer" + And I lock the work "Followup" + When I log out + And I go to inspiration's related works page + Then I should not see "Followup" + And I should not see "Worldbuilding" + When I go to remixer's related works page + Then I should not see "Followup" + And I should not see "Worldbuilding" + # Restricted inspiration + When I am logged in as "remixer" + And I unlock the work "Followup" + When I am logged in as "inspiration" + And I lock the work "Worldbuilding" + When I log out + And I go to inspiration's related works page + Then I should not see "Followup" + And I should not see "Worldbuilding" + When I go to remixer's related works page + Then I should not see "Followup" + And I should not see "Worldbuilding" + +Scenario: Restricted translations and translated works should not be listed on related work pages for guests + Given I have related works setup + And a translation has been posted and approved + # Restricted translation + When I am logged in as "translator" + And I lock the work "Worldbuilding Translated" + When I log out + And I go to inspiration's related works page + Then I should not see "Worldbuilding" + When I go to translator's related works page + Then I should not see "Worldbuilding" + # Restricted translated work + When I am logged in as "translator" + And I unlock the work "Worldbuilding Translated" + When I am logged in as "inspiration" + And I lock the work "Worldbuilding" + When I log out + And I go to inspiration's related works page + Then I should not see "Worldbuilding" + When I go to translator's related works page + Then I should not see "Worldbuilding" + Scenario: Anonymous works listed as inspiration should have links to the authors, but only for the authors themselves and admins Given I have related works setup @@ -373,6 +421,84 @@ Scenario: Anonymous works listed as inspiration should have links to the authors Then I should see "Works inspired by this one: Followup by Anonymous" And I should not see "remixer" within ".afterword .children" +Scenario: Hidden inspired and inspiring works should not be listed on related work pages + Given I have related works setup + And a related work has been posted and approved + # Hidden inspired work + When I am logged in as a "policy_and_abuse" admin + And I hide the work "Followup" + And I go to inspiration's related works page + Then I should not see "Followup" + When I go to remixer's related works page + Then I should not see "Followup" + When I am logged in as "remixer" + And I view my related works + Then I should see "Related Works (0)" + And I should not see "Followup" + When I go to inspiration's related works page + Then I should not see "Followup" + When I am logged in as "inspiration" + And I view my related works + Then I should see "Related Works (0)" + And I should not see "Followup" + # Hidden inspiration + When I am logged in as a "policy_and_abuse" admin + And I unhide the work "Followup" + And I hide the work "Worldbuilding" + And I go to inspiration's related works page + Then I should not see "Worldbuilding" + When I go to remixer's related works page + Then I should not see "Worldbuilding" + When I am logged in as "inspiration" + And I view my related works + Then I should see "Related Works (0)" + And I should not see "Worldbuilding" + When I go to remixer's related works page + Then I should not see "Worldbuilding" + When I am logged in as "remixer" + And I view my related works + Then I should see "Related Works (0)" + And I should not see "Worldbuilding" + +Scenario: Hidden translations and translated works should not be listed on related work pages + Given I have related works setup + And a translation has been posted and approved + # Hidden translation + When I am logged in as a "policy_and_abuse" admin + And I hide the work "Worldbuilding Translated" + And I go to inspiration's related works page + Then I should not see "Worldbuilding Translated" + When I go to translator's related works page + Then I should not see "Worldbuilding Translated" + When I am logged in as "translator" + And I view my related works + Then I should see "Related Works (0)" + And I should not see "Worldbuilding Translated" + When I go to inspiration's related works page + Then I should not see "Worldbuilding Translated" + When I am logged in as "inspiration" + And I view my related works + Then I should see "Related Works (0)" + And I should not see "Worldbuilding Translated" + # Hidden translated work + When I am logged in as a "policy_and_abuse" admin + And I unhide the work "Worldbuilding Translated" + And I hide the work "Worldbuilding" + And I go to inspiration's related works page + Then I should not see "Worldbuilding" + When I go to translator's related works page + Then I should not see "Worldbuilding" + When I am logged in as "inspiration" + And I view my related works + Then I should see "Related Works (0)" + And I should not see "Worldbuilding" + When I go to translator's related works page + Then I should not see "Worldbuilding" + When I am logged in as "translator" + And I view my related works + Then I should see "Related Works (0)" + And I should not see "Worldbuilding" + Scenario: When a user is notified that a co-authored work has been inspired by a work they posted, the e-mail should link to each author's URL instead of showing escaped HTML Given I have related works setup