Skip to content

Instantly share code, notes, and snippets.

@soeffing
Last active August 29, 2015 13:56
Show Gist options
  • Save soeffing/9276483 to your computer and use it in GitHub Desktop.
Save soeffing/9276483 to your computer and use it in GitHub Desktop.
Pretty Model
module Legacy
class User < ActiveRecord::Base
# Constants
SENIORITY = {
0 => 'fan',
1 => 'novice',
2 => 'creative',
3 => 'senior',
4 => 'pro'
}
SENIORITY_TO_STARS = { 0 => 5, 1 => 5, 2 => 10, 3 => 15, 4 => 20 }
SKILLS = [ "director", "writer", "editor", "cinematographer", "producer", "motion_graphics", "animator", "audio_engineer", "musician", "composer", "actor", "voice_talent", "fx_specialist", "lighting", "graphic_design" ]
SKILLS_MAX = 4
WORK_EXPERIENCE_ITEM = { 'start_month' => Time.now.month, 'start_year' => Time.now.year, 'end_month' => Time.now.month, 'end_year' => 0,
'role' => "", 'project_or_client_name' => "", 'url' => "" }
WORK_EXPERIENCE_MAX = 5
EDUCATION_ITEM = { 'start_year' => Time.now.year, 'end_year' => 0, 'school_name' => "", 'degree' => "", 'url' => "" }
EDUCATION_MAX = 5
CONNECT_LINKS = %w(email facebook linkedin twitter vimeo youtube tumblr behance)
CONNECT_LINK_ITEM = { 'value' => '', 'selected' => 0 }
CONNECT_LINKS_MAX = 5
CLIENTS_MAX = 5
ENCODING_VIDEOS_JOBS_MAX = 15
ENCODING_VIDEOS_JOBS_PER_UPLOAD = 3
BLACK_LIST = %w!activate ads application atom bank banners blog blog_posts change_password comments community concepts contests convert corporate dashboard edit forum home platform invite login logout monitor myzooppa news ping prints awards radios sessions signup users videos votes works!
JOIN_ATTRIBUTES = %w!first_name last_name address zip_code country province city!
devise :database_authenticatable, :registerable, :trackable, :omniauthable, :recoverable,
:rememberable, :confirmable, :validatable, :encryptable, encryptor: :restful_authentication_sha1
# Assignments and serialization
attr_accessible :login, :email, :secondary_email, :password, :password_confirmation, :privacy, :newsletter, :platform, :time_zome,
:wants_private_messages, :first_name, :last_name, :birthdate, :url, :about_me, :address, :city, :province, :zip_code, :country, :avatar,
:gender, :third_party_privacy, :birth_year, :coupons, :att_customer, :facebook_user_id, :promo_code,
:updated_it_terms_acceptance, :partner_id, :skills, :display_full_name, :display_location, :display_total_awards, :connect_links,
:work_experience, :education, :clients, :use_custom_featured_work, :phone_number, :encoding_videos_jobs_count, :phone_country_code,
:phone_area_code, :client_account, :tax_tin_number, :tax_tin_type, :whitelabel
serialize :coupons
serialize :att_customer
serialize :skills
serialize :work_experience
serialize :education
serialize :clients
serialize :connect_links, Hash
# Relations
belongs_to :partner, counter_cache: true
has_many :votes, dependent: :destroy
has_many :contests, through: :ads
has_many :awards, through: :ads, class_name: '::Award'
has_many :following_as_follower, foreign_key: :follower_id, class_name: 'Following'
has_many :following_as_followed, foreign_key: :followed_id, class_name: 'Following'
has_many :followed, through: :following_as_follower, source: :followed, conditions: { state: 'active' }
has_many :followers, through: :following_as_followed, source: :follower, conditions: { state: 'active' }
has_many :ads
has_many :ip_traces
has_many :comments, dependent: :destroy
has_many :posts, dependent: :destroy
has_many :money_transactions
has_many :transaction_points, class_name: 'MoneyTransaction', conditions: ['amount > 0']
has_many :transaction_transfers, class_name: 'MoneyTransaction', conditions: ['amount < 0']
has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner
has_many :user_downloads
has_many :downloads, through: :user_downloads, conditions: "file_type IS NOT NULL"
has_many :project_acceptances, through: :user_downloads, conditions: "file_type IS NULL"
has_many :service_authentications, dependent: :destroy
has_many :docusign_tax_forms, order: 'created_at DESC'
has_many :offline_tax_forms, order: 'created_at DESC'
has_one :featured_video, dependent: :destroy
has_many :user_ndas
has_many :accepted_ndas, through: :user_ndas, source: :contest
# Callbacks
before_validation :set_time_zone
# before_validation :assign_default_platform, on: :create
before_save :check_for_changed_partner
after_create :assign_featured_video
after_save :send_email_changed_notification
#Validations
validates_acceptance_of :privacy, accept: true, allow_nil: false, on: :create
validates_presence_of :platform, :state, :login
validates_length_of :password, within: 4..40, if: :password_required?
validates_length_of :login, within: 3..25
validates_uniqueness_of :login #, case_sensitive: false
validates_format_of :login, with: %r{^[\w\d][\w\d\-]+?[\w\d]$}i, allow_blank: false
validates_exclusion_of :login, in: BLACK_LIST
validates_inclusion_of :gender, in: [ "", "male", "female" ], allow_blank: true
validates_format_of :email, with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, allow_blank: true
validates_uniqueness_of :email, case_sensitive: true
validates_format_of :url, with: %r{^(http|https)://.+$}i, allow_blank: true
validates_uniqueness_of :facebook_user_id, if: Proc.new { |u| !u.facebook_user_id.blank? }
validate :disposable_email, :skills_validation, :display_full_name_validation,
:connect_links_validation, :clients_validation,
:work_experience_validation, :education_validation, :encoding_videos_jobs_count_validation, if: Proc.new {|u| !u.has_attribute?(:whitelabel) }
validate :check_legal_age, on: :create, if: :birth_year?
acts_as_url :login, url_attribute: :permalink, sync_url: true
# Attachments
has_attached_file :avatar,
styles: { thumb: [ "50x50#", :jpg ], detail: [ "100x100#", :jpg ], original: [ "200x200#", :jpg ] },
storage: :s3,
path: ':attachment/:id/:timestamp_:style.:extension',
s3_credentials: open( "#{Rails.root}/config/aws.yml", 'r' ),
s3_permissions: 'public-read',
s3_protocol: 'http',
url: ':s3_alias_url',
s3_host_alias: S3Buckets[:users][:url],
bucket: S3Buckets[:users][:bucket],
default_url: '/assets/missing/users/:style.png',
s3_headers: { 'Expires' => 10.year.from_now.httpdate }
# Scopes
scope :active, where(state: 'active')
scope :by_platform, lambda { |platform| where(platform: platform) unless platform.nil? }
def complete_name
"#{ first_name } #{ last_name }"
end
def display_name
( display_full_name? and first_name.present? and last_name.present? ) ? complete_name : login
end
def set_attributes(attributes, requester)
if requester.admin?
self.assign_attributes(attributes, without_protection: true)
elsif requester.id == self.id
self.attributes = attributes
end
end
def can_join_contest?( contest )
contest.open_for_uploads? && ( contest.coupon.blank? || coupons.include?( contest.coupon ) )
end
def contactable?( other_user )
wants_private_messages? && active? && followed_ids.include?( other_user.id )
end
def can_send_messages?( other_user )
wants_private_messages? && other_user.contactable?( self )
end
def can_vote?( ad )
ad.contest.wants_votes? && (ad.contest.coupon.blank? || coupons.include?(ad.contest.coupon))
end
def can_comment_contest?(contest)
contest.wants_comments? && (contest.coupon.blank? || coupons.include?(contest.coupon))
end
def skills
read_attribute( :skills ) || [ ]
end
def make_activation_code(field)
self.update_attribute(field, Digest::SHA1.hexdigest(Time.now.to_s.split(//).sort_by {rand}.join))
end
def change_email!
self.email = self.secondary_email
self.update_attribute(:secondary_email, nil)
self.email_activation_code = nil
save!
end
def stars(code = nil)
SENIORITY_TO_STARS.keys.each do |seniority_range|
if respond_to?("seniority_#{ code }") && seniority_range == self.send("seniority_#{ code }").to_i
return SENIORITY_TO_STARS[seniority_range]
end
end
return 5
end
def stars_for_ad(ad)
stars_array = []
ad.contest.platforms.each do |platform|
stars_array << self.stars(platform.code)
end
stars_array.max
end
def password_required?
(service_authentications.empty? || !password.blank?) && super
end
def service_authentication_with(provider)
service_authentications.find_by_provider(provider)
end
def role
if admin?
'zooppa_administrator'
else
'zooppa_user'
end
end
def seniority_level(platform)
return 5 if admin?
self.send("seniority_#{ platform }") rescue 0
end
# OPTIMIZE This should be in a helper
def seniority_name(seniority_level = nil)
case seniority_level
when 0, nil
I18n.t( 'seniority.fan' )
when 1
I18n.t( 'seniority.novice' )
when 2
I18n.t( 'seniority.creative' )
when 3
I18n.t( 'seniority.senior' )
when 4
I18n.t( 'seniority.pro' )
when 5
I18n.t( 'seniority.zooppa' )
end
end
def calculate_seniority(platform)
contests_count = contests.count(joins: :platforms, conditions: ['platforms.code = ?', platform])
early_or_client_awards_count = awards.count(joins: { contest: :platforms },
conditions: ["(awards.award_type = 'early_entry' OR awards.award_type = 'client') AND platforms.code = ?", platform])
awards_count = awards.count(joins: { contest: :platforms }, conditions: ["platforms.code = ?", platform])
# $15,000 or more in awards or 6+ (Client or Early Entry) awards => Pro
if (points >= 15000 || early_or_client_awards_count >= 6)
seniority = 4
# 3+ (Client or Early Entry) awards => Senior
elsif (early_or_client_awards_count >= 3)
seniority = 3
# 1+ Awards of any type or 1+ Submission to 10+ contests => Creative
elsif (awards_count > 0 || contests_count >= 10)
seniority = 2
# 1+ Contest upload of any type => Novice
elsif (contests_count > 0)
seniority = 1
# Nothing => Fan
else
seniority = 0
end
seniority
end
def update_seniority(platform)
previous = self.send("seniority_#{ platform }") || 0
seniority = calculate_seniority(platform)
if seniority != previous
self.send("seniority_#{ platform }=", seniority)
self.save(validate: false)
end
end
def purified_url
url.gsub(/^(http|https|ftp):\/\/(www\.)*/, '')
end
def profile_completion
total = 0
total += 10 if skills.present?
total += 10 if first_name.present? and last_name.present?
total += 10 if address.present? and city.present? and province.present? and zip_code.present? and country.present?
total += 10 if url.present?
total += 20 if partner_id.present?
total += 10 if any_connect_links_provided?
total += 10 if work_experience.present?
total += 10 if work_experience.present?
total += 10 if avatar_file_name.present?
total
end
def profile_completion_suggestions
suggestions = []
suggestions.push(
I18n.t('users.suggestions.skills')
) if skills.blank?
suggestions.push(
I18n.t('users.suggestions.full_name')
) if first_name.blank? || last_name.blank?
suggestions.push(
I18n.t('users.suggestions.address')
) if address.blank? || city.blank? || province.blank? || zip_code.blank? || country.blank?
suggestions.push(
I18n.t('users.suggestions.url')
) if url.blank?
suggestions.push(
I18n.t('users.suggestions.partner')
) if partner_id.blank?
suggestions.push(
I18n.t('users.suggestions.connect')
) unless any_connect_links_provided?
suggestions.push(
I18n.t('users.suggestions.work_experience')
) if work_experience.blank?
suggestions.push(
I18n.t('users.suggestions.education')
) if education.blank?
suggestions.push(
I18n.t('users.suggestions.avatar')
) if avatar_file_name.blank?
suggestions
end
def location
location_array = []
location_array.push( city ) if city.present?
location_array.push( province ) if province.present?
location_array.push( I18n.t( country, scope: 'countries' ) ) if country.present?
# Replacing country with country code if too long
location_array[2] = country if location_array.join( ', ' ).size > 40
# Removing province if still too long
location_array.delete_at(1) if location_array.join( ', ' ).size > 40
location_array.join( ', ' )
end
def connect_links
connect_links_hash = read_attribute( :connect_links ) || default_connect_links
connect_links_ordered_hash = ActiveSupport::OrderedHash.new
CONNECT_LINKS.each do |key|
connect_links_ordered_hash[ key ] = connect_links_hash[ key ]
end
connect_links_ordered_hash
end
def default_connect_links
connect_links_hash = {}
CONNECT_LINKS.each do |name|
connect_links_hash[ name ] = CONNECT_LINK_ITEM
end
connect_links_hash
end
def selected_connect_links
connect_links_hash = {}
connect_links.collect do |name, val|
connect_links_hash[ name ] = val if val && val['selected'].to_i == 1
end
connect_links_hash
end
def any_connect_links_provided?
selected_connect_links.present?
end
def all_connect_links_provided?
selected_connect_links.size == connect_links.size
end
def phone_country_number
Country.new(@user.phone_country_code).country_code
rescue
nil
end
def credits(refresh = false)
refresh ? ( money_transactions.sum( :amount ).to_i ) : read_attribute( :credits )
end
def points(refresh = false)
refresh ? (transaction_points.sum( :amount ).to_i ) : read_attribute( :points )
end
def total_transferred(refresh = false)
if refresh
transaction_transfers.sum(:amount).to_i.abs
else
read_attribute(:total_transferred).blank? ? 0 : read_attribute(:total_transferred)
end
end
def update_credits
update_attribute :credits, credits( true )
end
def update_points
update_attribute :points, points( true )
end
def update_money_transfers
m = total_transferred(true)
update_attribute( :total_transferred, m ) if m
end
def check_legal_age
legal_age = birth_year.to_i > Date.today.year - ApplicationConfig['legal_age'][platform]
errors.add(:base, :birth_year) if legal_age
end
def can_join?
active? && completed_fields?( JOIN_ATTRIBUTES )
end
protected
def self.by_permalink( login, options = {}, current_user = nil )
find_by_permalink!( login, {conditions: ['state = "active"' ]}.merge( options ) )
end
def completed_fields?( fields )
!fields.any? { |field| self[ field ].blank? }
end
def should_change_email?(other)
!other.blank? && other != email && other =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
end
def assign_featured_video
new_video = FeaturedVideo.new
new_video.user = self
new_video.save
end
private
def disposable_email
if self.new_record?
errors.add(:base, :disposable_email) if (self.email && self.email[/@.*$/] && DisposableEmails['providers'].include?(self.email[/@.*$/][1..-1]))
end
end
def set_time_zone
case self.platform
when 'it'
self.time_zone = 'Rome'
when 'eu'
self.time_zone = 'London'
else
self.time_zone = 'Pacific Time (US & Canada)'
end
end
def skills_validation
if skills.size > SKILLS_MAX
errors.add :skills, I18n.t('validation.user.skills.max_length', count: SKILLS_MAX)
end
end
def display_full_name_validation
if display_full_name? and ( first_name.blank? or last_name.blank? )
errors.add :display_full_name, "You must fill out the first and last name fields in order to display your full name in your profile."
end
end
def connect_links_validation
if selected_connect_links.size > CONNECT_LINKS_MAX
errors.add :connect_links, I18n.t('validation.user.connect_links.max_length', count: CONNECT_LINKS_MAX)
end
end
def clients_validation
if clients.size > CLIENTS_MAX
errors.add :clients, I18n.t('validation.user.clients.max_length', count: CLIENTS_MAX)
end
end
def work_experience_validation
if work_experience.size > WORK_EXPERIENCE_MAX
errors.add :work_experience, I18n.t('validation.user.work_experience.max_length', count: WORK_EXPERIENCE_MAX)
end
end
def education_validation
if education.size > EDUCATION_MAX
errors.add :education, I18n.t('validation.user.education.max_length', count: EDUCATION_MAX)
end
end
def encoding_videos_jobs_count_validation
if ApplicationConfig[ 'video_upload' ][ 'limitation' ] and encoding_videos_jobs_count > ENCODING_VIDEOS_JOBS_MAX
errors.add :encoding_videos_jobs_count, I18n.t('validation.user.encoding_videos_jobs_count.max_length', count: ENCODING_VIDEOS_JOBS_MAX)
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment