<commit_before># == Schema Information
#
# Table name: users
#
#  id                     :integer         not null, primary key
#  email                  :string(255)     default(""), not null
#  full_name              :string(255)     not null
#  display_name           :string(255)
#  role                   :string(255)     not null
#  encrypted_password     :string(128)     default("")
#  confirmation_token     :string(255)
#  confirmed_at           :datetime
#  confirmation_sent_at   :datetime
#  reset_password_token   :string(255)
#  reset_password_sent_at :datetime
#  remember_created_at    :datetime
#  disabled_at            :datetime
#  created_at             :datetime        not null
#  updated_at             :datetime        not null
#  invitation_token       :string(60)
#  invitation_sent_at     :datetime
#  invitation_accepted_at :datetime
#  remembered_group_id    :integer
#  invitation_limit       :integer
#  invited_by_id          :integer
#  invited_by_type        :string(255)
#

class User < ActiveRecord::Base
  attr_accessible :email, :full_name, :display_name, :password, :password_confirmation, :disabled

  acts_as_voter

  devise :database_authenticatable, :registerable, :confirmable, :recoverable, :rememberable, :validatable, :invitable
  ALLOWED_ROLES = %w(member admin)

  has_many :memberships, class_name: "GroupMembership"
  has_many :groups, through: :memberships
  has_many :membership_requests, class_name: "GroupMembershipRequest"
  has_many :actioned_membership_requests, foreign_key: "actioned_by_id", class_name: "GroupMembershipRequest"
  has_many :issues, foreign_key: "created_by_id"
  has_many :created_threads, class_name: "MessageThread", foreign_key: "created_by_id"
  has_many :messages, foreign_key: "created_by_id"
  has_many :locations, class_name: "UserLocation"
  has_many :thread_subscriptions do
    def to(thread)
      where("thread_id = ?", thread).first
    end
  end
  # Would be better using the 'active' named scope on thread_subscriptions instead of the conditions block. But how?
  has_many :subscribed_threads, through: :thread_subscriptions, source: :thread, conditions: 'thread_subscriptions.deleted_at is NULL'
  has_many :thread_priorities, class_name: "UserThreadPriority"
  has_many :prioritised_threads, through: :thread_priorities, source: :thread
  has_many :thread_views
  has_many :site_comments
  has_one :profile, class_name: "UserProfile"
  has_one :prefs, class_name: "UserPref"
  belongs_to :remembered_group, class_name: "Group"

  accepts_nested_attributes_for :profile, update_only: true

  before_validation :set_default_role, :unless => :role
  after_create :create_user_prefs

  scope :active, where("disabled_at IS NULL AND confirmed_at IS NOT NULL")

  validates :full_name, presence: true
  validates :display_name, uniqueness: true, allow_blank: true
  validates :role, presence: true, inclusion: {in: ALLOWED_ROLES} 

  def self.find_or_invite(email_address, name = nil)
    existing = find_by_email(email_address)
    return existing if existing
    name = email_address.split("@").first if name.nil?
    User.invite!(full_name: name, email: email_address)
  end

  def self.init_user_prefs
    joins("LEFT OUTER JOIN user_prefs ON user_prefs.user_id = users.id").
      where("user_prefs.id IS NULL").
      each {|u| u.create_user_prefs }
  end

  def name
    return display_name unless display_name.blank?
    full_name
  end

  def name_with_email
    "#{name} <#{email}>"
  end

  def role_symbols
    return [:root] if root?
    [role.to_sym]
  end

  def root?
    id == 1
  end

  def profile_with_auto_build
    profile_without_auto_build || build_profile
  end
  alias_method_chain :profile, :auto_build

  def to_param
    "#{id}-#{name.parameterize}"
  end

  def subscribed_to_thread?(thread)
    thread_subscriptions.active.to(thread)
  end

  def ever_subscribed_to_thread?(thread)
    thread_subscriptions.to(thread)
  end

  def involved_threads
    MessageThread.with_messages_from(self)
  end

  def prioritised_thread?(thread)
    thread_priorities.where(thread_id: thread.id).exists?
  end

  def disabled
    disabled_at?
  end

  def disabled=(d)
    if d == "1" && !disabled_at?
      self.disabled_at = Time.now<commit_msg>Add helper methods to the user model related to thread_view handling.<commit_after># == Schema Information
