Skip to content

Instantly share code, notes, and snippets.

@davidimoore
Created December 7, 2015 18:52
Show Gist options
  • Select an option

  • Save davidimoore/3dd0ac6ea0c29f3d007e to your computer and use it in GitHub Desktop.

Select an option

Save davidimoore/3dd0ac6ea0c29f3d007e to your computer and use it in GitHub Desktop.
User
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# email :string(255) default(""), not null
# encrypted_password :string(255) default(""), not null
# reset_password_token :string(255)
# reset_password_sent_at :datetime
# remember_created_at :datetime
# sign_in_count :integer default(0), not null
# current_sign_in_at :datetime
# last_sign_in_at :datetime
# current_sign_in_ip :string(255)
# last_sign_in_ip :string(255)
# gender :string(255) default("U")
# first_name :string(255)
# last_name :string(255)
# join_me_username :string(255)
# join_me_password :string(255)
# skype_login :string(255)
# skype_password :string(255)
# oms_password :string(255)
# notes :string(255)
# call_number :string(255)
# sms_number :string(255)
# emulating_student :boolean default(FALSE)
# archived :boolean default(FALSE)
# roles :text default([]), is an Array
# created_at :datetime
# updated_at :datetime
# modal_states :json default({})
# speaks_spanish :boolean default(FALSE)
# tutored_previously :boolean default(FALSE)
# accepts_tutor_agreement_guidelines :boolean default(FALSE)
# cleared_background_check :boolean default(FALSE)
# student_city :string(255)
# tutor_city :string(255)
# address1 :string(255)
# address2 :string(255)
# city :string(255)
# state :string(255)
# zipcode :string(255)
# test :boolean default(FALSE)
# completed_tutor_training :boolean default(FALSE)
# completed_teacher_training :boolean default(FALSE)
# view_promotion :boolean default(TRUE)
# token :string
# profile :json default({})
# permissions :json default({})
# reading_stage :integer
# student_password :string default("1234")
# reading_stage_updated_at :datetime
# program_access :string
# oms_id :integer
# initial_reading_stage :integer default(1)
# initial_reading_stage_updated_at :datetime
# oms_login :string
#
class User < ActiveRecord::Base
include Roles
attr_accessor :description, :tutor_registration, :tutor_group_id
# Include default devise modules. Others available are:
# :confirmable, :lockable, :omniauthable, :timeoutable
devise :database_authenticatable, :recoverable, :rememberable, :registerable,
:trackable, :validatable, :async
with_options if: "tutor_registration?" do |tutor_registration|
tutor_registration.validates :first_name, presence: true
tutor_registration.validates :last_name, presence: true
tutor_registration.validates :call_number, presence: true
tutor_registration.validates :accepts_tutor_agreement_guidelines, acceptance: { accept: true }
tutor_registration.validate :validate_tutor_group
end
has_many :classroom_users
has_many :classrooms, through: :classroom_users
has_many :school_users
has_many :schools, through: :school_users
has_many :area_users
has_many :areas, through: :area_users
has_many :district_users
has_many :districts, through: :district_users
has_many :user_reading_stages, class_name: "UserReadingStage", foreign_key: :student_id
has_many :assessed_user_reading_stages, class_name: "UserReadingStage", foreign_key: :assessor_id
has_many :student_assignments, class_name: "TutorAssignment", foreign_key: :student_id
has_many :tutors, through: :student_assignments, source: :tutor
has_many :tutor_assignments, class_name: "TutorAssignment", foreign_key: :tutor_id
has_many :students, through: :tutor_assignments, source: :student
has_many :tutor_sessions, through: :tutor_assignments
has_many :tutor_session_feedbacks, foreign_key: :author_id
has_many :organization_users
has_many :organizations, through: :organization_users
has_many :tutor_group_users
has_many :tutor_groups, through: :tutor_group_users
has_many :meeting_users
has_many :meetings, through: :meeting_users
has_many :meeting_reservations
has_many :meetings_to_attend, through: :meeting_reservations, source: :meeting
has_many :tutor_events, class_name: "TutorEvent", foreign_key: :author_id
has_many :user_messages
has_many :messages, through: :user_messages
has_many :sent_messages, class_name: "Message", foreign_key: :author_id
has_many :authored_notes, class_name: "Note", foreign_key: :author_id
has_many :notes
has_many :evaluations
has_many :chat_transcripts
has_many :task_confirmations
has_many :reports
has_many :stimuli
has_many :conference_users
has_many :conferences, through: :conference_users
has_many :conference_sessions
has_many :user_previous_classrooms
has_many :previous_classrooms, through: :user_previous_classrooms, source: :classroom
has_many :client_errors
has_many :activity_logs, as: :loggable
default_scope { order("LOWER(last_name) ASC, LOWER(first_name) ASC") }
scope :with_one_of_roles, ->(*roles) { where.overlap(roles: roles) }
scope :active, -> { where(archived: false, test: false) }
scope :non_roles, -> { where("'user' = ANY (roles)").order(last_name: :asc) }
scope :teachers, -> { where("'#{Roles::TEACHER}' = ANY (roles)").order(last_name: :asc) }
scope :tutors, -> { where("'#{Roles::TUTOR}' = ANY (roles)").order(last_name: :asc) }
scope :test_tutors, -> { where(test: true).where("'#{Roles::TUTOR}' = ANY (roles)").order(last_name: :asc) }
scope :non_students, -> { where("'#{Roles::TUTOR}' = ANY (roles) OR '#{Roles::TEACHER}' = ANY (roles) OR '#{Roles::ADMIN}' = ANY (roles) OR '#{Roles::STAFF}' = ANY (roles)").order(last_name: :asc) }
scope :students, -> { where("'#{Roles::STUDENT}' = ANY (roles)").order(last_name: :asc) }
scope :staff, -> { where("'#{Roles::STAFF}' = ANY (roles)").order(last_name: :asc) }
scope :admins, -> { where("'#{Roles::ADMIN}' = ANY (roles)").order(last_name: :asc) }
scope :archived, -> { where(archived: true) }
scope :test, -> { where(test: true) }
scope :assigned_teachers, -> { joins(:classroom_users).where("'#{Roles::TEACHER}' = ANY (roles)").active.order(last_name: :asc) }
scope :autocomplete_tutor, -> (tutor_query) { tutors.active.where("first_name ilike ? or last_name ilike ?", "#{tutor_query}%", "#{tutor_query}%").includes(:tutor_groups).order(last_name: :asc, first_name: :asc) }
scope :autocomplete_student, -> (student_query) { students.active.where("first_name ilike ? or last_name ilike ?", "#{student_query}%", "%#{student_query}%").includes(:classrooms).order(last_name: :asc, first_name: :asc) }
scope :autocomplete, -> (user_query) { active.where("first_name ilike ? or last_name ilike ?", "#{user_query}%", "#{user_query}%").order(last_name: :asc, first_name: :asc) }
after_create :set_oms_login
after_create :set_default_role
after_create :set_reading_stage
after_create :update_profile
after_create :update_permissions
after_update :update_conferences
def generate_token!
self.token = SecureRandom.hex
save!
end
def description
@description
end
def full_name_with_desc
title = description || roles[0].capitalize
"#{full_name} (#{title})"
end
def full_name
"#{first_name} #{last_name}".gsub(/\b('?[a-z])/) { $1.capitalize }.strip
end
alias_method :name, :full_name
def full_name_abbreviated(last_name_length = 7)
first_name_abbrev = first_name.gsub(/\b('?[a-z])/) { $1.capitalize }.strip.slice(0, 1)
last_name_abbrev = last_name.gsub(/\b('?[a-z])/) { $1.capitalize }.strip.slice(0, last_name_length)
"#{first_name_abbrev}. #{last_name_abbrev}"
end
def student_name_abbreviated(first_name_length = 7)
first_name_abbrev = first_name.gsub(/\b('?[a-z])/) { $1.capitalize }.strip.slice(0, first_name_length)
last_name_abbrev = last_name.gsub(/\b('?[a-z])/) { $1.capitalize }.strip.slice(0, 1)
"#{first_name_abbrev} #{last_name_abbrev}."
end
def active_admin_access?
roles.any? { |role| Roles.system_roles.include?(role) }
end
def active_for_authentication?
super && !self.archived?
end
def user_role?
roles.any? { |role| Roles.user_roles.include?(role) }
end
def is?(role)
roles.include? role
end
def is_not?(role)
!roles.include? role
end
def roles_contain_one_of?(allowed_roles)
roles.any? do |role|
allowed_roles.include? role
end
end
def set_default_role
update_attribute :roles, ["user"] if roles.empty?
end
def admin?
is? Roles::ADMIN
end
def staff?
is?(Roles::ADMIN) || is?(Roles::STAFF)
end
def archived?
archived
end
def active?
((archived == false || archived.nil?) && (test == false || test.nil?))
end
def activity_role
emulating_student || is_not?(Roles::TUTOR) ? Roles::STUDENT : Roles::TUTOR
end
def active_admin_access?
roles.any? { |role| Roles.active_admin_roles.include?(role) }
end
def primary_tutor_assignment
tutor_assignments.active.first
rescue
nil
end
def primary_teaching_classroom
classrooms.where(classroom_users: { role: [ClassroomRoles::PRIMARY_TEACHER, ClassroomRoles::TEACHER] }).first
rescue
nil
end
def primary_classroom
primary_tutor_assignment.classroom
rescue
nil
end
def primary_student
tutor_assignments.active.first.student
rescue
nil
end
def primary_student_assignment
student_assignments.active.first
rescue
nil
end
def primary_tutor
student_assignments.where(archived: false).first.tutor
rescue
nil
end
def primary_district
districts.first
end
def primary_channel_open?
primary_tutor_assignment.present? && primary_tutor_assignment.tutor_channels.present? && primary_tutor_assignment.tutor_channels.first.open?
end
def active_tutor_session
return nil unless primary_tutor_assignment.present?
primary_tutor_assignment.tutor_sessions.where(end_time: nil).first
end
def flashcard_assessments
evaluation = evaluations.find_by evaluation_type: EvaluationTypes::TUTORMATE_FLASHCARD
evaluation ? evaluation.assessments : nil
end
def latest_reading_stage(assessor_role = "overall", context = ReadingStageContexts::CLASSROOM)
case assessor_role
when "teacher"
assessment = UserReadingStage.latest_by_teacher(self)
when "other"
assessment = UserReadingStage.latest_by_non_teacher(self, context)
else
assessment = UserReadingStage.latest_overall(self)
end
assessment ? assessment.reading_stage : ReadingStages::ONE
end
def primary_school
primary_classroom.try(:school)
end
def primary_area
primary_school.try(:area)
end
def primary_district
primary_area.try(:district)
end
def self.update_profiles
tutors.each{ |user| user.create_update_profile_job }
end
def create_update_profile_job
UserUpdateProfileWorker.perform_async(id)
end
def update_profile
data = {
user_id: id,
name: full_name,
email: email,
classroom_id: primary_classroom.try(:id) || 0,
classroom_name: primary_classroom.try(:abbreviation) || "No Classroom",
classroom_phone_number: primary_classroom.try(:call_number) || "No Classroom Phone Number",
school_name: primary_school.try(:abbreviation) || "No School",
area_name: primary_area.try(:name) || "No Area",
tutor_group_id: tutor_groups.try(:first).try(:id) || 0,
tutor_group_name: tutor_groups.try(:first).try(:name) || "No Tutor Group",
tutor_assignment_id: primary_tutor_assignment.try(:id) || 0,
student_name: primary_student.try(:student_name_abbreviated, 15) || "No Student"
}
update_attribute(:profile, data)
end
def json_chat_profile
{
user_id: id,
name: full_name,
email: email,
classroom_id: profile["classroom_id"] || 0,
classroom_name: profile["classroom_name"] || "No Classroom",
classroom_phone_number: profile["classroom_phone_number"] || "No Classroom Phone Number",
school_name: profile["school_name"] || "No School",
area_name: profile["area_name"] || "No Area",
tutor_assignment_id: profile["tutor_assignment_id"] || 0,
tutor_group_id: profile["tutor_group_id"] || 0,
tutor_group_name: profile["tutor_group_name"] || "No Tutor Group",
student_name: profile["student_name"] || "No Student"
}.as_json
end
def archive
update_attribute(:archived, true)
self.student_assignments.each{ |assignment| assignment.archive } if self.is?(Roles::STUDENT)
self.tutor_assignments.each{ |assignment| assignment.archive } if self.is?(Roles::TUTOR)
self.tutor_events.each{ |event| event.destroy } if self.is?(Roles::TUTOR)
self.meeting_reservations.each{ |reservation| reservation.destroy } if self.is?(Roles::TUTOR)
self.conferences.of_user.each{ |conference| conference.update_attribute(:archived, true) }
self.conference_users.of_groups.destroy_all
end
def unarchive
update_attribute(:archived, false)
self.conferences.of_user.each{ |conference| conference.update_attribute(archived: false) }
end
def primary_tutor_group
tutor_groups.first
rescue
nil
end
def needs_alt_chat?
primary_tutor_group.present? && primary_tutor_group.blocks_chat?
end
def qualified?
cleared_background_check == true && accepts_tutor_agreement_guidelines == true && completed_tutor_training == true
end
def self.update_users_permissions(model_name)
users = model_name.constantize.for_permissions.map{ |model_user| model_user.user }
users.each{|user| UserUpdatePermissionsWorker.perform_async(user.id) }
end
def update_permissions
case
when staff?
dis = District.all.order(abbreviation: :asc)
ars = Area.all.includes(:district).order(abbreviation: :asc)
scs = School.all.includes(:area).order(abbreviation: :asc)
crs = Classroom.all.includes(:school).order(abbreviation: :asc)
orgs = Organization.all.order(name: :asc).order(abbreviation: :asc)
tgs = TutorGroup.all.includes(:organization).order(abbreviation: :asc)
when (orgs = organizations.includes(:tutor_groups).order(abbreviation: :asc).with_reporting_rights).any?
tgs = orgs.map{ |organization| organization.tutor_groups.order(abbreviation: :asc) }.flatten
when (tgs = tutor_groups.order(abbreviation: :asc).with_reporting_rights).any?
when (dis = districts.includes(:areas, :schools, :classrooms).order(abbreviation: :asc).with_reporting_rights).any?
ars = dis.map{ |district| district.areas.order(abbreviation: :asc) }.flatten
scs = dis.map{ |district| district.schools.order(abbreviation: :asc) }.flatten
crs = dis.map{ |district| district.classrooms.order(abbreviation: :asc) }.flatten
when (ars = areas.includes(:schools, :classrooms).order(abbreviation: :asc).with_reporting_rights).any?
scs = ars.map{ |area| area.schools.order(abbreviation: :asc) }.flatten
crs = ars.map{ |area| area.classrooms.order(abbreviation: :asc) }.flatten
when (scs = schools.includes(:classrooms).order(abbreviation: :asc).with_reporting_rights).any?
crs = scs.map{ |school| school.classrooms.order(abbreviation: :asc) }.flatten
when (crs = classrooms.order(abbreviation: :asc).with_reporting_rights).any?
end
data = { districts: dis ||= [], areas: ars ||= [], schools: scs ||= [], classrooms: crs ||= [], organizations: orgs ||= [], tutor_groups: tgs ||= [] }
update_attribute(:permissions, data)
end
def highest_permission
permission = case
when staff?
{ entity: "any" }
when is?(Roles::STUDENT)
{ entity: "none" }
when permissions["organizations"].any?
{ entity: "organization", id: permissions["organizations"][0]["id"] }
when permissions["tutor_groups"].any?
{ entity: "tutor_group", id: permissions["tutor_groups"][0]["id"] }
when permissions["districts"].any?
{ entity: "district", id: permissions["districts"][0]["id"] }
when permissions["areas"].any?
{ entity: "area", id: permissions["areas"][0]["id"] }
when permissions["schools"].any?
{ entity: "school", id: permissions["schools"][0]["id"] }
when permissions["classrooms"].any?
{ entity: "classroom", id: permissions["classrooms"][0]["id"] }
else
{ entity: "none" }
end
end
def has_permission?(permission)
return true if self.staff?
permits = self.permissions[permission[:entity].pluralize]
if permits.present?
allowed_permit = permits.select{ |permit| permission[:id].to_i == permit["id"].to_i }
return allowed_permit.present?
else
return false
end
end
def pubnub_uuid
case
when staff?
"support_#{id}"
when is?(Roles::TEACHER)
"student_#{id}"
when is?(Roles::TUTOR)
"tutor_#{id}"
else
"user_#{id}"
end
end
def available_reports
if admin?
ReportTypes.allowed_for_staff
elsif is? Roles::TEACHER
ReportTypes.allowed_for_teachers
elsif is? Roles::TUTOR
ReportTypes.allowed_for_tutors
else
ReportTypes.allowed_for_tutors
end
end
def previous_classroom(school_year = SchoolYears::FALL_2014)
user_previous_classrooms.where(school_year: school_year).try(:first).try(:classroom)
end
def user_conferences
conferences.of_users
end
def oms_username
if self.is?(Roles::STUDENT)
"#{self.first_name}_#{self.id}"
else
email
end
end
def sync_create_student_on_oms
OmsCreateStudentWorker.perform_async(self.id) if self.is?(Roles::STUDENT)
end
def sync_update_student_on_oms
OmsUpdateStudentWorker.perform_async(self.id) if self.is?(Roles::STUDENT)
end
private
def update_conferences
if archived
conference_users.includes(:conference).each do |conference_user|
conference_user.destroy if conference_user.conference.conference_type == ConferenceTypes::GROUP
conference_user.conference.update_attribute(:archived, true) if conference_user.conference.conference_type == ConferenceTypes::USER
end
end
end
def set_reading_stage
if self.is?(Roles::STUDENT)
self.reading_stage = read_attribute(:reading_stage) || ReadingStages::ONE
self.reading_stage_updated_at = read_attribute(:reading_stage_updated_at) || Time.now
self.save
end
end
def tutor_registration?
!!self.tutor_registration
end
def validate_tutor_group
self.errors.add(:base, "Tutor group must be present") and return unless self.tutor_group_id.present?
tutor_group = TutorGroup.where(id: self.tutor_group_id).includes(:organization).first
organization = tutor_group.organization
return unless organization.requires_domain_validation?
email_domain = self.email.split("@").last
return if organization.domains.include?(email_domain)
self.errors.add(:base, "The email is not valid for the selected tutor group")
end
def set_oms_login
update_column(:oms_login, "#{first_name}_#{id}")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment