IT61/it61-rails

View on GitHub
app/models/user.rb

Summary

Maintainability
A
0 mins
Test Coverage
require "csv"

class User < ApplicationRecord
  include Gravtastic
  gravtastic
  mount_uploader :avatar, ImageUploader

  enum role: {
    member: 0,
    admin: 1,
    moderator: 2
  }

  # Devise modules
  devise :rememberable, :trackable, :omniauthable,
         omniauth_providers: [ :github, :facebook, :google_oauth2, :vkontakte ]

  has_many :events_attendees, dependent: :destroy
  has_many :social_accounts, dependent: :destroy
  has_many :owner_of_events, -> { ordered_desc }, class_name: "Event", foreign_key: "organizer_id"
  has_many :member_in_events, -> { published.ordered_desc }, class_name: "Event", through: :events_attendees, source: :event
  has_many :events, through: :events_attendees
  has_and_belongs_to_many :groups

  phony_normalize :phone, as: :normalized_phone, default_country_code: "RU"

  validates :phone, presence: true, phony_plausible: { country_code: "RU" }, if: :sms_reminders?
  validates :email, uniqueness: { allow_blank: true, case_sensitive: false }
  validates :role, presence: true

  before_save :nullify_empty_email
  before_save :downcase_email
  before_create :assign_defaults

  scope :notify_by_email, -> { where(email_reminders: true).where.not(email: nil) }
  scope :notify_by_sms, -> { where(sms_reminders: true).where.not(phone: nil) }
  scope :subscribed, -> { where(subscribed: true) }
  scope :with_email, -> { where.not(email: nil) }
  scope :active, -> { order(last_sign_in_at: :desc) }
  scope :recent, -> { order(created_at: :desc) }
  scope :with_name, -> { where("(first_name is not null and last_name is not null) or name is not null") }
  scope :presentable, -> { active.with_name.order(created_at: :desc) }
  scope :team, -> { joins(:groups).where("groups.kind = 2") }
  scope :developers, -> { joins(:groups).where("groups.kind = 1") }
  scope :organized_events, -> { joins(:events).where("organizer_id", self.id).ordered_desc }

  def self.from_omniauth!(auth)
    auth_info = auth.info
    email = auth_info.email.downcase if auth_info.email.present?
    user = User.find_or_initialize_by(email: email)

    if user.new_record?
      user.email = email
      user.name = auth_info.name
      user.first_name = auth_info.first_name
      user.last_name = auth_info.last_name
      user.remote_avatar_url = avatar_from_auth(auth)
    end

    social = SocialAccount.includes(:user).find_or_initialize_by(uid: auth.uid, provider: auth.provider)
    if social.new_record?
      social.link = SocialAccount.link_for(auth)
      user.social_accounts << social
    end

    user.save
    user
  end

  def self.avatar_from_auth(auth)
    if auth.provider == "vkontakte"
      auth.extra.raw_info.photo_400_orig
    end
  end

  def self.to_csv
    attributes = %w[last_name first_name]

    CSV.generate(headers: true) do |csv|
      csv << [ "Фамилия", "Имя", "Отметка" ]

      all.each do |user|
        csv << attributes.map { |attr| user.send(attr) }
      end
    end
  end

  def add_social(auth)
    SocialAccount.from_omniauth(auth, self)
  end

  def display_name
    if first_name.presence
      first_name
    else
      full_name
    end
  end

  def full_name
    [ first_name, last_name ].compact.join(" ").presence || name
  end

  def remember_me
    true
  end

  def subscribe!
    self.subscribed = true
    save!
  end

  def has_events?
    not (member_in_events.empty? && owner_of_events.empty?)
  end

  def can_fill_entry_form?(event)
    event.has_closed_registration? || event.user_participated?(self)
  end

  def update_with_fresh(params)
    assign_attributes(params)
    if fresh_fields_present?
      self.fresh = false
      save
    else
      false
    end
  end

  def linked_social_accounts
    social_accounts.filter do |social_account|
      Devise.omniauth_providers.include?(social_account.provider.to_sym)
    end
  end

  def unlinked_social_providers
    Devise.omniauth_providers.map(&:to_s) - linked_social_accounts.map(&:provider)
  end

  private

  def assign_defaults
    self.role ||= 0
    self.email_reminders ||= false
    self.sms_reminders ||= false
    self.subscribed ||= false
  end

  def nullify_empty_email
    self.email = nil unless email.present?
  end

  def downcase_email
    self.email = email.downcase if email.present?
  end

  def fresh_fields_present?
    email.present? && first_name.present? && last_name.present?
  end
end