<commit_before>require 'cdo/user_helpers'
# TODO -- remove this and change the APIs below to check logged in user instead of passing in a user id
module Dashboard
  def self.admin?(user_id)
    !!DASHBOARD_DB[:users].where(id: user_id, admin: true).first
  end
end

class DashboardStudent
  def self.fetch_user_students(user_id)
    DASHBOARD_DB[:users].
      join(:followers, :student_user_id=>:users__id).
      select(*fields).
      where(followers__user_id:user_id).
      all
  end

  def self.create(params)
    name = params[:name].to_s
    name = '<NAME>' if name.empty?

    params[:gender] = nil unless valid_gender?(params[:gender])
    params[:birthday] = age_to_birthday(params[:age]) if age_to_birthday(params[:age])

    created_at = DateTime.now

    row = DASHBOARD_DB[:users].insert({
      name:name,
      user_type:'student',
      provider:'sponsored',
      gender:params[:gender],
      birthday:params[:birthday],
      created_at:created_at,
      updated_at:created_at,
      username:UserHelpers.generate_username(DASHBOARD_DB[:users], name)
    }.merge(random_secrets))
    return nil unless row

    row
  end

  def self.fetch_if_allowed(id_or_ids, dashboard_user_id)
    if id_or_ids.kind_of?(Array)
      # TODO this should actually send a where id in (,,,) type query
      return id_or_ids.map {|id| fetch_if_allowed(id, dashboard_user_id)}
    end

    id = id_or_ids

    return unless DASHBOARD_DB[:followers].
      where(student_user_id: id,
            user_id: dashboard_user_id).first || Dashboard::admin?(dashboard_user_id)

    row = DASHBOARD_DB[:users].
      left_outer_join(:secret_pictures, id: :secret_picture_id).
      select(*fields,
             :secret_pictures__name___secret_picture_name,
             :secret_pictures__path___secret_picture_path,
            ).
      where(users__id:id).
      server(:default).
      first

    row.merge(age: birthday_to_age(row[:birthday]))
  end

  def self.update_if_allowed(params, dashboard_user_id)
    return unless DASHBOARD_DB[:followers].
      where(student_user_id: params[:id],
            user_id: dashboard_user_id)

    fields = {updated_at:DateTime.now}
    fields[:name] = params[:name] unless params[:name].nil_or_empty?
    fields[:encrypted_password] = encrypt_password(params[:password]) unless params[:password].nil_or_empty?
    fields[:gender] = params[:gender] if valid_gender?(params[:gender])
    fields[:birthday] = age_to_birthday(params[:age]) if age_to_birthday(params[:age])
    # TODO only save birthday if age changed
    fields.merge!(random_secrets) if params[:secrets].to_s == 'reset'

    rows_updated = DASHBOARD_DB[:users].
      where(id:params[:id]).
      update(fields)
    return nil unless rows_updated > 0

    fetch_if_allowed(params[:id], dashboard_user_id)
  end

  def self.birthday_to_age(birthday)
    return if birthday.nil?
    age = ((Date.today - birthday) / 365).to_i # TODO should this be 365.25
    age = "21+" if age >= 21
    age
  end

  def self.fields()
    [
      :users__id___id,
      :users__name___name,
      :users__username___username,
      :users__email___email,
      :users__hashed_email___hashed_email,
      :users__gender___gender,
      :users__birthday___birthday,
      :users__prize_earned___prize_earned,
      :users__total_lines___total_lines,
      :users__secret_words___secret_words
    ]
  end

  def self.completed_levels(user_id)
    DASHBOARD_DB[:user_levels].
      where(user_id: user_id).
      and("best_result >= #{ActivityConstants::MINIMUM_PASS_RESULT}")
  end

  VALID_GENDERS = %w(m f)
  def self.valid_gender?(gender)
    VALID_GENDERS.include?(gender)
  end

  def self.age_to_birthday(age)
    age = age.to_i
    return nil if age == 0
    Date.today - age * 365
  end

  def self.random_secrets
    {
     secret_picture_id: random_secret_picture_id,
     secret_words: random_secret_words
    }
  end

  def self.random_secret_picture_id
    SecureRandom.random_number(DASHBOARD_DB[:secret_pictures].count) + 1
  end

  def self.random_secret_words
    "#{random_secret_word} #{random_secret_word}"
  end

  def self.random_secret_word
    random_id = SecureRandom.random_number(DASHBOARD_DB[:secret_words].count) + 1
    DASHBOARD_DB[:secret_words].first(id: random_id)[:word]
  end

  PEPPER = CDO.dashboard_devise_pepper
  STRETCHES = 10

  def self.encrypt_password(password)
    BCrypt::Password.create("#{password}#{<PASSWORD>}", cost: STRETCHES).to_s
  end
