1
0
mirror of https://github.com/jcwimer/wrestlingApp synced 2026-04-13 16:40:48 +00:00

Merge pull request #6 from jcwimer/development

Development Merge
This commit is contained in:
2017-01-18 09:23:26 -05:00
committed by GitHub
109 changed files with 6902 additions and 954 deletions

3
.dockerignore Normal file
View File

@@ -0,0 +1,3 @@
.git
frontend/node_modules
log

1
.gitignore vendored
View File

@@ -16,3 +16,4 @@
/tmp /tmp
.rvmrc .rvmrc
/deploy/prod.env /deploy/prod.env
frontend/node_modules

View File

@@ -56,7 +56,9 @@ gem 'spring', :group => :development
gem 'delayed_job_active_record' gem 'delayed_job_active_record'
gem 'puma' gem 'puma'
gem 'brakeman' gem 'brakeman'
gem 'rails-lineman'
group :development do group :development do
#gem 'bullet' #gem 'bullet'
end end

View File

@@ -131,6 +131,8 @@ GEM
rails-deprecated_sanitizer (>= 1.0.1) rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.2) rails-html-sanitizer (1.0.2)
loofah (~> 2.0) loofah (~> 2.0)
rails-lineman (0.3.0)
rake
rails_12factor (0.0.3) rails_12factor (0.0.3)
rails_serve_static_assets rails_serve_static_assets
rails_stdout_logging rails_stdout_logging
@@ -207,6 +209,7 @@ DEPENDENCIES
passenger passenger
puma puma
rails (= 4.2.5) rails (= 4.2.5)
rails-lineman
rails_12factor rails_12factor
rb-readline rb-readline
round_robin_tournament round_robin_tournament
@@ -217,5 +220,8 @@ DEPENDENCIES
turbolinks turbolinks
uglifier (>= 1.3.0) uglifier (>= 1.3.0)
RUBY VERSION
ruby 2.3.0p0
BUNDLED WITH BUNDLED WITH
1.11.2 1.13.5

View File

@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View File

@@ -0,0 +1,4 @@
/*
Place all the styles related to the matching controller here.
They will automatically be included in application.css.
*/

View File

@@ -0,0 +1,28 @@
class ApiController < ApplicationController
protect_from_forgery with: :null_session
def index
end
def tournaments
if params[:search]
@tournaments = Tournament.search(params[:search]).order("created_at DESC")
else
@tournaments = Tournament.all.sort_by{|t| t.daysUntil}.first(20)
end
end
def tournament
@tournament = Tournament.where(:id => params[:tournament]).includes(:schools,:weights,:mats,:matches,:user,:wrestlers).first
end
def newTournament
@tournament = Tournament.new(JSON.parse(params[:tournament]))
@tournament.save
end
def currentUserTournaments
@tournaments = current_user.tournaments
end
end

View File

@@ -3,8 +3,21 @@ class ApplicationController < ActionController::Base
# For APIs, you may want to use :null_session instead. # For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception protect_from_forgery with: :exception
after_filter :set_csrf_cookie_for_ng
def set_csrf_cookie_for_ng
cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
end
rescue_from CanCan::AccessDenied do |exception| rescue_from CanCan::AccessDenied do |exception|
# flash[:error] = "Access denied!" # flash[:error] = "Access denied!"
redirect_to '/static_pages/not_allowed' redirect_to '/static_pages/not_allowed'
end end
protected
# In Rails 4.2 and above
def verified_request?
super || valid_authenticity_token?(session, request.headers['X-XSRF-TOKEN'])
end
end end

View File

@@ -163,7 +163,7 @@ class TournamentsController < ApplicationController
end end
def generate_matches def generate_matches
@tournament.generateMatchups GenerateTournamentMatches.new(@tournament).generate
end end
def brackets def brackets

View File

@@ -1,6 +1,6 @@
class WeightsController < ApplicationController class WeightsController < ApplicationController
before_action :set_weight, only: [:show, :edit, :update, :destroy] before_action :set_weight, only: [:show, :edit, :update, :destroy,:re_gen]
before_filter :check_access, only: [:new,:create,:update,:destroy,:edit] before_filter :check_access, only: [:new,:create,:update,:destroy,:edit, :re_gen]
# GET /weights/1 # GET /weights/1
@@ -70,6 +70,11 @@ class WeightsController < ApplicationController
end end
end end
def re_gen
@tournament = @weight.tournament
GenerateTournamentMatches.new(@tournament).generateWeight(@weight)
end
private private
# Use callbacks to share common setup or constraints between actions. # Use callbacks to share common setup or constraints between actions.
def set_weight def set_weight

View File

@@ -31,6 +31,7 @@ class WrestlersController < ApplicationController
def edit def edit
@weight = @wrestler.weight @weight = @wrestler.weight
@weights = @school.tournament.weights.sort_by{|w| w.max} @weights = @school.tournament.weights.sort_by{|w| w.max}
@school = @wrestler.school
end end
# POST /wrestlers # POST /wrestlers

View File

@@ -0,0 +1,2 @@
module ApiHelper
end

View File

@@ -1,62 +0,0 @@
module GeneratesTournamentMatches
def generateMatchups
self.curently_generating_matches = 1
self.save
resetSchoolScores
setSeedsAndRandomSeedingWrestlersWithoutSeeds
poolToBracket() if tournament_type == "Pool to bracket"
self.curently_generating_matches = nil
self.save
matches
end
if Rails.env.production?
handle_asynchronously :generateMatchups
end
def poolToBracket
destroyAllMatches
buildTournamentWeights
generateMatches
# This is not working for pool order and I cannot get tests working
movePoolSeedsToFinalPoolRound
end
def buildTournamentWeights
weights.order(:max).each do |weight|
Pool.new(weight).generatePools()
last_match = matches.where(weight: weight).order(round: :desc).limit(1).first
highest_round = last_match.round
PoolBracket.new(weight, highest_round).generateBracketMatches()
end
end
def generateMatches
moveFinalsMatchesToLastRound
assignBouts
assignLoserNames
assignFirstMatchesToMats
end
def moveFinalsMatchesToLastRound
finalsRound = self.totalRounds
finalsMatches = self.matches.select{|m| m.bracket_position == "1/2" || m.bracket_position == "3/4" || m.bracket_position == "5/6" || m.bracket_position == "7/8"}
finalsMatches. each do |m|
m.round = finalsRound
m.save
end
end
def setSeedsAndRandomSeedingWrestlersWithoutSeeds
weights.each do |w|
w.setSeeds
end
end
def movePoolSeedsToFinalPoolRound
self.weights.each do |w|
w.setOriginalSeedsToWrestleLastPoolRound
end
end
end

View File

@@ -7,6 +7,10 @@ class Match < ActiveRecord::Base
after_update do after_update do
after_update_actions
end
def after_update_actions
if self.finished == 1 && self.winner_id != nil if self.finished == 1 && self.winner_id != nil
if self.w1 && self.w2 if self.w1 && self.w2
wrestler1.touch wrestler1.touch
@@ -28,9 +32,7 @@ class Match < ActiveRecord::Base
wrestler2.school.calcScore wrestler2.school.calcScore
end end
end end
if Rails.env.production?
handle_asynchronously :calcSchoolPoints
end
def mat_assigned def mat_assigned
if self.mat if self.mat
@@ -53,15 +55,11 @@ class Match < ActiveRecord::Base
def advance_wrestlers def advance_wrestlers
if self.w1 && self.w2 if self.w1 && self.w2
@w1 = wrestler1 AdvanceWrestler.new(wrestler1).advance
@w2 = wrestler2 AdvanceWrestler.new(wrestler2).advance
@w1.advanceInBracket(self)
@w2.advanceInBracket(self)
end end
end end
if Rails.env.production?
handle_asynchronously :advance_wrestlers
end
def bracketScore def bracketScore
if self.finished != 1 if self.finished != 1

View File

@@ -24,6 +24,9 @@ class School < ActiveRecord::Base
self.score = newScore self.score = newScore
self.save self.save
end end
if Rails.env.production?
handle_asynchronously :calcScore
end
def totalWrestlerPoints def totalWrestlerPoints
points = 0 points = 0

View File

@@ -14,15 +14,11 @@ class Teampointadjust < ActiveRecord::Base
#Team score needs calculated #Team score needs calculated
if self.wrestler_id != nil if self.wrestler_id != nil
#In case this affects pool order #In case this affects pool order
if self.wrestler.lastFinishedMatch AdvanceWrestler.new(self.wrestler).advance
self.wrestler.lastFinishedMatch.advance_wrestlers
end
self.wrestler.school.calcScore self.wrestler.school.calcScore
elsif self.school_id != nil elsif self.school_id != nil
self.school.calcScore self.school.calcScore
end end
end end
if Rails.env.production?
handle_asynchronously :advance_wrestlers_and_calc_team_score
end
end end

View File

@@ -1,7 +1,5 @@
class Tournament < ActiveRecord::Base class Tournament < ActiveRecord::Base
include GeneratesLoserNames
include GeneratesTournamentMatches
belongs_to :user belongs_to :user
has_many :schools, dependent: :destroy has_many :schools, dependent: :destroy
has_many :weights, dependent: :destroy has_many :weights, dependent: :destroy
@@ -24,10 +22,6 @@ class Tournament < ActiveRecord::Base
time time
end end
def resetSchoolScores
schools.update_all("score = 0.0")
end
def tournament_types def tournament_types
["Pool to bracket"] ["Pool to bracket"]
end end
@@ -51,19 +45,6 @@ class Tournament < ActiveRecord::Base
matches.joins(:weight).where(round: round).order("weights.max") matches.joins(:weight).where(round: round).order("weights.max")
end end
def assignBouts
bout_counts = Hash.new(0)
matches.each do |m|
m.bout_number = m.round * 1000 + bout_counts[m.round]
bout_counts[m.round] += 1
m.save!
end
end
def assignFirstMatchesToMats
assignMats(mats)
end
def totalRounds def totalRounds
self.matches.sort_by{|m| m.round}.last.round self.matches.sort_by{|m| m.round}.last.round
end end

View File

@@ -14,7 +14,7 @@ class Weight < ActiveRecord::Base
end end
before_save do before_save do
self.tournament.destroyAllMatches # self.tournament.destroyAllMatches
end end
def wrestlersForPool(pool) def wrestlersForPool(pool)
@@ -46,22 +46,6 @@ class Weight < ActiveRecord::Base
wrestlersForPool(pool).sort_by{|w| [w.original_seed ? 0 : 1, w.original_seed || 0]} wrestlersForPool(pool).sort_by{|w| [w.original_seed ? 0 : 1, w.original_seed || 0]}
end end
def setOriginalSeedsToWrestleLastPoolRound
pool = 1
until pool > self.pools
wrestler1 = poolSeedOrder(pool).first
wrestler2 = poolSeedOrder(pool).second
match = wrestler1.poolMatches.sort_by{|m| m.round}.last
if match.w1 != wrestler2.id or match.w2 != wrestler2.id
if match.w1 == wrestler1.id
swapWrestlers(match.w2,wrestler2.id)
elsif match.w2 == wrestler1.id
swapWrestlers(match.w1,wrestler2.id)
end
end
pool += 1
end
end
def swapWrestlers(wrestler1_id,wrestler2_id) def swapWrestlers(wrestler1_id,wrestler2_id)
SwapWrestlers.new.swapWrestlers(wrestler1_id,wrestler2_id) SwapWrestlers.new.swapWrestlers(wrestler1_id,wrestler2_id)
@@ -181,37 +165,4 @@ class Weight < ActiveRecord::Base
PoolOrder.new(wrestlersForPool(pool)).getPoolOrder PoolOrder.new(wrestlersForPool(pool)).getPoolOrder
end end
def randomSeeding
wrestlerWithSeeds = self.wrestlers.select{|w| w.original_seed != nil }.sort_by{|w| w.original_seed}
if wrestlerWithSeeds.size > 0
highestSeed = wrestlerWithSeeds.last.seed
seed = highestSeed + 1
else
seed = 1
end
wrestlersWithoutSeed = self.wrestlers.select{|w| w.original_seed == nil }
wrestlersWithoutSeed.shuffle.each do |w|
w.seed = seed
w.save
seed += 1
end
end
def setSeeds
resetAllSeeds
wrestlerWithSeeds = self.wrestlers.select{|w| w.original_seed != nil }
wrestlerWithSeeds.each do |w|
w.seed = w.original_seed
w.save
end
randomSeeding
end
def resetAllSeeds
self.wrestlers.each do |w|
w.seed = nil
w.save
end
end
end end

View File

@@ -22,28 +22,19 @@ class Wrestler < ActiveRecord::Base
end end
def totalTeamPoints def totalTeamPoints
if self.extra CalculateWrestlerTeamScore.new(self).totalScore
return 0
else
teamPointsEarned - totalDeductedPoints
end
end end
def teamPointsEarned def teamPointsEarned
points = 0.0 CalculateWrestlerTeamScore.new(self).earnedPoints
points = points + (poolWins.size * 2) + (championshipAdvancementWins.size * 2) + (consoAdvancementWins.size * 1) + (pinWins.size * 2) + (techWins.size * 1.5) + (majorWins.size * 1) + placementPoints
end end
def placementPoints def placementPoints
PoolBracketPlacementPoints.new(self).calcPoints CalculateWrestlerTeamScore.new(self).placementPoints
end end
def totalDeductedPoints def totalDeductedPoints
points = 0 CalculateWrestlerTeamScore.new(self).deductedPoints
self.deductedPoints.each do |d|
points = points + d.points
end
points
end end
def nextMatch def nextMatch
@@ -88,15 +79,15 @@ class Wrestler < ActiveRecord::Base
end end
def resultByBout(bout) def resultByBout(bout)
@match = allMatches.select{|m| m.bout_number == bout and m.finished == 1} bout_match = allMatches.select{|m| m.bout_number == bout and m.finished == 1}
if @match.size == 0 if bout_match.size == 0
return "" return ""
end end
if @match.first.winner_id == self.id if bout_match.first.winner_id == self.id
return "W #{@match.first.bracketScore}" return "W #{bout_match.first.bracketScore}"
end end
if @match.first.winner_id != self.id if bout_match.first.winner_id != self.id
return "L #{@match.first.bracketScore}" return "L #{bout_match.first.bracketScore}"
end end
end end
@@ -113,26 +104,25 @@ class Wrestler < ActiveRecord::Base
end end
def generatePoolNumber def generatePoolNumber
@pool = self.weight.returnPoolNumber(self) self.weight.returnPoolNumber(self)
end end
def boutByRound(round) def boutByRound(round)
@match = allMatches.select{|m| m.round == round}.first round_match = allMatches.select{|m| m.round == round}.first
if @match.blank? if round_match.blank?
return "BYE" return "BYE"
else else
return @match.bout_number return round_match.bout_number
end end
end end
def allMatches def allMatches
@matches = matches.select{|m| m.w1 == self.id or m.w2 == self.id} return matches.select{|m| m.w1 == self.id or m.w2 == self.id}
return @matches
end end
def poolMatches def poolMatches
@poolMatches = allMatches.select{|m| m.bracket_position == "Pool"} pool_matches = allMatches.select{|m| m.bracket_position == "Pool"}
@poolMatches.select{|m| m.poolNumber == self.generatePoolNumber} pool_matches.select{|m| m.poolNumber == self.generatePoolNumber}
end end
def championshipAdvancementWins def championshipAdvancementWins
@@ -213,7 +203,4 @@ class Wrestler < ActiveRecord::Base
end end
end end
def advanceInBracket(match)
PoolAdvance.new(self,match).advanceWrestler
end
end end

View File

@@ -0,0 +1,14 @@
class AdvanceWrestler
def initialize( wrestler )
@wrestler = wrestler
@tournament = @wrestler.tournament
end
def advance
PoolAdvance.new(@wrestler,@wrestler.lastMatch).advanceWrestler if @tournament.tournament_type == "Pool to bracket"
end
if Rails.env.production?
handle_asynchronously :advance
end
end

View File

@@ -109,21 +109,26 @@ class PoolOrder
end end
def fastestPin def fastestPin
timeArray = [] wrestlersWithSamePointsWithPins = []
wrestlersWithSamePoints.each do |w| wrestlersWithSamePoints.each do |wr|
timeArray << w.fastestPin if wr.pinWins.size > 0
wrestlersWithSamePointsWithPins << wr
end
end end
fastest = timeArray.max if wrestlersWithSamePointsWithPins.size > 0
wrestlersWithFastestPin = wrestlersWithSamePoints.select{|w| w.fastestPin == fastest} fastest = wrestlersWithSamePointsWithPins.sort_by{|w| w.fastestPin.pinTime}.first.fastestPin
addPointsToWrestlersAhead(wrestlersWithFastestPin.first) secondFastest = wrestlersWithSamePointsWithPins.sort_by{|w| w.fastestPin.pinTime}.second.fastestPin
wrestlersWithFastestPin.each do |wr| wrestlersWithFastestPin = wrestlersWithSamePointsWithPins.select{|w| w.fastestPin.pinTime == fastest.pinTime}
addPoints(wr) addPointsToWrestlersAhead(wrestlersWithFastestPin.first)
end wrestlersWithFastestPin.each do |wr|
secondFastest = timeArray.sort[-2] addPoints(wr)
wrestlersWithSecondFastestPin = wrestlersWithSamePoints.select{|w| w.fastestPin == secondFastest} end
addPointsToWrestlersAhead(wrestlersWithSecondFastestPin.first)
wrestlersWithSecondFastestPin.each do |wr| wrestlersWithSecondFastestPin = wrestlersWithSamePointsWithPins.select{|w| w.fastestPin.pinTime == secondFastest.pinTime}
addPoints(wr) addPointsToWrestlersAhead(wrestlersWithSecondFastestPin.first)
wrestlersWithSecondFastestPin.each do |wr|
addPoints(wr)
end
end end
end end

View File

@@ -0,0 +1,83 @@
class GenerateTournamentMatches
def initialize( tournament )
@tournament = tournament
end
def generateWeight(weight)
WipeTournamentMatches.new(@tournament).wipeWeightMatches(weight)
@tournament.curently_generating_matches = 1
@tournament.save
unAssignBouts
PoolToBracketMatchGeneration.new(@tournament).generatePoolToBracketMatchesWeight(weight) if @tournament.tournament_type == "Pool to bracket"
postMatchCreationActions
PoolToBracketGenerateLoserNames.new(@tournament).assignLoserNamesWeight(weight) if @tournament.tournament_type == "Pool to bracket"
end
if Rails.env.production?
handle_asynchronously :generateWeight
end
def generate
standardStartingActions
PoolToBracketMatchGeneration.new(@tournament).generatePoolToBracketMatches if @tournament.tournament_type == "Pool to bracket"
postMatchCreationActions
PoolToBracketMatchGeneration.new(@tournament).assignLoserNames if @tournament.tournament_type == "Pool to bracket"
end
if Rails.env.production?
handle_asynchronously :generate
end
def standardStartingActions
@tournament.curently_generating_matches = 1
@tournament.save
WipeTournamentMatches.new(@tournament).setUpMatchGeneration
TournamentSeeding.new(@tournament).setSeeds
end
def postMatchCreationActions
moveFinalsMatchesToLastRound
assignBouts
assignFirstMatchesToMats
@tournament.curently_generating_matches = nil
@tournament.save
end
def assignBouts
bout_counts = Hash.new(0)
@tournament.matches.each do |m|
m.bout_number = m.round * 1000 + bout_counts[m.round]
bout_counts[m.round] += 1
m.save!
end
end
def moveFinalsMatchesToLastRound
finalsRound = @tournament.totalRounds
finalsMatches = @tournament.matches.select{|m| m.bracket_position == "1/2" || m.bracket_position == "3/4" || m.bracket_position == "5/6" || m.bracket_position == "7/8"}
finalsMatches. each do |m|
m.round = finalsRound
m.save
end
end
def assignFirstMatchesToMats
matsToAssign = @tournament.mats
if matsToAssign.count > 0
until matsToAssign.sort_by{|m| m.id}.last.matches.count == 4
matsToAssign.sort_by{|m| m.id}.each do |m|
m.assignNextMatch
end
end
end
end
def unAssignBouts
bout_counts = Hash.new(0)
@tournament.matches.each do |m|
m.bout_number = nil
m.save!
end
end
end

View File

@@ -1,4 +1,4 @@
class PoolBracket class PoolBracketGeneration
def initialize(weight, highest_round) def initialize(weight, highest_round)
@weight = weight @weight = weight

View File

@@ -1,4 +1,4 @@
class Pool class PoolGeneration
def initialize(weight) def initialize(weight)
@weight = weight @weight = weight
@tournament = @weight.tournament @tournament = @weight.tournament
@@ -6,17 +6,14 @@ class Pool
end end
def generatePools def generatePools
matches = []
pools = @weight.pools pools = @weight.pools
while @pool <= pools while @pool <= pools
matches += roundRobin() roundRobin
@pool += 1 @pool += 1
end end
return matches
end end
def roundRobin def roundRobin
matches = []
wrestlers = @weight.wrestlersForPool(@pool) wrestlers = @weight.wrestlersForPool(@pool)
poolMatches = RoundRobinTournament.schedule(wrestlers).reverse poolMatches = RoundRobinTournament.schedule(wrestlers).reverse
poolMatches.each_with_index do |b, index| poolMatches.each_with_index do |b, index|
@@ -24,16 +21,14 @@ class Pool
bouts = b.map bouts = b.map
bouts.each do |bout| bouts.each do |bout|
if bout[0] != nil and bout[1] != nil if bout[0] != nil and bout[1] != nil
match = @tournament.matches.create( @tournament.matches.create(
w1: bout[0].id, w1: bout[0].id,
w2: bout[1].id, w2: bout[1].id,
weight_id: @weight.id, weight_id: @weight.id,
bracket_position: "Pool", bracket_position: "Pool",
round: round) round: round)
matches << match
end end
end end
end end
matches
end end
end end

View File

@@ -1,8 +1,24 @@
module GeneratesLoserNames class PoolToBracketGenerateLoserNames
def assignLoserNames def initialize( tournament )
@tournament = tournament
end
def assignLoserNamesWeight(weight)
matches_by_weight = @tournament.matches.where(weight_id: weight.id)
if weight.pool_bracket_type == "twoPoolsToSemi"
twoPoolsToSemiLoser(matches_by_weight)
elsif weight.pool_bracket_type == "fourPoolsToQuarter"
fourPoolsToQuarterLoser(matches_by_weight)
elsif weight.pool_bracket_type == "fourPoolsToSemi"
fourPoolsToSemiLoser(matches_by_weight)
end
saveMatches(matches_by_weight)
end
def assignLoserNames
matches_by_weight = nil matches_by_weight = nil
weights.each do |w| @tournament.weights.each do |w|
matches_by_weight = matches.where(weight_id: w.id) matches_by_weight = @tournament.matches.where(weight_id: w.id)
if w.pool_bracket_type == "twoPoolsToSemi" if w.pool_bracket_type == "twoPoolsToSemi"
twoPoolsToSemiLoser(matches_by_weight) twoPoolsToSemiLoser(matches_by_weight)
elsif w.pool_bracket_type == "fourPoolsToQuarter" elsif w.pool_bracket_type == "fourPoolsToQuarter"
@@ -12,7 +28,7 @@ module GeneratesLoserNames
end end
saveMatches(matches_by_weight) saveMatches(matches_by_weight)
end end
end end
def twoPoolsToSemiLoser(matches_by_weight) def twoPoolsToSemiLoser(matches_by_weight)
match1 = matches_by_weight.select{|m| m.loser1_name == "Winner Pool 1"}.first match1 = matches_by_weight.select{|m| m.loser1_name == "Winner Pool 1"}.first
@@ -60,4 +76,5 @@ module GeneratesLoserNames
m.save! m.save!
end end
end end
end end

View File

@@ -0,0 +1,52 @@
class PoolToBracketMatchGeneration
def initialize( tournament )
@tournament = tournament
end
def generatePoolToBracketMatchesWeight(weight)
PoolGeneration.new(weight).generatePools()
last_match = @tournament.matches.where(weight: weight).order(round: :desc).limit(1).first
highest_round = last_match.round
PoolBracketGeneration.new(weight, highest_round).generateBracketMatches()
setOriginalSeedsToWrestleLastPoolRound(weight)
end
def generatePoolToBracketMatches
@tournament.weights.order(:max).each do |weight|
PoolGeneration.new(weight).generatePools()
last_match = @tournament.matches.where(weight: weight).order(round: :desc).limit(1).first
highest_round = last_match.round
PoolBracketGeneration.new(weight, highest_round).generateBracketMatches()
end
movePoolSeedsToFinalPoolRound
end
def movePoolSeedsToFinalPoolRound
@tournament.weights.each do |w|
setOriginalSeedsToWrestleLastPoolRound(w)
end
end
def setOriginalSeedsToWrestleLastPoolRound(weight)
pool = 1
until pool > weight.pools
wrestler1 = weight.poolSeedOrder(pool).first
wrestler2 = weight.poolSeedOrder(pool).second
match = wrestler1.poolMatches.sort_by{|m| m.round}.last
if match.w1 != wrestler2.id or match.w2 != wrestler2.id
if match.w1 == wrestler1.id
SwapWrestlers.new.swapWrestlers(match.w2,wrestler2.id)
elsif match.w2 == wrestler1.id
SwapWrestlers.new.swapWrestlers(match.w1,wrestler2.id)
end
end
pool += 1
end
end
def assignLoserNames
PoolToBracketGenerateLoserNames.new(@tournament).assignLoserNames
end
end

View File

@@ -0,0 +1,44 @@
class TournamentSeeding
def initialize( tournament )
@tournament = tournament
end
def setSeeds
@tournament.weights.each do |w|
resetAllSeeds(w)
setOriginalSeeds(w)
randomSeeding(w)
end
end
def randomSeeding(weight)
wrestlerWithSeeds = weight.wrestlers.select{|w| w.original_seed != nil }.sort_by{|w| w.original_seed}
if wrestlerWithSeeds.size > 0
highestSeed = wrestlerWithSeeds.last.seed
seed = highestSeed + 1
else
seed = 1
end
wrestlersWithoutSeed = weight.wrestlers.select{|w| w.original_seed == nil }
wrestlersWithoutSeed.shuffle.each do |w|
w.seed = seed
w.save
seed += 1
end
end
def setOriginalSeeds(weight)
wrestlerWithSeeds = weight.wrestlers.select{|w| w.original_seed != nil }
wrestlerWithSeeds.each do |w|
w.seed = w.original_seed
w.save
end
end
def resetAllSeeds(weight)
weight.wrestlers.each do |w|
w.seed = nil
w.save
end
end
end

View File

@@ -0,0 +1,23 @@
class WipeTournamentMatches
def initialize( tournament )
@tournament = tournament
end
def setUpMatchGeneration
wipeMatches
resetSchoolScores
end
def wipeWeightMatches(weight)
weight.matches.destroy_all
end
def wipeMatches
@tournament.matches.destroy_all
end
def resetSchoolScores
@tournament.schools.update_all("score = 0.0")
end
end

View File

@@ -0,0 +1,47 @@
class CalculateWrestlerTeamScore
def initialize( wrestler )
@wrestler = wrestler
@tournament = @wrestler.tournament
end
def totalScore
if @wrestler.extra
return 0
else
earnedPoints - deductedPoints
end
end
def earnedPoints
return poolPoints + bracketPoints + placementPoints + bonusWinPoints
end
def deductedPoints
points = 0
@wrestler.deductedPoints.each do |d|
points = points + d.points
end
points
end
def placementPoints
PoolBracketPlacementPoints.new(@wrestler).calcPoints if @tournament.tournament_type == "Pool to bracket"
end
def bracketPoints
(@wrestler.championshipAdvancementWins.size * 2) + (@wrestler.consoAdvancementWins.size * 1)
end
def poolPoints
if @tournament.tournament_type == "Pool to bracket"
(@wrestler.poolWins.size * 2)
else
0
end
end
def bonusWinPoints
(@wrestler.pinWins.size * 2) + (@wrestler.techWins.size * 1.5) + (@wrestler.majorWins.size * 1)
end
end

