2013-04-18 14:27:04 -04:00
require_dependency 'email'
2013-02-05 14:16:51 -05:00
require_dependency 'email_token'
require_dependency 'trust_level'
2013-03-06 23:12:16 +11:00
require_dependency 'pbkdf2'
2013-03-08 15:04:37 -05:00
require_dependency 'summarize'
2013-05-10 16:58:23 -04:00
require_dependency 'discourse'
2013-06-05 16:00:45 -04:00
require_dependency 'post_destroyer'
2013-06-06 16:40:10 +02:00
require_dependency 'user_name_suggester'
2013-06-07 00:07:59 +02:00
require_dependency 'roleable'
2013-06-23 14:32:46 +10:00
require_dependency 'pretty_text'
2013-02-05 14:16:51 -05:00
class User < ActiveRecord :: Base
2013-06-07 00:07:59 +02:00
include Roleable
2013-02-05 14:16:51 -05:00
has_many :posts
2013-09-03 17:19:29 -04:00
has_many :notifications , dependent : :destroy
has_many :topic_users , dependent : :destroy
2013-02-05 14:16:51 -05:00
has_many :topics
2013-04-11 16:04:20 -04:00
has_many :user_open_ids , dependent : :destroy
2013-09-03 17:19:29 -04:00
has_many :user_actions , dependent : :destroy
has_many :post_actions , dependent : :destroy
has_many :email_logs , dependent : :destroy
2013-02-05 14:16:51 -05:00
has_many :post_timings
2013-09-03 17:19:29 -04:00
has_many :topic_allowed_users , dependent : :destroy
2013-02-05 14:16:51 -05:00
has_many :topics_allowed , through : :topic_allowed_users , source : :topic
2013-09-03 17:19:29 -04:00
has_many :email_tokens , dependent : :destroy
2013-02-05 14:16:51 -05:00
has_many :views
2013-09-03 17:19:29 -04:00
has_many :user_visits , dependent : :destroy
has_many :invites , dependent : :destroy
has_many :topic_links , dependent : :destroy
has_many :uploads , dependent : :destroy
2013-05-10 16:58:23 -04:00
2013-06-24 17:03:51 +03:00
has_one :facebook_user_info , dependent : :destroy
2013-04-11 16:04:20 -04:00
has_one :twitter_user_info , dependent : :destroy
has_one :github_user_info , dependent : :destroy
2013-05-23 13:40:50 -07:00
has_one :cas_user_info , dependent : :destroy
2013-08-17 21:43:59 -07:00
has_one :oauth2_user_info , dependent : :destroy
2013-09-11 14:50:26 -04:00
has_one :user_stat , dependent : :destroy
2013-02-05 14:16:51 -05:00
belongs_to :approved_by , class_name : 'User'
2013-09-03 17:19:29 -04:00
has_many :group_users , dependent : :destroy
2013-04-29 16:33:24 +10:00
has_many :groups , through : :group_users
has_many :secure_categories , through : :groups , source : :categories
2013-09-03 17:19:29 -04:00
has_one :user_search_data , dependent : :destroy
2013-10-22 15:53:08 -04:00
has_one :api_key , dependent : :destroy
2013-05-22 15:33:33 -04:00
2013-08-13 22:08:29 +02:00
belongs_to :uploaded_avatar , class_name : 'Upload' , dependent : :destroy
2013-11-15 20:57:43 +05:30
delegate :last_sent_email_address , :to = > :email_logs
2013-02-05 14:16:51 -05:00
validates_presence_of :username
validate :username_validator
2013-07-25 13:01:27 -04:00
validates :email , presence : true , uniqueness : true
validates :email , email : true , if : :email_changed?
2013-02-05 14:16:51 -05:00
validate :password_validator
2013-10-21 14:49:51 -04:00
validates :ip_address , allowed_ip_address : { on : :create , message : :signup_not_allowed }
2013-02-05 14:16:51 -05:00
before_save :cook
before_save :update_username_lower
before_save :ensure_password_is_hashed
after_initialize :add_trust_level
2013-08-23 17:35:01 -04:00
after_initialize :set_default_email_digest
2013-02-05 14:16:51 -05:00
after_save :update_tracked_topics
2013-02-05 19:44:49 -07:00
after_create :create_email_token
2013-09-11 14:50:26 -04:00
after_create :create_user_stat
2013-02-05 14:16:51 -05:00
2013-09-03 17:19:29 -04:00
before_destroy do
# These tables don't have primary keys, so destroying them with activerecord is tricky:
PostTiming . delete_all ( user_id : self . id )
View . delete_all ( user_id : self . id )
end
2013-02-05 14:16:51 -05:00
# Whether we need to be sending a system message after creation
attr_accessor :send_welcome_message
# This is just used to pass some information into the serializer
attr_accessor :notification_channel_position
2013-06-06 16:40:10 +02:00
scope :blocked , - > { where ( blocked : true ) } # no index
2013-11-07 13:53:32 -05:00
scope :suspended , - > { where ( 'suspended_till IS NOT NULL AND suspended_till > ?' , Time . zone . now ) } # no index
scope :not_suspended , - > { where ( 'suspended_till IS NULL' ) }
2013-09-06 14:07:23 +10:00
# excluding fake users like the community user
scope :real , - > { where ( 'id > 0' ) }
2013-03-29 09:29:58 +03:00
2013-02-14 17:32:58 +11:00
module NewTopicDuration
2013-02-25 19:42:20 +03:00
ALWAYS = - 1
2013-02-14 17:32:58 +11:00
LAST_VISIT = - 2
end
2013-02-05 14:16:51 -05:00
def self . username_length
2013-02-05 19:44:49 -07:00
3 .. 15
2013-02-05 14:16:51 -05:00
end
2013-06-06 16:40:10 +02:00
def self . username_available? ( username )
lower = username . downcase
User . where ( username_lower : lower ) . blank?
2013-02-05 14:16:51 -05:00
end
2013-03-31 18:51:13 +02:00
EMAIL = %r{ ([^@]+)@([^ \ .]+) }
2013-04-13 00:46:55 +02:00
def self . new_from_params ( params )
user = User . new
user . name = params [ :name ]
user . email = params [ :email ]
user . password = params [ :password ]
user . username = params [ :username ]
user
end
2013-02-05 14:16:51 -05:00
def self . suggest_name ( email )
return " " unless email
name = email . split ( / [@ \ +] / ) [ 0 ]
2013-02-28 16:08:56 +03:00
name = name . gsub ( " . " , " " )
name . titleize
2013-02-05 14:16:51 -05:00
end
2013-04-29 16:33:24 +10:00
# Find a user by temporary key, nil if not found or key is invalid
def self . find_by_temporary_key ( key )
user_id = $redis . get ( " temporary_key: #{ key } " )
if user_id . present?
where ( id : user_id . to_i ) . first
end
end
def self . find_by_username_or_email ( username_or_email )
2013-10-28 16:29:07 +11:00
if username_or_email . include? ( '@' )
find_by_email ( username_or_email )
2013-06-19 10:31:19 +10:00
else
2013-10-28 16:29:07 +11:00
find_by_username ( username_or_email )
2013-06-19 10:31:19 +10:00
end
2013-04-29 16:33:24 +10:00
end
2013-10-24 13:29:58 +05:30
def self . find_by_email ( email )
2013-10-28 16:29:07 +11:00
where ( email : Email . downcase ( email ) ) . first
2013-10-24 13:29:58 +05:30
end
def self . find_by_username ( username )
2013-10-28 16:29:07 +11:00
where ( username_lower : username . downcase ) . first
2013-10-24 13:29:58 +05:30
end
2013-04-29 16:33:24 +10:00
def enqueue_welcome_message ( message_type )
return unless SiteSetting . send_welcome_message?
Jobs . enqueue ( :send_system_message , user_id : id , message_type : message_type )
end
2013-02-05 14:16:51 -05:00
def change_username ( new_username )
2013-06-28 16:21:46 -04:00
current_username = self . username
self . username = new_username
2013-02-05 14:16:51 -05:00
2013-07-07 12:40:35 +02:00
if current_username . downcase != new_username . downcase && valid?
2013-08-28 17:18:31 +10:00
DiscourseHub . nickname_operation { DiscourseHub . change_nickname ( current_username , new_username ) }
2013-02-05 14:16:51 -05:00
end
2013-02-28 16:08:56 +03:00
save
2013-02-05 14:16:51 -05:00
end
# Use a temporary key to find this user, store it in redis with an expiry
2013-02-05 19:44:49 -07:00
def temporary_key
2013-02-05 14:16:51 -05:00
key = SecureRandom . hex ( 32 )
$redis . setex " temporary_key: #{ key } " , 1 . week , id . to_s
key
end
2013-09-12 17:46:43 -04:00
def created_topic_count
topics . count
end
2013-02-26 19:27:59 +03:00
2013-02-05 14:16:51 -05:00
# tricky, we need our bus to be subscribed from the right spot
def sync_notification_channel_position
@unread_notifications_by_type = nil
2013-02-25 09:31:38 +11:00
self . notification_channel_position = MessageBus . last_id ( " /notification/ #{ id } " )
2013-02-05 14:16:51 -05:00
end
def invited_by
used_invite = invites . where ( " redeemed_at is not null " ) . includes ( :invited_by ) . first
2013-02-28 16:08:56 +03:00
used_invite . try ( :invited_by )
2013-02-05 14:16:51 -05:00
end
# Approve this user
2013-06-26 13:24:30 -04:00
def approve ( approved_by , send_mail = true )
2013-02-05 14:16:51 -05:00
self . approved = true
2013-07-11 11:21:39 +10:00
if Fixnum === approved_by
self . approved_by_id = approved_by
else
self . approved_by = approved_by
end
2013-02-05 14:16:51 -05:00
self . approved_at = Time . now
2013-06-05 20:16:31 -07:00
2013-06-26 13:24:30 -04:00
send_approval_email if save and send_mail
2013-02-05 14:16:51 -05:00
end
def self . email_hash ( email )
2013-02-05 19:44:49 -07:00
Digest :: MD5 . hexdigest ( email . strip . downcase )
2013-02-05 14:16:51 -05:00
end
def email_hash
2013-02-28 16:08:56 +03:00
User . email_hash ( email )
2013-02-05 14:16:51 -05:00
end
def unread_notifications_by_type
@unread_notifications_by_type || = notifications . where ( " id > ? and read = false " , seen_notification_id ) . group ( :notification_type ) . count
end
def reload
@unread_notifications_by_type = nil
2013-05-16 16:37:47 +10:00
@unread_pms = nil
2013-02-05 14:16:51 -05:00
super
end
def unread_private_messages
2013-05-16 16:37:47 +10:00
@unread_pms || = notifications . where ( " read = false AND notification_type = ? " , Notification . types [ :private_message ] ) . count
2013-02-05 14:16:51 -05:00
end
def unread_notifications
2013-03-01 15:07:44 +03:00
unread_notifications_by_type . except ( Notification . types [ :private_message ] ) . values . sum
2013-02-05 14:16:51 -05:00
end
2013-02-05 19:44:49 -07:00
2013-02-05 14:16:51 -05:00
def saw_notification_id ( notification_id )
2013-08-09 12:12:56 -04:00
User . where ( [ " id = ? and seen_notification_id < ? " , id , notification_id ] )
. update_all [ " seen_notification_id = ? " , notification_id ]
2013-02-05 14:16:51 -05:00
end
def publish_notifications_state
2013-02-28 16:08:56 +03:00
MessageBus . publish ( " /notification/ #{ id } " ,
2013-06-06 16:40:10 +02:00
{ unread_notifications : unread_notifications ,
unread_private_messages : unread_private_messages } ,
user_ids : [ id ] # only publish the notification to this user
)
2013-02-05 14:16:51 -05:00
end
# A selection of people to autocomplete on @mention
def self . mentionable_usernames
2013-02-05 19:44:49 -07:00
User . select ( :username ) . order ( 'last_posted_at desc' ) . limit ( 20 )
end
2013-02-05 14:16:51 -05:00
def password = ( password )
2013-02-05 19:44:49 -07:00
# special case for passwordless accounts
2013-02-28 16:08:56 +03:00
@raw_password = password unless password . blank?
2013-02-05 14:16:51 -05:00
end
2013-02-12 15:42:04 -05:00
# Indicate that this is NOT a passwordless account for the purposes of validation
2013-02-28 16:08:56 +03:00
def password_required!
2013-02-12 15:42:04 -05:00
@password_required = true
end
2013-02-05 14:16:51 -05:00
def confirm_password? ( password )
2013-02-28 16:08:56 +03:00
return false unless password_hash && salt
self . password_hash == hash_password ( password , salt )
2013-02-05 14:16:51 -05:00
end
2013-10-11 13:33:23 -04:00
def new_user?
created_at > = 24 . hours . ago || trust_level == TrustLevel . levels [ :newuser ]
end
2013-02-05 14:16:51 -05:00
2013-02-12 13:41:04 +08:00
def seen_before?
last_seen_at . present?
end
def has_visit_record? ( date )
2013-02-28 21:54:12 +03:00
user_visits . where ( visited_at : date ) . first
2013-02-12 13:41:04 +08:00
end
def update_visit_record! ( date )
2013-05-18 16:02:06 +10:00
unless has_visit_record? ( date )
2013-10-04 13:28:49 +10:00
user_stat . update_column ( :days_visited , user_stat . days_visited + 1 )
2013-04-05 17:53:39 +11:00
user_visits . create! ( visited_at : date )
2013-02-12 13:41:04 +08:00
end
end
2013-02-24 21:42:04 +11:00
def update_ip_address! ( new_ip_address )
2013-03-08 17:24:10 -08:00
unless ip_address == new_ip_address || new_ip_address . blank?
2013-02-24 22:56:08 +11:00
update_column ( :ip_address , new_ip_address )
2013-02-24 21:42:04 +11:00
end
end
2013-10-23 23:24:50 +02:00
def update_last_seen! ( now = Time . zone . now )
now_date = now . to_date
2013-02-05 14:16:51 -05:00
# Only update last seen once every minute
2013-10-23 23:24:50 +02:00
redis_key = " user: #{ id } : #{ now_date } "
return unless $redis . setnx ( redis_key , " 1 " )
2013-02-05 14:16:51 -05:00
2013-10-23 23:24:50 +02:00
$redis . expire ( redis_key , SiteSetting . active_user_rate_limit_secs )
update_previous_visit ( now )
# using update_column to avoid the AR transaction
update_column ( :last_seen_at , now )
2013-02-05 14:16:51 -05:00
end
2013-08-13 22:08:29 +02:00
def self . gravatar_template ( email )
2013-02-05 14:16:51 -05:00
email_hash = self . email_hash ( email )
2013-08-13 22:08:29 +02:00
" //www.gravatar.com/avatar/ #{ email_hash } .png?s={size}&r=pg&d=identicon "
2013-02-05 14:16:51 -05:00
end
2013-03-08 15:58:37 -05:00
# Don't pass this up to the client - it's meant for server side use
2013-08-13 22:08:29 +02:00
# This is used in
# - self oneboxes in open graph data
# - emails
2013-03-08 15:58:37 -05:00
def small_avatar_url
2013-08-16 00:26:22 +02:00
template = avatar_template
2013-08-16 09:58:20 +02:00
template . gsub ( " {size} " , " 45 " )
2013-03-08 15:58:37 -05:00
end
2013-09-10 15:18:22 -04:00
# the avatars might take a while to generate
# so return the url of the original image in the meantime
def uploaded_avatar_path
return unless SiteSetting . allow_uploaded_avatars? && use_uploaded_avatar
uploaded_avatar_template . present? ? uploaded_avatar_template : uploaded_avatar . try ( :url )
end
2013-02-05 14:16:51 -05:00
def avatar_template
2013-09-10 15:18:22 -04:00
uploaded_avatar_path || User . gravatar_template ( email )
2013-02-05 14:16:51 -05:00
end
# The following count methods are somewhat slow - definitely don't use them in a loop.
2013-03-06 08:52:24 +01:00
# They might need to be denormalized
2013-02-05 14:16:51 -05:00
def like_count
2013-02-28 16:08:56 +03:00
UserAction . where ( user_id : id , action_type : UserAction :: WAS_LIKED ) . count
2013-02-05 14:16:51 -05:00
end
def post_count
posts . count
end
def flags_given_count
2013-03-01 15:07:44 +03:00
PostAction . where ( user_id : id , post_action_type_id : PostActionType . flag_types . values ) . count
2013-02-05 14:16:51 -05:00
end
def flags_received_count
2013-03-01 15:07:44 +03:00
posts . includes ( :post_actions ) . where ( 'post_actions.post_action_type_id' = > PostActionType . flag_types . values ) . count
2013-02-05 14:16:51 -05:00
end
def private_topics_count
topics_allowed . where ( archetype : Archetype . private_message ) . count
end
def bio_excerpt
2013-06-04 12:05:36 -04:00
excerpt = PrettyText . excerpt ( bio_cooked , 350 )
return excerpt if excerpt . blank? || has_trust_level? ( :basic )
2013-06-05 15:28:10 -04:00
PrettyText . strip_links ( excerpt )
end
2013-06-04 12:05:36 -04:00
2013-06-05 15:28:10 -04:00
def bio_processed
return bio_cooked if bio_cooked . blank? || has_trust_level? ( :basic )
PrettyText . strip_links ( bio_cooked )
2013-02-05 14:16:51 -05:00
end
2013-02-07 18:11:56 +11:00
def delete_all_posts! ( guardian )
raise Discourse :: InvalidAccess unless guardian . can_delete_all_posts? self
2013-02-07 16:45:24 +01:00
2013-02-07 18:11:56 +11:00
posts . order ( " post_number desc " ) . each do | p |
2013-06-05 16:00:45 -04:00
PostDestroyer . new ( guardian . user , p ) . destroy
2013-02-07 18:11:56 +11:00
end
end
2013-11-07 13:53:32 -05:00
def suspended?
suspended_till && suspended_till > DateTime . now
2013-02-05 14:16:51 -05:00
end
2013-11-07 13:53:32 -05:00
def suspend_record
UserHistory . for ( self , :suspend_user ) . order ( 'id DESC' ) . first
2013-11-01 10:47:03 -04:00
end
2013-11-07 13:53:32 -05:00
def suspend_reason
suspend_record . try ( :details ) if suspended?
2013-11-01 10:47:03 -04:00
end
2013-02-05 14:16:51 -05:00
# Use this helper to determine if the user has a particular trust level.
# Takes into account admin, etc.
2013-02-05 19:44:49 -07:00
def has_trust_level? ( level )
2013-02-28 16:08:56 +03:00
raise " Invalid trust level #{ level } " unless TrustLevel . valid_level? ( level )
2013-03-19 21:05:19 -07:00
admin? || moderator? || TrustLevel . compare ( trust_level , level )
2013-02-05 14:16:51 -05:00
end
2013-03-19 16:51:39 -07:00
# a touch faster than automatic
2013-03-31 18:51:13 +02:00
def admin?
2013-03-19 16:51:39 -07:00
admin
end
2013-05-06 14:49:56 +10:00
def change_trust_level! ( level )
2013-02-28 16:08:56 +03:00
raise " Invalid trust level #{ level } " unless TrustLevel . valid_level? ( level )
2013-03-01 15:07:44 +03:00
self . trust_level = TrustLevel . levels [ level ]
2013-05-06 14:49:56 +10:00
transaction do
self . save!
Group . user_trust_level_change! ( self . id , self . trust_level )
end
2013-02-12 22:58:08 +00:00
end
2013-02-05 14:16:51 -05:00
def guardian
Guardian . new ( self )
end
2013-02-07 18:23:41 -05:00
def username_format_validator
2013-07-07 13:05:18 +02:00
UsernameValidator . perform_validation ( self , 'username' )
2013-02-07 18:23:41 -05:00
end
2013-02-11 11:18:26 -05:00
def email_confirmed?
2013-02-28 16:08:56 +03:00
email_tokens . where ( email : email , confirmed : true ) . present? || email_tokens . empty?
2013-02-11 11:18:26 -05:00
end
2013-05-07 21:58:34 -04:00
def activate
email_token = self . email_tokens . active . first
if email_token
EmailToken . confirm ( email_token . token )
else
self . active = true
save
end
end
def deactivate
self . active = false
save
end
2013-02-14 17:32:58 +11:00
def treat_as_new_topic_start_date
2013-02-25 19:42:20 +03:00
duration = new_topic_duration_minutes || SiteSetting . new_topic_duration_minutes
case duration
2013-06-06 16:40:10 +02:00
when User :: NewTopicDuration :: ALWAYS
created_at
when User :: NewTopicDuration :: LAST_VISIT
previous_visit_at || created_at
else
duration . minutes . ago
2013-02-25 19:42:20 +03:00
end
2013-02-14 17:32:58 +11:00
end
2013-02-07 18:23:41 -05:00
2013-02-21 10:20:00 -08:00
def readable_name
2013-03-06 15:17:07 -05:00
return " #{ name } ( #{ username } ) " if name . present? && name != username
username
2013-02-21 10:20:00 -08:00
end
2013-03-08 15:04:37 -05:00
def bio_summary
return nil unless bio_cooked . present?
Summarize . new ( bio_cooked ) . summary
end
2013-04-03 13:25:52 -04:00
def self . count_by_signup_date ( sinceDaysAgo = 30 )
where ( 'created_at > ?' , sinceDaysAgo . days . ago ) . group ( 'date(created_at)' ) . order ( 'date(created_at)' ) . count
2013-03-07 11:07:59 -05:00
end
2013-04-05 16:48:38 +11:00
2013-04-29 16:33:24 +10:00
def secure_category_ids
2013-09-10 14:29:02 +10:00
cats = self . staff? ? Category . where ( read_restricted : true ) : secure_categories . references ( :categories )
cats . pluck ( 'categories.id' ) . sort
2013-04-29 16:33:24 +10:00
end
2013-07-14 11:24:16 +10:00
def topic_create_allowed_category_ids
Category . topic_create_allowed ( self . id ) . select ( :id )
end
2013-09-12 17:46:43 -04:00
2013-05-10 16:58:23 -04:00
# Flag all posts from a user as spam
def flag_linked_posts_as_spam
admin = Discourse . system_user
topic_links . includes ( :post ) . each do | tl |
begin
2013-10-17 15:08:11 -04:00
PostAction . act ( admin , tl . post , PostActionType . types [ :spam ] , message : I18n . t ( 'flag_reason.spam_hosts' ) )
2013-05-10 16:58:23 -04:00
rescue PostAction :: AlreadyActed
# If the user has already acted, just ignore it
end
end
end
2013-05-13 18:04:03 +10:00
2013-08-13 22:08:29 +02:00
def has_uploaded_avatar
uploaded_avatar . present?
end
2013-05-24 20:58:26 +10:00
2013-10-16 14:58:18 +05:30
def added_a_day_ago?
created_at > 1 . day . ago
end
2013-10-07 11:19:45 +01:00
def upload_avatar ( avatar )
2013-10-19 15:18:11 +05:30
self . uploaded_avatar_template = nil
2013-10-07 11:19:45 +01:00
self . uploaded_avatar = avatar
2013-10-19 15:18:11 +05:30
self . use_uploaded_avatar = true
self . save!
end
2013-10-22 15:53:08 -04:00
def generate_api_key ( created_by )
if api_key . present?
api_key . regenerate! ( created_by )
api_key
else
ApiKey . create ( user : self , key : SecureRandom . hex ( 32 ) , created_by : created_by )
end
end
def revoke_api_key
ApiKey . where ( user_id : self . id ) . delete_all
end
2013-11-15 20:57:43 +05:30
def find_email
last_sent_email_address || email
end
2013-02-05 14:16:51 -05:00
protected
2013-06-06 16:40:10 +02:00
def cook
if bio_raw . present?
self . bio_cooked = PrettyText . cook ( bio_raw ) if bio_raw_changed?
else
self . bio_cooked = nil
2013-02-05 14:16:51 -05:00
end
2013-06-06 16:40:10 +02:00
end
2013-02-05 14:16:51 -05:00
2013-06-06 16:40:10 +02:00
def update_tracked_topics
return unless auto_track_topics_after_msecs_changed?
2013-10-23 23:24:50 +02:00
TrackedTopicsUpdater . new ( id , auto_track_topics_after_msecs ) . call
2013-06-06 16:40:10 +02:00
end
2013-02-05 14:16:51 -05:00
2013-09-11 14:50:26 -04:00
def create_user_stat
stat = UserStat . new
2013-10-04 13:28:49 +10:00
stat . user_id = id
2013-09-11 14:50:26 -04:00
stat . save!
end
2013-06-06 16:40:10 +02:00
def create_email_token
email_tokens . create ( email : email )
end
2013-02-05 14:16:51 -05:00
2013-06-06 16:40:10 +02:00
def ensure_password_is_hashed
if @raw_password
self . salt = SecureRandom . hex ( 16 )
self . password_hash = hash_password ( @raw_password , salt )
2013-02-05 14:16:51 -05:00
end
2013-06-06 16:40:10 +02:00
end
2013-02-05 14:16:51 -05:00
2013-06-06 16:40:10 +02:00
def hash_password ( password , salt )
2013-07-22 21:36:01 -04:00
Pbkdf2 . hash_password ( password , salt , Rails . configuration . pbkdf2_iterations , Rails . configuration . pbkdf2_algorithm )
2013-06-06 16:40:10 +02:00
end
2013-02-05 14:16:51 -05:00
2013-06-06 16:40:10 +02:00
def add_trust_level
# there is a possiblity we did not load trust level column, skip it
return unless has_attribute? :trust_level
self . trust_level || = SiteSetting . default_trust_level
end
2013-02-05 14:16:51 -05:00
2013-06-06 16:40:10 +02:00
def update_username_lower
self . username_lower = username . downcase
end
2013-02-05 19:44:49 -07:00
2013-06-06 16:40:10 +02:00
def username_validator
username_format_validator || begin
lower = username . downcase
2013-06-28 16:21:46 -04:00
existing = User . where ( username_lower : lower ) . first
if username_changed? && existing && existing . id != self . id
2013-06-06 16:40:10 +02:00
errors . add ( :username , I18n . t ( :'user.username.unique' ) )
2013-02-05 14:16:51 -05:00
end
2013-02-07 18:23:41 -05:00
end
2013-06-06 16:40:10 +02:00
end
2013-02-05 14:16:51 -05:00
2013-06-06 16:40:10 +02:00
def password_validator
if ( @raw_password && @raw_password . length < 6 ) || ( @password_required && ! @raw_password )
errors . add ( :password , " must be 6 letters or longer " )
2013-02-05 14:16:51 -05:00
end
2013-06-06 16:40:10 +02:00
end
2013-04-05 16:48:38 +11:00
2013-08-13 22:08:29 +02:00
def send_approval_email
Jobs . enqueue ( :user_email ,
type : :signup_after_approval ,
user_id : id ,
email_token : email_tokens . first . token
)
end
2013-07-07 12:40:35 +02:00
2013-08-23 17:35:01 -04:00
def set_default_email_digest
if has_attribute? ( :email_digests ) && self . email_digests . nil?
if SiteSetting . default_digest_email_frequency . blank?
self . email_digests = false
else
self . email_digests = true
self . digest_after_days || = SiteSetting . default_digest_email_frequency . to_i if has_attribute? ( :digest_after_days )
end
end
end
2013-07-07 12:40:35 +02:00
private
2013-10-23 23:24:50 +02:00
def previous_visit_at_update_required? ( timestamp )
seen_before? &&
( last_seen_at < ( timestamp - SiteSetting . previous_visit_timeout_hours . hours ) )
end
def update_previous_visit ( timestamp )
update_visit_record! ( timestamp . to_date )
if previous_visit_at_update_required? ( timestamp )
update_column ( :previous_visit_at , last_seen_at )
end
end
2013-02-05 14:16:51 -05:00
end
2013-05-24 12:48:32 +10:00
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# username :string(20) not null
# created_at :datetime not null
# updated_at :datetime not null
# name :string(255)
# bio_raw :text
# seen_notification_id :integer default(0), not null
# last_posted_at :datetime
# email :string(256) not null
# password_hash :string(64)
# salt :string(32)
# active :boolean
# username_lower :string(20) not null
# auth_token :string(32)
# last_seen_at :datetime
# website :string(255)
# admin :boolean default(FALSE), not null
# last_emailed_at :datetime
2013-08-28 10:42:58 +10:00
# email_digests :boolean not null
2013-05-24 12:48:32 +10:00
# trust_level :integer not null
# bio_cooked :text
# email_private_messages :boolean default(TRUE)
# email_direct :boolean default(TRUE), not null
# approved :boolean default(FALSE), not null
# approved_by_id :integer
# approved_at :datetime
2013-08-28 10:42:58 +10:00
# digest_after_days :integer
2013-05-24 12:48:32 +10:00
# previous_visit_at :datetime
2013-11-07 13:53:32 -05:00
# suspended_at :datetime
# suspended_till :datetime
2013-05-24 12:48:32 +10:00
# date_of_birth :date
# auto_track_topics_after_msecs :integer
# views :integer default(0), not null
# flag_level :integer default(0), not null
# ip_address :string
# new_topic_duration_minutes :integer
# external_links_in_new_tab :boolean default(FALSE), not null
# enable_quoting :boolean default(TRUE), not null
# moderator :boolean default(FALSE)
2013-06-17 02:48:58 +02:00
# blocked :boolean default(FALSE)
2013-06-20 17:42:15 +10:00
# dynamic_favicon :boolean default(FALSE), not null
2013-07-14 11:24:16 +10:00
# title :string(255)
2013-08-13 22:08:29 +02:00
# use_uploaded_avatar :boolean default(FALSE)
# uploaded_avatar_template :string(255)
# uploaded_avatar_id :integer
2013-10-04 13:28:49 +10:00
# email_always :boolean default(FALSE), not null
2013-05-24 12:48:32 +10:00
#
# Indexes
#
# index_users_on_auth_token (auth_token)
# index_users_on_email (email) UNIQUE
# index_users_on_last_posted_at (last_posted_at)
# index_users_on_username (username) UNIQUE
# index_users_on_username_lower (username_lower) UNIQUE
#
2013-08-28 10:42:58 +10:00