Skip to content

AO3-5742 Fix work_skin_allowed validation never running#5928

Open
pmonfort wants to merge 3 commits into
otwcode:masterfrom
pmonfort:AO3-5742
Open

AO3-5742 Fix work_skin_allowed validation never running#5928
pmonfort wants to merge 3 commits into
otwcode:masterfrom
pmonfort:AO3-5742

Conversation

@pmonfort

Copy link
Copy Markdown
Contributor

Pull Request Checklist

Issue

https://otwarchive.atlassian.net/browse/AO3-5742

Purpose

The work_skin_allowed validation was declared with on: :save, which is not a standard Rails validation context. Rails only runs validations on :create and :update by default, so this validation never executed. This allowed a user to apply another user's private work skin by manipulating the form's skin dropdown value via Inspect Element.

This PR:

  • Removes the on: :save option so the validation runs on both create and update
  • Uses pseuds_after_saving instead of self.users to check skin ownership, so the validation works for both new (unsaved) and existing works. Only approved creatorships are considered, a pending co-author invitation does not grant access to that user's private skins
  • Removes the unused custom_work_skin factory (hardcoded work_skin_id: 1)
  • Rewrites specs to cover: no skin, approved skin, public but not official skin (author and non-author), private skin (author, other user, and pending co-author)

Testing Instructions

  1. Log in as User A
  2. Go to Dashboard > Skins > My Work Skins > Create Work Skin
  3. Create a skin with obvious CSS (e.g. `p { color: re the ID from the URL
  4. Log in as User B
  5. Go to Post > New Work and fill in required fields
  6. Use Inspect Element on the "Select Work Skin" dropd User A's skin ID
  7. Press "Preview" or "Post Without Preview"
  8. Verify you get the error: "You do not have permissi stylesheet."

Credit

Pablo Monfort (he/him)

@sarken sarken left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of nitpicking, but nothing really major!

Comment thread config/locales/models/en.yml Outdated
at_most: must not add up to more than %{count}. Your work has %{value} of these tags, so you must remove %{diff} of them.
blocked_gifts: "%{byline} does not accept gifts."
blocked_your_gifts: "%{byline} does not accept gifts from you."
work_skin_not_allowed: You do not have permission to use that custom work stylesheet.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's change this while we're here, since the current phrasing is not how we'd normally refer to work skins. Better text would be: "You do not have permission to use that work skin."

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good 👍

Comment thread app/models/work.rb Outdated
unless self.users.include?(self.work_skin.author) || (self.work_skin.public? && self.work_skin.official?)
errors.add(:base, ts("You do not have permission to use that custom work stylesheet."))
end
return if work_skin.blank?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we do return if work_skin.blank? || (work_skin.public? && work_skin.official?) here? I don't think there's any reason to we need to do pseuds_after_saving.filter_map(&:user).uniq if we know the work skin is public and official.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense 👍

Comment thread app/models/work.rb Outdated
end
return if work_skin.blank?

skin_users = pseuds_after_saving.filter_map(&:user).uniq

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see where this name is coming from: it serves as a list of users whose skins we should be allowed to use.

However, I think something like work_users, approved_work_creators, or work_users_after_saving might be better -- something like return if approved_work_creators.include?(work_skin.author) feels clearer than return if skin_users.include?(work_skin.author)

Comment thread spec/models/work_spec.rb Outdated
end
end

context "when the work skin is approved" do

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is public and official might be clearer than approved, especially since the next thing is public but not official.

(Should we also have a test for skins that are official but not public? I'm not 100% sure, but I think it might unfortunately be possible to put a skin in that state...)

@pmonfort pmonfort Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, I'm going to add test 👍

Comment thread spec/models/work_spec.rb Outdated
let(:work) { build(:custom_work_skin, authors: [@second_author.pseuds.first], work_skin_id: @private_skin.id) }
it "cannot be used by another user" do
work.work_skin_allowed
it "is invalid when the skin author is a pending co-author" do

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you change this to pending co-creator? Whenever possible in the code, we try to call people who make works "creators" instead of "authors" to be more inclusive of non-textual fanworks.

It would also be a good idea to add a test that confirms the work is valid when the skin author is an approved co-creator. (Users with the archivist role can add co-creators without waiting for approval from the co-creator.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense, adding the extra test 👍

Comment thread spec/models/work_spec.rb Outdated

it "is valid when used by the skin author" do
work = build(:work, authors: [skin_author.default_pseud], work_skin_id: skin.id)
work.valid?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of calling work.valid? in these examples, could we do expect(work).to be_valid and expect(work).to be_invalid as appropriate?

Comment thread spec/models/work_spec.rb Outdated

context "when the work skin is approved" do
it "is valid even when used by a different user" do
skin = create(:work_skin, author: skin_author, public: true, official: true)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think create(:work_skin, :public) should work here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense, thanks!

Comment thread spec/models/work_spec.rb
let(:work) { build(:custom_work_skin, authors: [work_author.pseuds.first], work_skin_id: @private_skin.id) }
it "can be used by the work skin author" do
expect(work.save).to be_truthy
context "when the work skin is public but not official" do

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It probably makes sense to include the same co-creator situations we cover for when the work skin is private here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, adding the test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants