Merge pull request #284 from Earlopain/replacements-audit

Add replacement tracking for uploader
This commit is contained in:
Zwagoth 2022-01-02 19:56:10 -05:00 committed by GitHub
commit 0d531ff146
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 382 additions and 57 deletions

View File

@ -1,7 +1,7 @@
class PostReplacementsController < ApplicationController
respond_to :html
respond_to :html, :json
before_action :moderator_only, only: [:destroy]
before_action :janitor_only, only: [:create, :new, :approve, :reject, :promote]
before_action :janitor_only, only: [:create, :new, :approve, :reject, :promote, :toggle_penalize]
content_security_policy only: [:new] do |p|
p.img_src :self, :data, "*"
end
@ -15,48 +15,57 @@ class PostReplacementsController < ApplicationController
def create
@post = Post.find(params[:post_id])
@post_replacement = @post.replacements.create(create_params.merge(creator_id: CurrentUser.id, creator_ip_addr: CurrentUser.ip_addr))
if @post_replacement.errors.size == 0
flash[:notice] = "Post replacement submitted"
else
if @post_replacement.errors.any?
flash[:notice] = @post_replacement.errors.full_messages.join('; ')
else
flash[:notice] = "Post replacement submitted"
end
respond_with(@post_replacement, location: @post)
end
def approve
@post_replacement = PostReplacement.find(params[:id])
@post_replacement.approve!
@post_replacement.approve!(penalize_current_uploader: params[:penalize_current_uploader])
respond_with(@post_replacement, location: post_path(@post_replacement.post))
end
def toggle_penalize
@post_replacement = PostReplacement.find(params[:id])
@post_replacement.toggle_penalize!
respond_with(@post_replacement)
end
def reject
@post_replacement = PostReplacement.find(params[:id])
@post_replacement.reject!
respond_with(@post_replacement)
respond_with(@post_replacement, location: post_path(@post_replacement.post))
end
def destroy
@post_replacement = PostReplacement.find(params[:id])
@post_replacement.destroy
respond_with(@post_replacement)
respond_with(@post_replacement, location: post_path(@post_replacement.post))
end
def promote
@post_replacement = PostReplacement.find(params[:id])
@post = @post_replacement.promote!
if @post.errors.any?
respond_with(@post)
@upload = @post_replacement.promote!
if @post_replacement.errors.any?
respond_with(@post_replacement)
elsif @upload.errors.any?
respond_with(@upload)
else
respond_with(@post.post)
respond_with(@upload.post)
end
end
def index
params[:search][:post_id] = params.delete(:post_id) if params.has_key?(:post_id)
@post_replacements = PostReplacement.visible(CurrentUser.user).search(search_params).paginate(params[:page], limit: params[:limit])
@post_replacements = PostReplacement.includes(:post).visible(CurrentUser.user).search(search_params).paginate(params[:page], limit: params[:limit])
respond_with(@post_replacements)
end

View File

@ -1,6 +1,10 @@
module PostReplacementHelper
def replacement_thumbnail(replacement)
return tag.a(image_tag(replacement.replacement_thumb_url), href: replacement.replacement_file_url) if replacement.file_visible_to?(CurrentUser.user)
image_tag(replacement.replacement_thumb_url)
if replacement.post.deleteblocked?
image_tag(Danbooru.config.deleted_preview_url)
else
image_tag(replacement.replacement_thumb_url)
end
end
end

View File

@ -37,6 +37,7 @@ export { default as Note } from '../src/javascripts/notes.js';
export { default as Post } from '../src/javascripts/posts.js';
export { default as PostDeletion } from "../src/javascripts/post_delete.js";
export { default as PostModeMenu } from '../src/javascripts/post_mode_menu.js';
export { default as PostReplacement } from '../src/javascripts/post_replacement.js';
export { default as PostVersions } from '../src/javascripts/post_versions.js';
export { default as RelatedTag } from '../src/javascripts/related_tag.js';
export { default as Shortcuts } from '../src/javascripts/shortcuts.js';

View File

@ -0,0 +1,82 @@
import Utility from './utility'
let PostReplacement = {};
PostReplacement.initialize_all = function () {
$(".replacement-approve-action").on("click", e => {
const target = $(e.target);
e.preventDefault();
PostReplacement.approve(target.data("replacement-id"), target.data("penalize"));
});
$(".replacement-reject-action").on("click", e => {
e.preventDefault();
PostReplacement.reject($(e.target).data("replacement-id"));
});
$(".replacement-promote-action").on("click", e => {
e.preventDefault();
PostReplacement.promote($(e.target).data("replacement-id"));
});
$(".replacement-toggle-penalize-action").on("click", e => {
e.preventDefault();
PostReplacement.toggle_penalize($(e.target).data("replacement-id"));
});
};
PostReplacement.approve = function (id, penalize_current_uploader) {
$.ajax({
type: "PUT",
url: `/post_replacements/${id}/approve.json`,
data: {
penalize_current_uploader: penalize_current_uploader
},
dataType: 'json'
}).done(function () {
Utility.notice("Post Replacement accepted");
}).fail(function (data, status, xhr) {
Utility.error(data.responseText);
});
};
PostReplacement.reject = function (id) {
$.ajax({
type: "PUT",
url: `/post_replacements/${id}/reject.json`,
dataType: 'json'
}).done(function () {
Utility.notice("Post Replacement rejected");
}).fail(function (data, status, xhr) {
Utility.error(data.responseText);
});
}
PostReplacement.promote = function (id) {
$.ajax({
type: "POST",
url: `/post_replacements/${id}/promote.json`,
dataType: 'json'
}).done(function (data) {
Utility.notice(`Replacement promoted to post #${data.post.id}`)
}).fail(function (data, status, xhr) {
Utility.error(data.responseText);
});
}
PostReplacement.toggle_penalize = function (id) {
$.ajax({
type: "PUT",
url: `/post_replacements/${id}/toggle_penalize.json`,
dataType: 'json'
}).done(function (data) {
Utility.notice("User upload limit updated");
}).fail(function (data, status, xhr) {
Utility.error(data.responseText);
});
}
$(function () {
if ($("#c-post-replacements").length)
PostReplacement.initialize_all();
});
export default PostReplacement

View File

@ -35,7 +35,7 @@ class UploadService
raise ProcessingError, "Could not create post file backup?" if !repl.valid?
end
def process!
def process!(penalize_current_uploader:)
# Prevent trying to replace deleted posts
raise ProcessingError, "Cannot replace post: post is deleted." if post.is_deleted?
@ -76,6 +76,8 @@ class UploadService
post.generated_samples = nil
end
previous_uploader = post.uploader_id
post.md5 = upload.md5
post.file_ext = upload.file_ext
post.image_width = upload.image_width
@ -88,10 +90,22 @@ class UploadService
post.uploader_ip_addr = replacement.creator_ip_addr
post.save!
# rescaling notes reloads the post, be careful when accessing previous values
rescale_notes(post)
update_ugoira_frame_data(post, upload)
replacement.update({status: 'approved', approver_id: CurrentUser.id})
replacement.update({
status: 'approved',
approver_id: CurrentUser.id,
uploader_id_on_approve: previous_uploader,
penalize_uploader_on_approve: penalize_current_uploader.to_s.truthy?
})
UserStatus.for_user(previous_uploader).update_all("own_post_replaced_count = own_post_replaced_count + 1")
if penalize_current_uploader.to_s.truthy?
UserStatus.for_user(previous_uploader).update_all("own_post_replaced_penalize_count = own_post_replaced_penalize_count + 1")
end
if post.is_video?
post.generate_video_samples(later: true)

View File

@ -3,6 +3,7 @@ class PostReplacement < ApplicationRecord
belongs_to :post
belongs_to :creator, class_name: "User"
belongs_to :approver, class_name: "User", optional: true
belongs_to :uploader_on_approve, class_name: "User", foreign_key: :uploader_id_on_approve, optional: true
attr_accessor :replacement_file, :replacement_url, :final_source, :tags, :is_backup
validate :user_is_not_limited, on: :create
@ -168,33 +169,63 @@ class PostReplacement < ApplicationRecord
module ApiMethods
def hidden_attributes
super + [:storage_id]
super + %i[storage_id protected uploader_id_on_approve penalize_uploader_on_approve]
end
end
module ProcessingMethods
def approve!
def approve!(penalize_current_uploader:)
unless ["pending", "original"].include? status
errors.add(:status, "must be pending or original to approve")
return
end
transaction do
ModAction.log(:post_replacement_accept, {post_id: post.id, replacement_id: self.id, old_md5: post.md5, new_md5: self.md5})
processor = UploadService::Replacer.new(post: post, replacement: self)
processor.process!
processor.process!(penalize_current_uploader: penalize_current_uploader)
end
post.update_index
end
def toggle_penalize!
if status != "approved"
errors.add(:status, "must be approved to penalize")
return
end
if penalize_uploader_on_approve
UserStatus.for_user(uploader_on_approve).update_all("own_post_replaced_penalize_count = own_post_replaced_penalize_count - 1")
else
UserStatus.for_user(uploader_on_approve).update_all("own_post_replaced_penalize_count = own_post_replaced_penalize_count + 1")
end
update_attribute(:penalize_uploader_on_approve, !penalize_uploader_on_approve)
end
def promote!
if status != "pending"
errors.add(:status, "must be pending to promote")
return
end
transaction do
processor = UploadService.new(new_upload_params)
new_post = processor.start!
new_upload = processor.start!
update_attribute(:status, 'promoted')
new_post
new_upload
end
post.update_index
end
def reject!
if status != "pending"
errors.add(:status, "must be pending to reject")
return
end
ModAction.log(:post_replacement_reject, {post_id: post.id, replacement_id: self.id})
update_attribute(:status, 'rejected')
UserStatus.for_user(creator_id).update_all("post_replacement_rejected_count = post_replacement_rejected_count + 1")
post.update_index
end
end
@ -226,15 +257,23 @@ class PostReplacement < ApplicationRecord
q = q.attribute_exact_matches(:status, params[:status])
if params[:creator_id].present?
q = q.where(creator_id: params[:creator_id].split(",").map(&:to_i))
q = q.where("creator_id in (?)", params[:creator_id].split(",").first(100).map(&:to_i))
end
if params[:creator_name].present?
q = q.where(creator_id: User.name_to_id(params[:creator_name]))
q = q.where("creator_id = ?", User.name_to_id(params[:creator_name]))
end
if params[:uploader_id_on_approve].present?
q = q.where("uploader_id_on_approve in (?)", params[:uploader_id_on_approve].split(",").first(100).map(&:to_i))
end
if params[:uploader_name_on_approve].present?
q = q.where("uploader_id_on_approve = ?", User.name_to_id(params[:uploader_name_on_approve]))
end
if params[:post_id].present?
q = q.where(post_id: params[:post_id].split(",").map(&:to_i))
q = q.where("post_id in (?)", params[:post_id].split(",").first(100).map(&:to_i))
end
@ -257,6 +296,18 @@ class PostReplacement < ApplicationRecord
where(creator_id: id.to_i)
end
def for_uploader_on_approve(id)
where(uploader_id_on_approve: id.to_i)
end
def penalized
where(penalize_uploader_on_approve: true)
end
def not_penalized
where(penalize_uploader_on_approve: false)
end
def visible(user)
return where('status != ?', 'rejected') if user.is_anonymous?
return all if user.is_janitor?

View File

@ -584,7 +584,8 @@ class User < ApplicationRecord
def upload_limit_pieces
deleted_count = Post.deleted.for_user(id).count
rejected_replacement_count = PostReplacement.rejected.for_user(id).count
rejected_replacement_count = post_replacement_rejected_count
replaced_penalize_count = own_post_replaced_penalize_count
unapproved_count = Post.pending_or_flagged.for_user(id).count
unapproved_replacements_count = PostReplacement.pending.for_user(id).count
approved_count = Post.for_user(id).where('is_flagged = false AND is_deleted = false AND is_pending = false').count
@ -758,6 +759,18 @@ class User < ApplicationRecord
feedback.negative.count
end
def post_replacement_rejected_count
user_status.post_replacement_rejected_count
end
def own_post_replaced_count
user_status.own_post_replaced_count
end
def own_post_replaced_penalize_count
user_status.own_post_replaced_penalize_count
end
def refresh_counts!
self.class.without_timeout do
UserStatus.where(user_id: id).update_all(

View File

@ -78,6 +78,10 @@ class UserPresenter
template.link_to(user.post_deleted_count, template.deleted_posts_path(user_id: user.id))
end
def replaced_upload_count(template)
template.link_to(user.own_post_replaced_count, template.post_replacements_path(search: {uploader_name_on_approve: user.name}))
end
def favorite_count(template)
template.link_to(user.favorite_count, template.favorites_path(:user_id => user.id))
end

View File

@ -2,6 +2,7 @@
<%= f.input :md5, label: "MD5", input_html: { value: params.dig(:search, :md5) } %>
<%= f.input :creator_name, label: "Creator", input_html: { value: params.dig(:search, :creator_name) } %>
<%= f.input :post_id, label: "Post ID", input_html: { value: params.dig(:search, :post_id) } %>
<%= f.input :uploader_name_on_approve, label: "Uploader on Approve", input_html: { value: params.dig(:search, :uploader_name_on_approve) } %>
<%= f.input :status, label: "status", collection: ["pending", "rejected", "approved", "promoted"], include_blank: true, selected: params.dig(:search, :status) %>
<%= f.submit "Search" %>
<% end %>

View File

@ -70,6 +70,14 @@
<dt>Reason</dt>
<dd><%= post_replacement.reason %></dd>
<% if post_replacement.status == 'approved' %>
<dt>Original Uploader</dt>
<dd>
<%= link_to_user post_replacement.uploader_on_approve %>
<% if CurrentUser.is_janitor? %>
| penalized: <%= post_replacement.penalize_uploader_on_approve ? "yes" : "no" %>
<%= link_to "toggle", "#toggle", class: "replacement-toggle-penalize-action", data: { replacement_id: post_replacement.id} %><br>
<% end %>
</dd>
<dt>Approver</dt>
<dd><%= link_to_user post_replacement.approver %></dd>
<% end %>
@ -84,9 +92,15 @@
<td>
<% if CurrentUser.is_janitor? %>
<%= link_to "Approve", approve_post_replacement_path(post_replacement), method: :PUT %><br>
<%= link_to "Reject", reject_post_replacement_path(post_replacement), method: :PUT %><br>
<%= link_to "As New Post", promote_post_replacement_path(post_replacement), method: :PUT %><br>
<% if post_replacement.status == "pending"%>
<%= link_to "Approve And Penalize Current Uploader", "#approve", class: "replacement-approve-action", data: { replacement_id: post_replacement.id, penalize: true} %><br>
<%= link_to "Approve", "#approve", class: "replacement-approve-action", data: { replacement_id: post_replacement.id, penalize: false} %><br>
<%= link_to "Reject", "#reject", class: "replacement-reject-action", data: { replacement_id: post_replacement.id} %><br>
<%= link_to "As New Post", "#promote", class: "replacement-promote-action", data: { replacement_id: post_replacement.id} %><br>
<% end %>
<% if post_replacement.status == "original" %>
<%= link_to "Reset To", "#approve", class: "replacement-approve-action", data: { replacement_id: post_replacement.id, penalize: false} %><br>
<% end %>
<% end %>
<% if CurrentUser.is_moderator? %>
<%= link_to "Destroy", post_replacement_path(post_replacement), method: :DELETE, 'data-confirm': 'Are you sure you want to destroy this replacement?' %>

View File

@ -57,12 +57,13 @@
</tr>
<tr>
<th>Deleted Posts</th>
<th>Deleted/Replaced Posts</th>
<td>
<%= presenter.deleted_upload_count(self) %>
<% if CurrentUser.is_moderator? %>
[<%= link_to "sample", posts_path(:tags => "user:#{user.name} order:random limit:300 status:deleted") %>]
<% end %>
/ <%= presenter.replaced_upload_count(self) %>
</td>
<th>Post Changes</th>
<td>

View File

@ -250,7 +250,8 @@ Rails.application.routes.draw do
member do
put :approve
put :reject
put :promote
post :promote
put :toggle_penalize
end
end
resources :deleted_posts, only: [:index]

View File

@ -0,0 +1,9 @@
class AddReplacementAuditStats < ActiveRecord::Migration[6.1]
def change
add_column :post_replacements2, :uploader_id_on_approve, :int
add_column :post_replacements2, :penalize_uploader_on_approve, :boolean
add_column :user_statuses, :own_post_replaced_count, :int, nil: false, default: 0
add_column :user_statuses, :own_post_replaced_penalize_count, :int, nil: false, default: 0
add_column :user_statuses, :post_replacement_rejected_count, :int, nil: false, default: 0
end
end

View File

@ -1638,7 +1638,9 @@ CREATE TABLE public.post_replacements2 (
storage_id character varying NOT NULL,
status character varying DEFAULT 'pending'::character varying NOT NULL,
reason character varying NOT NULL,
protected boolean DEFAULT false NOT NULL
protected boolean DEFAULT false NOT NULL,
uploader_id_on_approve integer,
penalize_uploader_on_approve boolean
);
@ -2588,7 +2590,10 @@ CREATE TABLE public.user_statuses (
pool_edit_count integer DEFAULT 0 NOT NULL,
blip_count integer DEFAULT 0 NOT NULL,
set_count integer DEFAULT 0 NOT NULL,
artist_edit_count integer DEFAULT 0 NOT NULL
artist_edit_count integer DEFAULT 0 NOT NULL,
own_post_replaced_count integer DEFAULT 0,
own_post_replaced_penalize_count integer DEFAULT 0,
post_replacement_rejected_count integer DEFAULT 0
);
@ -5263,6 +5268,6 @@ INSERT INTO "schema_migrations" (version) VALUES
('20210426025625'),
('20210430201028'),
('20210506235640'),
('20210718172512');
('20210718172512'),
('20210625155528');

View File

@ -0,0 +1,24 @@
#!/usr/bin/env ruby
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'config', 'environment'))
UserStatus.find_each do |user_status|
user_status.update_column(:post_replacement_rejected_count, PostReplacement.rejected.for_user(user_status.user.id).count)
end
# post ids who have two replacements, one approved, one original
PostReplacement.select(:post_id).where(status: ["approved", "original"]).group(:post_id)
.having("count(post_id) = 2").map(&:post_id).each do |post_id|
replacements = PostReplacement.where(post_id: post_id).order(:status)
approved = replacements[0]
original = replacements[1]
approved.uploader_id_on_approve = original.creator_id
approved.penalize_uploader_on_approve = true
approved.save!
user_status = UserStatus.for_user(original.creator_id)
user_status.update_all("own_post_replaced_count = own_post_replaced_count + 1")
user_status.update_all("own_post_replaced_penalize_count = own_post_replaced_penalize_count + 1")
end