#
# Table name: users
#
#  id                     :integer         not null, primary key
#  email                  :string(255)     default(""), not null
#  full_name              :string(255)     not null
#  display_name           :string(255)
#  role                   :string(255)     not null
#  encrypted_password     :string(128)     default("")
#  confirmation_token     :string(255)
#  confirmed_at           :datetime
#  confirmation_sent_at   :datetime
#  reset_password_token   :string(255)
#  reset_password_sent_at :datetime
#  remember_created_at    :datetime
#  disabled_at            :datetime
#  created_at             :datetime        not null
#  updated_at             :datetime        not null
#  invitation_token       :string(60)
#  invitation_sent_at     :datetime
#  invitation_accepted_at :datetime
#  remembered_group_id    :integer
#  invitation_limit       :integer
#  invited_by_id          :integer
#  invited_by_type        :string(255)
#

class User < ActiveRecord::Base
  attr_accessible :email, :full_name, :display_name, :password, :password_confirmation, :disabled

  acts_as_voter

  devise :database_authenticatable, :registerable, :confirmable, :recoverable, :rememberable, :validatable, :invitable
  ALLOWED_ROLES = %w(member admin)

  has_many :memberships, class_name: "GroupMembership"
  has_many :groups, through: :memberships
  has_many :membership_requests, class_name: "GroupMembershipRequest"
  has_many :actioned_membership_requests, foreign_key: "actioned_by_id", class_name: "GroupMembershipRequest"
  has_many :issues, foreign_key: "created_by_id"
  has_many :created_threads, class_name: "MessageThread", foreign_key: "created_by_id"
  has_many :messages, foreign_key: "created_by_id"
  has_many :locations, class_name: "UserLocation"
  has_many :thread_subscriptions do
    def to(thread)
      where("thread_id = ?", thread).first
    end
  end
  # Would be better using the 'active' named scope on thread_subscriptions instead of the conditions block. But how?
  has_many :subscribed_threads, through: :thread_subscriptions, source: :thread, conditions: 'thread_subscriptions.deleted_at is NULL'
  has_many :thread_priorities, class_name: "UserThreadPriority"
  has_many :prioritised_threads, through: :thread_priorities, source: :thread
  has_many :thread_views
  has_many :site_comments
  has_one :profile, class_name: "UserProfile"
  has_one :prefs, class_name: "UserPref"
  belongs_to :remembered_group, class_name: "Group"

  accepts_nested_attributes_for :profile, update_only: true

  before_validation :set_default_role, :unless => :role
  after_create :create_user_prefs

  scope :active, where("disabled_at IS NULL AND confirmed_at IS NOT NULL")

  validates :full_name, presence: true
  validates :display_name, uniqueness: true, allow_blank: true
  validates :role, presence: true, inclusion: {in: ALLOWED_ROLES} 

  def self.find_or_invite(email_address, name = nil)
    existing = find_by_email(email_address)
    return existing if existing
    name = email_address.split("@").first if name.nil?
    User.invite!(full_name: name, email: email_address)
  end

  def self.init_user_prefs
    joins("LEFT OUTER JOIN user_prefs ON user_prefs.user_id = users.id").
      where("user_prefs.id IS NULL").
      each {|u| u.create_user_prefs }
  end

  def name
    return display_name unless display_name.blank?
    full_name
  end

  def name_with_email
    "#{name} <#{email}>"
  end

  def role_symbols
    return [:root] if root?
    [role.to_sym]
  end

  def root?
    id == 1
  end

  def profile_with_auto_build
    profile_without_auto_build || build_profile
  end
  alias_method_chain :profile, :auto_build

  def to_param
    "#{id}-#{name.parameterize}"
  end

  def subscribed_to_thread?(thread)
    thread_subscriptions.active.to(thread)
  end

  def ever_subscribed_to_thread?(thread)
    thread_subscriptions.to(thread)
  end

  def involved_threads
    MessageThread.with_messages_from(self)
  end

  def prioritised_thread?(thread)
    thread_priorities.where(thread_id: thread.id).exists?
  end

  def viewed_thread?(thread)
    thread_views.where(thread_id: thread.id).exists?
  end

  def viewed_thread_at(thread)
    thread_views.where(thread_id: thread.id).first.viewed_at
  end

  def disabled
    disabled_at?
  end

  def disabled=(d)
    if d == "1" && !disabled_at?
      self.disabled_at = Time.now
{'fraction_non_alphanumeric': 0.08752285191956125, 'fraction_numerical': 0.006398537477148081, 'mean_word_length': 3.870895937673901, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, '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': '7085278', 'n_tokens_mistral': 2891, 'n_tokens_neox': 2819, 'n_words': 669}