class User < ApplicationRecord
require "digest"
- require "xml/libxml"
+ include AASM
has_many :traces, -> { where(:visible => true) }
has_many :diary_entries, -> { order(:created_at => :desc) }
scope :active, -> { where(:status => %w[active confirmed]) }
scope :identifiable, -> { where(:data_public => true) }
- has_one_attached :avatar
+ has_one_attached :avatar, :service => Settings.avatar_storage
validates :display_name, :presence => true, :length => 3..255,
:exclusion => %w[new terms save confirm confirm-email go_public reset-password forgot-password suspended]
validates_email_format_of :email, :if => proc { |u| u.email_changed? }
validates_email_format_of :new_email, :allow_blank => true, :if => proc { |u| u.new_email_changed? }
- after_initialize :set_defaults
+ alias_attribute :created_at, :creation_time
+
before_save :encrypt_password
before_save :update_tile
after_save :spam_check
- after_save :reset_preferred_languages
def to_param
display_name
user
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
RichText.new(self[:description_format], self[:description])
end
@preferred_languages ||= Locale.list(languages)
end
- def reset_preferred_languages
- @preferred_languages = nil
- end
-
def nearby(radius = Settings.nearby_radius, num = Settings.nearby_users)
if home_lon && home_lat
gc = OSM::GreatCircle.new(home_lat, home_lon)
end
##
- # delete a user - leave the account but purge most personal data
- def delete
+ # remove personal data - leave the account but purge most personal data
+ def remove_personal_data
avatar.purge_later
self.display_name = "user_#{id}"
self.new_email = nil
self.auth_provider = nil
self.auth_uid = nil
- self.status = "deleted"
save
end
##
# perform a spam check on a user
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
def max_messages_per_hour
- account_age_in_seconds = Time.now.utc - creation_time
+ account_age_in_seconds = Time.now.utc - created_at
account_age_in_hours = account_age_in_seconds / 3600
recent_messages = messages.where("sent_on >= ?", Time.now.utc - 3600).count
active_reports = issues.with_status(:open).sum(:reports_count)
end
def max_friends_per_hour
- account_age_in_seconds = Time.now.utc - creation_time
+ account_age_in_seconds = Time.now.utc - created_at
account_age_in_hours = account_age_in_seconds / 3600
recent_friends = Friendship.where(:befriendee => self).where("created_at >= ?", Time.now.utc - 3600).count
active_reports = issues.with_status(:open).sum(:reports_count)
private
- def set_defaults
- self.creation_time = Time.now.getutc unless attribute_present?(:creation_time)
- end
-
def encrypt_password
if pass_crypt_confirmation
self.pass_crypt, self.pass_salt = PasswordHash.create(pass_crypt)