Last active
August 29, 2015 14:12
-
-
Save soeffing/ea811324890331bed021 to your computer and use it in GitHub Desktop.
Ad Model
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'open-uri' | |
class Ad < ActiveRecord::Base | |
# NOTE: These need to come before inclusion of CountsEntries module | |
STATES = [:uploaded, :encoded, :published, :invalid] | |
AVAILABLE_TYPES = %w(Video Print Radio Banner Concept) | |
include CountsEntries | |
include AASM | |
include ZooppaAnalytics | |
aasm_column :state | |
aasm.initial_state :uploaded | |
aasm.state :uploaded, enter: :do_upload | |
aasm.state :encoded, enter: :do_encode | |
aasm.state :published, enter: :do_publish | |
aasm.state :invalid, enter: :do_invalid | |
# Just formal event to support the 'upload!' method without a possibility to actually change the state | |
aasm.event :upload do | |
transitions to: :uploaded, from: :uploaded | |
end | |
aasm.event :encode do | |
transitions to: :encoded, from: :uploaded, guard: proc { |ad| ad.resource.is_a?(Video) } | |
end | |
aasm.event :publish do | |
transitions to: :published, from: :uploaded, guard: proc { |ad| ad.valid? && ad.resource.valid? } | |
transitions to: :published, from: :encoded, guard: proc { |ad| ad.resource.flv_encoded? && ad.resource.mp4_encoded? && ad.resource.ogg_encoded? && ad.valid? && ad.resource.valid? } | |
transitions to: :published, from: :published | |
end | |
aasm.event :invalid do | |
transitions to: :invalid, from: :encoded, guard: proc { |ad| ad.resource.is_a?(Video) } | |
transitions to: :invalid, from: :published, guard: proc { |ad| ad.resource.is_a?(Video) } | |
end | |
acts_as_url :title, url_attribute: :permalink | |
attr_accessible :title, :description, :copyright_disclaimer, :submission_agreement, | |
:user, :state, :muted, :hp_featured, :approved, | |
:facebook_upload, :new_clearance_attributes, :existing_clearance_attributes, | |
:clearance_video_author, :clearance_video_hire, :clearance_video_licensed, | |
:clearance_audio_author, :clearance_audio_hire, :clearance_audio_licensed, :clearance_audio_not_applicable, | |
:clearance_stills_author, :clearance_stills_hire, :clearance_stills_licensed, :clearance_stills_not_applicable, | |
:clearance_talent_release, :clearance_talent_not_applicable, | |
:clearance_meets_special_age_requirements, | |
:incorrect_grammar, :moderation_flags, :moderation_flags_attributes, | |
:contest_id, :display, :user_id, :resource_id, :resource_type, :recommended, :average_rating | |
attr_readonly :votes_count | |
delegate :login, :email, :platform, to: :user, prefix: true | |
delegate :country, to: 'user.profile', prefix: 'user' | |
belongs_to :resource, polymorphic: true | |
belongs_to :contest, class_name: '::Contest' | |
belongs_to :user, touch: true, class_name: '::User' | |
has_many :votes, dependent: :delete_all | |
has_many :awards, class_name: '::Award' | |
has_many :comments, dependent: :destroy | |
has_many :tickets | |
has_many :clearances, dependent: :destroy | |
has_many :moderation_flags, dependent: :destroy, class_name: 'Moderation::Flag' | |
has_many :shortlists, dependent: :destroy | |
has_many :ad_ratings, dependent: :destroy | |
has_many :my_favorites, dependent: :destroy | |
accepts_nested_attributes_for :clearances, :moderation_flags | |
validates :copyright_disclaimer, acceptance: true, on: :create, allow_nil: false | |
validates :submission_agreement, acceptance: true, on: :create, allow_nil: false, | |
if: proc { |ad| ad.contest.controlling_platform.submission_agreement.present? } | |
validates :user, :contest, :title, :description, presence: true | |
validates :title, length: { maximum: 40 } | |
validates_associated :clearances | |
before_create :set_display_flag | |
before_update :check_display_flag | |
after_create :encode_or_publish | |
after_create :upload_event_segment_com | |
after_create :create_moderation_flags | |
after_update :save_clearances | |
AVAILABLE_TYPES.each do |t| | |
scope t.downcase.pluralize.to_sym, -> { where resource_type: t } | |
end | |
scope :visible, -> { where display: true } | |
scope :from_facebook, -> { where facebook_upload: true } | |
def encode_or_publish | |
resource.is_a?(Video) ? encode! : publish! | |
user.update_seniority(contest.controlling) | |
end | |
def to_param | |
permalink | |
end | |
class << self | |
def detail(resource_type, permalink, contest_permalink, page, admin = false) | |
conditions = { resource_type: resource_type, permalink: permalink, contests: { permalink: contest_permalink } } | |
conditions.merge!(ads: { display: true, state: %w(published encoded) }) unless admin | |
ad = includes(:contest, :comments).references(:ads, :contests, :comments).find_by!(conditions) | |
comments = ad.comments.includes(:user).order('created_at DESC').paginate(page: page, per_page: 20) | |
related = ad.related(8) | |
p, n = ad.prev, ad.next | |
[ad.decorate, comments, related, p, n] | |
end | |
end | |
def update_ad_and_resource(user, params) | |
check_if_state_changed(params[:ad][:state]) if user.admin? | |
resource.update_attributes!(params[:ad][:resource]) if params[:ad][:resource].present? | |
update_attributes!(params[:ad].except(:resource)) | |
# Allow re-encoding only for published Ads | |
if resource_type == 'Video' && published? && params[:ad][:resource].present? && params[:ad][:resource][:original].present? | |
update_encoded | |
end | |
end | |
def can_be_voted?(user) | |
user && contest.opened? && user.active? && UserMiscellaneousPolicy.new(user).can_vote?(self) && !voted?(user) | |
end | |
def vote(user_id) | |
votes.find_by_user_id(user_id).rate | |
end | |
def voted?(user) | |
return false if user.nil? | |
votes.any? { |vote| vote.user_id == user.id } | |
end | |
def others | |
contest.ads.published.visible.where(resource_type: resource_type) | |
end | |
def related(n) | |
others.order('RAND()').limit(n) | |
end | |
def prev | |
others.order('created_at DESC').find_by('created_at < ?', created_at) | |
end | |
def next | |
others.order('created_at ASC').find_by('created_at > ?', created_at) | |
end | |
def position | |
index = others.order('score DESC').where(resource_type: resource_type).index(self) || 0 | |
index + 1 | |
end | |
def new_clearance_attributes=(clearance_attributes) | |
clearance_attributes = clearance_attributes.map { |k, v| v } if clearance_attributes.is_a?(Hash) | |
clearance_attributes.each do |attributes| | |
clearances.build(attributes) | |
end | |
end | |
def existing_clearance_attributes=(clearance_attributes) | |
clearances.reject(&:new_record?).each do |clearance| | |
attributes = clearance_attributes[clearance.id.to_s] | |
if attributes | |
clearance.attributes = attributes | |
else | |
clearances.delete(clearance) | |
end | |
end | |
end | |
def requires_video_clearance? | |
%w(Video).include?(resource_type) | |
end | |
def requires_audio_clearance? | |
%w(Video Radio).include?(resource_type) | |
end | |
def requires_stills_clearance? | |
%w(Video Print Banner).include?(resource_type) | |
end | |
def requires_talent_clearance? | |
%w(Video Radio Print Banner).include?(resource_type) | |
end | |
def requires_clearances? | |
requires_video_clearance? || requires_audio_clearance? || requires_stills_clearance? || requires_talent_clearance? | |
end | |
def save_clearances | |
clearances.each do |clearance| | |
clearance.save(validate: false) | |
end | |
end | |
Clearance::ASSET_TYPES.each do |type| | |
define_method "#{ type }_clearances_count" do | |
send("requires_#{ type }_clearance?") ? clearances.send(type).count : 0 | |
end | |
end | |
def check_if_state_changed(new_state) | |
return nil if state == new_state | |
case new_state | |
when 'uploaded' | |
upload! | |
when 'encoded' | |
encode! | |
when 'published' | |
publish! | |
when 'invalid' | |
invalid! | |
end | |
end | |
def update_encoded | |
# Here 'E198OGRLS9PMVD' is CloudFront dist ID for encoded | |
if Rails.env.production? && !CloudFrontInvalidator.new('E198OGRLS9PMVD').invalidate([resource.url, resource.url('ogg'), resource.url('mp4')]) | |
Rails.logger.error "[CLOUDFRONT VIDEO] Attachment invalidation failed: #{resource.original.url}" | |
end | |
do_encode | |
end | |
def path(contest_link = contest.permalink) | |
host = ApplicationConfig['host'] | |
path = "en-us/ads/#{ contest_link }/#{ resource_type.pluralize.downcase }/#{ permalink }" | |
"http://#{ host }/#{ path }" | |
end | |
def get_moderation_flag_type(type) | |
moderation_flags.find_or_initialize_by(flag_type: type) | |
end | |
def clearances_counter | |
v = 0 | |
Clearance::ASSET_TYPES.each do |type| | |
v += send("#{type}_clearances_count") | |
end | |
v | |
end | |
def update_moderation_flags(params) | |
params[:ad][:moderation_flags].each do |flag_type, value| | |
flag = Moderation::Flag.where(ad_id: self.id, flag_type: flag_type).first | |
if flag | |
flag.update_state(flag, value) | |
else | |
new_flag = Moderation::Flag.new(ad_id: self.id, user_id: self.user_id, flag_type: flag_type) | |
self.save! | |
new_flag.update_state(new_flag, value) | |
self.save! | |
end | |
end | |
end | |
def moderation_status | |
if moderation_flags.empty? | |
'under review' | |
elsif moderation_flags.any?{ |f| f.state == 'rejected' } | |
'incomplete' | |
elsif moderation_flags.all?{ |f| f.state == 'accepted' } | |
'complete' | |
else | |
'under review' | |
end | |
end | |
def moderation_status_available? | |
!moderation_flags.empty? | |
end | |
protected | |
def set_display_flag | |
self.display = false if contest.moderated? | |
nil | |
end | |
def check_display_flag | |
PublicationNotifier.new(self).perform if display_changed? && display? && contest.moderated? | |
end | |
def self.add_view!(resource_type, permalink_or_id) | |
# Flash players use ad ID while API and new video player use permalink | |
numeric = permalink_or_id.to_s =~ /^[0-9]+$/ | |
if numeric | |
ad = Ad.find_by_resource_type_and_resource_id!(resource_type, permalink_or_id) | |
else | |
ad = Ad.find_by_resource_type_and_permalink!(resource_type, permalink_or_id) | |
end | |
Ad.increment_counter(:views, ad.id) | |
end | |
private | |
def upload_event_segment_com | |
ZooppaAnalytics.upload(self.contest, self, self.user) if Rails.env.production? | |
end | |
def create_moderation_flags | |
Moderation::Flag::AVAILABLE_TYPES.each do |type| | |
Moderation::Flag.create(ad_id: self.id, user_id: self.user_id, flag_type: type) | |
end | |
end | |
def do_upload | |
UploadNotifier.new(self).perform | |
self.display = false if resource.is_a?(Video) | |
end | |
def do_encode | |
VideoEncoder.new(resource).perform | |
self.display = false | |
end | |
def do_publish | |
PublicationNotifier.new(self).perform | |
if resource.is_a?(Video) | |
self.display = !self.contest.moderated | |
end | |
end | |
def do_invalid | |
InvalidationNotifier.new(self).perform | |
self.display = false | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment