Users: add Contributor and Approver user levels
This commit is contained in:
@@ -10,10 +10,8 @@ module Admin
|
|||||||
@user = authorize User.find(params[:id]), :promote?
|
@user = authorize User.find(params[:id]), :promote?
|
||||||
|
|
||||||
@level = params.dig(:user, :level)
|
@level = params.dig(:user, :level)
|
||||||
@can_upload_free = params.dig(:user, :can_upload_free)
|
|
||||||
@can_approve_posts = params.dig(:user, :can_approve_posts)
|
|
||||||
|
|
||||||
@user.promote_to!(@level, CurrentUser.user, can_upload_free: @can_upload_free, can_approve_posts: @can_approve_posts)
|
@user.promote_to!(@level, CurrentUser.user)
|
||||||
|
|
||||||
redirect_to edit_admin_user_path(@user), :notice => "User updated"
|
redirect_to edit_admin_user_path(@user), :notice => "User updated"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -218,9 +218,7 @@ module ApplicationHelper
|
|||||||
def link_to_user(user, text = nil, classes: nil, **options)
|
def link_to_user(user, text = nil, classes: nil, **options)
|
||||||
return "anonymous" if user.blank?
|
return "anonymous" if user.blank?
|
||||||
|
|
||||||
user_class = "user user-#{user.level_string.downcase} #{classes}"
|
user_class = "user user-#{user.level_string.downcase} #{classes}".strip
|
||||||
user_class += " user-post-approver" if user.can_approve_posts?
|
|
||||||
user_class += " user-post-uploader" if user.can_upload_free?
|
|
||||||
user_class += " user-banned" if user.is_banned?
|
user_class += " user-banned" if user.is_banned?
|
||||||
|
|
||||||
text = user.pretty_name if text.blank?
|
text = user.pretty_name if text.blank?
|
||||||
|
|||||||
@@ -11,6 +11,14 @@ body {
|
|||||||
color: var(--user-moderator-color);
|
color: var(--user-moderator-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.user-approver {
|
||||||
|
color: var(--user-builder-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
a.user-contributor {
|
||||||
|
color: var(--user-builder-color);
|
||||||
|
}
|
||||||
|
|
||||||
a.user-builder {
|
a.user-builder {
|
||||||
color: var(--user-builder-color);
|
color: var(--user-builder-color);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,10 @@ module ApproverPruner
|
|||||||
# Get the list of inactive approvers.
|
# Get the list of inactive approvers.
|
||||||
# @return [Array<User>] the list of inactive approvers
|
# @return [Array<User>] the list of inactive approvers
|
||||||
def inactive_approvers
|
def inactive_approvers
|
||||||
approvers = User.bit_prefs_match(:can_approve_posts, true)
|
recently_promoted_approvers = UserFeedback.where("created_at >= ?", APPROVAL_PERIOD.ago).where_like(:body, "*You gained the ability to approve posts*").pluck(:user_id) # XXX remove in two months
|
||||||
approvers = approvers.where("level < ?", User::Levels::MODERATOR)
|
recently_promoted_approvers += UserFeedback.where("created_at >= ?", APPROVAL_PERIOD.ago).where_like(:body, "*You have been promoted to an Approver*").pluck(:user_id)
|
||||||
|
|
||||||
recently_promoted_approvers = UserFeedback.where("created_at >= ?", APPROVAL_PERIOD.ago).where_like(:body, "*You gained the ability to approve posts*").select(:user_id)
|
|
||||||
approvers = approvers.where.not(id: recently_promoted_approvers)
|
|
||||||
|
|
||||||
|
approvers = User.where(level: User::Levels::APPROVER).where.not(id: recently_promoted_approvers)
|
||||||
approvers.select do |approver|
|
approvers.select do |approver|
|
||||||
approver.post_approvals.where("created_at >= ?", APPROVAL_PERIOD.ago).count < MINIMUM_APPROVALS
|
approver.post_approvals.where("created_at >= ?", APPROVAL_PERIOD.ago).count < MINIMUM_APPROVALS
|
||||||
end
|
end
|
||||||
@@ -30,7 +28,7 @@ module ApproverPruner
|
|||||||
def prune!
|
def prune!
|
||||||
inactive_approvers.each do |user|
|
inactive_approvers.each do |user|
|
||||||
CurrentUser.scoped(User.system) do
|
CurrentUser.scoped(User.system) do
|
||||||
user.update!(can_approve_posts: false)
|
user.update!(level: User::Levels::CONTRIBUTOR)
|
||||||
user.feedback.create(category: "neutral", body: "Lost approval privileges", creator: User.system)
|
user.feedback.create(category: "neutral", body: "Lost approval privileges", creator: User.system)
|
||||||
|
|
||||||
Dmail.create_automated(
|
Dmail.create_automated(
|
||||||
|
|||||||
@@ -470,7 +470,7 @@ class PostQueryBuilder
|
|||||||
relation = relation.reorder(Arel.sql("log(3, posts.score) + (extract(epoch from posts.created_at) - extract(epoch from timestamp '2005-05-24')) / 35000 DESC"))
|
relation = relation.reorder(Arel.sql("log(3, posts.score) + (extract(epoch from posts.created_at) - extract(epoch from timestamp '2005-05-24')) / 35000 DESC"))
|
||||||
|
|
||||||
when "curated"
|
when "curated"
|
||||||
contributors = User.bit_prefs_match(:can_upload_free, true)
|
contributors = User.where("level >= ?", User::Levels::CONTRIBUTOR)
|
||||||
|
|
||||||
relation = relation
|
relation = relation
|
||||||
.joins(:favorites)
|
.joins(:favorites)
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class UploadLimit
|
|||||||
|
|
||||||
# @return [Boolean] true if the user can't upload because they're out of upload slots.
|
# @return [Boolean] true if the user can't upload because they're out of upload slots.
|
||||||
def limited?
|
def limited?
|
||||||
!user.can_upload_free? && used_upload_slots >= upload_slots
|
!user.is_contributor? && used_upload_slots >= upload_slots
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [Boolean] true if the user is at max level.
|
# @return [Boolean] true if the user is at max level.
|
||||||
@@ -91,7 +91,7 @@ class UploadLimit
|
|||||||
# @param is_approval [Boolean] true if the post is being approved or
|
# @param is_approval [Boolean] true if the post is being approved or
|
||||||
# undeleted, false if the post is being deleted.
|
# undeleted, false if the post is being deleted.
|
||||||
def update_limit!(is_pending, is_approval)
|
def update_limit!(is_pending, is_approval)
|
||||||
return if user.can_upload_free?
|
return if user.is_contributor?
|
||||||
|
|
||||||
user.with_lock do
|
user.with_lock do
|
||||||
# If we're approving or deleting a pending post, we can simply increment
|
# If we're approving or deleting a pending post, we can simply increment
|
||||||
|
|||||||
@@ -5,31 +5,22 @@
|
|||||||
# user a feedback, sends them a notification dmail, and creates a mod action for
|
# user a feedback, sends them a notification dmail, and creates a mod action for
|
||||||
# the promotion.
|
# the promotion.
|
||||||
class UserPromotion
|
class UserPromotion
|
||||||
attr_reader :user, :promoter, :new_level, :old_can_approve_posts, :old_can_upload_free, :can_upload_free, :can_approve_posts
|
attr_reader :user, :promoter, :new_level
|
||||||
|
|
||||||
# Initialize a new promotion.
|
# Initialize a new promotion.
|
||||||
# @param user [User] the user to promote
|
# @param user [User] the user to promote
|
||||||
# @param promoter [User] the user doing the promotion
|
# @param promoter [User] the user doing the promotion
|
||||||
# @param new_level [Integer] the new user level
|
# @param new_level [Integer] the new user level
|
||||||
# @param can_upload_free [Boolean] whether the user should gain unlimited upload privileges
|
def initialize(user, promoter, new_level)
|
||||||
# @param can_approve_posts [Boolean] whether the user should gain approval privileges
|
|
||||||
def initialize(user, promoter, new_level, can_upload_free: nil, can_approve_posts: nil)
|
|
||||||
@user = user
|
@user = user
|
||||||
@promoter = promoter
|
@promoter = promoter
|
||||||
@new_level = new_level.to_i
|
@new_level = new_level.to_i
|
||||||
@can_upload_free = can_upload_free
|
|
||||||
@can_approve_posts = can_approve_posts
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def promote!
|
def promote!
|
||||||
validate!
|
validate!
|
||||||
|
|
||||||
@old_can_approve_posts = user.can_approve_posts?
|
|
||||||
@old_can_upload_free = user.can_upload_free?
|
|
||||||
|
|
||||||
user.level = new_level
|
user.level = new_level
|
||||||
user.can_upload_free = can_upload_free unless can_upload_free.nil?
|
|
||||||
user.can_approve_posts = can_approve_posts unless can_approve_posts.nil?
|
|
||||||
|
|
||||||
create_user_feedback
|
create_user_feedback
|
||||||
create_dmail
|
create_dmail
|
||||||
@@ -41,18 +32,6 @@ class UserPromotion
|
|||||||
private
|
private
|
||||||
|
|
||||||
def create_mod_actions
|
def create_mod_actions
|
||||||
if old_can_approve_posts == false && user.can_approve_posts? == true
|
|
||||||
ModAction.log("granted approval privileges to \"#{user.name}\":#{Routes.user_path(user)}", :user_approval_privilege, subject: user, user: promoter)
|
|
||||||
elsif old_can_approve_posts == true && user.can_approve_posts? == false
|
|
||||||
ModAction.log("removed approval privileges from \"#{user.name}\":#{Routes.user_path(user)}", :user_approval_privilege, subject: user, user: promoter)
|
|
||||||
end
|
|
||||||
|
|
||||||
if old_can_upload_free == false && user.can_upload_free? == true
|
|
||||||
ModAction.log("granted unlimited upload privileges to \"#{user.name}\":#{Routes.user_path(user)}", :user_upload_privilege, subject: user, user: promoter)
|
|
||||||
elsif old_can_upload_free == false && user.can_upload_free? == true
|
|
||||||
ModAction.log("removed unlimited upload privileges from \"#{user.name}\":#{Routes.user_path(user)}", :user_upload_privilege, subject: user, user: promoter)
|
|
||||||
end
|
|
||||||
|
|
||||||
if user.level_changed? && user.level >= user.level_was
|
if user.level_changed? && user.level >= user.level_was
|
||||||
ModAction.log(%{promoted "#{user.name}":#{Routes.user_path(user)} from #{user.level_string_was} to #{user.level_string}}, :user_level_change, subject: user, user: promoter)
|
ModAction.log(%{promoted "#{user.name}":#{Routes.user_path(user)} from #{user.level_string_was} to #{user.level_string}}, :user_level_change, subject: user, user: promoter)
|
||||||
elsif user.level_changed? && user.level < user.level_was
|
elsif user.level_changed? && user.level < user.level_was
|
||||||
@@ -73,37 +52,20 @@ class UserPromotion
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Build the dmail and user feedback message.
|
# Build the dmail and user feedback message.
|
||||||
def build_messages
|
def build_message
|
||||||
messages = []
|
level_string = (user.level == User::Levels::APPROVER) ? "an Approver" : "a #{user.level_string}"
|
||||||
|
if user.level > user.level_was
|
||||||
if user.level_changed?
|
"You have been promoted to #{level_string} level account from #{user.level_string_was}."
|
||||||
if user.level > user.level_was
|
elsif user.level < user.level_was
|
||||||
messages << "You have been promoted to a #{user.level_string} level account from #{user.level_string_was}."
|
"You have been demoted to #{level_string} level account from #{user.level_string_was}."
|
||||||
elsif user.level < user.level_was
|
|
||||||
messages << "You have been demoted to a #{user.level_string} level account from #{user.level_string_was}."
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if user.can_approve_posts? && !old_can_approve_posts
|
|
||||||
messages << "You gained the ability to approve posts."
|
|
||||||
elsif !user.can_approve_posts? && old_can_approve_posts
|
|
||||||
messages << "You lost the ability to approve posts."
|
|
||||||
end
|
|
||||||
|
|
||||||
if user.can_upload_free? && !old_can_upload_free
|
|
||||||
messages << "You gained the ability to upload posts without limit."
|
|
||||||
elsif !user.can_upload_free? && old_can_upload_free
|
|
||||||
messages << "You lost the ability to upload posts without limit."
|
|
||||||
end
|
|
||||||
|
|
||||||
messages.join("\n")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_dmail
|
def create_dmail
|
||||||
Dmail.create_automated(to_id: user.id, title: "Your account has been updated", body: build_messages)
|
Dmail.create_automated(to_id: user.id, title: "Your account has been updated", body: build_message)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_user_feedback
|
def create_user_feedback
|
||||||
UserFeedback.create(user: user, creator: promoter, category: "neutral", body: build_messages, disable_dmail_notification: true)
|
UserFeedback.create(user: user, creator: promoter, category: "neutral", body: build_message, disable_dmail_notification: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ class Post < ApplicationRecord
|
|||||||
tag_string: tag_string,
|
tag_string: tag_string,
|
||||||
rating: rating,
|
rating: rating,
|
||||||
parent_id: parent_id,
|
parent_id: parent_id,
|
||||||
is_pending: !upload.uploader.can_upload_free? || is_pending.to_s.truthy?,
|
is_pending: !upload.uploader.is_contributor? || is_pending.to_s.truthy?,
|
||||||
artist_commentary: (commentary if commentary.any_field_present?),
|
artist_commentary: (commentary if commentary.any_field_present?),
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -12,13 +12,15 @@ class User < ApplicationRecord
|
|||||||
GOLD = 30
|
GOLD = 30
|
||||||
PLATINUM = 31
|
PLATINUM = 31
|
||||||
BUILDER = 32
|
BUILDER = 32
|
||||||
|
CONTRIBUTOR = 35
|
||||||
|
APPROVER = 37
|
||||||
MODERATOR = 40
|
MODERATOR = 40
|
||||||
ADMIN = 50
|
ADMIN = 50
|
||||||
OWNER = 60
|
OWNER = 60
|
||||||
end
|
end
|
||||||
|
|
||||||
# Used for `before_action :<role>_only`. Must have a corresponding `is_<role>?` method.
|
# Used for `before_action :<role>_only`. Must have a corresponding `is_<role>?` method.
|
||||||
Roles = Levels.constants.map(&:downcase) + %i[banned approver]
|
Roles = Levels.constants.map(&:downcase) + %i[banned]
|
||||||
|
|
||||||
BOOLEAN_ATTRIBUTES = %w[
|
BOOLEAN_ATTRIBUTES = %w[
|
||||||
is_banned
|
is_banned
|
||||||
@@ -34,8 +36,8 @@ class User < ApplicationRecord
|
|||||||
_unused_enable_auto_complete
|
_unused_enable_auto_complete
|
||||||
show_deleted_children
|
show_deleted_children
|
||||||
_unused_has_saved_searches
|
_unused_has_saved_searches
|
||||||
can_approve_posts
|
_unused_can_approve_posts
|
||||||
can_upload_free
|
_unused_can_upload_free
|
||||||
disable_categorized_saved_searches
|
disable_categorized_saved_searches
|
||||||
_unused_is_super_voter
|
_unused_is_super_voter
|
||||||
disable_tagged_filenames
|
disable_tagged_filenames
|
||||||
@@ -261,6 +263,8 @@ class User < ApplicationRecord
|
|||||||
"Gold" => Levels::GOLD,
|
"Gold" => Levels::GOLD,
|
||||||
"Platinum" => Levels::PLATINUM,
|
"Platinum" => Levels::PLATINUM,
|
||||||
"Builder" => Levels::BUILDER,
|
"Builder" => Levels::BUILDER,
|
||||||
|
"Contributor" => Levels::CONTRIBUTOR,
|
||||||
|
"Approver" => Levels::APPROVER,
|
||||||
"Moderator" => Levels::MODERATOR,
|
"Moderator" => Levels::MODERATOR,
|
||||||
"Admin" => Levels::ADMIN,
|
"Admin" => Levels::ADMIN,
|
||||||
"Owner" => Levels::OWNER,
|
"Owner" => Levels::OWNER,
|
||||||
@@ -268,42 +272,12 @@ class User < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def level_string(value)
|
def level_string(value)
|
||||||
case value
|
level_hash.key(value)
|
||||||
when Levels::ANONYMOUS
|
|
||||||
"Anonymous"
|
|
||||||
|
|
||||||
when Levels::RESTRICTED
|
|
||||||
"Restricted"
|
|
||||||
|
|
||||||
when Levels::MEMBER
|
|
||||||
"Member"
|
|
||||||
|
|
||||||
when Levels::BUILDER
|
|
||||||
"Builder"
|
|
||||||
|
|
||||||
when Levels::GOLD
|
|
||||||
"Gold"
|
|
||||||
|
|
||||||
when Levels::PLATINUM
|
|
||||||
"Platinum"
|
|
||||||
|
|
||||||
when Levels::MODERATOR
|
|
||||||
"Moderator"
|
|
||||||
|
|
||||||
when Levels::ADMIN
|
|
||||||
"Admin"
|
|
||||||
|
|
||||||
when Levels::OWNER
|
|
||||||
"Owner"
|
|
||||||
|
|
||||||
else
|
|
||||||
""
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def promote_to!(new_level, promoter = CurrentUser.user, **options)
|
def promote_to!(new_level, promoter = CurrentUser.user)
|
||||||
UserPromotion.new(self, promoter, new_level, **options).promote!
|
UserPromotion.new(self, promoter, new_level).promote!
|
||||||
end
|
end
|
||||||
|
|
||||||
def promote_to_owner_if_first_user
|
def promote_to_owner_if_first_user
|
||||||
@@ -311,8 +285,6 @@ class User < ApplicationRecord
|
|||||||
|
|
||||||
if name != Danbooru.config.system_user && !User.exists?(level: Levels::OWNER)
|
if name != Danbooru.config.system_user && !User.exists?(level: Levels::OWNER)
|
||||||
self.level = Levels::OWNER
|
self.level = Levels::OWNER
|
||||||
self.can_approve_posts = true
|
|
||||||
self.can_upload_free = true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -340,10 +312,6 @@ class User < ApplicationRecord
|
|||||||
level >= Levels::MEMBER
|
level >= Levels::MEMBER
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_builder?
|
|
||||||
level >= Levels::BUILDER
|
|
||||||
end
|
|
||||||
|
|
||||||
def is_gold?
|
def is_gold?
|
||||||
level >= Levels::GOLD
|
level >= Levels::GOLD
|
||||||
end
|
end
|
||||||
@@ -352,6 +320,18 @@ class User < ApplicationRecord
|
|||||||
level >= Levels::PLATINUM
|
level >= Levels::PLATINUM
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def is_builder?
|
||||||
|
level >= Levels::BUILDER
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_contributor?
|
||||||
|
level >= Levels::CONTRIBUTOR
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_approver?
|
||||||
|
level >= Levels::APPROVER
|
||||||
|
end
|
||||||
|
|
||||||
def is_moderator?
|
def is_moderator?
|
||||||
level >= Levels::MODERATOR
|
level >= Levels::MODERATOR
|
||||||
end
|
end
|
||||||
@@ -363,10 +343,6 @@ class User < ApplicationRecord
|
|||||||
def is_owner?
|
def is_owner?
|
||||||
level >= Levels::OWNER
|
level >= Levels::OWNER
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_approver?
|
|
||||||
can_approve_posts?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module EmailMethods
|
module EmailMethods
|
||||||
@@ -484,7 +460,7 @@ class User < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def is_appeal_limited?
|
def is_appeal_limited?
|
||||||
return false if can_upload_free?
|
return false if is_contributor?
|
||||||
upload_limit.free_upload_slots < UploadLimit::APPEAL_COST
|
upload_limit.free_upload_slots < UploadLimit::APPEAL_COST
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -496,7 +472,7 @@ class User < ApplicationRecord
|
|||||||
# Flags are unlimited if you're an approver or you have at least 30 flags
|
# Flags are unlimited if you're an approver or you have at least 30 flags
|
||||||
# in the last 3 months and have a 70% flag success rate.
|
# in the last 3 months and have a 70% flag success rate.
|
||||||
def has_unlimited_flags?
|
def has_unlimited_flags?
|
||||||
return true if can_approve_posts?
|
return true if is_approver?
|
||||||
|
|
||||||
recent_flags = post_flags.where("created_at >= ?", 3.months.ago)
|
recent_flags = post_flags.where("created_at >= ?", 3.months.ago)
|
||||||
flag_ratio = recent_flags.succeeded.count / recent_flags.count.to_f
|
flag_ratio = recent_flags.succeeded.count / recent_flags.count.to_f
|
||||||
@@ -642,11 +618,11 @@ class User < ApplicationRecord
|
|||||||
q = q.where("level <= ?", params[:max_level].to_i)
|
q = q.where("level <= ?", params[:max_level].to_i)
|
||||||
end
|
end
|
||||||
|
|
||||||
%w[can_approve_posts can_upload_free is_banned].each do |flag|
|
if params[:is_banned].present?
|
||||||
if params[flag].to_s.truthy?
|
if params[:is_banned].to_s.truthy?
|
||||||
q = q.bit_prefs_match(flag, true)
|
q = q.bit_prefs_match(:is_banned, true)
|
||||||
elsif params[flag].to_s.falsy?
|
elsif params[:is_banned].to_s.falsy?
|
||||||
q = q.bit_prefs_match(flag, false)
|
q = q.bit_prefs_match(:is_banned, false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -56,9 +56,8 @@ class UserPolicy < ApplicationPolicy
|
|||||||
|
|
||||||
def api_attributes
|
def api_attributes
|
||||||
attributes = %i[
|
attributes = %i[
|
||||||
id created_at name inviter_id level
|
id created_at name inviter_id level level_string
|
||||||
post_upload_count post_update_count note_update_count is_banned
|
post_upload_count post_update_count note_update_count is_banned
|
||||||
can_approve_posts can_upload_free level_string
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if record.id == user.id
|
if record.id == user.id
|
||||||
|
|||||||
@@ -15,20 +15,6 @@ class UserPresenter
|
|||||||
user.created_at.strftime("%Y-%m-%d")
|
user.created_at.strftime("%Y-%m-%d")
|
||||||
end
|
end
|
||||||
|
|
||||||
def permissions
|
|
||||||
permissions = []
|
|
||||||
|
|
||||||
if user.can_approve_posts?
|
|
||||||
permissions << "approve posts"
|
|
||||||
end
|
|
||||||
|
|
||||||
if user.can_upload_free?
|
|
||||||
permissions << "unrestricted uploads"
|
|
||||||
end
|
|
||||||
|
|
||||||
permissions.join(", ")
|
|
||||||
end
|
|
||||||
|
|
||||||
def posts_for_saved_search_category(category)
|
def posts_for_saved_search_category(category)
|
||||||
Post.user_tag_match("search:#{category}").limit(10)
|
Post.user_tag_match("search:#{category}").limit(10)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,8 +7,6 @@
|
|||||||
|
|
||||||
<%= edit_form_for(@user, url: admin_user_path(@user)) do |f| %>
|
<%= edit_form_for(@user, url: admin_user_path(@user)) do |f| %>
|
||||||
<%= f.input :level, collection: User.level_hash.to_a, selected: @user.level %>
|
<%= f.input :level, collection: User.level_hash.to_a, selected: @user.level %>
|
||||||
<%= f.input :can_upload_free, label: "Unrestricted Uploads", as: :boolean, selected: @user.can_upload_free %>
|
|
||||||
<%= f.input :can_approve_posts, label: "Approve Posts", as: :boolean, selected: @user.can_approve_posts %>
|
|
||||||
<%= f.submit "Update" %>
|
<%= f.submit "Update" %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<% if (CurrentUser.can_approve_posts? || post.created_at < Danbooru.config.moderation_period.ago) && disapprovals.length > 0 %>
|
<% if (CurrentUser.is_approver? || post.created_at < Danbooru.config.moderation_period.ago) && disapprovals.length > 0 %>
|
||||||
<% if disapprovals.map(&:reason).grep("breaks_rules").count > 0 %>
|
<% if disapprovals.map(&:reason).grep("breaks_rules").count > 0 %>
|
||||||
(breaks rules: <%= disapprovals.map(&:reason).grep("breaks_rules").count %>)
|
(breaks rules: <%= disapprovals.map(&:reason).grep("breaks_rules").count %>)
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<% if (CurrentUser.can_approve_posts? || post.created_at < Danbooru.config.moderation_period.ago) && disapprovals.length > 0 %>
|
<% if (CurrentUser.is_approver? || post.created_at < Danbooru.config.moderation_period.ago) && disapprovals.length > 0 %>
|
||||||
<p>
|
<p>
|
||||||
It has been reviewed by <%= pluralize disapprovals.length, "approver" %>.
|
It has been reviewed by <%= pluralize disapprovals.length, "approver" %>.
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<%= embed_wiki("help:upload_notice", id: "upload-guide-notice") %>
|
<%= embed_wiki("help:upload_notice", id: "upload-guide-notice") %>
|
||||||
|
|
||||||
<% unless CurrentUser.can_upload_free? %>
|
<% unless CurrentUser.is_contributor? %>
|
||||||
<p id="upload-limit">Upload Limit: <%= render "users/upload_limit", user: CurrentUser.user %></p>
|
<p id="upload-limit">Upload Limit: <%= render "users/upload_limit", user: CurrentUser.user %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
|
|
||||||
<%= f.submit "Post" %>
|
<%= f.submit "Post" %>
|
||||||
|
|
||||||
<% if CurrentUser.can_upload_free? %>
|
<% if CurrentUser.is_contributor? %>
|
||||||
<%= f.input :is_pending, as: :boolean, label: "Upload for approval", wrapper_html: { class: "inline-block" }, input_html: { checked: post.is_pending? } %>
|
<%= f.input :is_pending, as: :boolean, label: "Upload for approval", wrapper_html: { class: "inline-block" }, input_html: { checked: post.is_pending? } %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
|||||||
@@ -94,11 +94,6 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
|
||||||
<th>Permissions</th>
|
|
||||||
<td><%= presenter.permissions %></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<% if user.is_banned? && user.active_ban.present? %>
|
<% if user.is_banned? && user.active_ban.present? %>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Ban reason</th>
|
<th>Ban reason</th>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<%# user %>
|
<%# user %>
|
||||||
|
|
||||||
<% if user.can_upload_free? %>
|
<% if user.is_contributor? %>
|
||||||
none
|
none
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= link_to user.upload_limit.used_upload_slots, posts_path(tags: "user:#{user.name} status:pending") %> /
|
<%= link_to user.upload_limit.used_upload_slots, posts_path(tags: "user:#{user.name} status:pending") %> /
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
<%= search_form_for(users_path) do |f| %>
|
<%= search_form_for(users_path) do |f| %>
|
||||||
<%= f.input :name_matches, label: "Name", input_html: { value: params[:search][:name_matches], data: { autocomplete: "user" } } %>
|
<%= f.input :name_matches, label: "Name", input_html: { value: params[:search][:name_matches], data: { autocomplete: "user" } } %>
|
||||||
<%= f.input :level, collection: User.level_hash.to_a, include_blank: true, selected: params[:search][:level] %>
|
<%= f.input :level, collection: User.level_hash.to_a, include_blank: true, selected: params[:search][:level] %>
|
||||||
<%= f.input :can_upload_free, label: "Contributor?", as: :select, include_blank: true, selected: params[:search][:can_upload_free] %>
|
|
||||||
<%= f.input :can_approve_posts, label: "Approver?", as: :select, include_blank: true, selected: params[:search][:can_approve_posts] %>
|
|
||||||
<%= f.input :order, collection: [["Joined", "date"], ["Name", "name"], ["Posts", "post_upload_count"], ["Edits", "post_update_count"], ["Notes", "note_count"]], include_blank: true, selected: params[:search][:order] %>
|
<%= f.input :order, collection: [["Joined", "date"], ["Name", "name"], ["Posts", "post_upload_count"], ["Edits", "post_update_count"], ["Notes", "note_count"]], include_blank: true, selected: params[:search][:order] %>
|
||||||
<%= f.submit "Search" %>
|
<%= f.submit "Search" %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -7,14 +7,6 @@
|
|||||||
|
|
||||||
<% if @user.is_banned? %>
|
<% if @user.is_banned? %>
|
||||||
<%= link_to "Banned", users_path(search: { is_banned: true }), class: "user-tooltip-badge user-tooltip-badge-banned" %>
|
<%= link_to "Banned", users_path(search: { is_banned: true }), class: "user-tooltip-badge user-tooltip-badge-banned" %>
|
||||||
<% elsif @user.is_admin? %>
|
|
||||||
<%= link_to @user.level_string, users_path(search: { level: @user.level }), class: "user-tooltip-badge user-tooltip-badge-#{@user.level_string.downcase}" %>
|
|
||||||
<% elsif @user.is_moderator? %>
|
|
||||||
<%= link_to @user.level_string, users_path(search: { level: @user.level }), class: "user-tooltip-badge user-tooltip-badge-#{@user.level_string.downcase}" %>
|
|
||||||
<% elsif @user.can_approve_posts? %>
|
|
||||||
<%= link_to "Approver", users_path(search: { can_approve_posts: true }), class: "user-tooltip-badge user-tooltip-badge-approver" %>
|
|
||||||
<% elsif @user.can_upload_free? %>
|
|
||||||
<%= link_to "Contributor", users_path(search: { can_upload_free: true }), class: "user-tooltip-badge user-tooltip-badge-contributor" %>
|
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= link_to @user.level_string, users_path(search: { level: @user.level }), class: "user-tooltip-badge user-tooltip-badge-#{@user.level_string.downcase}" %>
|
<%= link_to @user.level_string, users_path(search: { level: @user.level }), class: "user-tooltip-badge user-tooltip-badge-#{@user.level_string.downcase}" %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -33,12 +33,6 @@ def populate_users(n, password: DEFAULT_PASSWORD)
|
|||||||
puts "Created user ##{user.id} (#{user.name})"
|
puts "Created user ##{user.id} (#{user.name})"
|
||||||
end
|
end
|
||||||
|
|
||||||
user = User.create(name: "contributor", password: password, password_confirmation: password, level: User::Levels::BUILDER, can_upload_free: true)
|
|
||||||
puts "Created user ##{user.id} (#{user.name})"
|
|
||||||
|
|
||||||
user = User.create(name: "approver", password: password, password_confirmation: password, level: User::Levels::BUILDER, can_upload_free: true, can_approve_posts: true)
|
|
||||||
puts "Created user ##{user.id} (#{user.name})"
|
|
||||||
|
|
||||||
n.times do |i|
|
n.times do |i|
|
||||||
user = User.create(name: FFaker::Internet.user_name, password: password, password_confirmation: password, level: User::Levels::MEMBER)
|
user = User.create(name: FFaker::Internet.user_name, password: password, password_confirmation: password, level: User::Levels::MEMBER)
|
||||||
puts "Created user ##{user.id}"
|
puts "Created user ##{user.id}"
|
||||||
|
|||||||
17
script/fixes/122_populate_approvers_and_contributors.rb
Executable file
17
script/fixes/122_populate_approvers_and_contributors.rb
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
require_relative "base"
|
||||||
|
|
||||||
|
with_confirmation do
|
||||||
|
User.where(level: User::Levels::BUILDER).bit_prefs_match(:_unused_can_upload_free, true).bit_prefs_match(:_unused_can_approve_posts, false).find_each do |contributor|
|
||||||
|
contributor.level = User::Levels::CONTRIBUTOR
|
||||||
|
contributor.save
|
||||||
|
puts "user ##{contributor.id} #{contributor.name} updated to contributor"
|
||||||
|
end
|
||||||
|
|
||||||
|
User.where(level: User::Levels::BUILDER).bit_prefs_match(:_unused_can_approve_posts, true).find_each do |approver|
|
||||||
|
approver.level = User::Levels::APPROVER
|
||||||
|
approver.save
|
||||||
|
puts "user ##{contributor.id} #{approver.name} updated to approver"
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -12,64 +12,30 @@ FactoryBot.define do
|
|||||||
end
|
end
|
||||||
|
|
||||||
factory(:restricted_user) do
|
factory(:restricted_user) do
|
||||||
level {10}
|
level {User::Levels::RESTRICTED}
|
||||||
requires_verification { true }
|
requires_verification { true }
|
||||||
is_verified { false }
|
is_verified { false }
|
||||||
end
|
end
|
||||||
|
|
||||||
factory(:member_user) do
|
User.level_hash.each do |level_name, level_value|
|
||||||
level {20}
|
# allows create(:moderator_user), create(:approver) etc
|
||||||
end
|
next if level_name == "Restricted" # already defined above
|
||||||
|
|
||||||
factory(:gold_user) do
|
factory(level_name.downcase) do
|
||||||
level {30}
|
level {level_value}
|
||||||
end
|
end
|
||||||
|
|
||||||
factory(:platinum_user) do
|
factory("#{level_name.downcase}_user") do
|
||||||
level {31}
|
level {level_value}
|
||||||
end
|
end
|
||||||
|
|
||||||
factory(:builder_user) do
|
|
||||||
level {32}
|
|
||||||
end
|
|
||||||
|
|
||||||
factory(:contributor_user) do
|
|
||||||
level {32}
|
|
||||||
can_upload_free {true}
|
|
||||||
end
|
|
||||||
|
|
||||||
factory(:contrib_user) do
|
|
||||||
level {32}
|
|
||||||
can_upload_free {true}
|
|
||||||
end
|
|
||||||
|
|
||||||
factory(:moderator_user) do
|
|
||||||
level {40}
|
|
||||||
can_approve_posts {true}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
factory(:mod_user) do
|
factory(:mod_user) do
|
||||||
level {40}
|
level {User::Levels::MODERATOR}
|
||||||
can_approve_posts {true}
|
|
||||||
end
|
|
||||||
|
|
||||||
factory(:admin_user) do
|
|
||||||
level {50}
|
|
||||||
can_approve_posts {true}
|
|
||||||
end
|
|
||||||
|
|
||||||
factory(:owner_user) do
|
|
||||||
level { User::Levels::OWNER }
|
|
||||||
can_approve_posts {true}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
factory(:uploader) do
|
factory(:uploader) do
|
||||||
created_at { 2.weeks.ago }
|
created_at { 2.weeks.ago }
|
||||||
end
|
end
|
||||||
|
|
||||||
factory(:approver) do
|
|
||||||
level {32}
|
|
||||||
can_approve_posts {true}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -22,37 +22,7 @@ class Admin::UsersControllerTest < ActionDispatch::IntegrationTest
|
|||||||
|
|
||||||
assert_redirected_to(edit_admin_user_path(@user))
|
assert_redirected_to(edit_admin_user_path(@user))
|
||||||
assert_equal(30, @user.reload.level)
|
assert_equal(30, @user.reload.level)
|
||||||
assert_match(/promoted "#{@user.name}":\/users\/#{@user.id} from Member to Gold/, ModAction.last.description)
|
assert_match(%r{promoted "#{@user.name}":/users/#{@user.id} from Member to Gold}, ModAction.last.description)
|
||||||
assert_equal(@user, ModAction.last.subject)
|
|
||||||
assert_equal(@mod, ModAction.last.creator)
|
|
||||||
end
|
|
||||||
|
|
||||||
should "promote the user to unrestricted uploads" do
|
|
||||||
put_auth admin_user_path(@user), @mod, params: { user: { level: User::Levels::BUILDER, can_upload_free: true }}
|
|
||||||
|
|
||||||
assert_redirected_to(edit_admin_user_path(@user.reload))
|
|
||||||
assert_equal(true, @user.is_builder?)
|
|
||||||
assert_equal(true, @user.can_upload_free?)
|
|
||||||
assert_equal(false, @user.can_approve_posts?)
|
|
||||||
assert_match(/granted unlimited upload privileges to "#{@user.name}":\/users\/#{@user.id}/, ModAction.first.description)
|
|
||||||
assert_match(/promoted "#{@user.name}":\/users\/#{@user.id} from Member to Builder/, ModAction.last.description)
|
|
||||||
assert_equal(@user, ModAction.first.subject)
|
|
||||||
assert_equal(@mod, ModAction.first.creator)
|
|
||||||
assert_equal(@user, ModAction.last.subject)
|
|
||||||
assert_equal(@mod, ModAction.last.creator)
|
|
||||||
end
|
|
||||||
|
|
||||||
should "promote the user to approver" do
|
|
||||||
put_auth admin_user_path(@user), @mod, params: { user: { level: User::Levels::BUILDER, can_approve_posts: true }}
|
|
||||||
|
|
||||||
assert_redirected_to(edit_admin_user_path(@user.reload))
|
|
||||||
assert_equal(true, @user.is_builder?)
|
|
||||||
assert_equal(false, @user.can_upload_free?)
|
|
||||||
assert_equal(true, @user.can_approve_posts?)
|
|
||||||
assert_match(/granted approval privileges to "#{@user.name}":\/users\/#{@user.id}/, ModAction.first.description)
|
|
||||||
assert_match(/promoted "#{@user.name}":\/users\/#{@user.id} from Member to Builder/, ModAction.last.description)
|
|
||||||
assert_equal(@user, ModAction.first.subject)
|
|
||||||
assert_equal(@mod, ModAction.first.creator)
|
|
||||||
assert_equal(@user, ModAction.last.subject)
|
assert_equal(@user, ModAction.last.subject)
|
||||||
assert_equal(@mod, ModAction.last.creator)
|
assert_equal(@mod, ModAction.last.creator)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -522,8 +522,8 @@ class PostsControllerTest < ActionDispatch::IntegrationTest
|
|||||||
|
|
||||||
context "with everything" do
|
context "with everything" do
|
||||||
setup do
|
setup do
|
||||||
@admin = create(:admin_user, can_approve_posts: true)
|
@admin = create(:admin_user)
|
||||||
@builder = create(:builder_user, can_approve_posts: true)
|
@approver = create(:approver_user)
|
||||||
|
|
||||||
as(@user) do
|
as(@user) do
|
||||||
@post.update!(tag_string: "1girl solo highres blah 2001")
|
@post.update!(tag_string: "1girl solo highres blah 2001")
|
||||||
@@ -545,7 +545,7 @@ class PostsControllerTest < ActionDispatch::IntegrationTest
|
|||||||
#create(:post_appeal, post: @post, creator: @user)
|
#create(:post_appeal, post: @post, creator: @user)
|
||||||
create(:post_vote, post: @post, user: @user)
|
create(:post_vote, post: @post, user: @user)
|
||||||
create(:favorite, post: @post, user: @user)
|
create(:favorite, post: @post, user: @user)
|
||||||
create(:moderation_report, model: @comment, creator: @builder)
|
create(:moderation_report, model: @comment, creator: @approver)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -560,7 +560,7 @@ class PostsControllerTest < ActionDispatch::IntegrationTest
|
|||||||
end
|
end
|
||||||
|
|
||||||
should "render for a builder" do
|
should "render for a builder" do
|
||||||
get_auth post_path(@post), @builder
|
get_auth post_path(@post), @approver
|
||||||
assert_response :success
|
assert_response :success
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -570,7 +570,7 @@ class PostsControllerTest < ActionDispatch::IntegrationTest
|
|||||||
end
|
end
|
||||||
|
|
||||||
should "render for a builder with a search query" do
|
should "render for a builder with a search query" do
|
||||||
get_auth post_path(@post, q: "tagme"), @builder
|
get_auth post_path(@post, q: "tagme"), @approver
|
||||||
assert_response :success
|
assert_response :success
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
|
|||||||
context "index action" do
|
context "index action" do
|
||||||
setup do
|
setup do
|
||||||
@mod_user = create(:moderator_user, name: "yukari")
|
@mod_user = create(:moderator_user, name: "yukari")
|
||||||
@other_user = create(:builder_user, can_upload_free: true, inviter: @mod_user, created_at: 2.weeks.ago)
|
@other_user = create(:contributor_user, inviter: @mod_user, created_at: 2.weeks.ago)
|
||||||
@uploader = create(:user, created_at: 2.weeks.ago)
|
@uploader = create(:user, created_at: 2.weeks.ago)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -41,7 +41,6 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
|
|||||||
|
|
||||||
should respond_to_search({}).with { [@uploader, @other_user, @mod_user, @user, User.system] }
|
should respond_to_search({}).with { [@uploader, @other_user, @mod_user, @user, User.system] }
|
||||||
should respond_to_search(min_level: User::Levels::BUILDER).with { [@other_user, @mod_user, User.system] }
|
should respond_to_search(min_level: User::Levels::BUILDER).with { [@other_user, @mod_user, User.system] }
|
||||||
should respond_to_search(can_upload_free: "true").with { @other_user }
|
|
||||||
should respond_to_search(name_matches: "yukari").with { @mod_user }
|
should respond_to_search(name_matches: "yukari").with { @mod_user }
|
||||||
|
|
||||||
context "using includes" do
|
context "using includes" do
|
||||||
@@ -114,7 +113,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
|
|||||||
context "show action" do
|
context "show action" do
|
||||||
setup do
|
setup do
|
||||||
# flesh out profile to get more test coverage of user presenter.
|
# flesh out profile to get more test coverage of user presenter.
|
||||||
@user = create(:user, can_approve_posts: true, created_at: 2.weeks.ago)
|
@user = create(:approver, created_at: 2.weeks.ago)
|
||||||
as(@user) do
|
as(@user) do
|
||||||
create(:saved_search, user: @user)
|
create(:saved_search, user: @user)
|
||||||
create(:post, uploader: @user, tag_string: "fav:#{@user.name}")
|
create(:post, uploader: @user, tag_string: "fav:#{@user.name}")
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ require 'test_helper'
|
|||||||
class ApproverPrunerTest < ActiveSupport::TestCase
|
class ApproverPrunerTest < ActiveSupport::TestCase
|
||||||
context "ApproverPruner" do
|
context "ApproverPruner" do
|
||||||
setup do
|
setup do
|
||||||
@approver = create(:user, can_approve_posts: true)
|
@approver = create(:approver)
|
||||||
end
|
end
|
||||||
|
|
||||||
should "demote inactive approvers" do
|
should "demote inactive approvers" do
|
||||||
assert_equal([@approver.id], ApproverPruner.inactive_approvers.map(&:id))
|
assert_equal([@approver.id], ApproverPruner.inactive_approvers.map(&:id))
|
||||||
assert_nothing_raised { ApproverPruner.prune! }
|
assert_nothing_raised { ApproverPruner.prune! }
|
||||||
assert_equal(false, @approver.reload.can_approve_posts)
|
assert_equal(User::Levels::CONTRIBUTOR, @approver.reload.level)
|
||||||
end
|
end
|
||||||
|
|
||||||
should "not demote active approvers" do
|
should "not demote active approvers" do
|
||||||
@@ -22,7 +22,7 @@ class ApproverPrunerTest < ActiveSupport::TestCase
|
|||||||
should "not demote recently promoted approvers" do
|
should "not demote recently promoted approvers" do
|
||||||
as(create(:admin_user)) do
|
as(create(:admin_user)) do
|
||||||
@user = create(:user)
|
@user = create(:user)
|
||||||
@user.promote_to!(User::Levels::BUILDER, can_approve_posts: true)
|
@user.promote_to!(User::Levels::APPROVER)
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_not_includes(ApproverPruner.inactive_approvers.map(&:id), @user.id)
|
assert_not_includes(ApproverPruner.inactive_approvers.map(&:id), @user.id)
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class PostAppealTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
context "for users with unrestricted uploads" do
|
context "for users with unrestricted uploads" do
|
||||||
should "should not have an appeal limit" do
|
should "should not have an appeal limit" do
|
||||||
@user = create(:user, can_upload_free: true)
|
@user = create(:contributor)
|
||||||
create_list(:post_appeal, 10, creator: @user)
|
create_list(:post_appeal, 10, creator: @user)
|
||||||
|
|
||||||
assert_equal(15, @user.upload_limit.upload_slots)
|
assert_equal(15, @user.upload_limit.upload_slots)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ class PostApprovalTest < ActiveSupport::TestCase
|
|||||||
setup do
|
setup do
|
||||||
@user = create(:user, created_at: 2.weeks.ago)
|
@user = create(:user, created_at: 2.weeks.ago)
|
||||||
@post = create(:post, uploader: @user, is_pending: true)
|
@post = create(:post, uploader: @user, is_pending: true)
|
||||||
@approver = create(:user, can_approve_posts: true)
|
@approver = create(:approver)
|
||||||
end
|
end
|
||||||
|
|
||||||
context "a pending post" do
|
context "a pending post" do
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ class PostFlagTest < ActiveSupport::TestCase
|
|||||||
context "PostFlag: " do
|
context "PostFlag: " do
|
||||||
context "an approver" do
|
context "an approver" do
|
||||||
should "be able to flag an unlimited number of posts" do
|
should "be able to flag an unlimited number of posts" do
|
||||||
@user = create(:user, can_approve_posts: true)
|
@user = create(:approver)
|
||||||
|
|
||||||
assert_nothing_raised do
|
assert_nothing_raised do
|
||||||
create_list(:post_flag, 6, creator: @user, status: :pending)
|
create_list(:post_flag, 6, creator: @user, status: :pending)
|
||||||
|
|||||||
Reference in New Issue
Block a user