end

class DashboardSection

  def initialize(row)
    @row = row
  end

  VALID_LOGIN_TYPES = %w(word picture email)

  def self.valid_login_type?(login_type)
    VALID_LOGIN_TYPES.include? login_type
  end

  VALID_GRADES = ['K'] + (1..12).collect(&:to_s) + ['Other']

  def self.valid_grade?(grade)
    VALID_GRADES.include? grade
  end

  def self.load_valid_courses
    return {} unless DASHBOARD_DB[:scripts].count rescue nil # don't crash when loading environment before database has been created
    Hash[
         DASHBOARD_DB[:scripts].
           where("hidden = 0").
           select(:id, :name).
           all.
           map { |c| [c[:id], c[:name]]}
        ]
  end
  VALID_COURSES = load_valid_courses
  # only do this query once because in prod we only change courses
  # when deploying (technically this isn't true since we are in
  # pegasus and courses are owned by dashboard...)

  def self.valid_course_id?(course_id)
    VALID_COURSES[course_id.to_i]<commit_msg>really fix error when creating new db<commit_after>require 'cdo/user_helpers'
# TODO -- remove this and change the APIs below to check logged in user instead of passing in a user id
module Dashboard
  def self.admin?(user_id)
    !!DASHBOARD_DB[:users].where(id: user_id, admin: true).first
  end
end

