2014-03-26 11:09:39 +00:00
|
|
|
# == Schema Information
|
|
|
|
#
|
|
|
|
# Table name: challenges
|
|
|
|
#
|
|
|
|
# id :integer not null, primary key
|
|
|
|
# contester1_id :integer
|
|
|
|
# contester2_id :integer
|
|
|
|
# match_time :datetime
|
|
|
|
# default_time :datetime
|
|
|
|
# mandatory :boolean
|
|
|
|
# server_id :integer
|
|
|
|
# user_id :integer
|
|
|
|
# details :string(255)
|
|
|
|
# response :string(255)
|
|
|
|
# created_at :datetime
|
|
|
|
# updated_at :datetime
|
|
|
|
# map1_id :string(255)
|
|
|
|
# map2_id :string(255)
|
|
|
|
# status :integer default(0), not null
|
|
|
|
#
|
|
|
|
|
2014-03-23 00:22:25 +00:00
|
|
|
class Challenge < ActiveRecord::Base
|
|
|
|
include Extra
|
|
|
|
|
|
|
|
STATUS_PENDING = 0
|
|
|
|
STATUS_ACCEPTED = 1
|
|
|
|
STATUS_DEFAULT = 2
|
|
|
|
STATUS_FORFEIT = 3
|
|
|
|
STATUS_DECLINED = 4
|
|
|
|
AUTO_DEFAULT_TIME = 10800 # Normal default time: 3 hours
|
|
|
|
CHALLENGE_BEFORE_MANDATORY = 432000 # Min. time threshold for mandatory matches: 5 days
|
|
|
|
CHALLENGE_BEFORE_VOLUNTARY = 900 # Min. time threshold for voluntary matches: 15 mins
|
|
|
|
ACCEPT_BEFORE_MANDATORY = 86400 # Time to accept before mandatory match time: 1 day
|
|
|
|
ACCEPT_BEFORE_VOLUNTARY = 300 # Time to accept before voluntary match time: 5 mins
|
|
|
|
MATCH_LENGTH = 7200 # Usual match length (for servers): 2 hours
|
|
|
|
|
|
|
|
attr_protected :id, :updated_at, :created_at, :default_time, :user_id, :status
|
|
|
|
|
|
|
|
validates_presence_of :contester1, :contester2, :server, :map1
|
|
|
|
validates_presence_of :map2, :on => :update
|
|
|
|
#validates_datetime :match_time, :default_time
|
|
|
|
#validates_length_of [:details, :response], :maximum => 255, :allow_blank => true, :allow_nil => true
|
|
|
|
#validate_on_create:validate_teams
|
|
|
|
#validate_on_create:validate_contest
|
|
|
|
#validate_on_create:validate_mandatory
|
|
|
|
#validate_on_create:validate_match_time
|
|
|
|
#validate_on_create:validate_server
|
|
|
|
#validate_on_create:validate_map1
|
|
|
|
#validate_on_update :validate_map2
|
|
|
|
#validate_on_update :validate_status
|
|
|
|
|
|
|
|
scope :of_contester,
|
|
|
|
lambda { |contester| {:conditions => ["contester1_id = ? OR contester2_id = ?", contester.id, contester.id]} }
|
|
|
|
scope :within_time,
|
|
|
|
lambda { |from, to| {:conditions => ["match_time > ? AND match_time < ?", from.utc, to.utc]} }
|
|
|
|
scope :around,
|
|
|
|
lambda { |time| {:conditions => ["match_time > ? AND match_time < ?", time.ago(MATCH_LENGTH).utc, time.ago(-MATCH_LENGTH).utc]} }
|
|
|
|
scope :on_week,
|
|
|
|
lambda { |time| {:conditions => ["match_time > ? and match_time < ?", time.beginning_of_week, time.end_of_week]} }
|
|
|
|
scope :pending, :conditions => {:status => STATUS_PENDING}
|
|
|
|
scope :mandatory, :conditions => {:mandatory => true}
|
|
|
|
scope :future, :conditions => "match_time > UTC_TIMESTAMP()"
|
|
|
|
scope :past, :conditions => "match_time < UTC_TIMESTAMP()"
|
|
|
|
|
|
|
|
has_one :match
|
|
|
|
belongs_to :map1, :class_name => "Map"
|
|
|
|
belongs_to :map2, :class_name => "Map"
|
|
|
|
belongs_to :user
|
|
|
|
belongs_to :server
|
|
|
|
belongs_to :contester1, :class_name => "Contester", :include => 'team'
|
|
|
|
belongs_to :contester2, :class_name => "Contester", :include => 'team'
|
|
|
|
|
|
|
|
def statuses
|
|
|
|
{STATUS_PENDING => "Pending response",
|
|
|
|
STATUS_ACCEPTED => "Accepted",
|
|
|
|
STATUS_DEFAULT => "Default Time",
|
|
|
|
STATUS_FORFEIT => "Forfeited",
|
|
|
|
STATUS_DECLINED => "Declined"}
|
|
|
|
end
|
|
|
|
|
|
|
|
def autodefault
|
|
|
|
match_time - (mandatory ? ACCEPT_BEFORE_MANDATORY : ACCEPT_BEFORE_VOLUNTARY)
|
|
|
|
end
|
|
|
|
|
|
|
|
def get_margin
|
|
|
|
mandatory ? CHALLENGE_BEFORE_MANDATORY : CHALLENGE_BEFORE_VOLUNTARY
|
|
|
|
end
|
|
|
|
|
|
|
|
def get_deadline
|
|
|
|
mandatory ? ACCEPT_BEFORE_MANDATORY : ACCEPT_BEFORE_VOLUNTARY
|
|
|
|
end
|
|
|
|
|
|
|
|
def get_contester1
|
|
|
|
self.contester1 = user.active_contesters.of_contest(contester2.contest).first
|
|
|
|
end
|
|
|
|
|
|
|
|
def before_validation_on_create
|
|
|
|
self.status = STATUS_PENDING
|
|
|
|
self.default_time = match_time.end_of_week.change \
|
|
|
|
:hour => contester1.contest.default_time.hour,
|
|
|
|
:minute => contester1.contest.default_time.strftime("%M").to_i
|
|
|
|
end
|
|
|
|
|
|
|
|
def after_create
|
|
|
|
contester2.team.teamers.active.leaders.each do |teamer|
|
|
|
|
if teamer.user.profile.notify_pms
|
|
|
|
Notifications.challenge teamer.user, self
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def validate_teams
|
|
|
|
if contester1.team == contester2.team
|
|
|
|
errors.add_to_base I18n.t(:challenges_yourself)
|
|
|
|
end
|
|
|
|
if contester1.contest != contester2.contest
|
|
|
|
errors.add_to_base I18n.t(:challenges_opponent_contest)
|
|
|
|
end
|
|
|
|
if !contester2.active or !contester2.team.active
|
|
|
|
errors.add_to_base I18n.t(:challenges_opponent_inactive)
|
|
|
|
end
|
|
|
|
if !contester1.active or !contester1.team.active
|
|
|
|
errors.add_to_base I18n.t(:challenges_inactive)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def validate_contest
|
|
|
|
if contester1.contest.end.past? or contester1.contest.status == Contest::STATUS_CLOSED
|
|
|
|
errors.add_to_base I18n.t(:contests_closed)
|
|
|
|
end
|
|
|
|
if contester1.contest.contest_type != Contest::TYPE_LADDER and !match
|
|
|
|
errors.add_to_base I18n.t(:contests_notladder)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def validate_mandatory
|
|
|
|
return unless mandatory
|
|
|
|
|
|
|
|
if contester2.score < contester1.score
|
|
|
|
errors.add_to_base I18n.t(:challenges_mandatory)
|
|
|
|
end
|
|
|
|
if Challenge.pending.count(:conditions => \
|
|
|
|
["contester1_id = ? AND contester2_id = ? AND mandatory = true AND default_time < UTC_TIMESTAMP()",
|
|
|
|
contester1.id, contester2.id]) > 0
|
|
|
|
errors.add_to_base I18n.t(:challenges_mandatory_handled)
|
|
|
|
end
|
|
|
|
if Match.of_contester(contester2).on_week(match_time).count > 0
|
|
|
|
errors.add_to_base I18n.t(:challenges_opponent_week)
|
|
|
|
end
|
|
|
|
if Challenge.of_contester(contester2).mandatory.on_week(match_time).count > 0
|
|
|
|
errors.add_to_base I18n.t(:challenges_opponent_mandatory_week)
|
|
|
|
end
|
|
|
|
if Challenge.of_contester(contester2).mandatory.on_week(default_time).count > 0
|
|
|
|
errors.add_to_base I18n.t(:challenges_opponent_mandatory_week_defaulttime)
|
|
|
|
end
|
|
|
|
if Match.of_contester(contester2).around(default_time).count > 0
|
|
|
|
errors.add_to_base I18n.t(:challenges_opponent_defaulttime)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def validate_match_time
|
|
|
|
if (match_time-get_margin).past?
|
|
|
|
if get_margin > 86400
|
|
|
|
errors.add_to_base I18n.t(:matches_time1) + get_margin / 60 / 60 / 24 + I18n.t(:matches_time2)
|
|
|
|
else
|
|
|
|
errors.add_to_base I18n.t(:matches_time1) + get_margin / 60 + I18n.t(:matches_time3)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if Challenge.of_contester(contester2).around(match_time).pending.count > 0
|
|
|
|
errors.add_to_base I18n.t(:challenges_opponent_specifictime)
|
|
|
|
end
|
|
|
|
if Match.of_contester(contester2).around(match_time).count > 0
|
|
|
|
errors.add_to_base I18n.t(:challenges_opponent_match_specifictime)
|
|
|
|
end
|
|
|
|
if match_time > contester1.contest.end
|
|
|
|
errors.add_to_base I18n.t(:contests_end)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def validate_server
|
|
|
|
unless server and server.official
|
|
|
|
errors.add_to_base I18n.t(:servers_notavailable)
|
|
|
|
end
|
|
|
|
unless server.is_free match_time
|
|
|
|
errors.add_to_base I18n.t(:servers_notfree_specifictime)
|
|
|
|
end
|
|
|
|
if !server.is_free default_time
|
|
|
|
errors.add_to_base I18n.t(:servers_notfree_defaulttime)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def validate_map1
|
|
|
|
unless contester1.contest.maps.exists?(map1)
|
|
|
|
errors.add_to_base I18n.t(:contests_map_notavailable)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def validate_map2
|
|
|
|
unless contester2.contest.maps.exists?(map2)
|
|
|
|
errors.add_to_base I18n.t(:contests_map_notavailable)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def validate_status
|
|
|
|
if mandatory and ![STATUS_ACCEPTED, STATUS_DEFAULT, STATUS_FORFEIT].include? status
|
|
|
|
errors.add_to_base I18n.t(:challenges_mandatory_invalidresult)
|
|
|
|
end
|
|
|
|
unless statuses.include? status
|
|
|
|
errors.add_to_base I18n.t(:challenges_mandatory_invalidresult)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def after_update
|
|
|
|
if status_changed?
|
|
|
|
if status == STATUS_ACCEPTED
|
|
|
|
make_match.save
|
|
|
|
elsif status == STATUS_DEFAULT
|
|
|
|
m = make_match
|
|
|
|
m.match_time = default_time
|
|
|
|
m.save
|
|
|
|
elsif status == STATUS_FORFEIT
|
|
|
|
m = make_match
|
|
|
|
m.forfeit = true
|
|
|
|
m.score1 = 4
|
|
|
|
m.score2 = 0
|
|
|
|
m.match_time = default_time
|
|
|
|
m.save
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def make_match
|
|
|
|
match = Match.new
|
|
|
|
match.contester1 = contester1
|
|
|
|
match.contester2 = contester2
|
|
|
|
match.map1 = map1
|
|
|
|
match.map2 = map2
|
|
|
|
match.contest = contester1.contest
|
|
|
|
match.challenge = self
|
|
|
|
match.server = server
|
|
|
|
match.match_time = match_time
|
|
|
|
match
|
|
|
|
end
|
|
|
|
|
|
|
|
def can_create? cuser
|
|
|
|
return false unless cuser
|
|
|
|
return false if cuser.banned?(Ban::TYPE_LEAGUE)
|
|
|
|
validate_teams
|
|
|
|
validate_contest
|
|
|
|
true if (contester1.team.is_leader?(cuser) or cuser.admin?) and errors.size == 0
|
|
|
|
end
|
|
|
|
|
|
|
|
def can_update? cuser
|
|
|
|
cuser and (contester2.team.is_leader? cuser or cuser.admin?) and status == STATUS_PENDING and autodefault.future?
|
|
|
|
end
|
|
|
|
|
|
|
|
def can_destroy? cuser
|
|
|
|
cuser and (contester1.team.is_leader? cuser or cuser.admin?) and status == STATUS_PENDING and autodefault.future?
|
|
|
|
end
|
|
|
|
end
|