<commit_before># Copyright (C) 2009 <NAME>.

require 'digest/sha1'

# User Levels:
# 0 - Opt-Out
# 1 - Manually Added
# 2 - Visited
# 3 - Registered
# 4 - Subscribed
# 5 - Conversion


# Sources:
# website
# import
# referrel

class EndUser < DomainModel
  validates_confirmation_of :password

  # Only need an email if we aren't a client user
  validates_presence_of :email, :if => Proc.new { |usr| !usr.client_user_id && !usr.admin_edit }

  validates_format_of :username, :with => /^([a-zA-Z0-9!#\$%^&*@()_\-.]+)$/,:allow_blank => true, 
                      :message => 'can only contain numbers, letters, and the symbols: !@#$%^&()-_.'

  # Email always needs to be unique - but can be blank if user is an client user
  validates_uniqueness_of :email,:allow_blank => true
  validates_uniqueness_of :username, :allow_blank => true
  validates_presence_of :user_class
  validates_as_email :email
  
  attr_accessor :admin_edit
  attr_accessor :password
  attr_accessor :site_policy

  attr_reader :login
  
  belongs_to :domain_file
  belongs_to :second_image, :class_name => 'DomainFile',:foreign_key => :second_image_id
  
  belongs_to :address, :class_name => 'EndUserAddress', :foreign_key => :address_id
  belongs_to :shipping_address, :class_name => 'EndUserAddress', :foreign_key => :shipping_address_id
  belongs_to :billing_address, :class_name => 'EndUserAddress', :foreign_key => :billing_address_id
  belongs_to :work_address, :class_name => 'EndUserAddress', :foreign_key => :work_address_id
  has_many :addresses, :class_name => 'EndUserAddress', :dependent => :destroy

  has_one :tag_cache, :dependent => :destroy
  
  has_many :end_user_cookies, :dependent => :delete_all, :class_name => 'EndUserCookie'

  has_many :email_friends, :dependent => :delete_all
  has_many :end_user_actions, :dependent => :delete_all

  has_many :end_user_tokens, :dependent => :delete_all
  has_many :access_tokens, :through => :end_user_tokens
  
  acts_as_taggable :join_table => 'end_user_tags', :join_class_name => 'EndUserTag'

  has_many :end_user_tags, :class_name => 'EndUserTag'
  #has_many :tags, :through => :user_tags
  
  belongs_to :source_user, :class_name => 'EndUser'
  
  has_many :user_subscriptions, :through => :user_subscription_entries
  has_many :user_subscription_entries, :dependent => :destroy
  
  has_many :domain_emails

  belongs_to :user_class

  attr_protected :client_user_id
  attr_accessor :email_confirmation

  accepts_nested_attributes_for :end_user_tokens

  has_options :introduction, ['Mr.','Mrs.','Ms.']
  
  has_options :user_level, [ [ '0 - Opt-Out', 0 ], 
                        [ '1 - Added Manually', 1],
                        [ '2 - Visited', 2],
                        [ '3 - Registered', 3],
                        [ '4 - Subscribed', 4],
                        [ '5 - Converison', 5] ]
                      
  has_options :source, [ [ 'Website', 'website' ],
                         [ 'Import', 'import' ],
                         [ 'Referrel', 'referrel' ] ]



  ## Validation Fucntions 
  
  
  
  def before_validation
    self.email = self.email.downcase unless self.email.blank?
  end

  def validate
    if self.registered? && !self.hashed_password && (!self.password || self.password.empty?)
      errors.add(:password, 'is missing')
    end  
  end

  def validate_password(pw)
    return EndUser.hash_password(pw) == self.hashed_password
  end

  def update_verification_string!
    self.update_attribute(:verification_string, Digest::SHA1.hexdigest(Time.now.to_s + rand(1000000000000).to_s)[0..12])
  end

  
  def client_user?
    client_user_id.to_i > 0
  end

  def client_user
    return nil unless client_user_id
    return @client_user if @client_user
    @client_user = ClientUser.find_by_id(client_user_id)
  end

  # Return an Array of subscription ids
  def subscriptions
      self.user_subscriptions.collect { |sub| sub.id }
  end


  ## Access Token Stuff
  def tokens
    through_connection_cache(:end_user_tokens,@access_token_cache)
  end

  def tokens=(val)
    @access_token_cache = val
  end

  after_save :token_cache_update

  def token_cache_update
    if(@access_token_cache)
      set_through_collection_with_attributes(:end_user_tokens,:access_token_id,@access_token_cache)
    end
  end

  def add_token!(tkn)
    self.end_user_tokens.find_by_access_token_id(tkn) ||
      self.end_user_tokens.create(:access_token_id => tkn.id)
  end
  
  def self.select_options(editor=false)
    self.find(:all, :order => 'last_name, first_name',:include => :user_class,
              :conditions => [ 'user_classes.editor = ?',editor ] ).collect { |usr| [ "#{usr.last_name}, #{usr.first_name} (##{usr.id})", usr.id ] } 
  end
  
  
  def image
    self.domain_file ? self.domain_file : Configuration.missing_image(self.gender)
  end
  
  
  def identifier_name
    self.name + " (#{self.id})"
  end
  
  
  def editor?
    self.user_profile.editor?
  end
  
  serialize :options
  
  include VerifiedModel
  
  # Get user class, otherwise just the first (anonymous) user class
  def user_profile
    self.user_class || UserClass.anonymous_class
  end

  def user_profile_id
    self.user_class_id || UserClass.anonymous_class_id
  end


  ## Action Functionality
  def action(action_path,opts = {})
    EndUserAction.log_action(self,action_path,opts)<commit_msg>Set default user action level to 3 unless specified<commit_after># Copyright (C) 2009 <NAME>.

require 'digest/sha1'

# User Levels:
# 0 - Opt-Out
# 1 - Manually Added
# 2 - Visited
# 3 - Registered
# 4 - Subscribed
# 5 - Conversion


# Sources:
# website
# import
# referrel

class EndUser < DomainModel
  validates_confirmation_of :password

  # Only need an email if we aren't a client user
  validates_presence_of :email, :if => Proc.new { |usr| !usr.client_user_id && !usr.admin_edit }

  validates_format_of :username, :with => /^([a-zA-Z0-9!#\$%^&*@()_\-.]+)$/,:allow_blank => true, 
                      :message => 'can only contain numbers, letters, and the symbols: !@#$%^&()-_.'

  # Email always needs to be unique - but can be blank if user is an client user
  validates_uniqueness_of :email,:allow_blank => true
  validates_uniqueness_of :username, :allow_blank => true
  validates_presence_of :user_class
  validates_as_email :email
  
  attr_accessor :admin_edit
  attr_accessor :password
  attr_accessor :site_policy

  attr_reader :login
  
  belongs_to :domain_file
  belongs_to :second_image, :class_name => 'DomainFile',:foreign_key => :second_image_id
  
  belongs_to :address, :class_name => 'EndUserAddress', :foreign_key => :address_id
  belongs_to :shipping_address, :class_name => 'EndUserAddress', :foreign_key => :shipping_address_id
  belongs_to :billing_address, :class_name => 'EndUserAddress', :foreign_key => :billing_address_id
  belongs_to :work_address, :class_name => 'EndUserAddress', :foreign_key => :work_address_id
  has_many :addresses, :class_name => 'EndUserAddress', :dependent => :destroy

  has_one :tag_cache, :dependent => :destroy
  
  has_many :end_user_cookies, :dependent => :delete_all, :class_name => 'EndUserCookie'

  has_many :email_friends, :dependent => :delete_all
  has_many :end_user_actions, :dependent => :delete_all

  has_many :end_user_tokens, :dependent => :delete_all
  has_many :access_tokens, :through => :end_user_tokens
  
  acts_as_taggable :join_table => 'end_user_tags', :join_class_name => 'EndUserTag'

  has_many :end_user_tags, :class_name => 'EndUserTag'
  #has_many :tags, :through => :user_tags
  
  belongs_to :source_user, :class_name => 'EndUser'
  
  has_many :user_subscriptions, :through => :user_subscription_entries
  has_many :user_subscription_entries, :dependent => :destroy
  
  has_many :domain_emails

  belongs_to :user_class

  attr_protected :client_user_id
  attr_accessor :email_confirmation

  accepts_nested_attributes_for :end_user_tokens

  has_options :introduction, ['Mr.','Mrs.','Ms.']
  
  has_options :user_level, [ [ '0 - Opt-Out', 0 ], 
                        [ '1 - Added Manually', 1],
                        [ '2 - Visited', 2],
                        [ '3 - Registered', 3],
                        [ '4 - Subscribed', 4],
                        [ '5 - Converison', 5] ]
                      
  has_options :source, [ [ 'Website', 'website' ],
                         [ 'Import', 'import' ],
                         [ 'Referrel', 'referrel' ] ]



  ## Validation Fucntions 
  
  
  
  def before_validation
    self.email = self.email.downcase unless self.email.blank?
  end

  def validate
    if self.registered? && !self.hashed_password && (!self.password || self.password.empty?)
      errors.add(:password, '<PASSWORD>')
    end  
  end

  def validate_password(pw)
    return EndUser.hash_password(pw) == self.hashed_password
  end

  def update_verification_string!
    self.update_attribute(:verification_string, Digest::SHA1.hexdigest(Time.now.to_s + rand(1000000000000).to_s)[0..12])
  end

  
  def client_user?
    client_user_id.to_i > 0
  end

  def client_user
    return nil unless client_user_id
    return @client_user if @client_user
    @client_user = ClientUser.find_by_id(client_user_id)
  end

  # Return an Array of subscription ids
  def subscriptions
      self.user_subscriptions.collect { |sub| sub.id }
  end


  ## Access Token Stuff
  def tokens
    through_connection_cache(:end_user_tokens,@access_token_cache)
  end

  def tokens=(val)
    @access_token_cache = val
  end

  after_save :token_cache_update

  def token_cache_update
    if(@access_token_cache)
      set_through_collection_with_attributes(:end_user_tokens,:access_token_id,@access_token_cache)
    end
  end

  def add_token!(tkn)
    self.end_user_tokens.find_by_access_token_id(tkn) ||
      self.end_user_tokens.create(:access_token_id => tkn.id)
  end
  
  def self.select_options(editor=false)
    self.find(:all, :order => 'last_name, first_name',:include => :user_class,
              :conditions => [ 'user_classes.editor = ?',editor ] ).collect { |usr| [ "#{usr.last_name}, #{usr.first_name} (##{usr.id})", usr.id ] } 
  end
  
  
  def image
    self.domain_file ? self.domain_file : Configuration.missing_image(self.gender)
  end
  
  
  def identifier_name
    self.name + " (#{self.id})"
  end
  
  
  def editor?
    self.user_profile.editor?
  end
  
  serialize :options
  
  include VerifiedModel
  
  # Get user class, otherwise just the first (anonymous) user class
  def user_profile
    self.user_class || UserClass.anonymous_class
  end

  def user_profile_id
    self.user_class_id || UserClass.anonymous_class_id
  end


  ## Action Functionality
  def action(action_path,opts = {})
    opts[:level] ||= 3
    EndUserAction.log_action(self,action_path,opts)
{'fraction_non_alphanumeric': 0.11302165628775908, 'fraction_numerical': 0.008179198810298355, 'mean_word_length': 3.4926931106471817, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 80, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6776955', 'n_tokens_mistral': 3765, 'n_tokens_neox': 3597, 'n_words': 762}