Rename "Blocked" to "Silenced"

This commit is contained in:
Robin Ward 2017-11-10 12:18:08 -05:00
parent ec3d800492
commit 1f14350220
51 changed files with 366 additions and 332 deletions

View File

@ -7,7 +7,7 @@ import computed from 'ember-addons/ember-computed-decorators';
const PROBLEMS_CHECK_MINUTES = 1;
const ATTRIBUTES = [ 'disk_space','admins', 'moderators', 'blocked', 'suspended', 'top_traffic_sources',
const ATTRIBUTES = [ 'disk_space','admins', 'moderators', 'silenced', 'suspended', 'top_traffic_sources',
'top_referred_topics', 'updated_at'];
const REPORTS = [ 'global_reports', 'page_view_reports', 'private_message_reports', 'http_reports',

View File

@ -58,8 +58,8 @@ export default Ember.Controller.extend(CanCheckEmails, {
saveTrustLevel() { return this.get("model").saveTrustLevel(); },
restoreTrustLevel() { return this.get("model").restoreTrustLevel(); },
lockTrustLevel(locked) { return this.get("model").lockTrustLevel(locked); },
unblock() { return this.get("model").unblock(); },
block() { return this.get("model").block(); },
unsilence() { return this.get("model").unsilence(); },
silence() { return this.get("model").silence(); },
deleteAllPosts() { return this.get("model").deleteAllPosts(); },
anonymize() { return this.get('model').anonymize(); },
destroy() { return this.get('model').destroy(); },

View File

@ -299,32 +299,32 @@ const AdminUser = Discourse.User.extend({
});
},
unblock() {
this.set('blockingUser', true);
return ajax('/admin/users/' + this.id + '/unblock', {
unsilence() {
this.set('silencingUser', true);
return ajax('/admin/users/' + this.id + '/unsilence', {
type: 'PUT'
}).then(function() {
window.location.reload();
}).catch(function(e) {
var error = I18n.t('admin.user.unblock_failed', { error: "http: " + e.status + " - " + e.body });
var error = I18n.t('admin.user.unsilence_failed', { error: "http: " + e.status + " - " + e.body });
bootbox.alert(error);
});
},
block() {
silence() {
const user = this,
message = I18n.t("admin.user.block_confirm");
message = I18n.t("admin.user.silence_confirm");
const performBlock = function() {
user.set('blockingUser', true);
return ajax('/admin/users/' + user.id + '/block', {
const performSilence = function() {
user.set('silencingUser', true);
return ajax('/admin/users/' + user.id + '/silence', {
type: 'PUT'
}).then(function() {
window.location.reload();
}).catch(function(e) {
var error = I18n.t('admin.user.block_failed', { error: "http: " + e.status + " - " + e.body });
var error = I18n.t('admin.user.silence_failed', { error: "http: " + e.status + " - " + e.body });
bootbox.alert(error);
user.set('blockingUser', false);
user.set('silencingUser', false);
});
};
@ -333,9 +333,9 @@ const AdminUser = Discourse.User.extend({
"class": "cancel",
"link": true
}, {
"label": `${iconHTML('exclamation-triangle')} ` + I18n.t('admin.user.block_accept'),
"label": `${iconHTML('exclamation-triangle')} ` + I18n.t('admin.user.silence_accept'),
"class": "btn btn-danger",
"callback": function() { performBlock(); }
"callback": function() { performSilence(); }
}];
bootbox.dialog(message, buttons, { "classes": "delete-user-modal" });

View File

@ -37,8 +37,8 @@
<tr>
<td class="title">{{d-icon "shield"}} {{i18n 'admin.dashboard.moderators'}}</td>
<td class="value">{{#link-to 'adminUsersList.show' 'moderators'}}{{moderators}}{{/link-to}}</td>
<td class="title">{{d-icon "ban"}} {{i18n 'admin.dashboard.blocked'}}</td>
<td class="value">{{#link-to 'adminUsersList.show' 'blocked'}}{{blocked}}{{/link-to}}</td>
<td class="title">{{d-icon "ban"}} {{i18n 'admin.dashboard.silenced'}}</td>
<td class="value">{{#link-to 'adminUsersList.show' 'silenced'}}{{silenced}}{{/link-to}}</td>
</tr>
</table>
</div>

View File

@ -347,17 +347,17 @@
</div>
{{/if}}
<div class="display-row {{if model.blocked 'highlight-danger'}}">
<div class='field'>{{i18n 'admin.user.blocked'}}</div>
<div class='value'>{{i18n-yes-no model.blocked}}</div>
<div class="display-row {{if model.silenced 'highlight-danger'}}">
<div class='field'>{{i18n 'admin.user.silenced'}}</div>
<div class='value'>{{i18n-yes-no model.silenced}}</div>
<div class='controls'>
{{#conditional-loading-spinner size="small" condition=model.blockingUser}}
{{#if model.blocked}}
{{d-button action="unblock" icon="thumbs-o-up" label="admin.user.unblock"}}
{{i18n 'admin.user.block_explanation'}}
{{#conditional-loading-spinner size="small" condition=model.silencingUser}}
{{#if model.silenced}}
{{d-button action="unsilence" icon="thumbs-o-up" label="admin.user.unsilence"}}
{{i18n 'admin.user.silence_explanation'}}
{{else}}
{{d-button action="block" icon="ban" label="admin.user.block"}}
{{i18n 'admin.user.block_explanation'}}
{{d-button action="silence" icon="ban" label="admin.user.silence"}}
{{i18n 'admin.user.silence_explanation'}}
{{/if}}
{{/conditional-loading-spinner}}
</div>

View File

@ -8,7 +8,7 @@
{{/if}}
{{nav-item route='adminUsersList.show' routeParam='staff' label='admin.users.nav.staff'}}
{{nav-item route='adminUsersList.show' routeParam='suspended' label='admin.users.nav.suspended'}}
{{nav-item route='adminUsersList.show' routeParam='blocked' label='admin.users.nav.blocked'}}
{{nav-item route='adminUsersList.show' routeParam='silenced' label='admin.users.nav.silenced'}}
{{nav-item route='adminUsersList.show' routeParam='suspect' label='admin.users.nav.suspect'}}
</ul>
</div>

View File

@ -10,8 +10,8 @@
{{#user-link user=post.user}}
{{post.user.username}}
{{/user-link}}
{{#if post.user.blocked}}
{{d-icon "ban" title="user.blocked_tooltip"}}
{{#if post.user.silenced}}
{{d-icon "ban" title="user.silenced_tooltip"}}
{{/if}}
</span>
</div>

View File

@ -5,7 +5,7 @@ class Admin::EmailTemplatesController < Admin::AdminController
"custom_invite_mailer", "custom_invite_forum_mailer",
"new_version_mailer", "new_version_mailer_with_notes", "queued_posts_reminder",
"system_messages.backup_failed", "system_messages.backup_succeeded",
"system_messages.blocked_by_staff", "system_messages.bulk_invite_failed",
"system_messages.silenced_by_staff", "system_messages.bulk_invite_failed",
"system_messages.bulk_invite_succeeded", "system_messages.csv_export_failed",
"system_messages.csv_export_succeeded", "system_messages.download_remote_images_disabled",
"system_messages.email_error_notification", "system_messages.email_reject_auto_generated",
@ -19,7 +19,7 @@ class Admin::EmailTemplatesController < Admin::AdminController
"system_messages.pending_users_reminder", "system_messages.post_hidden",
"system_messages.restore_failed", "system_messages.restore_succeeded",
"system_messages.spam_post_blocked", "system_messages.too_many_spam_flags",
"system_messages.unblocked", "system_messages.user_automatically_blocked",
"system_messages.unsilenced", "system_messages.user_automatically_silenced",
"system_messages.welcome_invite", "system_messages.welcome_user", "test_mailer",
"user_notifications.account_created", "user_notifications.admin_login",
"user_notifications.confirm_new_email", "user_notifications.confirm_old_email",

View File

@ -15,8 +15,8 @@ class Admin::UsersController < Admin::AdminController
:approve,
:activate,
:deactivate,
:block,
:unblock,
:silence,
:unsilence,
:trust_level,
:trust_level_lock,
:add_group,
@ -272,15 +272,15 @@ class Admin::UsersController < Admin::AdminController
render body: nil
end
def block
guardian.ensure_can_block_user! @user
UserBlocker.block(@user, current_user, keep_posts: true)
def silence
guardian.ensure_can_silence_user! @user
UserSilencer.silence(@user, current_user, keep_posts: true)
render body: nil
end
def unblock
guardian.ensure_can_unblock_user! @user
UserBlocker.unblock(@user, current_user)
def unsilence
guardian.ensure_can_unsilence_user! @user
UserSilencer.unsilence(@user, current_user)
render body: nil
end

View File

@ -10,7 +10,7 @@ module Jobs
HEADER_ATTRS_FOR ||= HashWithIndifferentAccess.new(
user_archive: ['topic_title', 'category', 'sub_category', 'is_pm', 'post', 'like_count', 'reply_count', 'url', 'created_at'],
user_list: ['id', 'name', 'username', 'email', 'title', 'created_at', 'last_seen_at', 'last_posted_at', 'last_emailed_at', 'trust_level', 'approved', 'suspended_at', 'suspended_till', 'blocked', 'active', 'admin', 'moderator', 'ip_address', 'staged'],
user_list: ['id', 'name', 'username', 'email', 'title', 'created_at', 'last_seen_at', 'last_posted_at', 'last_emailed_at', 'trust_level', 'approved', 'suspended_at', 'suspended_till', 'silenced', 'active', 'admin', 'moderator', 'ip_address', 'staged'],
user_stats: ['topics_entered', 'posts_read_count', 'time_read', 'topic_count', 'post_count', 'likes_given', 'likes_received'],
user_profile: ['location', 'website', 'views'],
user_sso: ['external_id', 'external_email', 'external_username', 'external_name', 'external_avatar_url'],
@ -181,7 +181,7 @@ module Jobs
def get_base_user_array(user)
user_array = []
user_array.push(user.id, escape_comma(user.name), user.username, user.email, escape_comma(user.title), user.created_at, user.last_seen_at, user.last_posted_at, user.last_emailed_at, user.trust_level, user.approved, user.suspended_at, user.suspended_till, user.blocked, user.active, user.admin, user.moderator, user.ip_address, user.staged, user.user_stat.topics_entered, user.user_stat.posts_read_count, user.user_stat.time_read, user.user_stat.topic_count, user.user_stat.post_count, user.user_stat.likes_given, user.user_stat.likes_received, escape_comma(user.user_profile.location), user.user_profile.website, user.user_profile.views)
user_array.push(user.id, escape_comma(user.name), user.username, user.email, escape_comma(user.title), user.created_at, user.last_seen_at, user.last_posted_at, user.last_emailed_at, user.trust_level, user.approved, user.suspended_at, user.suspended_till, user.silenced, user.active, user.admin, user.moderator, user.ip_address, user.staged, user.user_stat.topics_entered, user.user_stat.posts_read_count, user.user_stat.time_read, user.user_stat.topic_count, user.user_stat.post_count, user.user_stat.likes_given, user.user_stat.likes_received, escape_comma(user.user_profile.location), user.user_profile.website, user.user_profile.views)
end
def add_single_sign_on(user, user_info_array)

View File

@ -15,7 +15,7 @@ module Jobs
return if !post || post.trashed? || post.user_deleted? || !post.topic
users =
User.activated.not_blocked.not_suspended.real
User.activated.not_silenced.not_suspended.real
.joins(:user_option)
.where('user_options.mailing_list_mode AND user_options.mailing_list_mode_frequency > 0')
.where('NOT EXISTS (

View File

@ -22,7 +22,7 @@ module Jobs
ub.badge_id = #{Badge::Anniversary} AND
ub.granted_at BETWEEN '#{fmt_start_date}' AND '#{fmt_end_date}'
WHERE u.active AND
NOT u.blocked AND
NOT u.silenced AND
NOT p.hidden AND
p.deleted_at IS NULL AND
t.visible AND

View File

@ -147,7 +147,7 @@ class AdminDashboardData
admins: User.admins.count,
moderators: User.moderators.count,
suspended: User.suspended.count,
blocked: User.blocked.count,
silenced: User.silenced.count,
top_referrers: IncomingLinksReport.find('top_referrers').as_json,
top_traffic_sources: IncomingLinksReport.find('top_traffic_sources').as_json,
top_referred_topics: IncomingLinksReport.find('top_referred_topics').as_json,

View File

@ -82,7 +82,7 @@ class DirectoryItem < ActiveRecord::Base
LEFT OUTER JOIN posts AS p ON ua.target_post_id = p.id
LEFT OUTER JOIN categories AS c ON t.category_id = c.id
WHERE u.active
AND NOT u.blocked
AND NOT u.silenced
AND t.deleted_at IS NULL
AND COALESCE(t.visible, true)
AND p.deleted_at IS NULL

View File

@ -66,7 +66,7 @@ class QueuedPost < ActiveRecord::Base
QueuedPost.transaction do
change_to!(:approved, approved_by)
UserBlocker.unblock(user, approved_by) if user.blocked?
UserSilencer.unsilence(user, approved_by) if user.silenced?
created_post = creator.create

View File

@ -146,9 +146,9 @@ class User < ActiveRecord::Base
# TODO-PERF: There is no indexes on any of these
# and NotifyMailingListSubscribers does a select-all-and-loop
# may want to create an index on (active, blocked, suspended_till)?
scope :blocked, -> { where(blocked: true) }
scope :not_blocked, -> { where(blocked: false) }
# may want to create an index on (active, silence, suspended_till)?
scope :silenced, -> { where(silenced: true) }
scope :not_silenced, -> { where(silenced: false) }
scope :suspended, -> { where('suspended_till IS NOT NULL AND suspended_till > ?', Time.zone.now) }
scope :not_suspended, -> { where('suspended_till IS NULL OR suspended_till <= ?', Time.zone.now) }
scope :activated, -> { where(active: true) }
@ -1141,7 +1141,7 @@ end
# flag_level :integer default(0), not null
# ip_address :inet
# moderator :boolean default(FALSE)
# blocked :boolean default(FALSE)
# silenced :boolean default(FALSE)
# title :string
# uploaded_avatar_id :integer
# locale :string(10)

View File

@ -45,8 +45,8 @@ class UserHistory < ActiveRecord::Base
delete_category: 27,
create_category: 28,
change_site_text: 29,
block_user: 30,
unblock_user: 31,
silence_user: 30,
unsilence_user: 31,
grant_admin: 32,
revoke_admin: 33,
grant_moderation: 34,
@ -90,8 +90,8 @@ class UserHistory < ActiveRecord::Base
:change_category_settings,
:delete_category,
:create_category,
:block_user,
:unblock_user,
:silence_user,
:unsilence_user,
:grant_admin,
:revoke_admin,
:grant_moderation,

View File

@ -22,7 +22,7 @@ class AdminUserListSerializer < BasicUserSerializer
:suspended_at,
:suspended_till,
:suspended,
:blocked,
:silenced,
:time_read,
:staged

View File

@ -1,37 +1,37 @@
class SpamRule::AutoBlock
class SpamRule::AutoSilence
def initialize(user)
@user = user
end
def self.block?(user)
self.new(user).block?
def self.silence?(user)
self.new(user).silence?
end
def self.punish!(user)
self.new(user).block_user
self.new(user).silence_user
end
def perform
block_user if block?
silence_user if silence?
end
def block?
return true if @user.blocked?
def silence?
return true if @user.silenced?
return false if @user.staged?
return false if @user.has_trust_level?(TrustLevel[1])
if SiteSetting.num_spam_flags_to_block_new_user > (0) &&
SiteSetting.num_users_to_block_new_user > (0) &&
num_spam_flags_against_user >= (SiteSetting.num_spam_flags_to_block_new_user) &&
num_users_who_flagged_spam_against_user >= (SiteSetting.num_users_to_block_new_user)
if SiteSetting.num_spam_flags_to_silence_new_user > (0) &&
SiteSetting.num_users_to_silence_new_user > (0) &&
num_spam_flags_against_user >= (SiteSetting.num_spam_flags_to_silence_new_user) &&
num_users_who_flagged_spam_against_user >= (SiteSetting.num_users_to_silence_new_user)
return true
end
if SiteSetting.num_tl3_flags_to_block_new_user > (0) &&
SiteSetting.num_tl3_users_to_block_new_user > (0) &&
num_tl3_flags_against_user >= (SiteSetting.num_tl3_flags_to_block_new_user) &&
num_tl3_users_who_flagged >= (SiteSetting.num_tl3_users_to_block_new_user)
if SiteSetting.num_tl3_flags_to_silence_new_user > (0) &&
SiteSetting.num_tl3_users_to_silence_new_user > (0) &&
num_tl3_flags_against_user >= (SiteSetting.num_tl3_flags_to_silence_new_user) &&
num_tl3_users_who_flagged >= (SiteSetting.num_tl3_users_to_silence_new_user)
return true
end
@ -70,10 +70,10 @@ class SpamRule::AutoBlock
.pluck(:id)
end
def block_user
def silence_user
Post.transaction do
if UserBlocker.block(@user, Discourse.system_user, message: :too_many_spam_flags) && SiteSetting.notify_mods_when_user_blocked
GroupMessage.create(Group[:moderators].name, :user_automatically_blocked, user: @user, limit_once_per: false)
if UserSilencer.silence(@user, Discourse.system_user, message: :too_many_spam_flags) && SiteSetting.notify_mods_when_user_silenced
GroupMessage.create(Group[:moderators].name, :user_automatically_silenced, user: @user, limit_once_per: false)
end
end
end

View File

@ -12,7 +12,7 @@ class SpamRulesEnforcer
end
def enforce!
SpamRule::AutoBlock.new(@user).perform if @user
SpamRule::AutoSilence.new(@user).perform if @user
SpamRule::FlagSockpuppets.new(@post).perform if @post
true
end

View File

@ -273,15 +273,15 @@ class StaffActionLogger
context: category.url))
end
def log_block_user(user, opts = {})
def log_silence_user(user, opts = {})
raise Discourse::InvalidParameters.new(:user) unless user
UserHistory.create(params(opts).merge(action: UserHistory.actions[:block_user],
UserHistory.create(params(opts).merge(action: UserHistory.actions[:silence_user],
target_user_id: user.id))
end
def log_unblock_user(user, opts = {})
def log_unsilence_user(user, opts = {})
raise Discourse::InvalidParameters.new(:user) unless user
UserHistory.create(params(opts).merge(action: UserHistory.actions[:unblock_user],
UserHistory.create(params(opts).merge(action: UserHistory.actions[:unsilence_user],
target_user_id: user.id))
end

View File

@ -1,26 +1,26 @@
class UserBlocker
class UserSilencer
def initialize(user, by_user = nil, opts = {})
@user, @by_user, @opts = user, by_user, opts
end
def self.block(user, by_user = nil, opts = {})
UserBlocker.new(user, by_user, opts).block
def self.silence(user, by_user = nil, opts = {})
UserSilencer.new(user, by_user, opts).silence
end
def self.unblock(user, by_user = nil, opts = {})
UserBlocker.new(user, by_user, opts).unblock
def self.unsilence(user, by_user = nil, opts = {})
UserSilencer.new(user, by_user, opts).unsilence
end
def block
def silence
hide_posts unless @opts[:keep_posts]
unless @user.blocked?
@user.blocked = true
unless @user.silenced?
@user.silenced = true
if @user.save
message_type = @opts[:message] || :blocked_by_staff
message_type = @opts[:message] || :silenced_by_staff
post = SystemMessage.create(@user, message_type)
if post && @by_user
StaffActionLogger.new(@by_user).log_block_user(@user, context: "#{message_type}: '#{post.topic&.title rescue ''}' #{@opts[:reason]}")
StaffActionLogger.new(@by_user).log_silence_user(@user, context: "#{message_type}: '#{post.topic&.title rescue ''}' #{@opts[:reason]}")
end
end
else
@ -36,11 +36,11 @@ class UserBlocker
Topic.where(id: topic_ids).update_all(visible: false) unless topic_ids.empty?
end
def unblock
@user.blocked = false
def unsilence
@user.silenced = false
if @user.save
SystemMessage.create(@user, :unblocked)
StaffActionLogger.new(@by_user).log_unblock_user(@user) if @by_user
SystemMessage.create(@user, :unsilenced)
StaffActionLogger.new(@by_user).log_unsilence_user(@user) if @by_user
end
end

View File

@ -605,7 +605,7 @@ en:
admin: "{{user}} is an admin"
moderator_tooltip: "This user is a moderator"
admin_tooltip: "This user is an admin"
blocked_tooltip: "This user is blocked"
silenced_tooltip: "This user is silenced"
suspended_notice: "This user is suspended until {{date}}."
suspended_permanently: "This user is suspended."
suspended_reason: "Reason: "
@ -2575,7 +2575,7 @@ en:
no_problems: "No problems were found."
moderators: 'Moderators:'
admins: 'Admins:'
blocked: 'Blocked:'
silenced: 'Silenced:'
suspended: 'Suspended:'
private_messages_short: "Msgs"
private_messages_title: "Messages"
@ -3136,8 +3136,8 @@ en:
change_category_settings: "change category settings"
delete_category: "delete category"
create_category: "create category"
block_user: "block user"
unblock_user: "unblock user"
silence_user: "silence user"
unsilence_user: "unsilence user"
grant_admin: "grant admin"
revoke_admin: "revoke admin"
grant_moderation: "grant moderation"
@ -3235,7 +3235,7 @@ en:
pending: "Pending"
staff: 'Staff'
suspended: 'Suspended'
blocked: 'Blocked'
silenced: 'Silenced'
suspect: 'Suspect'
approved: "Approved?"
approved_selected:
@ -3256,7 +3256,7 @@ en:
staff: "Staff"
admins: 'Admin Users'
moderators: 'Moderators'
blocked: 'Blocked Users'
silenced: 'Silenced Users'
suspended: 'Suspended Users'
suspect: 'Suspect Users'
reject_successful:
@ -3287,12 +3287,12 @@ en:
# keys ending with _MF use message format, see https://meta.discourse.org/t/message-format-support-for-localization/7035 for details
delete_all_posts_confirm_MF: "You are about to delete {POSTS, plural, one {1 post} other {# posts}} and {TOPICS, plural, one {1 topic} other {# topics}}. Are you sure?"
suspend: "Suspend"
unsuspend: "Unsuspend"
suspended: "Suspended?"
silence: "Silence"
unsilence: "Unsilence"
silenced: "Silenced?"
moderator: "Moderator?"
admin: "Admin?"
blocked: "Blocked?"
suspended: "Suspended?"
staged: "Staged?"
show_admin_profile: "Admin"
refresh_browsers: "Force browser refresh"
@ -3308,8 +3308,8 @@ en:
grant_admin_confirm: "We've sent you an email to verify the new administrator. Please open it and follow the instructions."
revoke_moderation: 'Revoke Moderation'
grant_moderation: 'Grant Moderation'
unblock: 'Unblock'
block: 'Block'
unsuspend: 'Unsuspend'
suspend: 'Suspend'
reputation: Reputation
permissions: Permissions
activity: Activity
@ -3356,10 +3356,10 @@ en:
activate_failed: "There was a problem activating the user."
deactivate_account: "Deactivate Account"
deactivate_failed: "There was a problem deactivating the user."
unblock_failed: 'There was a problem unblocking the user.'
block_failed: 'There was a problem blocking the user.'
block_confirm: 'Are you sure you want to block this user? They will not be able to create any new topics or posts.'
block_accept: 'Yes, block this user'
unsilence_failed: 'There was a problem unsilencing the user.'
silence_failed: 'There was a problem unsilencing the user.'
silence_confirm: 'Are you sure you want to silence this user? They will not be able to create any new topics or posts.'
silence_accept: 'Yes, silence this user'
bounce_score: "Bounce Score"
reset_bounce_score:
label: "Reset"
@ -3368,7 +3368,7 @@ en:
deactivate_explanation: "A deactivated user must re-validate their email."
suspended_explanation: "A suspended user can't log in."
block_explanation: "A blocked user can't post or start topics."
silence_explanation: "A silenced user can't post or start topics."
staged_explanation: "A staged user can only post via email in specific topics."
bounce_score_explanation:
none: "No bounces were received recently from that email."

View File

@ -70,7 +70,7 @@ en:
no_body_detected_error: "Happens when we couldn't extract a body and there were no attachments."
no_sender_detected_error: "Happens when we couldn't find a valid email address in the From header."
inactive_user_error: "Happens when the sender is not active."
blocked_user_error: "Happens when the sender has been blocked."
silenced_user_error: "Happens when the sender has been silenced."
bad_destination_address: "Happens when none of the email addresses in To/Cc/Bcc fields matched a configured incoming email address."
strangers_not_allowed_error: "Happens when a user tried to create a new topic in a category they're not a member of."
insufficient_trust_level_error: "Happens when a user tried to create a new topic in a category they don't have the required trust level for."
@ -1046,11 +1046,11 @@ en:
tl3_additional_likes_per_day_multiplier: "Increase limit of likes per day for tl3 (regular) by multiplying with this number"
tl4_additional_likes_per_day_multiplier: "Increase limit of likes per day for tl4 (leader) by multiplying with this number"
num_spam_flags_to_block_new_user: "If a new user's posts get this many spam flags from num_users_to_block_new_user different users, hide all their posts and prevent future posting. 0 to disable."
num_users_to_block_new_user: "If a new user's posts get num_spam_flags_to_block_new_user spam flags from this many different users, hide all their posts and prevent future posting. 0 to disable."
num_tl3_flags_to_block_new_user: "If a new user's posts get this many flags from num_tl3_users_to_block_new_user different trust level 3 users, hide all their posts and prevent future posting. 0 to disable."
num_tl3_users_to_block_new_user: "If a new user's posts get num_tl3_flags_to_block_new_user flags from this many different trust level 3 users, hide all their posts and prevent future posting. 0 to disable."
notify_mods_when_user_blocked: "If a user is automatically blocked, send a message to all moderators."
num_spam_flags_to_silence_new_user: "If a new user's posts get this many spam flags from num_users_to_silence_new_user different users, hide all their posts and prevent future posting. 0 to disable."
num_users_to_silence_new_user: "If a new user's posts get num_spam_flags_to_silence_new_user spam flags from this many different users, hide all their posts and prevent future posting. 0 to disable."
num_tl3_flags_to_silence_new_user: "If a new user's posts get this many flags from num_tl3_users_to_silence_new_user different trust level 3 users, hide all their posts and prevent future posting. 0 to disable."
num_tl3_users_to_silence_new_user: "If a new user's posts get num_tl3_flags_to_silence_new_user flags from this many different trust level 3 users, hide all their posts and prevent future posting. 0 to disable."
notify_mods_when_user_silenced: "If a user is automatically silenced, send a message to all moderators."
flag_sockpuppets: "If a new user replies to a topic from the same IP address as the new user who started the topic, flag both of their posts as potential spam."
traditional_markdown_linebreaks: "Use traditional linebreaks in Markdown, which require two trailing spaces for a linebreak."
@ -1354,9 +1354,9 @@ en:
auto_respond_to_flag_actions: "Enable automatic reply when disposing a flag."
min_first_post_typing_time: "Minimum amount of time in milliseconds a user must type during first post, if threshold is not met post will automatically enter the needs approval queue. Set to 0 to disable (not recommended)"
auto_block_fast_typers_on_first_post: "Automatically block users that do not meet min_first_post_typing_time"
auto_block_fast_typers_max_trust_level: "Maximum trust level to auto block fast typers"
auto_block_first_post_regex: "Case insensitive regex that if passed will cause first post by user to be blocked and sent to approval queue. Example: raging|a[bc]a , will cause all posts containing raging or aba or aca to be blocked on first. Only applies to first post."
auto_silence_fast_typers_on_first_post: "Automatically silence users that do not meet min_first_post_typing_time"
auto_silence_fast_typers_max_trust_level: "Maximum trust level to auto silence fast typers"
auto_silence_first_post_regex: "Case insensitive regex that if passed will cause first post by user to be silenced and sent to approval queue. Example: raging|a[bc]a , will cause all posts containing raging or aba or aca to be silenced on first. Only applies to first post."
flags_default_topics: "Show flagged topics by default in the admin section"
reply_by_email_enabled: "Enable replying to topics via email."
@ -2172,13 +2172,13 @@ en:
Your account associated with this email address is not activated. Please activate your account before sending emails in.
email_reject_blocked_user:
title: "Email Reject Blocked User"
subject_template: "[%{email_prefix}] Email issue -- Blocked User"
email_reject_silenced_user:
title: "Email Reject Silenced User"
subject_template: "[%{email_prefix}] Email issue -- Silenced User"
text_body_template: |
We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work.
Your account associated with this email address has been blocked.
Your account associated with this email address has been silenced.
email_reject_reply_user_not_matching:
title: "Email Reject User Not Matching"
@ -2324,7 +2324,7 @@ en:
This is an automated message from %{site_name} to let you know that your posts have been temporarily hidden because they were flagged by the community.
As a precautionary measure, your new account has been blocked from creating new replies or topics until a staff member can review your account. We apologize for the inconvenience.
As a precautionary measure, your new account has been silenced from creating new replies or topics until a staff member can review your account. We apologize for the inconvenience.
For additional guidance, please refer to our [community guidelines](%{base_url}/guidelines).
too_many_tl3_flags:
@ -2335,11 +2335,11 @@ en:
This is an automated message from %{site_name} to let you know you that your account has been placed on hold due to a large number of community flags.
As a precautionary measure, your new account has been blocked from creating new replies or topics until a staff member can review your account. We apologize for the inconvenience.
As a precautionary measure, your new account has been silenced from creating new replies or topics until a staff member can review your account. We apologize for the inconvenience.
For additional guidance, please refer to our [community guidelines](%{base_url}/guidelines).
blocked_by_staff:
title: "Blocked by Staff"
silenced_by_staff:
title: "Silenced by Staff"
subject_template: "Account temporarily on hold"
text_body_template: |
Hello,
@ -2350,32 +2350,32 @@ en:
For additional guidance, refer to our [community guidelines](%{base_url}/guidelines).
user_automatically_blocked:
title: "User Automatically Blocked"
subject_template: "New user %{username} blocked by community flags"
user_automatically_silenced:
title: "User Automatically Silenced"
subject_template: "New user %{username} silenced by community flags"
text_body_template: |
This is an automated message.
The new user [%{username}](%{user_url}) was automatically blocked because multiple users flagged %{username}'s post(s).
The new user [%{username}](%{user_url}) was automatically silenced because multiple users flagged %{username}'s post(s).
Please [review the flags](%{base_url}/admin/flags). If %{username} was incorrectly blocked from posting, click the unblock button on [the admin page for this user](%{user_url}).
Please [review the flags](%{base_url}/admin/flags). If %{username} was incorrectly silenced from posting, click the unsilence button on [the admin page for this user](%{user_url}).
This threshold can be changed via the `block_new_user` site settings.
spam_post_blocked:
title: "Spam Post Blocked"
subject_template: "New user %{username} posts blocked due to repeated links"
spam_post_silenced:
title: "Spam Post Silenced"
subject_template: "New user %{username} posts silenced due to repeated links"
text_body_template: |
This is an automated message.
The new user [%{username}](%{user_url}) tried to create multiple posts with links to %{domains}, but those posts were blocked to avoid spam. The user is still able to create new posts that do not link to %{domains}.
The new user [%{username}](%{user_url}) tried to create multiple posts with links to %{domains}, but those posts were silenced to avoid spam. The user is still able to create new posts that do not link to %{domains}.
Please [review the user](%{user_url}).
This can be modified via the `newuser_spam_host_threshold` and `white_listed_spam_host_domains` site settings.
unblocked:
title: "Unblocked"
unsilenced:
title: "Unsilenced"
subject_template: "Account no longer on hold"
text_body_template: |
Hello,

View File

@ -117,8 +117,8 @@ Discourse::Application.routes.draw do
post "log_out", constraints: AdminConstraint.new
put "activate"
put "deactivate"
put "block"
put "unblock"
put "silence"
put "unsilence"
put "trust_level"
put "trust_level_lock"
put "primary_group"

View File

@ -968,11 +968,11 @@ spam:
add_rel_nofollow_to_user_content: true
flags_required_to_hide_post: 3
cooldown_minutes_after_hiding_posts: 10
num_spam_flags_to_block_new_user: 3
num_users_to_block_new_user: 3
num_tl3_flags_to_block_new_user: 4
num_tl3_users_to_block_new_user: 2
notify_mods_when_user_blocked: false
num_spam_flags_to_silence_new_user: 3
num_users_to_silence_new_user: 3
num_tl3_flags_to_silence_new_user: 4
num_tl3_users_to_silence_new_user: 2
notify_mods_when_user_silenced: false
flag_sockpuppets: false
newuser_spam_host_threshold: 3
white_listed_spam_host_domains:
@ -992,9 +992,9 @@ spam:
min: 1
auto_respond_to_flag_actions: true
min_first_post_typing_time: 3000
auto_block_fast_typers_on_first_post: true
auto_block_fast_typers_max_trust_level: 0
auto_block_first_post_regex: ""
auto_silence_fast_typers_on_first_post: true
auto_silence_fast_typers_max_trust_level: 0
auto_silence_first_post_regex: ""
flags_default_topics:
default: false
client: true

View File

@ -61,6 +61,17 @@ ColumnDropper.drop(
}
)
ColumnDropper.drop(
table: 'users',
after_migration: 'RenameBlockedSilence',
columns: %w[
blocked
],
on_drop: ->() {
STDERR.puts 'Removing user blocked column!'
}
)
# User for the smoke tests
if ENV["SMOKE"] == "1"
UserEmail.seed do |ue|

View File

@ -0,0 +1,32 @@
class RenameBlockedSilence < ActiveRecord::Migration[5.1]
def setting(old, new)
execute "UPDATE site_settings SET name='#{new}' where name='#{old}'"
end
def up
add_column :users, :silenced, :boolean, default: false, null: false
execute "UPDATE users set silenced = blocked"
setting :notify_mods_when_user_blocked, :notify_mods_when_user_silenced
setting :auto_block_fast_typers_on_first_post, :auto_silence_fast_typers_on_first_post
setting :auto_block_fast_typers_max_trust_level, :auto_silence_fast_typers_max_trust_level
setting :auto_block_first_post_regex, :auto_silence_first_post_regex
setting :num_spam_flags_to_block_new_user, :num_spam_flags_to_silence_new_user
setting :num_users_to_block_new_user, :num_users_to_silence_new_user
setting :num_tl3_flags_to_block_new_user, :num_tl3_flags_to_silence_new_user
setting :num_tl3_users_to_block_new_user, :num_tl3_users_to_silence_new_user
end
def down
remove_column :users, :silenced
setting :notify_mods_when_user_silenced, :notify_mods_when_user_blocked
setting :auto_silence_fast_typers_on_first_post, :auto_block_fast_typers_on_first_post
setting :auto_silence_fast_typers_max_trust_level, :auto_block_fast_typers_max_trust_level
setting :auto_silence_first_post_regex, :auto_block_first_post_regex
setting :num_spam_flags_to_silence_new_user, :num_spam_flags_to_block_new_user
setting :num_users_to_silence_new_user, :num_users_to_block_new_user
setting :num_tl3_flags_to_silence_new_user, :num_tl3_flags_to_block_new_user
setting :num_tl3_users_to_silence_new_user, :num_tl3_users_to_block_new_user
end
end

View File

@ -94,7 +94,7 @@ class AdminUserIndexQuery
when 'staff' then @query.where("admin or moderator")
when 'admins' then @query.where(admin: true)
when 'moderators' then @query.where(moderator: true)
when 'blocked' then @query.blocked
when 'silenced' then @query.silenced
when 'suspended' then @query.suspended
when 'pending' then @query.not_suspended.where(approved: false, active: true)
when 'suspect' then suspect_users

View File

@ -141,10 +141,10 @@ SQL
SELECT invited_by_id
FROM invites i
JOIN users u2 ON u2.id = i.user_id
WHERE i.deleted_at IS NULL AND u2.active AND u2.trust_level >= #{trust_level.to_i} AND not u2.blocked
WHERE i.deleted_at IS NULL AND u2.active AND u2.trust_level >= #{trust_level.to_i} AND not u2.silenced
GROUP BY invited_by_id
HAVING COUNT(*) >= #{count.to_i}
) AND u.active AND NOT u.blocked AND u.id > 0 AND
) AND u.active AND NOT u.silenced AND u.id > 0 AND
(:backfill OR u.id IN (:user_ids) )
"
end

View File

@ -43,7 +43,7 @@ module Email
when Email::Receiver::EmailNotAllowed then :email_reject_not_allowed_email
when Email::Receiver::AutoGeneratedEmailError then :email_reject_auto_generated
when Email::Receiver::InactiveUserError then :email_reject_inactive_user
when Email::Receiver::BlockedUserError then :email_reject_blocked_user
when Email::Receiver::SilencedUserError then :email_reject_silenced_user
when Email::Receiver::BadDestinationAddress then :email_reject_bad_destination_address
when Email::Receiver::StrangersNotAllowedError then :email_reject_strangers_not_allowed
when Email::Receiver::InsufficientTrustLevelError then :email_reject_insufficient_trust_level

View File

@ -21,7 +21,7 @@ module Email
class NoBodyDetectedError < ProcessingError; end
class NoSenderDetectedError < ProcessingError; end
class InactiveUserError < ProcessingError; end
class BlockedUserError < ProcessingError; end
class SilencedUserError < ProcessingError; end
class BadDestinationAddress < ProcessingError; end
class StrangersNotAllowedError < ProcessingError; end
class InsufficientTrustLevelError < ProcessingError; end
@ -144,7 +144,7 @@ module Email
@incoming_email.update_columns(user_id: user.id)
raise InactiveUserError if !user.active && !user.staged
raise BlockedUserError if user.blocked
raise SilencedUserError if user.silenced?
end
def is_bounce?

View File

@ -25,7 +25,7 @@ class Guardian
def moderator?; false; end
def approved?; false; end
def staged?; false; end
def blocked?; false; end
def silenced?; false; end
def secure_category_ids; []; end
def topic_create_allowed_category_ids; []; end
def has_trust_level?(level); false; end
@ -63,8 +63,8 @@ class Guardian
@user.moderator?
end
def is_blocked?
@user.blocked?
def is_silenced?
@user.silenced?
end
def is_developer?
@ -122,7 +122,7 @@ class Guardian
end
def can_moderate?(obj)
obj && authenticated? && !is_blocked? && (is_staff? || (obj.is_a?(Topic) && @user.has_trust_level?(TrustLevel[4])))
obj && authenticated? && !is_silenced? && (is_staff? || (obj.is_a?(Topic) && @user.has_trust_level?(TrustLevel[4])))
end
alias :can_move_posts? :can_moderate?
alias :can_see_flags? :can_moderate?
@ -300,8 +300,8 @@ class Guardian
(is_staff? || SiteSetting.enable_private_messages) &&
# Can't send PMs to suspended users
(is_staff? || is_group || !target.suspended?) &&
# Blocked users can only send PM to staff
(!is_blocked? || target.staff?)
# Silenced users can only send PM to staff
(!is_silenced? || target.staff?)
end
def cand_send_private_messages_to_email?

View File

@ -80,7 +80,7 @@ module PostGuardian
# Creating Method
def can_create_post?(parent)
(!SpamRule::AutoBlock.block?(@user) || (!!parent.try(:private_message?) && parent.allowed_users.include?(@user))) && (
(!SpamRule::AutoSilence.silence?(@user) || (!!parent.try(:private_message?) && parent.allowed_users.include?(@user))) && (
!parent ||
!parent.category ||
Category.post_create_allowed(self).where(id: parent.category.id).count == 1

View File

@ -30,11 +30,11 @@ module UserGuardian
is_me?(user) || is_admin?
end
def can_block_user?(user)
def can_silence_user?(user)
user && is_staff? && not(user.staff?)
end
def can_unblock_user?(user)
def can_unsilence_user?(user)
user && is_staff?
end

View File

@ -44,14 +44,14 @@ class NewPostManager
is_first_post?(manager) &&
args[:typing_duration_msecs].to_i < SiteSetting.min_first_post_typing_time &&
SiteSetting.auto_block_fast_typers_on_first_post &&
manager.user.trust_level <= SiteSetting.auto_block_fast_typers_max_trust_level
SiteSetting.auto_silence_fast_typers_on_first_post &&
manager.user.trust_level <= SiteSetting.auto_silence_fast_typers_max_trust_level
end
def self.matches_auto_block_regex?(manager)
def self.matches_auto_silence_regex?(manager)
args = manager.args
pattern = SiteSetting.auto_block_first_post_regex
pattern = SiteSetting.auto_silence_first_post_regex
return false unless pattern.present?
return false unless is_first_post?(manager)
@ -59,7 +59,7 @@ class NewPostManager
begin
regex = Regexp.new(pattern, Regexp::IGNORECASE)
rescue => e
Rails.logger.warn "Invalid regex in auto_block_first_post_regex #{e}"
Rails.logger.warn "Invalid regex in auto_silence_first_post_regex #{e}"
return false
end
@ -80,7 +80,7 @@ class NewPostManager
(user.trust_level < SiteSetting.approve_unless_trust_level.to_i) ||
(manager.args[:title].present? && user.trust_level < SiteSetting.approve_new_topics_unless_trust_level.to_i) ||
is_fast_typer?(manager) ||
matches_auto_block_regex?(manager) ||
matches_auto_silence_regex?(manager) ||
WordWatcher.new("#{manager.args[:title]} #{manager.args[:raw]}").requires_approval?
end
@ -110,9 +110,9 @@ class NewPostManager
result = manager.enqueue('default')
if is_fast_typer?(manager)
UserBlocker.block(manager.user, Discourse.system_user, keep_posts: true, reason: I18n.t("user.new_user_typed_too_fast"))
elsif matches_auto_block_regex?(manager)
UserBlocker.block(manager.user, Discourse.system_user, keep_posts: true, reason: I18n.t("user.content_matches_auto_block_regex"))
UserSilencer.silence(manager.user, Discourse.system_user, keep_posts: true, reason: I18n.t("user.new_user_typed_too_fast"))
elsif matches_auto_silence_regex?(manager)
UserSilencer.silence(manager.user, Discourse.system_user, keep_posts: true, reason: I18n.t("user.content_matches_auto_silence_regex"))
end
result

View File

@ -165,12 +165,12 @@ describe AdminUserIndexQuery do
end
describe "with a blocked user" do
describe "with a silenced user" do
let!(:user) { Fabricate(:user, blocked: true) }
let!(:user) { Fabricate(:user, silenced: true) }
it "finds the blocked user" do
query = ::AdminUserIndexQuery.new(query: 'blocked')
it "finds the silenced user" do
query = ::AdminUserIndexQuery.new(query: 'silenced')
expect(query.find_users.count).to eq(1)
end

View File

@ -56,9 +56,9 @@ describe Email::Receiver do
expect { process(:inactive_sender) }.to raise_error(Email::Receiver::InactiveUserError)
end
it "raises a BlockedUserError when the sender has been blocked" do
Fabricate(:user, email: "blocked@bar.com", blocked: true)
expect { process(:blocked_sender) }.to raise_error(Email::Receiver::BlockedUserError)
it "raises a SilencedUserError when the sender has been silenced" do
Fabricate(:user, email: "silenced@bar.com", silenced: true)
expect { process(:silenced_sender) }.to raise_error(Email::Receiver::SilencedUserError)
end
it "doesn't raise an InactiveUserError when the sender is staged" do

View File

@ -193,9 +193,9 @@ describe Guardian do
end
end
context "author is blocked" do
context "author is silenced" do
before do
user.blocked = true
user.silenced = true
user.save
end
@ -852,14 +852,14 @@ describe Guardian do
expect(Guardian.new(user).can_create?(Post, private_message)).to be_falsey
end
it "allows new posts from blocked users included in the pm" do
user.update_attribute(:blocked, true)
it "allows new posts from silenced users included in the pm" do
user.update_attribute(:silenced, true)
private_message.topic_allowed_users.create!(user_id: user.id)
expect(Guardian.new(user).can_create?(Post, private_message)).to be_truthy
end
it "doesn't allow new posts from blocked users not invited to the pm" do
user.update_attribute(:blocked, true)
it "doesn't allow new posts from silenced users not invited to the pm" do
user.update_attribute(:silenced, true)
expect(Guardian.new(user).can_create?(Post, private_message)).to be_falsey
end
end
@ -1374,9 +1374,9 @@ describe Guardian do
expect(Guardian.new(user).can_moderate?(nil)).to be_falsey
end
context 'when user is blocked' do
context 'when user is silenced' do
it 'returns false' do
user.toggle!(:blocked)
user.toggle!(:silenced)
expect(Guardian.new(user).can_moderate?(post)).to be(false)
expect(Guardian.new(user).can_moderate?(topic)).to be(false)
end

View File

@ -583,48 +583,48 @@ describe Admin::UsersController do
end
end
context 'block' do
context 'silence' do
before do
@reg_user = Fabricate(:user)
end
it "raises an error when the user doesn't have permission" do
Guardian.any_instance.expects(:can_block_user?).with(@reg_user).returns(false)
UserBlocker.expects(:block).never
put :block, params: { user_id: @reg_user.id }, format: :json
Guardian.any_instance.expects(:can_silence_user?).with(@reg_user).returns(false)
UserSilencer.expects(:silence).never
put :silence, params: { user_id: @reg_user.id }, format: :json
expect(response).to be_forbidden
end
it "returns a 403 if the user doesn't exist" do
put :block, params: { user_id: 123123 }, format: :json
put :silence, params: { user_id: 123123 }, format: :json
expect(response).to be_forbidden
end
it "punishes the user for spamming" do
UserBlocker.expects(:block).with(@reg_user, @user, anything)
put :block, params: { user_id: @reg_user.id }, format: :json
UserSilencer.expects(:silence).with(@reg_user, @user, anything)
put :silence, params: { user_id: @reg_user.id }, format: :json
end
end
context 'unblock' do
context 'unsilence' do
before do
@reg_user = Fabricate(:user)
end
it "raises an error when the user doesn't have permission" do
Guardian.any_instance.expects(:can_unblock_user?).with(@reg_user).returns(false)
put :unblock, params: { user_id: @reg_user.id }, format: :json
Guardian.any_instance.expects(:can_unsilence_user?).with(@reg_user).returns(false)
put :unsilence, params: { user_id: @reg_user.id }, format: :json
expect(response).to be_forbidden
end
it "returns a 403 if the user doesn't exist" do
put :unblock, params: { user_id: 123123 }, format: :json
put :unsilence, params: { user_id: 123123 }, format: :json
expect(response).to be_forbidden
end
it "punishes the user for spamming" do
UserBlocker.expects(:unblock).with(@reg_user, @user, anything)
put :unblock, params: { user_id: @reg_user.id }, format: :json
UserSilencer.expects(:unsilence).with(@reg_user, @user, anything)
put :unsilence, params: { user_id: @reg_user.id }, format: :json
end
end

View File

@ -695,7 +695,7 @@ describe PostsController do
context "fast typing" do
before do
SiteSetting.min_first_post_typing_time = 3000
SiteSetting.auto_block_fast_typers_max_trust_level = 1
SiteSetting.auto_silence_fast_typers_max_trust_level = 1
end
it 'queues the post if min_first_post_typing_time is not met' do
@ -710,7 +710,7 @@ describe PostsController do
expect(parsed["action"]).to eq("enqueued")
user.reload
expect(user.blocked).to eq(true)
expect(user.silenced).to eq(true)
qp = QueuedPost.first
@ -718,7 +718,7 @@ describe PostsController do
qp.approve!(mod)
user.reload
expect(user.blocked).to eq(false)
expect(user.silenced).to eq(false)
end
it "doesn't enqueue replies when the topic is closed" do
@ -749,8 +749,8 @@ describe PostsController do
end
end
it 'blocks correctly based on auto_block_first_post_regex' do
SiteSetting.auto_block_first_post_regex = "I love candy|i eat s[1-5]"
it 'silences correctly based on auto_silence_first_post_regex' do
SiteSetting.auto_silence_first_post_regex = "I love candy|i eat s[1-5]"
post :create, params: {
raw: 'this is the test content',
@ -763,7 +763,7 @@ describe PostsController do
expect(parsed["action"]).to eq("enqueued")
user.reload
expect(user.blocked).to eq(true)
expect(user.silenced).to eq(true)
end
it "can send a message to a group" do

View File

@ -1,9 +0,0 @@
Return-Path: <blocked@bar.com>
From: Foo Bar <blocked@bar.com>
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <8@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
Lorem ipsum dolor sit amet, consectetur adipiscing elit.

View File

@ -4,7 +4,7 @@ require 'rails_helper'
describe SpamRulesEnforcer do
describe 'auto-blocking users based on flagging' do
describe 'auto-silenceing users based on flagging' do
let!(:admin) { Fabricate(:admin) } # needed to send a system message
let!(:moderator) { Fabricate(:moderator) }
let(:user1) { Fabricate(:user) }
@ -12,8 +12,8 @@ describe SpamRulesEnforcer do
before do
SiteSetting.flags_required_to_hide_post = 0
SiteSetting.num_spam_flags_to_block_new_user = 2
SiteSetting.num_users_to_block_new_user = 2
SiteSetting.num_spam_flags_to_silence_new_user = 2
SiteSetting.num_users_to_silence_new_user = 2
end
context 'spammer is a new user' do
@ -37,7 +37,7 @@ describe SpamRulesEnforcer do
expect(spam_post.reload).to_not be_hidden
expect(spam_post2.reload).to_not be_hidden
expect(spammer.reload).to_not be_blocked
expect(spammer.reload).to_not be_silenced
end
end
@ -55,7 +55,7 @@ describe SpamRulesEnforcer do
end
it 'should hide the posts' do
expect(spammer.reload).to be_blocked
expect(spammer.reload).to be_silenced
expect(spam_post.reload).to be_hidden
expect(spam_post2.reload).to be_hidden
expect(spammer.reload.private_topics_count).to eq(private_messages_count + 1)
@ -63,35 +63,35 @@ describe SpamRulesEnforcer do
# The following cases describe when a staff user takes some action, but the user
# still won't be able to make posts.
# A staff user needs to clear the blocked flag from the user record.
# A staff user needs to clear the silenced flag from the user record.
context "a post's flags are cleared" do
it 'should block the spammer' do
it 'should silence the spammer' do
PostAction.clear_flags!(spam_post, admin); spammer.reload
expect(spammer.reload).to be_blocked
expect(spammer.reload).to be_silenced
end
end
context "a post is deleted" do
it 'should block the spammer' do
it 'should silence the spammer' do
spam_post.trash!(moderator); spammer.reload
expect(spammer.reload).to be_blocked
expect(spammer.reload).to be_silenced
end
end
context "spammer becomes trust level 1" do
it 'should block the spammer' do
it 'should silence the spammer' do
spammer.change_trust_level!(TrustLevel[1]); spammer.reload
expect(spammer.reload).to be_blocked
expect(spammer.reload).to be_silenced
end
end
end
context 'flags_required_to_hide_post takes effect too' do
it 'should block the spammer' do
it 'should silence the spammer' do
SiteSetting.flags_required_to_hide_post = 2
PostAction.act(user2, spam_post, PostActionType.types[:spam])
expect(spammer.reload).to be_blocked
expect(spammer.reload).to be_silenced
expect(Guardian.new(spammer).can_create_topic?(nil)).to be false
end
end

View File

@ -23,8 +23,8 @@ describe Jobs::GrantAnniversaryBadges do
expect(badge).to be_blank
end
it "doesn't award to a blocked user" do
user = Fabricate(:user, created_at: 400.days.ago, blocked: true)
it "doesn't award to a silenced user" do
user = Fabricate(:user, created_at: 400.days.ago, silenced: true)
Fabricate(:post, user: user, created_at: 1.week.ago)
granter.execute({})

View File

@ -65,8 +65,8 @@ describe Jobs::NotifyMailingListSubscribers do
include_examples "no emails"
end
context "to a blocked user" do
before { mailing_list_user.update(blocked: true) }
context "to a silenced user" do
before { mailing_list_user.update(silenced: true) }
include_examples "no emails"
end

View File

@ -677,7 +677,7 @@ describe Topic do
context "when moderator post fails to be created" do
before do
user.toggle!(:blocked)
user.toggle!(:silenced)
end
it "should not increment moderator_posts_count" do

View File

@ -1,32 +1,32 @@
require 'rails_helper'
describe SpamRule::AutoBlock do
describe SpamRule::AutoSilence do
before do
SiteSetting.flags_required_to_hide_post = 0 # never
SiteSetting.num_spam_flags_to_block_new_user = 2
SiteSetting.num_users_to_block_new_user = 2
SiteSetting.num_spam_flags_to_silence_new_user = 2
SiteSetting.num_users_to_silence_new_user = 2
end
describe 'perform' do
let(:post) { Fabricate.build(:post, user: Fabricate.build(:user, trust_level: TrustLevel[0])) }
subject { described_class.new(post.user) }
it 'takes no action if user should not be blocked' do
subject.stubs(:block?).returns(false)
subject.expects(:block_user).never
it 'takes no action if user should not be silenced' do
subject.stubs(:silence?).returns(false)
subject.expects(:silence_user).never
subject.perform
end
it 'delivers punishment when user should be blocked' do
subject.stubs(:block?).returns(true)
subject.expects(:block_user)
it 'delivers punishment when user should be silenced' do
subject.stubs(:silence?).returns(true)
subject.expects(:silence_user)
subject.perform
end
end
describe 'num_spam_flags_against_user' do
before { described_class.any_instance.stubs(:block_user) }
before { described_class.any_instance.stubs(:silence_user) }
let(:post) { Fabricate(:post) }
let(:enforcer) { described_class.new(post.user) }
subject { enforcer.num_spam_flags_against_user }
@ -53,7 +53,7 @@ describe SpamRule::AutoBlock do
end
describe 'num_users_who_flagged_spam_against_user' do
before { described_class.any_instance.stubs(:block_user) }
before { described_class.any_instance.stubs(:silence_user) }
let(:post) { Fabricate(:post) }
let(:enforcer) { described_class.new(post.user) }
subject { enforcer.num_users_who_flagged_spam_against_user }
@ -124,85 +124,85 @@ describe SpamRule::AutoBlock do
end
end
describe 'block_user' do
describe 'silence_user' do
let!(:admin) { Fabricate(:admin) } # needed for SystemMessage
let(:user) { Fabricate(:user) }
let!(:post) { Fabricate(:post, user: user) }
subject { described_class.new(user) }
before do
described_class.stubs(:block?).with { |u| u.id != user.id }.returns(false)
described_class.stubs(:block?).with { |u| u.id == user.id }.returns(true)
subject.stubs(:block?).returns(true)
described_class.stubs(:silence?).with { |u| u.id != user.id }.returns(false)
described_class.stubs(:silence?).with { |u| u.id == user.id }.returns(true)
subject.stubs(:silence?).returns(true)
end
context 'user is not blocked' do
context 'user is not silenced' do
before do
UserBlocker.expects(:block).with(user, Discourse.system_user, message: :too_many_spam_flags).returns(true)
UserSilencer.expects(:silence).with(user, Discourse.system_user, message: :too_many_spam_flags).returns(true)
end
it 'prevents the user from making new posts' do
subject.block_user
subject.silence_user
expect(Guardian.new(user).can_create_post?(nil)).to be_falsey
end
it 'sends private message to moderators' do
SiteSetting.notify_mods_when_user_blocked = true
SiteSetting.notify_mods_when_user_silenced = true
moderator = Fabricate(:moderator)
GroupMessage.expects(:create).with do |group, msg_type, params|
group == (Group[:moderators].name) && msg_type == (:user_automatically_blocked) && params[:user].id == (user.id)
group == (Group[:moderators].name) && msg_type == (:user_automatically_silenced) && params[:user].id == (user.id)
end
subject.block_user
subject.silence_user
end
it "doesn't send a pm to moderators if notify_mods_when_user_blocked is false" do
SiteSetting.notify_mods_when_user_blocked = false
it "doesn't send a pm to moderators if notify_mods_when_user_silenced is false" do
SiteSetting.notify_mods_when_user_silenced = false
GroupMessage.expects(:create).never
subject.block_user
subject.silence_user
end
end
context 'user is already blocked' do
context 'user is already silenced' do
before do
UserBlocker.expects(:block).with(user, Discourse.system_user, message: :too_many_spam_flags).returns(false)
UserSilencer.expects(:silence).with(user, Discourse.system_user, message: :too_many_spam_flags).returns(false)
end
it "doesn't send a pm to moderators if the user is already blocked" do
it "doesn't send a pm to moderators if the user is already silenced" do
GroupMessage.expects(:create).never
subject.block_user
subject.silence_user
end
end
end
describe 'block?' do
describe 'silence?' do
context 'never been blocked' do
shared_examples "can't be blocked" do
context 'never been silenced' do
shared_examples "can't be silenced" do
it "returns false" do
enforcer = described_class.new(user)
enforcer.expects(:num_spam_flags_against_user).never
enforcer.expects(:num_users_who_flagged_spam_against_user).never
enforcer.expects(:num_flags_against_user).never
enforcer.expects(:num_users_who_flagged).never
expect(enforcer.block?).to eq(false)
expect(enforcer.silence?).to eq(false)
end
end
(1..4).each do |trust_level|
context "user has trust level #{trust_level}" do
let(:user) { Fabricate(:user, trust_level: trust_level) }
include_examples "can't be blocked"
include_examples "can't be silenced"
end
end
context "user is an admin" do
let(:user) { Fabricate(:admin) }
include_examples "can't be blocked"
include_examples "can't be silenced"
end
context "user is a moderator" do
let(:user) { Fabricate(:moderator) }
include_examples "can't be blocked"
include_examples "can't be silenced"
end
end
@ -213,73 +213,73 @@ describe SpamRule::AutoBlock do
it 'returns false if there are no spam flags' do
subject.stubs(:num_spam_flags_against_user).returns(0)
subject.stubs(:num_users_who_flagged_spam_against_user).returns(0)
expect(subject.block?).to be_falsey
expect(subject.silence?).to be_falsey
end
it 'returns false if there are not received enough flags' do
subject.stubs(:num_spam_flags_against_user).returns(1)
subject.stubs(:num_users_who_flagged_spam_against_user).returns(2)
expect(subject.block?).to be_falsey
expect(subject.silence?).to be_falsey
end
it 'returns false if there have not been enough users' do
subject.stubs(:num_spam_flags_against_user).returns(2)
subject.stubs(:num_users_who_flagged_spam_against_user).returns(1)
expect(subject.block?).to be_falsey
expect(subject.silence?).to be_falsey
end
it 'returns false if num_spam_flags_to_block_new_user is 0' do
SiteSetting.num_spam_flags_to_block_new_user = 0
it 'returns false if num_spam_flags_to_silence_new_user is 0' do
SiteSetting.num_spam_flags_to_silence_new_user = 0
subject.stubs(:num_spam_flags_against_user).returns(100)
subject.stubs(:num_users_who_flagged_spam_against_user).returns(100)
expect(subject.block?).to be_falsey
expect(subject.silence?).to be_falsey
end
it 'returns false if num_users_to_block_new_user is 0' do
SiteSetting.num_users_to_block_new_user = 0
it 'returns false if num_users_to_silence_new_user is 0' do
SiteSetting.num_users_to_silence_new_user = 0
subject.stubs(:num_spam_flags_against_user).returns(100)
subject.stubs(:num_users_who_flagged_spam_against_user).returns(100)
expect(subject.block?).to be_falsey
expect(subject.silence?).to be_falsey
end
it 'returns true when there are enough flags from enough users' do
subject.stubs(:num_spam_flags_against_user).returns(2)
subject.stubs(:num_users_who_flagged_spam_against_user).returns(2)
expect(subject.block?).to be_truthy
expect(subject.silence?).to be_truthy
end
context "all types of flags" do
before do
SiteSetting.num_tl3_flags_to_block_new_user = 3
SiteSetting.num_tl3_users_to_block_new_user = 2
SiteSetting.num_tl3_flags_to_silence_new_user = 3
SiteSetting.num_tl3_users_to_silence_new_user = 2
end
it 'returns false if there are not enough flags' do
subject.stubs(:num_tl3_flags_against_user).returns(1)
subject.stubs(:num_tl3_users_who_flagged).returns(1)
expect(subject.block?).to be_falsey
expect(subject.silence?).to be_falsey
end
it 'returns false if enough flags but not enough users' do
subject.stubs(:num_tl3_flags_against_user).returns(3)
subject.stubs(:num_tl3_users_who_flagged).returns(1)
expect(subject.block?).to be_falsey
expect(subject.silence?).to be_falsey
end
it 'returns true if enough flags and users' do
subject.stubs(:num_tl3_flags_against_user).returns(3)
subject.stubs(:num_tl3_users_who_flagged).returns(2)
expect(subject.block?).to eq(true)
expect(subject.silence?).to eq(true)
end
end
end
context "blocked, but has higher trust level now" do
let(:user) { Fabricate(:user, blocked: true, trust_level: TrustLevel[1]) }
context "silenced, but has higher trust level now" do
let(:user) { Fabricate(:user, silenced: true, trust_level: TrustLevel[1]) }
subject { described_class.new(user) }
it 'returns false' do
expect(subject.block?).to be_truthy
expect(subject.silence?).to be_truthy
end
end
end

View File

@ -11,7 +11,7 @@ describe GroupMessage do
Discourse.stubs(:system_user).returns(admin)
end
subject(:send_group_message) { GroupMessage.create(moderators_group, :user_automatically_blocked, user: user) }
subject(:send_group_message) { GroupMessage.create(moderators_group, :user_automatically_silenced, user: user) }
describe 'not sent recently' do
before { GroupMessage.any_instance.stubs(:sent_recently?).returns(false) }
@ -42,7 +42,7 @@ describe GroupMessage do
describe 'sent recently' do
before { GroupMessage.any_instance.stubs(:sent_recently?).returns(true) }
subject { GroupMessage.create(moderators_group, :user_automatically_blocked, user: user) }
subject { GroupMessage.create(moderators_group, :user_automatically_silenced, user: user) }
it { is_expected.to eq(false) }
@ -61,8 +61,8 @@ describe GroupMessage do
end
end
context 'user_automatically_blocked' do
subject { GroupMessage.new(moderators_group, :user_automatically_blocked, user: user).message_params }
context 'user_automatically_silenced' do
subject { GroupMessage.new(moderators_group, :user_automatically_silenced, user: user).message_params }
include_examples 'common message params for group messages'
end
@ -74,7 +74,7 @@ describe GroupMessage do
describe 'methods that use redis' do
let(:user) { Fabricate.build(:user, id: 123123) }
subject(:group_message) { GroupMessage.new(moderators_group, :user_automatically_blocked, user: user) }
subject(:group_message) { GroupMessage.new(moderators_group, :user_automatically_silenced, user: user) }
before do
PostCreator.stubs(:create).returns(stub_everything)
group_message.stubs(:sent_recently_key).returns('the_key')
@ -92,7 +92,7 @@ describe GroupMessage do
end
it 'always returns false if limit_once_per is false' do
gm = GroupMessage.new(moderators_group, :user_automatically_blocked, user: user, limit_once_per: false)
gm = GroupMessage.new(moderators_group, :user_automatically_silenced, user: user, limit_once_per: false)
gm.stubs(:sent_recently_key).returns('the_key')
$redis.stubs(:get).with(gm.sent_recently_key).returns('1')
expect(gm.sent_recently?).to be_falsey
@ -107,12 +107,12 @@ describe GroupMessage do
it 'can use a given expiry time' do
$redis.expects(:setex).with(anything, 30 * 60, anything).returns('OK')
GroupMessage.new(moderators_group, :user_automatically_blocked, user: user, limit_once_per: 30.minutes).remember_message_sent
GroupMessage.new(moderators_group, :user_automatically_silenced, user: user, limit_once_per: 30.minutes).remember_message_sent
end
it 'can be disabled' do
$redis.expects(:setex).never
GroupMessage.new(moderators_group, :user_automatically_blocked, user: user, limit_once_per: false).remember_message_sent
GroupMessage.new(moderators_group, :user_automatically_silenced, user: user, limit_once_per: false).remember_message_sent
end
end
end

View File

@ -19,8 +19,8 @@ describe SpamRulesEnforcer do
context 'user argument' do
subject(:enforce) { described_class.enforce!(Fabricate.build(:user)) }
it 'performs the AutoBlock' do
SpamRule::AutoBlock.any_instance.expects(:perform).once
it 'performs the AutoSilence' do
SpamRule::AutoSilence.any_instance.expects(:perform).once
enforce
end
end

View File

@ -1,39 +1,39 @@
require 'rails_helper'
describe UserBlocker do
describe UserSilencer do
before do
SystemMessage.stubs(:create)
end
describe 'block' do
describe 'silence' do
let(:user) { stub_everything(save: true) }
let(:blocker) { UserBlocker.new(user) }
subject(:block_user) { blocker.block }
let(:silencer) { UserSilencer.new(user) }
subject(:silence_user) { silencer.silence }
it 'blocks the user' do
it 'silences the user' do
u = Fabricate(:user)
expect { UserBlocker.block(u) }.to change { u.reload.blocked? }
expect { UserSilencer.silence(u) }.to change { u.reload.silenced? }
end
it 'hides posts' do
blocker.expects(:hide_posts)
block_user
silencer.expects(:hide_posts)
silence_user
end
context 'given a staff user argument' do
it 'sends the correct message to the blocked user' do
it 'sends the correct message to the silenced user' do
SystemMessage.unstub(:create)
SystemMessage.expects(:create).with(user, :blocked_by_staff).returns(true)
UserBlocker.block(user, Fabricate.build(:admin))
SystemMessage.expects(:create).with(user, :silenced_by_staff).returns(true)
UserSilencer.silence(user, Fabricate.build(:admin))
end
end
context 'not given a staff user argument' do
it 'sends a default message to the user' do
SystemMessage.unstub(:create)
SystemMessage.expects(:create).with(user, :blocked_by_staff).returns(true)
UserBlocker.block(user, Fabricate.build(:admin))
SystemMessage.expects(:create).with(user, :silenced_by_staff).returns(true)
UserSilencer.silence(user, Fabricate.build(:admin))
end
end
@ -41,7 +41,7 @@ describe UserBlocker do
it 'sends that message to the user' do
SystemMessage.unstub(:create)
SystemMessage.expects(:create).with(user, :the_custom_message).returns(true)
UserBlocker.block(user, Fabricate.build(:admin), message: :the_custom_message)
UserSilencer.silence(user, Fabricate.build(:admin), message: :the_custom_message)
end
end
@ -49,50 +49,50 @@ describe UserBlocker do
user.stubs(:save).returns(false)
SystemMessage.unstub(:create)
SystemMessage.expects(:create).never
block_user
silence_user
end
it "doesn't send a pm if the user is already blocked" do
user.stubs(:blocked?).returns(true)
it "doesn't send a pm if the user is already silenced" do
user.stubs(:silenced?).returns(true)
SystemMessage.unstub(:create)
SystemMessage.expects(:create).never
expect(block_user).to eq(false)
expect(silence_user).to eq(false)
end
it "logs it with context" do
SystemMessage.stubs(:create).returns(Fabricate.build(:post))
expect {
UserBlocker.block(user, Fabricate(:admin))
UserSilencer.silence(user, Fabricate(:admin))
}.to change { UserHistory.count }.by(1)
expect(UserHistory.last.context).to be_present
end
end
describe 'unblock' do
describe 'unsilence' do
let(:user) { stub_everything(save: true) }
subject(:unblock_user) { UserBlocker.unblock(user, Fabricate.build(:admin)) }
subject(:unsilence_user) { UserSilencer.unsilence(user, Fabricate.build(:admin)) }
it 'unblocks the user' do
u = Fabricate(:user, blocked: true)
expect { UserBlocker.unblock(u) }.to change { u.reload.blocked? }
it 'unsilences the user' do
u = Fabricate(:user, silenced: true)
expect { UserSilencer.unsilence(u) }.to change { u.reload.silenced? }
end
it 'sends a message to the user' do
SystemMessage.unstub(:create)
SystemMessage.expects(:create).with(user, :unblocked).returns(true)
unblock_user
SystemMessage.expects(:create).with(user, :unsilenced).returns(true)
unsilence_user
end
it "doesn't send a pm if save fails" do
user.stubs(:save).returns(false)
SystemMessage.unstub(:create)
SystemMessage.expects(:create).never
unblock_user
unsilence_user
end
it "logs it" do
expect {
unblock_user
unsilence_user
}.to change { UserHistory.count }.by(1)
end
end
@ -100,28 +100,28 @@ describe UserBlocker do
describe 'hide_posts' do
let(:user) { Fabricate(:user, trust_level: 0) }
let!(:post) { Fabricate(:post, user: user) }
subject { UserBlocker.new(user) }
subject { UserSilencer.new(user) }
it "hides all the user's posts" do
subject.block
subject.silence
expect(post.reload).to be_hidden
end
it "hides the topic if the post was the first post" do
subject.block
subject.silence
expect(post.topic.reload).to_not be_visible
end
it "doesn't hide posts if user is TL1" do
user.trust_level = 1
subject.block
subject.silence
expect(post.reload).to_not be_hidden
expect(post.topic.reload).to be_visible
end
it "only hides posts from the past 24 hours" do
old_post = Fabricate(:post, user: user, created_at: 2.days.ago)
subject.block
subject.silence
expect(post.reload).to be_hidden
expect(post.topic.reload).to_not be_visible
old_post.reload

View File

@ -10,7 +10,7 @@ QUnit.test("For topics: body of post, title, category and tags are all editbale"
return [
200,
{"Content-Type": "application/json"},
{"users":[{"id":3,"username":"test_user","avatar_template":"/letter_avatar_proxy/v2/letter/t/eada6e/{size}.png","active":true,"admin":false,"moderator":false,"last_seen_at":"2017-08-11T20:48:05.405Z","last_emailed_at":null,"created_at":"2017-08-07T02:23:33.309Z","last_seen_age":"1d","last_emailed_age":null,"created_at_age":"6d","username_lower":"test_user","trust_level":0,"trust_level_locked":false,"flag_level":0,"title":null,"suspended_at":null,"suspended_till":null,"suspended":null,"blocked":false,"time_read":"19m","staged":false,"days_visited":4,"posts_read_count":12,"topics_entered":6,"post_count":2}],"queued_posts":[{"id":22,"queue":"default","user_id":3,"state":1,"topic_id":null,"approved_by_id":null,"rejected_by_id":null,"raw":"some content","post_options":{"archetype":"regular","category":"1","typing_duration_msecs":"3200","composer_open_duration_msecs":"19007","visible":true,"is_warning":false,"title":"a new topic that needs to be reviewed","ip_address":"172.17.0.1","first_post_checks":true,"is_poll":true},"created_at":"2017-08-11T20:43:41.115Z","category_id":1,"can_delete_user":true}],"__rest_serializer":"1","refresh_queued_posts":"/queued_posts?status=new"}
{"users":[{"id":3,"username":"test_user","avatar_template":"/letter_avatar_proxy/v2/letter/t/eada6e/{size}.png","active":true,"admin":false,"moderator":false,"last_seen_at":"2017-08-11T20:48:05.405Z","last_emailed_at":null,"created_at":"2017-08-07T02:23:33.309Z","last_seen_age":"1d","last_emailed_age":null,"created_at_age":"6d","username_lower":"test_user","trust_level":0,"trust_level_locked":false,"flag_level":0,"title":null,"suspended_at":null,"suspended_till":null,"suspended":null,"silenced":false,"time_read":"19m","staged":false,"days_visited":4,"posts_read_count":12,"topics_entered":6,"post_count":2}],"queued_posts":[{"id":22,"queue":"default","user_id":3,"state":1,"topic_id":null,"approved_by_id":null,"rejected_by_id":null,"raw":"some content","post_options":{"archetype":"regular","category":"1","typing_duration_msecs":"3200","composer_open_duration_msecs":"19007","visible":true,"is_warning":false,"title":"a new topic that needs to be reviewed","ip_address":"172.17.0.1","first_post_checks":true,"is_poll":true},"created_at":"2017-08-11T20:43:41.115Z","category_id":1,"can_delete_user":true}],"__rest_serializer":"1","refresh_queued_posts":"/queued_posts?status=new"}
];
});
@ -31,7 +31,7 @@ QUnit.test("For replies: only the body of post is editbale", assert => {
return [
200,
{"Content-Type": "application/json"},
{"users":[{"id":3,"username":"test_user","avatar_template":"/letter_avatar_proxy/v2/letter/t/eada6e/{size}.png","active":true,"admin":false,"moderator":false,"last_seen_at":"2017-08-11T20:48:05.405Z","last_emailed_at":null,"created_at":"2017-08-07T02:23:33.309Z","last_seen_age":"1d","last_emailed_age":null,"created_at_age":"6d","username_lower":"test_user","trust_level":0,"trust_level_locked":false,"flag_level":0,"title":null,"suspended_at":null,"suspended_till":null,"suspended":null,"blocked":false,"time_read":"19m","staged":false,"days_visited":4,"posts_read_count":12,"topics_entered":6,"post_count":2}],"topics":[{"id":11,"title":"This is a topic","fancy_title":"This is a topic","slug":"this-is-a-topic","posts_count":2}],"queued_posts":[{"id":4,"queue":"default","user_id":3,"state":1,"topic_id":11,"approved_by_id":null,"rejected_by_id":null,"raw":"edited haahaasdfasdfasdfasdf","post_options":{"archetype":"regular","category":"3","reply_to_post_number":"2","typing_duration_msecs":"1900","composer_open_duration_msecs":"12096","visible":true,"is_warning":false,"featured_link":"","ip_address":"172.17.0.1","first_post_checks":true,"is_poll":true},"created_at":"2017-08-07T19:11:52.018Z","category_id":3,"can_delete_user":true}],"__rest_serializer":"1","refresh_queued_posts":"/queued_posts?status=new"}
{"users":[{"id":3,"username":"test_user","avatar_template":"/letter_avatar_proxy/v2/letter/t/eada6e/{size}.png","active":true,"admin":false,"moderator":false,"last_seen_at":"2017-08-11T20:48:05.405Z","last_emailed_at":null,"created_at":"2017-08-07T02:23:33.309Z","last_seen_age":"1d","last_emailed_age":null,"created_at_age":"6d","username_lower":"test_user","trust_level":0,"trust_level_locked":false,"flag_level":0,"title":null,"suspended_at":null,"suspended_till":null,"suspended":null,"silenced":false,"time_read":"19m","staged":false,"days_visited":4,"posts_read_count":12,"topics_entered":6,"post_count":2}],"topics":[{"id":11,"title":"This is a topic","fancy_title":"This is a topic","slug":"this-is-a-topic","posts_count":2}],"queued_posts":[{"id":4,"queue":"default","user_id":3,"state":1,"topic_id":11,"approved_by_id":null,"rejected_by_id":null,"raw":"edited haahaasdfasdfasdfasdf","post_options":{"archetype":"regular","category":"3","reply_to_post_number":"2","typing_duration_msecs":"1900","composer_open_duration_msecs":"12096","visible":true,"is_warning":false,"featured_link":"","ip_address":"172.17.0.1","first_post_checks":true,"is_poll":true},"created_at":"2017-08-07T19:11:52.018Z","category_id":3,"can_delete_user":true}],"__rest_serializer":"1","refresh_queued_posts":"/queued_posts?status=new"}
];
});