<commit_before># == Schema Information
#
# Table name: users
#
#  id              :integer(4)      not null, primary key
#  email           :string(50)
#  preferred_email :string(50)
#  password        :string(32)
#  salt            :string(32)
#  role            :string(20)      default("member")
#  status          :string(20)      default("ok")
#  icu_id          :integer(4)
#  expiry          :date
#  last_pull       :string(255)
#  last_pulled_at  :datetime
#  created_at      :datetime
#  updated_at      :datetime
#

class User < ActiveRecord::Base
  extend ICU::Util::Pagination

  belongs_to :icu_player, foreign_key: "icu_id"
  has_many :logins
  has_many :uploads
  has_many :tournaments
  has_many :articles

  ROLES  = %w[member reporter officer admin]  # MUST be in order lowest to highest (see role?)
  EMAIL  = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
  STATUS = %w[ok pending]

  attr_reader :new_password

  before_validation :normalise_attributes

  validates :email, format: { with: EMAIL, message: "(%{value}) is invalid"}
  validates :preferred_email, format: { with: EMAIL, message: "(%{value}) is invalid" }, allow_nil: true
  validates :email, uniqueness: { case_sensitive: false }
  validates :password, presence: true
  validates :role, inclusion: { in: ROLES, message: "(%{value}) is invalid" }
  validates :status, inclusion: { in: STATUS, message: "(%{value}) is invalid" }
  validates :icu_id, numericality: { only_integer: true, greater_than: 0, message: "(%{value}) is invalid" }
  validates :expiry, timeliness: { on_or_after: "2004-12-31", type: :date }

  default_scope -> { includes(:icu_player).references(:icu_player) }

  def self.search(params, path)
    matches = order("users.email")
    if params[:last_name].present? || params[:first_name].present?
      matches = matches.joins(:icu_player)
      matches = matches.where("icu_players.last_name LIKE ?", "%#{params[:last_name]}%") if params[:last_name].present?
      matches = matches.where("icu_players.first_name LIKE ?", "%#{params[:first_name]}%") if params[:first_name].present?
    end
    matches = matches.where("users.icu_id = ?", params[:icu_id].to_i) if params[:icu_id].to_i > 0
    matches = matches.where("users.role = ?", params[:role]) if params[:role].present?
    matches = matches.where("users.status = ?", params[:status]) if params[:status].present?
    matches = matches.where("users.email LIKE ?", "%#{params[:email]}%") if params[:email].present?
    paginate(matches, path, params)
  end

  def self.contacts
    users = User.where("role != 'member'").joins(:icu_player).order("last_name, first_name")
    users = users.inject(Hash.new { |h, k| h[k] = [] }) { |hash, user| hash[user.role] << user; hash }
    if users["officer"].size == 0 && users["admin"].size == 1
      users["officer"] = users["admin"]
      users["admin"] = []
    end
    users
  end

  def self.authenticate!(params, ip, admin)
    user = find_by(email: params[:email])
    raise "Invalid email or password" unless user
    user.pull_www_member unless user.password_ok?(params[:password], admin) && user.status == "ok" && !user.expiry.past?
    user.login_event(ip, admin, :password) unless user.password_ok?(params[:password], admin)
    user.login_event(ip, admin, :status) unless user.status == "ok"
    user.login_event(ip, admin, :expiry) if user.expiry.past?
    user.login_event(ip, admin, :none)
    user
  end

  def login_event(ip, admin, problem)
    logins.create(ip: ip, problem: problem.to_s, role: role) unless admin
    err = case problem
      when :expiry   then "Sorry, account suspended #{expiry} due to lapsed membership"
      when :status   then "Sorry, your account has not yet been activated (see Help)"
      when :password then "Invalid email or password"<commit_msg>More rewording<commit_after># == Schema Information
