2012-02-25 16:30:42 +00:00
|
|
|
class User < ActiveRecord::Base
|
|
|
|
|
2014-04-10 20:22:33 +00:00
|
|
|
USERNAME_FORMAT = /\A[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]\z/
|
2014-04-10 20:03:21 +00:00
|
|
|
|
2014-10-12 18:36:31 +00:00
|
|
|
InvalidEmailError = Class.new(StandardError)
|
|
|
|
|
2014-02-09 13:44:09 +00:00
|
|
|
has_many :api_tokens, :dependent => :destroy
|
2012-04-06 12:06:40 +00:00
|
|
|
has_many :asciicasts, :dependent => :destroy
|
|
|
|
has_many :likes, :dependent => :destroy
|
2012-04-06 20:58:44 +00:00
|
|
|
has_many :comments, :dependent => :destroy
|
2014-10-04 17:56:16 +00:00
|
|
|
has_many :expiring_tokens, dependent: :destroy
|
2012-03-04 17:14:58 +00:00
|
|
|
|
2014-10-05 16:26:30 +00:00
|
|
|
validates :email, presence: true, on: :update
|
|
|
|
validates :email, format: { with: /.+@.+\..+/i }, uniqueness: true, if: :email
|
2014-10-05 15:47:42 +00:00
|
|
|
validates :username, uniqueness: { case_sensitive: false },
|
2014-04-10 20:03:21 +00:00
|
|
|
format: { with: USERNAME_FORMAT },
|
2014-04-10 20:22:33 +00:00
|
|
|
length: { minimum: 2, maximum: 16 },
|
2014-10-05 15:47:42 +00:00
|
|
|
if: :username
|
2013-10-22 15:52:04 +00:00
|
|
|
|
2014-10-05 15:47:42 +00:00
|
|
|
scope :with_username, -> { where('username IS NOT NULL') }
|
2014-02-12 18:51:25 +00:00
|
|
|
|
2013-10-22 17:16:18 +00:00
|
|
|
before_create :generate_auth_token
|
|
|
|
|
2014-10-12 18:36:31 +00:00
|
|
|
def self.for_email!(email)
|
|
|
|
raise InvalidEmailError if email.blank?
|
|
|
|
|
|
|
|
self.where(email: email).first_or_create!
|
2013-10-19 18:59:39 +00:00
|
|
|
|
2014-10-12 18:36:31 +00:00
|
|
|
rescue ActiveRecord::RecordInvalid => e
|
|
|
|
if e.record.errors[:email].present?
|
|
|
|
raise InvalidEmailError
|
|
|
|
else
|
|
|
|
raise e
|
2014-09-23 17:05:14 +00:00
|
|
|
end
|
2013-10-20 16:51:35 +00:00
|
|
|
end
|
2013-10-19 18:59:39 +00:00
|
|
|
|
2014-10-05 15:47:42 +00:00
|
|
|
def self.for_username!(username)
|
|
|
|
with_username.where(username: username).first!
|
2014-02-12 18:51:25 +00:00
|
|
|
end
|
|
|
|
|
2014-02-15 20:37:05 +00:00
|
|
|
def self.for_api_token(token)
|
2014-02-11 16:49:22 +00:00
|
|
|
return nil if token.blank?
|
|
|
|
|
2015-04-04 17:59:58 +00:00
|
|
|
joins(:api_tokens).where(
|
|
|
|
'api_tokens.token' => token,
|
|
|
|
'api_tokens.revoked_at' => nil,
|
|
|
|
).first
|
2014-02-11 16:49:22 +00:00
|
|
|
end
|
|
|
|
|
2014-02-20 22:14:36 +00:00
|
|
|
def self.for_auth_token(auth_token)
|
|
|
|
where(auth_token: auth_token).first
|
|
|
|
end
|
|
|
|
|
2013-10-22 17:16:18 +00:00
|
|
|
def self.generate_auth_token
|
|
|
|
SecureRandom.urlsafe_base64
|
|
|
|
end
|
|
|
|
|
2014-10-05 15:47:42 +00:00
|
|
|
def self.null
|
|
|
|
new(temporary_username: 'anonymous')
|
|
|
|
end
|
|
|
|
|
2015-04-02 09:45:39 +00:00
|
|
|
def active_api_tokens
|
|
|
|
api_tokens.active
|
|
|
|
end
|
|
|
|
|
|
|
|
def revoked_api_tokens
|
|
|
|
api_tokens.revoked
|
|
|
|
end
|
|
|
|
|
2014-10-05 15:47:42 +00:00
|
|
|
def confirmed?
|
|
|
|
email.present?
|
|
|
|
end
|
|
|
|
|
2014-02-12 19:51:01 +00:00
|
|
|
def username=(value)
|
2013-10-22 15:56:14 +00:00
|
|
|
value ? super(value.strip) : super
|
|
|
|
end
|
|
|
|
|
|
|
|
def email=(value)
|
|
|
|
value ? super(value.strip) : super
|
|
|
|
end
|
|
|
|
|
2014-06-30 21:26:25 +00:00
|
|
|
def theme
|
|
|
|
theme_name.presence && Theme.for_name(theme_name)
|
|
|
|
end
|
|
|
|
|
2014-02-12 16:41:06 +00:00
|
|
|
def assign_api_token(token)
|
|
|
|
api_token = ApiToken.for_token(token)
|
|
|
|
|
|
|
|
if api_token
|
|
|
|
api_token.reassign_to(self)
|
|
|
|
else
|
|
|
|
api_token = api_tokens.create!(token: token)
|
|
|
|
end
|
|
|
|
|
|
|
|
api_token
|
|
|
|
end
|
|
|
|
|
|
|
|
def merge_to(target_user)
|
|
|
|
self.class.transaction do |tx|
|
|
|
|
asciicasts.update_all(user_id: target_user.id, updated_at: DateTime.now)
|
|
|
|
api_tokens.update_all(user_id: target_user.id, updated_at: DateTime.now)
|
|
|
|
destroy
|
|
|
|
end
|
2012-03-04 19:29:19 +00:00
|
|
|
end
|
2013-08-19 15:08:13 +00:00
|
|
|
|
2013-11-18 18:06:56 +00:00
|
|
|
def asciicast_count
|
|
|
|
asciicasts.count
|
|
|
|
end
|
|
|
|
|
2014-01-18 10:44:13 +00:00
|
|
|
def asciicasts_excluding(asciicast, limit)
|
|
|
|
asciicasts.where('id <> ?', asciicast.id).order('RANDOM()').limit(limit)
|
|
|
|
end
|
|
|
|
|
2014-02-01 00:16:28 +00:00
|
|
|
def paged_asciicasts(page, per_page)
|
|
|
|
asciicasts.
|
|
|
|
includes(:user).
|
|
|
|
order("created_at DESC").
|
|
|
|
paginate(page, per_page)
|
|
|
|
end
|
|
|
|
|
2014-07-05 12:59:42 +00:00
|
|
|
def admin?
|
|
|
|
CFG.admin_ids.include?(id)
|
|
|
|
end
|
|
|
|
|
2014-10-12 18:36:31 +00:00
|
|
|
def first_login?
|
|
|
|
expiring_tokens.count == 1
|
|
|
|
end
|
|
|
|
|
2013-10-22 17:16:18 +00:00
|
|
|
private
|
|
|
|
|
|
|
|
def generate_auth_token
|
|
|
|
begin
|
|
|
|
self[:auth_token] = self.class.generate_auth_token
|
|
|
|
end while User.exists?(auth_token: self[:auth_token])
|
|
|
|
end
|
|
|
|
|
2012-02-25 16:30:42 +00:00
|
|
|
end
|