View File

@ -3,11 +3,11 @@ require 'test_helper'
class PostReplacementsControllerTest < ActionDispatch::IntegrationTest
setup do
Sidekiq::Testing::inline!
Sidekiq::Testing.inline!
end
teardown do
Sidekiq::Testing::fake!
Sidekiq::Testing.fake!
end
context "The post replacements controller" do
@ -43,7 +43,7 @@ class PostReplacementsControllerTest < ActionDispatch::IntegrationTest
context "reject action" do
should "reject replacement" do
put_auth reject_post_replacement_path(@replacement), @user
assert_redirected_to post_replacement_path(@replacement)
assert_redirected_to post_path(@post)
@replacement.reload
@post.reload
assert_equal @replacement.status, "rejected"
@ -64,7 +64,7 @@ class PostReplacementsControllerTest < ActionDispatch::IntegrationTest
context "promote action" do
should "create post" do
put_auth promote_post_replacement_path(@replacement), @user
post_auth promote_post_replacement_path(@replacement), @user
last_post = Post.last
assert_redirected_to post_path(last_post)
@replacement.reload
@ -74,6 +74,18 @@ class PostReplacementsControllerTest < ActionDispatch::IntegrationTest
end
end
context "toggle action" do
should "change penalize_uploader flag" do
put_auth approve_post_replacement_path(@replacement, penalize_current_uploader: true), @user
@replacement.reload
assert @replacement.penalize_uploader_on_approve
put_auth toggle_penalize_post_replacement_path(@replacement), @user
assert_redirected_to post_replacement_path(@replacement)
@replacement.reload
assert !@replacement.penalize_uploader_on_approve
end
end
context "index action" do
should "render" do
get post_replacements_path

