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