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
has_many :notifications
has_many :topic_users
has_many :topics
2013-04-11 16:04:20 -04:00
has_many :user_open_ids , dependent : :destroy
2013-02-05 14:16:51 -05:00
has_many :user_actions
has_many :post_actions
has_many :email_logs
has_many :post_timings
has_many :topic_allowed_users
has_many :topics_allowed , through : :topic_allowed_users , source : :topic
has_many :email_tokens
has_many :views
has_many :user_visits
has_many :invites
2013-05-10 16:58:23 -04:00
has_many :topic_links
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-02-05 14:16:51 -05:00
belongs_to :approved_by , class_name : 'User'
2013-04-29 16:33:24 +10:00
has_many :group_users
has_many :groups , through : :group_users
has_many :secure_categories , through : :groups , source : :categories
2013-05-22 15:33:33 -04:00
has_one :user_search_data
2013-02-05 14:16:51 -05:00
validates_presence_of :username
validates_presence_of :email
validates_uniqueness_of :email
validate :username_validator
2013-02-28 16:08:56 +03:00
validate :email_validator , if : :email_changed?
2013-02-05 14:16:51 -05:00
validate :password_validator
before_save :cook
before_save :update_username_lower
before_save :ensure_password_is_hashed
after_initialize :add_trust_level
after_save :update_tracked_topics
2013-02-05 19:44:49 -07:00
after_create :create_email_token
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-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 . create_for_email ( email , opts = { } )
2013-06-06 16:40:10 +02:00
username = UserNameSuggester . suggest ( email )
2013-02-05 14:16:51 -05:00
2013-02-14 12:57:26 -05:00
if SiteSetting . call_discourse_hub?
2013-02-05 14:16:51 -05:00
begin
2013-02-28 16:08:56 +03:00
match , available , suggestion = DiscourseHub . nickname_match? ( username , email )
username = suggestion unless match || available
2013-02-05 14:16:51 -05:00
rescue = > e
Rails . logger . error e . message + " \n " + e . backtrace . join ( " \n " )
end
end
user = User . new ( email : email , username : username , name : username )
user . trust_level = opts [ :trust_level ] if opts [ :trust_level ] . present?
user . save!
2013-02-14 12:57:26 -05:00
if SiteSetting . call_discourse_hub?
2013-02-05 14:16:51 -05:00
begin
2013-02-28 16:08:56 +03:00
DiscourseHub . register_nickname ( username , email )
2013-02-05 14:16:51 -05:00
rescue = > e
Rails . logger . error e . message + " \n " + e . backtrace . join ( " \n " )
end
end
user
end
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 )
lower_user = username_or_email . downcase
lower_email = Email . downcase ( username_or_email )
2013-06-19 10:31:19 +10:00
users =
if username_or_email . include? ( '@' )
User . where ( email : lower_email )
else
User . where ( username_lower : lower_user )
end
. to_a
if users . count > 1
raise Discourse :: TooManyMatches
elsif users . count == 1
users [ 0 ]
else
nil
end
2013-04-29 16:33:24 +10:00
end
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-06-28 16:21:46 -04:00
if current_username . downcase != new_username . downcase && SiteSetting . call_discourse_hub? && valid?
2013-02-05 14:16:51 -05:00
begin
2013-02-28 16:08:56 +03:00
DiscourseHub . change_nickname ( current_username , new_username )
2013-02-14 12:57:26 -05:00
rescue DiscourseHub :: NicknameUnavailable
2013-02-28 16:08:56 +03:00
false
2013-02-05 14:16:51 -05:00
rescue = > e
Rails . logger . error e . message + " \n " + e . backtrace . join ( " \n " )
end
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-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
self . approved_by = approved_by
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-07-01 20:45:52 +02:00
User . where ( [ " seen_notification_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-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 )
update_column ( :days_visited , 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-06-28 15:14:44 +10:00
def update_last_seen! ( now = nil )
now || = Time . zone . now
2013-02-05 14:16:51 -05:00
now_date = now . to_date
2013-06-28 16:07:36 +10:00
2013-02-05 14:16:51 -05:00
# Only update last seen once every minute
2013-06-28 16:08:48 +10:00
redis_key = " user: #{ self . id } : #{ now_date } "
2013-02-05 14:16:51 -05:00
if $redis . setnx ( redis_key , " 1 " )
$redis . expire ( redis_key , SiteSetting . active_user_rate_limit_secs )
2013-02-12 13:41:04 +08:00
update_visit_record! ( now_date )
2013-02-05 14:16:51 -05:00
2013-02-12 13:41:04 +08:00
# using update_column to avoid the AR transaction
2013-02-05 14:16:51 -05:00
# Keep track of our last visit
2013-02-12 13:41:04 +08:00
if seen_before? && ( self . last_seen_at < ( now - SiteSetting . previous_visit_timeout_hours . hours ) )
previous_visit_at = last_seen_at
2013-02-28 16:08:56 +03:00
update_column ( :previous_visit_at , previous_visit_at )
2013-02-05 14:16:51 -05:00
end
2013-06-06 16:40:10 +02:00
update_column ( :last_seen_at , now )
2013-02-05 14:16:51 -05:00
end
end
def self . avatar_template ( email )
email_hash = self . email_hash ( email )
# robohash was possibly causing caching issues
# robohash = CGI.escape("http://robohash.org/size_") << "{size}x{size}" << CGI.escape("/#{email_hash}.png")
2013-03-01 00:58:36 +04:00
" https://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-05-01 16:37:27 +10:00
# The only spot this is now used is for self oneboxes in open graph data
2013-03-08 15:58:37 -05:00
def small_avatar_url
2013-05-01 16:37:27 +10:00
" https://www.gravatar.com/avatar/ #{ email_hash } .png?s=60&r=pg&d=identicon "
2013-03-08 15:58:37 -05:00
end
2013-02-05 14:16:51 -05:00
# return null for local avatars, a template for gravatar
def avatar_template
2013-02-28 16:08:56 +03:00
User . avatar_template ( email )
2013-02-05 14:16:51 -05:00
end
# Updates the denormalized view counts for all users
def self . update_view_counts
# Update denormalized topics_entered
exec_sql " UPDATE users SET topics_entered = x.c
FROM
2013-02-05 19:44:49 -07:00
( SELECT v . user_id ,
2013-02-05 14:16:51 -05:00
COUNT ( DISTINCT parent_id ) AS c
FROM views AS v
WHERE parent_type = 'Topic'
GROUP BY v . user_id ) AS X
WHERE x . user_id = users . id "
# Update denormalzied posts_read_count
exec_sql " UPDATE users SET posts_read_count = x.c
FROM
( SELECT pt . user_id ,
COUNT ( * ) AS c
FROM post_timings AS pt
GROUP BY pt . user_id ) AS X
WHERE x . user_id = users . id "
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-02-05 14:16:51 -05:00
def is_banned?
2013-02-28 16:08:56 +03:00
banned_till && banned_till > DateTime . now
2013-02-05 14:16:51 -05:00
end
# 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-02-08 15:52:56 +01:00
validator = UsernameValidator . new ( username )
unless validator . valid_format?
2013-02-08 14:12:48 -05:00
validator . errors . each { | e | errors . add ( :username , e ) }
2013-02-07 18:23:41 -05:00
end
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-25 18:42:42 +11:00
MAX_TIME_READ_DIFF = 100
# attempt to add total read time to user based on previous time this was called
2013-02-25 19:42:20 +03:00
def update_time_read!
2013-02-25 18:42:42 +11:00
last_seen_key = " user-last-seen: #{ id } "
last_seen = $redis . get ( last_seen_key )
if last_seen . present?
diff = ( Time . now . to_f - last_seen . to_f ) . round
if diff > 0 && diff < MAX_TIME_READ_DIFF
2013-07-01 20:45:52 +02:00
User . where ( id : id , time_read : time_read ) . update_all [ " time_read = time_read + ? " , diff ]
2013-02-25 18:42:42 +11:00
end
end
$redis . set ( last_seen_key , Time . now . to_f )
end
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-03-15 18:08:46 -04:00
def self . counts_by_trust_level
group ( 'trust_level' ) . count
end
2013-04-05 16:48:38 +11:00
def update_topic_reply_count
2013-04-05 17:44:56 +11:00
self . topic_reply_count =
2013-06-06 16:40:10 +02:00
Topic
2013-04-05 16:48:38 +11:00
. where ( [ ' id in (
SELECT topic_id FROM posts p
JOIN topics t2 ON t2 . id = p . topic_id
2013-04-05 17:43:48 +11:00
WHERE p . deleted_at IS NULL AND
2013-04-05 16:48:38 +11:00
t2 . user_id < > p . user_id AND
p . user_id = ?
) ' , self . id ] )
. count
end
2013-04-29 16:33:24 +10:00
def secure_category_ids
2013-05-10 16:47:47 +10:00
cats = self . staff? ? Category . select ( :id ) . where ( secure : true ) : secure_categories . select ( 'categories.id' )
2013-06-06 16:40:10 +02:00
cats . map { | c | c . id } . sort
2013-04-29 16:33:24 +10:00
end
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
PostAction . act ( admin , tl . post , PostActionType . types [ :spam ] )
rescue PostAction :: AlreadyActed
# If the user has already acted, just ignore it
end
end
end
2013-05-13 18:04:03 +10:00
2013-05-24 20:58:26 +10:00
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-02-05 14:16:51 -05:00
2013-06-06 16:40:10 +02:00
where_conditions = { notifications_reason_id : nil , user_id : id }
if auto_track_topics_after_msecs < 0
2013-07-01 20:45:52 +02:00
TopicUser . where ( where_conditions ) . update_all ( { notification_level : TopicUser . notification_levels [ :regular ] } )
2013-06-06 16:40:10 +02:00
else
2013-07-01 20:45:52 +02:00
TopicUser . where ( where_conditions ) . update_all ( [ " notification_level = CASE WHEN total_msecs_viewed < ? THEN ? ELSE ? END " ,
auto_track_topics_after_msecs , TopicUser . notification_levels [ :regular ] , TopicUser . notification_levels [ :tracking ] ] )
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 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 )
Pbkdf2 . hash_password ( password , salt , Rails . configuration . pbkdf2_iterations )
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 email_validator
if ( setting = SiteSetting . email_domains_whitelist ) . present?
unless email_in_restriction_setting? ( setting )
errors . add ( :email , I18n . t ( :'user.email.not_allowed' ) )
end
elsif ( setting = SiteSetting . email_domains_blacklist ) . present?
if email_in_restriction_setting? ( setting )
errors . add ( :email , I18n . t ( :'user.email.not_allowed' ) )
2013-02-13 12:28:23 -05:00
end
end
2013-06-06 16:40:10 +02:00
end
2013-03-31 18:51:13 +02:00
2013-06-06 16:40:10 +02:00
def email_in_restriction_setting? ( setting )
domains = setting . gsub ( '.' , '\.' )
regexp = Regexp . new ( " @( #{ domains } ) " , true )
self . email =~ regexp
end
2013-02-13 12:28:23 -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-06-05 20:16:31 -07:00
def send_approval_email
Jobs . enqueue ( :user_email ,
type : :signup_after_approval ,
user_id : id ,
email_token : email_tokens . first . token
)
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
# email_digests :boolean default(TRUE), not null
# 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
# topics_entered :integer default(0), not null
# posts_read_count :integer default(0), not null
# digest_after_days :integer default(7), not null
# previous_visit_at :datetime
# banned_at :datetime
# banned_till :datetime
# date_of_birth :date
# auto_track_topics_after_msecs :integer
# views :integer default(0), not null
# flag_level :integer default(0), not null
# time_read :integer default(0), not null
# days_visited :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)
# likes_given :integer default(0), not null
# likes_received :integer default(0), not null
# topic_reply_count :integer default(0), not null
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-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
#