#
# Table name: users
#
#  id              :integer(4)      not null, primary key
#  email           :string(50)
#  preferred_email :string(50)
#  password        :string(32)
#  salt            :string(32)
#  role            :string(20)      default("member")
#  status          :string(20)      default("ok")
#  icu_id          :integer(4)
#  expiry          :date
#  last_pull       :string(255)
#  last_pulled_at  :datetime
#  created_at      :datetime
#  updated_at      :datetime
#

class User < ActiveRecord::Base
  extend ICU::Util::Pagination

  belongs_to :icu_player, foreign_key: "icu_id"
  has_many :logins
  has_many :uploads
  has_many :tournaments
  has_many :articles

  ROLES  = %w[member reporter officer admin]  # MUST be in order lowest to highest (see role?)
  EMAIL  = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
  STATUS = %w[ok pending]

  attr_reader :new_password

  before_validation :normalise_attributes

  validates :email, format: { with: EMAIL, message: "(%{value}) is invalid"}
  validates :preferred_email, format: { with: EMAIL, message: "(%{value}) is invalid" }, allow_nil: true
  validates :email, uniqueness: { case_sensitive: false }
  validates :password, presence: true
  validates :role, inclusion: { in: ROLES, message: "(%{value}) is invalid" }
  validates :status, inclusion: { in: STATUS, message: "(%{value}) is invalid" }
  validates :icu_id, numericality: { only_integer: true, greater_than: 0, message: "(%{value}) is invalid" }
  validates :expiry, timeliness: { on_or_after: "2004-12-31", type: :date }

  default_scope -> { includes(:icu_player).references(:icu_player) }

  def self.search(params, path)
    matches = order("users.email")
    if params[:last_name].present? || params[:first_name].present?
      matches = matches.joins(:icu_player)
      matches = matches.where("icu_players.last_name LIKE ?", "%#{params[:last_name]}%") if params[:last_name].present?
      matches = matches.where("icu_players.first_name LIKE ?", "%#{params[:first_name]}%") if params[:first_name].present?
    end
    matches = matches.where("users.icu_id = ?", params[:icu_id].to_i) if params[:icu_id].to_i > 0
    matches = matches.where("users.role = ?", params[:role]) if params[:role].present?
    matches = matches.where("users.status = ?", params[:status]) if params[:status].present?
    matches = matches.where("users.email LIKE ?", "%#{params[:email]}%") if params[:email].present?
    paginate(matches, path, params)
  end

  def self.contacts
    users = User.where("role != 'member'").joins(:icu_player).order("last_name, first_name")
    users = users.inject(Hash.new { |h, k| h[k] = [] }) { |hash, user| hash[user.role] << user; hash }
    if users["officer"].size == 0 && users["admin"].size == 1
      users["officer"] = users["admin"]
      users["admin"] = []
    end
    users
  end

  def self.authenticate!(params, ip, admin)
    user = find_by(email: params[:email])
    raise "Invalid email or password" unless user
    user.pull_www_member unless user.password_ok?(params[:password], admin) && user.status == "ok" && !user.expiry.past?
    user.login_event(ip, admin, :password) unless user.password_ok?(params[:password], admin)
    user.login_event(ip, admin, :status) unless user.status == "ok"
    user.login_event(ip, admin, :expiry) if user.expiry.past?
    user.login_event(ip, admin, :none)
    user
  end

  def login_event(ip, admin, problem)
    logins.create(ip: ip, problem: problem.to_s, role: role) unless admin
    err = case problem
      when :expiry   then "Sorry, account suspended #{expiry} due to lapsed ICU membership"
      when :status   then "Sorry, your account has not yet been activated (see Help)"
      when :password then "<PASSWORD>"
{'fraction_non_alphanumeric': 0.15457662885782117, 'fraction_numerical': 0.008441044579266685, 'mean_word_length': 3.805449936628644, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '5663639', 'n_tokens_mistral': 2580, 'n_tokens_neox': 2504, 'n_words': 618}