View File

@@ -0,0 +1,3 @@
json.array!(@tournaments) do |tournament|
json.extract! tournament, :id, :name, :address, :director, :director_email, :date
end

View File

@@ -0,0 +1,2 @@
<%= stylesheet_link_tag "lineman/app" %>
<%= javascript_include_tag "lineman/app" %>

View File

@@ -0,0 +1,55 @@
json.cache! ["api_tournament", @tournament] do
json.content(@tournament)
json.(@tournament, :id, :name, :address, :director, :director_email, :tournament_type, :created_at, :updated_at, :user_id)
json.schools @tournament.schools do |school|
json.id school.id
json.name school.name
json.score school.score
end
json.weights @tournament.weights do |weight|
json.id weight.id
json.max weight.max
json.bracket_size weight.bracket_size
json.wrestlers weight.wrestlers do |wrestler|
json.id wrestler.id
json.name wrestler.name
json.school wrestler.school.name
json.original_seed wrestler.original_seed
json.criteria wrestler.criteria
json.extra wrestler.extra
json.seasonWinPercentage wrestler.seasonWinPercentage
json.season_win wrestler.season_win
json.season_loss wrestler.season_loss
end
end
json.mats @tournament.mats do |mat|
json.name mat.name
json.unfinishedMatches mat.unfinishedMatches do |match|
json.bout_number match.bout_number
json.w1_name match.w1_name
json.w2_name match.w2_name
end
end
json.unassignedMatches @tournament.matches.select{|m| m.mat_id == nil}.sort_by{|m| m.bout_number}[0...9] do |match|
json.bout_number match.bout_number
json.w1_name match.w1_name
json.w2_name match.w2_name
json.weightClass match.weight.max
json.round match.round
end
json.matches @tournament.matches do |match|
json.bout_number match.bout_number
json.w1_name match.w1_name
json.w2_name match.w2_name
json.weightClass match.weight.max
json.round match.round
json.w1 match.w1
json.w2 match.w2
end
end

View File

@@ -0,0 +1,3 @@
json.array!(@tournaments) do |tournament|
json.extract! tournament, :id, :name, :address, :director, :director_email, :date
end

View File

@@ -9,7 +9,7 @@
<script src="https://cdn.datatables.net/1.10.6/js/jquery.dataTables.min.js"></script> <script src="https://cdn.datatables.net/1.10.6/js/jquery.dataTables.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.map"></script>
<!--Mobile and tablet detection--> <!--Mobile and tablet detection-->
<script type='text/javascript' src="//wurfl.io/wurfl.js"></script> <script type='text/javascript' src="//wurfl.io/wurfl.js"></script>

View File

@@ -0,0 +1,3 @@
<%= link_to "Back to #{@weight.tournament.name}", "/tournaments/#{@weight.tournament.id}", :class=>"btn btn-default" %>
<br><br>
<%= @weight.max %> lbs Matches are being generated. This can take anywhere from 1-5 minutes to finish. It is recommended to delete all delegated school permissions to prevent lineup changes after the tournament has started.

View File

@@ -4,6 +4,9 @@
<%= link_to "Back to #{@tournament.name}", "/tournaments/#{@tournament.id}", :class=>"btn btn-default" %> <%= link_to "Back to #{@tournament.name}", "/tournaments/#{@tournament.id}", :class=>"btn btn-default" %>
<% if can? :manage, @tournament %> <% if can? :manage, @tournament %>
| <%= link_to "Edit #{@weight.max} Weight Class", edit_weight_path(@weight), :class=>"btn btn-primary" %> | <%= link_to "Edit #{@weight.max} Weight Class", edit_weight_path(@weight), :class=>"btn btn-primary" %>
| <%= form_for(@weight, url: regen_weight_path(@weight.id), :method => "post") do |f| %>
<%= submit_tag "Regenerate Weight Class Matches", :class=>"btn"%>
<% end %>
<% end %> <% end %>
<br> <br>

View File

@@ -17,14 +17,12 @@
<%= f.text_field :name %> <%= f.text_field :name %>
</div> </div>
<% if can? :manage, @wrestler.tournament %> <% if can? :manage, @wrestler.tournament %>
<% if @tournament %>
<%= f.hidden_field :school_id, :value => @school.id %>
<% else %>
<div class="field"> <div class="field">
<%= f.label 'School' %><br> <%= f.label 'School' %><br>
<%= f.collection_select :school_id, @school.tournament.schools, :id, :name %> <%= f.collection_select :school_id, @school.tournament.schools, :id, :name %>
</div> </div>
<% end %> <% else %>
<%= f.hidden_field :school_id, :value => @school.id %>
<% end %> <% end %>
<div class="field"> <div class="field">
<%= f.label 'Weight Class' %><br> <%= f.label 'Weight Class' %><br>

View File

