uploads: replace old upload limits with new upload limits.
This commit is contained in:
1
Gemfile
1
Gemfile
@@ -14,7 +14,6 @@ gem 'ruby-vips'
|
||||
gem 'net-sftp'
|
||||
gem 'diff-lcs', :require => "diff/lcs/array"
|
||||
gem 'bcrypt', :require => "bcrypt"
|
||||
gem 'statistics2'
|
||||
gem 'capistrano', '~> 3.10'
|
||||
gem 'capistrano-rails'
|
||||
gem 'capistrano-rbenv'
|
||||
|
||||
@@ -361,7 +361,6 @@ GEM
|
||||
net-scp (>= 1.1.2)
|
||||
net-ssh (>= 2.8.0)
|
||||
stackprof (0.2.15)
|
||||
statistics2 (0.54)
|
||||
streamio-ffmpeg (3.0.2)
|
||||
multi_json (~> 1.8)
|
||||
stripe (5.14.0)
|
||||
@@ -466,7 +465,6 @@ DEPENDENCIES
|
||||
simplecov
|
||||
sinatra
|
||||
stackprof
|
||||
statistics2
|
||||
streamio-ffmpeg
|
||||
stripe
|
||||
unicorn
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
class DanbooruMath
|
||||
def self.ci_lower_bound(pos, n, confidence = 0.95)
|
||||
if n == 0
|
||||
return 0
|
||||
end
|
||||
|
||||
z = Statistics2.pnormaldist(1 - (1 - confidence) / 2)
|
||||
phat = 1.0 * pos / n
|
||||
100 * (phat + z * z / (2 * n) - z * Math.sqrt((phat * (1 - phat) + z * z / (4 * n)) / n)) / (1 + z * z / n)
|
||||
end
|
||||
end
|
||||
@@ -11,7 +11,23 @@ class UploadLimit
|
||||
end
|
||||
|
||||
def limited?
|
||||
used_upload_slots >= upload_slots
|
||||
if user.can_upload_free?
|
||||
false
|
||||
elsif user.created_at > 1.week.ago
|
||||
true
|
||||
else
|
||||
used_upload_slots >= upload_slots
|
||||
end
|
||||
end
|
||||
|
||||
def limit_reason
|
||||
if user.created_at > 1.week.ago
|
||||
"cannot upload during your first week of registration"
|
||||
elsif limited?
|
||||
"have reached your upload limit"
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def used_upload_slots
|
||||
|
||||
@@ -27,6 +27,7 @@ class Post < ApplicationRecord
|
||||
validate :has_enough_tags
|
||||
validate :post_is_not_its_own_parent
|
||||
validate :updater_can_change_rating
|
||||
validate :uploader_is_not_limited, on: :create
|
||||
before_save :update_tag_post_counts
|
||||
before_save :set_tag_counts
|
||||
before_create :autoban
|
||||
@@ -1280,7 +1281,7 @@ class Post < ApplicationRecord
|
||||
give_favorites_to_parent(options) if options[:move_favorites]
|
||||
|
||||
is_automatic = (reason == "Unapproved in three days")
|
||||
uploader.new_upload_limit.update_limit!(self, incremental: is_automatic)
|
||||
uploader.upload_limit.update_limit!(self, incremental: is_automatic)
|
||||
|
||||
unless options[:without_mod_action]
|
||||
ModAction.log("deleted post ##{id}, reason: #{reason}", :post_delete)
|
||||
@@ -1648,6 +1649,10 @@ class Post < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def uploader_is_not_limited
|
||||
errors[:uploader] << uploader.upload_limit.limit_reason if uploader.upload_limit.limited?
|
||||
end
|
||||
|
||||
def added_tags_are_valid
|
||||
new_tags = added_tags.select { |t| t.post_count <= 0 }
|
||||
new_general_tags = new_tags.select { |t| t.category == Tag.categories.general }
|
||||
|
||||
@@ -32,7 +32,7 @@ class PostApproval < ApplicationRecord
|
||||
post.update(approver: user, is_flagged: false, is_pending: false, is_deleted: false)
|
||||
ModAction.log("undeleted post ##{post_id}", :post_undelete) if is_undeletion
|
||||
|
||||
post.uploader.new_upload_limit.update_limit!(post, incremental: !is_undeletion)
|
||||
post.uploader.upload_limit.update_limit!(post, incremental: !is_undeletion)
|
||||
end
|
||||
|
||||
def self.search(params)
|
||||
|
||||
@@ -60,7 +60,6 @@ class Upload < ApplicationRecord
|
||||
|
||||
before_validation :initialize_attributes, on: :create
|
||||
before_validation :assign_rating_from_tags
|
||||
validate :uploader_is_not_limited, on: :create
|
||||
# validates :source, format: { with: /\Ahttps?/ }, if: ->(record) {record.file.blank?}, on: :create
|
||||
validates :rating, inclusion: { in: %w(q e s) }, allow_nil: true
|
||||
validates :md5, confirmation: true, if: ->(rec) { rec.md5_confirmation.present? }
|
||||
@@ -235,12 +234,6 @@ class Upload < ApplicationRecord
|
||||
extend SearchMethods
|
||||
include SourceMethods
|
||||
|
||||
def uploader_is_not_limited
|
||||
if !uploader.can_upload?
|
||||
errors.add(:uploader, uploader.upload_limited_reason)
|
||||
end
|
||||
end
|
||||
|
||||
def assign_rating_from_tags
|
||||
if rating = Tag.has_metatag?(tag_string, :rating)
|
||||
self.rating = rating.downcase.first
|
||||
|
||||
@@ -417,26 +417,6 @@ class User < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def can_upload?
|
||||
if can_upload_free?
|
||||
true
|
||||
elsif is_admin?
|
||||
true
|
||||
elsif created_at > 1.week.ago
|
||||
false
|
||||
else
|
||||
upload_limit > 0
|
||||
end
|
||||
end
|
||||
|
||||
def upload_limited_reason
|
||||
if created_at > 1.week.ago
|
||||
"cannot upload during your first week of registration"
|
||||
else
|
||||
"have reached your upload limit for the day"
|
||||
end
|
||||
end
|
||||
|
||||
def can_comment?
|
||||
if is_gold?
|
||||
true
|
||||
@@ -469,38 +449,8 @@ class User < ApplicationRecord
|
||||
(is_moderator? && flag.not_uploaded_by?(id)) || flag.creator_id == id
|
||||
end
|
||||
|
||||
def new_upload_limit
|
||||
@new_upload_limit ||= UploadLimit.new(self)
|
||||
end
|
||||
|
||||
def upload_limit
|
||||
[max_upload_limit - used_upload_slots, 0].max
|
||||
end
|
||||
|
||||
def used_upload_slots
|
||||
uploaded_count = posts.where("created_at >= ?", 23.hours.ago).count
|
||||
uploaded_comic_count = posts.tag_match("comic").where("created_at >= ?", 23.hours.ago).count / 3
|
||||
uploaded_count - uploaded_comic_count
|
||||
end
|
||||
memoize :used_upload_slots
|
||||
|
||||
def max_upload_limit
|
||||
[(base_upload_limit * upload_limit_multiplier).ceil, 10].max
|
||||
end
|
||||
|
||||
def upload_limit_multiplier
|
||||
(1 - (adjusted_deletion_confidence / 15.0))
|
||||
end
|
||||
|
||||
def adjusted_deletion_confidence
|
||||
[deletion_confidence(60.days.ago), 15].min
|
||||
end
|
||||
memoize :adjusted_deletion_confidence
|
||||
|
||||
def deletion_confidence(date)
|
||||
deletions = posts.deleted.where("created_at >= ?", date).count
|
||||
total = posts.where("created_at >= ?", date).count
|
||||
DanbooruMath.ci_lower_bound(deletions, total)
|
||||
@upload_limit ||= UploadLimit.new(self)
|
||||
end
|
||||
|
||||
def base_upload_limit
|
||||
@@ -624,7 +574,6 @@ class User < ApplicationRecord
|
||||
forum_post_count comment_count favorite_group_count
|
||||
appeal_count flag_count positive_feedback_count
|
||||
neutral_feedback_count negative_feedback_count upload_limit
|
||||
max_upload_limit
|
||||
]
|
||||
end
|
||||
|
||||
|
||||
@@ -43,22 +43,6 @@ class UserPresenter
|
||||
Post.tag_match("search:#{category}").limit(10)
|
||||
end
|
||||
|
||||
def upload_limit(template)
|
||||
if user.can_upload_free?
|
||||
return "none"
|
||||
end
|
||||
|
||||
slots_tooltip = "Next free slot: #{template.time_ago_in_words(user.next_free_upload_slot)}"
|
||||
limit_tooltip = <<-EOS.strip_heredoc
|
||||
Base: #{user.base_upload_limit}
|
||||
Del. Rate: #{format("%.2f", user.adjusted_deletion_confidence)}
|
||||
Multiplier: (1 - (#{format("%.2f", user.adjusted_deletion_confidence)} / 15)) = #{user.upload_limit_multiplier}
|
||||
Upload Limit: #{user.base_upload_limit} * #{format("%.2f", user.upload_limit_multiplier)} = #{user.max_upload_limit}
|
||||
EOS
|
||||
|
||||
%{<abbr title="#{slots_tooltip}">#{user.used_upload_slots}</abbr> / <abbr title="#{limit_tooltip}">#{user.max_upload_limit}</abbr>}.html_safe
|
||||
end
|
||||
|
||||
def uploads
|
||||
Post.tag_match("user:#{user.name}").limit(6)
|
||||
end
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
<div id="a-new">
|
||||
<h1>Upload</h1>
|
||||
|
||||
<% if CurrentUser.can_upload? %>
|
||||
<% if !CurrentUser.user.upload_limit.limited? %>
|
||||
<%= embed_wiki("help:upload_notice", id: "upload-guide-notice") %>
|
||||
|
||||
<% unless CurrentUser.can_upload_free? %>
|
||||
<p>Upload limit: <strong><%= CurrentUser.user.presenter.upload_limit(self) %></strong>.</p>
|
||||
<p id="upload-limit">
|
||||
Upload Limit: <%= render "users/upload_limit", user: CurrentUser.user %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<%= render "image" %>
|
||||
@@ -80,7 +82,7 @@
|
||||
<%= render "related_tags/container" %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<h2 style="margin-bottom: 1em;">You <%= CurrentUser.user.upload_limited_reason %></h2>
|
||||
<h2 style="margin-bottom: 1em;">You <%= CurrentUser.user.upload_limit.limit_reason %></h2>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -63,15 +63,8 @@
|
||||
|
||||
<tr>
|
||||
<th>Upload Limit</th>
|
||||
<td><%= presenter.upload_limit(self) %> (<%= link_to_wiki "help", "about:upload_limits" %>)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>New Upload Limit</th>
|
||||
<td>
|
||||
<%= link_to user.new_upload_limit.used_upload_slots, posts_path(tags: "user:#{user.name} status:pending") %>
|
||||
/
|
||||
<%= tag.abbr user.new_upload_limit.upload_slots, title: "Next level: #{user.new_upload_limit.approvals_on_current_level} / #{user.new_upload_limit.approvals_for_next_level} approvals" %>
|
||||
<%= render "users/upload_limit", user: user %>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
10
app/views/users/_upload_limit.html.erb
Normal file
10
app/views/users/_upload_limit.html.erb
Normal file
@@ -0,0 +1,10 @@
|
||||
<%# user %>
|
||||
|
||||
<% if user.can_upload_free? %>
|
||||
none
|
||||
<% else %>
|
||||
<%= link_to user.upload_limit.used_upload_slots, posts_path(tags: "user:#{user.name} status:pending") %> /
|
||||
<%= tag.abbr user.upload_limit.upload_slots, title: "#{pluralize(user.upload_limit.approvals_for_next_level - user.upload_limit.approvals_on_current_level, "approved post")} needed for next level (progress: #{user.upload_limit.approvals_on_current_level} / #{user.upload_limit.approvals_for_next_level}) " %>
|
||||
<% end %>
|
||||
|
||||
(<%= link_to_wiki "help", "about:upload_limits" %>)
|
||||
@@ -43,6 +43,8 @@ en:
|
||||
approver: "You"
|
||||
approver_id: "You"
|
||||
updater_id: "You"
|
||||
uploader: "You"
|
||||
uploader_id: "You"
|
||||
post_flag:
|
||||
creator: "You"
|
||||
creator_id: "You"
|
||||
|
||||
@@ -6,7 +6,7 @@ uploaders = User.where(id: Post.select(:uploader_id)).bit_prefs_match(:can_uploa
|
||||
|
||||
warn "uploaders=#{uploaders.count}"
|
||||
uploaders.find_each.with_index do |uploader, n|
|
||||
uploader.new_upload_limit.update_limit!(nil, incremental: false)
|
||||
uploader.upload_limit.update_limit!(nil, incremental: false)
|
||||
warn "n=#{n} id=#{uploader.id} name=#{uploader.name} points=#{uploader.upload_points}"
|
||||
end
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
FactoryBot.define do
|
||||
factory(:post) do
|
||||
created_at { 2.weeks.ago }
|
||||
sequence :md5 do |n|
|
||||
n.to_s
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FactoryBot.define do
|
||||
factory(:user, aliases: [:creator, :updater, :uploader]) do
|
||||
factory(:user, aliases: [:creator, :updater]) do
|
||||
sequence :name do |n|
|
||||
"user#{n}"
|
||||
end
|
||||
@@ -58,5 +58,9 @@ FactoryBot.define do
|
||||
level {50}
|
||||
can_approve_posts {true}
|
||||
end
|
||||
|
||||
factory(:uploader) do
|
||||
created_at { 2.weeks.ago }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -223,6 +223,22 @@ class UploadsControllerTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
end
|
||||
|
||||
context "when the uploader is limited" do
|
||||
should "not allow uploading" do
|
||||
@member = create(:user, created_at: 2.weeks.ago, upload_points: 0)
|
||||
create_list(:post, @member.upload_limit.upload_slots, uploader: @member, is_pending: true)
|
||||
|
||||
assert_no_difference("Post.count") do
|
||||
file = Rack::Test::UploadedFile.new("#{Rails.root}/test/files/test.jpg", "image/jpeg")
|
||||
post_auth uploads_path, @member, params: { upload: { file: file, tag_string: "aaa", rating: "q" }}
|
||||
end
|
||||
|
||||
@upload = Upload.last
|
||||
assert_redirected_to @upload
|
||||
assert_match(/have reached your upload limit/, @upload.status)
|
||||
end
|
||||
end
|
||||
|
||||
should "create a new upload" do
|
||||
assert_difference("Upload.count", 1) do
|
||||
file = Rack::Test::UploadedFile.new("#{Rails.root}/test/files/test.jpg", "image/jpeg")
|
||||
|
||||
@@ -3,7 +3,7 @@ require 'test_helper'
|
||||
class UploadLimitTest < ActiveSupport::TestCase
|
||||
context "Upload limits:" do
|
||||
setup do
|
||||
@user = create(:user, upload_points: 1000)
|
||||
@user = create(:user, upload_points: 1000, created_at: 2.weeks.ago)
|
||||
@approver = create(:moderator_user)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
require 'test_helper'
|
||||
|
||||
class UploadTest < ActiveSupport::TestCase
|
||||
SOURCE_URL = "https://upload.wikimedia.org/wikipedia/commons/thumb/6/66/NAMA_Machine_d%27Anticyth%C3%A8re_1.jpg/538px-NAMA_Machine_d%27Anticyth%C3%A8re_1.jpg?download"
|
||||
|
||||
context "In all cases" do
|
||||
setup do
|
||||
mock_iqdb_service!
|
||||
user = FactoryBot.create(:contributor_user)
|
||||
CurrentUser.user = user
|
||||
CurrentUser.ip_addr = "127.0.0.1"
|
||||
end
|
||||
|
||||
teardown do
|
||||
CurrentUser.user = nil
|
||||
CurrentUser.ip_addr = nil
|
||||
end
|
||||
|
||||
context "An upload" do
|
||||
context "from a user that is limited" do
|
||||
setup do
|
||||
CurrentUser.user = FactoryBot.create(:user, :created_at => 1.year.ago)
|
||||
User.any_instance.stubs(:upload_limit).returns(0)
|
||||
end
|
||||
|
||||
should "fail creation" do
|
||||
@upload = FactoryBot.build(:jpg_upload, :tag_string => "")
|
||||
@upload.save
|
||||
assert_equal(["You have reached your upload limit for the day"], @upload.errors.full_messages)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -48,24 +48,6 @@ class UserTest < ActiveSupport::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
should "limit post uploads" do
|
||||
assert(!@user.can_upload?)
|
||||
@user.update_column(:created_at, 15.days.ago)
|
||||
assert(@user.can_upload?)
|
||||
assert_equal(10, @user.upload_limit)
|
||||
|
||||
9.times do
|
||||
FactoryBot.create(:post, :uploader => @user, :is_pending => true)
|
||||
end
|
||||
|
||||
@user = User.find(@user.id)
|
||||
assert_equal(1, @user.upload_limit)
|
||||
assert(@user.can_upload?)
|
||||
FactoryBot.create(:post, :uploader => @user, :is_pending => true)
|
||||
@user = User.find(@user.id)
|
||||
assert(!@user.can_upload?)
|
||||
end
|
||||
|
||||
should "limit comment votes" do
|
||||
Danbooru.config.stubs(:member_comment_time_threshold).returns(1.week.from_now)
|
||||
Danbooru.config.stubs(:member_comment_limit).returns(10)
|
||||
|
||||
Reference in New Issue
Block a user