diff --git a/app/controllers/post_replacements_controller.rb b/app/controllers/post_replacements_controller.rb
index 73e7d258a..b001b2e8d 100644
--- a/app/controllers/post_replacements_controller.rb
+++ b/app/controllers/post_replacements_controller.rb
@@ -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
diff --git a/app/helpers/post_replacement_helper.rb b/app/helpers/post_replacement_helper.rb
index 1a287c8f7..e8894b3a5 100644
--- a/app/helpers/post_replacement_helper.rb
+++ b/app/helpers/post_replacement_helper.rb
@@ -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
diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js
index a551f70b2..314d3bc7f 100644
--- a/app/javascript/packs/application.js
+++ b/app/javascript/packs/application.js
@@ -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';
diff --git a/app/javascript/src/javascripts/post_replacement.js b/app/javascript/src/javascripts/post_replacement.js
new file mode 100644
index 000000000..3e0c6e15e
--- /dev/null
+++ b/app/javascript/src/javascripts/post_replacement.js
@@ -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
diff --git a/app/logical/upload_service/replacer.rb b/app/logical/upload_service/replacer.rb
index d435e49c8..861a75297 100644
--- a/app/logical/upload_service/replacer.rb
+++ b/app/logical/upload_service/replacer.rb
@@ -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)
diff --git a/app/models/post_replacement.rb b/app/models/post_replacement.rb
index 4ecb98696..29c7b8ea0 100644
--- a/app/models/post_replacement.rb
+++ b/app/models/post_replacement.rb
@@ -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?
diff --git a/app/models/user.rb b/app/models/user.rb
index 22967487b..bd893d5a3 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -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(
diff --git a/app/presenters/user_presenter.rb b/app/presenters/user_presenter.rb
index afe402dc5..10b0e4cdb 100644
--- a/app/presenters/user_presenter.rb
+++ b/app/presenters/user_presenter.rb
@@ -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
diff --git a/app/views/post_replacements/_search.html.erb b/app/views/post_replacements/_search.html.erb
index c488e3157..57d21666f 100644
--- a/app/views/post_replacements/_search.html.erb
+++ b/app/views/post_replacements/_search.html.erb
@@ -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 %>
diff --git a/app/views/post_replacements/index.html.erb b/app/views/post_replacements/index.html.erb
index 38a7bd663..64257480b 100644
--- a/app/views/post_replacements/index.html.erb
+++ b/app/views/post_replacements/index.html.erb
@@ -70,6 +70,14 @@
Reason
<%= post_replacement.reason %>
<% if post_replacement.status == 'approved' %>
+ Original Uploader
+
+ <%= 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} %>
+ <% end %>
+
Approver
<%= link_to_user post_replacement.approver %>
<% end %>
@@ -84,9 +92,15 @@
<% if CurrentUser.is_janitor? %>
- <%= link_to "Approve", approve_post_replacement_path(post_replacement), method: :PUT %>
- <%= link_to "Reject", reject_post_replacement_path(post_replacement), method: :PUT %>
- <%= link_to "As New Post", promote_post_replacement_path(post_replacement), method: :PUT %>
+ <% 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} %>
+ <%= link_to "Approve", "#approve", class: "replacement-approve-action", data: { replacement_id: post_replacement.id, penalize: false} %>
+ <%= link_to "Reject", "#reject", class: "replacement-reject-action", data: { replacement_id: post_replacement.id} %>
+ <%= link_to "As New Post", "#promote", class: "replacement-promote-action", data: { replacement_id: post_replacement.id} %>
+ <% end %>
+ <% if post_replacement.status == "original" %>
+ <%= link_to "Reset To", "#approve", class: "replacement-approve-action", data: { replacement_id: post_replacement.id, penalize: false} %>
+ <% 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?' %>
diff --git a/app/views/users/_statistics.html.erb b/app/views/users/_statistics.html.erb
index 920ccbaf8..979b0e18b 100644
--- a/app/views/users/_statistics.html.erb
+++ b/app/views/users/_statistics.html.erb
@@ -57,12 +57,13 @@
|
- Deleted Posts |
+ Deleted/Replaced Posts |
<%= 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) %>
|
Post Changes |
diff --git a/config/routes.rb b/config/routes.rb
index a2dd8bed7..f6728c481 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -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]
diff --git a/db/migrate/20210625155528_add_replacement_audit_stats.rb b/db/migrate/20210625155528_add_replacement_audit_stats.rb
new file mode 100644
index 000000000..e7a161a96
--- /dev/null
+++ b/db/migrate/20210625155528_add_replacement_audit_stats.rb
@@ -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
diff --git a/db/structure.sql b/db/structure.sql
index 261914176..dad12bd03 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -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');
diff --git a/script/fixes/103_fill_new_post_replacement_fields.rb b/script/fixes/103_fill_new_post_replacement_fields.rb
new file mode 100644
index 000000000..66b5f21a9
--- /dev/null
+++ b/script/fixes/103_fill_new_post_replacement_fields.rb
@@ -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
diff --git a/test/functional/post_replacements_controller_test.rb b/test/functional/post_replacements_controller_test.rb
index bacd5fd4a..4486d3967 100644
--- a/test/functional/post_replacements_controller_test.rb
+++ b/test/functional/post_replacements_controller_test.rb
@@ -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
diff --git a/test/unit/post_replacement_test.rb b/test/unit/post_replacement_test.rb
index 77f6771e3..603895655 100644
--- a/test/unit/post_replacement_test.rb
+++ b/test/unit/post_replacement_test.rb
@@ -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
|