Refine Banish User (#1168)

* add banish user test

* refactor banish user wip

* banish user wip - bust comment cache synchronously

* add more spec scenarios

* Update Banish#strip_user_profile

* Refactor specs
This commit is contained in:
Jess Lee 2018-11-21 16:55:26 -05:00 committed by Ben Halpern
parent b34ee48c1f
commit e36cf51a9e
7 changed files with 186 additions and 15 deletions

View file

@ -92,7 +92,7 @@ class Internal::UsersController < Internal::ApplicationController
def banish
@user = User.find(params[:id])
strip_user(@user)
Moderator::Banisher.call(admin: current_user, offender: @user)
redirect_to "/internal/users/#{@user.id}/edit"
end
@ -151,10 +151,10 @@ class Internal::UsersController < Internal::ApplicationController
def user_params
params.require(:user).permit(:seeking_mentorship,
:offering_mentorship,
:add_mentor,
:add_mentee,
:mentorship_note,
:ban_from_mentorship)
:offering_mentorship,
:add_mentor,
:add_mentee,
:mentorship_note,
:ban_from_mentorship)
end
end

View file

@ -13,10 +13,10 @@ class Article < ApplicationRecord
counter_culture :user
belongs_to :organization, optional: true
belongs_to :collection, optional: true
has_many :reactions, as: :reactable, dependent: :destroy
has_many :comments, as: :commentable
has_many :buffer_updates
has_many :reactions, as: :reactable, dependent: :destroy
has_many :notifications, as: :notifiable
has_many :notifications, as: :notifiable
validates :slug, presence: { if: :published? }, format: /\A[0-9a-z-]*\z/,
uniqueness: { scope: :user_id }
@ -392,8 +392,7 @@ class Article < ApplicationRecord
def before_destroy_actions
bust_cache
remove_algolia_index
reactions.destroy_all
user.delay.resave_articles
user.cache_bust_all_articles
organization&.delay&.resave_articles
end

View file

@ -281,18 +281,18 @@ class Comment < ApplicationRecord
handle_asynchronously :create_first_reaction
def before_destroy_actions
bust_cache
bust_cache_without_delay
remove_algolia_index
reactions.destroy_all
end
def bust_cache
Comment.delay.comment_async_bust(commentable, user.username)
Comment.comment_async_bust(commentable, user.username)
expire_root_fragment
cache_buster = CacheBuster.new
cache_buster.bust(commentable.path.to_s) if commentable
cache_buster.bust("#{commentable.path}/comments") if commentable
end
handle_asynchronously :bust_cache
def send_email_notification
NotifyMailer.new_reply_email(self).deliver

View file

@ -15,9 +15,9 @@ class Reaction < ApplicationRecord
before_save :assign_points
after_save :update_reactable
before_destroy :update_reactable_without_delay
after_save :touch_user
after_save :async_bust
before_destroy :update_reactable_without_delay
before_destroy :clean_up_before_destroy
scope :for_article, ->(id) { where(reactable_id: id, reactable_type: "Article") }

View file

