From a5418abb31927bb2f1e74be24866bd99f74433d3 Mon Sep 17 00:00:00 2001 From: evazion Date: Fri, 20 Mar 2020 01:55:51 -0500 Subject: [PATCH] pundit: convert posts to pundit. --- app/controllers/posts_controller.rb | 45 ++++-------- app/policies/post_policy.rb | 68 +++++++++++++++++++ app/views/comments/_index_by_comment.html.erb | 2 +- .../comments/partials/index/_header.html.erb | 2 +- app/views/favorites/_update.js.erb | 2 +- app/views/posts/index.html.erb | 2 +- .../partials/common/_secondary_links.html.erb | 8 ++- .../posts/partials/index/_mode_menu.html.erb | 2 +- .../posts/partials/index/_options.html.erb | 2 +- app/views/posts/partials/show/_edit.html.erb | 12 ++-- app/views/posts/partials/show/_image.html.erb | 2 +- .../posts/partials/show/_information.html.erb | 6 +- .../posts/partials/show/_notices.html.erb | 4 +- .../posts/partials/show/_options.html.erb | 28 +++++--- app/views/posts/show.html+tooltip.erb | 2 +- app/views/posts/show.html.erb | 16 +++-- test/functional/posts_controller_test.rb | 45 +++++++++++- test/unit/post_test.rb | 25 ------- 18 files changed, 178 insertions(+), 95 deletions(-) create mode 100644 app/policies/post_policy.rb diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 39e270b8b..722ef96a8 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -1,17 +1,17 @@ class PostsController < ApplicationController - before_action :member_only, :except => [:show, :show_seq, :index, :home, :random] respond_to :html, :xml, :json, :js layout "sidebar" def index if params[:md5].present? - @post = Post.find_by!(md5: params[:md5]) + @post = authorize Post.find_by!(md5: params[:md5]) respond_with(@post) do |format| format.html { redirect_to(@post) } end else + tag_query = params[:tags] || params.dig(:post, :tags) @post_set = PostSets::Post.new(tag_query, params[:page], params[:limit], raw: params[:raw], random: params[:random], format: params[:format]) - @posts = @post_set.posts + @posts = authorize @post_set.posts respond_with(@posts) do |format| format.atom end @@ -19,7 +19,7 @@ class PostsController < ApplicationController end def show - @post = Post.find(params[:id]) + @post = authorize Post.find(params[:id]) if request.format.html? @comments = @post.comments @@ -41,6 +41,7 @@ class PostsController < ApplicationController end def show_seq + authorize Post context = PostSearchContext.new(params) if context.post_id redirect_to(post_path(context.post_id, q: params[:q])) @@ -50,19 +51,15 @@ class PostsController < ApplicationController end def update - @post = Post.find(params[:id]) - - @post.update(post_params) if @post.visible? + @post = authorize Post.find(params[:id]) + @post.update(permitted_attributes(@post)) respond_with_post_after_update(@post) end def revert - @post = Post.find(params[:id]) + @post = authorize Post.find(params[:id]) @version = @post.versions.find(params[:version_id]) - - if @post.visible? - @post.revert_to!(@version) - end + @post.revert_to!(@version) respond_with(@post) do |format| format.js @@ -71,7 +68,7 @@ class PostsController < ApplicationController def copy_notes @post = Post.find(params[:id]) - @other_post = Post.find(params[:other_post_id].to_i) + @other_post = authorize Post.find(params[:other_post_id].to_i) @post.copy_notes_to(@other_post) if @post.errors.any? @@ -83,7 +80,7 @@ class PostsController < ApplicationController end def random - @post = Post.tag_match(params[:tags]).random + @post = authorize Post.tag_match(params[:tags]).random raise ActiveRecord::RecordNotFound if @post.nil? respond_with(@post) do |format| format.html { redirect_to post_path(@post, :tags => params[:tags]) } @@ -91,17 +88,13 @@ class PostsController < ApplicationController end def mark_as_translated - @post = Post.find(params[:id]) + @post = authorize Post.find(params[:id]) @post.mark_as_translated(params[:post]) respond_with_post_after_update(@post) end private - def tag_query - params[:tags] || (params[:post] && params[:post][:tags]) - end - def respond_with_post_after_update(post) respond_with(post) do |format| format.html do @@ -124,18 +117,4 @@ class PostsController < ApplicationController end end end - - def post_params - permitted_params = %i[ - tag_string old_tag_string - parent_id old_parent_id - source old_source - rating old_rating - has_embedded_notes - ] - permitted_params += %i[is_rating_locked is_note_locked] if CurrentUser.is_builder? - permitted_params += %i[is_status_locked] if CurrentUser.is_admin? - - params.require(:post).permit(permitted_params) - end end diff --git a/app/policies/post_policy.rb b/app/policies/post_policy.rb new file mode 100644 index 000000000..c173dc86c --- /dev/null +++ b/app/policies/post_policy.rb @@ -0,0 +1,68 @@ +class PostPolicy < ApplicationPolicy + def show_seq? + true + end + + def random? + true + end + + def update? + unbanned? && record.visible? + end + + def revert? + update? + end + + def copy_notes? + update? + end + + def mark_as_translated? + update? + end + + def visible? + record.visible? + end + + def can_view_uploader? + user.is_moderator? + end + + def can_lock_rating? + user.is_builder? + end + + def can_lock_notes? + user.is_builder? + end + + def can_lock_status? + user.is_admin? + end + + def can_use_mode_menu? + user.is_gold? + end + + def can_view_favlist? + user.is_gold? + end + + # whether to show the + - links in the tag list. + def show_extra_links? + user.is_gold? + end + + def permitted_attributes + [ + :tag_string, :old_tag_string, :parent_id, :old_parent_id, + :source, :old_source, :rating, :old_rating, :has_embedded_notes, + (:is_rating_locked if can_lock_rating?), + (:is_noted_locked if can_lock_notes?), + (:is_status_locked if can_lock_status?), + ].compact + end +end diff --git a/app/views/comments/_index_by_comment.html.erb b/app/views/comments/_index_by_comment.html.erb index 8acbeeda9..43bbb6bb6 100644 --- a/app/views/comments/_index_by_comment.html.erb +++ b/app/views/comments/_index_by_comment.html.erb @@ -4,7 +4,7 @@ <% if CurrentUser.is_moderator? || (params[:search] && params[:search][:is_deleted] =~ /t/) || !comment.is_deleted? %> <%= content_tag(:div, { id: "post_#{comment.post.id}", class: ["post", *PostPresenter.preview_class(comment.post)].join(" ") }.merge(PostPresenter.data_attributes(comment.post))) do %>
- <% if comment.post.visible? %> + <% if policy(comment.post).visible? %> <%= link_to(image_tag(comment.post.preview_file_url), post_path(comment.post)) %> <% end %>
diff --git a/app/views/comments/partials/index/_header.html.erb b/app/views/comments/partials/index/_header.html.erb index 7fc70b676..86211bf0b 100644 --- a/app/views/comments/partials/index/_header.html.erb +++ b/app/views/comments/partials/index/_header.html.erb @@ -4,7 +4,7 @@ Date <%= compact_time(post.created_at) %> - <% if CurrentUser.is_moderator? %> + <% if policy(post).can_view_uploader? %> User <%= link_to_user(post.uploader) %> diff --git a/app/views/favorites/_update.js.erb b/app/views/favorites/_update.js.erb index 5cf305e87..ebea2bcb9 100644 --- a/app/views/favorites/_update.js.erb +++ b/app/views/favorites/_update.js.erb @@ -4,7 +4,7 @@ $("#score-for-post-<%= @post.id %>").text(<%= @post.score %>); $("#favcount-for-post-<%= @post.id %>").text(<%= @post.fav_count %>); $(".fav-buttons").toggleClass("fav-buttons-false").toggleClass("fav-buttons-true"); -<% if CurrentUser.is_gold? %> +<% if policy(@post).can_view_favlist? %> var fav_count = <%= @post.fav_count %>; $("#favlist").html("<%= j post_favlist(@post) %>"); diff --git a/app/views/posts/index.html.erb b/app/views/posts/index.html.erb index 2c03d877b..5eb8b27c7 100644 --- a/app/views/posts/index.html.erb +++ b/app/views/posts/index.html.erb @@ -7,7 +7,7 @@

Tags

- <%= @post_set.presenter.tag_list_html(current_query: params[:tags], show_extra_links: CurrentUser.user.is_gold?) %> + <%= @post_set.presenter.tag_list_html(current_query: params[:tags], show_extra_links: policy(Post).show_extra_links?) %>
<% if Danbooru.config.addthis_key.present? %> diff --git a/app/views/posts/partials/common/_secondary_links.html.erb b/app/views/posts/partials/common/_secondary_links.html.erb index ef9f3ba72..6d9613491 100644 --- a/app/views/posts/partials/common/_secondary_links.html.erb +++ b/app/views/posts/partials/common/_secondary_links.html.erb @@ -5,13 +5,17 @@ <% if RecommenderService.available_for_user?(CurrentUser.user) %> <%= subnav_link_to "Recommended", recommended_posts_path(search: { user_name: CurrentUser.name }) %> <% end %> - <% unless CurrentUser.is_anonymous? %> + <% if policy(Favorite).create? %> <%= subnav_link_to "Favorites", posts_path(tags: "ordfav:#{CurrentUser.user.name}") %> + <% end %> + <% if policy(FavoriteGroup).create? %> <%= subnav_link_to "Fav groups", favorite_groups_path(search: { creator_name: CurrentUser.name }) %> + <% end %> + <% if policy(SavedSearch).create? %> <%= subnav_link_to "Saved searches", posts_path(tags: "search:all") %> <% end %> <%= subnav_link_to "Changes", post_versions_path %> - <% if CurrentUser.can_approve_posts? %> + <% if policy(PostApproval).create? %> <%= subnav_link_to "Modqueue", modqueue_index_path %> <% end %> <%= subnav_link_to "Help", wiki_page_path("help:posts") %> diff --git a/app/views/posts/partials/index/_mode_menu.html.erb b/app/views/posts/partials/index/_mode_menu.html.erb index 724772e37..3f42e70c4 100644 --- a/app/views/posts/partials/index/_mode_menu.html.erb +++ b/app/views/posts/partials/index/_mode_menu.html.erb @@ -1,4 +1,4 @@ -<% if CurrentUser.is_gold? %> +<% if policy(Post).can_use_mode_menu? %>

Mode

diff --git a/app/views/posts/partials/index/_options.html.erb b/app/views/posts/partials/index/_options.html.erb index bd0b653c6..3f8b0e7b2 100644 --- a/app/views/posts/partials/index/_options.html.erb +++ b/app/views/posts/partials/index/_options.html.erb @@ -1,7 +1,7 @@

Options

    - <% if CurrentUser.is_member? %> + <% if policy(SavedSearch).create? %>
  • <%= button_tag(tag.i(class: "fas fa-bookmark") + " Save search", id: "save-search", class: "ui-button ui-widget ui-corner-all sub") %>
  • <% end %>
diff --git a/app/views/posts/partials/show/_edit.html.erb b/app/views/posts/partials/show/_edit.html.erb index 683124e7e..295c1f22d 100644 --- a/app/views/posts/partials/show/_edit.html.erb +++ b/app/views/posts/partials/show/_edit.html.erb @@ -26,13 +26,17 @@ <%= f.input :has_embedded_notes, label: "Embed notes", as: :boolean, boolean_style: :inline, disabled: post.is_note_locked? %> - <% if CurrentUser.is_builder? %> + <% if policy(post).can_lock_rating? || policy(post).can_lock_notes? || policy(post).can_lock_status? %>
- <%= f.input :is_rating_locked, label: "Rating", as: :boolean, boolean_style: :inline %> - <%= f.input :is_note_locked, label: "Notes", as: :boolean, boolean_style: :inline %> - <% if CurrentUser.is_admin? %> + <% if policy(post).can_lock_rating? %> + <%= f.input :is_rating_locked, label: "Rating", as: :boolean, boolean_style: :inline %> + <% end %> + <% if policy(post).can_lock_notes? %> + <%= f.input :is_note_locked, label: "Notes", as: :boolean, boolean_style: :inline %> + <% end %> + <% if policy(post).can_lock_status? %> <%= f.input :is_status_locked, label: "Status", as: :boolean, boolean_style: :inline %> <% end %>
diff --git a/app/views/posts/partials/show/_image.html.erb b/app/views/posts/partials/show/_image.html.erb index 6255a146a..6d60c2f4c 100644 --- a/app/views/posts/partials/show/_image.html.erb +++ b/app/views/posts/partials/show/_image.html.erb @@ -1,3 +1,3 @@ -<% if post.visible? %> +<% if policy(post).visible? %> <%= image_tag(post.file_url_for(CurrentUser.user), :width => post.image_width_for(CurrentUser.user), :height => post.image_height_for(CurrentUser.user), :id => "image", "data-original-width" => post.image_width, "data-original-height" => post.image_height, "data-large-width" => post.large_image_width, "data-large-height" => post.large_image_height, "data-tags" => post.tag_string, :alt => post.presenter.humanized_essential_tag_string, "data-uploader" => post.uploader.name, "data-rating" => post.rating, "data-flags" => post.status_flags, "data-parent-id" => post.parent_id, "data-has-children" => post.has_children?, "data-has-active-children" => post.has_active_children?, "data-score" => post.score, "data-fav-count" => post.fav_count, "itemprop" => "contentUrl") %> <% end %> diff --git a/app/views/posts/partials/show/_information.html.erb b/app/views/posts/partials/show/_information.html.erb index e4a596eae..d4ee57820 100644 --- a/app/views/posts/partials/show/_information.html.erb +++ b/app/views/posts/partials/show/_information.html.erb @@ -1,6 +1,6 @@
  • ID: <%= post.id %>
  • - <% if CurrentUser.is_moderator? %> + <% if policy(post).can_view_uploader? %>
  • Uploader: <%= link_to_user(post.uploader) %>
  • <% end %>
  • @@ -11,7 +11,7 @@
  • Approver: <%= link_to_user(post.approver) %>
  • <% end %>
  • - Size: <%= link_to_if post.visible?, number_to_human_size(post.file_size), post.tagged_file_url %> + Size: <%= link_to_if policy(post).visible?, number_to_human_size(post.file_size), post.tagged_file_url %> <% if post.has_dimensions? %> (<%= post.image_width %>x<%= post.image_height %>) <% end %> @@ -31,7 +31,7 @@ <% end %>
  • Favorites: <%= post.fav_count %> - <% if CurrentUser.is_gold? %> + <% if policy(post).can_view_favlist? %> <%= link_to "Show »", "#", id: "show-favlist-link", style: ("display: none;" if post.fav_count == 0) %> <%= link_to "« Hide", "#", id: "hide-favlist-link", style: "display: none;" %> diff --git a/app/views/posts/partials/show/_notices.html.erb b/app/views/posts/partials/show/_notices.html.erb index 849cfa0db..c34441759 100644 --- a/app/views/posts/partials/show/_notices.html.erb +++ b/app/views/posts/partials/show/_notices.html.erb @@ -41,7 +41,7 @@ <%= render "post_disapprovals/counts", :disapprovals => post.disapprovals, :post => post %> - <% if CurrentUser.can_approve_posts? && !post.disapproved_by?(CurrentUser.user) %> + <% if policy(PostDisapproval).create? && !post.disapproved_by?(CurrentUser.user) %> <%= render "modqueue/quick_mod", post: post %> <%= render "post_disapprovals/detailed_rejection_dialog" %> <% end %> @@ -67,7 +67,7 @@ <% end %> -<% if post.visible? && post.has_large? && !post.is_ugoira? %> +<% if policy(post).visible? && post.has_large? && !post.is_ugoira? %>
    "> Resized to <%= number_to_percentage post.resize_percentage.floor, :precision => 0 %> of original (<%= link_to "view original", post.tagged_file_url, :id => "image-resize-link" %>) Loading... diff --git a/app/views/posts/partials/show/_options.html.erb b/app/views/posts/partials/show/_options.html.erb index 38960796f..8371313c2 100644 --- a/app/views/posts/partials/show/_options.html.erb +++ b/app/views/posts/partials/show/_options.html.erb @@ -7,17 +7,21 @@
  • <%= link_to "Find similar", iqdb_queries_path(post_id: post.id) %>
  • -
  • - <%= link_to_if post.visible?, "Download", post.tagged_file_url + "?download=1", download: post.presenter.filename_for_download %> -
  • + <% if policy(post).visible? %> +
  • + <%= link_to "Download", post.tagged_file_url + "?download=1", download: post.presenter.filename_for_download %> +
  • + <% end %> - <% if CurrentUser.is_member? %> + <% if policy(Favorite).create? %>
  • <%= link_to "Favorite", favorites_path(post_id: post.id), remote: true, method: :post, id: "add-to-favorites", "data-shortcut": "f", style: ("display: none;" if @post.is_favorited?) %>
  • <%= link_to "Unfavorite", favorite_path(post), remote: true, method: :delete, id: "remove-from-favorites", "data-shortcut": "shift+f", style: ("display: none;" if !@post.is_favorited?) %>
  • + <% end %> + <% if policy(post).update? %>
  • <%= link_to "Edit", "#edit", id: "side-edit-link" %>
  • <%= link_to "Add to pool", "#", id: "pool" %>
  • @@ -31,18 +35,21 @@
  • <%= link_to "Copy notes", "#", id: "copy-notes" %>
  • <% end %>
  • <%= link_to "Add commentary", "#", id: "add-commentary" %>
  • + <% end %> + <% if policy(FavoriteGroup).create? %>
  • <%= link_to "Add to fav group", "#", id: "open-favgroup-dialog-link", "data-shortcut": "g" %>
  • + <% end %> <% if post.is_status_locked? %>
  • Status locked
  • <% else %> - <% if !post.is_deleted? && !post.is_pending? && !post.is_flagged? %> + <% if (!post.is_deleted? && !post.is_pending? && !post.is_flagged?) && policy(PostFlag).create? %>
  • <%= link_to "Flag", new_post_flag_path(post_flag: { post_id: post.id }), remote: true %>
  • - <% elsif post.is_flagged? || post.is_deleted? %> + <% elsif (post.is_flagged? || post.is_deleted?) && policy(PostAppeal).create? %>
  • <%= link_to "Appeal", new_post_appeal_path(post_appeal: { post_id: post.id }), remote: true %>
  • <% end %> - <% if CurrentUser.can_approve_posts? %> + <% if policy(PostApproval).create? %> <% if post.is_deleted? %>
  • <%= link_to "Undelete", post_approvals_path(post_id: post.id), remote: true, method: :post, "data-confirm": "Are you sure you want to undelete this post?" %>
  • <% if post.fav_count > 0 && post.parent_id %> @@ -66,11 +73,10 @@ <% if CurrentUser.is_admin? %>
  • <%= link_to "Expunge", expunge_moderator_post_post_path(post_id: post.id), remote: true, method: :post, "data-confirm": "This will permanently delete this post (meaning the file will be deleted). Are you sure you want to delete this post?" %>
  • <% end %> + <% end %> - <% if CurrentUser.is_moderator? %> -
  • <%= link_to "Replace image", new_post_replacement_path(post_id: post.id), remote: true %>
  • - <% end %> + <% if policy(PostReplacement).create? %> +
  • <%= link_to "Replace image", new_post_replacement_path(post_id: post.id), remote: true %>
  • <% end %> <% end %> - <% end %>
diff --git a/app/views/posts/show.html+tooltip.erb b/app/views/posts/show.html+tooltip.erb index 520662ad5..80b6b74cb 100644 --- a/app/views/posts/show.html+tooltip.erb +++ b/app/views/posts/show.html+tooltip.erb @@ -1,6 +1,6 @@
- <% if CurrentUser.is_moderator? %> + <% if policy(@post).can_view_uploader? %> <%= link_to_user @post.uploader %> <% end %> diff --git a/app/views/posts/show.html.erb b/app/views/posts/show.html.erb index 71a60c601..890709b9e 100644 --- a/app/views/posts/show.html.erb +++ b/app/views/posts/show.html.erb @@ -10,7 +10,7 @@ <%= render "posts/partials/index/blacklist" %>
- <%= @post.presenter.split_tag_list_html(current_query: params[:q], show_extra_links: CurrentUser.user.is_gold?) %> + <%= @post.presenter.split_tag_list_html(current_query: params[:q], show_extra_links: policy(@post).show_extra_links?) %>
@@ -108,7 +108,7 @@
  • Recommended
  • <% end %> - <% if CurrentUser.is_member? && @post.visible? %> + <% if policy(@post).update? %>
  • Edit
  • <% end %> @@ -134,22 +134,26 @@ <% end %>
    - <% if CurrentUser.is_member? && @post.visible? %> + <% if policy(@post).update? %> <% end %> <% end %> -<% if CurrentUser.is_member? %> +<% if policy(Pool).create? %> +<% end %> +<% if policy(ArtistCommentary).create_or_update? %> +<% end %> +<% if policy(FavoriteGroup).create? %> @@ -161,7 +165,7 @@ - <% if @post.visible? %> + <% if policy(@post).visible? %> <%= tag.meta name: "og:image", content: @post.open_graph_image_url %> <% end %> @@ -170,7 +174,7 @@ <% if @post.twitter_card_supported? %> - <% if @post.visible? %> + <% if policy(@post).visible? %> <%= tag.meta name: "twitter:image", content: @post.open_graph_image_url %> <% end %> <% end %> diff --git a/test/functional/posts_controller_test.rb b/test/functional/posts_controller_test.rb index 3c1398d76..4a3b387a7 100644 --- a/test/functional/posts_controller_test.rb +++ b/test/functional/posts_controller_test.rb @@ -36,7 +36,7 @@ class PostsControllerTest < ActionDispatch::IntegrationTest get posts_path, params: { tags: "bkub" } assert_response :success - artist.update(is_banned: false, is_active: false) + artist.update(is_banned: false, is_deleted: true) get posts_path, params: { tags: "bkub" } assert_response :success @@ -258,6 +258,13 @@ class PostsControllerTest < ActionDispatch::IntegrationTest put_auth post_path(@post), @user, params: {:post => {:last_noted_at => 1.minute.ago}} assert_nil(@post.reload.last_noted_at) end + + should "not allow unprivileged users to update restricted posts" do + as(@user) { @post.update!(is_banned: true) } + put_auth post_path(@post), @user, params: { post: { tag_string: "blah" }} + assert_response 403 + assert_not_equal("blah", @post.reload.tag_string) + end end context "revert action" do @@ -288,5 +295,41 @@ class PostsControllerTest < ActionDispatch::IntegrationTest assert_response :missing end end + + context "copy_notes action" do + setup do + as(@user) do + @src = create(:post, image_width: 100, image_height: 100, tag_string: "translated partially_translated", has_embedded_notes: true) + @dst = create(:post, image_width: 200, image_height: 200, tag_string: "translation_request") + create(:note, post: @src, x: 10, y: 10, width: 10, height: 10, body: "test") + create(:note, post: @src, x: 10, y: 10, width: 10, height: 10, body: "deleted", is_active: false) + end + end + + should "copy notes and tags" do + put_auth copy_notes_post_path(@src), @user, params: { other_post_id: @dst.id } + assert_response :success + + assert_equal(1, @dst.reload.notes.active.length) + assert_equal(true, @dst.has_embedded_notes) + assert_equal("lowres partially_translated translated", @dst.tag_string) + end + + should "rescale notes" do + put_auth copy_notes_post_path(@src), @user, params: { other_post_id: @dst.id } + assert_response :success + + note = @dst.notes.active.first + assert_equal([20, 20, 20, 20], [note.x, note.y, note.width, note.height]) + end + end + + context "mark_as_translated action" do + should "mark the post as translated" do + put_auth mark_as_translated_post_path(@post), @user, params: { post: { check_translation: false, partially_translated: false }} + assert_redirected_to @post + assert(@post.reload.has_tag?("translated")) + end + end end end diff --git a/test/unit/post_test.rb b/test/unit/post_test.rb index 3985ec857..5fceed12e 100644 --- a/test/unit/post_test.rb +++ b/test/unit/post_test.rb @@ -2792,31 +2792,6 @@ class PostTest < ActiveSupport::TestCase end end - context "Notes:" do - context "#copy_notes_to" do - setup do - @src = FactoryBot.create(:post, image_width: 100, image_height: 100, tag_string: "translated partially_translated", has_embedded_notes: true) - @dst = FactoryBot.create(:post, image_width: 200, image_height: 200, tag_string: "translation_request") - - create(:note, post: @src, x: 10, y: 10, width: 10, height: 10, body: "test") - create(:note, post: @src, x: 10, y: 10, width: 10, height: 10, body: "deleted", is_active: false) - - @src.reload.copy_notes_to(@dst) - end - - should "copy notes and tags" do - assert_equal(1, @dst.notes.active.length) - assert_equal(true, @dst.has_embedded_notes) - assert_equal("lowres partially_translated translated", @dst.tag_string) - end - - should "rescale notes" do - note = @dst.notes.active.first - assert_equal([20, 20, 20, 20], [note.x, note.y, note.width, note.height]) - end - end - end - context "#replace!" do subject { @post.replace!(tags: "something", replacement_url: "https://danbooru.donmai.us/images/download-preview.png") }