@@ -29,7 +29,15 @@ module Wrestling
config.active_job.queue_adapter = :delayed_job config.active_job.queue_adapter = :delayed_job
config.rails_lineman.lineman_project_location = "frontend"
config.to_prepare do
DeviseController.respond_to :html, :json
end
config.autoload_paths += %W(#{config.root}/app/services/tournament_services)
config.autoload_paths += %W(#{config.root}/app/services/wrestler_services)
config.autoload_paths += %W(#{config.root}/app/services/bracket_advancement)
end end

View File

@@ -110,4 +110,7 @@ Wrestling::Application.configure do
config.action_mailer.perform_deliveries = true config.action_mailer.perform_deliveries = true
#Devise needs origin of email #Devise needs origin of email
Rails.application.routes.default_url_options[:host] = 'https://wrestlingdev.com' Rails.application.routes.default_url_options[:host] = 'https://wrestlingdev.com'
#For lineman creating assets
config.serve_static_files = true
end end

View File

@@ -51,6 +51,15 @@ Wrestling::Application.routes.draw do
get 'tournaments/:id/error' => 'tournaments#error' get 'tournaments/:id/error' => 'tournaments#error'
post "/tournaments/:id/swap" => "tournaments#swap", :as => :swap_wrestlers post "/tournaments/:id/swap" => "tournaments#swap", :as => :swap_wrestlers
post 'weights/:id/re_gen' => 'weights#re_gen', :as => :regen_weight
#API
get "/api/tournaments" => "api#tournaments"
get "/api/tournaments/user" => "api#currentUserTournaments"
get "/api/tournaments/:tournament" => "api#tournament"
get "/api/index" => "api#index"
post "/api/tournaments/new" => "newTournament"
# Example of regular route: # Example of regular route:
# get 'products/:id' => 'catalog#view' # get 'products/:id' => 'catalog#view'

View File

@@ -1,5 +1,6 @@
cd .. cd ..
bash rails-prod.sh wrestlingdev docker build -t wrestlingdev -f rails-prod-Dockerfile .
cd deploy cd deploy
docker-compose -f docker-compose-test.yml kill
docker-compose -f docker-compose-test.yml up -d docker-compose -f docker-compose-test.yml up -d
echo Make sure your local mysql database has a wrestlingtourney db echo Make sure your local mysql database has a wrestlingtourney db

View File

@@ -23,3 +23,10 @@ worker:
restart: always restart: always
env_file: env_file:
- ./prod.env - ./prod.env
command: bundle exec rake jobs:work RAILS_ENV=production
memcached:
extends:
file: docker-compose-common.yml
service: memcached
restart: always

View File

@@ -10,10 +10,14 @@ app:
- WRESTLINGDEV_DB_PORT=3306 - WRESTLINGDEV_DB_PORT=3306
- WRESTLINGDEV_DEVISE_SECRET_KEY=2f29d49db6704377ba263f7cb9db085b386bcb301c0cd501126a674686ab1a109754071165b08cd72af03cec4642a4dd04361c994462254dd5d85e9594e8b9aa - WRESTLINGDEV_DEVISE_SECRET_KEY=2f29d49db6704377ba263f7cb9db085b386bcb301c0cd501126a674686ab1a109754071165b08cd72af03cec4642a4dd04361c994462254dd5d85e9594e8b9aa
- WRESTLINGDEV_SECRET_KEY_BASE=077cdbef5c2ccf22543fb17a67339f234306b7fa2e1e4463d851c444c10a5611829a2290b253da78339427f131571fac9a42c83d960b2d25ecc10a4a0a7ce1a2 - WRESTLINGDEV_SECRET_KEY_BASE=077cdbef5c2ccf22543fb17a67339f234306b7fa2e1e4463d851c444c10a5611829a2290b253da78339427f131571fac9a42c83d960b2d25ecc10a4a0a7ce1a2
- MEMCACHIER_SERVERS=memcached:11211
- MEMCACHIER_USERNAME=
- MEMCACHIER_PASSWORD=
links: links:
- db - db
- memcached
restart: always restart: always
db: db:
extends: extends:
file: docker-compose-common.yml file: docker-compose-common.yml
@@ -21,6 +25,7 @@ db:
environment: environment:
- MYSQL_ROOT_PASSWORD=password - MYSQL_ROOT_PASSWORD=password
restart: always restart: always
worker: worker:
extends: extends:
file: docker-compose-common.yml file: docker-compose-common.yml
@@ -33,7 +38,18 @@ worker:
- WRESTLINGDEV_DB_PORT=3306 - WRESTLINGDEV_DB_PORT=3306
- WRESTLINGDEV_DEVISE_SECRET_KEY=2f29d49db6704377ba263f7cb9db085b386bcb301c0cd501126a674686ab1a109754071165b08cd72af03cec4642a4dd04361c994462254dd5d85e9594e8b9aa - WRESTLINGDEV_DEVISE_SECRET_KEY=2f29d49db6704377ba263f7cb9db085b386bcb301c0cd501126a674686ab1a109754071165b08cd72af03cec4642a4dd04361c994462254dd5d85e9594e8b9aa
- WRESTLINGDEV_SECRET_KEY_BASE=077cdbef5c2ccf22543fb17a67339f234306b7fa2e1e4463d851c444c10a5611829a2290b253da78339427f131571fac9a42c83d960b2d25ecc10a4a0a7ce1a2 - WRESTLINGDEV_SECRET_KEY_BASE=077cdbef5c2ccf22543fb17a67339f234306b7fa2e1e4463d851c444c10a5611829a2290b253da78339427f131571fac9a42c83d960b2d25ecc10a4a0a7ce1a2
- MEMCACHIER_SERVERS=memcached:11211
- MEMCACHIER_USERNAME=
- MEMCACHIER_PASSWORD=
links: links:
- db - db
- memcached
restart: always restart: always
command: bundle exec rake jobs:work RAILS_ENV=production
memcached:
extends:
file: docker-compose-common.yml
service: memcached
restart: always

9
frontend/.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
.DS_Store
#ignore node_modules, as the node project is not "deployed" per se: http://www.mikealrogers.com/posts/nodemodules-in-git.html
/node_modules
/dist
/generated
.sass-cache

9
frontend/.npmignore Normal file
View File

@@ -0,0 +1,9 @@
.DS_Store
#ignore node_modules, as the node project is not "deployed" per se: http://www.mikealrogers.com/posts/nodemodules-in-git.html
/node_modules
/dist
/generated
.sass-cache

4
frontend/.travis.yml Normal file
View File

@@ -0,0 +1,4 @@
language: node_js
node_js:
- 0.10
script: "lineman spec-ci"

4
frontend/Gruntfile.js Normal file
View File

@@ -0,0 +1,4 @@
/*global module:false*/
module.exports = function(grunt) {
require('./config/lineman').config.grunt.run(grunt);
};

1
frontend/Procfile Normal file
View File

@@ -0,0 +1 @@
web: npm run production

1
frontend/README.md Normal file
View File

@@ -0,0 +1 @@
# My Lineman Application

View File

@@ -0,0 +1,4 @@
.hello {
background-color: #efefef;
border: 1px solid #dedede;
}

0
frontend/app/img/.keep Normal file
View File

0
frontend/app/js/.keep Normal file
View File

11
frontend/app/js/app.js Normal file
View File

@@ -0,0 +1,11 @@
var app = angular.module("wrestlingdev", ["ngRoute","Devise"]).run(function($rootScope) {
// adds some basic utilities to the $rootScope for debugging purposes
$rootScope.log = function(thing) {
console.log(thing);
};
$rootScope.alert = function(thing) {
alert(thing);
};
});

View File

@@ -0,0 +1,51 @@
'use strict';
app.controller("loginController", function($scope, $routeParams, Auth, $rootScope) {
$scope.credentials = {
email: '',
password: ''
};
var config = {
headers: {
'X-HTTP-Method-Override': 'POST'
}
};
$scope.login = function(){
Auth.login($scope.credentials, config).then(function(user) {
console.log(user); // => {id: 1, ect: '...'}
$rootScope.user = user;
$rootScope.alertClass = "alert alert-success";
$rootScope.alertMessage = "Logged in successfully";
}, function(error) {
console.log(error);
$rootScope.alertClass = "alert alert-danger";
$rootScope.alertMessage = "Username and/or password is incorrect";
});
};
$scope.logout = function(){
Auth.logout(config).then(function(oldUser) {
// alert(oldUser.name + "you're signed out now.");
$rootScope.user = null;
$rootScope.alertClass = "alert alert-success";
$rootScope.alertMessage = "Logged out successfully";
}, function(error) {
// An error occurred logging out.
$rootScope.alertClass = "alert alert-danger";
$rootScope.alertMessage = "There was an error logging out";
});
};
Auth.currentUser().then(function(user) {
// User was logged in, or Devise returned
// previously authenticated session.
$rootScope.user = user;
}, function(error) {
// unauthenticated error
$rootScope.user = null;
});
});

View File

@@ -0,0 +1,11 @@
'use strict';
app.controller("myTournamentsController", function($scope, tournamentsService, $rootScope) {
tournamentsService.getMyTournaments().then(function(data) {
//this will execute when the
//AJAX call completes.
$scope.allTournaments = data;
});
});

View File

@@ -0,0 +1,86 @@
'use strict';
app.controller("tournamentController", function($scope, tournamentsService, $routeParams, Wrestler, Auth, $rootScope) {
$scope.message = "Test message in scope.";
// $scope.tournamentData = "test";
tournamentsService.tournamentDetails($routeParams.id).then(function(data) {
//this will execute when the
//AJAX call completes.
$scope.tournament = data;
});
$scope.refreshTournamentData = function(){
tournamentsService.tournamentDetails($routeParams.id).then(function(data) {
//this will execute when the
//AJAX call completes.
$scope.tournament = data;
});
};
// refresh tournament data every 10 seconds
// setInterval(function(){
// tournamentsService.tournamentDetails($routeParams.id).then(function(data) {
// //this will execute when the
// //AJAX call completes.
// $scope.tournament = data;
// });
// }, 10000);
$scope.wrestler = Wrestler;
$scope.showSchools = false;
$scope.toggleSchools = function(){
$scope.showSchools = !$scope.showSchools;
};
$scope.showWeightSeeds = false;
$scope.toggleWeightSeeds = function(){
$scope.showWeightSeeds = !$scope.showWeightSeeds;
};
$scope.showBoutBoard = false;
$scope.toggleBoutBoard = function(){
$scope.showBoutBoard = !$scope.showBoutBoard;
};
$scope.isTournamentOwner = function(tournamentId,userId){
if(userId == tournamentId){
return true;
} else {
return false;
}
};
$scope.newSchool = null;
$scope.saveNewSchool = function(){
$scope.newSchool.tournament_id = $scope.tournament.id;
tournamentsService.saveNewSchool($scope.newSchool).then(function(data) {
$scope.tournament.schools.push(data);
});
$scope.newSchool = null;
$('#NewSchool').modal('hide');
};
$scope.deleteSchool = function(school){
if (confirm('Are you sure you want to delete ' + school.name + '?')) {
tournamentsService.deleteSchool(school).then(function(data) {
$scope.tournament.schools.splice( $scope.tournament.schools.indexOf(school), 1 );
});
}
};
$scope.updateSchool = function(school){
tournamentsService.updateSchool(school);
$('#EditSchool' + school.id).modal('hide');
};
});

View File

@@ -0,0 +1,19 @@
'use strict';
app.controller("tournamentsController", function($scope, tournamentsService) {
tournamentsService.getAllTournaments().then(function(data) {
//this will execute when the
//AJAX call completes.
$scope.allTournaments = data;
});
$scope.searchTournaments = function (){
tournamentsService.searchTournaments($scope.searchTerms).then(function(data) {
//this will execute when the
//AJAX call completes.
$scope.allTournaments = data;
});
};
});

View File

@@ -0,0 +1,24 @@
(function(){
app.directive('usSpinner', ['$http', '$rootScope' ,function ($http, $rootScope){
return {
link: function (scope, elm, attrs)
{
$rootScope.spinnerActive = false;
scope.isLoading = function () {
return $http.pendingRequests.length > 0;
};
scope.$watch(scope.isLoading, function (loading)
{
$rootScope.spinnerActive = loading;
if(loading){
elm.removeClass('ng-hide');
}else{
elm.addClass('ng-hide');
}
});
}
};
}]);
}).call(this);

View File

@@ -0,0 +1,18 @@
'use strict';
app.factory('Wrestler', function Wrestler(){
var vm = this;
vm.matches = function(wrestler,matches){
console.log(matches);
return _.filter(matches, function(match){
return match.w1 == wrestler.id || match.w2 == wrestler.id;
});
};
return vm;
});

49
frontend/app/js/routes.js Normal file
View File

@@ -0,0 +1,49 @@
// $routeProvider.when('/list-of-books', {
// templateUrl: 'angular/books.html',
// controller: 'BooksController'
// // uncomment if you want to see an example of a route that resolves a request prior to rendering
// // resolve: {
// // books : function(BookService) {
// // return BookService.get();
// // }
// // }
// });
app.config(['$routeProvider', '$locationProvider', function($routeProvider,$locationProvider) {
$routeProvider.when('/', {
templateUrl: 'home.html',
});
$routeProvider.when('/tournaments', {
templateUrl: 'tournaments-search.html',
controller: 'tournamentsController'
});
$routeProvider.when('/tournaments/user', {
templateUrl: 'my-tournaments.html',
controller: 'myTournamentsController'
});
$routeProvider.when('/tournaments/:id', {
templateUrl: 'tournaments-show.html',
controller: 'tournamentController'
});
$routeProvider.when('/about', {
templateUrl: 'about.html',
});
$routeProvider.when('/tutorials', {
templateUrl: 'tutorials.html',
});
$routeProvider.otherwise({redirectTo: '/'});
//this give me normal routes instead of /#/
// $locationProvider.html5Mode(true);
}]);

View File

@@ -0,0 +1,101 @@
app.factory('tournamentsService', tournamentsService);
function tournamentsService($http,$rootScope){
var service = {};
service.getMyTournaments = function(user){
return $http({
url: '/api/tournaments/user/',
method: "GET"
}).then(successResponse, errorCallback);
};
service.getAllTournaments = function(){
return $http({
url: '/api/tournaments/',
method: "GET"
}).then(successResponse, errorCallback);
};
service.searchTournaments = function(search){
return $http({
method: 'GET',
url: '/api/tournaments/',
params: {
search: search
}
}).then(successResponse, errorCallback);
};
service.tournamentDetails = function(tournamentId){
return $http({
url: '/api/tournaments/' + tournamentId,
method: "GET"
}).then(successResponse, errorCallback);
};
service.saveNewSchool = function(newSchool){
return $http({
url: '/schools.json',
method: "POST",
data: {
school: {
'name': newSchool.name,
'tournament_id': newSchool.tournament_id
}
},
headers: {
"Content-Type": "application/json"
}
}).then(successResponse, errorCallback);
};
service.deleteSchool = function(school){
return $http({
url: '/schools/' + school.id + '/',
method: "DELETE"
}).then(successResponse, errorCallback);
};
service.updateSchool = function(schoolToEdit){
return $http({
url: '/schools/' + schoolToEdit.id,
method: "PATCH",
data: {
school: {
'name': schoolToEdit.name,
'tournament_id': schoolToEdit.tournament_id
}
},
headers: {
"Content-Type": "application/json"
}
}).then(successResponse, errorCallback);
};
function successResponse(response){
// console.log("success log below");
// console.log(response);
if(response.config.method == "POST" || response.config.method == "DELETE" || response.config.method == "PATCH"){
$rootScope.alertClass = "alert alert-success";
$rootScope.alertMessage = response.statusText;
}
return response.data;
}
function errorCallback(err){
// console.log("error log below");
// console.log(err);
if(err.status > 0){
$rootScope.alertClass = "alert alert-danger";
$rootScope.alertMessage = err.statusText;
}
return err;
}
return service;
}

View File

@@ -0,0 +1,98 @@
<!DOCTYPE html>
<html ng-app="wrestlingdev">
<head>
<base href="/#/">
<title>WrestlingDev</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">
</head>
<body style="padding-top: 70px;">
<div class="container">
<div class="navbar-roof"></div>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/#/">WrestlingDev</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav navbar-right navbar-custom-link">
<li><a href="/#/tournaments">Browse Tournaments</a></li>
<li><a href="/#/about">About</a></li>
<li><a href="/#/tutorials">Tutorials</a></li>
<li class="dropdown" ng-controller="loginController">
<a ng-if="user == null" class="dropdown-toggle" data-toggle="dropdown">Login<span class="caret"></a>
<div ng-if="user == null" class="dropdown-menu" style="padding:17px;">
<form class="form" id="formLogin">
<div class="form-group">
<input name="username" class="form-control" id="username" type="text" placeholder="Email" ng-model="credentials.email">
<input name="password" class="form-control" id="password" type="password" placeholder="Password" ng-model="credentials.password"><br>
<button type="button" id="btnLogin" class="btn btn-primary" ng-click="login()">Login</button>
</div>
</form>
</div>
<a ng-if="user != null" class="dropdown-toggle" data-toggle="dropdown">{{user.email}}<span class="caret"></a>
<ul ng-if="user != null" class="dropdown-menu" style="list-style-type: none;">
<li><a href="/#/tournaments/user">My Tournaments and schools</a></li>
<li><a ng-click="logout()">Logout</a></li>
</ul>
</li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div id="page-content">
<div class="row no-margin">
<div ng-if="alertMessage != null" ng-class="alertClass">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
{{alertMessage}}
</div>
<div class="col-md-2">
<!--left sidebar-->
</div>
<div class="col-md-8" style="padding-left: 2%;">
<div id="view" ng-view></div>
</div>
<div class="col-md-2" >
<!--right sidebar-->
</div>
</div>
</div>
<!--footer-->
</div>
</body>
<!-- Latest compiled and minified JavaScript -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-route.js"></script>
<script type="text/javascript" src="/js/app.js"></script>
<script src="//code.jquery.com/jquery-1.12.0.min.js"></script>
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<script src="https://cdn.datatables.net/1.10.6/js/jquery.dataTables.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<!--Mobile and tablet detection-->
<script type='text/javascript' src="//wurfl.io/wurfl.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</html>

View File

@@ -0,0 +1,46 @@
<h3>About WrestlingDev</h3>
<br>
<p>WrestlingDev was created to help bring wrestling into the 21st century for <strong>free</strong>. This site is <a href="https://github.com/jcwimer/wrestlingApp">open source</a> and is supported by the ads on the sidebar.</p>
<br>
<h4>Features</h4>
<br>
<p>At this moment in time, WrestlingDev supports a pool to bracket type tournament for up to 16 teams. The bracket format follows OHSAA's 5 match per day rule. WrestlingDev will automatically generate brackets, generate bout numbers, generate and update a bout board, track team points, and update brackets.</p>
<p>For pool to bracket tournaments, pool tie breakers are the following:</p>
<ul>
<li>Least team points deducted</li>
<li>Head to head</li>
<li>Most team points scored</li>
<li>Most wins by fall, default, dq</li>
<li>Most wins by tech fall</li>
<li>Most wins by major</li>
<li>Most points scored in decisions</li>
<li>Quickest pin</li>
<li>Coin flip</li>
</ul>
<p>If three wrestlers are tied, they will be put through this sequence until two wrestlers are left. Once two wrestlers are left, the pool runner up will be decided by head to head.</p>
<p>For pool to bracket tournaments, team points will be calculated as follows:</p>
<ul>
<li>Pool win: 2pt</li>
<li>Win in championship bracket: 2pt</li>
<li>Win in consolation bracket: 1pt</li>
<li>Win by major: 1pt extra</li>
<li>Win by tech fall: 1.5pt extra</li>
<li>Win by fall, default, dq: 2pt extra</li>
<li>1st place: 16pt</li>
<li>2nd place: 12pt</li>
<li>3rd place: 10pt</li>
<li>4th place: 9pt</li>
<li>5th place: 7pt</li>
<li>6th place: 6pt</li>
<li>7th place: 4pt</li>
<li>8th place: 3pt</li>
</ul>
<p>Finals matches will only recieve extra placement points for placing higher and bonus points for pin, tech, major, etc. Please note, only brackets with four pools place up to 8. Brackets with 1 or 2 pools only place top 4.</p>
<br>
<h4>Future Plans</h4>
<br>
<p>Future development plans to support normal double elimination brackets are underway and are planned to be finished in time for the 2016-2017 wrestling season.</p>
<br>
<h4>Contact</h4>
<br>
<p>Suggestions, criticism, and kind words are welcomed. Please contact us.</p>

View File

@@ -0,0 +1,10 @@
<div class="center hero-unit" >
<h1>Welcome to WrestlingDev</h1>
<br>
<p>This website was created to help wrestling coaches run their tournaments. It is 2015, why are we still running bout sheets to tables and why are we still using resources to push cards on a bout board? This website was created as a <strong>free</strong> way for coaches to run a tournament smoothly with as few workers as possible.</p>
<br>
<p>If you would like to run a tournament, please click log in and then click sign up.</p>
<br>
<a href='/#/tournaments' class="btn btn-large btn-primary">Browse Tournaments</a>
<p></p>
</div>

View File

@@ -0,0 +1,17 @@
<h3>Tutorials</h3>
<br>
<p>Unfortunately, I do not have tutorials available at this moment in time. If you would like to learn how to use this software, please email me at jacob.wimer@gmail.com and I will gladly provide an overview of how to use this software. I've done my best to make the software intuitive and easy to use.</p>
<br>
<h4>Planning on using this software?</h4>
<br>
<p>Here is a list of features available:</p>
<br>
<ul>
<li>Pool to bracket type bracket generation for up to 16 man brackets</li>
<li>Delegate control to coaches for lineup entry</li>
<li>Automatically updated bout board</li>
<li>Automatically updated brackets</li>
<li>Automatically updated team scores</li>
<li>Delegate director privileges to multiple people for tournament administration</li>
<li>Matches can be scored at the tables and submitted via computer or bout sheets can be brought to the head table and entered there</li>
</ul>

View File

@@ -0,0 +1,17 @@
<h2>My Tournaments</h2>
<br>
<table class="table">
<thead class="font-spot-color">
<tr>
<th>Name</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="tournament in allTournaments">
<td><a ng-href="/#/tournaments/{{tournament.id}}">{{ tournament.name }}</a></td>
<td>{{ tournament.date }}</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,25 @@
<h2>Upcoming Tournaments</h2>
<br>
<form ng-submit="searchTournaments()">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search by name or date YYYY-MM-DD" ng-model="searchTerms">
<span class="input-group-btn">
<button class="btn btn-default" type="submit" id="submit">Search</button>
</span>
</div>
</form>
<br>
<table class="table">
<thead class="font-spot-color">
<tr>
<th>Name</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="tournament in allTournaments">
<td><a ng-href="/#/tournaments/{{tournament.id}}">{{ tournament.name }}</a></td>
<td>{{ tournament.date }}</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,222 @@
<a href="/#/tournaments" class="btn btn-default">Back to browse tournaments</a>
<h1>
{{ tournament.name }}
</h1>
<p>
<strong>Address:</strong>
{{ tournament.address }}
</p>
<p>
<strong>Director:</strong>
{{ tournament.director }}
</p>
<p>
<strong>Director email:</strong>
{{ tournament.director_email }}
</p>
<p>
<strong>Tournament Type:</strong>
{{ tournament.tournament_type }}
</p>
<br>
<div class="panel panel-default">
<a class="panel-heading" ng-click="toggleSchools()" style="display: block;">
<h3 class="panel-title">School Lineups and Team Scores<span class="pull-left clickable"><i ng-if="showSchools == false" class="glyphicon glyphicon-chevron-down"></i>
<i ng-if="showSchools == true" class="glyphicon glyphicon-chevron-up"></i></span></h3>
</a>
<div id="Schools" ng-if="showSchools == true">
<div class="panel-body">
<button ng-if="isTournamentOwner(user.id,tournament.user_id)" class="btn btn-success btn-sm" data-toggle="modal" data-target="#NewSchool">Create New School</button>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Score</th>
<th ng-if="isTournamentOwner(user.id,tournament.user_id)">Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="school in tournament.schools | orderBy : 'score'">
<td>{{ school.name }}</td>
<td>{{ school.score }}</td>
<td ng-if="isTournamentOwner(user.id,tournament.user_id)">
<button class="btn btn-sm" data-toggle="modal" data-target="#EditSchool{{school.id}}">Edit</button>
<button ng-click="deleteSchool(school)"class="btn btn-danger btn-sm">Destroy</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="panel panel-default">
<a class="panel-heading" ng-click="toggleWeightSeeds()" style="display: block;">
<h3 class="panel-title">Weights and Seeds<span class="pull-left clickable"><i ng-if="showWeightSeeds == false" class="glyphicon glyphicon-chevron-down"></i>
<i ng-if="showWeightSeeds == true" class="glyphicon glyphicon-chevron-up"></i></span></h3>
</a>
<div id="Weights" ng-if="showWeightSeeds == true">
<div class="panel-body">
<p>Click weight class for seeds</p>
<br>
<table class="table">
<thead>
<tr>
<th>Weight Class</th>
<th>Bracket Size</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="weight in tournament.weights | orderBy : 'max' : reverse">
<td><a data-toggle="modal" data-target="#Weight{{weight.id}}">{{ weight.max }}</a></td>
<td>{{ weight.bracket_size }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="panel panel-default">
<a class="panel-heading" ng-click="toggleBoutBoard()" style="display: block;" >
<h3 class="panel-title">Mats and Bout Board<span class="pull-left clickable"><i ng-if="showBoutBoard == false" class="glyphicon glyphicon-chevron-down"></i>
<i ng-if="showBoutBoard == true" class="glyphicon glyphicon-chevron-up"></i></span></h3>
</a>
<div id="Mats" ng-if="showBoutBoard == true">
<div class="panel-body">
<p ng-if="tournament.matches.length == 0">Matches have not been generated</p>
<table ng-if="tournament.matches.length > 0" class="table">
<thead>
<tr>
<th>Name</th>
<th>On Mat</th>
<th>On Deck</th>
<th>In The Hole</th>
<th>Warm Up</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="mat in tournament.mats">
<td>{{ mat.name }}</td>
<td>{{ mat.unfinishedMatches[0].bout_number }} {{ mat.unfinishedMatches[0].w1_name }} vs. {{ mat.unfinishedMatches[0].w2_name }}</td>
<td>{{ mat.unfinishedMatches[1].bout_number }} {{ mat.unfinishedMatches[0].w1_name }} vs. {{ mat.unfinishedMatches[0].w2_name }}</td>
<td>{{ mat.unfinishedMatches[2].bout_number }} {{ mat.unfinishedMatches[0].w1_name }} vs. {{ mat.unfinishedMatches[0].w2_name }}</td>
<td>{{ mat.unfinishedMatches[3].bout_number }} {{ mat.unfinishedMatches[0].w1_name }} vs. {{ mat.unfinishedMatches[0].w2_name }}</td>
</tr>
</tbody>
</table>
<br>
<h3 ng-if="tournament.matches.length > 0" >Matches not assigned</h3>
<br>
<table ng-if="tournament.matches.length > 0" class="table">
<thead>
<tr>
<th>Round</th>
<th>Bout Number</th>
<th>Weight Class</th>
<th>Matchup</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="match in tournament.unassignedMatches">
<td>Round {{ match.round }}</td>
<td>{{ match.bout_number }}</td>
<td>{{ match.weightClass }}</td>
<td>{{ match.w1_name }} vs. {{ match.w2_name }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!--Hidden modals for weight seeds-->
<div ng-repeat="weight in tournament.weights">
<div class="modal fade bs-example-modal-lg" id="Weight{{weight.id}}" tabindex="-1" role="dialog" aria-labelledby="Weight{{weight.id}}">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h3 class="modal-title" id="gridSystemModalLabel">{{weight.max}}</h3>
</div>
<div class="modal-body">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>School</th>
<th>Seed</th>
<th>Record</th>
<th>Criteria</th>
<th>Extra?</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="wrestler in weight.wrestlers | orderBy : 'original_seed' : reverse">
<td>{{wrestler.name}}</td>
<td>{{wrestler.school}}</td>
<td>{{wrestler.original_seed}}</td>
<td>{{wrestler.season_win}}-{{wrestler.season_loss}}</td>
<td>{{wrestler.criteria}} Win %{{wrestler.seasonWinPercentage}}</td>
<td>{{wrestler.extra}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!--Hidden model for new school-->
<div class="modal fade bs-example-modal-lg" id="NewSchool" tabindex="-1" role="dialog" aria-labelledby="NewSchool">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h3 class="modal-title" id="gridSystemModalLabel">New School for {{tournament.name}}</h3>
</div>
<div class="modal-body">
<form class="form" id="formNewSchool" name="form" ng-submit="saveNewSchool()">
<div class="form-group">
<input name="school[name]" class="form-control" id="name" type="text" placeholder="School Name" ng-model="newSchool.name"><br>
<input type="submit" id="btnSaveNewSchool" class="btn btn-success" value="Save School">
</div>
</form>
</div>
</div>
</div>
</div>
<!--Hidden modals for school edit forms-->
<div ng-repeat="school in tournament.schools">
<div class="modal fade bs-example-modal-lg" id="EditSchool{{school.id}}" tabindex="-1" role="dialog" aria-labelledby="EditSchool{{school.id}}">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h3 class="modal-title" id="gridSystemModalLabel">Edit {{school.name}}</h3>
</div>
<div class="modal-body">
<form class="form" id="formEditSchool{{school.id}}" name="form" ng-submit="updateSchool(school)">
<div class="form-group">
<input name="school[name]" class="form-control" id="name" type="text" placeholder="School Name" ng-model="school.name"><br>
<input type="submit" id="btnSaveNewSchool" class="btn btn-success" value="Save School">
</div>
</form>
</div>
</div>
</div>
</div>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,3 @@
<div class="hello">
<%= text %>
</div>

View File

@@ -0,0 +1,66 @@
/* Exports a function which returns an object that overrides the default &
* plugin grunt configuration object.
*
* You can familiarize yourself with Lineman's defaults by looking at:
*
* - https://github.com/linemanjs/lineman/blob/master/config/application.coffee
* - https://github.com/linemanjs/lineman/blob/master/config/plugins
*
* You can also ask about Lineman's config from the command line:
*
* $ lineman config #=> to print the entire config
* $ lineman config concat_sourcemap.js #=> to see the JS config for the concat task.
*/
module.exports = function(lineman) {
//Override application configuration here. Common examples follow in the comments.
return {
// API Proxying
//
// During development, you'll likely want to make XHR (AJAX) requests to an API on the same
// port as your lineman development server. By enabling the API proxy and setting the port, all
// requests for paths that don't match a static asset in ./generated will be forwarded to
// whatever service might be running on the specified port.
//
server: {
apiProxy: {
enabled: true,
host: 'localhost',
port: 8080
},
web: {
port: 8081
}
},
removeTasks: {
common: ["jshint"]
},
// Sass
//
// Lineman supports Sass via grunt-contrib-sass, which requires you first
// have Ruby installed as well as the `sass` gem. To enable it, uncomment the
// following line:
//
// enableSass: true,
// Asset Fingerprints
//
// Lineman can fingerprint your static assets by appending a hash to the filename
// and logging a manifest of logical-to-hashed filenames in dist/assets.json
// via grunt-asset-fingerprint
//
// enableAssetFingerprint: true,
// LiveReload
//
// Lineman can LiveReload browsers whenever a file is changed that results in
// assets to be processed, preventing the need to hit F5/Cmd-R every time you
// make a change in each browser you're working against. To enable LiveReload,
// comment out the following line:
//
// livereload: true
};
};

26
frontend/config/files.js Normal file
View File

@@ -0,0 +1,26 @@
/* Exports a function which returns an object that overrides the default &
* plugin file patterns (used widely through the app configuration)
*
* To see the default definitions for Lineman's file paths and globs, see:
*
* - https://github.com/linemanjs/lineman/blob/master/config/files.coffee
*/
module.exports = function(lineman) {
//Override file patterns here
return {
// As an example, to override the file patterns for
// the order in which to load third party JS libs:
//
// js: {
// vendor: [
// "vendor/js/underscore.js",
// "vendor/js/**/*.js"
// ]
// }
//Override file patterns here
};
};

View File

@@ -0,0 +1 @@
module.exports = require(process.env['LINEMAN_MAIN']);

21
frontend/config/server.js Normal file
View File

@@ -0,0 +1,21 @@
/* Define custom server-side HTTP routes for lineman's development server
* These might be as simple as stubbing a little JSON to
* facilitate development of code that interacts with an HTTP service
* (presumably, mirroring one that will be reachable in a live environment).
*
* It's important to remember that any custom endpoints defined here
* will only be available in development, as lineman only builds
* static assets, it can't run server-side code.
*
* This file can be very useful for rapid prototyping or even organically
* defining a spec based on the needs of the client code that emerge.
*
*/
module.exports = {
drawRoutes: function(app) {
// app.get('/api/greeting/:message', function(req, res){
// res.json({ message: "OK, "+req.params.message });
// });
}
};

View File

@@ -0,0 +1,9 @@
{
"framework" : "jasmine",
"launch_in_dev" : ["Chrome"],
"launch_in_ci" : ["PhantomJS"],
"src_files" : [
"generated/js/app.js",
"generated/js/spec.js"
]
}

15
frontend/package.json Normal file
View File

@@ -0,0 +1,15 @@
{
"name": "frontend",
"description": "Frontend for wrestlingdev",
"version": "0.0.1",
"private": true,
"author": "Jacob Cody Wimer",
"devDependencies": {
"lineman": "~0.36.6"
},
"scripts": {
"start": "lineman run",
"test": "lineman spec-ci",
"production": "lineman clean build && npm i express@3 && node -e \"var e = require('express'), a = e(); a.use(e.static('dist/')); a.listen(process.env.PORT)\""
}
}

View File

@@ -0,0 +1,4 @@
describe(".helloText", function(){
When(function(){ this.result = helloText(); });
Then(function(){ expect(this.result).toEqual("Hello, World!"); });
});

View File

@@ -0,0 +1,2 @@
window.context = window.describe;
window.xcontext = window.xdescribe;

View File

@@ -0,0 +1,433 @@
/* jasmine-fixture - 1.3.2
* Makes injecting HTML snippets into the DOM easy & clean!
* https://github.com/searls/jasmine-fixture
*/
(function() {
var createHTMLBlock,
__slice = [].slice;
(function($) {
var ewwSideEffects, jasmineFixture, originalAffix, originalJasmineDotFixture, originalJasmineFixture, root, _, _ref;
root = (1, eval)('this');
originalJasmineFixture = root.jasmineFixture;
originalJasmineDotFixture = (_ref = root.jasmine) != null ? _ref.fixture : void 0;
originalAffix = root.affix;
_ = function(list) {
return {
inject: function(iterator, memo) {
var item, _i, _len, _results;
_results = [];
for (_i = 0, _len = list.length; _i < _len; _i++) {
item = list[_i];
_results.push(memo = iterator(memo, item));
}
return _results;
}
};
};
root.jasmineFixture = function($) {
var $whatsTheRootOf, affix, create, jasmineFixture, noConflict;
affix = function(selectorOptions) {
return create.call(this, selectorOptions, true);
};
create = function(selectorOptions, attach) {
var $top;
$top = null;
_(selectorOptions.split(/[ ](?![^\{]*\})(?=[^\]]*?(?:\[|$))/)).inject(function($parent, elementSelector) {
var $el;
if (elementSelector === ">") {
return $parent;
}
$el = createHTMLBlock($, elementSelector);
if (attach || $top) {
$el.appendTo($parent);
}
$top || ($top = $el);
return $el;
}, $whatsTheRootOf(this));
return $top;
};
noConflict = function() {
var currentJasmineFixture, _ref1;
currentJasmineFixture = jasmine.fixture;
root.jasmineFixture = originalJasmineFixture;
if ((_ref1 = root.jasmine) != null) {
_ref1.fixture = originalJasmineDotFixture;
}
root.affix = originalAffix;
return currentJasmineFixture;
};
$whatsTheRootOf = function(that) {
if ((that != null ? that.jquery : void 0) != null) {
return that;
} else if ($('#jasmine_content').length > 0) {
return $('#jasmine_content');
} else {
return $('<div id="jasmine_content"></div>').appendTo('body');
}
};
jasmineFixture = {
affix: affix,
create: create,
noConflict: noConflict
};
ewwSideEffects(jasmineFixture);
return jasmineFixture;
};
ewwSideEffects = function(jasmineFixture) {
var _ref1;
if ((_ref1 = root.jasmine) != null) {
_ref1.fixture = jasmineFixture;
}
$.fn.affix = root.affix = jasmineFixture.affix;
return afterEach(function() {
return $('#jasmine_content').remove();
});
};
if ($) {
return jasmineFixture = root.jasmineFixture($);
} else {
return root.affix = function() {
var nowJQueryExists;
nowJQueryExists = window.jQuery || window.$;
if (nowJQueryExists != null) {
jasmineFixture = root.jasmineFixture(nowJQueryExists);
return affix.call.apply(affix, [this].concat(__slice.call(arguments)));
} else {
throw new Error("jasmine-fixture requires jQuery to be defined at window.jQuery or window.$");
}
};
}
})(window.jQuery || window.$);
createHTMLBlock = (function() {
var bindData, bindEvents, parseAttributes, parseClasses, parseContents, parseEnclosure, parseReferences, parseVariableScope, regAttr, regAttrDfn, regAttrs, regCBrace, regClass, regClasses, regData, regDatas, regEvent, regEvents, regExclamation, regId, regReference, regTag, regTagNotContent, regZenTagDfn;
createHTMLBlock = function($, ZenObject, data, functions, indexes) {
var ZenCode, arr, block, blockAttrs, blockClasses, blockHTML, blockId, blockTag, blocks, el, el2, els, forScope, indexName, inner, len, obj, origZenCode, paren, result, ret, zc, zo;
if ($.isPlainObject(ZenObject)) {
ZenCode = ZenObject.main;
} else {
ZenCode = ZenObject;
ZenObject = {
main: ZenCode
};
}
origZenCode = ZenCode;
if (indexes === undefined) {
indexes = {};
}
if (ZenCode.charAt(0) === "!" || $.isArray(data)) {
if ($.isArray(data)) {
forScope = ZenCode;
} else {
obj = parseEnclosure(ZenCode, "!");
obj = obj.substring(obj.indexOf(":") + 1, obj.length - 1);
forScope = parseVariableScope(ZenCode);
}
while (forScope.charAt(0) === "@") {
forScope = parseVariableScope("!for:!" + parseReferences(forScope, ZenObject));
}
zo = ZenObject;
zo.main = forScope;
el = $();
if (ZenCode.substring(0, 5) === "!for:" || $.isArray(data)) {
if (!$.isArray(data) && obj.indexOf(":") > 0) {
indexName = obj.substring(0, obj.indexOf(":"));
obj = obj.substr(obj.indexOf(":") + 1);
}
arr = ($.isArray(data) ? data : data[obj]);
zc = zo.main;
if ($.isArray(arr) || $.isPlainObject(arr)) {
$.map(arr, function(value, index) {
var next;
zo.main = zc;
if (indexName !== undefined) {
indexes[indexName] = index;
}
if (!$.isPlainObject(value)) {
value = {
value: value
};
}
next = createHTMLBlock($, zo, value, functions, indexes);
if (el.length !== 0) {
return $.each(next, function(index, value) {
return el.push(value);
});
}
});
}
if (!$.isArray(data)) {
ZenCode = ZenCode.substr(obj.length + 6 + forScope.length);
} else {
ZenCode = "";
}
} else if (ZenCode.substring(0, 4) === "!if:") {
result = parseContents("!" + obj + "!", data, indexes);
if (result !== "undefined" || result !== "false" || result !== "") {
el = createHTMLBlock($, zo, data, functions, indexes);
}
ZenCode = ZenCode.substr(obj.length + 5 + forScope.length);
}
ZenObject.main = ZenCode;
} else if (ZenCode.charAt(0) === "(") {
paren = parseEnclosure(ZenCode, "(", ")");
inner = paren.substring(1, paren.length - 1);
ZenCode = ZenCode.substr(paren.length);
zo = ZenObject;
zo.main = inner;
el = createHTMLBlock($, zo, data, functions, indexes);
} else {
blocks = ZenCode.match(regZenTagDfn);
block = blocks[0];
if (block.length === 0) {
return "";
}
if (block.indexOf("@") >= 0) {
ZenCode = parseReferences(ZenCode, ZenObject);
zo = ZenObject;
zo.main = ZenCode;
return createHTMLBlock($, zo, data, functions, indexes);
}
block = parseContents(block, data, indexes);
blockClasses = parseClasses($, block);
if (regId.test(block)) {
blockId = regId.exec(block)[1];
}
blockAttrs = parseAttributes(block, data);
blockTag = (block.charAt(0) === "{" ? "span" : "div");
if (ZenCode.charAt(0) !== "#" && ZenCode.charAt(0) !== "." && ZenCode.charAt(0) !== "{") {
blockTag = regTag.exec(block)[1];
}
if (block.search(regCBrace) !== -1) {
blockHTML = block.match(regCBrace)[1];
}
blockAttrs = $.extend(blockAttrs, {
id: blockId,
"class": blockClasses,
html: blockHTML
});
el = $("<" + blockTag + ">", blockAttrs);
el.attr(blockAttrs);
el = bindEvents(block, el, functions);
el = bindData(block, el, data);
ZenCode = ZenCode.substr(blocks[0].length);
ZenObject.main = ZenCode;
}
if (ZenCode.length > 0) {
if (ZenCode.charAt(0) === ">") {
if (ZenCode.charAt(1) === "(") {
zc = parseEnclosure(ZenCode.substr(1), "(", ")");
ZenCode = ZenCode.substr(zc.length + 1);
} else if (ZenCode.charAt(1) === "!") {
obj = parseEnclosure(ZenCode.substr(1), "!");
forScope = parseVariableScope(ZenCode.substr(1));
zc = obj + forScope;
ZenCode = ZenCode.substr(zc.length + 1);
} else {
len = Math.max(ZenCode.indexOf("+"), ZenCode.length);
zc = ZenCode.substring(1, len);
ZenCode = ZenCode.substr(len);
}
zo = ZenObject;
zo.main = zc;
els = $(createHTMLBlock($, zo, data, functions, indexes));
els.appendTo(el);
}
if (ZenCode.charAt(0) === "+") {
zo = ZenObject;
zo.main = ZenCode.substr(1);
el2 = createHTMLBlock($, zo, data, functions, indexes);
$.each(el2, function(index, value) {
return el.push(value);
});
}
}
ret = el;
return ret;
};
bindData = function(ZenCode, el, data) {
var datas, i, split;
if (ZenCode.search(regDatas) === 0) {
return el;
}
datas = ZenCode.match(regDatas);
if (datas === null) {
return el;
}
i = 0;
while (i < datas.length) {
split = regData.exec(datas[i]);
if (split[3] === undefined) {
$(el).data(split[1], data[split[1]]);
} else {
$(el).data(split[1], data[split[3]]);
}
i++;
}
return el;
};
bindEvents = function(ZenCode, el, functions) {
var bindings, fn, i, split;
if (ZenCode.search(regEvents) === 0) {
return el;
}
bindings = ZenCode.match(regEvents);
if (bindings === null) {
return el;
}
i = 0;
while (i < bindings.length) {
split = regEvent.exec(bindings[i]);
if (split[2] === undefined) {
fn = functions[split[1]];
} else {
fn = functions[split[2]];
}
$(el).bind(split[1], fn);
i++;
}
return el;
};
parseAttributes = function(ZenBlock, data) {
var attrStrs, attrs, i, parts;
if (ZenBlock.search(regAttrDfn) === -1) {
return undefined;
}
attrStrs = ZenBlock.match(regAttrDfn);
attrs = {};
i = 0;
while (i < attrStrs.length) {
parts = regAttr.exec(attrStrs[i]);
attrs[parts[1]] = "";
if (parts[3] !== undefined) {
attrs[parts[1]] = parseContents(parts[3], data);
}
i++;
}
return attrs;
};
parseClasses = function($, ZenBlock) {
var classes, clsString, i;
ZenBlock = ZenBlock.match(regTagNotContent)[0];
if (ZenBlock.search(regClasses) === -1) {
return undefined;
}
classes = ZenBlock.match(regClasses);
clsString = "";
i = 0;
while (i < classes.length) {
clsString += " " + regClass.exec(classes[i])[1];
i++;
}
return $.trim(clsString);
};
parseContents = function(ZenBlock, data, indexes) {
var html;
if (indexes === undefined) {
indexes = {};
}
html = ZenBlock;
if (data === undefined) {
return html;
}
while (regExclamation.test(html)) {
html = html.replace(regExclamation, function(str, str2) {
var begChar, fn, val;
begChar = "";
if (str.indexOf("!for:") > 0 || str.indexOf("!if:") > 0) {
return str;
}
if (str.charAt(0) !== "!") {
begChar = str.charAt(0);
str = str.substring(2, str.length - 1);
}
fn = new Function("data", "indexes", "var r=undefined;" + "with(data){try{r=" + str + ";}catch(e){}}" + "with(indexes){try{if(r===undefined)r=" + str + ";}catch(e){}}" + "return r;");
val = unescape(fn(data, indexes));
return begChar + val;
});
}
html = html.replace(/\\./g, function(str) {
return str.charAt(1);
});
return unescape(html);
};
parseEnclosure = function(ZenCode, open, close, count) {
var index, ret;
if (close === undefined) {
close = open;
}
index = 1;
if (count === undefined) {
count = (ZenCode.charAt(0) === open ? 1 : 0);
}
if (count === 0) {
return;
}
while (count > 0 && index < ZenCode.length) {
if (ZenCode.charAt(index) === close && ZenCode.charAt(index - 1) !== "\\") {
count--;
} else {
if (ZenCode.charAt(index) === open && ZenCode.charAt(index - 1) !== "\\") {
count++;
}
}
index++;
}
ret = ZenCode.substring(0, index);
return ret;
};
parseReferences = function(ZenCode, ZenObject) {
ZenCode = ZenCode.replace(regReference, function(str) {
var fn;
str = str.substr(1);
fn = new Function("objs", "var r=\"\";" + "with(objs){try{" + "r=" + str + ";" + "}catch(e){}}" + "return r;");
return fn(ZenObject, parseReferences);
});
return ZenCode;
};
parseVariableScope = function(ZenCode) {
var forCode, rest, tag;
if (ZenCode.substring(0, 5) !== "!for:" && ZenCode.substring(0, 4) !== "!if:") {
return undefined;
}
forCode = parseEnclosure(ZenCode, "!");
ZenCode = ZenCode.substr(forCode.length);
if (ZenCode.charAt(0) === "(") {
return parseEnclosure(ZenCode, "(", ")");
}
tag = ZenCode.match(regZenTagDfn)[0];
ZenCode = ZenCode.substr(tag.length);
if (ZenCode.length === 0 || ZenCode.charAt(0) === "+") {
return tag;
} else if (ZenCode.charAt(0) === ">") {
rest = "";
rest = parseEnclosure(ZenCode.substr(1), "(", ")", 1);
return tag + ">" + rest;
}
return undefined;
};
regZenTagDfn = /([#\.\@]?[\w-]+|\[([\w-!?=:"']+(="([^"]|\\")+")? {0,})+\]|\~[\w$]+=[\w$]+|&[\w$]+(=[\w$]+)?|[#\.\@]?!([^!]|\\!)+!){0,}(\{([^\}]|\\\})+\})?/i;
regTag = /(\w+)/i;
regId = /(?:^|\b)#([\w-!]+)/i;
regTagNotContent = /((([#\.]?[\w-]+)?(\[([\w!]+(="([^"]|\\")+")? {0,})+\])?)+)/i;
/*
See lookahead syntax (?!) at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp
*/
regClasses = /(\.[\w-]+)(?!["\w])/g;
regClass = /\.([\w-]+)/i;
regReference = /(@[\w$_][\w$_\d]+)/i;
regAttrDfn = /(\[([\w-!]+(="?([^"]|\\")+"?)? {0,})+\])/ig;
regAttrs = /([\w-!]+(="([^"]|\\")+")?)/g;
regAttr = /([\w-!]+)(="?((([\w]+(\[.*?\])+)|[^"\]]|\\")+)"?)?/i;
regCBrace = /\{(([^\}]|\\\})+)\}/i;
regExclamation = /(?:([^\\]|^))!([^!]|\\!)+!/g;
regEvents = /\~[\w$]+(=[\w$]+)?/g;
regEvent = /\~([\w$]+)=([\w$]+)/i;
regDatas = /&[\w$]+(=[\w$]+)?/g;
regData = /&([\w$]+)(=([\w$]+))?/i;
return createHTMLBlock;
})();
}).call(this);

View File

@@ -0,0 +1,373 @@
/* jasmine-given - 2.6.3
* Adds a Given-When-Then DSL to jasmine as an alternative style for specs
* https://github.com/searls/jasmine-given
*/
/* jasmine-matcher-wrapper - 0.0.3
* Wraps Jasmine 1.x matchers for use with Jasmine 2
* https://github.com/testdouble/jasmine-matcher-wrapper
*/
(function() {
var __hasProp = {}.hasOwnProperty,
__slice = [].slice;
(function(jasmine) {
var comparatorFor, createMatcher;
if (jasmine == null) {
return typeof console !== "undefined" && console !== null ? console.warn("jasmine was not found. Skipping jasmine-matcher-wrapper. Verify your script load order.") : void 0;
}
if (jasmine.matcherWrapper != null) {
return;
}
jasmine.matcherWrapper = {
wrap: function(matchers) {
var matcher, name, wrappedMatchers;
if (jasmine.addMatchers == null) {
return matchers;
}
wrappedMatchers = {};
for (name in matchers) {
if (!__hasProp.call(matchers, name)) continue;
matcher = matchers[name];
wrappedMatchers[name] = createMatcher(name, matcher);
}
return wrappedMatchers;
}
};
createMatcher = function(name, matcher) {
return function() {
return {
compare: comparatorFor(matcher, false),
negativeCompare: comparatorFor(matcher, true)
};
};
};
return comparatorFor = function(matcher, isNot) {
return function() {
var actual, context, message, params, pass, _ref;
actual = arguments[0], params = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
context = {
actual: actual,
isNot: isNot
};
pass = matcher.apply(context, params);
if (isNot) {
pass = !pass;
}
if (!pass) {
message = (_ref = context.message) != null ? _ref.apply(context, params) : void 0;
}
return {
pass: pass,
message: message
};
};
};
})(jasmine || getJasmineRequireObj());
}).call(this);
(function() {
var __slice = [].slice;
(function(jasmine) {
var Waterfall, additionalInsightsForErrorMessage, apparentReferenceError, attemptedEquality, cloneArray, comparisonInsight, currentSpec, declareJasmineSpec, deepEqualsNotice, doneWrapperFor, errorWithRemovedLines, evalInContextOfSpec, finalStatementFrom, getBlock, invariantList, mostRecentExpectations, mostRecentStacks, mostRecentlyUsed, o, root, stringifyExpectation, wasComparison, whenList, wrapAsExpectations;
mostRecentlyUsed = null;
root = (1, eval)('this');
currentSpec = null;
beforeEach(function() {
return currentSpec = this;
});
root.Given = function() {
mostRecentlyUsed = root.Given;
return beforeEach(getBlock(arguments));
};
whenList = [];
root.When = function() {
var b;
mostRecentlyUsed = root.When;
b = getBlock(arguments);
beforeEach(function() {
return whenList.push(b);
});
return afterEach(function() {
return whenList.pop();
});
};
invariantList = [];
root.Invariant = function() {
var invariantBehavior;
mostRecentlyUsed = root.Invariant;
invariantBehavior = getBlock(arguments);
beforeEach(function() {
return invariantList.push(invariantBehavior);
});
return afterEach(function() {
return invariantList.pop();
});
};
getBlock = function(thing) {
var assignResultTo, setupFunction;
setupFunction = o(thing).firstThat(function(arg) {
return o(arg).isFunction();
});
assignResultTo = o(thing).firstThat(function(arg) {
return o(arg).isString();
});
return doneWrapperFor(setupFunction, function(done) {
var context, result;
context = currentSpec;
result = setupFunction.call(context, done);
if (assignResultTo) {
if (!context[assignResultTo]) {
return context[assignResultTo] = result;
} else {
throw new Error("Unfortunately, the variable '" + assignResultTo + "' is already assigned to: " + context[assignResultTo]);
}
}
});
};
mostRecentExpectations = null;
mostRecentStacks = null;
declareJasmineSpec = function(specArgs, itFunction) {
var expectationFunction, expectations, label, stacks;
if (itFunction == null) {
itFunction = it;
}
label = o(specArgs).firstThat(function(arg) {
return o(arg).isString();
});
expectationFunction = o(specArgs).firstThat(function(arg) {
return o(arg).isFunction();
});
mostRecentlyUsed = root.subsequentThen;
mostRecentExpectations = expectations = [expectationFunction];
mostRecentStacks = stacks = [errorWithRemovedLines("failed expectation", 3)];
itFunction("then " + (label != null ? label : stringifyExpectation(expectations)), doneWrapperFor(expectationFunction, function(jasmineDone) {
var userCommands;
userCommands = [].concat(whenList, invariantList, wrapAsExpectations(expectations, stacks));
return new Waterfall(userCommands, jasmineDone).flow();
}));
return {
Then: subsequentThen,
And: subsequentThen
};
};
wrapAsExpectations = function(expectations, stacks) {
var expectation, i, _i, _len, _results;
_results = [];
for (i = _i = 0, _len = expectations.length; _i < _len; i = ++_i) {
expectation = expectations[i];
_results.push((function(expectation, i) {
return doneWrapperFor(expectation, function(maybeDone) {
return expect(expectation).not.toHaveReturnedFalseFromThen(currentSpec, i + 1, stacks[i], maybeDone);
});
})(expectation, i));
}
return _results;
};
doneWrapperFor = function(func, toWrap) {
if (func.length === 0) {
return function() {
return toWrap();
};
} else {
return function(done) {
return toWrap(done);
};
}
};
root.Then = function() {
return declareJasmineSpec(arguments);
};
root.Then.only = function() {
return declareJasmineSpec(arguments, it.only);
};
root.subsequentThen = function(additionalExpectation) {
mostRecentExpectations.push(additionalExpectation);
mostRecentStacks.push(errorWithRemovedLines("failed expectation", 3));
return this;
};
errorWithRemovedLines = function(msg, n) {
var error, lines, stack, _ref;
if (stack = new Error(msg).stack) {
_ref = stack.split("\n"), error = _ref[0], lines = 2 <= _ref.length ? __slice.call(_ref, 1) : [];
return "" + error + "\n" + (lines.slice(n).join("\n"));
}
};
mostRecentlyUsed = root.Given;
root.And = function() {
return mostRecentlyUsed.apply(this, jasmine.util.argsToArray(arguments));
};
o = function(thing) {
return {
isFunction: function() {
return Object.prototype.toString.call(thing) === "[object Function]";
},
isString: function() {
return Object.prototype.toString.call(thing) === "[object String]";
},
firstThat: function(test) {
var i;
i = 0;
while (i < thing.length) {
if (test(thing[i]) === true) {
return thing[i];
}
i++;
}
return void 0;
}
};
};
Waterfall = (function() {
function Waterfall(functions, finalCallback) {
if (functions == null) {
functions = [];
}
this.finalCallback = finalCallback != null ? finalCallback : function() {};
this.functions = cloneArray(functions);
}
Waterfall.prototype.flow = function() {
var func,
_this = this;
if (this.functions.length === 0) {
return this.finalCallback();
}
func = this.functions.shift();
if (func.length > 0) {
return func(function() {
return _this.flow();
});
} else {
func();
return this.flow();
}
};
return Waterfall;
})();
cloneArray = function(a) {
return a.slice(0);
};
jasmine._given = {
matchers: {
toHaveReturnedFalseFromThen: function(context, n, stackTrace, done) {
var e, exception, result;
result = false;
exception = void 0;
try {
result = this.actual.call(context, done);
} catch (_error) {
e = _error;
exception = e;
}
this.message = function() {
var msg, stringyExpectation;
stringyExpectation = stringifyExpectation(this.actual);
msg = "Then clause" + (n > 1 ? " #" + n : "") + " `" + stringyExpectation + "` failed by ";
if (exception) {
msg += "throwing: " + exception.toString();
} else {
msg += "returning false";
}
msg += additionalInsightsForErrorMessage(stringyExpectation);
if (stackTrace != null) {
msg += "\n\n" + stackTrace;
}
return msg;
};
return result === false;
}
},
__Waterfall__: Waterfall
};
stringifyExpectation = function(expectation) {
var matches;
matches = expectation.toString().replace(/\n/g, '').match(/function\s?\(.*\)\s?{\s*(return\s+)?(.*?)(;)?\s*}/i);
if (matches && matches.length >= 3) {
return matches[2].replace(/\s+/g, ' ');
} else {
return "";
}
};
additionalInsightsForErrorMessage = function(expectationString) {
var comparison, expectation;
expectation = finalStatementFrom(expectationString);
if (comparison = wasComparison(expectation)) {
return comparisonInsight(expectation, comparison);
} else {
return "";
}
};
finalStatementFrom = function(expectationString) {
var multiStatement;
if (multiStatement = expectationString.match(/.*return (.*)/)) {
return multiStatement[multiStatement.length - 1];
} else {
return expectationString;
}
};
wasComparison = function(expectation) {
var comparator, comparison, left, right, s;
if (comparison = expectation.match(/(.*) (===|!==|==|!=|>|>=|<|<=) (.*)/)) {
s = comparison[0], left = comparison[1], comparator = comparison[2], right = comparison[3];
return {
left: left,
comparator: comparator,
right: right
};
}
};
comparisonInsight = function(expectation, comparison) {
var left, msg, right;
left = evalInContextOfSpec(comparison.left);
right = evalInContextOfSpec(comparison.right);
if (apparentReferenceError(left) && apparentReferenceError(right)) {
return "";
}
msg = "\n\nThis comparison was detected:\n " + expectation + "\n " + left + " " + comparison.comparator + " " + right;
if (attemptedEquality(left, right, comparison.comparator)) {
msg += "\n\n" + (deepEqualsNotice(comparison.left, comparison.right));
}
return msg;
};
apparentReferenceError = function(result) {
return /^<Error: "ReferenceError/.test(result);
};
evalInContextOfSpec = function(operand) {
var e;
try {
return (function() {
return eval(operand);
}).call(currentSpec);
} catch (_error) {
e = _error;
return "<Error: \"" + ((e != null ? typeof e.message === "function" ? e.message() : void 0 : void 0) || e) + "\">";
}
};
attemptedEquality = function(left, right, comparator) {
var _ref;
if (!(comparator === "==" || comparator === "===")) {
return false;
}
if (((_ref = jasmine.matchersUtil) != null ? _ref.equals : void 0) != null) {
return jasmine.matchersUtil.equals(left, right);
} else {
return jasmine.getEnv().equals_(left, right);
}
};
deepEqualsNotice = function(left, right) {
return "However, these items are deeply equal! Try an expectation like this instead:\n expect(" + left + ").toEqual(" + right + ")";
};
return beforeEach(function() {
if (jasmine.addMatchers != null) {
return jasmine.addMatchers(jasmine.matcherWrapper.wrap(jasmine._given.matchers));
} else {
return this.addMatchers(jasmine._given.matchers);
}
});
})(jasmine);
}).call(this);

View File

@@ -0,0 +1,98 @@
/* jasmine-only - 0.1.1
* Exclusivity spec helpers for jasmine: `describe.only` and `it.only`
* https://github.com/davemo/jasmine-only
*/
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
(function(jasmine) {
var describeOnly, env, itOnly, root;
root = (1, eval)('this');
env = jasmine.getEnv();
describeOnly = function(description, specDefinitions) {
var suite;
suite = new jasmine.Suite(this, description, null, this.currentSuite);
suite.exclusive_ = 1;
this.exclusive_ = Math.max(this.exclusive_, 1);
return this.describe_(suite, specDefinitions);
};
itOnly = function(description, func) {
var spec;
spec = this.it(description, func);
spec.exclusive_ = 2;
this.exclusive_ = 2;
return spec;
};
env.exclusive_ = 0;
env.describe = function(description, specDefinitions) {
var suite;
suite = new jasmine.Suite(this, description, null, this.currentSuite);
return this.describe_(suite, specDefinitions);
};
env.describe_ = function(suite, specDefinitions) {
var declarationError, e, parentSuite;
parentSuite = this.currentSuite;
if (parentSuite) {
parentSuite.add(suite);
} else {
this.currentRunner_.add(suite);
}
this.currentSuite = suite;
declarationError = null;
try {
specDefinitions.call(suite);
} catch (_error) {
e = _error;
declarationError = e;
}
if (declarationError) {
this.it("encountered a declaration exception", function() {
throw declarationError;
});
}
this.currentSuite = parentSuite;
return suite;
};
env.specFilter = function(spec) {
return this.exclusive_ <= spec.exclusive_;
};
env.describe.only = function() {
return describeOnly.apply(env, arguments);
};
env.it.only = function() {
return itOnly.apply(env, arguments);
};
root.describe.only = function(description, specDefinitions) {
return env.describe.only(description, specDefinitions);
};
root.it.only = function(description, func) {
return env.it.only(description, func);
};
root.iit = root.it.only;
root.ddescribe = root.describe.only;
jasmine.Spec = (function(_super) {
__extends(Spec, _super);
function Spec(env, suite, description) {
this.exclusive_ = suite.exclusive_;
Spec.__super__.constructor.call(this, env, suite, description);
}
return Spec;
})(jasmine.Spec);
return jasmine.Suite = (function(_super) {
__extends(Suite, _super);
function Suite(env, suite, specDefinitions, parentSuite) {
this.exclusive_ = parentSuite && parentSuite.exclusive_ || 0;
Suite.__super__.constructor.call(this, env, suite, specDefinitions, parentSuite);
}
return Suite;
})(jasmine.Suite);
})(jasmine);
}).call(this);

View File

@@ -0,0 +1,214 @@
/* jasmine-stealth - 0.0.17
* Makes Jasmine spies a bit more robust
* https://github.com/searls/jasmine-stealth
*/
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
(function() {
var Captor, fake, root, stubChainer, unfakes, whatToDoWhenTheSpyGetsCalled, _;
root = (1, eval)('this');
_ = function(obj) {
return {
each: function(iterator) {
var item, _i, _len, _results;
_results = [];
for (_i = 0, _len = obj.length; _i < _len; _i++) {
item = obj[_i];
_results.push(iterator(item));
}
return _results;
},
isFunction: function() {
return Object.prototype.toString.call(obj) === "[object Function]";
},
isString: function() {
return Object.prototype.toString.call(obj) === "[object String]";
}
};
};
root.spyOnConstructor = function(owner, classToFake, methodsToSpy) {
var fakeClass, spies;
if (methodsToSpy == null) {
methodsToSpy = [];
}
if (_(methodsToSpy).isString()) {
methodsToSpy = [methodsToSpy];
}
spies = {
constructor: jasmine.createSpy("" + classToFake + "'s constructor")
};
fakeClass = (function() {
function _Class() {
spies.constructor.apply(this, arguments);
}
return _Class;
})();
_(methodsToSpy).each(function(methodName) {
spies[methodName] = jasmine.createSpy("" + classToFake + "#" + methodName);
return fakeClass.prototype[methodName] = function() {
return spies[methodName].apply(this, arguments);
};
});
fake(owner, classToFake, fakeClass);
return spies;
};
unfakes = [];
afterEach(function() {
_(unfakes).each(function(u) {
return u();
});
return unfakes = [];
});
fake = function(owner, thingToFake, newThing) {
var originalThing;
originalThing = owner[thingToFake];
owner[thingToFake] = newThing;
return unfakes.push(function() {
return owner[thingToFake] = originalThing;
});
};
root.stubFor = root.spyOn;
jasmine.createStub = jasmine.createSpy;
jasmine.createStubObj = function(baseName, stubbings) {
var name, obj, stubbing;
if (stubbings.constructor === Array) {
return jasmine.createSpyObj(baseName, stubbings);
} else {
obj = {};
for (name in stubbings) {
stubbing = stubbings[name];
obj[name] = jasmine.createSpy(baseName + "." + name);
if (_(stubbing).isFunction()) {
obj[name].andCallFake(stubbing);
} else {
obj[name].andReturn(stubbing);
}
}
return obj;
}
};
whatToDoWhenTheSpyGetsCalled = function(spy) {
var matchesStub, priorPlan;
matchesStub = function(stubbing, args, context) {
switch (stubbing.type) {
case "args":
return jasmine.getEnv().equals_(stubbing.ifThis, jasmine.util.argsToArray(args));
case "context":
return jasmine.getEnv().equals_(stubbing.ifThis, context);
}
};
priorPlan = spy.plan;
return spy.andCallFake(function() {
var i, stubbing;
i = 0;
while (i < spy._stealth_stubbings.length) {
stubbing = spy._stealth_stubbings[i];
if (matchesStub(stubbing, arguments, this)) {
if (stubbing.satisfaction === "callFake") {
return stubbing.thenThat.apply(stubbing, arguments);
} else {
return stubbing.thenThat;
}
}
i++;
}
return priorPlan.apply(spy, arguments);
});
};
jasmine.Spy.prototype.whenContext = function(context) {
var spy;
spy = this;
spy._stealth_stubbings || (spy._stealth_stubbings = []);
whatToDoWhenTheSpyGetsCalled(spy);
return stubChainer(spy, "context", context);
};
jasmine.Spy.prototype.when = function() {
var ifThis, spy;
spy = this;
ifThis = jasmine.util.argsToArray(arguments);
spy._stealth_stubbings || (spy._stealth_stubbings = []);
whatToDoWhenTheSpyGetsCalled(spy);
return stubChainer(spy, "args", ifThis);
};
stubChainer = function(spy, type, ifThis) {
var addStubbing;
addStubbing = function(satisfaction) {
return function(thenThat) {
spy._stealth_stubbings.unshift({
type: type,
ifThis: ifThis,
satisfaction: satisfaction,
thenThat: thenThat
});
return spy;
};
};
return {
thenReturn: addStubbing("return"),
thenCallFake: addStubbing("callFake")
};
};
jasmine.Spy.prototype.mostRecentCallThat = function(callThat, context) {
var i;
i = this.calls.length - 1;
while (i >= 0) {
if (callThat.call(context || this, this.calls[i]) === true) {
return this.calls[i];
}
i--;
}
};
jasmine.Matchers.ArgThat = (function(_super) {
__extends(ArgThat, _super);
function ArgThat(matcher) {
this.matcher = matcher;
}
ArgThat.prototype.jasmineMatches = function(actual) {
return this.matcher(actual);
};
return ArgThat;
})(jasmine.Matchers.Any);
jasmine.Matchers.ArgThat.prototype.matches = jasmine.Matchers.ArgThat.prototype.jasmineMatches;
jasmine.argThat = function(expected) {
return new jasmine.Matchers.ArgThat(expected);
};
jasmine.Matchers.Capture = (function(_super) {
__extends(Capture, _super);
function Capture(captor) {
this.captor = captor;
}
Capture.prototype.jasmineMatches = function(actual) {
this.captor.value = actual;
return true;
};
return Capture;
})(jasmine.Matchers.Any);
jasmine.Matchers.Capture.prototype.matches = jasmine.Matchers.Capture.prototype.jasmineMatches;
Captor = (function() {
function Captor() {}
Captor.prototype.capture = function() {
return new jasmine.Matchers.Capture(this);
};
return Captor;
})();
return jasmine.captor = function() {
return new Captor();
};
})();
}).call(this);

0
frontend/tasks/.keep Normal file
View File

0
frontend/vendor/css/.keep vendored Normal file
View File

0
frontend/vendor/img/.keep vendored Normal file
View File

10
frontend/vendor/js/devise-min.js vendored Normal file
View File

@@ -0,0 +1,10 @@
// AngularDevise
// -------------------
// v1.2.1
//
// Copyright (c)2016 Justin Ridgewell
// Distributed under MIT license
//
// https://github.com/cloudspace/angular_devise
!function(a){"use strict";var b=a.module("Devise",[]);b.provider("AuthIntercept",function(){var a=!1;this.interceptAuth=function(b){return a=!!b||void 0===b,this},this.$get=["$rootScope","$q",function(b,c){return{responseError:function(d){var e=d.config.interceptAuth;if(e=!!e||a&&void 0===e,e&&401===d.status){var f=c.defer();return b.$broadcast("devise:unauthorized",d,f),f.reject(d),f.promise}return c.reject(d)}}}]}).config(["$httpProvider",function(a){a.interceptors.push("AuthIntercept")}]),b.provider("Auth",function(){function b(b,c,d){var h={method:f[b].toLowerCase(),url:e[b]};return c&&(g?(h.data={},h.data[g]=c):h.data=c),a.extend(h,d),h}function c(b,c){a.forEach(b,function(a,d){this[d+c]=function(a){return void 0===a?b[d]:(b[d]=a,this)}},this)}function d(a){return function(){return a}}var e={login:"/users/sign_in.json",logout:"/users/sign_out.json",register:"/users.json",sendResetPasswordInstructions:"/users/password.json",resetPassword:"/users/password.json"},f={login:"POST",logout:"DELETE",register:"POST",sendResetPasswordInstructions:"POST",resetPassword:"PUT"},g="user",h=function(a){return a.data};c.call(this,f,"Method"),c.call(this,e,"Path"),this.resourceName=function(a){return void 0===a?g:(g=a,this)},this.parse=function(a){return"function"!=typeof a?h:(h=a,this)},this.$get=["$q","$http","$rootScope",function(a,c,e){function f(a){return j._currentUser=a,a}function g(){f(null),j._promise=null}function i(a){return function(b){return e.$broadcast("devise:"+a,b),b}}var j={_currentUser:null,parse:h,_promise:null,reset:function(){g(),j.currentUser()},login:function(a,d){var e=arguments.length>0,g=j.isAuthenticated();return a=a||{},c(b("login",a,d)).then(j.parse).then(f).then(function(a){return e&&!g?i("new-session")(a):a}).then(i("login"))},logout:function(a){var e=d(j._currentUser);return c(b("logout",void 0,a)).then(g).then(e).then(i("logout"))},register:function(a,d){return a=a||{},c(b("register",a,d)).then(j.parse).then(f).then(i("new-registration"))},sendResetPasswordInstructions:function(a){return a=a||{},c(b("sendResetPasswordInstructions",a)).then(j.parse).then(i("send-reset-password-instructions-successfully"))},resetPassword:function(a){return a=a||{},c(b("resetPassword",a)).then(j.parse).then(f).then(i("reset-password-successfully"))},currentUser:function(){return j.isAuthenticated()?a.when(j._currentUser):(null===j._promise&&(j._promise=j.login()),j._promise)},isAuthenticated:function(){return!!j._currentUser}};return j}]})}(angular);

1343
frontend/vendor/js/underscore.js vendored Normal file

File diff suppressed because it is too large Load Diff

0
frontend/vendor/static/.keep vendored Normal file
View File

View File

@@ -3,7 +3,7 @@ FROM ruby:2.3.0
RUN apt-get update RUN apt-get update
RUN apt-get install -y build-essential RUN apt-get install -y build-essential
RUN apt-get install -y nodejs sqlite3 RUN apt-get install -y nodejs-legacy nodejs sqlite3 npm
ENV WRESTLINGDEV_SECRET_KEY_BASE 077cdbef5c2ccf22543fb17a67339f234306b7fa2e1e4463d851c444c10a5611829a2290b253da78339427f131571fac9a42c83d960b2d25ecc10a4a0a7ce1a2 ENV WRESTLINGDEV_SECRET_KEY_BASE 077cdbef5c2ccf22543fb17a67339f234306b7fa2e1e4463d851c444c10a5611829a2290b253da78339427f131571fac9a42c83d960b2d25ecc10a4a0a7ce1a2
ENV WRESTLINGDEV_DEVISE_SECRET_KEY 2f29d49db6704377ba263f7cb9db085b386bcb301c0cd501126a674686ab1a109754071165b08cd72af03cec4642a4dd04361c994462254dd5d85e9594e8b9aa ENV WRESTLINGDEV_DEVISE_SECRET_KEY 2f29d49db6704377ba263f7cb9db085b386bcb301c0cd501126a674686ab1a109754071165b08cd72af03cec4642a4dd04361c994462254dd5d85e9594e8b9aa
@@ -13,8 +13,13 @@ ADD Gemfile* /tmp/
WORKDIR /tmp WORKDIR /tmp
RUN bundle install --without production RUN bundle install --without production
RUN npm install -g lineman
RUN mkdir /rails RUN mkdir /rails
WORKDIR /rails WORKDIR /rails
ADD . /rails
VOLUME ["/rails"] VOLUME ["/rails"]
EXPOSE 3000 EXPOSE 3000

View File

@@ -4,7 +4,7 @@ FROM ruby:2.3.0
RUN apt-get update RUN apt-get update
RUN apt-get -y upgrade RUN apt-get -y upgrade
RUN DEBIAN_FRONTEND=noninteractive apt-get -y install build-essential libssl-dev libyaml-dev libreadline-dev openssl curl git-core zlib1g-dev bison libxml2-dev libxslt1-dev libcurl4-openssl-dev libsqlite3-dev sqlite3 wget apache2 apt-transport-https nodejs mysql-client postfix RUN DEBIAN_FRONTEND=noninteractive apt-get -y install build-essential libssl-dev libyaml-dev libreadline-dev openssl curl git-core zlib1g-dev bison libxml2-dev libxslt1-dev libcurl4-openssl-dev libsqlite3-dev sqlite3 wget apache2 apt-transport-https nodejs nodejs-legacy npm mysql-client postfix
#New Relic #New Relic
#RUN echo deb http://apt.newrelic.com/debian/ newrelic non-free >> /etc/apt/sources.list.d/newrelic.list #RUN echo deb http://apt.newrelic.com/debian/ newrelic non-free >> /etc/apt/sources.list.d/newrelic.list
@@ -50,6 +50,12 @@ COPY Gemfile Gemfile
COPY Gemfile.lock Gemfile.lock COPY Gemfile.lock Gemfile.lock
RUN bundle install --without test RUN bundle install --without test
#Cache node_modules
WORKDIR /tmp
COPY frontend/package.json package.json
RUN npm install
RUN npm install lineman
RUN npm install -g lineman
# Copy site into place. # Copy site into place.
RUN rm -rf /var/www RUN rm -rf /var/www
@@ -59,9 +65,13 @@ ENV WRESTLINGDEV_SECRET_KEY_BASE 077cdbef5c2ccf22543fb17a67339f234306b7fa2e1e446
ENV WRESTLINGDEV_DEVISE_SECRET_KEY 2f29d49db6704377ba263f7cb9db085b386bcb301c0cd501126a674686ab1a109754071165b08cd72af03cec4642a4dd04361c994462254dd5d85e9594e8b9aa ENV WRESTLINGDEV_DEVISE_SECRET_KEY 2f29d49db6704377ba263f7cb9db085b386bcb301c0cd501126a674686ab1a109754071165b08cd72af03cec4642a4dd04361c994462254dd5d85e9594e8b9aa
WORKDIR /var/www/ WORKDIR /var/www/
ADD . /var/www/ ADD . /var/www/
#Copy node_modules to /var/www
RUN mv /tmp/node_modules /var/www/frontend/node_modules
#RUN RAILS_ENV=production bundle exec rake db:migrate #RUN RAILS_ENV=production bundle exec rake db:migrate
RUN RAILS_ENV=production bundle exec rake assets:precompile RUN RAILS_ENV=production bundle exec rake assets:precompile
#RUN cp /var/www/frontend/dist/*.html /var/www/public/
# Update the default apache site with the config we created. # Update the default apache site with the config we created.
RUN rm /etc/apache2/sites-enabled/000-default.conf RUN rm /etc/apache2/sites-enabled/000-default.conf
@@ -75,6 +85,5 @@ RUN echo PassengerMinInstances 3 >> /etc/apache2/apache2.conf
RUN echo PassengerPreStart *:443 >> /etc/apache2/apache2.conf RUN echo PassengerPreStart *:443 >> /etc/apache2/apache2.conf
# By default, simply start apache. # By default, simply start apache.
CMD /usr/sbin/apache2ctl -D FOREGROUND CMD /usr/sbin/apache2ctl -D FOREGROUND

2
run-all-tests.sh Executable file
View File

@@ -0,0 +1,2 @@
rake db:migrate RAILS_ENV=test
rake test

View File

@@ -0,0 +1,7 @@
require 'test_helper'
class ApiControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View File

@@ -5,12 +5,12 @@ class MatchesControllerTest < ActionController::TestCase
setup do setup do
@tournament = Tournament.find(1) @tournament = Tournament.find(1)
@tournament.generateMatchups # @tournament.generateMatchups
@match = @tournament.matches.first @match = Match.where("tournament_id = ? and mat_id = ?",1,1).first
end end
def post_update def post_update
patch :update, id: @match.id, match: {w1: @match.w1, w2: @match.w2} patch :update, id: @match.id, match: {tournament_id: 1, mat_id: 1}
end end
def get_edit def get_edit

View File

@@ -5,7 +5,7 @@ class MatsControllerTest < ActionController::TestCase
setup do setup do
@tournament = Tournament.find(1) @tournament = Tournament.find(1)
@tournament.generateMatchups # @tournament.generateMatchups
@mat = mats(:one) @mat = mats(:one)
end end

View File

@@ -5,7 +5,7 @@ class SchoolsControllerTest < ActionController::TestCase
setup do setup do
@tournament = Tournament.find(1) @tournament = Tournament.find(1)
@tournament.generateMatchups # @tournament.generateMatchups
@school = @tournament.schools.first @school = @tournament.schools.first
end end

View File

@@ -5,7 +5,7 @@ class StaticPagesControllerTest < ActionController::TestCase
setup do setup do
@tournament = Tournament.find(1) @tournament = Tournament.find(1)
@tournament.generateMatchups # @tournament.generateMatchups
@school = @tournament.schools.first @school = @tournament.schools.first
end end

View File

@@ -5,7 +5,7 @@ include Devise::TestHelpers
setup do setup do
@tournament = Tournament.find(1) @tournament = Tournament.find(1)
@tournament.generateMatchups # @tournament.generateMatchups
@school = @tournament.schools.first @school = @tournament.schools.first
@wrestlers = @tournament.weights.first.wrestlers @wrestlers = @tournament.weights.first.wrestlers
@adjust = Teampointadjust.find(1) @adjust = Teampointadjust.find(1)

Some files were not shown because too many files have changed in this diff Show More