@ -356,6 +356,14 @@ class User < ApplicationRecord
end
end
def cache_bust_all_articles
cache_buster = CacheBuster.new
articles.each do |article|
cache_buster.bust(article.path)
cache_buster.bust(article.path + "?i=i")
end
end
def settings_tab_list
tab_list = %w(
Profile
@ -428,7 +436,7 @@ class User < ApplicationRecord
end
def conditionally_resave_articles
if core_profile_details_changed?
if core_profile_details_changed? && !user.banned
delay.resave_articles
end
end

View file

@ -0,0 +1,94 @@
module Moderator
class Banisher
attr_reader :user, :admin
def self.call(admin:, offender:)
new(offender: offender, admin: admin).banish
end
def initialize(admin:, offender:)
@user = offender
@admin = admin
end
def banish
# return unless user.comments.where("created_at < ?", 7.days.ago).empty?
ban_offender
strip_user_profile
destroy_dependents
user.remove_from_index!
end
def destroy_dependents
destroy_reactions
destroy_comments
destroy_articles
destroy_follows
end
def ban_offender
user.add_role :banned
unless user.notes.where(reason: "banned").any?
user.notes.
create!(reason: "banned", content: "spam account", author_id: admin.id)
end
end
def destroy_follows
user.follows.destroy_all
end
handle_asynchronously :destroy_follows
def destroy_reactions
user.reactions.destroy_all
end
def destroy_comments
user.comments.destroy_all
end
handle_asynchronously :destroy_comments
def destroy_articles
user.articles.destroy_all
end
handle_asynchronously :destroy_articles
def bust_user_cache(old_username)
CacheBuster.new.bust("/#{old_username}")
end
def strip_user_profile
bust_user_cache(user.username)
new_name = "spam_#{rand(10000)}"
new_username = "spam_#{rand(10000)}"
if User.find_by(name: new_name) || User.find_by(username: new_username)
new_name = "spam_#{rand(10000)}"
new_username = "spam_#{rand(10000)}"
end
user.name = new_name
user.username = new_username
user.twitter_username = ""
user.github_username = ""
user.website_url = ""
user.summary = ""
user.location = ""
user.education = ""
user.employer_name = ""
user.employer_url = ""
user.employment_title = ""
user.mostly_work_with = ""
user.currently_learning = ""
user.currently_hacking_on = ""
user.available_for = ""
user.email_public = false
user.facebook_url = nil
user.dribbble_url = nil
user.medium_url = nil
user.stackoverflow_url = nil
user.behance_url = nil
user.linkedin_url = nil
user.save
user.update_columns(old_username: nil)
end
end
end

View file

@ -0,0 +1,70 @@
require "rails_helper"
RSpec.describe "internal/users", type: :request do
context "when banishing user" do
let(:user) { create(:user) }
let(:article) { create(:article, user: user) }
let(:super_admin) { create(:user, :super_admin) }
let(:article2) { create(:article, user: super_admin) }
before do
sign_in super_admin
Delayed::Worker.delay_jobs = true
Delayed::Worker.destroy_failed_jobs = false
end
after do
Delayed::Worker.delay_jobs = false
end
def banish_user
post "/internal/users/#{user.id}/banish"
Delayed::Worker.new(quiet: false).work_off
user.reload
end
def create_dependents
# Article 1
create(:reaction, reactable: article, reactable_type: "Article", user: user)
parent_comment = create(:comment, commentable_type: "Article", commentable: article, user: user)
create(:comment, commentable_type: "Article", commentable: article, user: user, parent: parent_comment)
# Article 2 written by super_admin
create(:reaction, reactable: article2, reactable_type: "Article", user: user)
parent_comment2 = create(:comment, commentable_type: "Article", commentable: article2, user: user)
create(:comment, commentable_type: "Article", commentable: article2, user: super_admin, parent: parent_comment2)
user.follow(super_admin)
Delayed::Worker.new(quiet: true).work_off
end
context "when offender is a spam user" do
before do
create(:reaction, reactable: article, reactable_type: "Article", user: user)
create(:comment, commentable_type: "Article", commentable: article, user: user)
Delayed::Worker.new(quiet: true).work_off
end
it "works" do
banish_user
expect(Delayed::Job.where("failed_at IS NOT NULL").count).to eq(0)
expect(user.old_username).to eq(nil)
expect(user.twitter_username).to eq("")
end
end
xcontext "when offender has rich activity " do
it "works" do
create_dependents
banish_user
# failed = Delayed::Job.where("failed_at IS NOT NULL").first
# failed = YAML.load(failed.handler) if failed
# binding.pry
expect(Delayed::Job.where("failed_at IS NOT NULL").count).to eq(0)
expect(user.old_username).to eq(nil)
expect(user.twitter_username).to eq("")
end
end
end
end