class DashboardStudent
  def self.fetch_user_students(user_id)
    DASHBOARD_DB[:users].
      join(:followers, :student_user_id=>:users__id).
      select(*fields).
      where(followers__user_id:user_id).
      all
  end

  def self.create(params)
    name = params[:name].to_s
    name = '<NAME>' if name.empty?

    params[:gender] = nil unless valid_gender?(params[:gender])
    params[:birthday] = age_to_birthday(params[:age]) if age_to_birthday(params[:age])

    created_at = DateTime.now

    row = DASHBOARD_DB[:users].insert({
      name:name,
      user_type:'student',
      provider:'sponsored',
      gender:params[:gender],
      birthday:params[:birthday],
      created_at:created_at,
      updated_at:created_at,
      username:UserHelpers.generate_username(DASHBOARD_DB[:users], name)
    }.merge(random_secrets))
    return nil unless row

    row
  end

  def self.fetch_if_allowed(id_or_ids, dashboard_user_id)
    if id_or_ids.kind_of?(Array)
      # TODO this should actually send a where id in (,,,) type query
      return id_or_ids.map {|id| fetch_if_allowed(id, dashboard_user_id)}
    end

    id = id_or_ids

    return unless DASHBOARD_DB[:followers].
      where(student_user_id: id,
            user_id: dashboard_user_id).first || Dashboard::admin?(dashboard_user_id)

    row = DASHBOARD_DB[:users].
      left_outer_join(:secret_pictures, id: :secret_picture_id).
      select(*fields,
             :secret_pictures__name___secret_picture_name,
             :secret_pictures__path___secret_picture_path,
            ).
      where(users__id:id).
      server(:default).
      first

    row.merge(age: birthday_to_age(row[:birthday]))
  end

  def self.update_if_allowed(params, dashboard_user_id)
    return unless DASHBOARD_DB[:followers].
      where(student_user_id: params[:id],
            user_id: dashboard_user_id)

    fields = {updated_at:DateTime.now}
    fields[:name] = params[:name] unless params[:name].nil_or_empty?
    fields[:encrypted_password] = encrypt_password(params[:password]) unless params[:password].nil_or_empty?
    fields[:gender] = params[:gender] if valid_gender?(params[:gender])
    fields[:birthday] = age_to_birthday(params[:age]) if age_to_birthday(params[:age])
    # TODO only save birthday if age changed
    fields.merge!(random_secrets) if params[:secrets].to_s == 'reset'

    rows_updated = DASHBOARD_DB[:users].
      where(id:params[:id]).
      update(fields)
    return nil unless rows_updated > 0

    fetch_if_allowed(params[:id], dashboard_user_id)
  end

  def self.birthday_to_age(birthday)
    return if birthday.nil?
    age = ((Date.today - birthday) / 365).to_i # TODO should this be 365.25
    age = "21+" if age >= 21
    age
  end

  def self.fields()
    [
      :users__id___id,
      :users__name___name,
      :users__username___username,
      :users__email___email,
      :users__hashed_email___hashed_email,
      :users__gender___gender,
      :users__birthday___birthday,
      :users__prize_earned___prize_earned,
      :users__total_lines___total_lines,
      :users__secret_words___secret_words
    ]
  end

  def self.completed_levels(user_id)
    DASHBOARD_DB[:user_levels].
      where(user_id: user_id).
      and("best_result >= #{ActivityConstants::MINIMUM_PASS_RESULT}")
  end

  VALID_GENDERS = %w(m f)
  def self.valid_gender?(gender)
    VALID_GENDERS.include?(gender)
  end

  def self.age_to_birthday(age)
    age = age.to_i
    return nil if age == 0
    Date.today - age * 365
  end

  def self.random_secrets
    {
     secret_picture_id: random_secret_picture_id,
     secret_words: random_secret_words
    }
  end

  def self.random_secret_picture_id
    SecureRandom.random_number(DASHBOARD_DB[:secret_pictures].count) + 1
  end

  def self.random_secret_words
    "#{random_secret_word} #{random_secret_word}"
  end

  def self.random_secret_word
    random_id = SecureRandom.random_number(DASHBOARD_DB[:secret_words].count) + 1
    DASHBOARD_DB[:secret_words].first(id: random_id)[:word]
  end

  PEPPER = CDO.dashboard_devise_pepper
  STRETCHES = 10

  def self.encrypt_password(password)
    BCrypt::Password.create("#{password}#{PEPPER}", cost: STRETCHES).to_s
  end
end

class DashboardSection

  def initialize(row)
    @row = row
  end

  VALID_LOGIN_TYPES = %w(word picture email)

  def self.valid_login_type?(login_type)
    VALID_LOGIN_TYPES.include? login_type
  end

  VALID_GRADES = ['K'] + (1..12).collect(&:to_s) + ['Other']

  def self.valid_grade?(grade)
    VALID_GRADES.include? grade
  end

  def self.load_valid_courses
    return {} unless (DASHBOARD_DB[:scripts].count rescue nil) # don't crash when loading environment before database has been created
    Hash[
         DASHBOARD_DB[:scripts].
           where("hidden = 0").
           select(:id, :name).
           all.
           map { |c| [c[:id], c[:name]]}
        ]
  end
  VALID_COURSES = load_valid_courses
  # only do this query once because in prod we only change courses
  # when deploying (technically this isn't true since we are in
  # pegasus and courses are owned by dashboard...)

  def self.valid_course_id?(course_id)
    VALID_COURSES[course_id.to_i]
{'fraction_non_alphanumeric': 0.10532089961601755, 'fraction_numerical': 0.00457121960138965, 'mean_word_length': 3.598150483396385, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 14, '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': '4923998', 'n_tokens_mistral': 3840, 'n_tokens_neox': 3656, 'n_words': 729}