View File

@ -77,7 +77,7 @@ class PostReplacementTest < ActiveSupport::TestCase
end
should "affect user upload limit" do
assert_difference("PostReplacement.pending.for_user(@user.id).count", 1) do
assert_difference(->{PostReplacement.pending.for_user(@user.id).count}, 1) do
@replacement = @post.replacements.create(FactoryBot.attributes_for(:png_replacement).merge(creator: @user, creator_ip_addr: '127.0.0.1'))
end
end
@ -109,10 +109,26 @@ class PostReplacementTest < ActiveSupport::TestCase
end
should "give user back their upload slot" do
assert_difference("PostReplacement.pending.for_user(@user.id).count", -1) do
assert_difference(->{PostReplacement.pending.for_user(@user.id).count}, -1) do
@replacement.reject!
end
end
should "increment the users rejected replacements count" do
assert_difference(->{@user.post_replacement_rejected_count}, 1) do
assert_difference(->{PostReplacement.rejected.for_user(@user.id).count}, 1) do
@replacement.reject!
@user.reload
end
end
end
should "work only once for pending replacements" do
@replacement.reject!
assert_equal [], @replacement.errors.full_messages
@replacement.reject!
assert_equal ["Status must be pending to reject"], @replacement.errors.full_messages
end
end
context "Approve:" do
@ -124,20 +140,21 @@ class PostReplacementTest < ActiveSupport::TestCase
should "create a mod action" do
assert_difference("ModAction.count") do
@replacement.approve!
@replacement.approve! penalize_current_uploader: true
end
end
should "fail if post cannot be backed up" do
@post.md5 = "123" # Breaks file path, should force backup to fail.
assert_raise(ProcessingError) do
@replacement.approve!
@replacement.approve! penalize_current_uploader: true
end
end
should "update post with new image" do
old_md5 = @post.md5
@replacement.approve!
@replacement.approve! penalize_current_uploader: true
@post.reload
assert_not_equal @post.md5, old_md5
assert_equal @replacement.image_width, @post.image_width
@ -151,25 +168,25 @@ class PostReplacementTest < ActiveSupport::TestCase
should "generate videos samples if replacement is video" do
@replacement = FactoryBot.create(:webm_replacement, creator: @user, creator_ip_addr: '127.0.0.1', post: @post)
@post.expects(:generate_video_samples).times(1)
@replacement.approve!
@replacement.approve! penalize_current_uploader: true
end
should "delete original files immediately" do
sm = Danbooru.config.storage_manager
old_md5 = @post.md5
old_ext = @post.file_ext
@replacement.approve!
@replacement.approve! penalize_current_uploader: true
@post.reload
assert_not File.exists?(sm.file_path(old_md5, old_ext, :original))
assert_not File.exists?(sm.file_path(old_md5, old_ext, :preview))
assert_not File.exists?(sm.file_path(old_md5, old_ext, :large))
assert_not File.exists?(sm.file_path(old_md5, old_ext, :original, protected=true))
assert_not File.exist?(sm.file_path(old_md5, old_ext, :original))
assert_not File.exist?(sm.file_path(old_md5, old_ext, :preview))
assert_not File.exist?(sm.file_path(old_md5, old_ext, :large))
assert_not File.exist?(sm.file_path(old_md5, old_ext, :original, protected=true))
end
should "not be able to approve on deleted post" do
@post.update_column(:is_deleted, true)
assert_raise ProcessingError do
@replacement.approve!
@replacement.approve! penalize_current_uploader: true
end
end
@ -177,7 +194,7 @@ class PostReplacementTest < ActiveSupport::TestCase
old_md5 = @post.md5
old_source = @post.source
assert_difference("@post.replacements.size", 1) do
@replacement.approve!
@replacement.approve! penalize_current_uploader: true
end
new_replacement = @post.replacements.last
assert_equal 'original', new_replacement.status
@ -187,21 +204,78 @@ class PostReplacementTest < ActiveSupport::TestCase
end
should "update users upload counts" do
assert_difference("Post.for_user(@mod_user.id).where('is_flagged = false AND is_deleted = false AND is_pending = false').count", -1) do
assert_difference("Post.for_user(@user.id).where('is_flagged = false AND is_deleted = false AND is_pending = false').count", 1) do
@replacement.approve!
assert_difference(->{Post.for_user(@mod_user.id).where('is_flagged = false AND is_deleted = false AND is_pending = false').count}, -1) do
assert_difference(->{Post.for_user(@user.id).where('is_flagged = false AND is_deleted = false AND is_pending = false').count}, 1) do
@replacement.approve! penalize_current_uploader: true
end
end
end
should "update the original users upload limit if penalized" do
assert_difference(->{@mod_user.own_post_replaced_count}, 1) do
assert_difference(->{@mod_user.own_post_replaced_penalize_count}, 1) do
assert_difference(->{PostReplacement.penalized.for_uploader_on_approve(@mod_user.id).count}, 1) do
@replacement.approve! penalize_current_uploader: true
@mod_user.reload
end
end
end
end
should "not update the original users upload limit if not penalizing" do
assert_difference(-> {@mod_user.own_post_replaced_count}, 1) do
assert_difference(->{@mod_user.own_post_replaced_penalize_count}, 0) do
assert_difference(->{PostReplacement.not_penalized.for_uploader_on_approve(@mod_user.id).count}, 1) do
@replacement.approve! penalize_current_uploader: false
@mod_user.reload
end
end
end
end
should "correctly resize the posts notes" do
@replacement.approve!
@replacement.approve! penalize_current_uploader: true
@note.reload
assert_equal 153, @note.x
assert_equal 611, @note.y
assert_equal 153, @note.width
assert_equal 152, @note.height
end
should "only work on pending or original replacements" do
@replacement.reject!
@replacement.approve! penalize_current_uploader: false
assert_equal(["Status must be pending or original to approve"], @replacement.errors.full_messages)
end
should "only work once" do
@replacement.approve! penalize_current_uploader: false
assert_equal [], @replacement.errors.full_messages
@replacement.approve! penalize_current_uploader: false
assert_equal ["Status must be pending or original to approve"], @replacement.errors.full_messages
end
end
context "Toggle:" do
setup do
@replacement = FactoryBot.create(:png_replacement, creator: @user, creator_ip_addr: '127.0.0.1', post: @post)
assert @replacement
end
should "change the users upload limit" do
@replacement.approve! penalize_current_uploader: false
assert_difference(->{@mod_user.own_post_replaced_penalize_count}, 1) do
assert_difference(->{PostReplacement.penalized.for_uploader_on_approve(@mod_user.id).count}, 1) do
@replacement.toggle_penalize!
@mod_user.reload
end
end
end
should "only work on appoved replacements" do
@replacement.toggle_penalize!
assert_equal(["Status must be approved to penalize"], @replacement.errors.full_messages)
end
end
context "Promote:" do
@ -226,8 +300,8 @@ class PostReplacementTest < ActiveSupport::TestCase
end
should "credit replacer with new post" do
assert_difference("Post.for_user(@mod_user.id).where('is_flagged = false AND is_deleted = false AND is_pending = false').count", 0) do
assert_difference("Post.for_user(@user.id).where('is_flagged = false AND is_deleted = false').count", 1) do
assert_difference(->{Post.for_user(@mod_user.id).where('is_flagged = false AND is_deleted = false AND is_pending = false').count}, 0) do
assert_difference(->{Post.for_user(@user.id).where('is_flagged = false AND is_deleted = false').count}, 1) do
post = @replacement.promote!
assert post
assert_equal [], post.errors.full_messages
@ -235,5 +309,11 @@ class PostReplacementTest < ActiveSupport::TestCase
end
end
end
should "only work on pending replacements" do
@replacement.approve! penalize_current_uploader: false
@replacement.promote!
assert_equal(["Status must be pending to promote"], @replacement.errors.full_messages)
end
end
end