Merge remote-tracking branch 'upstream/pull/3419'
This commit is contained in:
commit
446837c351
14 changed files with 164 additions and 45 deletions
|
@ -25,7 +25,7 @@ class ConfirmationsController < ApplicationController
|
||||||
render_unknown_user token.user.display_name
|
render_unknown_user token.user.display_name
|
||||||
else
|
else
|
||||||
user = token.user
|
user = token.user
|
||||||
user.status = "active"
|
user.activate
|
||||||
user.email_valid = true
|
user.email_valid = true
|
||||||
flash[:notice] = gravatar_status_message(user) if gravatar_enable(user)
|
flash[:notice] = gravatar_status_message(user) if gravatar_enable(user)
|
||||||
user.save!
|
user.save!
|
||||||
|
|
|
@ -46,7 +46,7 @@ class PasswordsController < ApplicationController
|
||||||
if params[:user]
|
if params[:user]
|
||||||
current_user.pass_crypt = params[:user][:pass_crypt]
|
current_user.pass_crypt = params[:user][:pass_crypt]
|
||||||
current_user.pass_crypt_confirmation = params[:user][:pass_crypt_confirmation]
|
current_user.pass_crypt_confirmation = params[:user][:pass_crypt_confirmation]
|
||||||
current_user.status = "active" if current_user.status == "pending"
|
current_user.activate if current_user.may_activate?
|
||||||
current_user.email_valid = true
|
current_user.email_valid = true
|
||||||
|
|
||||||
if current_user.save
|
if current_user.save
|
||||||
|
|
|
@ -164,8 +164,6 @@ class UsersController < ApplicationController
|
||||||
|
|
||||||
Rails.logger.info "create: #{session[:referer]}"
|
Rails.logger.info "create: #{session[:referer]}"
|
||||||
|
|
||||||
current_user.status = "pending"
|
|
||||||
|
|
||||||
if current_user.auth_provider.present? && current_user.pass_crypt.empty?
|
if current_user.auth_provider.present? && current_user.pass_crypt.empty?
|
||||||
# We are creating an account with external authentication and
|
# We are creating an account with external authentication and
|
||||||
# no password was specified so create a random one
|
# no password was specified so create a random one
|
||||||
|
@ -202,15 +200,19 @@ class UsersController < ApplicationController
|
||||||
##
|
##
|
||||||
# sets a user's status
|
# sets a user's status
|
||||||
def set_status
|
def set_status
|
||||||
@user.status = params[:status]
|
@user.activate! if params[:event] == "activate"
|
||||||
@user.save
|
@user.confirm! if params[:event] == "confirm"
|
||||||
|
@user.unconfirm! if params[:event] == "unconfirm"
|
||||||
|
@user.hide! if params[:event] == "hide"
|
||||||
|
@user.unhide! if params[:event] == "unhide"
|
||||||
|
@user.unsuspend! if params[:event] == "unsuspend"
|
||||||
redirect_to user_path(:display_name => params[:display_name])
|
redirect_to user_path(:display_name => params[:display_name])
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# destroy a user, marking them as deleted and removing personal data
|
# destroy a user, marking them as deleted and removing personal data
|
||||||
def destroy
|
def destroy
|
||||||
@user.destroy
|
@user.soft_destroy!
|
||||||
redirect_to user_path(:display_name => params[:display_name])
|
redirect_to user_path(:display_name => params[:display_name])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
|
|
||||||
class User < ApplicationRecord
|
class User < ApplicationRecord
|
||||||
require "digest"
|
require "digest"
|
||||||
|
include AASM
|
||||||
|
|
||||||
has_many :traces, -> { where(:visible => true) }
|
has_many :traces, -> { where(:visible => true) }
|
||||||
has_many :diary_entries, -> { order(:created_at => :desc) }
|
has_many :diary_entries, -> { order(:created_at => :desc) }
|
||||||
|
@ -158,6 +159,64 @@ class User < ApplicationRecord
|
||||||
user
|
user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
aasm :column => :status, :no_direct_assignment => true do
|
||||||
|
state :pending, :initial => true
|
||||||
|
state :active
|
||||||
|
state :confirmed
|
||||||
|
state :suspended
|
||||||
|
state :deleted
|
||||||
|
|
||||||
|
# A normal account is active
|
||||||
|
event :activate do
|
||||||
|
transitions :from => :pending, :to => :active
|
||||||
|
end
|
||||||
|
|
||||||
|
# Used in test suite, not something that we would normally need to do.
|
||||||
|
if Rails.env.test?
|
||||||
|
event :deactivate do
|
||||||
|
transitions :from => :active, :to => :pending
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# To confirm an account is used to override the spam scoring
|
||||||
|
event :confirm do
|
||||||
|
transitions :from => [:pending, :active, :suspended], :to => :confirmed
|
||||||
|
end
|
||||||
|
|
||||||
|
# To unconfirm an account is to make it subject to future spam scoring again
|
||||||
|
event :unconfirm do
|
||||||
|
transitions :from => :confirmed, :to => :active
|
||||||
|
end
|
||||||
|
|
||||||
|
# Accounts can be automatically suspended by spam_check
|
||||||
|
event :suspend do
|
||||||
|
transitions :from => [:pending, :active], :to => :suspended
|
||||||
|
end
|
||||||
|
|
||||||
|
# Unsuspending an account moves it back to active without overriding the spam scoring
|
||||||
|
event :unsuspend do
|
||||||
|
transitions :from => :suspended, :to => :active
|
||||||
|
end
|
||||||
|
|
||||||
|
# Mark the account as deleted but keep all data intact
|
||||||
|
event :hide do
|
||||||
|
transitions :from => [:pending, :active, :confirmed, :suspended], :to => :deleted
|
||||||
|
end
|
||||||
|
|
||||||
|
event :unhide do
|
||||||
|
transitions :from => [:deleted], :to => :active
|
||||||
|
end
|
||||||
|
|
||||||
|
# Mark the account as deleted and remove personal data
|
||||||
|
event :soft_destroy do
|
||||||
|
before do
|
||||||
|
remove_personal_data
|
||||||
|
end
|
||||||
|
|
||||||
|
transitions :from => [:pending, :active, :confirmed, :suspended], :to => :deleted
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def description
|
def description
|
||||||
RichText.new(self[:description_format], self[:description])
|
RichText.new(self[:description_format], self[:description])
|
||||||
end
|
end
|
||||||
|
@ -241,8 +300,8 @@ class User < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# destroy a user - leave the account but purge most personal data
|
# remove personal data - leave the account but purge most personal data
|
||||||
def destroy
|
def remove_personal_data
|
||||||
avatar.purge_later
|
avatar.purge_later
|
||||||
|
|
||||||
self.display_name = "user_#{id}"
|
self.display_name = "user_#{id}"
|
||||||
|
@ -253,7 +312,6 @@ class User < ApplicationRecord
|
||||||
self.new_email = nil
|
self.new_email = nil
|
||||||
self.auth_provider = nil
|
self.auth_provider = nil
|
||||||
self.auth_uid = nil
|
self.auth_uid = nil
|
||||||
self.status = "deleted"
|
|
||||||
|
|
||||||
save
|
save
|
||||||
end
|
end
|
||||||
|
@ -279,7 +337,7 @@ class User < ApplicationRecord
|
||||||
##
|
##
|
||||||
# perform a spam check on a user
|
# perform a spam check on a user
|
||||||
def spam_check
|
def spam_check
|
||||||
update(:status => "suspended") if status == "active" && spam_score > Settings.spam_threshold
|
suspend! if may_suspend? && spam_score > Settings.spam_threshold
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
|
@ -139,30 +139,44 @@
|
||||||
<nav class='secondary-actions'>
|
<nav class='secondary-actions'>
|
||||||
<ul class='clearfix'>
|
<ul class='clearfix'>
|
||||||
<% if can? :set_status, User %>
|
<% if can? :set_status, User %>
|
||||||
<% if ["active", "confirmed"].include? @user.status %>
|
<% if @user.may_activate? %>
|
||||||
<li>
|
<li>
|
||||||
<%= link_to t(".deactivate_user"), set_status_user_path(:status => "pending", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
|
<%= link_to t(".activate_user"), set_status_user_path(:event => "activate", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
|
||||||
</li>
|
|
||||||
<% elsif ["pending"].include? @user.status %>
|
|
||||||
<li>
|
|
||||||
<%= link_to t(".activate_user"), set_status_user_path(:status => "active", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
|
|
||||||
</li>
|
</li>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% if ["active", "suspended"].include? @user.status %>
|
<% if @user.may_unsuspend? %>
|
||||||
<li>
|
<li>
|
||||||
<%= link_to t(".confirm_user"), set_status_user_path(:status => "confirmed", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
|
<%= link_to t(".unsuspend_user"), set_status_user_path(:event => "unsuspend", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
|
||||||
|
</li>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if @user.may_confirm? %>
|
||||||
|
<li>
|
||||||
|
<%= link_to t(".confirm_user"), set_status_user_path(:event => "confirm", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
|
||||||
|
</li>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if @user.may_unconfirm? %>
|
||||||
|
<li>
|
||||||
|
<%= link_to t(".unconfirm_user"), set_status_user_path(:event => "unconfirm", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
|
||||||
|
</li>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if @user.may_hide? %>
|
||||||
|
<li>
|
||||||
|
<%= link_to t(".hide_user"), set_status_user_path(:event => "hide", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
|
||||||
|
</li>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if @user.may_unhide? %>
|
||||||
|
<li>
|
||||||
|
<%= link_to t(".unhide_user"), set_status_user_path(:event => "unhide", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
|
||||||
</li>
|
</li>
|
||||||
<% end %>
|
<% end %>
|
||||||
<li>
|
|
||||||
<% if ["pending", "active", "confirmed", "suspended"].include? @user.status %>
|
|
||||||
<%= link_to t(".hide_user"), set_status_user_path(:status => "deleted", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
|
|
||||||
<% else %>
|
|
||||||
<%= link_to t(".unhide_user"), set_status_user_path(:status => "active", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
|
|
||||||
<% end %>
|
|
||||||
</li>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if can? :destroy, User %>
|
|
||||||
|
<% if can?(:destroy, User) && @user.may_soft_destroy? %>
|
||||||
<li>
|
<li>
|
||||||
<%= link_to t(".delete_user"), user_path(:display_name => @user.display_name), :method => :delete, :data => { :confirm => t(".confirm") } %>
|
<%= link_to t(".delete_user"), user_path(:display_name => @user.display_name), :method => :delete, :data => { :confirm => t(".confirm") } %>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -2591,6 +2591,8 @@ en:
|
||||||
activate_user: "Activate this User"
|
activate_user: "Activate this User"
|
||||||
deactivate_user: "Deactivate this User"
|
deactivate_user: "Deactivate this User"
|
||||||
confirm_user: "Confirm this User"
|
confirm_user: "Confirm this User"
|
||||||
|
unconfirm_user: "Unconfirm this User"
|
||||||
|
unsuspend_user: "Unsuspend this User"
|
||||||
hide_user: "Hide this User"
|
hide_user: "Hide this User"
|
||||||
unhide_user: "Unhide this User"
|
unhide_user: "Unhide this User"
|
||||||
delete_user: "Delete this User"
|
delete_user: "Delete this User"
|
||||||
|
|
|
@ -137,7 +137,7 @@ class BrowseControllerTest < ActionDispatch::IntegrationTest
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_read_note_hidden_user_comment
|
def test_read_note_hidden_user_comment
|
||||||
hidden_user = create(:user, :status => "deleted")
|
hidden_user = create(:user, :deleted)
|
||||||
note_with_hidden_user_comment = create(:note_with_comments, :comments_count => 2) do |note|
|
note_with_hidden_user_comment = create(:note_with_comments, :comments_count => 2) do |note|
|
||||||
create(:note_comment, :note => note, :author => hidden_user)
|
create(:note_comment, :note => note, :author => hidden_user)
|
||||||
end
|
end
|
||||||
|
@ -161,7 +161,7 @@ class BrowseControllerTest < ActionDispatch::IntegrationTest
|
||||||
assert_select "div.note-comments ul li", :count => 2
|
assert_select "div.note-comments ul li", :count => 2
|
||||||
assert_select "div.details", /Resolved by #{user.display_name}/
|
assert_select "div.details", /Resolved by #{user.display_name}/
|
||||||
|
|
||||||
user.destroy
|
user.soft_destroy!
|
||||||
|
|
||||||
reset!
|
reset!
|
||||||
|
|
||||||
|
|
|
@ -185,7 +185,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
|
||||||
post user_save_path, :params => { :read_ct => 1, :read_tou => 1 }
|
post user_save_path, :params => { :read_ct => 1, :read_tou => 1 }
|
||||||
confirm_string = User.find_by(:email => user.email).tokens.create.token
|
confirm_string = User.find_by(:email => user.email).tokens.create.token
|
||||||
|
|
||||||
User.find_by(:display_name => user.display_name).update(:status => "deleted")
|
User.find_by(:display_name => user.display_name).hide!
|
||||||
|
|
||||||
# Get the confirmation page
|
# Get the confirmation page
|
||||||
get user_confirm_path, :params => { :display_name => user.display_name, :confirm_string => confirm_string }
|
get user_confirm_path, :params => { :display_name => user.display_name, :confirm_string => confirm_string }
|
||||||
|
@ -242,7 +242,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
|
||||||
post user_new_path, :params => { :user => user.attributes }
|
post user_new_path, :params => { :user => user.attributes }
|
||||||
post user_save_path, :params => { :read_ct => 1, :read_tou => 1 }
|
post user_save_path, :params => { :read_ct => 1, :read_tou => 1 }
|
||||||
|
|
||||||
User.find_by(:display_name => user.display_name).update(:status => "deleted")
|
User.find_by(:display_name => user.display_name).hide!
|
||||||
|
|
||||||
assert_no_difference "ActionMailer::Base.deliveries.size" do
|
assert_no_difference "ActionMailer::Base.deliveries.size" do
|
||||||
perform_enqueued_jobs do
|
perform_enqueued_jobs do
|
||||||
|
|
|
@ -547,21 +547,21 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
|
||||||
user = create(:user)
|
user = create(:user)
|
||||||
|
|
||||||
# Try without logging in
|
# Try without logging in
|
||||||
post set_status_user_path(user), :params => { :status => "suspended" }
|
post set_status_user_path(user), :params => { :event => "confirm" }
|
||||||
assert_response :forbidden
|
assert_response :forbidden
|
||||||
|
|
||||||
# Now try as a normal user
|
# Now try as a normal user
|
||||||
session_for(user)
|
session_for(user)
|
||||||
post set_status_user_path(user), :params => { :status => "suspended" }
|
post set_status_user_path(user), :params => { :event => "confirm" }
|
||||||
assert_response :redirect
|
assert_response :redirect
|
||||||
assert_redirected_to :controller => :errors, :action => :forbidden
|
assert_redirected_to :controller => :errors, :action => :forbidden
|
||||||
|
|
||||||
# Finally try as an administrator
|
# Finally try as an administrator
|
||||||
session_for(create(:administrator_user))
|
session_for(create(:administrator_user))
|
||||||
post set_status_user_path(user), :params => { :status => "suspended" }
|
post set_status_user_path(user), :params => { :event => "confirm" }
|
||||||
assert_response :redirect
|
assert_response :redirect
|
||||||
assert_redirected_to :action => :show, :display_name => user.display_name
|
assert_redirected_to :action => :show, :display_name => user.display_name
|
||||||
assert_equal "suspended", User.find(user.id).status
|
assert_equal "confirmed", User.find(user.id).status
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_destroy
|
def test_destroy
|
||||||
|
|
|
@ -6,7 +6,10 @@ FactoryBot.define do
|
||||||
|
|
||||||
# These attributes are not the defaults, but in most tests we want
|
# These attributes are not the defaults, but in most tests we want
|
||||||
# a 'normal' user who can log in without being redirected etc.
|
# a 'normal' user who can log in without being redirected etc.
|
||||||
status { "active" }
|
after(:build) do |user, _evaluator|
|
||||||
|
user.activate
|
||||||
|
end
|
||||||
|
|
||||||
terms_seen { true }
|
terms_seen { true }
|
||||||
terms_agreed { Time.now.getutc }
|
terms_agreed { Time.now.getutc }
|
||||||
data_public { true }
|
data_public { true }
|
||||||
|
@ -17,23 +20,31 @@ FactoryBot.define do
|
||||||
end
|
end
|
||||||
|
|
||||||
trait :pending do
|
trait :pending do
|
||||||
status { "pending" }
|
after(:build) do |user, _evaluator|
|
||||||
|
user.deactivate
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
trait :active do
|
trait :active do
|
||||||
status { "active" }
|
# status { "active" }
|
||||||
end
|
end
|
||||||
|
|
||||||
trait :confirmed do
|
trait :confirmed do
|
||||||
status { "confirmed" }
|
after(:build) do |user, _evaluator|
|
||||||
|
user.confirm
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
trait :suspended do
|
trait :suspended do
|
||||||
status { "suspended" }
|
after(:build) do |user, _evaluator|
|
||||||
|
user.suspend
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
trait :deleted do
|
trait :deleted do
|
||||||
status { "deleted" }
|
after(:build) do |user, _evaluator|
|
||||||
|
user.soft_destroy
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
factory :moderator_user do
|
factory :moderator_user do
|
||||||
|
|
|
@ -246,9 +246,9 @@ class UserTest < ActiveSupport::TestCase
|
||||||
assert create(:moderator_user).has_role?("moderator")
|
assert create(:moderator_user).has_role?("moderator")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_destroy
|
def test_soft_destroy
|
||||||
user = create(:user, :with_home_location, :description => "foo")
|
user = create(:user, :with_home_location, :description => "foo")
|
||||||
user.destroy
|
user.soft_destroy
|
||||||
assert_equal "user_#{user.id}", user.display_name
|
assert_equal "user_#{user.id}", user.display_name
|
||||||
assert user.description.blank?
|
assert user.description.blank?
|
||||||
assert_nil user.home_lat
|
assert_nil user.home_lat
|
||||||
|
|
|
@ -35,7 +35,7 @@ class DiaryEntrySystemTest < ApplicationSystemTestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
test "deleted diary entries should not be shown to admins when the user is also deleted" do
|
test "deleted diary entries should not be shown to admins when the user is also deleted" do
|
||||||
@deleted_user = create(:user, :status => :deleted)
|
@deleted_user = create(:user, :deleted)
|
||||||
@deleted_entry = create(:diary_entry, :visible => false, :user => @deleted_user)
|
@deleted_entry = create(:diary_entry, :visible => false, :user => @deleted_user)
|
||||||
|
|
||||||
sign_in_as(create(:administrator_user))
|
sign_in_as(create(:administrator_user))
|
||||||
|
|
32
test/system/user_status_change_test.rb
Normal file
32
test/system/user_status_change_test.rb
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
require "application_system_test_case"
|
||||||
|
|
||||||
|
class UserStatusChangeTest < ApplicationSystemTestCase
|
||||||
|
def setup
|
||||||
|
admin = create(:administrator_user)
|
||||||
|
sign_in_as(admin)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Admin can unsuspend a user" do
|
||||||
|
user = create(:user, :suspended)
|
||||||
|
visit user_path(user)
|
||||||
|
accept_confirm do
|
||||||
|
click_on "Unsuspend"
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_no_content "Unsuspend"
|
||||||
|
user.reload
|
||||||
|
assert_equal "active", user.status
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Admin can confirm a user" do
|
||||||
|
user = create(:user, :suspended)
|
||||||
|
visit user_path(user)
|
||||||
|
accept_confirm do
|
||||||
|
click_on "Confirm"
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_no_content "Unsuspend"
|
||||||
|
user.reload
|
||||||
|
assert_equal "confirmed", user.status
|
||||||
|
end
|
||||||
|
end
|
|
@ -7,7 +7,7 @@ class UserSuspensionTest < ApplicationSystemTestCase
|
||||||
visit edit_account_path
|
visit edit_account_path
|
||||||
assert_content "My Settings"
|
assert_content "My Settings"
|
||||||
|
|
||||||
user.update(:status => "suspended")
|
user.suspend!
|
||||||
|
|
||||||
visit edit_account_path
|
visit edit_account_path
|
||||||
assert_content "This decision will be reviewed by an administrator shortly"
|
assert_content "This decision will be reviewed by an administrator shortly"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue