users: delete accounts with invalid names.
Add a fix script to delete all accounts with invalid usernames. Also change it so the owner-level user can delete accounts belonging to other users. Users who have logged in in the last year and who have a valid email address will be given a one week warning. After that all accounts with invalid names will be deleted. Anyone who has visited the site in the last 6 months will have already seen a warning page that their name must be changed to keep using the site.
This commit is contained in:
@@ -9,7 +9,7 @@ module Maintenance
|
|||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
deletion = UserDeletion.new(CurrentUser.user, params.dig(:user, :password), request)
|
deletion = UserDeletion.new(user: CurrentUser.user, deleter: CurrentUser.user, password: params.dig(:user, :password), request: request)
|
||||||
deletion.delete!
|
deletion.delete!
|
||||||
|
|
||||||
if deletion.errors.none?
|
if deletion.errors.none?
|
||||||
|
|||||||
@@ -7,16 +7,18 @@
|
|||||||
class UserDeletion
|
class UserDeletion
|
||||||
include ActiveModel::Validations
|
include ActiveModel::Validations
|
||||||
|
|
||||||
attr_reader :user, :password, :request
|
attr_reader :user, :deleter, :password, :request
|
||||||
|
|
||||||
validate :validate_deletion
|
validate :validate_deletion
|
||||||
|
|
||||||
# Initialize a user deletion.
|
# Initialize a user deletion.
|
||||||
# @param user [User] the user to delete
|
# @param user [User] the user to delete
|
||||||
|
# @param user [User] the user performing the deletion
|
||||||
# @param password [String] the user's password (for confirmation)
|
# @param password [String] the user's password (for confirmation)
|
||||||
# @param request the HTTP request (for logging the deletion in the user event log)
|
# @param request the HTTP request (for logging the deletion in the user event log)
|
||||||
def initialize(user, password, request)
|
def initialize(user:, deleter: user, password: nil, request: nil)
|
||||||
@user = user
|
@user = user
|
||||||
|
@deleter = deleter
|
||||||
@password = password
|
@password = password
|
||||||
@request = request
|
@request = request
|
||||||
end
|
end
|
||||||
@@ -40,11 +42,11 @@ class UserDeletion
|
|||||||
private
|
private
|
||||||
|
|
||||||
def create_mod_action
|
def create_mod_action
|
||||||
ModAction.log("deleted user ##{user.id}", :user_delete, user)
|
ModAction.log("deleted user ##{user.id}", :user_delete, deleter)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_user_event
|
def create_user_event
|
||||||
UserEvent.create_from_request!(user, :user_deletion, request)
|
UserEvent.create_from_request!(user, :user_deletion, request) if request.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def clear_saved_searches
|
def clear_saved_searches
|
||||||
@@ -79,16 +81,30 @@ class UserDeletion
|
|||||||
end
|
end
|
||||||
|
|
||||||
def validate_deletion
|
def validate_deletion
|
||||||
if !user.authenticate_password(password)
|
if user == deleter
|
||||||
errors.add(:base, "Password is incorrect")
|
if !user.authenticate_password(password)
|
||||||
end
|
errors.add(:base, "Password is incorrect")
|
||||||
|
end
|
||||||
|
|
||||||
if user.is_admin?
|
if user.is_admin?
|
||||||
errors.add(:base, "Admins cannot delete their account")
|
errors.add(:base, "Admins cannot delete their account")
|
||||||
end
|
end
|
||||||
|
|
||||||
if user.is_banned?
|
if user.is_banned?
|
||||||
errors.add(:base, "You cannot delete your account if you are banned")
|
errors.add(:base, "You cannot delete your account if you are banned")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if !deleter.is_owner?
|
||||||
|
errors.add(:base, "You cannot delete an account belonging to another user")
|
||||||
|
end
|
||||||
|
|
||||||
|
if user.is_gold?
|
||||||
|
errors.add(:base, "You cannot delete a privileged account")
|
||||||
|
end
|
||||||
|
|
||||||
|
if user.created_at.before?(6.months.ago)
|
||||||
|
errors.add(:base, "You cannot delete a recent account")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
57
script/fixes/115_delete_invalid_users.rb
Executable file
57
script/fixes/115_delete_invalid_users.rb
Executable file
@@ -0,0 +1,57 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
require_relative "base"
|
||||||
|
|
||||||
|
def delete(user)
|
||||||
|
return if !user.name_invalid?
|
||||||
|
|
||||||
|
if ENV.fetch("WARN", "false").truthy? && user.can_receive_email?
|
||||||
|
Dmail.create_automated(to: user, title: "Action required: Change your username or your Danbooru account will be deleted", body: <<~EOS)
|
||||||
|
Your current Danbooru username is invalid. Your Danbooru account will be deleted in one week unless you change your username. Use the link below to change your username:
|
||||||
|
|
||||||
|
* "Change username":/user_name_change_requests/new
|
||||||
|
EOS
|
||||||
|
|
||||||
|
puts "[WARN] id=#{user.id} user='#{user.name}' email='#{user.email_address.address}'"
|
||||||
|
elsif ENV.fetch("DELETE", "false").truthy?
|
||||||
|
UserDeletion.new(user: user, deleter: User.owner).delete!
|
||||||
|
puts "[DELETE] id=#{user.id} user='#{user.name}'"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
with_confirmation do
|
||||||
|
condition = ENV.fetch("COND", "TRUE")
|
||||||
|
users = User.where(Arel.sql(condition))
|
||||||
|
|
||||||
|
users.where("length(name) = 1").find_each do |user|
|
||||||
|
delete(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
users.where("length(name) >= 25").find_each do |user|
|
||||||
|
delete(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
users.where_regex(:name, "[[:space:]]").find_each do |user|
|
||||||
|
delete(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
users.where_regex(:name, "^[[:punct:]]").find_each do |user|
|
||||||
|
delete(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
users.where_regex(:name, "[[:punct:]]$").find_each do |user|
|
||||||
|
delete(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
users.where_regex(:name, "\.(html|json|xml|atom|rss|txt|js|css|csv|png|jpg|jpeg|gif|png|mp4|webm|zip|pdf|exe|sitemap)$").find_each do |user|
|
||||||
|
delete(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
users.where_regex(:name, "[`~!@#$%^&*()+={}\[\]|\\:;'\"<>,?/]").find_each do |user|
|
||||||
|
delete(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
users.where_not_regex(:name, "[[:ascii:]]").find_each do |user|
|
||||||
|
delete(user)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -12,7 +12,7 @@ class UserDeletionTest < ActiveSupport::TestCase
|
|||||||
context "for an invalid password" do
|
context "for an invalid password" do
|
||||||
should "fail" do
|
should "fail" do
|
||||||
@user = create(:user)
|
@user = create(:user)
|
||||||
@deletion = UserDeletion.new(@user, "wrongpassword", @request)
|
@deletion = UserDeletion.new(user: @user, password: "wrongpassword", request: @request)
|
||||||
@deletion.delete!
|
@deletion.delete!
|
||||||
assert_includes(@deletion.errors[:base], "Password is incorrect")
|
assert_includes(@deletion.errors[:base], "Password is incorrect")
|
||||||
end
|
end
|
||||||
@@ -21,7 +21,7 @@ class UserDeletionTest < ActiveSupport::TestCase
|
|||||||
context "for an admin" do
|
context "for an admin" do
|
||||||
should "fail" do
|
should "fail" do
|
||||||
@user = create(:admin_user)
|
@user = create(:admin_user)
|
||||||
@deletion = UserDeletion.new(@user, "password", @request)
|
@deletion = UserDeletion.new(user: @user, password: "password", request: @request)
|
||||||
@deletion.delete!
|
@deletion.delete!
|
||||||
assert_includes(@deletion.errors[:base], "Admins cannot delete their account")
|
assert_includes(@deletion.errors[:base], "Admins cannot delete their account")
|
||||||
end
|
end
|
||||||
@@ -30,7 +30,7 @@ class UserDeletionTest < ActiveSupport::TestCase
|
|||||||
context "for a banned user" do
|
context "for a banned user" do
|
||||||
should "fail" do
|
should "fail" do
|
||||||
@user = create(:banned_user)
|
@user = create(:banned_user)
|
||||||
@deletion = UserDeletion.new(@user, "password", @request)
|
@deletion = UserDeletion.new(user: @user, password: "password", request: @request)
|
||||||
@deletion.delete!
|
@deletion.delete!
|
||||||
assert_includes(@deletion.errors[:base], "You cannot delete your account if you are banned")
|
assert_includes(@deletion.errors[:base], "You cannot delete your account if you are banned")
|
||||||
end
|
end
|
||||||
@@ -40,7 +40,7 @@ class UserDeletionTest < ActiveSupport::TestCase
|
|||||||
context "a valid user deletion" do
|
context "a valid user deletion" do
|
||||||
setup do
|
setup do
|
||||||
@user = create(:user, name: "foo", email_address: build(:email_address))
|
@user = create(:user, name: "foo", email_address: build(:email_address))
|
||||||
@deletion = UserDeletion.new(@user, "password", @request)
|
@deletion = UserDeletion.new(user: @user, password: "password", request: @request)
|
||||||
end
|
end
|
||||||
|
|
||||||
should "blank out the email" do
|
should "blank out the email" do
|
||||||
@@ -82,4 +82,24 @@ class UserDeletionTest < ActiveSupport::TestCase
|
|||||||
assert_equal(0, @post.reload.fav_count)
|
assert_equal(0, @post.reload.fav_count)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "deleting another user's account" do
|
||||||
|
should "work for the owner-level user" do
|
||||||
|
@user = create(:user)
|
||||||
|
@deletion = UserDeletion.new(user: @user, deleter: create(:owner_user))
|
||||||
|
|
||||||
|
@deletion.delete!
|
||||||
|
assert_equal("user_#{@user.id}", @user.reload.name)
|
||||||
|
assert_equal(true, ModAction.exists?(description: "deleted user ##{@user.id}", creator: @deletion.deleter))
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not work for other users" do
|
||||||
|
@user = create(:user)
|
||||||
|
@deletion = UserDeletion.new(user: @user, deleter: create(:admin_user))
|
||||||
|
|
||||||
|
@deletion.delete!
|
||||||
|
assert_not_equal("user_#{@user.id}", @user.reload.name)
|
||||||
|
assert_equal(0, ModAction.count)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user