mirror of
https://github.com/jcwimer/wrestlingApp
synced 2026-03-25 01:14:43 +00:00
Compare commits
175 Commits
circleci-p
...
4accedbb43
| Author | SHA1 | Date | |
|---|---|---|---|
| 4accedbb43 | |||
| 2856060b11 | |||
| 68a7b214c9 | |||
| 1fcaec876f | |||
| 3e4317dbc5 | |||
| 44fb5388b4 | |||
| ed7186e5ce | |||
| 6e61a7245a | |||
| 4828d9b876 | |||
| 2d433b680a | |||
| 9c25a6cc39 | |||
| f32e711d2b | |||
| 010d9a5f6b | |||
| 91e1939e69 | |||
| 934b34d0b7 | |||
| 63b91f7ddd | |||
| dd0585ed55 | |||
| 735f7090b2 | |||
| 690e497654 | |||
| 54655a2ea9 | |||
| 5114ed7b08 | |||
| f6bc7aa1a4 | |||
| 3248fdf7ca | |||
| 60814fdd94 | |||
| cc62e1c2f1 | |||
| d57b2e6e6f | |||
| fd1a7c43ff | |||
| b241818c21 | |||
| 288cb6704e | |||
| c45ec8ab38 | |||
| e612a4b10e | |||
| 38785924ed | |||
| 275847befe | |||
| b5150a3a37 | |||
| 6adcc709e7 | |||
| bb3b05ee81 | |||
| 490bd762f6 | |||
| 210e763d4c | |||
| f3e0f5d4c5 | |||
| 50055fc278 | |||
| 49fbf6735d | |||
| 698576dac9 | |||
| e986ce225b | |||
| 15bf39014f | |||
| 13bb8067fb | |||
| 4f0f69223d | |||
| 7e6d7ddfbb | |||
| 6242100e01 | |||
| d34fd873c0 | |||
| a851436c0c | |||
| 5f049793c8 | |||
| fc43de71bb | |||
| 5219c2b1e3 | |||
| f18802a933 | |||
| f6ef471591 | |||
| f92faf4f5c | |||
| db440c0603 | |||
| 5d37e5e0d8 | |||
| ad8e486205 | |||
| bb548be81b | |||
| b1f8cc3532 | |||
| b974773289 | |||
| 1f18f338ff | |||
| 6cb523e350 | |||
| b108545034 | |||
| e46180e9ea | |||
| fc3623008b | |||
| 508dd493a1 | |||
| 92bd1ec3c9 | |||
| 87353da05e | |||
| 57baa3ea45 | |||
| 2eb38ce788 | |||
| e047383fe4 | |||
| 05b42dbf0e | |||
| f011dae730 | |||
| 1078dc9e97 | |||
| c133a8b051 | |||
| 1d0cff0e6f | |||
| 1ee886abd3 | |||
| 86bb0b8410 | |||
| c3480909a2 | |||
| bde2b6d8c4 | |||
| 288c144f53 | |||
| 371b44977f | |||
| eb56b9d16c | |||
| 6b57246080 | |||
| ffb7d8be5b | |||
| 22f5733160 | |||
| b5ab929270 | |||
| 1d646cb05d | |||
| c328bbd91c | |||
| d675337d7a | |||
| 2dccf8dd55 | |||
| 6eb71ef59e | |||
| 67bee921ab | |||
| 8672bdd73d | |||
| 9c1563febf | |||
| 994fc18365 | |||
| 645fb59e5b | |||
| 05acebbf5b | |||
| 9c5ac6c1aa | |||
| 85b0da6a30 | |||
| 907a2eadef | |||
| e6797fcce9 | |||
| add48b95c3 | |||
| 85701e194a | |||
| 4d3f93a109 | |||
| f9095d8c99 | |||
| a3724914aa | |||
| 6e712cd199 | |||
| a3391afe02 | |||
| cce2e5b5f8 | |||
| 2cd62bbbd5 | |||
| d6a273c964 | |||
| 78bd51cafb | |||
| ae70128479 | |||
| 9fec6c079f | |||
| 58d088907a | |||
| 7220ffe3c6 | |||
| 0c9349c871 | |||
| d42b683f67 | |||
| f0e8c99b9f | |||
| 6db1dacbb6 | |||
| eae2c6756c | |||
| 194fbca978 | |||
| 1c8e3af5f4 | |||
| b571bcc749 | |||
| a6cc05424c | |||
| efeea574ed | |||
| 54e755ba3a | |||
| 8430949a37 | |||
| 5ef27f19cc | |||
| 09651ff12e | |||
| c0ad06cea7 | |||
| ad259f00b5 | |||
| 7ee8abe81a | |||
| cc38c842e0 | |||
| f7ea68da17 | |||
| cb5f0e28ae | |||
| 873e5b9465 | |||
| df6a029ef1 | |||
| 03d884e672 | |||
| e1cba865b0 | |||
| e36de59971 | |||
| 329c01db79 | |||
| 4cdc9e7df1 | |||
| 1f43fdf8fa | |||
| f6aff5a753 | |||
| 3dabc16a82 | |||
| 9d51ef7b51 | |||
| 63b0541aa4 | |||
| 1e30344be8 | |||
| 683b2967af | |||
| 432903e7a9 | |||
| 537eccf04d | |||
| 89a695388a | |||
| 0aea26967a | |||
| 5677f4e944 | |||
| f5ddc6652d | |||
| 987c89b7d5 | |||
| b2ba1901df | |||
| 6c86f25add | |||
| ce063f5faa | |||
| 396e4be5b3 | |||
| 46919a2b1b | |||
| 55d122771c | |||
| e43f3253d4 | |||
| f720de0db6 | |||
| 44c9f947d7 | |||
| ee8d861bee | |||
| bdd80fc1d2 | |||
| db15e79c0f | |||
| 1f5aa304ff | |||
| 4522113396 | |||
| 7327902fe8 |
@@ -1,10 +0,0 @@
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
machine: true
|
||||
steps:
|
||||
- checkout
|
||||
# start proprietary DB using private Docker image
|
||||
# with credentials stored in the UI
|
||||
- run: |
|
||||
bash bin/run-tests-with-docker.sh
|
||||
6
.cursorrules
Normal file
6
.cursorrules
Normal file
@@ -0,0 +1,6 @@
|
||||
- If rails isn't installed use docker: docker run -it -v $(pwd):/rails wrestlingdev-dev <rails command>
|
||||
- If the docker image doesn't exist, use the build command: docker build -t wrestlingdev-dev -f deploy/rails-dev-Dockerfile .
|
||||
- If the Gemfile changes, you need to rebuild the docker image: docker build -t wrestlingdev-dev -f deploy/rails-dev-Dockerfile.
|
||||
- Do not add unnecessary comments to the code where you remove things.
|
||||
- Cypress tests are created for js tests. They can be found in cypress-tests/cypress
|
||||
- Cypress tests can be run with docker: bash cypress-tests/run-cypress-tests.sh
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -11,10 +11,18 @@ vendor/bundle/
|
||||
# Ignore the default SQLite database.
|
||||
db/*.sqlite3
|
||||
db/*.sqlite3-journal
|
||||
db/*.sqlite3-shm
|
||||
db/*.sqlite3-wal
|
||||
|
||||
# Ignore all logfiles and tempfiles.
|
||||
log/*.log
|
||||
log/*.log*
|
||||
tmp
|
||||
.rvmrc
|
||||
deploy/prod.env
|
||||
frontend/node_modules
|
||||
.aider*
|
||||
|
||||
# Ignore cypress test results
|
||||
cypress-tests/cypress/screenshots
|
||||
cypress-tests/cypress/videos
|
||||
|
||||
1
.ruby-gemset
Normal file
1
.ruby-gemset
Normal file
@@ -0,0 +1 @@
|
||||
wrestlingdev
|
||||
1
.ruby-version
Normal file
1
.ruby-version
Normal file
@@ -0,0 +1 @@
|
||||
ruby-3.2.0
|
||||
21
.travis.yml
21
.travis.yml
@@ -1,21 +0,0 @@
|
||||
sudo: required
|
||||
language: minimal
|
||||
services:
|
||||
- docker
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- docker-ce
|
||||
env:
|
||||
- DOCKER_COMPOSE_VERSION=1.22.0
|
||||
script:
|
||||
- bash bin/run-tests-with-docker.sh
|
||||
deploy:
|
||||
provider: heroku
|
||||
api_key:
|
||||
secure: WQnMF1v9J8n3z+Icx1Sp2tcu5bsIDwuCRgmGSEyFEl0aI3KsFxCpNWKEhHougkBxYRi7XXW1TZGGwRYb5VNf5UVG4xqlgJE7vm4ri3PjU2x/bLJb6tJq+WNrXoJNzfeyRqwXpfOYJT6n3/ak7lsZrVY2zSIuNTdQQ1oVWk33x9KNyr1RS/XmygJDnsG8n7dnz4xUi57F2w3hORVF3Lm3a63F9hoBcZjZUeMHzLPPhG4yySkpBe1oWtFk58ZSyqCSpcpbiQSSCxHiMrlSJ6GDZjUFDe+GIkx/P8by+MP0qcS2dw1w5yPZvsAATe826xP+LmcZX7g2LHJbIDu+ZwisQDbWfhpShvIkgtnhG95fAF7pv+md6VsLf3cTggtOYKHXDGBTO2nHDDuol/W7ZZHiVT5Da52MFdkJ/4TTgzqWmnlDmmJT6nAZKgGp/dcnslUHscwM1nnhJZZqbxbg8tIZ3Q9+hLjh9vikO76ujkIaseJ+fGcpzTl5SvwW7NfINzJPkVZsPQb6tYNs01iKVfLJ8xNKvUswKe3G3nvrbfJahgySZ0+4xDEjQbbaa63RjyOw06DAcN3SgMj0o1w66NGdd1GzloggN0mdUfXkn+mjP3okYh7zgPY1n+ZJ88BQYJoScS790g30pqxR1Tj0uR3+TEd3Qmp7McfXKlMJiMXX2mI=
|
||||
app: wrestlingapp
|
||||
on:
|
||||
repo: jcwimer/wrestlingApp
|
||||
branch: master
|
||||
run: rake db:migrate RAILS_ENV=production
|
||||
56
Gemfile
56
Gemfile
@@ -1,11 +1,21 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
ruby '2.6.5'
|
||||
ruby '3.2.0'
|
||||
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
|
||||
gem 'rails', '6.0.3.2'
|
||||
gem 'rails', '8.0.2'
|
||||
|
||||
# Added in rails 7.1
|
||||
gem 'rails-html-sanitizer'
|
||||
|
||||
# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
|
||||
gem "sprockets-rails"
|
||||
|
||||
# Reduces boot times through caching; required in config/boot.rb
|
||||
gem "bootsnap", require: false
|
||||
|
||||
# Use sqlite3 as the database for Active Record
|
||||
#gem 'sqlite3', '~> 1.3', '< 1.4', :group => :development
|
||||
gem 'sqlite3', :group => :development
|
||||
# Use sqlite3 version compatible with Rails 8
|
||||
gem 'sqlite3', ">= 2.1", :group => :development
|
||||
|
||||
# Use Uglifier as compressor for JavaScript assets
|
||||
gem 'uglifier'
|
||||
@@ -27,7 +37,7 @@ gem 'sdoc', :group => :doc
|
||||
gem 'spring', :group => :development
|
||||
|
||||
# Use ActiveModel has_secure_password
|
||||
# gem 'bcrypt', '~> 3.1.7'
|
||||
gem 'bcrypt', '~> 3.1.7'
|
||||
|
||||
# Use unicorn as the app server
|
||||
# gem 'unicorn'
|
||||
@@ -38,32 +48,48 @@ gem 'spring', :group => :development
|
||||
# Use debugger
|
||||
# gem 'debugger', group: [:development, :test]
|
||||
|
||||
|
||||
#Installed by me
|
||||
group :production do
|
||||
gem 'rails_12factor'
|
||||
gem 'mysql2'
|
||||
gem 'therubyracer'
|
||||
gem 'newrelic_rpm'
|
||||
gem 'dalli'
|
||||
end
|
||||
|
||||
gem 'devise'
|
||||
gem 'solid_cache'
|
||||
|
||||
gem 'influxdb-rails'
|
||||
# Authentication
|
||||
# gem 'devise' # Removed - replaced with Rails built-in authentication
|
||||
|
||||
# Role Management
|
||||
gem 'cancancan'
|
||||
gem 'round_robin_tournament'
|
||||
gem 'rb-readline'
|
||||
gem 'delayed_job_active_record'
|
||||
# Replacing Delayed Job with Solid Queue
|
||||
# gem 'delayed_job_active_record'
|
||||
gem 'solid_queue'
|
||||
gem 'solid_cable'
|
||||
gem 'puma'
|
||||
gem 'passenger'
|
||||
gem 'tzinfo-data'
|
||||
gem 'daemons'
|
||||
gem 'delayed_job_web'
|
||||
# Interface for viewing and managing background jobs
|
||||
# gem 'delayed_job_web'
|
||||
# Note: solid_queue-ui is not compatible with Rails 8.0 yet
|
||||
# We'll create a custom UI or wait for compatibility updates
|
||||
# gem 'solid_queue_ui', '~> 0.1.1'
|
||||
|
||||
group :development do
|
||||
gem 'rubocop'
|
||||
# gem 'rubocop'
|
||||
gem 'bullet'
|
||||
gem 'brakeman'
|
||||
gem 'hakiri'
|
||||
gem 'travis'
|
||||
gem 'bundler-audit'
|
||||
end
|
||||
|
||||
group :development, :test do
|
||||
gem 'mocha'
|
||||
# rails-controller-testing is needed for assert_template
|
||||
gem 'rails-controller-testing'
|
||||
end
|
||||
|
||||
gem 'font-awesome-sass'
|
||||
|
||||
|
||||
561
Gemfile.lock
561
Gemfile.lock
@@ -1,71 +1,93 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actioncable (6.0.3.2)
|
||||
actionpack (= 6.0.3.2)
|
||||
actioncable (8.0.2)
|
||||
actionpack (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
actionmailbox (6.0.3.2)
|
||||
actionpack (= 6.0.3.2)
|
||||
activejob (= 6.0.3.2)
|
||||
activerecord (= 6.0.3.2)
|
||||
activestorage (= 6.0.3.2)
|
||||
activesupport (= 6.0.3.2)
|
||||
mail (>= 2.7.1)
|
||||
actionmailer (6.0.3.2)
|
||||
actionpack (= 6.0.3.2)
|
||||
actionview (= 6.0.3.2)
|
||||
activejob (= 6.0.3.2)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (6.0.3.2)
|
||||
actionview (= 6.0.3.2)
|
||||
activesupport (= 6.0.3.2)
|
||||
rack (~> 2.0, >= 2.0.8)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actiontext (6.0.3.2)
|
||||
actionpack (= 6.0.3.2)
|
||||
activerecord (= 6.0.3.2)
|
||||
activestorage (= 6.0.3.2)
|
||||
activesupport (= 6.0.3.2)
|
||||
zeitwerk (~> 2.6)
|
||||
actionmailbox (8.0.2)
|
||||
actionpack (= 8.0.2)
|
||||
activejob (= 8.0.2)
|
||||
activerecord (= 8.0.2)
|
||||
activestorage (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
mail (>= 2.8.0)
|
||||
actionmailer (8.0.2)
|
||||
actionpack (= 8.0.2)
|
||||
actionview (= 8.0.2)
|
||||
activejob (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
mail (>= 2.8.0)
|
||||
rails-dom-testing (~> 2.2)
|
||||
actionpack (8.0.2)
|
||||
actionview (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (6.0.3.2)
|
||||
activesupport (= 6.0.3.2)
|
||||
rack (>= 2.2.4)
|
||||
rack-session (>= 1.0.1)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.2)
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
useragent (~> 0.16)
|
||||
actiontext (8.0.2)
|
||||
actionpack (= 8.0.2)
|
||||
activerecord (= 8.0.2)
|
||||
activestorage (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||
activejob (6.0.3.2)
|
||||
activesupport (= 6.0.3.2)
|
||||
erubi (~> 1.11)
|
||||
rails-dom-testing (~> 2.2)
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
activejob (8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (6.0.3.2)
|
||||
activesupport (= 6.0.3.2)
|
||||
activerecord (6.0.3.2)
|
||||
activemodel (= 6.0.3.2)
|
||||
activesupport (= 6.0.3.2)
|
||||
activestorage (6.0.3.2)
|
||||
actionpack (= 6.0.3.2)
|
||||
activejob (= 6.0.3.2)
|
||||
activerecord (= 6.0.3.2)
|
||||
marcel (~> 0.3.1)
|
||||
activesupport (6.0.3.2)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
tzinfo (~> 1.1)
|
||||
zeitwerk (~> 2.2, >= 2.2.2)
|
||||
addressable (2.4.0)
|
||||
ast (2.4.1)
|
||||
backports (3.18.2)
|
||||
bcrypt (3.1.16)
|
||||
brakeman (4.9.1)
|
||||
builder (3.2.4)
|
||||
bullet (6.1.0)
|
||||
activemodel (8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
activerecord (8.0.2)
|
||||
activemodel (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
timeout (>= 0.4.0)
|
||||
activestorage (8.0.2)
|
||||
actionpack (= 8.0.2)
|
||||
activejob (= 8.0.2)
|
||||
activerecord (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
marcel (~> 1.0)
|
||||
activesupport (8.0.2)
|
||||
base64
|
||||
benchmark (>= 0.3)
|
||||
bigdecimal
|
||||
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||
connection_pool (>= 2.2.5)
|
||||
drb
|
||||
i18n (>= 1.6, < 2)
|
||||
logger (>= 1.4.2)
|
||||
minitest (>= 5.1)
|
||||
securerandom (>= 0.3)
|
||||
tzinfo (~> 2.0, >= 2.0.5)
|
||||
uri (>= 0.13.1)
|
||||
base64 (0.2.0)
|
||||
bcrypt (3.1.20)
|
||||
benchmark (0.4.0)
|
||||
bigdecimal (3.1.9)
|
||||
bootsnap (1.18.4)
|
||||
msgpack (~> 1.2)
|
||||
brakeman (7.0.2)
|
||||
racc
|
||||
builder (3.3.0)
|
||||
bullet (8.0.3)
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.11)
|
||||
cancancan (3.1.0)
|
||||
bundler-audit (0.9.2)
|
||||
bundler (>= 1.2.0, < 3)
|
||||
thor (~> 1.0)
|
||||
cancancan (3.6.1)
|
||||
coffee-rails (5.0.0)
|
||||
coffee-script (>= 2.2.0)
|
||||
railties (>= 5.2.0)
|
||||
@@ -73,270 +95,263 @@ GEM
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.12.2)
|
||||
commander (4.4.6)
|
||||
highline (~> 1.7.2)
|
||||
concurrent-ruby (1.1.7)
|
||||
concurrent-ruby (1.3.5)
|
||||
connection_pool (2.5.0)
|
||||
crass (1.0.6)
|
||||
daemons (1.3.1)
|
||||
dalli (2.7.10)
|
||||
delayed_job (4.1.8)
|
||||
activesupport (>= 3.0, < 6.1)
|
||||
delayed_job_active_record (4.1.4)
|
||||
activerecord (>= 3.0, < 6.1)
|
||||
delayed_job (>= 3.0, < 5)
|
||||
delayed_job_web (1.4.3)
|
||||
activerecord (> 3.0.0)
|
||||
delayed_job (> 2.0.3)
|
||||
rack-protection (>= 1.5.5)
|
||||
sinatra (>= 1.4.4)
|
||||
devise (4.7.2)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
railties (>= 4.1.0)
|
||||
responders
|
||||
warden (~> 1.2.3)
|
||||
domain_name (0.5.20190701)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
erubi (1.9.0)
|
||||
ethon (0.12.0)
|
||||
ffi (>= 1.3.0)
|
||||
execjs (2.7.0)
|
||||
faraday (0.17.3)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
faraday_middleware (0.14.0)
|
||||
faraday (>= 0.7.4, < 1.0)
|
||||
ffi (1.13.1)
|
||||
gh (0.15.1)
|
||||
addressable (~> 2.4.0)
|
||||
backports
|
||||
faraday (~> 0.8)
|
||||
multi_json (~> 1.0)
|
||||
net-http-persistent (~> 2.9)
|
||||
net-http-pipeline
|
||||
globalid (0.4.2)
|
||||
activesupport (>= 4.2.0)
|
||||
hakiri (0.7.2)
|
||||
activesupport
|
||||
bundler
|
||||
commander
|
||||
i18n
|
||||
json
|
||||
rake
|
||||
rest-client
|
||||
terminal-table
|
||||
highline (1.7.10)
|
||||
http-accept (1.7.0)
|
||||
http-cookie (1.0.3)
|
||||
domain_name (~> 0.5)
|
||||
i18n (1.8.5)
|
||||
daemons (1.4.1)
|
||||
date (3.4.1)
|
||||
drb (2.2.1)
|
||||
erubi (1.13.1)
|
||||
et-orbi (1.2.11)
|
||||
tzinfo
|
||||
execjs (2.10.0)
|
||||
ffi (1.17.1-aarch64-linux-gnu)
|
||||
ffi (1.17.1-aarch64-linux-musl)
|
||||
ffi (1.17.1-arm-linux-gnu)
|
||||
ffi (1.17.1-arm-linux-musl)
|
||||
ffi (1.17.1-arm64-darwin)
|
||||
ffi (1.17.1-x86_64-darwin)
|
||||
ffi (1.17.1-x86_64-linux-gnu)
|
||||
ffi (1.17.1-x86_64-linux-musl)
|
||||
font-awesome-sass (6.7.2)
|
||||
sassc (~> 2.0)
|
||||
fugit (1.11.1)
|
||||
et-orbi (~> 1, >= 1.2.11)
|
||||
raabro (~> 1.4)
|
||||
globalid (1.2.1)
|
||||
activesupport (>= 6.1)
|
||||
i18n (1.14.7)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jbuilder (2.10.1)
|
||||
influxdb (0.8.1)
|
||||
influxdb-rails (1.0.3)
|
||||
influxdb (~> 0.6, >= 0.6.4)
|
||||
railties (>= 5.0)
|
||||
io-console (0.8.0)
|
||||
irb (1.15.2)
|
||||
pp (>= 0.6.0)
|
||||
rdoc (>= 4.0.0)
|
||||
reline (>= 0.4.2)
|
||||
jbuilder (2.13.0)
|
||||
actionview (>= 5.0.0)
|
||||
activesupport (>= 5.0.0)
|
||||
jquery-rails (4.4.0)
|
||||
jquery-rails (4.6.0)
|
||||
rails-dom-testing (>= 1, < 3)
|
||||
railties (>= 4.2.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
json (2.3.1)
|
||||
launchy (2.4.3)
|
||||
addressable (~> 2.3)
|
||||
libv8 (3.16.14.19)
|
||||
loofah (2.7.0)
|
||||
logger (1.7.0)
|
||||
loofah (2.24.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
mail (2.7.1)
|
||||
nokogiri (>= 1.12.0)
|
||||
mail (2.8.1)
|
||||
mini_mime (>= 0.1.1)
|
||||
marcel (0.3.3)
|
||||
mimemagic (~> 0.3.2)
|
||||
method_source (1.0.0)
|
||||
mime-types (3.3.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2020.0512)
|
||||
mimemagic (0.3.5)
|
||||
mini_mime (1.0.2)
|
||||
mini_portile2 (2.4.0)
|
||||
minitest (5.14.2)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.1.1)
|
||||
mustermann (1.1.1)
|
||||
ruby2_keywords (~> 0.0.1)
|
||||
mysql2 (0.5.3)
|
||||
net-http-persistent (2.9.4)
|
||||
net-http-pipeline (1.0.1)
|
||||
netrc (0.11.0)
|
||||
newrelic_rpm (6.12.0.367)
|
||||
nio4r (2.5.3)
|
||||
nokogiri (1.10.10)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
orm_adapter (0.5.0)
|
||||
parallel (1.19.2)
|
||||
parser (2.7.1.4)
|
||||
ast (~> 2.4.1)
|
||||
passenger (6.0.6)
|
||||
rack
|
||||
rake (>= 0.8.1)
|
||||
puma (4.3.6)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
marcel (1.0.4)
|
||||
mini_mime (1.1.5)
|
||||
minitest (5.25.5)
|
||||
mocha (2.7.1)
|
||||
ruby2_keywords (>= 0.0.5)
|
||||
msgpack (1.8.0)
|
||||
mysql2 (0.5.6)
|
||||
net-imap (0.5.6)
|
||||
date
|
||||
net-protocol
|
||||
net-pop (0.1.2)
|
||||
net-protocol
|
||||
net-protocol (0.2.2)
|
||||
timeout
|
||||
net-smtp (0.5.1)
|
||||
net-protocol
|
||||
nio4r (2.7.4)
|
||||
nokogiri (1.18.7-aarch64-linux-gnu)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.7-aarch64-linux-musl)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.7-arm-linux-gnu)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.7-arm-linux-musl)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.7-arm64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.7-x86_64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.7-x86_64-linux-gnu)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.7-x86_64-linux-musl)
|
||||
racc (~> 1.4)
|
||||
passenger (6.0.27)
|
||||
rack (>= 1.6.13)
|
||||
rackup (>= 1.0.1)
|
||||
rake (>= 12.3.3)
|
||||
pp (0.6.2)
|
||||
prettyprint
|
||||
prettyprint (0.2.0)
|
||||
psych (5.2.3)
|
||||
date
|
||||
stringio
|
||||
puma (6.6.0)
|
||||
nio4r (~> 2.0)
|
||||
pusher-client (0.6.2)
|
||||
json
|
||||
websocket (~> 1.0)
|
||||
rack (2.2.3)
|
||||
rack-protection (2.1.0)
|
||||
rack
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rails (6.0.3.2)
|
||||
actioncable (= 6.0.3.2)
|
||||
actionmailbox (= 6.0.3.2)
|
||||
actionmailer (= 6.0.3.2)
|
||||
actionpack (= 6.0.3.2)
|
||||
actiontext (= 6.0.3.2)
|
||||
actionview (= 6.0.3.2)
|
||||
activejob (= 6.0.3.2)
|
||||
activemodel (= 6.0.3.2)
|
||||
activerecord (= 6.0.3.2)
|
||||
activestorage (= 6.0.3.2)
|
||||
activesupport (= 6.0.3.2)
|
||||
bundler (>= 1.3.0)
|
||||
railties (= 6.0.3.2)
|
||||
sprockets-rails (>= 2.0.0)
|
||||
rails-dom-testing (2.0.3)
|
||||
activesupport (>= 4.2.0)
|
||||
raabro (1.4.0)
|
||||
racc (1.8.1)
|
||||
rack (3.1.12)
|
||||
rack-session (2.1.0)
|
||||
base64 (>= 0.1.0)
|
||||
rack (>= 3.0.0)
|
||||
rack-test (2.2.0)
|
||||
rack (>= 1.3)
|
||||
rackup (2.2.1)
|
||||
rack (>= 3)
|
||||
rails (8.0.2)
|
||||
actioncable (= 8.0.2)
|
||||
actionmailbox (= 8.0.2)
|
||||
actionmailer (= 8.0.2)
|
||||
actionpack (= 8.0.2)
|
||||
actiontext (= 8.0.2)
|
||||
actionview (= 8.0.2)
|
||||
activejob (= 8.0.2)
|
||||
activemodel (= 8.0.2)
|
||||
activerecord (= 8.0.2)
|
||||
activestorage (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 8.0.2)
|
||||
rails-controller-testing (1.0.5)
|
||||
actionpack (>= 5.0.1.rc1)
|
||||
actionview (>= 5.0.1.rc1)
|
||||
activesupport (>= 5.0.1.rc1)
|
||||
rails-dom-testing (2.2.0)
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.3.0)
|
||||
loofah (~> 2.3)
|
||||
rails-html-sanitizer (1.6.2)
|
||||
loofah (~> 2.21)
|
||||
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
||||
rails_12factor (0.0.3)
|
||||
rails_serve_static_assets
|
||||
rails_stdout_logging
|
||||
rails_serve_static_assets (0.0.5)
|
||||
rails_stdout_logging (0.0.5)
|
||||
railties (6.0.3.2)
|
||||
actionpack (= 6.0.3.2)
|
||||
activesupport (= 6.0.3.2)
|
||||
method_source
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.20.3, < 2.0)
|
||||
rainbow (3.0.0)
|
||||
rake (13.0.1)
|
||||
railties (8.0.2)
|
||||
actionpack (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
irb (~> 1.13)
|
||||
rackup (>= 1.0.0)
|
||||
rake (>= 12.2)
|
||||
thor (~> 1.0, >= 1.2.2)
|
||||
zeitwerk (~> 2.6)
|
||||
rake (13.2.1)
|
||||
rb-readline (0.5.5)
|
||||
rdoc (6.2.1)
|
||||
ref (2.0.0)
|
||||
regexp_parser (1.7.1)
|
||||
responders (3.0.1)
|
||||
actionpack (>= 5.0)
|
||||
railties (>= 5.0)
|
||||
rest-client (2.1.0)
|
||||
http-accept (>= 1.7.0, < 2.0)
|
||||
http-cookie (>= 1.0.2, < 2.0)
|
||||
mime-types (>= 1.16, < 4.0)
|
||||
netrc (~> 0.8)
|
||||
rexml (3.2.4)
|
||||
round_robin_tournament (0.0.1)
|
||||
rubocop (0.91.0)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.7.1.1)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 1.7)
|
||||
rexml
|
||||
rubocop-ast (>= 0.4.0, < 1.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 2.0)
|
||||
rubocop-ast (0.4.0)
|
||||
parser (>= 2.7.1.4)
|
||||
ruby-progressbar (1.10.1)
|
||||
ruby2_keywords (0.0.2)
|
||||
sdoc (1.1.0)
|
||||
rdoc (6.13.1)
|
||||
psych (>= 4.0.0)
|
||||
reline (0.6.1)
|
||||
io-console (~> 0.5)
|
||||
round_robin_tournament (0.1.2)
|
||||
ruby2_keywords (0.0.5)
|
||||
sassc (2.4.0)
|
||||
ffi (~> 1.9)
|
||||
sdoc (2.6.1)
|
||||
rdoc (>= 5.0)
|
||||
sinatra (2.1.0)
|
||||
mustermann (~> 1.0)
|
||||
rack (~> 2.2)
|
||||
rack-protection (= 2.1.0)
|
||||
tilt (~> 2.0)
|
||||
spring (2.1.1)
|
||||
sprockets (4.0.2)
|
||||
securerandom (0.4.1)
|
||||
solid_cable (3.0.7)
|
||||
actioncable (>= 7.2)
|
||||
activejob (>= 7.2)
|
||||
activerecord (>= 7.2)
|
||||
railties (>= 7.2)
|
||||
solid_cache (1.0.7)
|
||||
activejob (>= 7.2)
|
||||
activerecord (>= 7.2)
|
||||
railties (>= 7.2)
|
||||
solid_queue (1.1.4)
|
||||
activejob (>= 7.1)
|
||||
activerecord (>= 7.1)
|
||||
concurrent-ruby (>= 1.3.1)
|
||||
fugit (~> 1.11.0)
|
||||
railties (>= 7.1)
|
||||
thor (~> 1.3.1)
|
||||
spring (4.3.0)
|
||||
sprockets (4.2.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
sprockets-rails (3.2.2)
|
||||
actionpack (>= 4.0)
|
||||
activesupport (>= 4.0)
|
||||
rack (>= 2.2.4, < 4)
|
||||
sprockets-rails (3.5.2)
|
||||
actionpack (>= 6.1)
|
||||
activesupport (>= 6.1)
|
||||
sprockets (>= 3.0.0)
|
||||
sqlite3 (1.4.2)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
therubyracer (0.12.3)
|
||||
libv8 (~> 3.16.14.15)
|
||||
ref
|
||||
thor (1.0.1)
|
||||
thread_safe (0.3.6)
|
||||
tilt (2.0.10)
|
||||
travis (1.8.13)
|
||||
backports
|
||||
faraday (~> 0.9)
|
||||
faraday_middleware (~> 0.9, >= 0.9.1)
|
||||
gh (~> 0.13)
|
||||
highline (~> 1.6)
|
||||
launchy (~> 2.1)
|
||||
pusher-client (~> 0.4)
|
||||
typhoeus (~> 0.6, >= 0.6.8)
|
||||
sqlite3 (2.6.0-aarch64-linux-gnu)
|
||||
sqlite3 (2.6.0-aarch64-linux-musl)
|
||||
sqlite3 (2.6.0-arm-linux-gnu)
|
||||
sqlite3 (2.6.0-arm-linux-musl)
|
||||
sqlite3 (2.6.0-arm64-darwin)
|
||||
sqlite3 (2.6.0-x86_64-darwin)
|
||||
sqlite3 (2.6.0-x86_64-linux-gnu)
|
||||
sqlite3 (2.6.0-x86_64-linux-musl)
|
||||
stringio (3.1.6)
|
||||
thor (1.3.2)
|
||||
timeout (0.4.3)
|
||||
turbolinks (5.2.1)
|
||||
turbolinks-source (~> 5.2)
|
||||
turbolinks-source (5.2.0)
|
||||
typhoeus (0.8.0)
|
||||
ethon (>= 0.8.0)
|
||||
tzinfo (1.2.7)
|
||||
thread_safe (~> 0.1)
|
||||
tzinfo-data (1.2020.1)
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
tzinfo-data (1.2025.2)
|
||||
tzinfo (>= 1.0.0)
|
||||
uglifier (4.2.0)
|
||||
uglifier (4.2.1)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.7)
|
||||
unicode-display_width (1.7.0)
|
||||
uniform_notifier (1.13.0)
|
||||
warden (1.2.9)
|
||||
rack (>= 2.0.9)
|
||||
websocket (1.2.8)
|
||||
websocket-driver (0.7.3)
|
||||
uniform_notifier (1.16.0)
|
||||
uri (1.0.3)
|
||||
useragent (0.16.11)
|
||||
websocket-driver (0.7.7)
|
||||
base64
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.5)
|
||||
zeitwerk (2.4.0)
|
||||
zeitwerk (2.7.2)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
aarch64-linux-gnu
|
||||
aarch64-linux-musl
|
||||
arm-linux-gnu
|
||||
arm-linux-musl
|
||||
arm64-darwin
|
||||
x86_64-darwin
|
||||
x86_64-linux-gnu
|
||||
x86_64-linux-musl
|
||||
|
||||
DEPENDENCIES
|
||||
bcrypt (~> 3.1.7)
|
||||
bootsnap
|
||||
brakeman
|
||||
bullet
|
||||
bundler-audit
|
||||
cancancan
|
||||
coffee-rails
|
||||
daemons
|
||||
dalli
|
||||
delayed_job_active_record
|
||||
delayed_job_web
|
||||
devise
|
||||
hakiri
|
||||
font-awesome-sass
|
||||
influxdb-rails
|
||||
jbuilder
|
||||
jquery-rails
|
||||
mocha
|
||||
mysql2
|
||||
newrelic_rpm
|
||||
passenger
|
||||
puma
|
||||
rails (= 6.0.3.2)
|
||||
rails (= 8.0.2)
|
||||
rails-controller-testing
|
||||
rails-html-sanitizer
|
||||
rails_12factor
|
||||
rb-readline
|
||||
round_robin_tournament
|
||||
rubocop
|
||||
sdoc
|
||||
solid_cable
|
||||
solid_cache
|
||||
solid_queue
|
||||
spring
|
||||
sqlite3
|
||||
therubyracer
|
||||
travis
|
||||
sprockets-rails
|
||||
sqlite3 (>= 2.1)
|
||||
turbolinks
|
||||
tzinfo-data
|
||||
uglifier
|
||||
|
||||
RUBY VERSION
|
||||
ruby 2.6.5p114
|
||||
ruby 3.2.0p0
|
||||
|
||||
BUNDLED WITH
|
||||
2.0.2
|
||||
2.6.7
|
||||
|
||||
4
Procfile
4
Procfile
@@ -1,4 +0,0 @@
|
||||
worker: bundle exec bin/delayed_job -n 1 run
|
||||
#worker: bundle exec rake jobs:work
|
||||
#web: bundle exec puma -w 3 -t 5:5 -p ${PORT:-3000} -e ${RACK_ENV:-development}
|
||||
web: bundle exec passenger start -p $PORT --max-pool-size 2 --min-instances 2
|
||||
181
README.md
181
README.md
@@ -1,56 +1,177 @@
|
||||
# README
|
||||
This application is being created to run a wrestling tournament.
|
||||
|
||||
### Current master status
|
||||
[](https://travis-ci.org/jcwimer/wrestlingApp)
|
||||
|
||||
### Current development status
|
||||
[](https://travis-ci.org/jcwimer/wrestlingApp)
|
||||
|
||||
# Info
|
||||
**License:** MIT License
|
||||
|
||||
**Public Production Url:** [https://wrestlingdev.com](http://wrestlingdev.com)
|
||||
**Public Production Url:** [https://wrestlingdev.com](https://wrestlingdev.com)
|
||||
|
||||
**App Info**
|
||||
* Ruby 2.6.5
|
||||
* Rails 6.0.1
|
||||
* DB mysql or mariadb
|
||||
* Ruby 3.2.0
|
||||
* Rails 8.0.0
|
||||
* DB MySQL/MariaDB
|
||||
* Memcached
|
||||
* Delayed Jobs
|
||||
* Solid Queue for background job processing
|
||||
|
||||
# Development
|
||||
|
||||
## Develop with docker
|
||||
All dependencies are wrapped in docker. Tests can be run with `bash bin/run-tests-with-docker.sh`. That is the same command used in CI.
|
||||
|
||||
If you want to run a full rails environment shell in docker run: `bash bin/rails-dev-run.sh wrestlingapp-dev`
|
||||
|
||||
If you want to run a full rails environment shell in docker run: `bash bin/rails-dev-run.sh wrestlingdev-dev`
|
||||
From here, you can run the normal rails commands.
|
||||
|
||||
Special rake tasks:
|
||||
* `tournament:assign_random_wins` will complete all matches for tournament 204 from seed data. This task takes a while since it waits for the worker to complete tasks. In my testing, it takes about 3.5 hours to complete.
|
||||
* `rake tournament:assign_random_wins` to run locally
|
||||
* `docker-compose -f deploy/docker-compose-test.yml exec -T app rails tournament:assign_random_wins` to run on the dev server
|
||||
|
||||
To deploy a full local version of the app `bash deploy/deploy-test.sh` (this requires docker-compose to be installed). This deploys a full version of the app including Rails app, Solid Queue background workers, Memcached, and MariaDB. Now, you can open [http://localhost](http://localhost).
|
||||
|
||||
In development environments, background jobs run inline (synchronously) by default. In production and staging environments, jobs are processed asynchronously by separate worker processes.
|
||||
|
||||
To run a single test file:
|
||||
1. Get a shell with ruby and rails: `bash bin/rails-dev-run.sh wrestlingdev-development`
|
||||
2. `rake test TEST=test/models/match_test.rb`
|
||||
|
||||
To run a single test inside a file:
|
||||
1. Get a shell with ruby and rails: `bash bin/rails-dev-run.sh wrestlingdev-development`
|
||||
2. `rake test TEST=test/models/match_test.rb TESTOPTS="--name='/test_Match_should_not_be_valid_if_an_incorrect_win_type_is_given/'"`
|
||||
|
||||
## Develop with rvm
|
||||
With rvm installed, run `rvm install ruby-3.2.0`
|
||||
Then, `cd ../; cd wrestlingApp`. This will load the gemset file in this repo.
|
||||
|
||||
## Quick Rails Commands Without Local Installation
|
||||
You can run one-off Rails commands without installing Rails locally by using the development Docker image:
|
||||
|
||||
```bash
|
||||
# Build the development image
|
||||
docker build -t wrestlingdev-dev -f deploy/rails-dev-Dockerfile .
|
||||
|
||||
# Run a specific Rails command
|
||||
docker run -it -v $(pwd):/rails wrestlingdev-dev rails db:migrate
|
||||
|
||||
# Run the Rails console
|
||||
docker run -it -v $(pwd):/rails wrestlingdev-dev rails console
|
||||
|
||||
# Run a custom Rake task
|
||||
docker run -it -v $(pwd):/rails wrestlingdev-dev rake jobs:create_running
|
||||
```
|
||||
|
||||
This approach is useful for quick commands without the need to set up a full development environment. The image contains all required dependencies for the application.
|
||||
|
||||
For a more convenient experience with a persistent shell, use the included wrapper script:
|
||||
|
||||
```bash
|
||||
bash bin/rails-dev-run.sh wrestlingdev-dev
|
||||
```
|
||||
|
||||
## Rails commands
|
||||
Whether you have a shell from docker or are using rvm you can now run normal rails commands:
|
||||
* `bundle config set --local without 'production'`
|
||||
* `bundle install`
|
||||
* `rake db:seed` Development login email from seed data: `test@test.com` password: `password`
|
||||
* `rake test`
|
||||
* `rails generate blah blah blah`
|
||||
* ` rails s -b 0.0.0.0` port 3000 is exposed. You can open [http://localhost:3000](http://localhost:3000) after running that command
|
||||
* etc.
|
||||
* `rake finish_seed_tournament` will complete all matches from the seed data. This command takes about 5 minutes to execute
|
||||
* `rake finish_seed_tournaments` will complete all matches from the seed data. This command takes about 5 minutes to execute
|
||||
* `rake assets:clobber` - removes previously compiled assets stored in `public/assets` forcing Rails to recompile them from scratch the next time they are requested.
|
||||
|
||||
To deploy a a full local version of the app `bash deploy/deploy-test.sh` (this requires docker-compose to be installed). This deploys a full version of the app. App, delayed job, memcached, and mariadb. Now, you can open [http://localhost](http://localhost). Delayed jobs are turned off in dev and everything that is a delayed job in prod just runs in browser.
|
||||
## Testing Job Status
|
||||
|
||||
To help with testing the job status display in the UI, several rake tasks are provided:
|
||||
|
||||
```bash
|
||||
# Create a test "Running" job for the first tournament
|
||||
rails jobs:create_running
|
||||
|
||||
# Create a test "Completed" job for the first tournament
|
||||
rails jobs:create_completed
|
||||
|
||||
# Create a test "Error" job for the first tournament
|
||||
rails jobs:create_failed
|
||||
```
|
||||
|
||||
See `SOLID_QUEUE.md` for more details about the job system.
|
||||
|
||||
## Update gems
|
||||
|
||||
1. `bash bin/rails-dev-run.sh wrestlingdev-dev` to open a contianer with a rails shell available
|
||||
2. `bundle config --delete without` to remove the bundle config that ignores production gems
|
||||
3. `bundle update`
|
||||
4. `bundle config set --local without 'production'` to reset your without locally
|
||||
|
||||
Note: If updating rails, do not change the version in `Gemfile` until after you run `bash bin/rails-dev-run.sh wrestlingdev-dev`. Creating the container will fail due to a mismatch in Gemfile and Gemfile.lock.
|
||||
Then run `rails app:update` to update rails.
|
||||
|
||||
# Deployment
|
||||
|
||||
The production version of this is currently deployed in Kubernetes. See [Deploying with Kubernetes](deploy/kubernetes/README.md)
|
||||
|
||||
**Required environment variables for deployment**
|
||||
* `WRESTLINGDEV_DB_NAME=databasename`
|
||||
* `WRESTLINGDEV_DB_USER=databaseusername`
|
||||
* `WRESTLINGDEV_DB_PWD=databasepassword`
|
||||
* `WRESTLINGDEV_DB_HOST=database.homename`
|
||||
* `WRESTLINGDEV_DB_PORT=databaseport`
|
||||
* `WRESTLINGDEV_DEVISE_SECRET_KEY=devise_key` can be generated with `rake secret`
|
||||
* `WRESTLINGDEV_SECRET_KEY_BASE=secret_key` can be generated with `rake secret`
|
||||
* `WRESTLINGDEV_EMAIL_PWD=emailpwd` Email has to be a gmail account for now.
|
||||
* `WRESTLINGDEV_EMAIL=email address`
|
||||
## Server Configuration
|
||||
|
||||
**Optional environment variables**
|
||||
* `MEMCACHIER_PASSWORD=memcachier_password` needed for caching password
|
||||
* `MEMCACHIER_SERVERS=memcachier_hostname:memcachier_port` needed for caching
|
||||
* `MEMCACHIER_USERNAME=memcachier_username` needed for caching
|
||||
* `WRESTLINGDEV_NEW_RELIC_LICENSE_KEY=new_relic_license_key` this is only needed to use new relic
|
||||
### Puma and SolidQueue
|
||||
|
||||
The application uses an intelligent auto-scaling configuration for Puma (the web server) and SolidQueue (background job processing):
|
||||
|
||||
- **Auto Detection**: The server automatically detects available CPU cores and memory, and scales accordingly.
|
||||
- **Worker Scaling**: In production, the number of Puma workers is calculated based on available memory (assuming ~400MB per worker) and CPU cores.
|
||||
- **Thread Configuration**: Each Puma worker uses 5-12 threads by default, optimized for mixed I/O and CPU workloads.
|
||||
- **SolidQueue Integration**: When `SOLID_QUEUE_IN_PUMA=true`, background jobs run within the Puma process.
|
||||
- **Database Connection Pool**: Automatically sized based on the maximum number of threads across all workers.
|
||||
|
||||
The configuration is designed to adapt to different environments:
|
||||
- Small servers: Uses fewer workers to avoid memory exhaustion
|
||||
- Large servers: Scales up to utilize available CPU cores
|
||||
- Development: Uses a single worker for simplicity
|
||||
|
||||
All of these settings can be overridden with environment variables if needed.
|
||||
|
||||
To see the current configuration in the logs, look for these lines on startup:
|
||||
```
|
||||
Puma starting with X worker(s), Y-Z threads per worker
|
||||
Available system resources: X CPU(s), YMMMB RAM
|
||||
SolidQueue plugin enabled in Puma
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Required Environment Variables
|
||||
* `WRESTLINGDEV_DB_NAME` - Database name for the main application
|
||||
* `WRESTLINGDEV_DB_USR` - Database username
|
||||
* `WRESTLINGDEV_DB_PWD` - Database password
|
||||
* `WRESTLINGDEV_DB_HOST` - Database hostname
|
||||
* `WRESTLINGDEV_DB_PORT` - Database port
|
||||
* `WRESTLINGDEV_DEVISE_SECRET_KEY` - Secret key for Devise (can be generated with `rake secret`)
|
||||
* `WRESTLINGDEV_SECRET_KEY_BASE` - Rails application secret key (can be generated with `rake secret`)
|
||||
* `WRESTLINGDEV_EMAIL` - Email address (currently must be a Gmail account)
|
||||
* `WRESTLINGDEV_EMAIL_PWD` - Email password
|
||||
|
||||
### Optional Environment Variables
|
||||
* `SOLID_QUEUE_IN_PUMA` - Set to "true" to run Solid Queue workers inside Puma (default in development)
|
||||
* `WEB_CONCURRENCY` - Number of Puma workers (auto-detected based on CPU/memory if not specified)
|
||||
* `RAILS_MIN_THREADS` - Minimum number of threads per Puma worker (defaults to 5)
|
||||
* `RAILS_MAX_THREADS` - Maximum number of threads per Puma worker (defaults to 12)
|
||||
* `DATABASE_POOL_SIZE` - Database connection pool size (auto-calculated if not specified)
|
||||
* `SOLID_QUEUE_WORKERS` - Number of SolidQueue workers (auto-calculated if not specified)
|
||||
* `SOLID_QUEUE_THREADS` - Number of threads per SolidQueue worker (auto-calculated if not specified)
|
||||
* `PORT` - Port for Puma server to listen on (defaults to 3000)
|
||||
* `RAILS_LOG_LEVEL` - Log level for Rails in production (defaults to "info")
|
||||
* `PIDFILE` - PID file location for Puma
|
||||
* `RAILS_SSL_TERMINATION` - Set to "true" to enable force_ssl in production (HTTPS enforcement)
|
||||
* `REVERSE_PROXY_SSL_TERMINATION` - Set to "true" if the app is behind a SSL-terminating reverse proxy
|
||||
* `CI` - Set in CI environments to enable eager loading in test environment
|
||||
* `WRESTLINGDEV_NEW_RELIC_LICENSE_KEY` - New Relic license key for monitoring
|
||||
|
||||
### InfluxDB Configuration (all required if using InfluxDB)
|
||||
* `WRESTLINGDEV_INFLUXDB_DATABASE` - InfluxDB database name
|
||||
* `WRESTLINGDEV_INFLUXDB_HOST` - InfluxDB hostname
|
||||
* `WRESTLINGDEV_INFLUXDB_PORT` - InfluxDB port
|
||||
* `WRESTLINGDEV_INFLUXDB_USERNAME` - InfluxDB username (optional)
|
||||
* `WRESTLINGDEV_INFLUXDB_PASSWORD` - InfluxDB password (optional)
|
||||
|
||||
See `SOLID_QUEUE.md` for details about the job system configuration.
|
||||
|
||||
This project provides multiple ways to develop and deploy, with Docker being the primary method.
|
||||
288
SOLID_QUEUE.md
Normal file
288
SOLID_QUEUE.md
Normal file
@@ -0,0 +1,288 @@
|
||||
# SolidQueue, SolidCache, and SolidCable Setup
|
||||
|
||||
This application uses Rails 8's built-in background job processing, caching, and ActionCable features with separate dedicated databases.
|
||||
|
||||
## Database Configuration
|
||||
|
||||
We use separate databases for the main application, SolidQueue, SolidCache, and SolidCable. This ensures complete separation and avoids any conflicts or performance issues.
|
||||
|
||||
In `config/database.yml`, we have the following setup:
|
||||
|
||||
```yaml
|
||||
development:
|
||||
primary:
|
||||
database: db/development.sqlite3
|
||||
queue:
|
||||
database: db/development-queue.sqlite3
|
||||
cache:
|
||||
database: db/development-cache.sqlite3
|
||||
cable:
|
||||
database: db/development-cable.sqlite3
|
||||
|
||||
test:
|
||||
primary:
|
||||
database: db/test.sqlite3
|
||||
queue:
|
||||
database: db/test-queue.sqlite3
|
||||
cache:
|
||||
database: db/test-cache.sqlite3
|
||||
cable:
|
||||
database: db/test-cable.sqlite3
|
||||
|
||||
production:
|
||||
primary:
|
||||
database: <%= ENV['WRESTLINGDEV_DB_NAME'] %>
|
||||
queue:
|
||||
database: <%= ENV['WRESTLINGDEV_DB_NAME'] %>-queue
|
||||
cache:
|
||||
database: <%= ENV['WRESTLINGDEV_DB_NAME'] %>-cache
|
||||
cable:
|
||||
database: <%= ENV['WRESTLINGDEV_DB_NAME'] %>-cable
|
||||
```
|
||||
|
||||
## Migration Structure
|
||||
|
||||
Migrations for each database are stored in their respective directories:
|
||||
|
||||
- Main application migrations: `db/migrate/`
|
||||
- SolidQueue migrations: `db/queue/migrate/`
|
||||
- SolidCache migrations: `db/cache/migrate/`
|
||||
- SolidCable migrations: `db/cable/migrate/`
|
||||
|
||||
## Running Migrations
|
||||
|
||||
When deploying the application, you need to run migrations for each database separately:
|
||||
|
||||
```bash
|
||||
# Run main application migrations
|
||||
rails db:migrate
|
||||
|
||||
# Run SolidQueue migrations
|
||||
rails db:migrate:queue
|
||||
|
||||
# Run SolidCache migrations
|
||||
rails db:migrate:cache
|
||||
|
||||
# Run SolidCable migrations
|
||||
rails db:migrate:cable
|
||||
```
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
In the environment configuration files (`config/environments/*.rb`), we've configured the paths for migrations and set up the appropriate adapters:
|
||||
|
||||
```ruby
|
||||
# SolidCache configuration
|
||||
config.cache_store = :solid_cache_store
|
||||
config.paths["db/migrate"] << "db/cache/migrate"
|
||||
|
||||
# SolidQueue configuration
|
||||
config.active_job.queue_adapter = :solid_queue
|
||||
config.paths["db/migrate"] << "db/queue/migrate"
|
||||
|
||||
# ActionCable configuration
|
||||
config.paths["db/migrate"] << "db/cable/migrate"
|
||||
```
|
||||
|
||||
The database connections are configured in their respective YAML files:
|
||||
|
||||
### config/cache.yml
|
||||
```yaml
|
||||
production:
|
||||
database: cache
|
||||
# other options...
|
||||
```
|
||||
|
||||
### config/queue.yml
|
||||
```yaml
|
||||
production:
|
||||
database: queue
|
||||
# other options...
|
||||
```
|
||||
|
||||
### config/cable.yml
|
||||
```yaml
|
||||
production:
|
||||
adapter: solid_cable
|
||||
database: cable
|
||||
# other options...
|
||||
```
|
||||
|
||||
## SolidQueue Configuration
|
||||
|
||||
SolidQueue is used for background job processing in all environments except test. The application is configured to run jobs as follows:
|
||||
|
||||
### Development and Production
|
||||
In both development and production environments, SolidQueue is configured to process jobs asynchronously. This provides consistent behavior across environments while maintaining performance.
|
||||
|
||||
### Test
|
||||
In the test environment only, jobs are executed synchronously using the inline adapter. This makes testing more predictable and avoids the need for separate worker processes during tests.
|
||||
|
||||
Configuration is in `config/initializers/solid_queue.rb`:
|
||||
|
||||
```ruby
|
||||
# Configure ActiveJob queue adapter based on environment
|
||||
if Rails.env.test?
|
||||
# In test, use inline adapter for simplicity and predictability
|
||||
Rails.application.config.active_job.queue_adapter = :inline
|
||||
else
|
||||
# In development and production, use solid_queue with async execution
|
||||
Rails.application.config.active_job.queue_adapter = :solid_queue
|
||||
|
||||
# Configure for regular async processing
|
||||
Rails.application.config.active_job.queue_adapter_options = {
|
||||
execution_mode: :async,
|
||||
logger: Rails.logger
|
||||
}
|
||||
end
|
||||
```
|
||||
|
||||
## Running with Puma
|
||||
|
||||
By default, the application is configured to run SolidQueue workers within the Puma processes. This is done by setting the `SOLID_QUEUE_IN_PUMA` environment variable to `true` in the production Dockerfile, which enables the Puma plugin for SolidQueue.
|
||||
|
||||
This means you don't need to run separate worker processes in production - the same Puma processes that handle web requests also handle background jobs. This simplifies deployment and reduces resource requirements.
|
||||
|
||||
The application uses an intelligent auto-scaling configuration for SolidQueue when running in Puma:
|
||||
|
||||
1. **Auto Detection**: The Puma configuration automatically detects available CPU cores and memory
|
||||
2. **Worker Scaling**: Puma workers are calculated based on available memory and CPU cores
|
||||
3. **SolidQueue Integration**: When enabled, SolidQueue simply runs within the Puma process
|
||||
|
||||
You can enable SolidQueue in Puma by setting:
|
||||
```bash
|
||||
SOLID_QUEUE_IN_PUMA=true
|
||||
```
|
||||
|
||||
In `config/puma.rb`:
|
||||
```ruby
|
||||
# Run the Solid Queue supervisor inside of Puma for single-server deployments
|
||||
if ENV["SOLID_QUEUE_IN_PUMA"] == "true" && !Rails.env.test?
|
||||
# Simply load the SolidQueue plugin with default settings
|
||||
plugin :solid_queue
|
||||
|
||||
# Log that SolidQueue is enabled
|
||||
puts "SolidQueue plugin enabled in Puma"
|
||||
end
|
||||
```
|
||||
|
||||
On startup, you'll see a log message confirming that SolidQueue is enabled in Puma.
|
||||
|
||||
## Job Owner Tracking
|
||||
|
||||
Jobs in this application include metadata about their owner (typically a tournament) to allow tracking and displaying job status to tournament directors. Each job includes:
|
||||
|
||||
- `job_owner_id`: Usually the tournament ID
|
||||
- `job_owner_type`: A description of the job (e.g., "Create a backup")
|
||||
|
||||
This information is serialized with the job and can be used to filter and display jobs on tournament pages.
|
||||
|
||||
## Job Pattern: Simplified Job Enqueuing
|
||||
|
||||
Our job classes follow a simplified pattern that works consistently across all environments:
|
||||
|
||||
1. Service classes always use `perform_later` to enqueue jobs
|
||||
2. The execution mode is determined centrally by the ActiveJob adapter configuration
|
||||
3. Each job finds the needed records and calls the appropriate method on the service class or model
|
||||
|
||||
Example service class method:
|
||||
```ruby
|
||||
def create_backup
|
||||
# Set up job owner information for tracking
|
||||
job_owner_id = @tournament.id
|
||||
job_owner_type = "Create a backup"
|
||||
|
||||
# Use perform_later which will execute based on centralized adapter config
|
||||
TournamentBackupJob.perform_later(@tournament.id, @reason, job_owner_id, job_owner_type)
|
||||
end
|
||||
```
|
||||
|
||||
Example job class:
|
||||
```ruby
|
||||
class TournamentBackupJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
# For storing job owner metadata
|
||||
attr_accessor :job_owner_id, :job_owner_type
|
||||
|
||||
# For execution via job queue with IDs
|
||||
def perform(tournament_id, reason, job_owner_id = nil, job_owner_type = nil)
|
||||
# Store job owner metadata
|
||||
self.job_owner_id = job_owner_id
|
||||
self.job_owner_type = job_owner_type
|
||||
|
||||
# Find the record
|
||||
tournament = Tournament.find_by(id: tournament_id)
|
||||
return unless tournament
|
||||
|
||||
# Create the service class and call the raw method
|
||||
TournamentBackupService.new(tournament, reason).create_backup_raw
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Job Classes
|
||||
|
||||
The following job classes are available:
|
||||
|
||||
- `AdvanceWrestlerJob`: For advancing wrestlers in brackets
|
||||
- `TournamentBackupJob`: For creating tournament backups
|
||||
- `WrestlingdevImportJob`: For importing from wrestlingdev
|
||||
- `GenerateTournamentMatchesJob`: For generating tournament matches
|
||||
- `CalculateSchoolScoreJob`: For calculating school scores
|
||||
|
||||
## Job Status
|
||||
|
||||
Jobs in this application can have the following statuses:
|
||||
|
||||
1. **Running**: Job is currently being executed. This is determined by checking if a record exists in the `solid_queue_claimed_executions` table for the job.
|
||||
|
||||
2. **Scheduled**: Job is scheduled to run at a future time. This is determined by checking if `scheduled_at` is in the future.
|
||||
|
||||
3. **Error**: Job has failed. This is determined by:
|
||||
- Checking if a record exists in the `solid_queue_failed_executions` table for the job
|
||||
- Checking if `failed_at` is present
|
||||
|
||||
4. **Completed**: Job has finished successfully. This is determined by checking if `finished_at` is present and no error records exist.
|
||||
|
||||
5. **Pending**: Job is waiting to be picked up by a worker. This is the default status when none of the above conditions are met.
|
||||
|
||||
## Testing Job Status
|
||||
|
||||
To help with testing the job status display in the UI, several rake tasks are provided:
|
||||
|
||||
```bash
|
||||
# Create a test "Running" job for the first tournament
|
||||
rails jobs:create_running
|
||||
|
||||
# Create a test "Completed" job for the first tournament
|
||||
rails jobs:create_completed
|
||||
|
||||
# Create a test "Error" job for the first tournament
|
||||
rails jobs:create_failed
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you encounter issues with SolidQueue or the separate databases:
|
||||
|
||||
1. Make sure all databases exist:
|
||||
```sql
|
||||
CREATE DATABASE IF NOT EXISTS wrestlingtourney;
|
||||
CREATE DATABASE IF NOT EXISTS wrestlingtourney-queue;
|
||||
CREATE DATABASE IF NOT EXISTS wrestlingtourney-cache;
|
||||
CREATE DATABASE IF NOT EXISTS wrestlingtourney-cable;
|
||||
```
|
||||
|
||||
2. Ensure all migrations have been run for each database.
|
||||
|
||||
3. Check that environment configurations properly connect to the right databases.
|
||||
|
||||
4. Verify that the database user has appropriate permissions for all databases.
|
||||
|
||||
5. If jobs aren't processing in production, check that `SOLID_QUEUE_IN_PUMA` is set to `true` in your environment.
|
||||
|
||||
## References
|
||||
|
||||
- [SolidQueue README](https://github.com/rails/solid_queue)
|
||||
- [Rails Multiple Database Configuration](https://guides.rubyonrails.org/active_record_multiple_databases.html)
|
||||
@@ -10,7 +10,23 @@
|
||||
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
||||
// about supported directives.
|
||||
//
|
||||
//= require_tree .
|
||||
//= require jquery
|
||||
//= require jquery_ujs
|
||||
// Bootstrap 3.3.6 in vendor/assets/javascripts
|
||||
//= require bootstrap.min.js
|
||||
// Data Tables 1.10.6 in vendor/assets/javascripts
|
||||
//= require jquery.dataTables.min.js
|
||||
//= require turbolinks
|
||||
//
|
||||
//= require actioncable
|
||||
//= require_self
|
||||
//= require_tree .
|
||||
|
||||
// Create the Action Cable consumer instance
|
||||
(function() {
|
||||
this.App || (this.App = {});
|
||||
|
||||
App.cable = ActionCable.createConsumer();
|
||||
|
||||
}).call(this);
|
||||
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
|
||||
* file per style scope.
|
||||
*
|
||||
* For some reason this needs to be above bootstrap for the zindex of the main navbar to work.
|
||||
* With it lower, bootstraps css overrides it.
|
||||
*= require custom
|
||||
* Bootstrap 3.3.6 in vendor/assets/stylesheets
|
||||
*= require bootstrap.min.css
|
||||
*= require bootstrap-theme.min.css
|
||||
*= require_tree .
|
||||
*= require_self
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
.navbar-inverse.navbar-fixed-top {
|
||||
z-index: 1040; /* Ensure main navbar is above tournament navbar */
|
||||
}
|
||||
|
||||
#tournament-navbar {
|
||||
top: 50px; /* Position below the first fixed navbar */
|
||||
z-index: 1030; /* Explicitly set standard fixed navbar z-index */
|
||||
}
|
||||
|
||||
/* Make desktop navbar dropdowns scrollable if they overflow */
|
||||
@media (min-width: 768px) {
|
||||
/* Target dropdowns in main nav and tournament nav specifically */
|
||||
.navbar-fixed-top .dropdown-menu {
|
||||
max-height: 70vh; /* Adjust as needed - 70% of viewport height */
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
4
app/channels/application_cable/channel.rb
Normal file
4
app/channels/application_cable/channel.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
module ApplicationCable
|
||||
class Channel < ActionCable::Channel::Base
|
||||
end
|
||||
end
|
||||
4
app/channels/application_cable/connection.rb
Normal file
4
app/channels/application_cable/connection.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
module ApplicationCable
|
||||
class Connection < ActionCable::Connection::Base
|
||||
end
|
||||
end
|
||||
63
app/channels/match_channel.rb
Normal file
63
app/channels/match_channel.rb
Normal file
@@ -0,0 +1,63 @@
|
||||
class MatchChannel < ApplicationCable::Channel
|
||||
def subscribed
|
||||
@match = Match.find_by(id: params[:match_id])
|
||||
Rails.logger.info "[MatchChannel] Client subscribed with match_id: #{params[:match_id]}. Match found: #{@match.present?}"
|
||||
if @match
|
||||
stream_for @match
|
||||
else
|
||||
Rails.logger.warn "[MatchChannel] Match not found for ID: #{params[:match_id]}. Subscription may fail."
|
||||
# You might want to reject the subscription if the match isn't found
|
||||
# reject
|
||||
end
|
||||
end
|
||||
|
||||
def unsubscribed
|
||||
Rails.logger.info "[MatchChannel] Client unsubscribed for match #{@match&.id}"
|
||||
end
|
||||
|
||||
# Called when client sends data with action: 'send_stat'
|
||||
def send_stat(data)
|
||||
# Explicit check for @match at the start
|
||||
unless @match
|
||||
Rails.logger.error "[MatchChannel] Error: send_stat called but @match is nil. Client params on sub: #{params[:match_id]}"
|
||||
return # Stop if no match context
|
||||
end
|
||||
|
||||
Rails.logger.info "[MatchChannel] Received send_stat for match #{@match.id} with data: #{data.inspect}"
|
||||
|
||||
# Prepare attributes to update
|
||||
attributes_to_update = {}
|
||||
attributes_to_update[:w1_stat] = data['new_w1_stat'] if data.key?('new_w1_stat')
|
||||
attributes_to_update[:w2_stat] = data['new_w2_stat'] if data.key?('new_w2_stat')
|
||||
|
||||
if attributes_to_update.present?
|
||||
# Persist the changes to the database
|
||||
# Note: Consider background job or throttling for very high frequency updates
|
||||
begin
|
||||
if @match.update(attributes_to_update)
|
||||
Rails.logger.info "[MatchChannel] Updated match #{@match.id} stats in DB: #{attributes_to_update.keys.join(', ')}"
|
||||
|
||||
# Prepare payload for broadcast (using potentially updated values from @match)
|
||||
payload = {
|
||||
w1_stat: @match.w1_stat,
|
||||
w2_stat: @match.w2_stat
|
||||
}.compact
|
||||
|
||||
if payload.present?
|
||||
Rails.logger.info "[MatchChannel] Broadcasting DB-persisted stats to match #{@match.id} with payload: #{payload.inspect}"
|
||||
MatchChannel.broadcast_to(@match, payload)
|
||||
else
|
||||
Rails.logger.info "[MatchChannel] Payload empty after DB update for match #{@match.id}, not broadcasting."
|
||||
end
|
||||
else
|
||||
Rails.logger.error "[MatchChannel] Failed to update match #{@match.id} stats in DB: #{@match.errors.full_messages.join(', ')}"
|
||||
end
|
||||
rescue => e
|
||||
Rails.logger.error "[MatchChannel] Exception during match update for #{@match.id}: #{e.message}"
|
||||
Rails.logger.error e.backtrace.join("\n")
|
||||
end
|
||||
else
|
||||
Rails.logger.info "[MatchChannel] No new stat data provided in send_stat for match #{@match.id}, not updating DB or broadcasting."
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -14,7 +14,11 @@ class ApiController < ApplicationController
|
||||
end
|
||||
|
||||
def tournament
|
||||
@tournament = Tournament.where(:id => params[:tournament]).includes(:schools,:weights,:mats,:matches,:user,:wrestlers).first
|
||||
@tournament = Tournament.where(:id => params[:tournament]).includes(:user, :mats, :schools, :weights, :matches, wrestlers: [:school, :weight, :matches_as_w1, :matches_as_w2]).first
|
||||
@schools = @tournament.schools.includes(wrestlers: [:weight, :matches_as_w1, :matches_as_w2])
|
||||
@weights = @tournament.weights.includes(wrestlers: [:school, :matches_as_w1, :matches_as_w2])
|
||||
@matches = @tournament.matches.includes(:wrestlers,:schools)
|
||||
@mats = @tournament.mats.includes(:matches)
|
||||
end
|
||||
|
||||
def newTournament
|
||||
|
||||
@@ -5,19 +5,39 @@ class ApplicationController < ActionController::Base
|
||||
|
||||
after_action :set_csrf_cookie_for_ng
|
||||
|
||||
# Add helpers for authentication (replacing Devise)
|
||||
helper_method :current_user, :user_signed_in?
|
||||
|
||||
def current_user
|
||||
@current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
|
||||
end
|
||||
|
||||
def user_signed_in?
|
||||
current_user.present?
|
||||
end
|
||||
|
||||
def authenticate_user!
|
||||
redirect_to login_path, alert: "Please log in to access this page" unless user_signed_in?
|
||||
end
|
||||
|
||||
def set_csrf_cookie_for_ng
|
||||
cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
|
||||
end
|
||||
|
||||
rescue_from CanCan::AccessDenied do |exception|
|
||||
# flash[:error] = "Access denied!"
|
||||
redirect_to '/static_pages/not_allowed'
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
|
||||
# In Rails 4.2 and above
|
||||
def verified_request?
|
||||
super || valid_authenticity_token?(session, request.headers['X-XSRF-TOKEN'])
|
||||
end
|
||||
|
||||
# Override current_ability to pass school_permission_key
|
||||
# @school_permission_key needs to be defined on the controller
|
||||
def current_ability
|
||||
@current_ability ||= Ability.new(current_user, @school_permission_key)
|
||||
end
|
||||
end
|
||||
|
||||
77
app/controllers/mat_assignment_rules_controller.rb
Normal file
77
app/controllers/mat_assignment_rules_controller.rb
Normal file
@@ -0,0 +1,77 @@
|
||||
class MatAssignmentRulesController < ApplicationController
|
||||
before_action :set_tournament
|
||||
before_action :check_access_manage
|
||||
before_action :set_mat_assignment_rule, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
@mat_assignment_rules = @tournament.mat_assignment_rules
|
||||
@weights_by_id = @tournament.weights.index_by(&:id) # For quick lookup
|
||||
end
|
||||
|
||||
def new
|
||||
@mat_assignment_rule = @tournament.mat_assignment_rules.build
|
||||
load_form_data
|
||||
end
|
||||
|
||||
def create
|
||||
@mat_assignment_rule = @tournament.mat_assignment_rules.build(mat_assignment_rule_params)
|
||||
load_form_data
|
||||
|
||||
if @mat_assignment_rule.save
|
||||
redirect_to tournament_mat_assignment_rules_path(@tournament), notice: 'Mat assignment rule created successfully.'
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
load_form_data
|
||||
end
|
||||
|
||||
def update
|
||||
load_form_data
|
||||
|
||||
if @mat_assignment_rule.update(mat_assignment_rule_params)
|
||||
redirect_to tournament_mat_assignment_rules_path(@tournament), notice: 'Mat assignment rule updated successfully.'
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@mat_assignment_rule.destroy
|
||||
redirect_to tournament_mat_assignment_rules_path(@tournament), notice: 'Mat assignment rule was successfully deleted.'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_tournament
|
||||
@tournament = Tournament.find(params[:tournament_id])
|
||||
end
|
||||
|
||||
def set_mat_assignment_rule
|
||||
@mat_assignment_rule = @tournament.mat_assignment_rules.find(params[:id])
|
||||
end
|
||||
|
||||
def check_access_manage
|
||||
authorize! :manage, @tournament
|
||||
end
|
||||
|
||||
def mat_assignment_rule_params
|
||||
params[:mat_assignment_rule][:weight_classes] ||= []
|
||||
params[:mat_assignment_rule][:bracket_positions] ||= []
|
||||
params[:mat_assignment_rule][:rounds] ||= []
|
||||
|
||||
params.require(:mat_assignment_rule).permit(:mat_id, weight_classes: [], bracket_positions: [], rounds: []).tap do |whitelisted|
|
||||
whitelisted[:weight_classes] = Array(whitelisted[:weight_classes]).map(&:to_i)
|
||||
whitelisted[:rounds] = Array(whitelisted[:rounds]).map(&:to_i)
|
||||
whitelisted[:bracket_positions] = Array(whitelisted[:bracket_positions])
|
||||
end
|
||||
end
|
||||
|
||||
def load_form_data
|
||||
@available_mats = @tournament.mats
|
||||
@unique_bracket_positions = @tournament.matches.select(:bracket_position).distinct.pluck(:bracket_position)
|
||||
@unique_rounds = @tournament.matches.select(:round).distinct.pluck(:round)
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
class MatchesController < ApplicationController
|
||||
before_action :set_match, only: [:show, :edit, :update, :destroy, :stat]
|
||||
before_action :set_match, only: [:show, :edit, :update, :stat, :spectate]
|
||||
before_action :check_access, only: [:edit,:update, :stat]
|
||||
|
||||
# GET /matches/1
|
||||
@@ -16,41 +16,99 @@ class MatchesController < ApplicationController
|
||||
end
|
||||
if @match
|
||||
@wrestlers = @match.weight.wrestlers
|
||||
@tournament = @match.tournament
|
||||
end
|
||||
session[:return_path] = "/tournaments/#{@match.tournament.id}/matches"
|
||||
end
|
||||
|
||||
def stat
|
||||
# @show_next_bout_button = false
|
||||
if params[:match]
|
||||
@match = Match.where(:id => params[:match]).includes(:wrestlers).first
|
||||
end
|
||||
@wrestlers = []
|
||||
if @match
|
||||
@w1 = @match.wrestler1
|
||||
@w2 = @match.wrestler2
|
||||
@wrestlers = [@w1,@w2]
|
||||
if @match.w1
|
||||
@wrestler1_name = @match.wrestler1.name
|
||||
@wrestler1_school_name = @match.wrestler1.school.name
|
||||
@wrestler1_last_match = @match.wrestler1.last_match
|
||||
@wrestlers.push(@match.wrestler1)
|
||||
else
|
||||
@wrestler1_name = "Not assigned"
|
||||
@wrestler1_school_name = "N/A"
|
||||
@wrestler1_last_match = nil
|
||||
end
|
||||
if @match.w2
|
||||
@wrestler2_name = @match.wrestler2.name
|
||||
@wrestler2_school_name = @match.wrestler2.school.name
|
||||
@wrestler2_last_match = @match.wrestler2.last_match
|
||||
@wrestlers.push(@match.wrestler2)
|
||||
else
|
||||
@wrestler2_name = "Not assigned"
|
||||
@wrestler2_school_name = "N/A"
|
||||
@wrestler2_last_match = nil
|
||||
end
|
||||
@tournament = @match.tournament
|
||||
end
|
||||
session[:return_path] = "/tournaments/#{@tournament.id}/matches"
|
||||
session[:error_return_path] = "/matches/#{@match.id}/stat"
|
||||
end
|
||||
|
||||
# GET /matches/:id/spectate
|
||||
def spectate
|
||||
# Similar to stat, but potentially simplified for read-only view
|
||||
# We mainly need @match for the view to get the ID
|
||||
# and maybe initial wrestler names/schools
|
||||
if @match
|
||||
@wrestler1_name = @match.w1 ? @match.wrestler1.name : "Not assigned"
|
||||
@wrestler1_school_name = @match.w1 ? @match.wrestler1.school.name : "N/A"
|
||||
@wrestler2_name = @match.w2 ? @match.wrestler2.name : "Not assigned"
|
||||
@wrestler2_school_name = @match.w2 ? @match.wrestler2.school.name : "N/A"
|
||||
@tournament = @match.tournament
|
||||
else
|
||||
# Handle case where match isn't found, perhaps redirect or render error
|
||||
redirect_to root_path, alert: "Match not found."
|
||||
end
|
||||
end
|
||||
|
||||
# PATCH/PUT /matches/1
|
||||
# PATCH/PUT /matches/1.json
|
||||
def update
|
||||
respond_to do |format|
|
||||
if @match.update(match_params)
|
||||
# Broadcast the update
|
||||
MatchChannel.broadcast_to(
|
||||
@match,
|
||||
{
|
||||
w1_stat: @match.w1_stat,
|
||||
w2_stat: @match.w2_stat,
|
||||
score: @match.score,
|
||||
win_type: @match.win_type,
|
||||
winner_id: @match.winner_id,
|
||||
winner_name: @match.winner&.name,
|
||||
finished: @match.finished
|
||||
}
|
||||
)
|
||||
|
||||
if session[:return_path]
|
||||
format.html { redirect_to session.delete(:return_path), notice: 'Match was successfully updated.' }
|
||||
sanitized_return_path = sanitize_return_path(session[:return_path])
|
||||
format.html { redirect_to sanitized_return_path, notice: 'Match was successfully updated.' }
|
||||
session.delete(:return_path) # Remove the session variable
|
||||
else
|
||||
format.html { redirect_to "/tournaments/#{@match.tournament.id}", notice: 'Match was successfully updated.' }
|
||||
end
|
||||
format.json { head :no_content }
|
||||
else
|
||||
format.html { render action: 'edit' }
|
||||
format.json { render json: @match.errors, status: :unprocessable_entity }
|
||||
if session[:error_return_path]
|
||||
format.html { redirect_to session.delete(:error_return_path), alert: "Match did not save because: #{@match.errors.full_messages.to_s}" }
|
||||
format.json { render json: @match.errors, status: :unprocessable_entity }
|
||||
else
|
||||
format.html { redirect_to "/tournaments/#{@match.tournament.id}", alert: "Match did not save because: #{@match.errors.full_messages.to_s}" }
|
||||
format.json { render json: @match.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
@@ -61,10 +119,18 @@ class MatchesController < ApplicationController
|
||||
|
||||
# Never trust parameters from the scary internet, only allow the white list through.
|
||||
def match_params
|
||||
params.require(:match).permit(:w1, :w2, :w1_stat, :w2_stat, :winner_id, :win_type, :score, :finished)
|
||||
params.require(:match).permit(:w1, :w2, :w1_stat, :w2_stat, :winner_id, :win_type, :score, :overtime_type, :finished, :round)
|
||||
end
|
||||
|
||||
def check_access
|
||||
authorize! :manage, @match.tournament
|
||||
end
|
||||
|
||||
def sanitize_return_path(path)
|
||||
uri = URI.parse(path)
|
||||
params = Rack::Utils.parse_nested_query(uri.query)
|
||||
params.delete("bout_number") # Remove the bout_number param
|
||||
uri.query = params.to_query.presence # Rebuild the query string or set it to nil if empty
|
||||
uri.to_s # Return the full path as a string
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,19 +1,53 @@
|
||||
class MatsController < ApplicationController
|
||||
before_action :set_mat, only: [:show, :edit, :update, :destroy]
|
||||
before_action :check_access, only: [:new,:create,:update,:destroy,:edit,:show]
|
||||
before_action :set_mat, only: [:show, :edit, :update, :destroy, :assign_next_match]
|
||||
before_action :check_access, only: [:new,:create,:update,:destroy,:edit,:show, :assign_next_match]
|
||||
before_action :check_for_matches, only: [:show]
|
||||
|
||||
# GET /mats/1
|
||||
# GET /mats/1.json
|
||||
def show
|
||||
@match = @mat.unfinished_matches.first
|
||||
if @match
|
||||
@w1 = @match.wrestler1
|
||||
@w2 = @match.wrestler2
|
||||
@wrestlers = [@w1,@w2]
|
||||
bout_number_param = params[:bout_number] # Read the bout_number from the URL params
|
||||
|
||||
if bout_number_param
|
||||
@show_next_bout_button = false
|
||||
@match = @mat.unfinished_matches.find { |m| m.bout_number == bout_number_param.to_i }
|
||||
else
|
||||
@show_next_bout_button = true
|
||||
@match = @mat.unfinished_matches.first
|
||||
end
|
||||
|
||||
@next_match = @mat.unfinished_matches.second # Second unfinished match on the mat
|
||||
|
||||
@wrestlers = []
|
||||
if @match
|
||||
if @match.w1
|
||||
@wrestler1_name = @match.wrestler1.name
|
||||
@wrestler1_school_name = @match.wrestler1.school.name
|
||||
@wrestler1_last_match = @match.wrestler1.last_match
|
||||
@wrestlers.push(@match.wrestler1)
|
||||
else
|
||||
@wrestler1_name = "Not assigned"
|
||||
@wrestler1_school_name = "N/A"
|
||||
@wrestler1_last_match = nil
|
||||
end
|
||||
|
||||
if @match.w2
|
||||
@wrestler2_name = @match.wrestler2.name
|
||||
@wrestler2_school_name = @match.wrestler2.school.name
|
||||
@wrestler2_last_match = @match.wrestler2.last_match
|
||||
@wrestlers.push(@match.wrestler2)
|
||||
else
|
||||
@wrestler2_name = "Not assigned"
|
||||
@wrestler2_school_name = "N/A"
|
||||
@wrestler2_last_match = nil
|
||||
end
|
||||
|
||||
@tournament = @match.tournament
|
||||
end
|
||||
|
||||
session[:return_path] = request.original_fullpath
|
||||
end
|
||||
session[:error_return_path] = request.original_fullpath
|
||||
end
|
||||
|
||||
# GET /mats/new
|
||||
def new
|
||||
@@ -44,6 +78,20 @@ class MatsController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
# POST /mats/1/assign_next_match
|
||||
def assign_next_match
|
||||
@tournament = @mat.tournament_id
|
||||
respond_to do |format|
|
||||
if @mat.assign_next_match
|
||||
format.html { redirect_to "/tournaments/#{@mat.tournament.id}", notice: "Next Match on Mat #{@mat.name} successfully completed." }
|
||||
format.json { head :no_content }
|
||||
else
|
||||
format.html { redirect_to "/tournaments/#{@mat.tournament.id}", alert: "There was an error." }
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# PATCH/PUT /mats/1
|
||||
# PATCH/PUT /mats/1.json
|
||||
def update
|
||||
|
||||
57
app/controllers/password_resets_controller.rb
Normal file
57
app/controllers/password_resets_controller.rb
Normal file
@@ -0,0 +1,57 @@
|
||||
class PasswordResetsController < ApplicationController
|
||||
before_action :get_user, only: [:edit, :update]
|
||||
before_action :valid_user, only: [:edit, :update]
|
||||
before_action :check_expiration, only: [:edit, :update]
|
||||
|
||||
def new
|
||||
end
|
||||
|
||||
def create
|
||||
@user = User.find_by(email: params[:password_reset][:email].downcase)
|
||||
if @user
|
||||
@user.create_reset_digest
|
||||
@user.send_password_reset_email
|
||||
redirect_to root_url, notice: "Email sent with password reset instructions"
|
||||
else
|
||||
flash.now[:alert] = "Email address not found"
|
||||
render 'new'
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if params[:user][:password].empty?
|
||||
@user.errors.add(:password, "can't be empty")
|
||||
render 'edit'
|
||||
elsif @user.update(user_params)
|
||||
session[:user_id] = @user.id
|
||||
redirect_to root_url, notice: "Password has been reset"
|
||||
else
|
||||
render 'edit'
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:password, :password_confirmation)
|
||||
end
|
||||
|
||||
def get_user
|
||||
@user = User.find_by(email: params[:email])
|
||||
end
|
||||
|
||||
def valid_user
|
||||
unless @user && @user.authenticated?(:reset, params[:id])
|
||||
redirect_to root_url
|
||||
end
|
||||
end
|
||||
|
||||
def check_expiration
|
||||
if @user.password_reset_expired?
|
||||
redirect_to new_password_reset_url, alert: "Password reset has expired"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,7 +2,7 @@ class SchoolsController < ApplicationController
|
||||
before_action :set_school, only: [:import_baumspage_roster, :show, :edit, :update, :destroy, :stats]
|
||||
before_action :check_access_director, only: [:new,:create,:destroy]
|
||||
before_action :check_access_delegate, only: [:import_baumspage_roster, :update,:edit]
|
||||
|
||||
before_action :check_read_access, only: [:show, :stats]
|
||||
|
||||
def stats
|
||||
@tournament = @school.tournament
|
||||
@@ -12,7 +12,7 @@ class SchoolsController < ApplicationController
|
||||
# GET /schools/1.json
|
||||
def show
|
||||
session.delete(:return_path)
|
||||
@wrestlers = @school.wrestlers.includes(:deductedPoints,:matches,:weight)
|
||||
@wrestlers = @school.wrestlers.includes(:deductedPoints, :weight, :school, :matches_as_w1, :matches_as_w2)
|
||||
@tournament = @school.tournament
|
||||
end
|
||||
|
||||
@@ -84,7 +84,7 @@ class SchoolsController < ApplicationController
|
||||
private
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_school
|
||||
@school = School.where(:id => params[:id]).includes(:tournament,:wrestlers,:deductedPoints,:delegates).first
|
||||
@school = School.includes(:tournament, :delegates, :deductedPoints, wrestlers: [:weight, :deductedPoints, :matches_as_w1, :matches_as_w2]).find_by(id: params[:id])
|
||||
end
|
||||
|
||||
# Never trust parameters from the scary internet, only allow the white list through.
|
||||
@@ -93,20 +93,37 @@ class SchoolsController < ApplicationController
|
||||
end
|
||||
|
||||
def check_access_director
|
||||
if params[:tournament]
|
||||
if params[:tournament].present?
|
||||
@tournament = Tournament.find(params[:tournament])
|
||||
elsif params[:school]
|
||||
elsif params[:school].present?
|
||||
@tournament = Tournament.find(params[:school]["tournament_id"])
|
||||
elsif @school
|
||||
@tournament = @school.tournament
|
||||
elsif school_params
|
||||
@tournament = Tournament.find(school_params[:tournament_id])
|
||||
end
|
||||
|
||||
authorize! :manage, @tournament
|
||||
end
|
||||
|
||||
def check_access_delegate
|
||||
if params[:school].present?
|
||||
if school_params[:school_permission_key].present?
|
||||
@school_permission_key = params[:school_permission_key]
|
||||
end
|
||||
end
|
||||
|
||||
if params[:school_permission_key].present?
|
||||
@school_permission_key = params[:school_permission_key]
|
||||
end
|
||||
|
||||
authorize! :manage, @school
|
||||
end
|
||||
|
||||
def check_read_access
|
||||
# set @school_permission_key for use in ability
|
||||
if params[:school_permission_key].present?
|
||||
@school_permission_key = params[:school_permission_key]
|
||||
end
|
||||
|
||||
authorize! :read, @school
|
||||
end
|
||||
end
|
||||
|
||||
20
app/controllers/sessions_controller.rb
Normal file
20
app/controllers/sessions_controller.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
class SessionsController < ApplicationController
|
||||
def new
|
||||
end
|
||||
|
||||
def create
|
||||
user = User.find_by(email: params[:session][:email].downcase)
|
||||
if user && user.authenticate(params[:session][:password])
|
||||
session[:user_id] = user.id
|
||||
redirect_to root_path, notice: "Logged in successfully"
|
||||
else
|
||||
flash.now[:alert] = "Invalid email/password combination"
|
||||
render 'new'
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
session.delete(:user_id)
|
||||
redirect_to root_path, notice: "Logged out successfully"
|
||||
end
|
||||
end
|
||||
78
app/controllers/tournament_backups_controller.rb
Normal file
78
app/controllers/tournament_backups_controller.rb
Normal file
@@ -0,0 +1,78 @@
|
||||
class TournamentBackupsController < ApplicationController
|
||||
before_action :set_tournament
|
||||
before_action :set_tournament_backup, only: [:show, :destroy, :restore]
|
||||
before_action :check_access_manage
|
||||
|
||||
# GET /tournament/:tournament_id/tournament_backups
|
||||
def index
|
||||
@tournament_backups = @tournament.tournament_backups.order(created_at: :desc)
|
||||
end
|
||||
|
||||
# GET /tournament/:tournament_id/tournament_backups/:id
|
||||
def show
|
||||
end
|
||||
|
||||
# DELETE /tournament/:tournament_id/tournament_backups/:id
|
||||
def destroy
|
||||
if @tournament_backup.destroy
|
||||
redirect_to tournament_tournament_backups_path(@tournament), notice: 'Backup was successfully deleted.'
|
||||
else
|
||||
redirect_to tournament_tournament_backups_path(@tournament), alert: 'Failed to delete the backup.'
|
||||
end
|
||||
end
|
||||
|
||||
# POST /tournament/:tournament_id/tournament_backups/create
|
||||
def create
|
||||
TournamentBackupService.new(@tournament, 'Manual backup').create_backup
|
||||
redirect_to tournament_tournament_backups_path(@tournament), notice: 'Backup was successfully created. It will show up soon, check your background jobs for status.'
|
||||
end
|
||||
|
||||
# POST /tournament/:tournament_id/tournament_backups/:id/restore
|
||||
def restore
|
||||
WrestlingdevImporter.new(@tournament, @tournament_backup).import
|
||||
redirect_to tournament_path(@tournament), notice: 'Restore has successfully been submitted, please check your background jobs to see if it has finished.'
|
||||
end
|
||||
|
||||
# POST /tournament/:tournament_id/tournament_backups/import_manual
|
||||
def import_manual
|
||||
import_text = params[:tournament][:import_text]
|
||||
if import_text.blank?
|
||||
redirect_to tournament_tournament_backups_path(@tournament), alert: 'Import text cannot be blank.'
|
||||
return
|
||||
end
|
||||
|
||||
begin
|
||||
|
||||
# Create a temporary backup object
|
||||
backup = TournamentBackup.new(
|
||||
tournament: @tournament,
|
||||
backup_data: Base64.encode64(import_text),
|
||||
backup_reason: 'Manual Import'
|
||||
)
|
||||
|
||||
# Pass the backup object to the importer
|
||||
WrestlingdevImporter.new(@tournament, backup).import
|
||||
|
||||
redirect_to tournament_path(@tournament), notice: 'Restore has successfully been submitted, please check your background jobs to see if it has finished.'
|
||||
rescue JSON::ParserError => e
|
||||
redirect_to tournament_tournament_backups_path(@tournament), alert: "Failed to parse JSON: #{e.message}"
|
||||
rescue StandardError => e
|
||||
redirect_to tournament_tournament_backups_path(@tournament), alert: "An error occurred: #{e.message}"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_tournament
|
||||
@tournament = Tournament.find(params[:tournament_id])
|
||||
end
|
||||
|
||||
def set_tournament_backup
|
||||
@tournament_backup = @tournament.tournament_backups.find(params[:id])
|
||||
end
|
||||
|
||||
def check_access_manage
|
||||
authorize! :manage, @tournament
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,33 +1,20 @@
|
||||
class TournamentsController < ApplicationController
|
||||
before_action :set_tournament, only: [:calculate_team_scores, :import,:export,:bout_sheets,:swap,:weigh_in_sheet,:error,:teampointadjust,:remove_teampointadjust,:remove_school_delegate,:remove_delegate,:school_delegate,:delegate,:matches,:weigh_in,:weigh_in_weight,:create_custom_weights,:show,:edit,:update,:destroy,:up_matches,:no_matches,:team_scores,:brackets,:generate_matches,:bracket,:all_brackets]
|
||||
before_action :check_access_manage, only: [:calculate_team_scores, :import,:export,:swap,:weigh_in_sheet,:teampointadjust,:remove_teampointadjust,:remove_school_delegate,:school_delegate,:weigh_in,:weigh_in_weight,:create_custom_weights,:update,:edit,:generate_matches,:matches]
|
||||
before_action :set_tournament, only: [:all_results, :delete_school_keys, :generate_school_keys,:reset_bout_board,:calculate_team_scores,:bout_sheets,:swap,:weigh_in_sheet,:error,:teampointadjust,:remove_teampointadjust,:remove_school_delegate,:remove_delegate,:school_delegate,:delegate,:matches,:weigh_in,:weigh_in_weight,:create_custom_weights,:show,:edit,:update,:destroy,:up_matches,:no_matches,:team_scores,:generate_matches,:bracket,:all_brackets]
|
||||
before_action :check_access_manage, only: [:delete_school_keys, :generate_school_keys,:reset_bout_board,:calculate_team_scores,:swap,:weigh_in_sheet,:teampointadjust,:remove_teampointadjust,:remove_school_delegate,:school_delegate,:weigh_in,:weigh_in_weight,:create_custom_weights,:update,:edit,:generate_matches,:matches]
|
||||
before_action :check_access_destroy, only: [:destroy,:delegate,:remove_delegate]
|
||||
before_action :check_tournament_errors, only: [:generate_matches]
|
||||
before_action :check_for_matches, only: [:up_matches,:bracket,:all_brackets]
|
||||
before_action :check_for_matches, only: [:all_results,:up_matches,:bracket,:all_brackets]
|
||||
before_action :check_access_read, only: [:all_results,:up_matches,:bracket,:all_brackets]
|
||||
|
||||
def weigh_in_sheet
|
||||
|
||||
end
|
||||
|
||||
def export
|
||||
|
||||
end
|
||||
|
||||
def calculate_team_scores
|
||||
@tournament.schools.each do |school|
|
||||
school.calculate_score
|
||||
end
|
||||
respond_to do |format|
|
||||
format.html { redirect_to "/tournaments/#{@tournament.id}", notice: 'Team scores are calcuating.' }
|
||||
end
|
||||
end
|
||||
|
||||
def import
|
||||
import_text = params[:tournament][:import_text]
|
||||
respond_to do |format|
|
||||
if WrestlingdevImporter.new(@tournament,import_text).import
|
||||
format.html { redirect_to "/tournaments/#{@tournament.id}", notice: 'Import is on-going. This will take 1-5 minutes.' }
|
||||
format.json { render action: 'show', status: :created, location: @tournament }
|
||||
if @tournament.calculate_all_team_scores
|
||||
format.html { redirect_to "/tournaments/#{@tournament.id}", notice: 'Team scores are calcuating.' }
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -92,7 +79,7 @@ class TournamentsController < ApplicationController
|
||||
|
||||
def school_delegate
|
||||
if params[:search]
|
||||
@users = User.limit(200).search(params[:search])
|
||||
@user = User.where('email = ?', params[:search]).first
|
||||
elsif params[:school_delegate]
|
||||
@delegate = SchoolDelegate.new
|
||||
@delegate.user_id = params[:school_delegate]["user_id"]
|
||||
@@ -104,19 +91,18 @@ class TournamentsController < ApplicationController
|
||||
format.html { redirect_to "/tournaments/#{@tournament.id}/school_delegate", notice: 'There was an issue delegating permissions please try again' }
|
||||
end
|
||||
end
|
||||
else
|
||||
@users_delegates = []
|
||||
@tournament.schools.each do |s|
|
||||
s.delegates.each do |d|
|
||||
@users_delegates << d
|
||||
end
|
||||
end
|
||||
@users_delegates = []
|
||||
@tournament.schools.each do |s|
|
||||
s.delegates.each do |d|
|
||||
@users_delegates << d
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def delegate
|
||||
if params[:search]
|
||||
@users = User.limit(200).search(params[:search])
|
||||
@user = User.where('email = ?', params[:search]).first
|
||||
elsif params[:tournament_delegate]
|
||||
@delegate = TournamentDelegate.new
|
||||
@delegate.user_id = params[:tournament_delegate]["user_id"]
|
||||
@@ -128,13 +114,12 @@ class TournamentsController < ApplicationController
|
||||
format.html { redirect_to "/tournaments/#{@tournament.id}/delegate", notice: 'There was an issue delegating permissions please try again' }
|
||||
end
|
||||
end
|
||||
else
|
||||
@users_delegates = @tournament.delegates
|
||||
end
|
||||
@users_delegates = @tournament.delegates
|
||||
end
|
||||
|
||||
def matches
|
||||
@matches = @tournament.matches.sort_by{|m| m.bout_number}
|
||||
@matches = @tournament.matches.includes(:wrestlers,:schools).sort_by{|m| m.bout_number}
|
||||
if @match
|
||||
@w1 = @match.wrestler1
|
||||
@w2 = @match.wrestler2
|
||||
@@ -165,7 +150,7 @@ class TournamentsController < ApplicationController
|
||||
end
|
||||
|
||||
def create_custom_weights
|
||||
@custom = params[:customValue].to_s
|
||||
@custom = params[:customValue].split(",")
|
||||
@tournament.create_pre_defined_weights(@custom)
|
||||
redirect_to "/tournaments/#{@tournament.id}"
|
||||
end
|
||||
@@ -174,18 +159,27 @@ class TournamentsController < ApplicationController
|
||||
def all_brackets
|
||||
@schools = @tournament.schools
|
||||
@schools = @schools.sort_by{|s| s.page_score_string}.reverse!
|
||||
@matches = @tournament.matches.includes(:wrestlers,:schools)
|
||||
@weights = @tournament.weights.includes(:matches,:wrestlers)
|
||||
end
|
||||
|
||||
def bracket
|
||||
if params[:weight]
|
||||
@weight = Weight.where(:id => params[:weight]).includes(:matches,:wrestlers).first
|
||||
@matches = @weight.matches
|
||||
@wrestlers = @weight.wrestlers.includes(:school)
|
||||
if @tournament.tournament_type == "Pool to bracket"
|
||||
@pools = @weight.pool_rounds(@matches)
|
||||
@bracketType = @weight.pool_bracket_type
|
||||
end
|
||||
if params[:weight]
|
||||
@weight = Weight.includes(:matches, wrestlers: [:school, :matches_as_w1, :matches_as_w2]).find_by(id: params[:weight])
|
||||
@matches = @weight.matches
|
||||
@wrestlers = @weight.wrestlers
|
||||
|
||||
if @tournament.tournament_type == "Pool to bracket"
|
||||
@pools = @weight.pool_rounds(@matches)
|
||||
@bracketType = @weight.pool_bracket_type
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def all_results
|
||||
@matches = @tournament.matches.includes(:schools,:wrestlers,:weight)
|
||||
@round = nil
|
||||
@bracket_position = nil
|
||||
end
|
||||
|
||||
def generate_matches
|
||||
@@ -204,7 +198,14 @@ class TournamentsController < ApplicationController
|
||||
|
||||
|
||||
def up_matches
|
||||
@matches = @tournament.matches.where("mat_id is NULL and (finished <> ? or finished is NULL)",1).order('bout_number ASC').limit(10).includes(:wrestlers)
|
||||
# .where.not(loser1_name: 'BYE') won't return matches with NULL loser1_name
|
||||
# so I was only getting back matches with Loser of BOUT_NUMBER
|
||||
@matches = @tournament.matches
|
||||
.where("mat_id is NULL and (finished != 1 or finished is NULL)")
|
||||
.where("loser1_name != ? OR loser1_name IS NULL", "BYE")
|
||||
.where("loser2_name != ? OR loser2_name IS NULL", "BYE")
|
||||
.order('bout_number ASC')
|
||||
.limit(10).includes(:wrestlers)
|
||||
@mats = @tournament.mats.includes(:matches)
|
||||
end
|
||||
|
||||
@@ -221,16 +222,18 @@ class TournamentsController < ApplicationController
|
||||
|
||||
def index
|
||||
if params[:search]
|
||||
@tournaments = Tournament.limit(200).search(params[:search]).order("created_at DESC")
|
||||
# @tournaments = Tournament.limit(200).search(params[:search]).order("date DESC")
|
||||
@tournaments = Tournament.limit(200).search_date_name(params[:search]).order("date DESC")
|
||||
else
|
||||
@tournaments = Tournament.all.sort_by{|t| t.days_until_start}.first(20)
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@schools = @tournament.schools.includes(:delegates)
|
||||
@tournament = Tournament.find(params[:id])
|
||||
@schools = @tournament.schools.includes(:delegates).sort_by{|school|school.name}
|
||||
@weights = @tournament.weights.sort_by{|x|[x.max]}
|
||||
@mats = @tournament.mats
|
||||
@mats = @tournament.mats.sort_by{|mat|mat.name}
|
||||
end
|
||||
|
||||
def new
|
||||
@@ -246,6 +249,7 @@ class TournamentsController < ApplicationController
|
||||
redirect_to root_path
|
||||
end
|
||||
@tournament = Tournament.new(tournament_params)
|
||||
@tournament.user_id = current_user.id
|
||||
respond_to do |format|
|
||||
if @tournament.save
|
||||
format.html { redirect_to @tournament, notice: 'Tournament was successfully created.' }
|
||||
@@ -280,15 +284,32 @@ class TournamentsController < ApplicationController
|
||||
def error
|
||||
end
|
||||
|
||||
def reset_bout_board
|
||||
@tournament.reset_and_fill_bout_board
|
||||
redirect_to tournament_path(@tournament), notice: "Successfully reset the bout board."
|
||||
end
|
||||
|
||||
def generate_school_keys
|
||||
@tournament.schools.each do |school|
|
||||
school.update(permission_key: SecureRandom.uuid)
|
||||
end
|
||||
redirect_to school_delegate_path(@tournament), notice: "School permission keys generated successfully."
|
||||
end
|
||||
|
||||
def delete_school_keys
|
||||
@tournament.schools.update_all(permission_key: nil)
|
||||
redirect_to school_delegate_path(@tournament), notice: "All school permission keys have been deleted."
|
||||
end
|
||||
|
||||
private
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_tournament
|
||||
@tournament = Tournament.where(:id => params[:id]).includes(:schools,:weights,:mats,:matches,:user,:wrestlers).first
|
||||
@tournament = Tournament.includes(:user, :mats, :schools, :weights, :matches, wrestlers: [:school, :weight, :matches_as_w1, :matches_as_w2]).find_by(id: params[:id])
|
||||
end
|
||||
|
||||
# Never trust parameters from the scary internet, only allow the white list through.
|
||||
def tournament_params
|
||||
params.require(:tournament).permit(:name, :address, :director, :director_email, :tournament_type, :weigh_in_ref, :user_id, :date, :originalId, :swapId)
|
||||
params.require(:tournament).permit(:name, :address, :director, :director_email, :tournament_type, :weigh_in_ref, :date, :originalId, :swapId, :is_public)
|
||||
end
|
||||
|
||||
#Check for tournament owner
|
||||
@@ -300,6 +321,10 @@ class TournamentsController < ApplicationController
|
||||
authorize! :manage, @tournament
|
||||
end
|
||||
|
||||
def check_access_read
|
||||
authorize! :read, @tournament
|
||||
end
|
||||
|
||||
def check_for_matches
|
||||
if @tournament
|
||||
if @tournament.matches.empty? or @tournament.curently_generating_matches == 1
|
||||
|
||||
48
app/controllers/users_controller.rb
Normal file
48
app/controllers/users_controller.rb
Normal file
@@ -0,0 +1,48 @@
|
||||
class UsersController < ApplicationController
|
||||
before_action :require_login, only: [:edit, :update]
|
||||
before_action :correct_user, only: [:edit, :update]
|
||||
|
||||
def new
|
||||
@user = User.new
|
||||
end
|
||||
|
||||
def create
|
||||
@user = User.new(user_params)
|
||||
if @user.save
|
||||
session[:user_id] = @user.id
|
||||
redirect_to root_path, notice: "Account created successfully"
|
||||
else
|
||||
render 'new'
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@user = User.find(params[:id])
|
||||
end
|
||||
|
||||
def update
|
||||
@user = User.find(params[:id])
|
||||
if @user.update(user_params)
|
||||
redirect_to root_path, notice: "Account updated successfully"
|
||||
else
|
||||
render 'edit'
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:email, :password, :password_confirmation)
|
||||
end
|
||||
|
||||
def require_login
|
||||
unless current_user
|
||||
redirect_to login_path, alert: "Please log in to access this page"
|
||||
end
|
||||
end
|
||||
|
||||
def correct_user
|
||||
@user = User.find(params[:id])
|
||||
redirect_to root_path unless current_user == @user
|
||||
end
|
||||
end
|
||||
@@ -1,21 +1,28 @@
|
||||
class WeightsController < ApplicationController
|
||||
before_action :set_weight, only: [:pool_order, :show, :edit, :update, :destroy,:re_gen]
|
||||
before_action :check_access, only: [:pool_order, :new,:create,:update,:destroy,:edit, :re_gen]
|
||||
before_action :set_weight, only: [:pool_order, :show, :edit, :update, :destroy]
|
||||
before_action :check_access_manage, only: [:pool_order, :new,:create,:update,:destroy,:edit]
|
||||
before_action :check_access_read, only: [:show]
|
||||
|
||||
|
||||
# GET /weights/1
|
||||
# GET /weights/1.json
|
||||
def show
|
||||
if params[:wrestler]
|
||||
check_access_manage
|
||||
respond_to do |format|
|
||||
Wrestler.update(params[:wrestler].keys, params[:wrestler].values)
|
||||
# Sanitize the wrestler parameters
|
||||
sanitized_wrestlers = params.require(:wrestler).to_unsafe_h.transform_values do |attributes|
|
||||
ActionController::Parameters.new(attributes).permit(:original_seed)
|
||||
end
|
||||
|
||||
Wrestler.update(sanitized_wrestlers.keys, sanitized_wrestlers.values)
|
||||
format.html { redirect_to @weight, notice: 'Seeds were successfully updated.' }
|
||||
end
|
||||
end
|
||||
@wrestlers = @weight.wrestlers
|
||||
@tournament = @weight.tournament
|
||||
session[:return_path] = "/weights/#{@weight.id}"
|
||||
end
|
||||
end
|
||||
|
||||
# GET /weights/new
|
||||
def new
|
||||
@@ -72,11 +79,6 @@ class WeightsController < ApplicationController
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
def re_gen
|
||||
@tournament = @weight.tournament
|
||||
GenerateTournamentMatches.new(@tournament).generateWeight(@weight)
|
||||
end
|
||||
|
||||
def pool_order
|
||||
pool = params[:pool_to_order].to_i
|
||||
@@ -96,14 +98,15 @@ class WeightsController < ApplicationController
|
||||
private
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_weight
|
||||
@weight = Weight.where(:id => params[:id]).includes(:tournament,:wrestlers).first
|
||||
# Add nested includes for wrestlers
|
||||
@weight = Weight.includes(:tournament, wrestlers: [:school, :matches_as_w1, :matches_as_w2]).find_by(id: params[:id])
|
||||
end
|
||||
|
||||
# Never trust parameters from the scary internet, only allow the white list through.
|
||||
def weight_params
|
||||
params.require(:weight).permit(:max, :tournament_id, :mat_id)
|
||||
end
|
||||
def check_access
|
||||
def check_access_manage
|
||||
if params[:tournament]
|
||||
@tournament = Tournament.find(params[:tournament])
|
||||
elsif params[:weight]
|
||||
@@ -114,5 +117,16 @@ class WeightsController < ApplicationController
|
||||
authorize! :manage, @tournament
|
||||
end
|
||||
|
||||
def check_access_read
|
||||
if params[:tournament]
|
||||
@tournament = Tournament.find(params[:tournament])
|
||||
elsif params[:weight]
|
||||
@tournament = Tournament.find(params[:weight]["tournament_id"])
|
||||
elsif @weight
|
||||
@tournament = @weight.tournament
|
||||
end
|
||||
authorize! :read, @tournament
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
class WrestlersController < ApplicationController
|
||||
before_action :set_wrestler, only: [:show, :edit, :update, :destroy, :update_pool]
|
||||
before_action :check_access, only: [:new,:create,:update,:destroy,:edit,:update_pool]
|
||||
|
||||
|
||||
|
||||
before_action :set_wrestler, only: [:show, :edit, :update, :destroy]
|
||||
before_action :check_access, only: [:new, :create, :update, :destroy, :edit]
|
||||
before_action :check_read_access, only: [:show]
|
||||
|
||||
# GET /wrestlers/1
|
||||
# GET /wrestlers/1.json
|
||||
@@ -16,132 +14,149 @@ class WrestlersController < ApplicationController
|
||||
# GET /wrestlers/new
|
||||
def new
|
||||
@wrestler = Wrestler.new
|
||||
if params[:school]
|
||||
@school = School.find(params[:school])
|
||||
end
|
||||
if @school
|
||||
@tournament = Tournament.find(@school.tournament_id)
|
||||
end
|
||||
if @tournament
|
||||
@weights = Weight.where(tournament_id: @tournament.id).sort_by{|w| w.max}
|
||||
end
|
||||
|
||||
@school = School.find_by(id: params[:school]) if params[:school]
|
||||
# Save the key into an instance variable so the view can use it.
|
||||
@school_permission_key = params[:school_permission_key].presence
|
||||
@tournament = @school.tournament if @school
|
||||
@weights = @tournament.weights.sort_by(&:max) if @tournament
|
||||
end
|
||||
|
||||
# GET /wrestlers/1/edit
|
||||
def edit
|
||||
@tournament = @wrestler.tournament
|
||||
@weight = @wrestler.weight
|
||||
@weights = @school.tournament.weights.sort_by{|w| w.max}
|
||||
@school = @wrestler.school
|
||||
@weights = @school.tournament.weights.sort_by(&:max)
|
||||
end
|
||||
|
||||
# POST /wrestlers
|
||||
# POST /wrestlers.json
|
||||
def create
|
||||
@wrestler = Wrestler.new(wrestler_params)
|
||||
@school = School.find(wrestler_params[:school_id])
|
||||
@weights = @school.tournament.weights
|
||||
@school = School.find_by(id: wrestler_params[:school_id])
|
||||
# IMPORTANT: Get the key from wrestler_params (not from params directly)
|
||||
@school_permission_key = wrestler_params[:school_permission_key].presence
|
||||
@weights = @school.tournament.weights if @school
|
||||
|
||||
# Remove the key from attributes so it isn't assigned to the model.
|
||||
@wrestler = Wrestler.new(wrestler_params.except(:school_permission_key))
|
||||
|
||||
respond_to do |format|
|
||||
if @wrestler.save
|
||||
if session[:return_path]
|
||||
format.html { redirect_to session.delete(:return_path), notice: 'Wrestler was successfully created.' }
|
||||
else
|
||||
format.html { redirect_to @school, notice: 'Wrestler was successfully created.' }
|
||||
format.json { render action: 'show', status: :created, location: @wrestler }
|
||||
end
|
||||
redirect_path = session[:return_path] || school_path(@school)
|
||||
format.html { redirect_to append_permission_key(redirect_path), notice: 'Wrestler was successfully created.' }
|
||||
format.json { render :show, status: :created, location: @wrestler }
|
||||
else
|
||||
format.html { render action: 'new' }
|
||||
format.html { render :new }
|
||||
format.json { render json: @wrestler.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# PATCH/PUT /wrestlers/1
|
||||
# PATCH/PUT /wrestlers/1.json
|
||||
def update
|
||||
@tournament = @wrestler.tournament
|
||||
@weight = @wrestler.weight
|
||||
@weights = @tournament.weights.sort_by{|w| w.max}
|
||||
@school = @wrestler.school
|
||||
@weights = @tournament.weights.sort_by(&:max)
|
||||
|
||||
respond_to do |format|
|
||||
if @wrestler.update(wrestler_params)
|
||||
if session[:return_path]
|
||||
format.html { redirect_to session.delete(:return_path), notice: 'Wrestler was successfully updated.' }
|
||||
else
|
||||
format.html { redirect_to @school, notice: 'Wrestler was successfully updated.' }
|
||||
format.json { render action: 'show', status: :created, location: @wrestler }
|
||||
end
|
||||
if @wrestler.update(wrestler_params.except(:school_permission_key))
|
||||
redirect_path = session[:return_path] || school_path(@school)
|
||||
format.html { redirect_to append_permission_key(redirect_path), notice: 'Wrestler was successfully updated.' }
|
||||
format.json { render :show, status: :ok, location: @wrestler }
|
||||
else
|
||||
format.html { render action: 'edit' }
|
||||
format.html { render :edit }
|
||||
format.json { render json: @wrestler.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update_pool
|
||||
@tournament = @wrestler.tournament
|
||||
@weight = @wrestler.weight
|
||||
@weights = @tournament.weights.sort_by{|w| w.max}
|
||||
@school = @wrestler.school
|
||||
if params[:wrestler]['pool']
|
||||
@wrestler.pool = params[:wrestler]['pool']
|
||||
respond_to do |format|
|
||||
message = "Wrestler has successfully been switched to a new pool. Matches for that weight are now in a weird state. Please re-generate matches when you are done with all of your changes."
|
||||
if @wrestler.update(wrestler_params)
|
||||
format.html { redirect_to "/tournaments/#{@tournament.id}/brackets/#{@wrestler.weight.id}/", notice: message }
|
||||
format.json { head :no_content }
|
||||
else
|
||||
format.html { render action: 'edit' }
|
||||
format.json { render json: @wrestler.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /wrestlers/1
|
||||
# DELETE /wrestlers/1.json
|
||||
def destroy
|
||||
@school = @wrestler.school
|
||||
@wrestler.destroy
|
||||
message = "Wrestler was successfully deleted. This action has removed all matches. Please re-generate matches if you already had matches."
|
||||
|
||||
respond_to do |format|
|
||||
message = "Wrestler was successfully deleted. This action has removed all matches. Please re-generate matches if you already had matches."
|
||||
if session[:return_path]
|
||||
format.html { redirect_to session.delete(:return_path), notice: message }
|
||||
else
|
||||
format.html { redirect_to @school, notice: message }
|
||||
format.json { head :no_content }
|
||||
end
|
||||
redirect_path = session[:return_path] || school_path(@school)
|
||||
format.html { redirect_to append_permission_key(redirect_path), notice: message }
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_wrestler
|
||||
@wrestler = Wrestler.where(:id => params[:id]).includes(:school, :weight, :tournament, :matches).first
|
||||
|
||||
def set_wrestler
|
||||
@wrestler = Wrestler.includes(:school, :weight, :tournament, :matches_as_w1, :matches_as_w2).find_by(id: params[:id])
|
||||
|
||||
if @wrestler.nil?
|
||||
redirect_to root_path, alert: "Wrestler not found"
|
||||
end
|
||||
end
|
||||
|
||||
def wrestler_params
|
||||
params.require(:wrestler).permit(:name, :school_id, :weight_id, :seed, :original_seed, :season_win,
|
||||
:season_loss, :criteria, :extra, :offical_weight, :pool, :school_permission_key)
|
||||
end
|
||||
|
||||
def check_access
|
||||
if params[:school].present?
|
||||
@school = School.find(params[:school])
|
||||
#@tournament = Tournament.find(@school.tournament.id)
|
||||
elsif params[:wrestler].present?
|
||||
if params[:wrestler]["school_id"].present?
|
||||
@school = School.find(params[:wrestler]["school_id"])
|
||||
if wrestler_params[:school_permission_key].present?
|
||||
@school_permission_key = wrestler_params[:school_permission_key]
|
||||
end
|
||||
else
|
||||
@wrestler = Wrestler.find(params[:wrestler]["id"])
|
||||
@school = @wrestler.school
|
||||
end
|
||||
elsif @wrestler
|
||||
@school = @wrestler.school
|
||||
end
|
||||
|
||||
# Never trust parameters from the scary internet, only allow the white list through.
|
||||
def wrestler_params
|
||||
params.require(:wrestler).permit(:name, :school_id, :weight_id, :seed, :original_seed, :season_win, :season_loss,:criteria,:extra,:offical_weight,:pool)
|
||||
# set @school_permission_key for use in ability
|
||||
if params[:school_permission_key].present?
|
||||
@school_permission_key = params[:school_permission_key]
|
||||
end
|
||||
def check_access
|
||||
if params[:school]
|
||||
@school = School.find(params[:school])
|
||||
#@tournament = Tournament.find(@school.tournament.id)
|
||||
elsif params[:wrestler]
|
||||
if params[:wrestler]["school_id"]
|
||||
@school = School.find(params[:wrestler]["school_id"])
|
||||
else
|
||||
@wrestler = Wrestler.find(params[:wrestler]["id"])
|
||||
@school = @wrestler.school
|
||||
end
|
||||
#@tournament = Tournament.find(@school.tournament.id)
|
||||
elsif @wrestler
|
||||
@school = @wrestler.school
|
||||
#@tournament = @wrestler.tournament
|
||||
elsif wrestler_params
|
||||
@school = School.find(wrestler_params[:school_id])
|
||||
end
|
||||
authorize! :manage, @school
|
||||
authorize! :manage, @school
|
||||
end
|
||||
|
||||
def check_read_access
|
||||
if params[:school]
|
||||
@school = School.find(params[:school])
|
||||
elsif params[:wrestler].present?
|
||||
if params[:wrestler]["school_id"].present?
|
||||
@school = School.find(params[:wrestler]["school_id"])
|
||||
else
|
||||
@wrestler = Wrestler.find(params[:wrestler]["id"])
|
||||
@school = @wrestler.school
|
||||
end
|
||||
if wrestler_params[:school_permission_key].present?
|
||||
@school_permission_key = wrestler_params[:school_permission_key]
|
||||
end
|
||||
elsif @wrestler
|
||||
@school = @wrestler.school
|
||||
end
|
||||
|
||||
# set @school_permission_key for use in ability
|
||||
if params[:school_permission_key].present?
|
||||
@school_permission_key = params[:school_permission_key]
|
||||
end
|
||||
authorize! :read, @school
|
||||
end
|
||||
|
||||
# Helper method to append school_permission_key to redirects if it exists.
|
||||
def append_permission_key(path)
|
||||
return path unless @school_permission_key.present?
|
||||
|
||||
# If path is an ActiveRecord object, convert to URL.
|
||||
path = school_path(path) if path.is_a?(School)
|
||||
uri = URI.parse(path)
|
||||
query_params = Rack::Utils.parse_nested_query(uri.query || "")
|
||||
query_params["school_permission_key"] = @school_permission_key
|
||||
uri.query = query_params.to_query
|
||||
uri.to_s
|
||||
end
|
||||
end
|
||||
|
||||
37
app/jobs/advance_wrestler_job.rb
Normal file
37
app/jobs/advance_wrestler_job.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
class AdvanceWrestlerJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform(wrestler, match)
|
||||
# Add a small delay to increase chance of transaction commit
|
||||
# without this some matches were getting a deserialization error when running the rake task
|
||||
# to finish tournaments
|
||||
sleep(0.5) unless Rails.env.test?
|
||||
|
||||
# Get tournament from wrestler
|
||||
tournament = wrestler.tournament
|
||||
|
||||
# Create job status record
|
||||
job_name = "Advancing wrestler #{wrestler.name}"
|
||||
job_status = TournamentJobStatus.create!(
|
||||
tournament: tournament,
|
||||
job_name: job_name,
|
||||
status: "Running",
|
||||
details: "Match ID: #{match&.bout_number || 'No match'} Wrestler Name #{wrestler&.name || 'No Wrestler'}"
|
||||
)
|
||||
|
||||
begin
|
||||
# Execute the job
|
||||
service = AdvanceWrestler.new(wrestler, match)
|
||||
service.advance_raw
|
||||
|
||||
# Remove the job status record on success
|
||||
TournamentJobStatus.complete_job(tournament.id, job_name)
|
||||
rescue => e
|
||||
# Update status to errored
|
||||
job_status.update(status: "Errored", details: "Error: #{e.message}")
|
||||
|
||||
# Re-raise the error for SolidQueue to handle
|
||||
raise e
|
||||
end
|
||||
end
|
||||
end
|
||||
7
app/jobs/application_job.rb
Normal file
7
app/jobs/application_job.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
class ApplicationJob < ActiveJob::Base
|
||||
# Automatically retry jobs that encountered a deadlock
|
||||
# retry_on ActiveRecord::Deadlocked
|
||||
|
||||
# Most jobs are safe to ignore if the underlying records are no longer available
|
||||
# discard_on ActiveJob::DeserializationError
|
||||
end
|
||||
38
app/jobs/calculate_school_score_job.rb
Normal file
38
app/jobs/calculate_school_score_job.rb
Normal file
@@ -0,0 +1,38 @@
|
||||
class CalculateSchoolScoreJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
# Need for TournamentJobStatusIntegrationTest
|
||||
def self.perform_sync(school)
|
||||
# Execute directly on provided objects
|
||||
school.calculate_score_raw
|
||||
end
|
||||
|
||||
def perform(school)
|
||||
# Log information about the job
|
||||
Rails.logger.info("Calculating score for school ##{school.id} (#{school.name})")
|
||||
|
||||
# Create job status record
|
||||
tournament = school.tournament
|
||||
job_name = "Calculating team score for #{school.name}"
|
||||
job_status = TournamentJobStatus.create!(
|
||||
tournament: tournament,
|
||||
job_name: job_name,
|
||||
status: "Running",
|
||||
details: "School ID: #{school.id}"
|
||||
)
|
||||
|
||||
begin
|
||||
# Execute the calculation
|
||||
school.calculate_score_raw
|
||||
|
||||
# Remove the job status record on success
|
||||
TournamentJobStatus.complete_job(tournament.id, job_name)
|
||||
rescue => e
|
||||
# Update status to errored
|
||||
job_status.update(status: "Errored", details: "Error: #{e.message}")
|
||||
|
||||
# Re-raise the error for SolidQueue to handle
|
||||
raise e
|
||||
end
|
||||
end
|
||||
end
|
||||
20
app/jobs/generate_tournament_matches_job.rb
Normal file
20
app/jobs/generate_tournament_matches_job.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
class GenerateTournamentMatchesJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform(tournament)
|
||||
# Log information about the job
|
||||
Rails.logger.info("Starting tournament match generation for tournament ##{tournament.id}")
|
||||
|
||||
begin
|
||||
# Execute the job
|
||||
generator = GenerateTournamentMatches.new(tournament)
|
||||
generator.generate_raw
|
||||
|
||||
Rails.logger.info("Completed tournament match generation for tournament ##{tournament.id}")
|
||||
rescue => e
|
||||
Rails.logger.error("Error generating tournament matches: #{e.message}")
|
||||
Rails.logger.error(e.backtrace.join("\n"))
|
||||
raise # Re-raise the error so it's properly recorded
|
||||
end
|
||||
end
|
||||
end
|
||||
32
app/jobs/tournament_backup_job.rb
Normal file
32
app/jobs/tournament_backup_job.rb
Normal file
@@ -0,0 +1,32 @@
|
||||
class TournamentBackupJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform(tournament, reason = nil)
|
||||
# Log information about the job
|
||||
Rails.logger.info("Creating backup for tournament ##{tournament.id} (#{tournament.name}), reason: #{reason || 'manual'}")
|
||||
|
||||
# Create job status record
|
||||
job_name = "Backing up tournament"
|
||||
job_status = TournamentJobStatus.create!(
|
||||
tournament: tournament,
|
||||
job_name: job_name,
|
||||
status: "Running",
|
||||
details: "Reason: #{reason || 'manual'}"
|
||||
)
|
||||
|
||||
begin
|
||||
# Execute the backup
|
||||
service = TournamentBackupService.new(tournament, reason)
|
||||
service.create_backup_raw
|
||||
|
||||
# Remove the job status record on success
|
||||
TournamentJobStatus.complete_job(tournament.id, job_name)
|
||||
rescue => e
|
||||
# Update status to errored
|
||||
job_status.update(status: "Errored", details: "Error: #{e.message}")
|
||||
|
||||
# Re-raise the error for SolidQueue to handle
|
||||
raise e
|
||||
end
|
||||
end
|
||||
end
|
||||
36
app/jobs/tournament_cleanup_job.rb
Normal file
36
app/jobs/tournament_cleanup_job.rb
Normal file
@@ -0,0 +1,36 @@
|
||||
class TournamentCleanupJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform
|
||||
# Remove or clean up tournaments based on age and match status
|
||||
process_old_tournaments
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def process_old_tournaments
|
||||
# Get all tournaments older than 1 week that have a user_id
|
||||
old_tournaments = Tournament.where('date < ? AND user_id IS NOT NULL', 1.week.ago.to_date)
|
||||
|
||||
old_tournaments.each do |tournament|
|
||||
# Check if it has any non-BYE finished matches
|
||||
has_real_matches = tournament.matches.where(finished: 1).where.not(win_type: 'BYE').exists?
|
||||
|
||||
if has_real_matches
|
||||
|
||||
# 1. Remove all school delegates
|
||||
tournament.schools.each do |school|
|
||||
school.delegates.destroy_all
|
||||
end
|
||||
|
||||
# 2. Remove all tournament delegates
|
||||
tournament.delegates.destroy_all
|
||||
|
||||
# 3. Set user_id to null
|
||||
tournament.update(user_id: nil)
|
||||
else
|
||||
tournament.destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
33
app/jobs/wrestlingdev_import_job.rb
Normal file
33
app/jobs/wrestlingdev_import_job.rb
Normal file
@@ -0,0 +1,33 @@
|
||||
class WrestlingdevImportJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform(tournament, import_data = nil)
|
||||
# Log information about the job
|
||||
Rails.logger.info("Starting import for tournament ##{tournament.id} (#{tournament.name})")
|
||||
|
||||
# Create job status record
|
||||
job_name = "Importing tournament"
|
||||
job_status = TournamentJobStatus.create!(
|
||||
tournament: tournament,
|
||||
job_name: job_name,
|
||||
status: "Running",
|
||||
details: "Processing backup data"
|
||||
)
|
||||
|
||||
begin
|
||||
# Execute the import
|
||||
importer = WrestlingdevImporter.new(tournament)
|
||||
importer.import_data = import_data if import_data
|
||||
importer.import_raw
|
||||
|
||||
# Remove the job status record on success
|
||||
TournamentJobStatus.complete_job(tournament.id, job_name)
|
||||
rescue => e
|
||||
# Update status to errored
|
||||
job_status.update(status: "Errored", details: "Error: #{e.message}")
|
||||
|
||||
# Re-raise the error for SolidQueue to handle
|
||||
raise e
|
||||
end
|
||||
end
|
||||
end
|
||||
4
app/mailers/application_mailer.rb
Normal file
4
app/mailers/application_mailer.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
class ApplicationMailer < ActionMailer::Base
|
||||
default from: ENV["WRESTLINGDEV_EMAIL"] || 'noreply@wrestlingdev.com'
|
||||
layout 'mailer'
|
||||
end
|
||||
11
app/mailers/user_mailer.rb
Normal file
11
app/mailers/user_mailer.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
class UserMailer < ApplicationMailer
|
||||
# Subject can be set in your I18n file at config/locales/en.yml
|
||||
# with the following lookup:
|
||||
#
|
||||
# en.user_mailer.password_reset.subject
|
||||
#
|
||||
def password_reset(user)
|
||||
@user = user
|
||||
mail to: user.email, subject: "WrestlingDev - Password reset"
|
||||
end
|
||||
end
|
||||
@@ -1,57 +1,74 @@
|
||||
class Ability
|
||||
include CanCan::Ability
|
||||
|
||||
def initialize(user)
|
||||
# Define abilities for the passed in user here. For example:
|
||||
#
|
||||
# user ||= User.new # guest user (not logged in)
|
||||
# if user.admin?
|
||||
# can :manage, :all
|
||||
# else
|
||||
# can :read, :all
|
||||
# end
|
||||
#
|
||||
# The first argument to `can` is the action you are giving the user
|
||||
# permission to do.
|
||||
# If you pass :manage it will apply to every action. Other common actions
|
||||
# here are :read, :create, :update and :destroy.
|
||||
#
|
||||
# The second argument is the resource the user can perform the action on.
|
||||
# If you pass :all it will apply to every resource. Otherwise pass a Ruby
|
||||
# class of the resource.
|
||||
#
|
||||
# The third argument is an optional hash of conditions to further filter the
|
||||
# objects.
|
||||
# For example, here the user can only update published articles.
|
||||
#
|
||||
# can :update, Article, :published => true
|
||||
#
|
||||
# See the wiki for details:
|
||||
# https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities
|
||||
if !user.nil?
|
||||
#Can manage tournament if tournament owner
|
||||
can :manage, Tournament, :user_id => user.id
|
||||
#Can manage but cannot destroy tournament if tournament delegate
|
||||
def initialize(user, school_permission_key = nil)
|
||||
if user
|
||||
# LOGGED IN USER PERMISSIONS
|
||||
|
||||
# TOURNAMENT PERMISSIONS
|
||||
|
||||
# Can manage but cannot destroy tournament if tournament delegate
|
||||
can :manage, Tournament do |tournament|
|
||||
tournament.delegates.map(&:user_id).include? user.id
|
||||
tournament.user_id == user.id ||
|
||||
tournament.delegates.map(&:user_id).include?(user.id)
|
||||
end
|
||||
|
||||
# can destroy tournament if tournament owner
|
||||
can :destroy, Tournament do |tournament|
|
||||
tournament.user_id == user.id
|
||||
end
|
||||
# tournament delegates cannot destroy - explicitly deny
|
||||
cannot :destroy, Tournament do |tournament|
|
||||
tournament.delegates.map(&:user_id).include? user.id
|
||||
tournament.delegates.map(&:user_id).include?(user.id)
|
||||
end
|
||||
#Can manage school if tournament owner
|
||||
|
||||
# Can read tournament if tournament.is_public, tournament owner, or tournament delegate
|
||||
can :read, Tournament do |tournament|
|
||||
tournament.is_public ||
|
||||
tournament.delegates.map(&:user_id).include?(user.id) ||
|
||||
tournament.user_id == user.id
|
||||
end
|
||||
|
||||
# SCHOOL PERMISSIONS
|
||||
# wrestler permissions are included with school permissions
|
||||
|
||||
# Can manage school if is school delegate, is tournament delegate, or is tournament director
|
||||
can :manage, School do |school|
|
||||
school.delegates.map(&:user_id).include?(user.id) ||
|
||||
school.tournament.delegates.map(&:user_id).include?(user.id) ||
|
||||
school.tournament.user_id == user.id
|
||||
end
|
||||
#Can manage school if tournament delegate
|
||||
can :manage, School do |school|
|
||||
school.tournament.delegates.map(&:user_id).include? user.id
|
||||
|
||||
# Can read school if tournament.is_public OR is school delegate, is tournament delegate, or is tournament director
|
||||
can :read, School do |school|
|
||||
school.tournament.is_public ||
|
||||
school.delegates.map(&:user_id).include?(user.id) ||
|
||||
school.tournament.delegates.map(&:user_id).include?(user.id) ||
|
||||
school.tournament.user_id == user.id
|
||||
end
|
||||
#Can manage but cannot destroy school if school delegate
|
||||
can :manage, School do |school|
|
||||
school.delegates.map(&:user_id).include? user.id
|
||||
else
|
||||
# NON LOGGED IN USER PERMISSIONS
|
||||
|
||||
# TOURNAMENT PERMISSIONS
|
||||
|
||||
# Can read tournament if tournament is public
|
||||
can :read, Tournament do |tournament|
|
||||
tournament.is_public
|
||||
end
|
||||
cannot :destroy, School do |school|
|
||||
school.delegates.map(&:user_id).include? user.id
|
||||
|
||||
# SCHOOL PERMISSIONS
|
||||
# wrestler permissions are included with school permissions
|
||||
|
||||
# Can read school if tournament is public or a valid school permission key is provided
|
||||
can :read, School do |school|
|
||||
school.tournament.is_public ||
|
||||
(school_permission_key.present? && school.permission_key == school_permission_key)
|
||||
end
|
||||
|
||||
# Can read school if a valid school permission key is provided
|
||||
# school_permission_key comes from app/controllers/application_controller.rb
|
||||
can :manage, School do |school|
|
||||
(school_permission_key.present? && school.permission_key == school_permission_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
3
app/models/application_record.rb
Normal file
3
app/models/application_record.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
class ApplicationRecord < ActiveRecord::Base
|
||||
self.abstract_class = true
|
||||
end
|
||||
@@ -1,6 +1,7 @@
|
||||
class Mat < ActiveRecord::Base
|
||||
class Mat < ApplicationRecord
|
||||
belongs_to :tournament
|
||||
has_many :matches
|
||||
has_many :matches, dependent: :destroy
|
||||
has_many :mat_assignment_rules, dependent: :destroy
|
||||
|
||||
validates :name, presence: true
|
||||
|
||||
@@ -21,14 +22,65 @@ class Mat < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def assign_next_match
|
||||
t_matches = tournament.matches.select{|m| m.mat_id == nil && m.finished != 1 && m.bout_number != nil}
|
||||
if t_matches.size > 0
|
||||
match = t_matches.sort_by{|m| m.bout_number}.first
|
||||
match = next_eligible_match
|
||||
self.matches.reload
|
||||
if match and self.unfinished_matches.size < 4
|
||||
match.mat_id = self.id
|
||||
match.save
|
||||
if match.save
|
||||
# Invalidate any wrestler caches
|
||||
if match.w1
|
||||
match.wrestler1.touch
|
||||
match.wrestler1.school.touch
|
||||
end
|
||||
if match.w2
|
||||
match.wrestler2.touch
|
||||
match.wrestler2.school.touch
|
||||
end
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
def next_eligible_match
|
||||
# Start with all matches that are either unfinished (nil or 0), have a bout number, and are ordered by bout_number
|
||||
filtered_matches = tournament.matches
|
||||
.where(finished: [nil, 0]) # finished is nil or 0
|
||||
.where(mat_id: nil) # mat_id is nil
|
||||
.where.not(bout_number: nil) # bout_number is not nil
|
||||
.order(:bout_number)
|
||||
|
||||
# Filter out BYE matches
|
||||
filtered_matches = filtered_matches
|
||||
.where("loser1_name != ? OR loser1_name IS NULL", "BYE")
|
||||
.where("loser2_name != ? OR loser2_name IS NULL", "BYE")
|
||||
|
||||
# Apply mat assignment rules
|
||||
mat_assignment_rules.each do |rule|
|
||||
if rule.weight_classes.any?
|
||||
# Ensure weight_classes is treated as an array
|
||||
filtered_matches = filtered_matches.where(weight_id: Array(rule.weight_classes).map(&:to_i))
|
||||
end
|
||||
|
||||
if rule.bracket_positions.any?
|
||||
# Ensure bracket_positions is treated as an array
|
||||
filtered_matches = filtered_matches.where(bracket_position: Array(rule.bracket_positions).map(&:to_s))
|
||||
end
|
||||
|
||||
if rule.rounds.any?
|
||||
# Ensure rounds is treated as an array
|
||||
filtered_matches = filtered_matches.where(round: Array(rule.rounds).map(&:to_i))
|
||||
end
|
||||
end
|
||||
|
||||
# Return the first match in filtered results, or nil if none are left
|
||||
filtered_matches.first
|
||||
end
|
||||
|
||||
|
||||
def unfinished_matches
|
||||
matches.select{|m| m.finished != 1}.sort_by{|m| m.bout_number}
|
||||
end
|
||||
|
||||
29
app/models/mat_assignment_rule.rb
Normal file
29
app/models/mat_assignment_rule.rb
Normal file
@@ -0,0 +1,29 @@
|
||||
class MatAssignmentRule < ApplicationRecord
|
||||
belongs_to :mat
|
||||
belongs_to :tournament
|
||||
|
||||
# Convert comma-separated values to arrays
|
||||
def weight_classes
|
||||
(super || "").split(",").map(&:to_i)
|
||||
end
|
||||
|
||||
def weight_classes=(value)
|
||||
super(value.is_a?(Array) ? value.join(",") : value)
|
||||
end
|
||||
|
||||
def bracket_positions
|
||||
(super || "").split(",")
|
||||
end
|
||||
|
||||
def bracket_positions=(value)
|
||||
super(value.is_a?(Array) ? value.join(",") : value)
|
||||
end
|
||||
|
||||
def rounds
|
||||
(super || "").split(",").map(&:to_i)
|
||||
end
|
||||
|
||||
def rounds=(value)
|
||||
super(value.is_a?(Array) ? value.join(",") : value)
|
||||
end
|
||||
end
|
||||
@@ -1,18 +1,31 @@
|
||||
class Match < ActiveRecord::Base
|
||||
class Match < ApplicationRecord
|
||||
belongs_to :tournament, touch: true
|
||||
belongs_to :weight, touch: true
|
||||
belongs_to :mat, touch: true
|
||||
belongs_to :mat, touch: true, optional: true
|
||||
belongs_to :winner, class_name: 'Wrestler', foreign_key: 'winner_id', optional: true
|
||||
has_many :wrestlers, :through => :weight
|
||||
after_update :after_finished_actions, :if => :saved_change_to_finished? or :saved_change_to_winner_id? or :saved_change_to_win_type? or :saved_change_to_score?
|
||||
has_many :schools, :through => :wrestlers
|
||||
validate :score_validation, :win_type_validation, :bracket_position_validation, :overtime_type_validation
|
||||
|
||||
# Callback to update finished_at when a match is finished
|
||||
before_save :update_finished_at
|
||||
|
||||
after_update :after_finished_actions, if: -> {
|
||||
saved_change_to_finished? ||
|
||||
saved_change_to_winner_id? ||
|
||||
saved_change_to_win_type? ||
|
||||
saved_change_to_score? ||
|
||||
saved_change_to_overtime_type?
|
||||
}
|
||||
|
||||
def after_finished_actions
|
||||
if self.w1
|
||||
wrestler1.touch
|
||||
end
|
||||
if self.w2
|
||||
wrestler2.touch
|
||||
end
|
||||
if self.finished == 1 && self.winner_id != nil
|
||||
if self.w1
|
||||
wrestler1.touch
|
||||
end
|
||||
if self.w2
|
||||
wrestler2.touch
|
||||
end
|
||||
if self.mat
|
||||
self.mat.assign_next_match
|
||||
end
|
||||
@@ -23,9 +36,54 @@ class Match < ActiveRecord::Base
|
||||
|
||||
BRACKET_POSITIONS = ["Pool","1/2","3/4","5/6","7/8","Quarter","Semis","Conso Semis","Bracket","Conso", "Conso Quarter"]
|
||||
WIN_TYPES = ["Decision", "Major", "Tech Fall", "Pin", "Forfeit", "Injury Default", "Default", "DQ", "BYE"]
|
||||
OVERTIME_TYPES = ["", "SV-1", "TB-1", "UTB", "SV-2", "TB-2", "OT"] # had to keep the blank here for validations
|
||||
|
||||
def score_validation
|
||||
if finished == 1
|
||||
if ! winner_id
|
||||
errors.add(:winner_id, "cannot be blank")
|
||||
end
|
||||
if win_type == "Pin" and ! score.match(/^[0-5]?[0-9]:[0-5][0-9]/)
|
||||
errors.add(:score, "needs to be in time format MM:SS when win type is Pin example: 1:23 or 10:03")
|
||||
end
|
||||
if win_type == "Decision" or win_type == "Tech Fall" or win_type == "Major" and ! score.match(/^[0-9]?[0-9]-[0-9]?[0-9]/)
|
||||
errors.add(:score, "needs to be in Number-Number format when win type is Decision, Tech Fall, and Major example: 10-2")
|
||||
end
|
||||
if (win_type == "Forfeit" or win_type == "Injury Default" or win_type == "Default" or win_type == "BYE" or win_type == "DQ") and (score != "")
|
||||
errors.add(:score, "needs to be blank when win type is Forfeit, Injury Default, Default, BYE, or DQ win_type")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def win_type_validation
|
||||
if finished == 1
|
||||
if ! WIN_TYPES.include? win_type
|
||||
errors.add(:win_type, "can only be one of the following #{WIN_TYPES.to_s}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def overtime_type_validation
|
||||
# overtime_type can be nil or of type OVERTIME_TYPES
|
||||
if overtime_type != nil and ! OVERTIME_TYPES.include? overtime_type
|
||||
errors.add(:overtime_type, "can only be one of the following #{OVERTIME_TYPES.to_s}")
|
||||
end
|
||||
end
|
||||
|
||||
def bracket_position_validation
|
||||
# Allow "Bracket Round of 16", "Bracket Round of 16.1",
|
||||
# "Conso Round of 8", "Conso Round of 8.2", etc.
|
||||
bracket_round_regex = /\A(Bracket|Conso) Round of \d+(\.\d+)?\z/
|
||||
|
||||
unless BRACKET_POSITIONS.include?(bracket_position) || bracket_position.match?(bracket_round_regex)
|
||||
errors.add(:bracket_position,
|
||||
"must be one of #{BRACKET_POSITIONS.to_s} " \
|
||||
"or match the pattern 'Bracket Round of X'/'Conso Round of X'")
|
||||
end
|
||||
end
|
||||
|
||||
def is_consolation_match
|
||||
if self.bracket_position == "Conso" or self.bracket_position == "Conso Quarter" or self.bracket_position == "Conso Semis" or self.bracket_position == "3/4" or self.bracket_position == "5/6" or self.bracket_position == "7/8"
|
||||
if self.bracket_position.include? "Conso" or self.bracket_position == "3/4" or self.bracket_position == "5/6" or self.bracket_position == "7/8"
|
||||
return true
|
||||
else
|
||||
return false
|
||||
@@ -33,7 +91,7 @@ class Match < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def is_championship_match
|
||||
if self.bracket_position == "Pool" or self.bracket_position == "Quarter" or self.bracket_position == "Semis" or self.bracket_position == "Bracket" or self.bracket_position == "1/2"
|
||||
if self.bracket_position == "Pool" or self.bracket_position == "Quarter" or self.bracket_position == "Semis" or self.bracket_position.include? "Bracket" or self.bracket_position == "1/2"
|
||||
return true
|
||||
else
|
||||
return false
|
||||
@@ -70,7 +128,7 @@ class Match < ActiveRecord::Base
|
||||
sec = time.partition(':').last.to_i
|
||||
return minutes_in_seconds + sec
|
||||
else
|
||||
nil
|
||||
0
|
||||
end
|
||||
end
|
||||
|
||||
@@ -89,17 +147,19 @@ class Match < ActiveRecord::Base
|
||||
return ""
|
||||
end
|
||||
if self.finished == 1
|
||||
if self.win_type == "Default"
|
||||
return "(Def)"
|
||||
elsif self.win_type == "Injury Default"
|
||||
overtime_type_abbreviation = ""
|
||||
if self.overtime_type != "" and self.overtime_type
|
||||
overtime_type_abbreviation = " #{self.overtime_type}"
|
||||
end
|
||||
if self.win_type == "Injury Default"
|
||||
return "(Inj)"
|
||||
elsif self.win_type == "DQ"
|
||||
return "(DQ)"
|
||||
elsif self.win_type == "Forfeit"
|
||||
return "(For)"
|
||||
return "(FF)"
|
||||
else
|
||||
win_type_abbreviation = "#{self.win_type.chars.to_a[0..2].join('')}"
|
||||
return "(#{win_type_abbreviation} #{self.score})"
|
||||
return "(#{win_type_abbreviation} #{self.score}#{overtime_type_abbreviation})"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -137,56 +197,73 @@ class Match < ActiveRecord::Base
|
||||
end
|
||||
if self.w1 != nil
|
||||
if self.round == 1
|
||||
if self.wrestler1.original_seed
|
||||
return_string = return_string + "[#{wrestler1.original_seed}] "
|
||||
end
|
||||
return_string = return_string + "#{w1_name} - #{wrestler1.school.name} (#{wrestler1.season_win}-#{wrestler1.season_loss})"
|
||||
return_string = return_string + "#{wrestler1.long_bracket_name}"
|
||||
else
|
||||
return_string = return_string + "#{w1_name} (#{wrestler1.school.abbreviation})"
|
||||
return_string = return_string + "#{wrestler1.short_bracket_name}"
|
||||
end
|
||||
else
|
||||
return_string = return_string + "#{w1_name}"
|
||||
return_string = return_string + "#{self.loser1_name}"
|
||||
end
|
||||
return return_string + return_string_ending
|
||||
end
|
||||
|
||||
def w2_bracket_name
|
||||
return_string = ""
|
||||
return_string_ending = ""
|
||||
if self.w2 and self.winner_id == self.w2
|
||||
return_string = return_string + "<strong>"
|
||||
return_string_ending = return_string_ending + "</strong>"
|
||||
end
|
||||
if self.w2 != nil
|
||||
if self.round == 1
|
||||
if self.wrestler2.original_seed
|
||||
return_string = return_string + "#{wrestler2.original_seed} "
|
||||
end
|
||||
return_string = return_string + "#{w2_name} - #{wrestler2.school.name} (#{wrestler2.season_win}-#{wrestler2.season_loss})"
|
||||
else
|
||||
return_string = return_string + "#{w2_name} (#{wrestler2.school.abbreviation})"
|
||||
end
|
||||
else
|
||||
return_string = return_string + "#{w2_name}"
|
||||
end
|
||||
return return_string + return_string_ending
|
||||
return_string = ""
|
||||
return_string_ending = ""
|
||||
if self.w2 and self.winner_id == self.w2
|
||||
return_string = return_string + "<strong>"
|
||||
return_string_ending = return_string_ending + "</strong>"
|
||||
end
|
||||
if self.w2 != nil
|
||||
if self.round == 1
|
||||
return_string = return_string + "#{wrestler2.long_bracket_name}"
|
||||
else
|
||||
return_string = return_string + "#{wrestler2.short_bracket_name}"
|
||||
end
|
||||
else
|
||||
return_string = return_string + "#{self.loser2_name}"
|
||||
end
|
||||
return return_string + return_string_ending
|
||||
end
|
||||
|
||||
def winner_name
|
||||
if self.finished != 1
|
||||
return ""
|
||||
end
|
||||
if self.winner_id == self.w1
|
||||
if self.winner == self.wrestler1
|
||||
return self.w1_name
|
||||
end
|
||||
if self.winner_id == self.w2
|
||||
if self.winner == self.wrestler2
|
||||
return self.w2_name
|
||||
end
|
||||
end
|
||||
|
||||
def all_results_text
|
||||
if self.finished != 1
|
||||
return ""
|
||||
end
|
||||
winning_wrestler = self.winner
|
||||
if winning_wrestler == self.wrestler1
|
||||
losing_wrestler = self.wrestler2
|
||||
elsif winning_wrestler == self.wrestler2
|
||||
losing_wrestler = self.wrestler1
|
||||
else
|
||||
# Handle cases where winner is not w1 or w2 (e.g., BYE, DQ where opponent might be nil)
|
||||
# Or maybe the match hasn't been fully populated yet after a win?
|
||||
# Returning an empty string for now, but this might need review based on expected scenarios.
|
||||
return ""
|
||||
end
|
||||
# Ensure losing_wrestler is not nil before accessing its properties
|
||||
losing_wrestler_name = losing_wrestler ? losing_wrestler.name : "Unknown"
|
||||
losing_wrestler_school = losing_wrestler ? losing_wrestler.school.name : "Unknown"
|
||||
|
||||
return "#{self.weight.max} lbs - #{winning_wrestler.name} (#{winning_wrestler.school.name}) #{self.win_type} #{losing_wrestler_name} (#{losing_wrestler_school}) #{self.score}"
|
||||
end
|
||||
|
||||
def bracket_winner_name
|
||||
if winner_name != ""
|
||||
return "#{winner_name} (#{Wrestler.find(winner_id).school.abbreviation})"
|
||||
# Use the winner association directly
|
||||
if self.winner
|
||||
return "#{self.winner.name} (#{self.winner.school.abbreviation})"
|
||||
else
|
||||
""
|
||||
end
|
||||
@@ -239,4 +316,16 @@ class Match < ActiveRecord::Base
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_finished_at
|
||||
# Get the changes that will be persisted
|
||||
changes = changes_to_save
|
||||
|
||||
# Check if finished is changing from 0 to 1 or if it's already 1 but has no timestamp
|
||||
if (changes['finished'] && changes['finished'][1] == 1) || (finished == 1 && finished_at.nil?)
|
||||
self.finished_at = Time.current.utc
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
class School < ActiveRecord::Base
|
||||
class School < ApplicationRecord
|
||||
belongs_to :tournament, touch: true
|
||||
has_many :wrestlers, dependent: :destroy
|
||||
has_many :deductedPoints, class_name: "Teampointadjust"
|
||||
has_many :delegates, class_name: "SchoolDelegate"
|
||||
has_many :deductedPoints, class_name: "Teampointadjust", dependent: :destroy
|
||||
has_many :delegates, class_name: "SchoolDelegate", dependent: :destroy
|
||||
|
||||
validates :name, presence: true
|
||||
|
||||
@@ -14,10 +14,15 @@ class School < ActiveRecord::Base
|
||||
|
||||
def abbreviation
|
||||
name_array = self.name.split(' ')
|
||||
if name_array.size > 1
|
||||
return "#{name_array[0].chars.to_a.first}#{name_array[1].chars.to_a[0..1].join('').upcase}"
|
||||
if name_array.size > 2
|
||||
# If three words, use first letter of first word, first letter of second, and first two of third
|
||||
return "#{name_array[0].chars.to_a.first}#{name_array[1].chars.to_a.first}#{name_array[2].chars.to_a[0..1].join('').upcase}"
|
||||
elsif name_array.size > 1
|
||||
# If two words use first letter of first word and first three of the second
|
||||
return "#{name_array[0].chars.to_a.first}#{name_array[1].chars.to_a[0..2].join('').upcase}"
|
||||
else
|
||||
return "#{name_array[0].chars.to_a[0..2].join('').upcase}"
|
||||
# If one word use first four letters
|
||||
return "#{name_array[0].chars.to_a[0..3].join('').upcase}"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -31,40 +36,29 @@ class School < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def calculate_score
|
||||
if Rails.env.production?
|
||||
self.delay(:job_owner_id => self.tournament.id, :job_owner_type => "Calculate team score for #{self.name}").calculate_score_raw
|
||||
else
|
||||
calculate_score_raw
|
||||
end
|
||||
|
||||
end
|
||||
# Use perform_later which will execute based on centralized adapter config
|
||||
CalculateSchoolScoreJob.perform_later(self)
|
||||
end
|
||||
|
||||
def calculate_score_raw
|
||||
newScore = total_points_scored_by_wrestlers - total_points_deducted
|
||||
newScore = total_points_scored_by_wrestlers - total_points_deducted
|
||||
self.score = newScore
|
||||
self.save
|
||||
end
|
||||
|
||||
def total_points_scored_by_wrestlers
|
||||
points = 0
|
||||
points = 0.0
|
||||
self.wrestlers.each do |w|
|
||||
if w.extra != true
|
||||
points = points + w.total_team_points
|
||||
end
|
||||
points = points + w.total_team_points
|
||||
end
|
||||
points
|
||||
end
|
||||
|
||||
def total_points_deducted
|
||||
points = 0
|
||||
points = 0.0
|
||||
deductedPoints.each do |d|
|
||||
points = points + d.points
|
||||
end
|
||||
self.wrestlers.each do |w|
|
||||
w.deductedPoints.each do |d|
|
||||
points = points + d.points
|
||||
end
|
||||
end
|
||||
points
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class SchoolDelegate < ActiveRecord::Base
|
||||
class SchoolDelegate < ApplicationRecord
|
||||
belongs_to :school
|
||||
belongs_to :user
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class Teampointadjust < ActiveRecord::Base
|
||||
belongs_to :wrestler, touch: true
|
||||
belongs_to :school, touch: true
|
||||
class Teampointadjust < ApplicationRecord
|
||||
belongs_to :wrestler, touch: true, optional: true
|
||||
belongs_to :school, touch: true, optional: true
|
||||
|
||||
after_save do
|
||||
advance_wrestlers_and_calc_team_score
|
||||
@@ -14,7 +14,7 @@ class Teampointadjust < ActiveRecord::Base
|
||||
#Team score needs calculated
|
||||
if self.wrestler_id != nil
|
||||
#In case this affects pool order
|
||||
AdvanceWrestler.new(self.wrestler).advance
|
||||
AdvanceWrestler.new(self.wrestler,self.wrestler.last_match).advance
|
||||
self.wrestler.school.calculate_score
|
||||
elsif self.school_id != nil
|
||||
self.school.calculate_score
|
||||
|
||||
@@ -1,23 +1,39 @@
|
||||
class Tournament < ActiveRecord::Base
|
||||
class Tournament < ApplicationRecord
|
||||
|
||||
belongs_to :user
|
||||
belongs_to :user, optional: true
|
||||
has_many :schools, dependent: :destroy
|
||||
has_many :weights, dependent: :destroy
|
||||
has_many :mats, dependent: :destroy
|
||||
has_many :wrestlers, through: :weights
|
||||
has_many :matches, dependent: :destroy
|
||||
has_many :delegates, class_name: "TournamentDelegate"
|
||||
has_many :delegates, class_name: "TournamentDelegate", dependent: :destroy
|
||||
has_many :mat_assignment_rules, dependent: :destroy
|
||||
has_many :tournament_backups, dependent: :destroy
|
||||
has_many :tournament_job_statuses, dependent: :destroy
|
||||
|
||||
validates :date, :name, :tournament_type, :address, :director, :director_email , presence: true
|
||||
|
||||
attr_accessor :import_text
|
||||
|
||||
def deferred_jobs
|
||||
Delayed::Job.where(job_owner_id: self.id)
|
||||
end
|
||||
|
||||
def self.search(search)
|
||||
where("date LIKE ? or name LIKE ?", "%#{search}%", "%#{search}%")
|
||||
def self.search_date_name(pattern)
|
||||
if pattern.blank? # blank? covers both nil and empty string
|
||||
all
|
||||
else
|
||||
search_functions = []
|
||||
search_variables = []
|
||||
search_terms = pattern.split(' ').map{|word| "%#{word.downcase}%"}
|
||||
search_terms.each do |word|
|
||||
search_functions << '(LOWER(name) LIKE ? or LOWER(date) LIKE ?)'
|
||||
# add twice for both ?'s in the function above
|
||||
search_variables << word
|
||||
search_variables << word
|
||||
end
|
||||
like_patterns = search_functions.join(' and ')
|
||||
# puts "where(#{like_patterns})"
|
||||
# puts *search_variables
|
||||
# example: (LOWER(name LIKE ? or LOWER(date) LIKE ?) and (LOWER(name) LIKE ? or LOWER(date) LIKE ?), %test%, %test%, %2016%, %2016%
|
||||
where("#{like_patterns}", *search_variables)
|
||||
end
|
||||
end
|
||||
|
||||
def days_until_start
|
||||
@@ -29,17 +45,27 @@ class Tournament < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def tournament_types
|
||||
["Pool to bracket","Modified 16 Man Double Elimination","Double Elimination 1-6"]
|
||||
["Pool to bracket","Modified 16 Man Double Elimination 1-6","Modified 16 Man Double Elimination 1-8","Regular Double Elimination 1-6","Regular Double Elimination 1-8"]
|
||||
end
|
||||
|
||||
def create_pre_defined_weights(value)
|
||||
|
||||
def number_of_placers
|
||||
if self.tournament_type.include? "1-8"
|
||||
return 8
|
||||
elsif self.tournament_type.include? "1-6"
|
||||
return 6
|
||||
end
|
||||
end
|
||||
|
||||
def calculate_all_team_scores
|
||||
self.schools.each do |school|
|
||||
school.calculate_score
|
||||
end
|
||||
end
|
||||
|
||||
def create_pre_defined_weights(weight_classes)
|
||||
weights.destroy_all
|
||||
if value == 'hs'
|
||||
Weight::HS_WEIGHT_CLASSES.each do |w|
|
||||
weights.create(max: w)
|
||||
end
|
||||
else
|
||||
raise "Unspecified behavior"
|
||||
weight_classes.each do |w|
|
||||
weights.create(max: w)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -52,11 +78,8 @@ class Tournament < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def total_rounds
|
||||
if self.matches.count > 0
|
||||
self.matches.sort_by{|m| m.round}.last.round
|
||||
else
|
||||
0
|
||||
end
|
||||
# Assuming this is line 147 that's causing the error
|
||||
matches.maximum(:round) || 0 # Return 0 if no matches or max round is nil
|
||||
end
|
||||
|
||||
def assign_mats(mats_to_assign)
|
||||
@@ -101,22 +124,24 @@ class Tournament < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def pool_to_bracket_weights_with_too_many_wrestlers
|
||||
if self.tournament_type == "Pool to bracket"
|
||||
weightsWithTooManyWrestlers = weights.select{|w| w.wrestlers.size > 24}
|
||||
if weightsWithTooManyWrestlers.size < 1
|
||||
return nil
|
||||
else
|
||||
return weightsWithTooManyWrestlers
|
||||
end
|
||||
else
|
||||
nil
|
||||
end
|
||||
def pool_to_bracket_number_of_wrestlers_error
|
||||
error_string = ""
|
||||
if self.tournament_type.include? "Pool to bracket"
|
||||
weights_with_too_many_wrestlers = weights.select{|w| w.wrestlers.size > 24}
|
||||
weight_with_too_few_wrestlers = weights.select{|w| w.wrestlers.size < 2}
|
||||
weights_with_too_many_wrestlers.each do |weight|
|
||||
error_string = error_string + " The weight class #{weight.max} has more than 24 wrestlers."
|
||||
end
|
||||
weight_with_too_few_wrestlers.each do |weight|
|
||||
error_string = error_string + " The weight class #{weight.max} has less than 2 wrestlers."
|
||||
end
|
||||
end
|
||||
return error_string
|
||||
end
|
||||
|
||||
def modified_sixteen_man_number_of_wrestlers
|
||||
def modified_sixteen_man_number_of_wrestlers_error
|
||||
error_string = ""
|
||||
if self.tournament_type == "Modified 16 Man Double Elimination"
|
||||
if self.tournament_type.include? "Modified 16 Man Double Elimination"
|
||||
weights_with_too_many_wrestlers = weights.select{|w| w.wrestlers.size > 16}
|
||||
weight_with_too_few_wrestlers = weights.select{|w| w.wrestlers.size < 12}
|
||||
weights_with_too_many_wrestlers.each do |weight|
|
||||
@@ -129,10 +154,10 @@ class Tournament < ActiveRecord::Base
|
||||
return error_string
|
||||
end
|
||||
|
||||
def double_elim_number_of_wrestlers
|
||||
def double_elim_number_of_wrestlers_error
|
||||
error_string = ""
|
||||
if self.tournament_type == "Double Elimination 1-6"
|
||||
weights_with_too_many_wrestlers = weights.select{|w| w.wrestlers.size > 16}
|
||||
if self.tournament_type == "Double Elimination 1-6" or self.tournament_type == "Double Elimination 1-8"
|
||||
weights_with_too_many_wrestlers = weights.select{|w| w.wrestlers.size > 32}
|
||||
weight_with_too_few_wrestlers = weights.select{|w| w.wrestlers.size < 4}
|
||||
weights_with_too_many_wrestlers.each do |weight|
|
||||
error_string = error_string + " The weight class #{weight.max} has more than 16 wrestlers."
|
||||
@@ -143,23 +168,115 @@ class Tournament < ActiveRecord::Base
|
||||
end
|
||||
return error_string
|
||||
end
|
||||
|
||||
def wrestlers_with_higher_seed_than_bracket_size_error
|
||||
error_string = ""
|
||||
weights.each do |weight|
|
||||
weight.wrestlers.each do |wrestler|
|
||||
if wrestler.original_seed != nil && wrestler.original_seed > weight.wrestlers.size
|
||||
error_string += "Wrestler: #{wrestler.name} has a seed of #{wrestler.original_seed} which is greater than the amount of wrestlers (#{weight.wrestlers.size}) in the weight class #{weight.max}."
|
||||
end
|
||||
end
|
||||
end
|
||||
return error_string
|
||||
end
|
||||
|
||||
def wrestlers_with_duplicate_original_seed_error
|
||||
error_string = ""
|
||||
weights.each do |weight|
|
||||
weight.wrestlers.select{|wr| wr.original_seed != nil}.each do |wrestler|
|
||||
if weight.wrestlers.select{|wr| wr.original_seed == wrestler.original_seed}.size > 1
|
||||
error_string += "More than 1 wrestler in the #{weight.max} weight class is seeded #{wrestler.original_seed}."
|
||||
end
|
||||
end
|
||||
end
|
||||
return error_string
|
||||
end
|
||||
|
||||
def match_generation_error
|
||||
errorString = "There is a tournament error."
|
||||
modified_sixteen_man_error = modified_sixteen_man_number_of_wrestlers
|
||||
double_elim_error = double_elim_number_of_wrestlers
|
||||
if pool_to_bracket_weights_with_too_many_wrestlers != nil
|
||||
errorString = errorString + " The following weights have too many wrestlers "
|
||||
pool_to_bracket_weights_with_too_many_wrestlers.each do |w|
|
||||
errorString = errorString + "#{w.max} "
|
||||
end
|
||||
return errorString
|
||||
elsif modified_sixteen_man_error.length > 0
|
||||
return errorString + modified_sixteen_man_error
|
||||
elsif double_elim_error.length > 0
|
||||
return error_string + double_elim_error
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
def wrestlers_with_out_of_order_seed_error
|
||||
error_string = ""
|
||||
weights.each do |weight|
|
||||
original_seeds = weight.wrestlers.map(&:original_seed).compact.sort
|
||||
if original_seeds.any? && original_seeds != (original_seeds.first..original_seeds.last).to_a
|
||||
error_string += "The weight class #{weight.max} has wrestlers with out-of-order seeds: #{original_seeds}. There is a gap in the sequence."
|
||||
end
|
||||
end
|
||||
return error_string
|
||||
end
|
||||
|
||||
def match_generation_error
|
||||
error_string = ""
|
||||
if pool_to_bracket_number_of_wrestlers_error.length > 0
|
||||
error_string += pool_to_bracket_number_of_wrestlers_error
|
||||
elsif modified_sixteen_man_number_of_wrestlers_error.length > 0
|
||||
error_string += modified_sixteen_man_number_of_wrestlers_error
|
||||
elsif double_elim_number_of_wrestlers_error.length > 0
|
||||
error_string += double_elim_number_of_wrestlers_error
|
||||
elsif wrestlers_with_higher_seed_than_bracket_size_error.length > 0
|
||||
error_string += wrestlers_with_higher_seed_than_bracket_size_error
|
||||
elsif wrestlers_with_duplicate_original_seed_error.length > 0
|
||||
error_string += wrestlers_with_duplicate_original_seed_error
|
||||
elsif wrestlers_with_out_of_order_seed_error.length > 0
|
||||
error_string += wrestlers_with_out_of_order_seed_error
|
||||
end
|
||||
if error_string.length > 0
|
||||
return "There is a tournament error. #{error_string}"
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
def reset_and_fill_bout_board
|
||||
reset_mats
|
||||
|
||||
if mats.any?
|
||||
4.times do
|
||||
# Iterate over each mat and assign the next available match
|
||||
mats.each do |mat|
|
||||
match_assigned = mat.assign_next_match
|
||||
# If no more matches are available, exit early
|
||||
unless match_assigned
|
||||
puts "No more eligible matches to assign."
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_backup()
|
||||
TournamentBackupService.new(self, "Manual backup").create_backup
|
||||
end
|
||||
|
||||
def confirm_all_weights_have_original_seeds
|
||||
error_string = wrestlers_with_higher_seed_than_bracket_size_error
|
||||
error_string += wrestlers_with_duplicate_original_seed_error
|
||||
error_string += wrestlers_with_out_of_order_seed_error
|
||||
|
||||
return error_string.blank?
|
||||
end
|
||||
|
||||
def confirm_each_weight_class_has_correct_number_of_wrestlers
|
||||
error_string = pool_to_bracket_number_of_wrestlers_error
|
||||
error_string += modified_sixteen_man_number_of_wrestlers_error
|
||||
error_string += double_elim_number_of_wrestlers_error
|
||||
|
||||
return error_string.blank?
|
||||
end
|
||||
|
||||
# Check if there are any active jobs for this tournament
|
||||
def has_active_jobs?
|
||||
tournament_job_statuses.active.exists?
|
||||
end
|
||||
|
||||
# Get all active jobs for this tournament
|
||||
def active_jobs
|
||||
tournament_job_statuses.active
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def connection_adapter
|
||||
ActiveRecord::Base.connection.adapter_name
|
||||
end
|
||||
end
|
||||
5
app/models/tournament_backup.rb
Normal file
5
app/models/tournament_backup.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
class TournamentBackup < ApplicationRecord
|
||||
belongs_to :tournament
|
||||
|
||||
validates :backup_data, presence: true
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
class TournamentDelegate < ActiveRecord::Base
|
||||
class TournamentDelegate < ApplicationRecord
|
||||
belongs_to :tournament
|
||||
belongs_to :user
|
||||
end
|
||||
|
||||
22
app/models/tournament_job_status.rb
Normal file
22
app/models/tournament_job_status.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
class TournamentJobStatus < ApplicationRecord
|
||||
belongs_to :tournament, optional: false
|
||||
|
||||
# Validations
|
||||
validates :job_name, presence: true
|
||||
validates :status, presence: true
|
||||
validates_inclusion_of :status, in: ["Queued", "Running", "Errored"], allow_nil: false
|
||||
validates :tournament, presence: true
|
||||
|
||||
# Scopes
|
||||
scope :active, -> { where.not(status: "Errored") }
|
||||
|
||||
# Class methods to find jobs for a tournament
|
||||
def self.for_tournament(tournament)
|
||||
where(tournament_id: tournament.id)
|
||||
end
|
||||
|
||||
# Clean up completed jobs (should be called when job finishes successfully)
|
||||
def self.complete_job(tournament_id, job_name)
|
||||
where(tournament_id: tournament_id, job_name: job_name).destroy_all
|
||||
end
|
||||
end
|
||||
@@ -1,12 +1,56 @@
|
||||
class User < ActiveRecord::Base
|
||||
class User < ApplicationRecord
|
||||
attr_accessor :reset_token
|
||||
|
||||
# Include default devise modules. Others available are:
|
||||
# :confirmable, :lockable, :timeoutable and :omniauthable
|
||||
has_many :tournaments
|
||||
has_many :delegated_tournament_permissions, class_name: "TournamentDelegate"
|
||||
has_many :delegated_school_permissions, class_name: "SchoolDelegate"
|
||||
has_many :delegated_tournament_permissions, class_name: "TournamentDelegate", dependent: :destroy
|
||||
has_many :delegated_school_permissions, class_name: "SchoolDelegate", dependent: :destroy
|
||||
|
||||
devise :database_authenticatable, :registerable,
|
||||
:recoverable, :rememberable, :trackable, :validatable
|
||||
# Replace Devise with has_secure_password
|
||||
has_secure_password
|
||||
|
||||
# Add validations that were handled by Devise
|
||||
validates :email, presence: true, uniqueness: { case_sensitive: false }
|
||||
validates :password, length: { minimum: 6 }, allow_nil: true
|
||||
|
||||
# These are the Devise modules we were using:
|
||||
# devise :database_authenticatable, :registerable,
|
||||
# :recoverable, :rememberable, :trackable, :validatable
|
||||
|
||||
# Returns the hash digest of the given string
|
||||
def self.digest(string)
|
||||
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
|
||||
BCrypt::Password.create(string, cost: cost)
|
||||
end
|
||||
|
||||
# Returns a random token
|
||||
def self.new_token
|
||||
SecureRandom.urlsafe_base64
|
||||
end
|
||||
|
||||
# Sets the password reset attributes
|
||||
def create_reset_digest
|
||||
self.reset_token = User.new_token
|
||||
update_columns(reset_digest: User.digest(reset_token), reset_sent_at: Time.zone.now)
|
||||
end
|
||||
|
||||
# Sends password reset email
|
||||
def send_password_reset_email
|
||||
UserMailer.password_reset(self).deliver_now
|
||||
end
|
||||
|
||||
# Returns true if a password reset has expired
|
||||
def password_reset_expired?
|
||||
reset_sent_at < 2.hours.ago
|
||||
end
|
||||
|
||||
# Returns true if the given token matches the digest
|
||||
def authenticated?(attribute, token)
|
||||
digest = send("#{attribute}_digest")
|
||||
return false if digest.nil?
|
||||
BCrypt::Password.new(digest).is_password?(token)
|
||||
end
|
||||
|
||||
def delegated_tournaments
|
||||
tournaments_delegated = []
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class Weight < ActiveRecord::Base
|
||||
belongs_to :tournament
|
||||
class Weight < ApplicationRecord
|
||||
belongs_to :tournament, touch: true
|
||||
has_many :wrestlers, dependent: :destroy
|
||||
has_many :matches, dependent: :destroy
|
||||
|
||||
@@ -7,7 +7,13 @@ class Weight < ActiveRecord::Base
|
||||
|
||||
validates :max, presence: true
|
||||
|
||||
HS_WEIGHT_CLASSES = [106,113,120,126,132,138,145,152,160,170,182,195,220,285]
|
||||
# passed via layouts/_tournament-navbar.html.erb
|
||||
# tournaments controller does a .split(',') on this string and creates an array via commas
|
||||
# tournament model runs the code via method create_pre_defined_weights
|
||||
HS_WEIGHT_CLASSES = "106,113,120,126,132,138,144,150,157,165,175,190,215,285"
|
||||
HS_GIRLS_WEIGHT_CLASSES = "100,105,110,115,120,125,130,135,140,145,155,170,190,235"
|
||||
MS_WEIGHT_CLASSES = "80,86,92,98,104,110,116,122,128,134,142,150,160,172,205,245"
|
||||
MS_GIRLS_WEIGHT_CLASSES = "72,80,86,92,98,104,110,116,122,128,134,142,155,170,190,235"
|
||||
|
||||
before_destroy do
|
||||
self.tournament.destroy_all_matches
|
||||
@@ -148,5 +154,48 @@ class Weight < ActiveRecord::Base
|
||||
def wrestlers_without_pool_assignment
|
||||
wrestlers.select{|w| w.pool == nil}
|
||||
end
|
||||
|
||||
|
||||
def calculate_bracket_size
|
||||
num_wrestlers = wrestlers.reload.size
|
||||
return nil if num_wrestlers <= 0 # Handle invalid input
|
||||
|
||||
# Find the smallest power of 2 greater than or equal to num_wrestlers
|
||||
2**Math.log2(num_wrestlers).ceil
|
||||
end
|
||||
|
||||
def highest_bracket_round
|
||||
bracket_matches_sorted_by_round_descending = matches.select{|m| m.bracket_position.include? "Bracket"}.sort_by{|m| m.round}.reverse
|
||||
if bracket_matches_sorted_by_round_descending.size > 0
|
||||
return bracket_matches_sorted_by_round_descending.first.round
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
def lowest_bracket_round
|
||||
bracket_matches_sorted_by_round_ascending = matches.select{|m| m.bracket_position.include? "Bracket"}.sort_by{|m| m.round}
|
||||
if bracket_matches_sorted_by_round_ascending.size > 0
|
||||
return bracket_matches_sorted_by_round_ascending.first.round
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
def highest_conso_round
|
||||
conso_matches_sorted_by_round_descending = matches.select{|m| m.bracket_position.include? "Conso"}.sort_by{|m| m.round}.reverse
|
||||
if conso_matches_sorted_by_round_descending.size > 0
|
||||
return conso_matches_sorted_by_round_descending.first.round
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
def lowest_conso_round
|
||||
conso_matches_sorted_by_round_ascending = matches.select{|m| m.bracket_position.include? "Conso"}.sort_by{|m| m.round}
|
||||
if conso_matches_sorted_by_round_ascending.size > 0
|
||||
return conso_matches_sorted_by_round_ascending.first.round
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
class Wrestler < ActiveRecord::Base
|
||||
class Wrestler < ApplicationRecord
|
||||
belongs_to :school, touch: true
|
||||
belongs_to :weight, touch: true
|
||||
has_one :tournament, through: :weight
|
||||
has_many :matches, through: :weight
|
||||
has_many :deductedPoints, class_name: "Teampointadjust"
|
||||
has_many :matches_as_w1, ->(wrestler){ where(weight_id: wrestler.weight_id) }, class_name: 'Match', foreign_key: 'w1'
|
||||
has_many :matches_as_w2, ->(wrestler){ where(weight_id: wrestler.weight_id) }, class_name: 'Match', foreign_key: 'w2'
|
||||
has_many :deductedPoints, class_name: "Teampointadjust", dependent: :destroy
|
||||
attr_accessor :poolAdvancePoints, :originalId, :swapId
|
||||
|
||||
validates :name, :weight_id, :school_id, presence: true
|
||||
@@ -18,7 +19,7 @@ class Wrestler < ActiveRecord::Base
|
||||
|
||||
|
||||
def last_finished_match
|
||||
all_matches.select{|m| m.finished == 1}.sort_by{|m| m.bout_number}.last
|
||||
all_matches.select{|m| m.finished == 1}.sort_by{|m| m.finished_at}.last
|
||||
end
|
||||
|
||||
def total_team_points
|
||||
@@ -38,7 +39,7 @@ class Wrestler < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def total_pool_points_for_pool_order
|
||||
CalculateWrestlerTeamScore.new(self).poolPoints + CalculateWrestlerTeamScore.new(self).bonusWinPoints
|
||||
CalculateWrestlerTeamScore.new(self).poolPoints + CalculateWrestlerTeamScore.new(self).pool_bonus_points
|
||||
end
|
||||
|
||||
def unfinished_pool_matches
|
||||
@@ -59,7 +60,7 @@ class Wrestler < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def winner_of_last_match?
|
||||
if last_match.winner_id == self.id
|
||||
if last_match && last_match.winner == self # Keep winner association change
|
||||
return true
|
||||
else
|
||||
return false
|
||||
@@ -85,17 +86,30 @@ class Wrestler < ActiveRecord::Base
|
||||
def unfinished_matches
|
||||
all_matches.select{|m| m.finished != 1}.sort_by{|m| m.bout_number}
|
||||
end
|
||||
|
||||
|
||||
def result_by_bout(bout)
|
||||
bout_match = all_matches.select{|m| m.bout_number == bout and m.finished == 1}
|
||||
if bout_match.size == 0
|
||||
bout_match_results = all_matches.select{|m| m.bout_number == bout and m.finished == 1}
|
||||
if bout_match_results.empty?
|
||||
return ""
|
||||
end
|
||||
if bout_match.first.winner_id == self.id
|
||||
return "W #{bout_match.first.bracket_score_string}"
|
||||
bout_match = bout_match_results.first
|
||||
if bout_match.winner == self # Keep winner association change
|
||||
return "W #{bout_match.bracket_score_string}"
|
||||
else
|
||||
return "L #{bout_match.bracket_score_string}"
|
||||
end
|
||||
if bout_match.first.winner_id != self.id
|
||||
return "L #{bout_match.first.bracket_score_string}"
|
||||
end
|
||||
|
||||
def result_by_id(id)
|
||||
bout_match_results = all_matches.select{|m| m.id == id and m.finished == 1}
|
||||
if bout_match_results.empty?
|
||||
return ""
|
||||
end
|
||||
bout_match = bout_match_results.first
|
||||
if bout_match.winner == self # Keep winner association change
|
||||
return "W #{bout_match.bracket_score_string}"
|
||||
else
|
||||
return "L #{bout_match.bracket_score_string}"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -107,7 +121,8 @@ class Wrestler < ActiveRecord::Base
|
||||
if all_matches.blank?
|
||||
return false
|
||||
else
|
||||
return true
|
||||
# Original logic checked blank?, not specific round. Reverting to that.
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
@@ -119,9 +134,22 @@ class Wrestler < ActiveRecord::Base
|
||||
return round_match.bout_number
|
||||
end
|
||||
end
|
||||
|
||||
def match_id_by_round(round)
|
||||
round_match = all_matches.select{|m| m.round == round}.first
|
||||
if round_match.blank?
|
||||
return "BYE"
|
||||
else
|
||||
return round_match.id
|
||||
end
|
||||
end
|
||||
|
||||
# Restore all_matches method
|
||||
def all_matches
|
||||
return matches.select{|m| m.w1 == self.id or m.w2 == self.id}
|
||||
# Combine the two specific associations.
|
||||
# This returns an Array, similar to the previous select method.
|
||||
# Add .uniq for safety and sort for consistent order.
|
||||
(matches_as_w1 + matches_as_w2).uniq.sort_by(&:bout_number)
|
||||
end
|
||||
|
||||
def pool_matches
|
||||
@@ -130,7 +158,9 @@ class Wrestler < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def has_a_pool_bye
|
||||
if weight.pool_rounds(matches) > pool_matches.size
|
||||
# Revert back to using all_matches here too? Seems complex.
|
||||
# Sticking with original: uses `matches` (all weight) and `pool_matches` (derived from all_matches)
|
||||
if weight.pool_rounds(all_matches) > pool_matches.size
|
||||
return true
|
||||
else
|
||||
return false
|
||||
@@ -138,11 +168,19 @@ class Wrestler < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def championship_advancement_wins
|
||||
matches_won.select{|m| (m.bracket_position == "Quarter" or m.bracket_position == "Semis" or m.bracket_position == "Bracket") and m.win_type != "BYE"}
|
||||
matches_won.select{|m| (m.bracket_position == "Quarter" or m.bracket_position == "Semis" or m.bracket_position.include? "Bracket") and m.win_type != "BYE"}
|
||||
end
|
||||
|
||||
def consolation_advancement_wins
|
||||
matches_won.select{|m| (m.bracket_position == "Conso Semis" or m.bracket_position == "Conso" or m.bracket_position == "Conso Quarter") and m.win_type != "BYE"}
|
||||
matches_won.select{|m| (m.bracket_position.include? "Conso") and m.win_type != "BYE"}
|
||||
end
|
||||
|
||||
def championship_byes
|
||||
matches_won.select{|m| (m.bracket_position == "Quarter" or m.bracket_position == "Semis" or m.bracket_position.include? "Bracket") and m.win_type == "BYE"}
|
||||
end
|
||||
|
||||
def consolation_byes
|
||||
matches_won.select{|m| (m.bracket_position.include? "Conso") and m.win_type == "BYE"}
|
||||
end
|
||||
|
||||
def finished_matches
|
||||
@@ -158,7 +196,8 @@ class Wrestler < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def matches_won
|
||||
all_matches.select{|m| m.winner_id == self.id}
|
||||
# Revert, but keep using winner association check
|
||||
all_matches.select{|m| m.winner == self}
|
||||
end
|
||||
|
||||
def pool_wins
|
||||
@@ -196,9 +235,28 @@ class Wrestler < ActiveRecord::Base
|
||||
points_scored
|
||||
end
|
||||
|
||||
def decision_points_scored_pool
|
||||
points_scored = 0
|
||||
decision_wins.select{|m| m.bracket_position == "Pool"}.each do |m|
|
||||
score_of_match = m.score.delete(" ")
|
||||
score_one = score_of_match.partition('-').first.to_i
|
||||
score_two = score_of_match.partition('-').last.to_i
|
||||
if score_one > score_two
|
||||
points_scored = points_scored + score_one
|
||||
elsif score_two > score_one
|
||||
points_scored = points_scored + score_two
|
||||
end
|
||||
end
|
||||
points_scored
|
||||
end
|
||||
|
||||
def fastest_pin
|
||||
pin_wins.sort_by{|m| m.pin_time_in_seconds}.first
|
||||
end
|
||||
|
||||
def fastest_pin_pool
|
||||
pin_wins.select{|m| m.bracket_position == "Pool"}.sort_by{|m| m.pin_time_in_seconds}.first
|
||||
end
|
||||
|
||||
def pin_time
|
||||
time = 0
|
||||
@@ -208,14 +266,28 @@ class Wrestler < ActiveRecord::Base
|
||||
time
|
||||
end
|
||||
|
||||
def pin_time_pool
|
||||
time = 0
|
||||
pin_wins.select{|m| m.bracket_position == "Pool"}.each do | m |
|
||||
time = time + m.pin_time_in_seconds
|
||||
end
|
||||
time
|
||||
end
|
||||
|
||||
def season_win_percentage
|
||||
win = self.season_win.to_f
|
||||
loss = self.season_loss.to_f
|
||||
# Revert to original logic
|
||||
if win > 0 and loss != nil
|
||||
match_total = win + loss
|
||||
percentage_dec = win / match_total
|
||||
percentage = percentage_dec * 100
|
||||
return percentage.to_i
|
||||
if match_total > 0
|
||||
percentage_dec = win / match_total
|
||||
percentage = percentage_dec * 100
|
||||
return percentage.to_i
|
||||
else
|
||||
# Avoid division by zero if somehow win > 0 but total <= 0
|
||||
return 0
|
||||
end
|
||||
elsif self.season_win == 0
|
||||
return 0
|
||||
elsif self.season_win == nil or self.season_loss == nil
|
||||
@@ -223,4 +295,26 @@ class Wrestler < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def long_bracket_name
|
||||
# Revert to original logic
|
||||
return_string = ""
|
||||
if self.original_seed
|
||||
return_string = return_string + "[#{self.original_seed}] "
|
||||
end
|
||||
return_string = return_string + "#{self.name} - #{self.school.name}"
|
||||
if self.season_win && self.season_loss
|
||||
return_string = return_string + " (#{self.season_win}-#{self.season_loss})"
|
||||
end
|
||||
return return_string
|
||||
end
|
||||
|
||||
def short_bracket_name
|
||||
# Revert to original logic
|
||||
return "#{self.name} (#{self.school.abbreviation})"
|
||||
end
|
||||
|
||||
def name_with_school
|
||||
# Revert to original logic
|
||||
return "#{self.name} - #{self.school.name}"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
class AdvanceWrestler
|
||||
def initialize( wrestler, last_match )
|
||||
def initialize(wrestler, last_match)
|
||||
@wrestler = wrestler
|
||||
@tournament = @wrestler.tournament
|
||||
@last_match = last_match
|
||||
end
|
||||
|
||||
def advance
|
||||
if Rails.env.production?
|
||||
self.delay(:job_owner_id => @tournament.id, :job_owner_type => "Advance wrestler #{@wrestler.name} in the bracket").advance_raw
|
||||
else
|
||||
advance_raw
|
||||
end
|
||||
# Use perform_later which will execute based on centralized adapter config
|
||||
# This will be converted to inline execution in test environment by ActiveJob
|
||||
AdvanceWrestlerJob.perform_later(@wrestler, @last_match)
|
||||
end
|
||||
|
||||
def advance_raw
|
||||
|
||||
if @last_match && @last_match.finished?
|
||||
pool_to_bracket_advancement if @tournament.tournament_type == "Pool to bracket"
|
||||
DoubleEliminationAdvance.new(@wrestler, @last_match).bracket_advancement if @tournament.tournament_type == "Modified 16 Man Double Elimination" or
|
||||
@tournament.tournament_type == "Double Elimination 1-6"
|
||||
ModifiedDoubleEliminationAdvance.new(@wrestler, @last_match).bracket_advancement if @tournament.tournament_type.include? "Modified 16 Man Double Elimination"
|
||||
DoubleEliminationAdvance.new(@wrestler, @last_match).bracket_advancement if @tournament.tournament_type.include? "Regular Double Elimination"
|
||||
end
|
||||
end
|
||||
|
||||
def pool_to_bracket_advancement
|
||||
|
||||
@@ -7,62 +7,52 @@ class DoubleEliminationAdvance
|
||||
end
|
||||
|
||||
def bracket_advancement
|
||||
if @last_match.winner_id == @wrestler.id
|
||||
winner_advance
|
||||
end
|
||||
if @last_match.winner_id != @wrestler.id
|
||||
loser_advance
|
||||
end
|
||||
advance_wrestler
|
||||
advance_double_byes
|
||||
set_bye_for_placement
|
||||
end
|
||||
|
||||
def winner_advance
|
||||
def advance_wrestler
|
||||
# Advance winner
|
||||
if @last_match.winner == @wrestler
|
||||
winners_bracket_advancement
|
||||
# Advance loser
|
||||
elsif @last_match.winner != @wrestler
|
||||
losers_bracket_advancement
|
||||
end
|
||||
end
|
||||
|
||||
def winners_bracket_advancement
|
||||
if (@last_match.loser1_name == "BYE" or @last_match.loser2_name == "BYE") and @last_match.is_championship_match
|
||||
update_consolation_bye
|
||||
end
|
||||
if @last_match.bracket_position == "Quarter"
|
||||
new_match = Match.where("bracket_position = ? AND bracket_position_number = ? AND weight_id = ?","Semis",@next_match_position_number.ceil,@wrestler.weight_id).first
|
||||
update_new_match(new_match, get_wrestler_number)
|
||||
elsif @last_match.bracket_position == "Semis"
|
||||
new_match = Match.where("bracket_position = ? AND bracket_position_number = ? AND weight_id = ?","1/2",@next_match_position_number.ceil,@wrestler.weight_id).first
|
||||
update_new_match(new_match, get_wrestler_number)
|
||||
elsif @last_match.bracket_position == "Conso Semis"
|
||||
# if its a regular double elim
|
||||
if Match.where("bracket_position = ? AND bracket_position_number = ? AND weight_id = ?","Conso Semis",@next_match_position_number.ceil,@wrestler.weight_id).first.loser1_name != nil
|
||||
new_match = Match.where("bracket_position = ? AND bracket_position_number = ? AND weight_id = ?","3/4",@next_match_position_number.ceil,@wrestler.weight_id).first
|
||||
update_new_match(new_match, get_wrestler_number)
|
||||
# if it's a special bracket where consolations wrestler for 5th
|
||||
else
|
||||
new_match = Match.where("bracket_position = ? AND bracket_position_number = ? AND weight_id = ?","5/6",@next_match_position_number.ceil,@wrestler.weight_id).first
|
||||
update_new_match(new_match, get_wrestler_number)
|
||||
end
|
||||
elsif @last_match.bracket_position == "Conso Quarter"
|
||||
next_round_matches = Match.where("weight_id = ? and bracket_position = ?", @wrestler.weight_id, "Conso Semis").sort_by{|m| m.round}
|
||||
this_round_matches = Match.where("weight_id = ? and round = ? and bracket_position = ?", @wrestler.weight_id, @last_match.round, "Conso Quarter")
|
||||
if next_round_matches.size == this_round_matches.size
|
||||
# if a semi loser is dropping down
|
||||
new_match = Match.where("bracket_position = ? AND bracket_position_number = ? AND weight_id = ?","Conso Semis",@last_match.bracket_position_number,@wrestler.weight_id).first
|
||||
update_new_match(new_match,2)
|
||||
else
|
||||
# if it's a special bracket where a semi loser is not dropping down
|
||||
new_match = Match.where("bracket_position = ? AND bracket_position_number = ? AND weight_id = ?","Conso Semis",@next_match_position_number.ceil,@wrestler.weight_id).first
|
||||
update_new_match(new_match, get_wrestler_number)
|
||||
end
|
||||
elsif @last_match.bracket_position == "Bracket"
|
||||
new_match = Match.where("bracket_position_number = ? and weight_id = ? and round > ? and (bracket_position = ? or bracket_position = ?)", @next_match_position_number.ceil,@wrestler.weight_id, @last_match.round , "Bracket", "Quarter").sort_by{|m| m.round}.first
|
||||
update_new_match(new_match, get_wrestler_number)
|
||||
elsif @last_match.bracket_position == "Conso"
|
||||
next_round = next_round_matches = Match.where("weight_id = ? and round > ? and (bracket_position = ? or bracket_position = ?)", @wrestler.weight_id, @last_match.round, "Conso", "Conso Quarter").sort_by{|m| m.round}.first.round
|
||||
next_round_matches = Match.where("weight_id = ? and round = ? and (bracket_position = ? or bracket_position = ?)", @wrestler.weight_id, next_round, "Conso", "Conso Quarter")
|
||||
this_round_matches = Match.where("weight_id = ? and round = ? and (bracket_position = ? or bracket_position = ?)", @wrestler.weight_id, @last_match.round, "Conso", "Conso Quarter")
|
||||
# if a loser is dropping down
|
||||
if next_round_matches.size == this_round_matches.size
|
||||
new_match = Match.where("bracket_position_number = ? and weight_id = ? and round > ? and (bracket_position = ? or bracket_position = ?)", @last_match.bracket_position_number,@wrestler.weight_id, @last_match.round, "Conso", "Conso Quarter").sort_by{|m| m.round}.first
|
||||
update_new_match(new_match, 2)
|
||||
else
|
||||
new_match = Match.where("bracket_position_number = ? and weight_id = ? and round > ? and (bracket_position = ? or bracket_position = ?)", @next_match_position_number.ceil,@wrestler.weight_id, @last_match.round, "Conso", "Conso Quarter").sort_by{|m| m.round}.first
|
||||
update_new_match(new_match, get_wrestler_number)
|
||||
end
|
||||
|
||||
future_round_matches = @last_match.weight.matches.select{|m| m.round > @last_match.round}
|
||||
next_match = nil
|
||||
next_match_bracket_position = nil
|
||||
next_match_position_number = @next_match_position_number.ceil
|
||||
|
||||
if @last_match.is_championship_match and future_round_matches.size > 0
|
||||
next_match_round = future_round_matches.select{|m| m.is_championship_match}.sort_by{|m| m.round}.first.round
|
||||
next_match_bracket_position = future_round_matches.select{|m| m.is_championship_match}.sort_by{|m| m.round}.first.bracket_position
|
||||
end
|
||||
|
||||
if @last_match.is_consolation_match and future_round_matches.size > 0
|
||||
next_match_round = future_round_matches.select{|m| m.is_consolation_match}.sort_by{|m| m.round}.first.round
|
||||
next_match_bracket_position = future_round_matches.select{|m| m.is_consolation_match}.sort_by{|m| m.round}.first.bracket_position
|
||||
next_match_loser1_name = future_round_matches.select{|m| m.is_consolation_match}.sort_by{|m| m.round}.first.loser1_name
|
||||
# If someone is falling down to them in this round, then their bracket_position_number stays the same
|
||||
if next_match_loser1_name
|
||||
next_match_position_number = @last_match.bracket_position_number
|
||||
end
|
||||
end
|
||||
|
||||
if next_match_bracket_position
|
||||
next_match = Match.where("bracket_position = ? AND bracket_position_number = ? AND weight_id = ?",next_match_bracket_position,next_match_position_number.ceil,@wrestler.weight_id).first
|
||||
end
|
||||
|
||||
if next_match
|
||||
update_new_match(next_match, get_wrestler_number)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -92,26 +82,39 @@ class DoubleEliminationAdvance
|
||||
end
|
||||
end
|
||||
|
||||
def loser_advance
|
||||
bout = @last_match.bout_number
|
||||
next_match = Match.where("(loser1_name = ? OR loser2_name = ?) AND weight_id = ?","Loser of #{bout}","Loser of #{bout}",@wrestler.weight_id)
|
||||
if next_match.size > 0
|
||||
next_match = next_match.first
|
||||
next_match.replace_loser_name_with_wrestler(@wrestler,"Loser of #{bout}")
|
||||
if next_match.loser1_name == "BYE" or next_match.loser2_name == "BYE"
|
||||
next_match.winner_id = @wrestler.id
|
||||
next_match.win_type = "BYE"
|
||||
next_match.finished = 1
|
||||
next_match.save
|
||||
next_match.advance_wrestlers
|
||||
end
|
||||
def losers_bracket_advancement
|
||||
bout = @last_match.bout_number
|
||||
next_match = Match.where("(loser1_name = ? OR loser2_name = ?) AND weight_id = ?", "Loser of #{bout}", "Loser of #{bout}", @wrestler.weight_id).first
|
||||
|
||||
if next_match.present?
|
||||
next_match.replace_loser_name_with_wrestler(@wrestler, "Loser of #{bout}")
|
||||
next_match.reload
|
||||
|
||||
if next_match.loser1_name == "BYE" || next_match.loser2_name == "BYE"
|
||||
next_match.winner_id = @wrestler.id
|
||||
next_match.win_type = "BYE"
|
||||
next_match.score = ""
|
||||
next_match.finished = 1
|
||||
# puts "Before save: winner_id=#{next_match.winner_id}"
|
||||
|
||||
# if next_match.save
|
||||
# puts "Save successful: winner_id=#{next_match.reload.winner_id}"
|
||||
# else
|
||||
# puts "Save failed: #{next_match.errors.full_messages}"
|
||||
# end
|
||||
next_match.save
|
||||
|
||||
next_match.advance_wrestlers
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def advance_double_byes
|
||||
weight = @wrestler.weight
|
||||
weight.matches.select{|m| m.loser1_name == "BYE" and m.loser2_name == "BYE" and m.finished != 1}.each do |match|
|
||||
match.finished = 1
|
||||
match.score = ""
|
||||
match.win_type = "BYE"
|
||||
next_match_position_number = (match.bracket_position_number / 2.0).ceil
|
||||
after_matches = weight.matches.select{|m| m.round > match.round and m.is_consolation_match == match.is_consolation_match }.sort_by{|m| m.round}
|
||||
@@ -134,4 +137,26 @@ class DoubleEliminationAdvance
|
||||
match.save
|
||||
end
|
||||
end
|
||||
|
||||
def set_bye_for_placement
|
||||
weight = @wrestler.weight
|
||||
fifth_finals = weight.matches.select{|match| match.bracket_position == '5/6'}.first
|
||||
seventh_finals = weight.matches.select{|match| match.bracket_position == '7/8'}.first
|
||||
if seventh_finals
|
||||
conso_quarter = weight.matches.select{|match| match.bracket_position == 'Conso Quarter'}
|
||||
conso_quarter.each do |match|
|
||||
if match.loser1_name == "BYE" or match.loser2_name == "BYE"
|
||||
seventh_finals.replace_loser_name_with_bye("Loser of #{match.bout_number}")
|
||||
end
|
||||
end
|
||||
end
|
||||
if fifth_finals
|
||||
conso_semis = weight.matches.select{|match| match.bracket_position == 'Conso Semis'}
|
||||
conso_semis.each do |match|
|
||||
if match.loser1_name == "BYE" or match.loser2_name == "BYE"
|
||||
fifth_finals.replace_loser_name_with_bye("Loser of #{match.bout_number}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
class ModifiedDoubleEliminationAdvance
|
||||
|
||||
def initialize(wrestler,last_match)
|
||||
@wrestler = wrestler
|
||||
@last_match = last_match
|
||||
@next_match_position_number = (@last_match.bracket_position_number / 2.0)
|
||||
end
|
||||
|
||||
def bracket_advancement
|
||||
advance_wrestler
|
||||
advance_double_byes
|
||||
set_bye_for_placement
|
||||
end
|
||||
|
||||
def advance_wrestler
|
||||
if @last_match.winner == @wrestler
|
||||
winners_bracket_advancement
|
||||
elsif @last_match.winner != @wrestler
|
||||
losers_bracket_advancement
|
||||
end
|
||||
end
|
||||
|
||||
def winners_bracket_advancement
|
||||
if (@last_match.loser1_name == "BYE" or @last_match.loser2_name == "BYE") and @last_match.is_championship_match
|
||||
update_consolation_bye
|
||||
end
|
||||
if @last_match.bracket_position == "Quarter"
|
||||
new_match = Match.where("bracket_position = ? AND bracket_position_number = ? AND weight_id = ?","Semis",@next_match_position_number.ceil,@wrestler.weight_id).first
|
||||
update_new_match(new_match, get_wrestler_number)
|
||||
elsif @last_match.bracket_position == "Semis"
|
||||
new_match = Match.where("bracket_position = ? AND bracket_position_number = ? AND weight_id = ?","1/2",@next_match_position_number.ceil,@wrestler.weight_id).first
|
||||
update_new_match(new_match, get_wrestler_number)
|
||||
elsif @last_match.bracket_position == "Conso Semis"
|
||||
new_match = Match.where("bracket_position = ? AND bracket_position_number = ? AND weight_id = ?","5/6",@next_match_position_number.ceil,@wrestler.weight_id).first
|
||||
update_new_match(new_match, get_wrestler_number)
|
||||
elsif @last_match.bracket_position == "Conso Quarter"
|
||||
# it's a special bracket where a semi loser is not dropping down
|
||||
new_match = Match.where("bracket_position = ? AND bracket_position_number = ? AND weight_id = ?","Conso Semis",@next_match_position_number.ceil,@wrestler.weight_id).first
|
||||
update_new_match(new_match, get_wrestler_number)
|
||||
elsif @last_match.bracket_position == "Bracket Round of 16"
|
||||
new_match = Match.where("bracket_position_number = ? and weight_id = ? and round > ? and bracket_position = ?", @next_match_position_number.ceil,@wrestler.weight_id, @last_match.round , "Quarter").sort_by{|m| m.round}.first
|
||||
update_new_match(new_match, get_wrestler_number)
|
||||
elsif @last_match.bracket_position == "Conso Round of 8"
|
||||
new_match = Match.where("bracket_position_number = ? and weight_id = ? and round > ? and bracket_position = ?", @last_match.bracket_position_number,@wrestler.weight_id, @last_match.round, "Conso Quarter").sort_by{|m| m.round}.first
|
||||
update_new_match(new_match, get_wrestler_number)
|
||||
end
|
||||
end
|
||||
|
||||
def update_new_match(match, wrestler_number)
|
||||
if wrestler_number == 2 or (match.loser1_name and match.loser1_name.include? "Loser of")
|
||||
match.w2 = @wrestler.id
|
||||
match.save
|
||||
elsif wrestler_number == 1
|
||||
match.w1 = @wrestler.id
|
||||
match.save
|
||||
end
|
||||
end
|
||||
|
||||
def update_consolation_bye
|
||||
bout = @wrestler.last_match.bout_number
|
||||
next_match = Match.where("(loser1_name = ? OR loser2_name = ?) AND weight_id = ?","Loser of #{bout}","Loser of #{bout}",@wrestler.weight_id)
|
||||
if next_match.size > 0
|
||||
next_match.first.replace_loser_name_with_bye("Loser of #{bout}")
|
||||
end
|
||||
end
|
||||
|
||||
def get_wrestler_number
|
||||
if @next_match_position_number != @next_match_position_number.ceil
|
||||
return 1
|
||||
elsif @next_match_position_number == @next_match_position_number.ceil
|
||||
return 2
|
||||
end
|
||||
end
|
||||
|
||||
def losers_bracket_advancement
|
||||
bout = @last_match.bout_number
|
||||
next_match = Match.where("(loser1_name = ? OR loser2_name = ?) AND weight_id = ?", "Loser of #{bout}", "Loser of #{bout}", @wrestler.weight_id).first
|
||||
|
||||
if next_match.present?
|
||||
next_match.replace_loser_name_with_wrestler(@wrestler, "Loser of #{bout}")
|
||||
next_match.reload
|
||||
|
||||
if next_match.loser1_name == "BYE" || next_match.loser2_name == "BYE"
|
||||
next_match.winner_id = @wrestler.id
|
||||
next_match.win_type = "BYE"
|
||||
next_match.score = ""
|
||||
next_match.finished = 1
|
||||
# puts "Before save: winner_id=#{next_match.winner_id}"
|
||||
|
||||
# if next_match.save
|
||||
# puts "Save successful: winner_id=#{next_match.reload.winner_id}"
|
||||
# else
|
||||
# puts "Save failed: #{next_match.errors.full_messages}"
|
||||
# end
|
||||
next_match.save
|
||||
|
||||
next_match.advance_wrestlers
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def advance_double_byes
|
||||
weight = @wrestler.weight
|
||||
weight.matches.select{|m| m.loser1_name == "BYE" and m.loser2_name == "BYE" and m.finished != 1}.each do |match|
|
||||
match.finished = 1
|
||||
match.score = ""
|
||||
match.win_type = "BYE"
|
||||
next_match_position_number = (match.bracket_position_number / 2.0).ceil
|
||||
after_matches = weight.matches.select{|m| m.round > match.round and m.is_consolation_match == match.is_consolation_match }.sort_by{|m| m.round}
|
||||
next_matches = weight.matches.select{|m| m.round == after_matches.first.round and m.is_consolation_match == match.is_consolation_match }
|
||||
this_round_matches = weight.matches.select{|m| m.round == match.round and m.is_consolation_match == match.is_consolation_match }
|
||||
|
||||
if next_matches.size == this_round_matches.size
|
||||
next_match = next_matches.select{|m| m.bracket_position_number == match.bracket_position_number}.first
|
||||
next_match.loser2_name = "BYE"
|
||||
next_match.save
|
||||
elsif next_matches.size < this_round_matches.size and next_matches.size > 0
|
||||
next_match = next_matches.select{|m| m.bracket_position_number == next_match_position_number}.first
|
||||
if next_match.bracket_position_number == next_match_position_number
|
||||
next_match.loser2_name = "BYE"
|
||||
else
|
||||
next_match.loser1_name = "BYE"
|
||||
end
|
||||
end
|
||||
next_match.save
|
||||
match.save
|
||||
end
|
||||
end
|
||||
|
||||
def set_bye_for_placement
|
||||
weight = @wrestler.weight
|
||||
seventh_finals = weight.matches.select{|match| match.bracket_position == '7/8'}.first
|
||||
if seventh_finals
|
||||
conso_quarter = weight.matches.select{|match| match.bracket_position == 'Conso Semis'}
|
||||
conso_quarter.each do |match|
|
||||
if match.loser1_name == "BYE" or match.loser2_name == "BYE"
|
||||
seventh_finals.replace_loser_name_with_bye("Loser of #{match.bout_number}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,15 +30,20 @@ class PoolAdvance
|
||||
end
|
||||
|
||||
def bracketAdvancment
|
||||
if @last_match.winner_id == @wrestler.id
|
||||
winnerAdvance
|
||||
end
|
||||
if @last_match.winner_id != @wrestler.id
|
||||
loserAdvance
|
||||
end
|
||||
advance_wrestlers
|
||||
end
|
||||
|
||||
def winnerAdvance
|
||||
def advance_wrestlers
|
||||
# Advance winner
|
||||
if @last_match.winner == @wrestler
|
||||
winner_advance
|
||||
# Advance loser
|
||||
elsif @last_match.winner != @wrestler
|
||||
loser_advance
|
||||
end
|
||||
end
|
||||
|
||||
def winner_advance
|
||||
if @wrestler.last_match.bracket_position == "Quarter"
|
||||
new_match = Match.where("bracket_position = ? AND bracket_position_number = ? AND weight_id = ?","Semis",@wrestler.next_match_position_number.ceil,@wrestler.weight_id).first
|
||||
updateNewMatch(new_match)
|
||||
@@ -65,7 +70,7 @@ class PoolAdvance
|
||||
end
|
||||
end
|
||||
|
||||
def loserAdvance
|
||||
def loser_advance
|
||||
bout = @wrestler.last_match.bout_number
|
||||
next_match = Match.where("(loser1_name = ? OR loser2_name = ?) AND weight_id = ?","Loser of #{bout}","Loser of #{bout}",@wrestler.weight_id)
|
||||
if next_match.size > 0
|
||||
|
||||
@@ -4,36 +4,48 @@ class PoolOrder
|
||||
end
|
||||
|
||||
def getPoolOrder
|
||||
# clear caching for weight for bracket page
|
||||
@wrestlers.first.weight.touch
|
||||
setOriginalPoints
|
||||
while checkForTieBreakers == true
|
||||
breakTie
|
||||
while checkForTies(@wrestlers) == true
|
||||
getWrestlersOrderByPoolAdvancePoints.each do |wrestler|
|
||||
wrestlers_with_same_points = getWrestlersOrderByPoolAdvancePoints.select{|w| w.poolAdvancePoints == wrestler.poolAdvancePoints}
|
||||
if wrestlers_with_same_points.size > 1
|
||||
breakTie(wrestlers_with_same_points)
|
||||
end
|
||||
end
|
||||
end
|
||||
@wrestlers.sort_by{|w| w.poolAdvancePoints}.reverse.each_with_index do |wrestler, index|
|
||||
placement = index + 1
|
||||
wrestler.pool_placement = placement
|
||||
wrestler.save
|
||||
getWrestlersOrderByPoolAdvancePoints.each_with_index do |wrestler, index|
|
||||
placement = index + 1
|
||||
wrestler.pool_placement = placement
|
||||
wrestler.save
|
||||
end
|
||||
@wrestlers.sort_by{|w| w.poolAdvancePoints}.reverse!
|
||||
end
|
||||
|
||||
def getWrestlersOrderByPoolAdvancePoints
|
||||
@wrestlers.sort_by{|w| w.poolAdvancePoints}.reverse
|
||||
end
|
||||
|
||||
def setOriginalPoints
|
||||
@wrestlers.each do |w|
|
||||
matches = w.reload.all_matches
|
||||
w.pool_placement_tiebreaker = nil
|
||||
w.pool_placement = nil
|
||||
w.poolAdvancePoints = w.pool_wins.size
|
||||
end
|
||||
end
|
||||
|
||||
def checkForTieBreakers
|
||||
if wrestlersWithSamePoints.size > 1
|
||||
def checkForTies(wrestlers_to_check)
|
||||
if wrestlersWithSamePoints(wrestlers_to_check).size > 1
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def wrestlersWithSamePoints
|
||||
@wrestlers.each do |w|
|
||||
wrestlersWithSamePointsLocal = @wrestlers.select{|wr| wr.poolAdvancePoints == w.poolAdvancePoints}
|
||||
def wrestlersWithSamePoints(wrestlers_to_check)
|
||||
wrestlers_to_check.each do |w|
|
||||
wrestlersWithSamePointsLocal = wrestlers_to_check.select{|wr| wr.poolAdvancePoints == w.poolAdvancePoints}
|
||||
if wrestlersWithSamePointsLocal.size > 1
|
||||
return wrestlersWithSamePointsLocal
|
||||
end
|
||||
@@ -41,42 +53,47 @@ class PoolOrder
|
||||
return []
|
||||
end
|
||||
|
||||
def ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize)
|
||||
if wrestlersWithSamePoints.size == originalTieSize
|
||||
def ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize,wrestlers_to_check)
|
||||
if wrestlersWithSamePoints(wrestlers_to_check).size == originalTieSize
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def breakTie
|
||||
originalTieSize = wrestlersWithSamePoints.size
|
||||
deductedPoints(originalTieSize) if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize)
|
||||
def breakTie(wrestlers_with_same_points)
|
||||
originalTieSize = wrestlers_with_same_points.size
|
||||
deductedPoints(originalTieSize,wrestlers_with_same_points) if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize,wrestlers_with_same_points)
|
||||
if originalTieSize == 2
|
||||
headToHead if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize)
|
||||
headToHead(wrestlers_with_same_points) if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize,wrestlers_with_same_points)
|
||||
end
|
||||
teamPoints if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize)
|
||||
mostFalls if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize)
|
||||
mostTechs if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize)
|
||||
mostMajors if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize)
|
||||
mostDecisionPointsScored if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize)
|
||||
fastest_pins if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize)
|
||||
coinFlip if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize)
|
||||
teamPoints(wrestlers_with_same_points) if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize,wrestlers_with_same_points)
|
||||
mostFalls(wrestlers_with_same_points) if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize,wrestlers_with_same_points)
|
||||
mostTechs(wrestlers_with_same_points) if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize,wrestlers_with_same_points)
|
||||
mostMajors(wrestlers_with_same_points) if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize,wrestlers_with_same_points)
|
||||
mostDecisionPointsScored(wrestlers_with_same_points) if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize,wrestlers_with_same_points)
|
||||
fastest_pins(wrestlers_with_same_points) if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize,wrestlers_with_same_points)
|
||||
coinFlip(wrestlers_with_same_points) if ifWrestlersWithSamePointsIsSameAsOriginal(originalTieSize,wrestlers_with_same_points)
|
||||
end
|
||||
|
||||
|
||||
def headToHead
|
||||
wrestlersWithSamePoints.each do |wr|
|
||||
otherWrestler = wrestlersWithSamePoints.select{|w| w.id != wr.id}.first
|
||||
if otherWrestler and wr.match_against(otherWrestler).first.winner_id == wr.id
|
||||
addPointsToWrestlersAhead(wr)
|
||||
wr.pool_placement_tiebreaker = "Head to Head"
|
||||
def headToHead(wrestlers_with_same_points)
|
||||
wrestlers_with_same_points.each do |wr|
|
||||
otherWrestler = wrestlers_with_same_points.select{|w| w.id != wr.id}.first
|
||||
if otherWrestler
|
||||
matches = wr.match_against(otherWrestler).select { |match| match.bracket_position == "Pool" }
|
||||
if matches.any? && matches.first.winner == wr
|
||||
addPointsToWrestlersAhead(wr)
|
||||
wr.pool_placement_tiebreaker = "Head to Head"
|
||||
addPoints(wr)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def addPoints(wrestler)
|
||||
# addPointsToWrestlersAhead(wrestler)
|
||||
# Cannot go here because if team points are the same the first with points added will stay ahead
|
||||
wrestler.poolAdvancePoints = wrestler.poolAdvancePoints + 1
|
||||
end
|
||||
|
||||
@@ -87,13 +104,13 @@ class PoolOrder
|
||||
end
|
||||
end
|
||||
|
||||
def deductedPoints(originalTieSize)
|
||||
def deductedPoints(originalTieSize,wrestlers_with_same_points)
|
||||
pointsArray = []
|
||||
wrestlersWithSamePoints.each do |w|
|
||||
wrestlers_with_same_points.each do |w|
|
||||
pointsArray << w.total_points_deducted
|
||||
end
|
||||
leastPoints = pointsArray.min
|
||||
wrestlersWithLeastDeductedPoints = wrestlersWithSamePoints.select{|w| w.total_points_deducted == leastPoints}
|
||||
wrestlersWithLeastDeductedPoints = wrestlers_with_same_points.select{|w| w.total_points_deducted == leastPoints}
|
||||
addPointsToWrestlersAhead(wrestlersWithLeastDeductedPoints.first)
|
||||
if wrestlersWithLeastDeductedPoints.size != originalTieSize
|
||||
wrestlersWithLeastDeductedPoints.each do |wr|
|
||||
@@ -103,38 +120,37 @@ class PoolOrder
|
||||
end
|
||||
end
|
||||
|
||||
def mostDecisionPointsScored
|
||||
def mostDecisionPointsScored(wrestlers_with_same_points)
|
||||
pointsArray = []
|
||||
wrestlersWithSamePoints.each do |w|
|
||||
pointsArray << w.decision_points_scored
|
||||
wrestlers_with_same_points.each do |w|
|
||||
pointsArray << w.decision_points_scored_pool
|
||||
end
|
||||
mostPoints = pointsArray.max
|
||||
wrestlersWithMostPoints = wrestlersWithSamePoints.select{|w| w.decision_points_scored == mostPoints}
|
||||
wrestlersWithMostPoints = wrestlers_with_same_points.select{|w| w.decision_points_scored_pool == mostPoints}
|
||||
addPointsToWrestlersAhead(wrestlersWithMostPoints.first)
|
||||
wrestlersWithMostPoints.each do |wr|
|
||||
wr.pool_placement_tiebreaker = "Points Scored"
|
||||
wr.pool_placement_tiebreaker = "Decision Points Scored"
|
||||
addPoints(wr)
|
||||
end
|
||||
secondPoints = pointsArray.sort[-2]
|
||||
wrestlersWithSecondMostPoints = wrestlersWithSamePoints.select{|w| w.decision_points_scored == secondPoints}
|
||||
wrestlersWithSecondMostPoints = wrestlers_with_same_points.select{|w| w.decision_points_scored_pool == secondPoints}
|
||||
addPointsToWrestlersAhead(wrestlersWithSecondMostPoints.first)
|
||||
wrestlersWithSecondMostPoints.each do |wr|
|
||||
wr.pool_placement_tiebreaker = "Points Scored"
|
||||
wr.pool_placement_tiebreaker = "Decision Points Scored"
|
||||
addPoints(wr)
|
||||
end
|
||||
end
|
||||
|
||||
def fastest_pins
|
||||
def fastest_pins(wrestlers_with_same_points)
|
||||
wrestlersWithSamePointsWithPins = []
|
||||
wrestlersWithSamePoints.each do |wr|
|
||||
if wr.pin_wins.size > 0
|
||||
wrestlers_with_same_points.each do |wr|
|
||||
if wr.pin_wins.select{|m| m.bracket_position == "Pool"}.size > 0
|
||||
wrestlersWithSamePointsWithPins << wr
|
||||
end
|
||||
end
|
||||
if wrestlersWithSamePointsWithPins.size > 0
|
||||
fastest = wrestlersWithSamePointsWithPins.sort_by{|w| w.fastest_pin.pin_time_in_seconds}.first.fastest_pin
|
||||
secondFastest = wrestlersWithSamePointsWithPins.sort_by{|w| w.fastest_pin.pin_time_in_seconds}.second.fastest_pin
|
||||
wrestlersWithFastestPin = wrestlersWithSamePointsWithPins.select{|w| w.fastest_pin.pin_time_in_seconds == fastest.pin_time_in_seconds}
|
||||
fastest = wrestlersWithSamePointsWithPins.sort_by{|w| w.pin_time_pool}.first.pin_time_pool
|
||||
wrestlersWithFastestPin = wrestlersWithSamePointsWithPins.select{|w| w.pin_time_pool == fastest}
|
||||
addPointsToWrestlersAhead(wrestlersWithFastestPin.first)
|
||||
wrestlersWithFastestPin.each do |wr|
|
||||
wr.pool_placement_tiebreaker = "Pin Time"
|
||||
@@ -143,13 +159,13 @@ class PoolOrder
|
||||
end
|
||||
end
|
||||
|
||||
def teamPoints
|
||||
pointsArray = []
|
||||
wrestlersWithSamePoints.each do |w|
|
||||
pointsArray << w.total_pool_points_for_pool_order
|
||||
def teamPoints(wrestlers_with_same_points)
|
||||
teamPointsArray = []
|
||||
wrestlers_with_same_points.each do |w|
|
||||
teamPointsArray << w.total_pool_points_for_pool_order
|
||||
end
|
||||
mostPoints = pointsArray.max
|
||||
wrestlersSortedByTeamPoints = wrestlersWithSamePoints.select{|w| w.total_pool_points_for_pool_order == mostPoints}
|
||||
mostPoints = teamPointsArray.max
|
||||
wrestlersSortedByTeamPoints = wrestlers_with_same_points.select{|w| w.total_pool_points_for_pool_order == mostPoints}
|
||||
addPointsToWrestlersAhead(wrestlersSortedByTeamPoints.first)
|
||||
wrestlersSortedByTeamPoints.each do |wr|
|
||||
wr.pool_placement_tiebreaker = "Team Points"
|
||||
@@ -157,50 +173,56 @@ class PoolOrder
|
||||
end
|
||||
end
|
||||
|
||||
def mostFalls
|
||||
pointsArray = []
|
||||
wrestlersWithSamePoints.each do |w|
|
||||
pointsArray << w.pin_wins.size
|
||||
def mostFalls(wrestlers_with_same_points)
|
||||
mostPins = []
|
||||
wrestlers_with_same_points.each do |w|
|
||||
mostPins << w.pin_wins.select{|m| m.bracket_position == "Pool"}.size
|
||||
end
|
||||
pinsMax = mostPins.max
|
||||
wrestlersSortedByFallWins = wrestlers_with_same_points.select{|w| w.pin_wins.select{|m| m.bracket_position == "Pool"}.size == pinsMax}
|
||||
if pinsMax > 0
|
||||
addPointsToWrestlersAhead(wrestlersSortedByFallWins.first)
|
||||
wrestlersSortedByFallWins.each do |wr|
|
||||
wr.pool_placement_tiebreaker = "Most Pins"
|
||||
addPoints(wr)
|
||||
end
|
||||
end
|
||||
mostPoints = pointsArray.max
|
||||
wrestlersSortedByFallWins = wrestlersWithSamePoints.select{|w| w.pin_wins.size == mostPoints}
|
||||
addPointsToWrestlersAhead(wrestlersSortedByFallWins.first)
|
||||
wrestlersSortedByFallWins.each do |wr|
|
||||
wr.pool_placement_tiebreaker = "Most Pins"
|
||||
addPoints(wr)
|
||||
end
|
||||
end
|
||||
|
||||
def mostTechs
|
||||
pointsArray = []
|
||||
wrestlersWithSamePoints.each do |w|
|
||||
pointsArray << w.tech_wins.size
|
||||
def mostTechs(wrestlers_with_same_points)
|
||||
techsArray = []
|
||||
wrestlers_with_same_points.each do |w|
|
||||
techsArray << w.tech_wins.select{|m| m.bracket_position == "Pool"}.size
|
||||
end
|
||||
mostTechsWins = techsArray.max
|
||||
wrestlersSortedByTechWins = wrestlers_with_same_points.select{|w| w.tech_wins.select{|m| m.bracket_position == "Pool"}.size == mostTechsWins}
|
||||
if mostTechsWins > 0
|
||||
addPointsToWrestlersAhead(wrestlersSortedByTechWins.first)
|
||||
wrestlersSortedByTechWins.each do |wr|
|
||||
wr.pool_placement_tiebreaker = "Most Techs"
|
||||
addPoints(wr)
|
||||
end
|
||||
end
|
||||
mostPoints = pointsArray.max
|
||||
wrestlersSortedByTechWins = wrestlersWithSamePoints.select{|w| w.tech_wins.size == mostPoints}
|
||||
addPointsToWrestlersAhead(wrestlersSortedByTechWins.first)
|
||||
wrestlersSortedByTechWins.each do |wr|
|
||||
wr.pool_placement_tiebreaker = "Most Techs"
|
||||
addPoints(wr)
|
||||
end
|
||||
end
|
||||
|
||||
def mostMajors
|
||||
pointsArray = []
|
||||
wrestlersWithSamePoints.each do |w|
|
||||
pointsArray << w.major_wins.size
|
||||
def mostMajors(wrestlers_with_same_points)
|
||||
majorsArray = []
|
||||
wrestlers_with_same_points.each do |w|
|
||||
majorsArray << w.major_wins.select{|m| m.bracket_position == "Pool"}.size
|
||||
end
|
||||
mostMajorWins = majorsArray.max
|
||||
wrestlersSortedByMajorWins = wrestlers_with_same_points.select{|w| w.major_wins.select{|m| m.bracket_position == "Pool"}.size == mostMajorWins}
|
||||
if mostMajorWins > 0
|
||||
addPointsToWrestlersAhead(wrestlersSortedByMajorWins.first)
|
||||
wrestlersSortedByMajorWins.each do |wr|
|
||||
wr.pool_placement_tiebreaker = "Most Majors"
|
||||
addPoints(wr)
|
||||
end
|
||||
end
|
||||
mostPoints = pointsArray.max
|
||||
wrestlersSortedByMajorWins = wrestlersWithSamePoints.select{|w| w.major_wins.size == mostPoints}
|
||||
addPointsToWrestlersAhead(wrestlersSortedByMajorWins.first)
|
||||
wrestlersSortedByMajorWins.each do |wr|
|
||||
wr.pool_placement_tiebreaker = "Most Majors"
|
||||
addPoints(wr)
|
||||
end
|
||||
end
|
||||
|
||||
def coinFlip
|
||||
wrestler = wrestlersWithSamePoints.sample
|
||||
def coinFlip(wrestlers_with_same_points)
|
||||
wrestler = wrestlers_with_same_points.sample
|
||||
wrestler.pool_placement_tiebreaker = "Coin Flip"
|
||||
addPointsToWrestlersAhead(wrestler)
|
||||
addPoints(wrestler)
|
||||
|
||||
@@ -1,13 +1,132 @@
|
||||
class DoubleEliminationGenerateLoserNames
|
||||
def initialize( tournament )
|
||||
@tournament = tournament
|
||||
end
|
||||
def initialize(tournament)
|
||||
@tournament = tournament
|
||||
end
|
||||
|
||||
def assign_loser_names
|
||||
@tournament.weights.each do |weight|
|
||||
SixteenManDoubleEliminationGenerateLoserNames.new(weight).assign_loser_names_for_weight if weight.wrestlers.size >= 9 and weight.wrestlers.size <= 16
|
||||
EightManDoubleEliminationGenerateLoserNames.new(weight).assign_loser_names_for_weight if weight.wrestlers.size >= 4 and weight.wrestlers.size <= 8
|
||||
def assign_loser_names
|
||||
@tournament.weights.each do |weight|
|
||||
assign_loser_names_for_weight(weight)
|
||||
advance_bye_matches_championship(weight.matches.reload)
|
||||
end
|
||||
end
|
||||
|
||||
def define_losername_championship_mappings(bracket_size)
|
||||
# Use hashes instead of arrays for mappings
|
||||
case bracket_size
|
||||
when 4
|
||||
[
|
||||
{ conso_bracket_position: "3/4", championship_bracket_position: "Semis", cross_bracket: false, both_wrestlers: true }
|
||||
]
|
||||
when 8
|
||||
[
|
||||
{ conso_bracket_position: "Conso Quarter", championship_bracket_position: "Quarter", cross_bracket: false, both_wrestlers: true },
|
||||
{ conso_bracket_position: "Conso Semis", championship_bracket_position: "Semis", cross_bracket: true, both_wrestlers: false }
|
||||
]
|
||||
when 16
|
||||
[
|
||||
{ conso_bracket_position: "Conso Round of 8.1", championship_bracket_position: "Bracket Round of 16", cross_bracket: false, both_wrestlers: true },
|
||||
{ conso_bracket_position: "Conso Round of 8.2", championship_bracket_position: "Quarter", cross_bracket: true, both_wrestlers: false },
|
||||
{ conso_bracket_position: "Conso Semis", championship_bracket_position: "Semis", cross_bracket: false, both_wrestlers: false }
|
||||
]
|
||||
when 32
|
||||
[
|
||||
{ conso_bracket_position: "Conso Round of 16.1", championship_bracket_position: "Bracket Round of 32", cross_bracket: false, both_wrestlers: true },
|
||||
{ conso_bracket_position: "Conso Round of 16.2", championship_bracket_position: "Bracket Round of 16", cross_bracket: true, both_wrestlers: false },
|
||||
{ conso_bracket_position: "Conso Round of 8.2", championship_bracket_position: "Quarter", cross_bracket: false, both_wrestlers: false },
|
||||
{ conso_bracket_position: "Conso Semis", championship_bracket_position: "Semis", cross_bracket: true, both_wrestlers: false },
|
||||
|
||||
]
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def assign_loser_names_for_weight(weight)
|
||||
number_of_placers = @tournament.number_of_placers
|
||||
bracket_size = weight.calculate_bracket_size
|
||||
matches_by_weight = weight.matches.reload
|
||||
|
||||
loser_name_championship_mappings = define_losername_championship_mappings(bracket_size)
|
||||
|
||||
loser_name_championship_mappings.each do |mapping|
|
||||
conso_bracket_position = mapping[:conso_bracket_position]
|
||||
championship_bracket_position = mapping[:championship_bracket_position]
|
||||
cross_bracket = mapping[:cross_bracket]
|
||||
both_wrestlers = mapping[:both_wrestlers]
|
||||
|
||||
conso_matches = matches_by_weight.select do |match|
|
||||
match.bracket_position == conso_bracket_position && match.bracket_position == conso_bracket_position
|
||||
end.sort_by(&:bracket_position_number)
|
||||
|
||||
championship_matches = matches_by_weight.select do |match|
|
||||
match.bracket_position == championship_bracket_position && match.bracket_position == championship_bracket_position
|
||||
end.sort_by(&:bracket_position_number)
|
||||
|
||||
conso_matches.reverse! if cross_bracket
|
||||
|
||||
championship_bracket_position_number = 1
|
||||
conso_matches.each do |match|
|
||||
bout_number1 = championship_matches.find do |bout_match|
|
||||
bout_match.bracket_position_number == championship_bracket_position_number
|
||||
end.bout_number
|
||||
|
||||
match.loser1_name = "Loser of #{bout_number1}"
|
||||
if both_wrestlers
|
||||
championship_bracket_position_number += 1
|
||||
bout_number2 = championship_matches.find do |bout_match|
|
||||
bout_match.bracket_position_number == championship_bracket_position_number
|
||||
end.bout_number
|
||||
match.loser2_name = "Loser of #{bout_number2}"
|
||||
end
|
||||
championship_bracket_position_number += 1
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
conso_semi_matches = matches_by_weight.select { |match| match.bracket_position == "Conso Semis" }
|
||||
conso_quarter_matches = matches_by_weight.select { |match| match.bracket_position == "Conso Quarter" }
|
||||
|
||||
if number_of_placers >= 6 && weight.wrestlers.size >= 5
|
||||
five_six_match = matches_by_weight.find { |match| match.bracket_position == "5/6" }
|
||||
bout_number1 = conso_semi_matches.find { |match| match.bracket_position_number == 1 }.bout_number
|
||||
bout_number2 = conso_semi_matches.find { |match| match.bracket_position_number == 2 }.bout_number
|
||||
five_six_match.loser1_name = "Loser of #{bout_number1}"
|
||||
five_six_match.loser2_name = "Loser of #{bout_number2}"
|
||||
end
|
||||
|
||||
if number_of_placers >= 8 && weight.wrestlers.size >= 7
|
||||
seven_eight_match = matches_by_weight.find { |match| match.bracket_position == "7/8" }
|
||||
bout_number1 = conso_quarter_matches.find { |match| match.bracket_position_number == 1 }.bout_number
|
||||
bout_number2 = conso_quarter_matches.find { |match| match.bracket_position_number == 2 }.bout_number
|
||||
seven_eight_match.loser1_name = "Loser of #{bout_number1}"
|
||||
seven_eight_match.loser2_name = "Loser of #{bout_number2}"
|
||||
end
|
||||
|
||||
save_matches(matches_by_weight)
|
||||
end
|
||||
|
||||
def save_matches(matches)
|
||||
matches.each(&:save!)
|
||||
end
|
||||
|
||||
def advance_bye_matches_championship(matches)
|
||||
first_round = matches.sort_by{|m| m.round}.first.round
|
||||
matches.select do |m|
|
||||
m.round == first_round
|
||||
end.sort_by(&:bracket_position_number).each do |match|
|
||||
next unless match.w1.nil? || match.w2.nil?
|
||||
|
||||
match.finished = 1
|
||||
match.win_type = "BYE"
|
||||
if match.w1
|
||||
match.winner_id = match.w1
|
||||
match.loser2_name = "BYE"
|
||||
elsif match.w2
|
||||
match.winner_id = match.w2
|
||||
match.loser1_name = "BYE"
|
||||
end
|
||||
match.score = ""
|
||||
match.save
|
||||
match.advance_wrestlers
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,12 +1,275 @@
|
||||
class DoubleEliminationMatchGeneration
|
||||
def initialize( tournament )
|
||||
@tournament = tournament
|
||||
def initialize(tournament)
|
||||
@tournament = tournament
|
||||
end
|
||||
|
||||
def generate_matches
|
||||
#
|
||||
# PHASE 1: Generate matches (with local round definitions).
|
||||
#
|
||||
@tournament.weights.each do |weight|
|
||||
generate_matches_for_weight(weight)
|
||||
end
|
||||
|
||||
def generate_matches
|
||||
@tournament.weights.each do |weight|
|
||||
SixteenManDoubleEliminationMatchGeneration.new(weight).generate_matches_for_weight if weight.wrestlers.size >= 9 and weight.wrestlers.size <= 16
|
||||
EightManDoubleEliminationMatchGeneration.new(weight).generate_matches_for_weight if weight.wrestlers.size >= 4 and weight.wrestlers.size <= 8
|
||||
#
|
||||
# PHASE 2: Align all rounds to match the largest bracket’s definitions.
|
||||
#
|
||||
align_all_rounds_to_largest_bracket
|
||||
end
|
||||
|
||||
###########################################################################
|
||||
# PHASE 1: Generate all matches for each bracket, using a single definition.
|
||||
###########################################################################
|
||||
def generate_matches_for_weight(weight)
|
||||
bracket_size = weight.calculate_bracket_size
|
||||
bracket_info = define_bracket_matches(bracket_size)
|
||||
return unless bracket_info
|
||||
|
||||
# 1) Round one matchups
|
||||
bracket_info[:round_one_matchups].each_with_index do |matchup, idx|
|
||||
seed1, seed2 = matchup[:seeds]
|
||||
bracket_position = matchup[:bracket_position]
|
||||
bracket_pos_number = idx + 1
|
||||
round_number = matchup[:round] # Use the round from our definition
|
||||
|
||||
create_matchup_from_seed(
|
||||
seed1,
|
||||
seed2,
|
||||
bracket_position,
|
||||
bracket_pos_number,
|
||||
round_number,
|
||||
weight
|
||||
)
|
||||
end
|
||||
|
||||
# 2) Championship rounds
|
||||
bracket_info[:championship_rounds].each do |round_info|
|
||||
bracket_position = round_info[:bracket_position]
|
||||
matches_this_round = round_info[:number_of_matches]
|
||||
round_number = round_info[:round]
|
||||
|
||||
matches_this_round.times do |i|
|
||||
create_matchup(
|
||||
nil,
|
||||
nil,
|
||||
bracket_position,
|
||||
i + 1,
|
||||
round_number,
|
||||
weight
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# 3) Consolation rounds
|
||||
bracket_info[:consolation_rounds].each do |round_info|
|
||||
bracket_position = round_info[:bracket_position]
|
||||
matches_this_round = round_info[:number_of_matches]
|
||||
round_number = round_info[:round]
|
||||
|
||||
matches_this_round.times do |i|
|
||||
create_matchup(
|
||||
nil,
|
||||
nil,
|
||||
bracket_position,
|
||||
i + 1,
|
||||
round_number,
|
||||
weight
|
||||
)
|
||||
end
|
||||
|
||||
#
|
||||
# 5/6, 7/8 placing logic
|
||||
#
|
||||
if weight.wrestlers.size >= 5
|
||||
if @tournament.number_of_placers >= 6 && matches_this_round == 1
|
||||
create_matchup(nil, nil, "5/6", 1, round_number, weight)
|
||||
end
|
||||
end
|
||||
if weight.wrestlers.size >= 7
|
||||
if @tournament.number_of_placers >= 8 && matches_this_round == 1
|
||||
create_matchup(nil, nil, "7/8", 1, round_number, weight)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Single bracket definition that includes both bracket_position and round.
|
||||
# If you later decide to tweak round numbering, you do it in ONE place.
|
||||
#
|
||||
def define_bracket_matches(bracket_size)
|
||||
case bracket_size
|
||||
when 4
|
||||
{
|
||||
round_one_matchups: [
|
||||
# First round is Semis => round=1
|
||||
{ seeds: [1, 4], bracket_position: "Semis", round: 1 },
|
||||
{ seeds: [2, 3], bracket_position: "Semis", round: 1 }
|
||||
],
|
||||
championship_rounds: [
|
||||
# Final => round=2
|
||||
{ bracket_position: "1/2", number_of_matches: 1, round: 2 }
|
||||
],
|
||||
consolation_rounds: [
|
||||
# 3rd place => round=2
|
||||
{ bracket_position: "3/4", number_of_matches: 1, round: 2 }
|
||||
]
|
||||
}
|
||||
|
||||
when 8
|
||||
{
|
||||
round_one_matchups: [
|
||||
# Quarter => round=1
|
||||
{ seeds: [1, 8], bracket_position: "Quarter", round: 1 },
|
||||
{ seeds: [4, 5], bracket_position: "Quarter", round: 1 },
|
||||
{ seeds: [3, 6], bracket_position: "Quarter", round: 1 },
|
||||
{ seeds: [2, 7], bracket_position: "Quarter", round: 1 }
|
||||
],
|
||||
championship_rounds: [
|
||||
# Semis => round=2, Final => round=4
|
||||
{ bracket_position: "Semis", number_of_matches: 2, round: 2 },
|
||||
{ bracket_position: "1/2", number_of_matches: 1, round: 4 }
|
||||
],
|
||||
consolation_rounds: [
|
||||
# Conso Quarter => round=2, Conso Semis => round=3, 3/4 => round=4
|
||||
{ bracket_position: "Conso Quarter", number_of_matches: 2, round: 2 },
|
||||
{ bracket_position: "Conso Semis", number_of_matches: 2, round: 3 },
|
||||
{ bracket_position: "3/4", number_of_matches: 1, round: 4 }
|
||||
]
|
||||
}
|
||||
|
||||
when 16
|
||||
{
|
||||
round_one_matchups: [
|
||||
{ seeds: [1,16], bracket_position: "Bracket Round of 16", round: 1 },
|
||||
{ seeds: [8,9], bracket_position: "Bracket Round of 16", round: 1 },
|
||||
{ seeds: [5,12], bracket_position: "Bracket Round of 16", round: 1 },
|
||||
{ seeds: [4,13], bracket_position: "Bracket Round of 16", round: 1 },
|
||||
{ seeds: [3,14], bracket_position: "Bracket Round of 16", round: 1 },
|
||||
{ seeds: [6,11], bracket_position: "Bracket Round of 16", round: 1 },
|
||||
{ seeds: [7,10], bracket_position: "Bracket Round of 16", round: 1 },
|
||||
{ seeds: [2,15], bracket_position: "Bracket Round of 16", round: 1 }
|
||||
],
|
||||
championship_rounds: [
|
||||
# Quarter => round=2, Semis => round=4, Final => round=6
|
||||
{ bracket_position: "Quarter", number_of_matches: 4, round: 2 },
|
||||
{ bracket_position: "Semis", number_of_matches: 2, round: 4 },
|
||||
{ bracket_position: "1/2", number_of_matches: 1, round: 6 }
|
||||
],
|
||||
consolation_rounds: [
|
||||
# Just carry over your standard numbering
|
||||
{ bracket_position: "Conso Round of 8.1", number_of_matches: 4, round: 2 },
|
||||
{ bracket_position: "Conso Round of 8.2", number_of_matches: 4, round: 3 },
|
||||
{ bracket_position: "Conso Quarter", number_of_matches: 2, round: 4 },
|
||||
{ bracket_position: "Conso Semis", number_of_matches: 2, round: 5 },
|
||||
{ bracket_position: "3/4", number_of_matches: 1, round: 6 }
|
||||
]
|
||||
}
|
||||
|
||||
when 32
|
||||
{
|
||||
round_one_matchups: [
|
||||
{ seeds: [1,32], bracket_position: "Bracket Round of 32", round: 1 },
|
||||
{ seeds: [16,17], bracket_position: "Bracket Round of 32", round: 1 },
|
||||
{ seeds: [9,24], bracket_position: "Bracket Round of 32", round: 1 },
|
||||
{ seeds: [8,25], bracket_position: "Bracket Round of 32", round: 1 },
|
||||
{ seeds: [5,28], bracket_position: "Bracket Round of 32", round: 1 },
|
||||
{ seeds: [12,21], bracket_position: "Bracket Round of 32", round: 1 },
|
||||
{ seeds: [13,20], bracket_position: "Bracket Round of 32", round: 1 },
|
||||
{ seeds: [4,29], bracket_position: "Bracket Round of 32", round: 1 },
|
||||
{ seeds: [3,30], bracket_position: "Bracket Round of 32", round: 1 },
|
||||
{ seeds: [14,19], bracket_position: "Bracket Round of 32", round: 1 },
|
||||
{ seeds: [11,22], bracket_position: "Bracket Round of 32", round: 1 },
|
||||
{ seeds: [6,27], bracket_position: "Bracket Round of 32", round: 1 },
|
||||
{ seeds: [7,26], bracket_position: "Bracket Round of 32", round: 1 },
|
||||
{ seeds: [10,23], bracket_position: "Bracket Round of 32", round: 1 },
|
||||
{ seeds: [15,18], bracket_position: "Bracket Round of 32", round: 1 },
|
||||
{ seeds: [2,31], bracket_position: "Bracket Round of 32", round: 1 }
|
||||
],
|
||||
championship_rounds: [
|
||||
{ bracket_position: "Bracket Round of 16", number_of_matches: 8, round: 2 },
|
||||
{ bracket_position: "Quarter", number_of_matches: 4, round: 4 },
|
||||
{ bracket_position: "Semis", number_of_matches: 2, round: 6 },
|
||||
{ bracket_position: "1/2", number_of_matches: 1, round: 8 }
|
||||
],
|
||||
consolation_rounds: [
|
||||
{ bracket_position: "Conso Round of 16.1", number_of_matches: 8, round: 2 },
|
||||
{ bracket_position: "Conso Round of 16.2", number_of_matches: 8, round: 3 },
|
||||
{ bracket_position: "Conso Round of 8.1", number_of_matches: 4, round: 4 },
|
||||
{ bracket_position: "Conso Round of 8.2", number_of_matches: 4, round: 5 },
|
||||
{ bracket_position: "Conso Quarter", number_of_matches: 2, round: 6 },
|
||||
{ bracket_position: "Conso Semis", number_of_matches: 2, round: 7 },
|
||||
{ bracket_position: "3/4", number_of_matches: 1, round: 8 }
|
||||
]
|
||||
}
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
###########################################################################
|
||||
# PHASE 2: Overwrite rounds in all smaller brackets to match the largest one.
|
||||
###########################################################################
|
||||
def align_all_rounds_to_largest_bracket
|
||||
#
|
||||
# 1) Find the bracket size that is largest
|
||||
#
|
||||
largest_weight = @tournament.weights.max_by { |w| w.calculate_bracket_size }
|
||||
return unless largest_weight
|
||||
|
||||
#
|
||||
# 2) Gather all matches for that bracket. Build a map from bracket_position => round
|
||||
#
|
||||
# We assume "largest bracket" is the single weight with the largest bracket_size.
|
||||
#
|
||||
largest_bracket_size = largest_weight.calculate_bracket_size
|
||||
largest_matches = largest_weight.tournament.matches.where(weight_id: largest_weight.id)
|
||||
|
||||
position_to_round = {}
|
||||
largest_matches.each do |m|
|
||||
# In case multiple matches have the same bracket_position but different rounds
|
||||
# (like "3/4" might appear more than once), you can pick the first or max.
|
||||
position_to_round[m.bracket_position] ||= m.round
|
||||
end
|
||||
|
||||
#
|
||||
# 3) For every other match in the entire tournament (including possibly the largest bracket, if you want),
|
||||
# overwrite the round to match this map.
|
||||
#
|
||||
@tournament.matches.find_each do |match|
|
||||
# If there's a known round for this bracket_position, use it
|
||||
if position_to_round.key?(match.bracket_position)
|
||||
match.update(round: position_to_round[match.bracket_position])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
###########################################################################
|
||||
# Helper methods
|
||||
###########################################################################
|
||||
def wrestler_with_seed(seed, weight)
|
||||
Wrestler.where("weight_id = ? AND bracket_line = ?", weight.id, seed).first&.id
|
||||
end
|
||||
|
||||
def create_matchup_from_seed(w1_seed, w2_seed, bracket_position, bracket_position_number, round, weight)
|
||||
create_matchup(
|
||||
wrestler_with_seed(w1_seed, weight),
|
||||
wrestler_with_seed(w2_seed, weight),
|
||||
bracket_position,
|
||||
bracket_position_number,
|
||||
round,
|
||||
weight
|
||||
)
|
||||
end
|
||||
|
||||
def create_matchup(w1, w2, bracket_position, bracket_position_number, round, weight)
|
||||
weight.tournament.matches.create!(
|
||||
w1: w1,
|
||||
w2: w2,
|
||||
weight_id: weight.id,
|
||||
round: round,
|
||||
bracket_position: bracket_position,
|
||||
bracket_position_number: bracket_position_number
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
class EightManDoubleEliminationGenerateLoserNames
|
||||
def initialize( weight )
|
||||
@weight = weight
|
||||
end
|
||||
|
||||
def assign_loser_names_for_weight
|
||||
matches_by_weight = nil
|
||||
matches_by_weight = @weight.matches
|
||||
conso_round_2(matches_by_weight)
|
||||
conso_round_4(matches_by_weight)
|
||||
fifth_sixth(matches_by_weight)
|
||||
save_matches(matches_by_weight)
|
||||
matches_by_weight = @weight.matches.reload
|
||||
advance_bye_matches_championship(matches_by_weight)
|
||||
save_matches(matches_by_weight)
|
||||
end
|
||||
|
||||
def conso_round_2(matches)
|
||||
matches.select{|m| m.bracket_position == "Conso Quarter"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
if match.bracket_position_number == 1
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 1 and m.round == 1 and m.bracket_position == "Quarter"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position_number == 2 and m.round == 1 and m.bracket_position == "Quarter"}.first.bout_number}"
|
||||
elsif match.bracket_position_number == 2
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 3 and m.round == 1 and m.bracket_position == "Quarter"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position_number == 4 and m.round == 1 and m.bracket_position == "Quarter"}.first.bout_number}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def conso_round_4(matches)
|
||||
matches.select{|m| m.bracket_position == "Conso Semis"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
if match.bracket_position_number == 1
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 2 and m.bracket_position == "Semis"}.first.bout_number}"
|
||||
elsif match.bracket_position_number == 2
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 1 and m.bracket_position == "Semis"}.first.bout_number}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def fifth_sixth(matches)
|
||||
matches.select{|m| m.bracket_position == "5/6"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position == "Conso Semis"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position == "Conso Semis"}.second.bout_number}"
|
||||
end
|
||||
end
|
||||
|
||||
def advance_bye_matches_championship(matches)
|
||||
matches.select{|m| m.round == 1 and m.bracket_position == "Quarter"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
if match.w1 == nil or match.w2 == nil
|
||||
match.finished = 1
|
||||
match.win_type = "BYE"
|
||||
if match.w1 != nil
|
||||
match.winner_id = match.w1
|
||||
match.loser2_name = "BYE"
|
||||
match.save
|
||||
match.advance_wrestlers
|
||||
elsif match.w2 != nil
|
||||
match.winner_id = match.w2
|
||||
match.loser1_name = "BYE"
|
||||
match.save
|
||||
match.advance_wrestlers
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def save_matches(matches)
|
||||
matches.each do |m|
|
||||
m.save!
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,63 +0,0 @@
|
||||
class EightManDoubleEliminationMatchGeneration
|
||||
def initialize( weight )
|
||||
@weight = weight
|
||||
end
|
||||
|
||||
def generate_matches_for_weight
|
||||
round_one(@weight)
|
||||
round_two(@weight)
|
||||
round_three(@weight)
|
||||
round_four(@weight)
|
||||
end
|
||||
|
||||
def round_one(weight)
|
||||
create_matchup_from_seed(1,8,"Quarter",1,1,weight)
|
||||
create_matchup_from_seed(4,5,"Quarter",2,1,weight)
|
||||
create_matchup_from_seed(3,6,"Quarter",3,1,weight)
|
||||
create_matchup_from_seed(2,7,"Quarter",4,1,weight)
|
||||
end
|
||||
|
||||
def round_two(weight)
|
||||
create_matchup(nil,nil,"Semis",1,2,weight)
|
||||
create_matchup(nil,nil,"Semis",2,2,weight)
|
||||
create_matchup(nil,nil,"Conso Quarter",1,2,weight)
|
||||
create_matchup(nil,nil,"Conso Quarter",2,2,weight)
|
||||
end
|
||||
|
||||
def round_three(weight)
|
||||
create_matchup(nil,nil,"Conso Semis",1,3,weight)
|
||||
create_matchup(nil,nil,"Conso Semis",2,3,weight)
|
||||
end
|
||||
|
||||
def round_four(weight)
|
||||
create_matchup(nil,nil,"1/2",1,4,weight)
|
||||
create_matchup(nil,nil,"3/4",1,4,weight)
|
||||
create_matchup(nil,nil,"5/6",1,4,weight)
|
||||
end
|
||||
|
||||
def wrestler_with_seed(seed,weight)
|
||||
wrestler = Wrestler.where("weight_id = ? and bracket_line = ?", weight.id, seed).first
|
||||
if wrestler
|
||||
return wrestler.id
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
def create_matchup_from_seed(w1_seed, w2_seed, bracket_position, bracket_position_number,round,weight)
|
||||
# if wrestler_with_seed(w1_seed,weight) and wrestler_with_seed(w2_seed,weight)
|
||||
create_matchup(wrestler_with_seed(w1_seed,weight),wrestler_with_seed(w2_seed,weight), bracket_position, bracket_position_number,round,weight)
|
||||
# end
|
||||
end
|
||||
|
||||
def create_matchup(w1, w2, bracket_position, bracket_position_number,round,weight)
|
||||
@weight.tournament.matches.create(
|
||||
w1: w1,
|
||||
w2: w2,
|
||||
weight_id: weight.id,
|
||||
round: round,
|
||||
bracket_position: bracket_position,
|
||||
bracket_position_number: bracket_position_number
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -3,55 +3,33 @@ class GenerateTournamentMatches
|
||||
@tournament = tournament
|
||||
end
|
||||
|
||||
def generateWeight(weight)
|
||||
if Rails.env.production?
|
||||
self.delay(:job_owner_id => @tournament.id, :job_owner_type => "Generate matches for weights class #{weight.max}").generate_weight_raw(weight)
|
||||
else
|
||||
self.generate_weight_raw(weight)
|
||||
end
|
||||
end
|
||||
|
||||
def generate_weight_raw(weight)
|
||||
WipeTournamentMatches.new(@tournament).wipeWeightMatches(weight)
|
||||
@tournament.curently_generating_matches = 1
|
||||
@tournament.save
|
||||
unAssignBouts
|
||||
unAssignMats
|
||||
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
|
||||
|
||||
def generate
|
||||
if Rails.env.production?
|
||||
self.delay(:job_owner_id => @tournament.id, :job_owner_type => "Generate matches for all weights").generate_raw
|
||||
else
|
||||
self.generate_raw
|
||||
end
|
||||
# Use perform_later which will execute based on centralized adapter config
|
||||
GenerateTournamentMatchesJob.perform_later(@tournament)
|
||||
end
|
||||
|
||||
def generate_raw
|
||||
standardStartingActions
|
||||
PoolToBracketMatchGeneration.new(@tournament).generatePoolToBracketMatches if @tournament.tournament_type == "Pool to bracket"
|
||||
ModifiedSixteenManMatchGeneration.new(@tournament).generate_matches if @tournament.tournament_type == "Modified 16 Man Double Elimination"
|
||||
DoubleEliminationMatchGeneration.new(@tournament).generate_matches if @tournament.tournament_type == "Double Elimination 1-6"
|
||||
ModifiedSixteenManMatchGeneration.new(@tournament).generate_matches if @tournament.tournament_type.include? "Modified 16 Man Double Elimination"
|
||||
DoubleEliminationMatchGeneration.new(@tournament).generate_matches if @tournament.tournament_type.include? "Regular Double Elimination"
|
||||
postMatchCreationActions
|
||||
PoolToBracketMatchGeneration.new(@tournament).assignLoserNames if @tournament.tournament_type == "Pool to bracket"
|
||||
ModifiedSixteenManGenerateLoserNames.new(@tournament).assign_loser_names if @tournament.tournament_type == "Modified 16 Man Double Elimination"
|
||||
DoubleEliminationGenerateLoserNames.new(@tournament).assign_loser_names if @tournament.tournament_type == "Double Elimination 1-6"
|
||||
ModifiedSixteenManGenerateLoserNames.new(@tournament).assign_loser_names if @tournament.tournament_type.include? "Modified 16 Man Double Elimination"
|
||||
DoubleEliminationGenerateLoserNames.new(@tournament).assign_loser_names if @tournament.tournament_type.include? "Regular Double Elimination"
|
||||
end
|
||||
|
||||
def standardStartingActions
|
||||
@tournament.curently_generating_matches = 1
|
||||
@tournament.save
|
||||
WipeTournamentMatches.new(@tournament).setUpMatchGeneration
|
||||
TournamentSeeding.new(@tournament).setSeeds
|
||||
TournamentSeeding.new(@tournament).set_seeds
|
||||
end
|
||||
|
||||
def postMatchCreationActions
|
||||
moveFinalsMatchesToLastRound
|
||||
moveFinalsMatchesToLastRound if ! @tournament.tournament_type.include? "Regular Double Elimination"
|
||||
assignBouts
|
||||
assignFirstMatchesToMats
|
||||
@tournament.reset_and_fill_bout_board
|
||||
@tournament.curently_generating_matches = nil
|
||||
@tournament.save!
|
||||
end
|
||||
@@ -75,17 +53,6 @@ class GenerateTournamentMatches
|
||||
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.assign_next_match
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def unAssignMats
|
||||
matches = @tournament.matches.reload
|
||||
matches.each do |m|
|
||||
|
||||
@@ -10,6 +10,7 @@ class ModifiedSixteenManGenerateLoserNames
|
||||
conso_round_2(matches_by_weight)
|
||||
conso_round_3(matches_by_weight)
|
||||
third_fourth(matches_by_weight)
|
||||
seventh_eighth(matches_by_weight)
|
||||
save_matches(matches_by_weight)
|
||||
matches_by_weight = @tournament.matches.where(weight_id: w.id).reload
|
||||
advance_bye_matches_championship(matches_by_weight)
|
||||
@@ -18,25 +19,25 @@ class ModifiedSixteenManGenerateLoserNames
|
||||
end
|
||||
|
||||
def conso_round_2(matches)
|
||||
matches.select{|m| m.round == 2 and m.bracket_position == "Conso"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
matches.select{|m| m.bracket_position == "Conso Round of 8"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
if match.bracket_position_number == 1
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 1 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position_number == 2 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 1 and m.bracket_position == "Bracket Round of 16"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position_number == 2 and m.bracket_position == "Bracket Round of 16"}.first.bout_number}"
|
||||
elsif match.bracket_position_number == 2
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 3 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position_number == 4 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 3 and m.bracket_position == "Bracket Round of 16"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position_number == 4 and m.bracket_position == "Bracket Round of 16"}.first.bout_number}"
|
||||
elsif match.bracket_position_number == 3
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 5 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position_number == 6 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 5 and m.bracket_position == "Bracket Round of 16"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position_number == 6 and m.bracket_position == "Bracket Round of 16"}.first.bout_number}"
|
||||
elsif match.bracket_position_number == 4
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 7 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position_number == 8 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 7 and m.bracket_position == "Bracket Round of 16"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position_number == 8 and m.bracket_position == "Bracket Round of 16"}.first.bout_number}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def conso_round_3(matches)
|
||||
matches.select{|m| m.round == 3 and m.bracket_position == "Conso Quarter"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
matches.select{|m| m.bracket_position == "Conso Quarter"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
if match.bracket_position_number == 1
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 4 and m.bracket_position == "Quarter"}.first.bout_number}"
|
||||
elsif match.bracket_position_number == 2
|
||||
@@ -55,21 +56,29 @@ class ModifiedSixteenManGenerateLoserNames
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position == "Semis"}.second.bout_number}"
|
||||
end
|
||||
end
|
||||
|
||||
def seventh_eighth(matches)
|
||||
matches.select{|m| m.bracket_position == "7/8"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position == "Conso Semis"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position == "Conso Semis"}.second.bout_number}"
|
||||
end
|
||||
end
|
||||
|
||||
def advance_bye_matches_championship(matches)
|
||||
matches.select{|m| m.round == 1 and m.bracket_position == "Bracket"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
matches.select{|m| m.bracket_position == "Bracket Round of 16"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
if match.w1 == nil or match.w2 == nil
|
||||
puts match.bout_number
|
||||
match.finished = 1
|
||||
match.win_type = "BYE"
|
||||
if match.w1 != nil
|
||||
match.winner_id = match.w1
|
||||
match.loser2_name = "BYE"
|
||||
match.score = ""
|
||||
match.save
|
||||
match.advance_wrestlers
|
||||
elsif match.w2 != nil
|
||||
match.winner_id = match.w2
|
||||
match.loser1_name = "BYE"
|
||||
match.score = ""
|
||||
match.save
|
||||
match.advance_wrestlers
|
||||
end
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
class ModifiedSixteenManMatchGeneration
|
||||
def initialize( tournament )
|
||||
@tournament = tournament
|
||||
@number_of_placers = @tournament.number_of_placers
|
||||
end
|
||||
|
||||
def generate_matches
|
||||
@@ -18,14 +19,14 @@ class ModifiedSixteenManMatchGeneration
|
||||
end
|
||||
|
||||
def round_one(weight)
|
||||
create_matchup_from_seed(1,16, "Bracket", 1, 1,weight)
|
||||
create_matchup_from_seed(8,9, "Bracket", 2, 1,weight)
|
||||
create_matchup_from_seed(5,12, "Bracket", 3, 1,weight)
|
||||
create_matchup_from_seed(4,14, "Bracket", 4, 1,weight)
|
||||
create_matchup_from_seed(3,13, "Bracket", 5, 1,weight)
|
||||
create_matchup_from_seed(6,11, "Bracket", 6, 1,weight)
|
||||
create_matchup_from_seed(7,10, "Bracket", 7, 1,weight)
|
||||
create_matchup_from_seed(2,15, "Bracket", 8, 1,weight)
|
||||
create_matchup_from_seed(1,16, "Bracket Round of 16", 1, 1,weight)
|
||||
create_matchup_from_seed(8,9, "Bracket Round of 16", 2, 1,weight)
|
||||
create_matchup_from_seed(5,12, "Bracket Round of 16", 3, 1,weight)
|
||||
create_matchup_from_seed(4,14, "Bracket Round of 16", 4, 1,weight)
|
||||
create_matchup_from_seed(3,13, "Bracket Round of 16", 5, 1,weight)
|
||||
create_matchup_from_seed(6,11, "Bracket Round of 16", 6, 1,weight)
|
||||
create_matchup_from_seed(7,10, "Bracket Round of 16", 7, 1,weight)
|
||||
create_matchup_from_seed(2,15, "Bracket Round of 16", 8, 1,weight)
|
||||
end
|
||||
|
||||
def round_two(weight)
|
||||
@@ -33,10 +34,10 @@ class ModifiedSixteenManMatchGeneration
|
||||
create_matchup(nil,nil,"Quarter",2,2,weight)
|
||||
create_matchup(nil,nil,"Quarter",3,2,weight)
|
||||
create_matchup(nil,nil,"Quarter",4,2,weight)
|
||||
create_matchup(nil,nil,"Conso",1,2,weight)
|
||||
create_matchup(nil,nil,"Conso",2,2,weight)
|
||||
create_matchup(nil,nil,"Conso",3,2,weight)
|
||||
create_matchup(nil,nil,"Conso",4,2,weight)
|
||||
create_matchup(nil,nil,"Conso Round of 8",1,2,weight)
|
||||
create_matchup(nil,nil,"Conso Round of 8",2,2,weight)
|
||||
create_matchup(nil,nil,"Conso Round of 8",3,2,weight)
|
||||
create_matchup(nil,nil,"Conso Round of 8",4,2,weight)
|
||||
end
|
||||
|
||||
def round_three(weight)
|
||||
@@ -57,6 +58,9 @@ class ModifiedSixteenManMatchGeneration
|
||||
create_matchup(nil,nil,"1/2",1,5,weight)
|
||||
create_matchup(nil,nil,"3/4",1,5,weight)
|
||||
create_matchup(nil,nil,"5/6",1,5,weight)
|
||||
if @number_of_placers >= 8
|
||||
create_matchup(nil,nil,"7/8",1,5,weight)
|
||||
end
|
||||
end
|
||||
|
||||
def wrestler_with_seed(seed,weight)
|
||||
|
||||
@@ -2,14 +2,6 @@ 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|
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
class SixteenManDoubleEliminationGenerateLoserNames
|
||||
def initialize( weight )
|
||||
@weight = weight
|
||||
end
|
||||
|
||||
def assign_loser_names_for_weight
|
||||
matches_by_weight = nil
|
||||
matches_by_weight = @weight.matches
|
||||
conso_round_2(matches_by_weight)
|
||||
conso_round_3(matches_by_weight)
|
||||
conso_round_5(matches_by_weight)
|
||||
fifth_sixth(matches_by_weight)
|
||||
save_matches(matches_by_weight)
|
||||
matches_by_weight = @weight.matches.reload
|
||||
advance_bye_matches_championship(matches_by_weight)
|
||||
save_matches(matches_by_weight)
|
||||
end
|
||||
|
||||
def conso_round_2(matches)
|
||||
matches.select{|m| m.round == 2 and m.bracket_position == "Conso"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
if match.bracket_position_number == 1
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 1 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position_number == 2 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
elsif match.bracket_position_number == 2
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 3 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position_number == 4 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
elsif match.bracket_position_number == 3
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 5 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position_number == 6 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
elsif match.bracket_position_number == 4
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 7 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position_number == 8 and m.round == 1 and m.bracket_position == "Bracket"}.first.bout_number}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def conso_round_3(matches)
|
||||
matches.select{|m| m.round == 3 and m.bracket_position == "Conso"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
if match.bracket_position_number == 1
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 4 and m.bracket_position == "Quarter"}.first.bout_number}"
|
||||
elsif match.bracket_position_number == 2
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 3 and m.bracket_position == "Quarter"}.first.bout_number}"
|
||||
elsif match.bracket_position_number == 3
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 2 and m.bracket_position == "Quarter"}.first.bout_number}"
|
||||
elsif match.bracket_position_number == 4
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 1 and m.bracket_position == "Quarter"}.first.bout_number}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def conso_round_5(matches)
|
||||
matches.select{|m| m.round == 5 and m.bracket_position == "Conso Semis"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
if match.bracket_position_number == 1
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 1 and m.bracket_position == "Semis"}.first.bout_number}"
|
||||
elsif match.bracket_position_number == 2
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 2 and m.bracket_position == "Semis"}.first.bout_number}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def fifth_sixth(matches)
|
||||
matches.select{|m| m.bracket_position == "5/6"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position == "Conso Semis"}.first.bout_number}"
|
||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position == "Conso Semis"}.second.bout_number}"
|
||||
end
|
||||
end
|
||||
|
||||
def advance_bye_matches_championship(matches)
|
||||
matches.select{|m| m.round == 1 and m.bracket_position == "Bracket"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
||||
if match.w1 == nil or match.w2 == nil
|
||||
match.finished = 1
|
||||
match.win_type = "BYE"
|
||||
if match.w1 != nil
|
||||
match.winner_id = match.w1
|
||||
match.loser2_name = "BYE"
|
||||
match.save
|
||||
match.advance_wrestlers
|
||||
elsif match.w2 != nil
|
||||
match.winner_id = match.w2
|
||||
match.loser1_name = "BYE"
|
||||
match.save
|
||||
match.advance_wrestlers
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def save_matches(matches)
|
||||
matches.each do |m|
|
||||
m.save!
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,87 +0,0 @@
|
||||
class SixteenManDoubleEliminationMatchGeneration
|
||||
def initialize( weight )
|
||||
@weight = weight
|
||||
end
|
||||
|
||||
def generate_matches_for_weight
|
||||
round_one(@weight)
|
||||
round_two(@weight)
|
||||
round_three(@weight)
|
||||
round_four(@weight)
|
||||
round_five(@weight)
|
||||
round_six(@weight)
|
||||
end
|
||||
|
||||
def round_one(weight)
|
||||
create_matchup_from_seed(1,16, "Bracket", 1, 1,weight)
|
||||
create_matchup_from_seed(8,9, "Bracket", 2, 1,weight)
|
||||
create_matchup_from_seed(5,12, "Bracket", 3, 1,weight)
|
||||
create_matchup_from_seed(4,14, "Bracket", 4, 1,weight)
|
||||
create_matchup_from_seed(3,13, "Bracket", 5, 1,weight)
|
||||
create_matchup_from_seed(6,11, "Bracket", 6, 1,weight)
|
||||
create_matchup_from_seed(7,10, "Bracket", 7, 1,weight)
|
||||
create_matchup_from_seed(2,15, "Bracket", 8, 1,weight)
|
||||
end
|
||||
|
||||
def round_two(weight)
|
||||
create_matchup(nil,nil,"Quarter",1,2,weight)
|
||||
create_matchup(nil,nil,"Quarter",2,2,weight)
|
||||
create_matchup(nil,nil,"Quarter",3,2,weight)
|
||||
create_matchup(nil,nil,"Quarter",4,2,weight)
|
||||
create_matchup(nil,nil,"Conso",1,2,weight)
|
||||
create_matchup(nil,nil,"Conso",2,2,weight)
|
||||
create_matchup(nil,nil,"Conso",3,2,weight)
|
||||
create_matchup(nil,nil,"Conso",4,2,weight)
|
||||
end
|
||||
|
||||
def round_three(weight)
|
||||
create_matchup(nil,nil,"Conso",1,3,weight)
|
||||
create_matchup(nil,nil,"Conso",2,3,weight)
|
||||
create_matchup(nil,nil,"Conso",3,3,weight)
|
||||
create_matchup(nil,nil,"Conso",4,3,weight)
|
||||
end
|
||||
|
||||
def round_four(weight)
|
||||
create_matchup(nil,nil,"Semis",1,4,weight)
|
||||
create_matchup(nil,nil,"Semis",2,4,weight)
|
||||
create_matchup(nil,nil,"Conso Quarter",1,4,weight)
|
||||
create_matchup(nil,nil,"Conso Quarter",2,4,weight)
|
||||
end
|
||||
|
||||
def round_five(weight)
|
||||
create_matchup(nil,nil,"Conso Semis",1,5,weight)
|
||||
create_matchup(nil,nil,"Conso Semis",2,5,weight)
|
||||
end
|
||||
|
||||
def round_six(weight)
|
||||
create_matchup(nil,nil,"1/2",1,6,weight)
|
||||
create_matchup(nil,nil,"3/4",1,6,weight)
|
||||
create_matchup(nil,nil,"5/6",1,6,weight)
|
||||
end
|
||||
|
||||
def wrestler_with_seed(seed,weight)
|
||||
wrestler = Wrestler.where("weight_id = ? and bracket_line = ?", weight.id, seed).first
|
||||
if wrestler
|
||||
return wrestler.id
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
def create_matchup_from_seed(w1_seed, w2_seed, bracket_position, bracket_position_number,round,weight)
|
||||
# if wrestler_with_seed(w1_seed,weight) and wrestler_with_seed(w2_seed,weight)
|
||||
create_matchup(wrestler_with_seed(w1_seed,weight),wrestler_with_seed(w2_seed,weight), bracket_position, bracket_position_number,round,weight)
|
||||
# end
|
||||
end
|
||||
|
||||
def create_matchup(w1, w2, bracket_position, bracket_position_number,round,weight)
|
||||
@weight.tournament.matches.create(
|
||||
w1: w1,
|
||||
w2: w2,
|
||||
weight_id: weight.id,
|
||||
round: round,
|
||||
bracket_position: bracket_position,
|
||||
bracket_position_number: bracket_position_number
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,69 @@
|
||||
class TournamentBackupService
|
||||
def initialize(tournament, reason)
|
||||
@tournament = tournament
|
||||
@reason = reason
|
||||
end
|
||||
|
||||
def create_backup
|
||||
# Use perform_later which will execute based on centralized adapter config
|
||||
TournamentBackupJob.perform_later(@tournament, @reason)
|
||||
end
|
||||
|
||||
def create_backup_raw
|
||||
# Generate the JSON directly in Ruby and encode it
|
||||
backup_data = Base64.encode64(generate_json.to_json)
|
||||
|
||||
begin
|
||||
# Save the backup with encoded data
|
||||
TournamentBackup.create!(tournament: @tournament, backup_data: backup_data, backup_reason: @reason)
|
||||
Rails.logger.info("Backup created successfully for tournament ##{@tournament.id}")
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
Rails.logger.error("Failed to save backup: #{e.message}")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_json
|
||||
@tournament.reload
|
||||
@tournament.schools.reload
|
||||
@tournament.weights.reload
|
||||
@tournament.mats.reload
|
||||
@tournament.mat_assignment_rules.reload
|
||||
@tournament.wrestlers.reload
|
||||
@tournament.matches.reload
|
||||
data = {
|
||||
tournament: {
|
||||
attributes: @tournament.attributes,
|
||||
schools: @tournament.schools.map(&:attributes),
|
||||
weights: @tournament.weights.map(&:attributes),
|
||||
mats: @tournament.mats.map(&:attributes),
|
||||
mat_assignment_rules: @tournament.mat_assignment_rules.map do |rule|
|
||||
rule.attributes.merge(
|
||||
mat: Mat.find_by(id: rule.mat_id)&.attributes.slice("name"),
|
||||
weight_classes: rule.weight_classes.map do |weight_id|
|
||||
Weight.find_by(id: weight_id)&.max
|
||||
end
|
||||
)
|
||||
end,
|
||||
wrestlers: @tournament.wrestlers.map do |wrestler|
|
||||
wrestler.attributes.merge(
|
||||
school: wrestler.school&.attributes,
|
||||
weight: wrestler.weight&.attributes
|
||||
)
|
||||
end,
|
||||
matches: @tournament.matches.sort_by(&:bout_number).map do |match|
|
||||
match.attributes.merge(
|
||||
w1_name: match.wrestler1&.name,
|
||||
w2_name: match.wrestler2&.name,
|
||||
winner_name: match.winner&.name,
|
||||
weight: match.weight&.attributes,
|
||||
mat: match.mat&.attributes
|
||||
)
|
||||
end
|
||||
}
|
||||
}
|
||||
# puts "Generated JSON for backup: #{data[:tournament][:mats]}"
|
||||
data
|
||||
end
|
||||
end
|
||||
@@ -3,42 +3,82 @@ class TournamentSeeding
|
||||
@tournament = tournament
|
||||
end
|
||||
|
||||
def setSeeds
|
||||
@tournament.weights.each do |w|
|
||||
resetAllSeeds(w)
|
||||
setOriginalSeeds(w)
|
||||
randomSeeding(w)
|
||||
def set_seeds
|
||||
@tournament.weights.each do |weight|
|
||||
wrestlers = weight.wrestlers
|
||||
bracket_size = weight.calculate_bracket_size
|
||||
|
||||
wrestlers = reset_bracket_line_for_lines_higher_than_bracket_size(wrestlers, bracket_size)
|
||||
wrestlers = set_original_seed_to_bracket_line(wrestlers)
|
||||
wrestlers = random_seeding(wrestlers, bracket_size)
|
||||
wrestlers.each(&:save)
|
||||
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.bracket_line
|
||||
seed = highestSeed + 1
|
||||
def random_seeding(wrestlers, bracket_size)
|
||||
half_of_bracket = bracket_size / 2
|
||||
available_bracket_lines = (1..bracket_size).to_a
|
||||
first_half_available_bracket_lines = (1..half_of_bracket).to_a
|
||||
|
||||
# remove bracket lines that are taken from available_bracket_lines
|
||||
wrestlers_with_bracket_lines = wrestlers.select{|w| w.bracket_line != nil }
|
||||
wrestlers_with_bracket_lines.each do |wrestler|
|
||||
available_bracket_lines.delete(wrestler.bracket_line)
|
||||
first_half_available_bracket_lines.delete(wrestler.bracket_line)
|
||||
end
|
||||
|
||||
wrestlers_without_bracket_lines = wrestlers.select{|w| w.bracket_line == nil }
|
||||
if @tournament.tournament_type == "Pool to bracket"
|
||||
wrestlers_without_bracket_lines.shuffle.each do |wrestler|
|
||||
# pool brackets just grab the first available seed
|
||||
first_available_bracket_line = available_bracket_lines.first
|
||||
wrestler.bracket_line = first_available_bracket_line
|
||||
available_bracket_lines.delete(first_available_bracket_line)
|
||||
end
|
||||
else
|
||||
seed = 1
|
||||
end
|
||||
wrestlersWithoutSeed = weight.wrestlers.select{|w| w.original_seed == nil }
|
||||
wrestlersWithoutSeed.shuffle.each do |w|
|
||||
w.bracket_line = seed
|
||||
w.save
|
||||
seed += 1
|
||||
# Iterrate over the list randomly
|
||||
wrestlers_without_bracket_lines.shuffle.each do |wrestler|
|
||||
if first_half_available_bracket_lines.size > 0
|
||||
random_available_bracket_line = first_half_available_bracket_lines.sample
|
||||
wrestler.bracket_line = random_available_bracket_line
|
||||
available_bracket_lines.delete(random_available_bracket_line)
|
||||
first_half_available_bracket_lines.delete(random_available_bracket_line)
|
||||
else
|
||||
random_available_bracket_line = available_bracket_lines.sample
|
||||
wrestler.bracket_line = random_available_bracket_line
|
||||
available_bracket_lines.delete(random_available_bracket_line)
|
||||
end
|
||||
end
|
||||
end
|
||||
return wrestlers
|
||||
end
|
||||
|
||||
def setOriginalSeeds(weight)
|
||||
wrestlerWithSeeds = weight.wrestlers.select{|w| w.original_seed != nil }
|
||||
wrestlerWithSeeds.each do |w|
|
||||
w.bracket_line = w.original_seed
|
||||
w.save
|
||||
def set_original_seed_to_bracket_line(wrestlers)
|
||||
wrestlers_with_seeds = wrestlers.select{|w| w.original_seed != nil }
|
||||
wrestlers_with_seeds.each do |wrestler|
|
||||
wrestlers_with_seeded_wrestlers_bracket_line = wrestlers.select{|w| w.bracket_line == wrestler.original_seed && w.id != wrestler.id}
|
||||
wrestlers_with_seeded_wrestlers_bracket_line.each do |wrestler_with_wrong_bracket_line|
|
||||
wrestler_with_wrong_bracket_line.bracket_line = nil
|
||||
end
|
||||
|
||||
wrestler.bracket_line = wrestler.original_seed
|
||||
end
|
||||
return wrestlers
|
||||
end
|
||||
|
||||
def resetAllSeeds(weight)
|
||||
weight.wrestlers.each do |w|
|
||||
def reset_bracket_line_for_lines_higher_than_bracket_size(wrestlers, bracket_size)
|
||||
wrestlers.each do |w|
|
||||
if w.bracket_line && w.bracket_line > bracket_size
|
||||
w.bracket_line = nil
|
||||
end
|
||||
end
|
||||
return wrestlers
|
||||
end
|
||||
|
||||
def reset_all_seeds(wrestlers)
|
||||
wrestlers.each do |w|
|
||||
w.bracket_line = nil
|
||||
w.save
|
||||
end
|
||||
return wrestlers
|
||||
end
|
||||
end
|
||||
@@ -1,179 +1,148 @@
|
||||
class WrestlingdevImporter
|
||||
def initialize( tournament, import_text )
|
||||
@tournament = tournament
|
||||
@import_text = import_text
|
||||
@attribute_separator = ";;"
|
||||
@model_separator = ",,"
|
||||
##### Note, the json contains id's for each row in the tables as well as its associations
|
||||
##### this ignores those ids and uses this tournament id and then looks up associations based on name
|
||||
##### and this tournament id
|
||||
attr_accessor :import_data
|
||||
|
||||
# Support both parameter styles for backward compatibility
|
||||
# Old: initialize(tournament, backup)
|
||||
# New: initialize(tournament) with import_data setter
|
||||
def initialize(tournament, backup = nil)
|
||||
@tournament = tournament
|
||||
|
||||
# Handle the old style where backup was passed directly
|
||||
if backup.present?
|
||||
@import_data = JSON.parse(Base64.decode64(backup.backup_data)) rescue nil
|
||||
end
|
||||
end
|
||||
|
||||
def import
|
||||
if Rails.env.production?
|
||||
self.delay(:job_owner_id => @tournament.id, :job_owner_type => "Importing a backup").import_raw
|
||||
else
|
||||
import_raw
|
||||
end
|
||||
# Use perform_later which will execute based on centralized adapter config
|
||||
WrestlingdevImportJob.perform_later(@tournament, @import_data)
|
||||
end
|
||||
|
||||
def import_raw
|
||||
@tournament.curently_generating_matches = 1
|
||||
@tournament.save
|
||||
destroy_all
|
||||
parse_text
|
||||
parse_data
|
||||
@tournament.curently_generating_matches = nil
|
||||
@tournament.save
|
||||
end
|
||||
|
||||
def destroy_all
|
||||
@tournament.mats.reload.each do | mat |
|
||||
mat.destroy
|
||||
end
|
||||
@tournament.matches.each do | match |
|
||||
match.destroy
|
||||
end
|
||||
@tournament.schools.each do | school |
|
||||
school.wrestlers.each do | wrestler |
|
||||
wrestler.destroy
|
||||
end
|
||||
school.destroy
|
||||
end
|
||||
@tournament.weights.each do | weight |
|
||||
weight.destroy
|
||||
end
|
||||
# These depend directly on @tournament and will cascade deletes
|
||||
# due to `dependent: :destroy` in the Tournament model
|
||||
@tournament.schools.destroy_all # Cascades to Wrestlers, Teampointadjusts, SchoolDelegates
|
||||
@tournament.weights.destroy_all # Cascades to Wrestlers, Matches
|
||||
@tournament.mats.destroy_all # Cascades to Matches, MatAssignmentRules
|
||||
# Explicitly destroy matches again just in case some aren't linked via mats/weights? Unlikely but safe.
|
||||
# Also handles matches linked directly to tournament if that's possible.
|
||||
@tournament.matches.destroy_all
|
||||
@tournament.mat_assignment_rules.destroy_all # Explicitly destroy rules (might be redundant if Mat cascades)
|
||||
@tournament.delegates.destroy_all
|
||||
@tournament.tournament_backups.destroy_all
|
||||
@tournament.tournament_job_statuses.destroy_all
|
||||
# Note: Teampointadjusts are deleted via School/Wrestler cascade
|
||||
end
|
||||
|
||||
def parse_text
|
||||
@import_text.each_line do |line|
|
||||
line_array = line.split(@model_separator,-1)
|
||||
if line_array[0] == "--Tournament--"
|
||||
line_array.shift
|
||||
parse_tournament(line_array)
|
||||
elsif line_array[0] == "--Schools--"
|
||||
line_array.shift
|
||||
parse_schools(line_array)
|
||||
elsif line_array[0] == "--Weights--"
|
||||
line_array.shift
|
||||
parse_weights(line_array)
|
||||
elsif line_array[0] == "--Mats--"
|
||||
line_array.shift
|
||||
parse_mats(line_array)
|
||||
elsif line_array[0] == "--Wrestlers--"
|
||||
line_array.shift
|
||||
parse_wrestlers(line_array)
|
||||
elsif line_array[0] == "--Matches--"
|
||||
line_array.shift
|
||||
parse_matches(line_array)
|
||||
end
|
||||
end
|
||||
def parse_data
|
||||
parse_tournament(@import_data["tournament"]["attributes"])
|
||||
parse_schools(@import_data["tournament"]["schools"])
|
||||
parse_weights(@import_data["tournament"]["weights"])
|
||||
parse_mats(@import_data["tournament"]["mats"])
|
||||
parse_wrestlers(@import_data["tournament"]["wrestlers"])
|
||||
parse_matches(@import_data["tournament"]["matches"])
|
||||
parse_mat_assignment_rules(@import_data["tournament"]["mat_assignment_rules"])
|
||||
end
|
||||
|
||||
def parse_tournament(tournament_attributes)
|
||||
tournament_array = tournament_attributes[0].split(@attribute_separator,-1)
|
||||
@tournament.name = tournament_array[0]
|
||||
@tournament.address = tournament_array[1]
|
||||
@tournament.director = tournament_array[2]
|
||||
@tournament.director_email = tournament_array[3]
|
||||
@tournament.tournament_type = tournament_array[4]
|
||||
@tournament.weigh_in_ref = tournament_array[5]
|
||||
@tournament.user_id = tournament_array[6]
|
||||
#@tournament.curently_generating_matches = tournament_array[7]
|
||||
@tournament.date = tournament_array[8]
|
||||
@tournament.save
|
||||
end
|
||||
|
||||
def parse_wrestlers(wrestlers)
|
||||
wrestlers.each do | wrestler |
|
||||
wrestler_array = wrestler.split(@attribute_separator,-1)
|
||||
new_wrestler = Wrestler.new
|
||||
new_wrestler.name = wrestler_array[0]
|
||||
|
||||
school_id = School.where("name = ? and tournament_id = ?",wrestler_array[1],@tournament.id).first.id
|
||||
weight_id = Weight.where("max = ? and tournament_id = ?",wrestler_array[2],@tournament.id).first.id
|
||||
new_wrestler.school_id = school_id
|
||||
new_wrestler.weight_id = weight_id
|
||||
|
||||
new_wrestler.bracket_line = wrestler_array[3]
|
||||
new_wrestler.original_seed = wrestler_array[4]
|
||||
new_wrestler.season_win = wrestler_array[5]
|
||||
new_wrestler.season_loss = wrestler_array[6]
|
||||
new_wrestler.criteria = wrestler_array[7]
|
||||
new_wrestler.extra = wrestler_array[8]
|
||||
new_wrestler.offical_weight = wrestler_array[9]
|
||||
new_wrestler.pool = wrestler_array[10]
|
||||
new_wrestler.pool_placement = wrestler_array[11]
|
||||
new_wrestler.pool_placement_tiebreaker = wrestler_array[12]
|
||||
new_wrestler.save
|
||||
end
|
||||
end
|
||||
|
||||
def parse_matches(matches)
|
||||
matches.each do | match |
|
||||
@tournament.reload
|
||||
@tournament.mats.reload
|
||||
match_array = match.split(@attribute_separator,-1)
|
||||
new_match = Match.new
|
||||
weight_id = Weight.where("max = ? and tournament_id = ?",match_array[10],@tournament.id).first.id
|
||||
if match_array[0].size > 0
|
||||
w1_id = Wrestler.where("name = ? and weight_id = ?",match_array[0],weight_id).first.id
|
||||
end
|
||||
if match_array[1].size > 0
|
||||
w2_id = Wrestler.where("name = ? and weight_id = ?",match_array[1],weight_id).first.id
|
||||
end
|
||||
if match_array[4].size > 0
|
||||
winner_id = Wrestler.where("name = ? and weight_id = ?",match_array[4],weight_id).first.id
|
||||
end
|
||||
if match_array[15].size > 0
|
||||
# mat_id = Mat.where("name = ? and tournament_id = ?",match_array[15],@tournament.id).first.id
|
||||
end
|
||||
new_match.w1 = w1_id if match_array[0].size > 0
|
||||
new_match.w2 = w2_id if match_array[1].size > 0
|
||||
new_match.winner_id = winner_id if match_array[4].size > 0
|
||||
new_match.w1_stat = match_array[2]
|
||||
new_match.w2_stat = match_array[3]
|
||||
new_match.win_type = match_array[5]
|
||||
new_match.score = match_array[6]
|
||||
new_match.tournament_id = @tournament.id
|
||||
new_match.round = match_array[7]
|
||||
new_match. finished = match_array[8]
|
||||
new_match.bout_number = match_array[9]
|
||||
new_match.weight_id = weight_id
|
||||
new_match.bracket_position = match_array[11]
|
||||
new_match.bracket_position_number = match_array[12]
|
||||
new_match.loser1_name = match_array[13]
|
||||
new_match.loser2_name = match_array[14]
|
||||
# new_match.mat_id = mat_id if match_array[15].size > 0
|
||||
new_match.save
|
||||
end
|
||||
def parse_tournament(attributes)
|
||||
attributes.except!("id")
|
||||
@tournament.update(attributes)
|
||||
end
|
||||
|
||||
def parse_schools(schools)
|
||||
schools.each do | school |
|
||||
school_array = school.split(@attribute_separator,-1)
|
||||
new_school = School.new
|
||||
new_school.tournament_id = @tournament.id
|
||||
new_school.name = school_array[0]
|
||||
new_school.score = school_array[1]
|
||||
new_school.save
|
||||
schools.each do |school_attributes|
|
||||
school_attributes.except!("id")
|
||||
School.create(school_attributes.merge(tournament_id: @tournament.id))
|
||||
end
|
||||
end
|
||||
|
||||
def parse_weights(weights)
|
||||
weights.each do | weight |
|
||||
weight_array = weight.split(@attribute_separator,-1)
|
||||
new_weight = Weight.new
|
||||
new_weight.tournament_id = @tournament.id
|
||||
new_weight.max = weight_array[0]
|
||||
new_weight.save
|
||||
weights.each do |weight_attributes|
|
||||
weight_attributes.except!("id")
|
||||
Weight.create(weight_attributes.merge(tournament_id: @tournament.id))
|
||||
end
|
||||
end
|
||||
|
||||
def parse_mats(mats)
|
||||
mats.each do | mat |
|
||||
mat_array = mat.split(@attribute_separator,-1)
|
||||
new_mat = Mat.new
|
||||
new_mat.tournament_id = @tournament.id
|
||||
new_mat.name = mat_array[0]
|
||||
new_mat.save
|
||||
mats.each do |mat_attributes|
|
||||
mat_attributes.except!("id")
|
||||
Mat.create(mat_attributes.merge(tournament_id: @tournament.id))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
def parse_mat_assignment_rules(mat_assignment_rules)
|
||||
mat_assignment_rules.each do |rule_attributes|
|
||||
mat_name = rule_attributes.dig("mat", "name")
|
||||
mat = Mat.find_by(name: mat_name, tournament_id: @tournament.id)
|
||||
|
||||
# Map max values of weight_classes to their new IDs
|
||||
new_weight_classes = rule_attributes["weight_classes"].map do |max_value|
|
||||
Weight.find_by(max: max_value, tournament_id: @tournament.id)&.id
|
||||
end.compact
|
||||
|
||||
# Extract bracket_positions and rounds
|
||||
bracket_positions = rule_attributes["bracket_positions"]
|
||||
rounds = rule_attributes["rounds"]
|
||||
|
||||
rule_attributes.except!("id", "mat", "tournament_id", "weight_classes")
|
||||
|
||||
MatAssignmentRule.create(
|
||||
rule_attributes.merge(
|
||||
tournament_id: @tournament.id,
|
||||
mat_id: mat&.id,
|
||||
weight_classes: new_weight_classes,
|
||||
bracket_positions: bracket_positions,
|
||||
rounds: rounds
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def parse_wrestlers(wrestlers)
|
||||
wrestlers.each do |wrestler_attributes|
|
||||
school = School.find_by(name: wrestler_attributes["school"]["name"], tournament_id: @tournament.id)
|
||||
weight = Weight.find_by(max: wrestler_attributes["weight"]["max"], tournament_id: @tournament.id)
|
||||
wrestler_attributes.except!("id", "school", "weight")
|
||||
Wrestler.create(wrestler_attributes.merge(
|
||||
school_id: school&.id,
|
||||
weight_id: weight&.id
|
||||
))
|
||||
end
|
||||
end
|
||||
|
||||
def parse_matches(matches)
|
||||
matches.each do |match_attributes|
|
||||
next unless match_attributes # Skip if match_attributes is nil
|
||||
|
||||
weight = Weight.find_by(max: match_attributes.dig("weight", "max"), tournament_id: @tournament.id)
|
||||
mat = Mat.find_by(name: match_attributes.dig("mat", "name"), tournament_id: @tournament.id)
|
||||
|
||||
w1 = Wrestler.find_by(name: match_attributes["w1_name"], weight_id: weight&.id) if match_attributes["w1_name"]
|
||||
w2 = Wrestler.find_by(name: match_attributes["w2_name"], weight_id: weight&.id) if match_attributes["w2_name"]
|
||||
winner = Wrestler.find_by(name: match_attributes["winner_name"], weight_id: weight&.id) if match_attributes["winner_name"]
|
||||
|
||||
match_attributes.except!("id", "weight", "mat", "w1_name", "w2_name", "winner_name", "tournament_id")
|
||||
|
||||
Match.create(match_attributes.merge(
|
||||
tournament_id: @tournament.id,
|
||||
weight_id: weight&.id,
|
||||
mat_id: mat&.id,
|
||||
w1: w1&.id,
|
||||
w2: w2&.id,
|
||||
winner_id: winner&.id
|
||||
))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,111 +5,35 @@ class GeneratePoolNumbers
|
||||
|
||||
def savePoolNumbers
|
||||
@weight.wrestlers.each do |wrestler|
|
||||
if wrestler.pool and (wrestler.pool) > (@weight.pools)
|
||||
resetPool
|
||||
elsif @weight.one_pool_empty
|
||||
resetPool
|
||||
end
|
||||
end
|
||||
if @weight.pools == 4
|
||||
saveFourPoolNumbers(@weight.wrestlers_without_pool_assignment)
|
||||
elsif @weight.pools == 2
|
||||
saveTwoPoolNumbers(@weight.wrestlers_without_pool_assignment)
|
||||
elsif @weight.pools == 1
|
||||
saveOnePoolNumbers(@weight.wrestlers_without_pool_assignment)
|
||||
elsif @weight.pools == 8
|
||||
saveEightPoolNumbers(@weight.wrestlers_without_pool_assignment)
|
||||
end
|
||||
saveRandomPool(@weight.reload.wrestlers_without_pool_assignment)
|
||||
end
|
||||
|
||||
def resetPool
|
||||
@weight.wrestlers.each do |wrestler|
|
||||
wrestler.pool = nil
|
||||
wrestler.save
|
||||
@weight.reload
|
||||
end
|
||||
end
|
||||
|
||||
def saveRandomPool(poolWrestlers)
|
||||
pool = 1
|
||||
poolWrestlers.sort_by{|x| x.bracket_line }.reverse.each do |wrestler|
|
||||
wrestler.pool = pool
|
||||
wrestler.save
|
||||
if pool < @weight.pools
|
||||
pool = pool + 1
|
||||
else
|
||||
pool = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def saveOnePoolNumbers(poolWrestlers)
|
||||
poolWrestlers.sort_by{|x| x.bracket_line }.each do |w|
|
||||
w.pool = 1
|
||||
w.save
|
||||
wrestler.pool = get_wrestler_pool_number(@weight.pools, wrestler.bracket_line)
|
||||
wrestler.save
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def saveTwoPoolNumbers(poolWrestlers)
|
||||
poolWrestlers.sort_by{|x| x.bracket_line }.reverse.each do |w|
|
||||
if w.bracket_line == 1
|
||||
w.pool = 1
|
||||
elsif w.bracket_line == 2
|
||||
w.pool = 2
|
||||
elsif w.bracket_line == 3
|
||||
w.pool = 2
|
||||
elsif w.bracket_line == 4
|
||||
w.pool = 1
|
||||
end
|
||||
w.save
|
||||
def get_wrestler_pool_number(number_of_pools, wrestler_seed)
|
||||
# Convert seed to zero-based index for easier math
|
||||
zero_based = wrestler_seed - 1
|
||||
|
||||
# Determine which "row" we're on (0-based)
|
||||
# e.g., with 4 pools:
|
||||
# seeds 1..4 are in row 0,
|
||||
# seeds 5..8 are in row 1,
|
||||
# seeds 9..12 in row 2, etc.
|
||||
row = zero_based / number_of_pools
|
||||
|
||||
# Column within that row (also 0-based)
|
||||
col = zero_based % number_of_pools
|
||||
|
||||
if row.even?
|
||||
# Row is even => left-to-right
|
||||
# col=0 => pool 1, col=1 => pool 2, etc.
|
||||
pool = col + 1
|
||||
else
|
||||
# Row is odd => right-to-left
|
||||
# col=0 => pool number_of_pools, col=1 => pool number_of_pools-1, etc.
|
||||
pool = number_of_pools - col
|
||||
end
|
||||
end
|
||||
|
||||
def saveFourPoolNumbers(poolWrestlers)
|
||||
poolWrestlers.sort_by{|x| x.bracket_line }.reverse.each do |w|
|
||||
if w.bracket_line == 1
|
||||
w.pool = 1
|
||||
elsif w.bracket_line == 2
|
||||
w.pool = 2
|
||||
elsif w.bracket_line == 3
|
||||
w.pool = 3
|
||||
elsif w.bracket_line == 4
|
||||
w.pool = 4
|
||||
elsif w.bracket_line == 8
|
||||
w.pool = 1
|
||||
elsif w.bracket_line == 7
|
||||
w.pool = 2
|
||||
elsif w.bracket_line == 6
|
||||
w.pool = 3
|
||||
elsif w.bracket_line == 5
|
||||
w.pool = 4
|
||||
end
|
||||
w.save
|
||||
end
|
||||
end
|
||||
|
||||
def saveEightPoolNumbers(poolWrestlers)
|
||||
poolWrestlers.sort_by{|x| x.bracket_line }.reverse.each do |w|
|
||||
if w.bracket_line == 1
|
||||
w.pool = 1
|
||||
elsif w.bracket_line == 2
|
||||
w.pool = 2
|
||||
elsif w.bracket_line == 3
|
||||
w.pool = 3
|
||||
elsif w.bracket_line == 4
|
||||
w.pool = 4
|
||||
elsif w.bracket_line == 5
|
||||
w.pool = 5
|
||||
elsif w.bracket_line == 6
|
||||
w.pool = 6
|
||||
elsif w.bracket_line == 7
|
||||
w.pool = 7
|
||||
elsif w.bracket_line == 8
|
||||
w.pool = 8
|
||||
end
|
||||
w.save
|
||||
end
|
||||
end
|
||||
|
||||
pool
|
||||
end
|
||||
end
|
||||
@@ -5,7 +5,7 @@ class CalculateWrestlerTeamScore
|
||||
end
|
||||
|
||||
def totalScore
|
||||
if @wrestler.extra or @wrestler.matches.count == 0
|
||||
if @wrestler.extra or @wrestler.all_matches.count == 0
|
||||
return 0
|
||||
else
|
||||
earnedPoints - deductedPoints
|
||||
@@ -26,8 +26,8 @@ class CalculateWrestlerTeamScore
|
||||
|
||||
def placement_points
|
||||
return PoolBracketPlacementPoints.new(@wrestler).calcPoints if @tournament.tournament_type == "Pool to bracket"
|
||||
return ModifiedSixteenManPlacementPoints.new(@wrestler).calc_points if @tournament.tournament_type == "Modified 16 Man Double Elimination"
|
||||
return DoubleEliminationPlacementPoints.new(@wrestler).calc_points if @tournament.tournament_type == "Double Elimination 1-6"
|
||||
return ModifiedSixteenManPlacementPoints.new(@wrestler).calc_points if @tournament.tournament_type.include? "Modified 16 Man Double Elimination"
|
||||
return DoubleEliminationPlacementPoints.new(@wrestler).calc_points if @tournament.tournament_type.include? "Regular Double Elimination"
|
||||
return 0
|
||||
end
|
||||
|
||||
@@ -43,16 +43,43 @@ class CalculateWrestlerTeamScore
|
||||
end
|
||||
end
|
||||
|
||||
def pool_bonus_points
|
||||
if @tournament.tournament_type == "Pool to bracket"
|
||||
(@wrestler.pin_wins.select{|m| m.bracket_position == "Pool"}.size * 2) + (@wrestler.tech_wins.select{|m| m.bracket_position == "Pool"}.size * 1.5) + (@wrestler.major_wins.select{|m| m.bracket_position == "Pool"}.size * 1)
|
||||
else
|
||||
0
|
||||
end
|
||||
end
|
||||
|
||||
def byePoints
|
||||
points = 0
|
||||
if @tournament.tournament_type == "Pool to bracket"
|
||||
if @wrestler.pool_wins.size >= 1 and @wrestler.has_a_pool_bye == true
|
||||
2
|
||||
else
|
||||
0
|
||||
points += 2
|
||||
end
|
||||
else
|
||||
0
|
||||
end
|
||||
if @tournament.tournament_type.include? "Regular Double Elimination"
|
||||
if @wrestler.championship_advancement_wins.size > 0 or @wrestler.matches_won.select{|m| m.bracket_position == "1/2" and m.win_type != "BYE"}.size > 0
|
||||
# if they have a win in the championship round or if they got a bye all the way to finals and won the finals
|
||||
points += @wrestler.championship_byes.size * 2
|
||||
end
|
||||
if @wrestler.consolation_advancement_wins.size > 0 or @wrestler.matches_won.select{|m| m.bracket_position == "3/4" and m.win_type != "BYE"}.size > 0
|
||||
# if they have a win in the consolation round or if they got a bye all the way to 3rd/4th match and won
|
||||
points += @wrestler.consolation_byes.size * 1
|
||||
end
|
||||
end
|
||||
if @tournament.tournament_type.include? "Modified 16 Man Double Elimination"
|
||||
if @wrestler.championship_advancement_wins.size > 0 or @wrestler.matches_won.select{|m| m.bracket_position == "1/2" and m.win_type != "BYE"}.size > 0
|
||||
# if they have a win in the championship round or if they got a bye all the way to finals and won the finals
|
||||
points += @wrestler.championship_byes.size * 2
|
||||
end
|
||||
if @wrestler.consolation_advancement_wins.size > 0 or @wrestler.matches_won.select{|m| m.bracket_position == "5/6" and m.win_type != "BYE"}.size > 0
|
||||
# if they have a win in the consolation round or if they got a bye all the way to 5th/6th match and won
|
||||
# since the consolation bracket goes to 5/6 in a modified tournament
|
||||
points += @wrestler.consolation_byes.size * 1
|
||||
end
|
||||
end
|
||||
return points
|
||||
end
|
||||
|
||||
def bonusWinPoints
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
class DoubleEliminationPlacementPoints
|
||||
def initialize(wrestler)
|
||||
@wrestler = wrestler
|
||||
if wrestler.tournament.tournament_type == "Double Elimination 1-6"
|
||||
@number_of_placers = 6
|
||||
end
|
||||
@number_of_placers = @wrestler.tournament.number_of_placers
|
||||
end
|
||||
|
||||
def calc_points
|
||||
@@ -22,17 +20,29 @@ class DoubleEliminationPlacementPoints
|
||||
elsif won_bracket_position_size("7/8") > 0
|
||||
return PlacementPoints.new(@number_of_placers).seventhPlace
|
||||
elsif bracket_position_size("Conso Quarter") > 0 and @number_of_placers >= 8
|
||||
return PlacementPoints.new(@number_of_placers).eigthPlace
|
||||
return PlacementPoints.new(@number_of_placers).eighthPlace
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
def bracket_position_size(bracket_position_name)
|
||||
@wrestler.all_matches.select{|m| m.bracket_position == bracket_position_name}.size
|
||||
@wrestler.all_matches.select{|m| m.bracket_position == bracket_position_name}.size
|
||||
end
|
||||
|
||||
def won_bracket_position_size(bracket_position_name)
|
||||
@wrestler.matches_won.select{|m| m.bracket_position == bracket_position_name}.size
|
||||
end
|
||||
|
||||
def bracket_placement_points(bracket_position_name)
|
||||
if bracket_position_name == "Did not place"
|
||||
return 0
|
||||
end
|
||||
if @wrestler.participating_matches.where(bracket_position: bracket_position_name).count > 0
|
||||
points = Teampointadjust.find_by(tournament_id: @wrestler.tournament.id, points_for_placement: bracket_position_name)
|
||||
if points
|
||||
# ... existing code ...
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,7 +1,8 @@
|
||||
class ModifiedSixteenManPlacementPoints
|
||||
def initialize(wrestler)
|
||||
@wrestler = wrestler
|
||||
@number_of_placers = 6
|
||||
@wrestler = wrestler
|
||||
@number_of_placers = @wrestler.tournament.number_of_placers
|
||||
end
|
||||
|
||||
def calc_points
|
||||
@@ -17,6 +18,10 @@ class ModifiedSixteenManPlacementPoints
|
||||
return PlacementPoints.new(@number_of_placers).fifthPlace
|
||||
elsif bracket_position_size("5/6") > 0
|
||||
return PlacementPoints.new(@number_of_placers).sixthPlace
|
||||
elsif won_bracket_position_size("7/8") > 0
|
||||
return PlacementPoints.new(@number_of_placers).seventhPlace
|
||||
elsif bracket_position_size("Conso Semis") > 0 and @number_of_placers >= 8
|
||||
return PlacementPoints.new(@number_of_placers).eighthPlace
|
||||
else
|
||||
return 0
|
||||
end
|
||||
|
||||
@@ -3,13 +3,13 @@ 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.schools @schools do |school|
|
||||
json.id school.id
|
||||
json.name school.name
|
||||
json.score school.score
|
||||
end
|
||||
|
||||
json.weights @tournament.weights do |weight|
|
||||
json.weights @weights do |weight|
|
||||
json.id weight.id
|
||||
json.max weight.max
|
||||
json.bracket_size weight.bracket_size
|
||||
@@ -26,7 +26,7 @@ json.cache! ["api_tournament", @tournament] do
|
||||
end
|
||||
end
|
||||
|
||||
json.mats @tournament.mats do |mat|
|
||||
json.mats @mats do |mat|
|
||||
json.name mat.name
|
||||
json.unfinished_matches mat.unfinished_matches do |match|
|
||||
json.bout_number match.bout_number
|
||||
@@ -35,7 +35,7 @@ json.cache! ["api_tournament", @tournament] do
|
||||
end
|
||||
end
|
||||
|
||||
json.unassignedMatches @tournament.matches.select{|m| m.mat_id == nil}.sort_by{|m| m.bout_number}[0...9] do |match|
|
||||
json.unassignedMatches @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
|
||||
@@ -43,7 +43,7 @@ json.cache! ["api_tournament", @tournament] do
|
||||
json.round match.round
|
||||
end
|
||||
|
||||
json.matches @tournament.matches do |match|
|
||||
json.matches @matches do |match|
|
||||
json.bout_number match.bout_number
|
||||
json.w1_name match.w1_name
|
||||
json.w2_name match.w2_name
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<h2>Resend confirmation instructions</h2>
|
||||
|
||||
<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<div><%= f.label :email %><br />
|
||||
<%= f.email_field :email, :autofocus => true %></div>
|
||||
|
||||
<div><%= f.submit "Resend confirmation instructions" %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
@@ -1,5 +0,0 @@
|
||||
<p>Welcome <%= @email %>!</p>
|
||||
|
||||
<p>You can confirm your account email through the link below:</p>
|
||||
|
||||
<p><%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @token) %></p>
|
||||
@@ -1,8 +0,0 @@
|
||||
<p>Hello <%= @resource.email %>!</p>
|
||||
|
||||
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
|
||||
|
||||
<p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @token) %></p>
|
||||
|
||||
<p>If you didn't request this, please ignore this email.</p>
|
||||
<p>Your password won't change until you access the link above and create a new one.</p>
|
||||
@@ -1,7 +0,0 @@
|
||||
<p>Hello <%= @resource.email %>!</p>
|
||||
|
||||
<p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>
|
||||
|
||||
<p>Click the link below to unlock your account:</p>
|
||||
|
||||
<p><%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @token) %></p>
|
||||
@@ -1,16 +0,0 @@
|
||||
<h2>Change your password</h2>
|
||||
|
||||
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
<%= f.hidden_field :reset_password_token %>
|
||||
|
||||
<div><%= f.label :password, "New password" %><br />
|
||||
<%= f.password_field :password, :autofocus => true %></div>
|
||||
|
||||
<div><%= f.label :password_confirmation, "Confirm new password" %><br />
|
||||
<%= f.password_field :password_confirmation %></div>
|
||||
|
||||
<div><%= f.submit "Change my password", :class=>"btn btn-success"%></div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
@@ -1,13 +0,0 @@
|
||||
<h2>Forgot your password?</h2>
|
||||
|
||||
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<div><%= f.label :email %><br />
|
||||
<%= f.email_field :email, :autofocus => true %></div>
|
||||
<br>
|
||||
<div><%= f.submit "Send me reset password instructions",:class=>"btn btn-success" %></div>
|
||||
<% end %>
|
||||
<br>
|
||||
<br>
|
||||
<%= render "devise/shared/links" %>
|
||||
@@ -1,29 +0,0 @@
|
||||
<h2>Edit <%= resource_name.to_s.humanize %></h2>
|
||||
|
||||
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<div><%= f.label :email %><br />
|
||||
<%= f.email_field :email, :autofocus => true %></div>
|
||||
|
||||
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
|
||||
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
|
||||
<% end %>
|
||||
|
||||
<div><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
|
||||
<%= f.password_field :password, :autocomplete => "off" %></div>
|
||||
|
||||
<div><%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation %></div>
|
||||
|
||||
<div><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
|
||||
<%= f.password_field :current_password %></div>
|
||||
<br>
|
||||
<div><%= f.submit "Update",:class=>"btn btn-success" %></div>
|
||||
<% end %>
|
||||
|
||||
<h3>Cancel my account</h3>
|
||||
|
||||
<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), :data => { :confirm => "Are you sure?" }, :method => :delete, :class=>"btn btn-danger" %></p>
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<h2>Sign up</h2>
|
||||
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<div><%= f.label :email %><br />
|
||||
<%= f.email_field :email, :autofocus => true %></div>
|
||||
|
||||
<div><%= f.label :password %><br />
|
||||
<%= f.password_field :password %></div>
|
||||
|
||||
<div><%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation %></div>
|
||||
|
||||
<div><%= f.submit "Sign up" %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
@@ -1,18 +0,0 @@
|
||||
<h2 class="form-signin-heading">Sign in</h2>
|
||||
|
||||
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
|
||||
<div><%= f.label :email ,:class=>"sr-only"%><br />
|
||||
<%= f.email_field :email, :autofocus => true,:class=>"form-control",:placeholder=>"Email Address" %></div>
|
||||
|
||||
<div><%= f.label :password,:class=>"sr-only" %><br />
|
||||
<%= f.password_field :password,:class=>"form-control",:placeholder=>"Password" %></div>
|
||||
|
||||
<% if devise_mapping.rememberable? -%>
|
||||
<div class="checkbox"><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>
|
||||
<% end -%>
|
||||
|
||||
<div><%= f.submit "Sign in" ,:class=>"btn btn-lg btn-primary btn-block" %></div>
|
||||
<% end %>
|
||||
<br>
|
||||
<br>
|
||||
<%= render "devise/shared/links" %>
|
||||
@@ -1,25 +0,0 @@
|
||||
<%- if controller_name != 'sessions' %>
|
||||
<%= link_to "Sign in", new_session_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
|
||||
<%= link_to "Sign up", new_registration_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
|
||||
<%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
|
||||
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
|
||||
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.omniauthable? %>
|
||||
<%- resource_class.omniauth_providers.each do |provider| %>
|
||||
<%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %><br />
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
@@ -1,12 +0,0 @@
|
||||
<h2>Resend unlock instructions</h2>
|
||||
|
||||
<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<div><%= f.label :email %><br />
|
||||
<%= f.email_field :email, :autofocus => true %></div>
|
||||
|
||||
<div><%= f.submit "Resend unlock instructions" %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
@@ -1,9 +1 @@
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-64366913-2', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
<script defer data-api="/plausible/api/event" data-domain="wrestlingdev.com" src="/plausible/js/script.js"></script>
|
||||
@@ -1,17 +1,7 @@
|
||||
<!-- Bootstrap CDN -->
|
||||
<!-- 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">
|
||||
<!-- Latest compiled and minified JavaScript -->
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
|
||||
|
||||
<!-- DataTables CDN -->
|
||||
<script src="https://cdn.datatables.net/1.10.6/js/jquery.dataTables.min.js"></script>
|
||||
<!-- Fontawesome CDN -->
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
|
||||
|
||||
|
||||
<!-- Fontawesome Modifications -->
|
||||
<style>
|
||||
.fa {
|
||||
color: #777;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<a class="navbar-brand" href="/">WrestlingDev</a>
|
||||
</div>
|
||||
<div id="navbar" class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><%= link_to "Browse Tournaments", "/tournaments/" %></li>
|
||||
<li><%= link_to "About", "/static_pages/about" %></li>
|
||||
<li><%= link_to "Tutorials", "/static_pages/tutorials" %></li>
|
||||
@@ -19,13 +19,13 @@
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#"><%= current_user.email %>
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><%=link_to "Log out", destroy_user_session_url ,:method => 'delete' %></li>
|
||||
<li><%=link_to "Edit user", edit_user_registration_path %></li>
|
||||
<li><%=link_to "My tournaments and schools","/static_pages/my_tournaments" %></li>
|
||||
<li><%= link_to "Log out", logout_path, method: :delete %></li>
|
||||
<li><%= link_to "Edit profile", edit_user_path(current_user) %></li>
|
||||
<li><%= link_to "My tournaments and schools", "/static_pages/my_tournaments" %></li>
|
||||
</ul>
|
||||
</li>
|
||||
<% else %>
|
||||
<li><%= link_to "Log In" , new_user_session_path %></li>
|
||||
<li><%= link_to "Log In", login_path %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<script src="//instant.page/5.1.0" type="module" integrity="sha384-by67kQnR+pyfy8yWP4kPO12fHKRLHZPfEsiSXR8u2IKcTdxD805MGUXBzVPnkLHw"></script>
|
||||
@@ -1,28 +1,38 @@
|
||||
<% if @tournament and @tournament.id %>
|
||||
<h2><%= @tournament.name %> Links</h2>
|
||||
<nav class="navbar navbar-default navbar-static-top" role="navigation" id="tournament-navbar">
|
||||
<nav class="navbar navbar-default navbar-fixed-top" role="navigation" id="tournament-navbar">
|
||||
<div class="container">
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><%= link_to " Tournament Home" , "/tournaments/#{@tournament.id}", class: "fas fa-home" %></li>
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#"><i class="fas fa-poll-h"> Tournament Results/Brackets</i>
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><strong>Results</strong></li>
|
||||
<li><%= link_to "Team Scores" , "/tournaments/#{@tournament.id}/team_scores" %></li>
|
||||
<li><strong>Brackets</strong></li>
|
||||
<% @tournament.weights.sort_by{|weight| weight.max }.each do |weight| %>
|
||||
<li><%= link_to "#{weight.max}" , "/tournaments/#{@tournament.id}/brackets/#{weight.id}" %></li>
|
||||
<% end %>
|
||||
<li><%= link_to "All Brackets (Printable)", "/tournaments/#{@tournament.id}/all_brackets?print=true", target: :_blank %></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><%= link_to " Bout Board" , "/tournaments/#{@tournament.id}/up_matches", class: "fas fa-list-alt" %></li>
|
||||
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#tournament-navbar-collapse" 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>
|
||||
<%= link_to "Tournament Menu", "/tournaments/#{@tournament.id}", class: "navbar-brand" %>
|
||||
</div>
|
||||
<div id="tournament-navbar-collapse" class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><%= link_to " Home" , "/tournaments/#{@tournament.id}", class: "fas fa-home" %></li>
|
||||
<% if can? :read, @tournament %>
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#"><i class="fas fa-poll-h"> Results/Brackets</i>
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><strong>Results</strong></li>
|
||||
<li><%= link_to "Team Scores" , "/tournaments/#{@tournament.id}/team_scores" %></li>
|
||||
<li><%= link_to "All Match Results" , "/tournaments/#{@tournament.id}/all_results" %></li>
|
||||
<li><strong>Brackets</strong></li>
|
||||
<% @tournament.weights.sort_by{|weight| weight.max }.each do |weight| %>
|
||||
<li><%= link_to "#{weight.max}" , "/tournaments/#{@tournament.id}/brackets/#{weight.id}" %></li>
|
||||
<% end %>
|
||||
<li><%= link_to "All Brackets (Printable)", "/tournaments/#{@tournament.id}/all_brackets?print=true", target: :_blank %></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><%= link_to " Bout Board" , "/tournaments/#{@tournament.id}/up_matches", class: "fas fa-list-alt" %></li>
|
||||
<% end %>
|
||||
<% if can? :manage, @tournament %>
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#director"><i class="fas fa-tools"> Tournament Director Links</i>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#director"><i class="fas fa-tools"> Director Links</i>
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><strong>Pages</strong></li>
|
||||
@@ -31,6 +41,9 @@
|
||||
<li><%= link_to "All Matches" , "/tournaments/#{@tournament.id}/matches" %></li>
|
||||
<li><%= link_to "Full Screen Bout Board" , "/tournaments/#{@tournament.id}/up_matches?print=true" , target: :_blank %></li>
|
||||
<li><%= link_to "Deduct Team Points" , "/tournaments/#{@tournament.id}/teampointadjust" %></li>
|
||||
<li><%= link_to "View All Mat Assignment Rules", tournament_mat_assignment_rules_path(@tournament) %></li>
|
||||
<li><%= link_to 'Manage Backups', tournament_tournament_backups_path(@tournament) %></li>
|
||||
<li><%= link_to "Reset Bout Board", reset_bout_board_tournament_path(@tournament), method: :post, data: { confirm: "Are you sure you want to reset the bout board?" } %></li>
|
||||
<% if can? :destroy, @tournament %>
|
||||
<li><%= link_to "Tournament Delegation" , "/tournaments/#{@tournament.id}/delegate" %></li>
|
||||
<% end %>
|
||||
@@ -42,9 +55,12 @@
|
||||
<% end %>
|
||||
<% end %>
|
||||
<li><strong>Time Savers</strong></li>
|
||||
<li><%= link_to "Create High School Weights (106-285)" , "/tournaments/#{@tournament.id}/create_custom_weights?customValue=hs",data: { confirm: 'Are you sure? This will delete all current weights.' } %></li>
|
||||
<li><%= link_to "Create Boys High School Weights (106-285)" , "/tournaments/#{@tournament.id}/create_custom_weights?customValue=#{Weight::HS_WEIGHT_CLASSES}",data: { confirm: 'Are you sure? This will delete all current weights.' } %></li>
|
||||
<li><%= link_to "Create Girls High School Weights (100-235)" , "/tournaments/#{@tournament.id}/create_custom_weights?customValue=#{Weight::HS_GIRLS_WEIGHT_CLASSES}",data: { confirm: 'Are you sure? This will delete all current weights.' } %></li>
|
||||
<li><%= link_to "Create Boys Middle School Weights (80-245)" , "/tournaments/#{@tournament.id}/create_custom_weights?customValue=#{Weight::MS_WEIGHT_CLASSES}",data: { confirm: 'Are you sure? This will delete all current weights.' } %></li>
|
||||
<li><%= link_to "Create Girls Middle School Weights (72-235)" , "/tournaments/#{@tournament.id}/create_custom_weights?customValue=#{Weight::MS_GIRLS_WEIGHT_CLASSES}",data: { confirm: 'Are you sure? This will delete all current weights.' } %></li>
|
||||
<li><strong>Tournament Actions</strong></li>
|
||||
<li><%= link_to "Calculate Team Scores" , "/tournaments/#{@tournament.id}/calculate_team_scores", method: :post %></li>
|
||||
<li><%= link_to "Calculate Team Scores" , "/tournaments/#{@tournament.id}/calculate_team_scores", :method => :put %></li>
|
||||
<li><%= link_to "Generate Brackets" , "/tournaments/#{@tournament.id}/generate_matches", data: { confirm: 'Are you sure? This will delete all current matches.' } %></li>
|
||||
<li><%= link_to "Export Data" , "/tournaments/#{@tournament.id}/export?print=true", target: :_blank %></li>
|
||||
</ul>
|
||||
|
||||
@@ -10,41 +10,41 @@
|
||||
(adsbygoogle = window.adsbygoogle || []).push({});
|
||||
</script>
|
||||
<% end %>
|
||||
<div class="afs_ads"> </div>
|
||||
<div class="alert alert-danger alert-dismissible" id="blocked_message" style="display: none;"><a href="#" class="close" data-dismiss="alert" aria-label="close">×</a>
|
||||
<p>We've detected that you have an ad blocker enabled! Please consider disabling it for <strong>wrestlingdev.com</strong>. This site is free for users and supported by ads. Ad blockers also block performance monitoring that help us with user experience.</p>
|
||||
</div>
|
||||
<script>
|
||||
(function() {
|
||||
var message = "We've detected that you have an ad blocker enabled! Please consider disabling it for wrestlingdev.com. This site is free for users and supported by ads. Ad blockers also block performance monitoring that help us with user experience.";
|
||||
|
||||
// Define a function for showing the message.
|
||||
// Set a timeout of 2 seconds to give adblocker
|
||||
// a chance to do its thing
|
||||
var tryMessage = function() {
|
||||
setTimeout(function() {
|
||||
if(!document.getElementsByClassName) return;
|
||||
var ads = document.getElementsByClassName('afs_ads'),
|
||||
ad = ads[ads.length - 1];
|
||||
|
||||
if(!ad
|
||||
|| ad.innerHTML.length == 0
|
||||
|| ad.clientHeight === 0) {
|
||||
//alert(message);
|
||||
document.getElementById("blocked_message").style.display = 'block';
|
||||
//window.location.href = '[URL of the donate page. Remove the two slashes at the start of thsi line to enable.]';
|
||||
} else {
|
||||
ad.style.display = 'none';
|
||||
}
|
||||
|
||||
}, 2000);
|
||||
// Only run ad blocker check if fakeAd hasn't been checked yet in this context
|
||||
if (typeof window.adBlockerCheckExecuted === 'undefined') {
|
||||
let fakeAd = document.createElement("div");
|
||||
fakeAd.className = "textads banner-ads banner_ads ad-unit ad-zone ad-space adsbox"
|
||||
|
||||
fakeAd.style.height = "1px"
|
||||
fakeAd.style.position = "absolute"; // Prevent potential layout shift
|
||||
fakeAd.style.top = "-10px";
|
||||
fakeAd.style.left = "-10px";
|
||||
|
||||
document.body.appendChild(fakeAd)
|
||||
|
||||
// Use requestAnimationFrame to ensure the element is rendered before checking offsetHeight
|
||||
requestAnimationFrame(() => {
|
||||
let x_width = fakeAd.offsetHeight;
|
||||
// let msg = document.getElementById("msg") // msg variable wasn't used
|
||||
|
||||
if(x_width){
|
||||
console.log("No AdBlocker Detected")
|
||||
}else{
|
||||
console.log("AdBlocker detected")
|
||||
const blockedMessage = document.getElementById("blocked_message");
|
||||
if (blockedMessage) {
|
||||
blockedMessage.style.display = 'block';
|
||||
}
|
||||
}
|
||||
// Clean up the fake element
|
||||
document.body.removeChild(fakeAd);
|
||||
});
|
||||
|
||||
/* Attach a listener for page load ... then show the message */
|
||||
if(window.addEventListener) {
|
||||
window.addEventListener('load', tryMessage, false);
|
||||
} else {
|
||||
window.attachEvent('onload', tryMessage); //IE
|
||||
}
|
||||
})();
|
||||
// Mark check as executed
|
||||
window.adBlockerCheckExecuted = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
<% if params[:print] %>
|
||||
<head>
|
||||
<%= csrf_meta_tags %>
|
||||
<%= action_cable_meta_tag %>
|
||||
<title>WrestlingDev</title>
|
||||
<%= stylesheet_link_tag "application", media: "all",
|
||||
"data-turbolinks-track" => true %>
|
||||
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
|
||||
<%= render 'layouts/cdn' %>
|
||||
<%= render 'layouts/shim' %>
|
||||
</head>
|
||||
@@ -13,26 +17,25 @@
|
||||
<% else %>
|
||||
<head>
|
||||
<title>WrestlingDev</title>
|
||||
<%= action_cable_meta_tag %>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<% if Rails.env.production? %>
|
||||
<%= render 'layouts/analytics' %>
|
||||
<% end %>
|
||||
<%= stylesheet_link_tag "application", media: "all",
|
||||
"data-turbolinks-track" => true %>
|
||||
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
|
||||
<%= stylesheet_link_tag "application" %>
|
||||
<%= javascript_include_tag "application" %>
|
||||
<%= csrf_meta_tags %>
|
||||
<%= render 'layouts/cdn' %>
|
||||
<%= render 'layouts/shim' %>
|
||||
<%= render 'layouts/instantpage' %>
|
||||
</head>
|
||||
<body style="padding-top: 70px;">
|
||||
<body style="padding-top: 100px;">
|
||||
<%= render 'layouts/header' %>
|
||||
<%= render 'layouts/tournament-navbar' %>
|
||||
|
||||
<div class="container">
|
||||
<div class="navbar-roof"></div>
|
||||
<%= render 'layouts/header' %>
|
||||
|
||||
<div id="page-content">
|
||||
<div class="row">
|
||||
<%= render 'layouts/tournament-navbar' %>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><%= render 'layouts/underheader' %></div>
|
||||
</div>
|
||||
@@ -41,7 +44,13 @@
|
||||
<% if notice %>
|
||||
<p id="notice" class="alert alert-success alert-dismissible"><a href="#" class="close" data-dismiss="alert" aria-label="close">×</a><%= notice %></p>
|
||||
<% end %>
|
||||
<div id="view"><%= yield %></div>
|
||||
<% if alert %>
|
||||
<p id="alert" class="alert alert-danger alert-dismissible"><a href="#" class="close" data-dismiss="alert" aria-label="close">×</a><%= alert %></p>
|
||||
<% end %>
|
||||
<div id="view" style="overflow-x: auto; overflow-y: hidden;"> <%# Horizontal scroll only %>
|
||||
<br><br>
|
||||
<%= yield %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
13
app/views/layouts/mailer.html.erb
Normal file
13
app/views/layouts/mailer.html.erb
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<style>
|
||||
/* Email styles need to be inline */
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<%= yield %>
|
||||
</body>
|
||||
</html>
|
||||
1
app/views/layouts/mailer.text.erb
Normal file
1
app/views/layouts/mailer.text.erb
Normal file
@@ -0,0 +1 @@
|
||||
<%= yield %>
|
||||
61
app/views/mat_assignment_rules/_form.html.erb
Normal file
61
app/views/mat_assignment_rules/_form.html.erb
Normal file
@@ -0,0 +1,61 @@
|
||||
<%= form_with model: [@tournament, @mat_assignment_rule] do |form| %>
|
||||
<!-- Mat Selection -->
|
||||
<div>
|
||||
<%= form.label :mat_id, "Select Mat" %><br>
|
||||
<% if @available_mats.any? %>
|
||||
<%= form.collection_select :mat_id, @available_mats, :id, :name, { prompt: "Choose a Mat" } %>
|
||||
<% else %>
|
||||
<p>No mats are available. Please create a mat first.</p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<!-- Weight Classes as Checkboxes -->
|
||||
<div>
|
||||
<%= form.label :weight_classes, "Allowed Weight Classes" %><br>
|
||||
<% if @tournament.weights.any? %>
|
||||
<% @tournament.weights.sort_by{|w| w.max}.each do |weight| %>
|
||||
<div>
|
||||
<%= check_box_tag "mat_assignment_rule[weight_classes][]", weight.id, Array(@mat_assignment_rule.weight_classes).map(&:to_i).include?(weight.id) %>
|
||||
<%= label_tag "mat_assignment_rule_weight_classes_#{weight.id}", weight.max %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<p>No weight classes are available. Please create weight classes first.</p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<!-- Bracket Positions as Checkboxes -->
|
||||
<div>
|
||||
<%= form.label :bracket_positions, "Allowed Bracket Positions" %><br>
|
||||
<% if @unique_bracket_positions.present? %>
|
||||
<% @unique_bracket_positions.each do |position| %>
|
||||
<div>
|
||||
<%= check_box_tag "mat_assignment_rule[bracket_positions][]", position, Array(@mat_assignment_rule.bracket_positions).include?(position) %>
|
||||
<%= label_tag "mat_assignment_rule_bracket_positions_#{position}", position %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<p>No bracket positions are available. Please ensure matches have bracket positions set.</p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<!-- Rounds as Checkboxes -->
|
||||
<div>
|
||||
<%= form.label :rounds, "Allowed Rounds" %><br>
|
||||
<% if @unique_rounds.present? %>
|
||||
<% @unique_rounds.each do |round| %>
|
||||
<div>
|
||||
<%= check_box_tag "mat_assignment_rule[rounds][]", round, Array(@mat_assignment_rule.rounds).map(&:to_i).include?(round) %>
|
||||
<%= label_tag "mat_assignment_rule_rounds_#{round}", round %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<p>No rounds are available. Please ensure matches have rounds set.</p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<div>
|
||||
<%= form.submit 'Submit', class: "btn btn-success" %>
|
||||
</div>
|
||||
<% end %>
|
||||
3
app/views/mat_assignment_rules/edit.html.erb
Normal file
3
app/views/mat_assignment_rules/edit.html.erb
Normal file
@@ -0,0 +1,3 @@
|
||||
<h1>Edit Mat Assignment Rule for <%= @tournament.name %></h1>
|
||||
|
||||
<%= render "form", tournament: @tournament, mat_assignment: @mat_assignment_rule, available_mats: @available_mats %>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user