mirror of
https://github.com/jcwimer/wrestlingApp
synced 2026-03-25 01:14:43 +00:00
Compare commits
32 Commits
8c2ddf55ed
...
developmen
| Author | SHA1 | Date | |
|---|---|---|---|
| 7526148ba5 | |||
| e8e0fa291b | |||
| 679fc2fcb9 | |||
| 18d39c6c8f | |||
| ca4d5ce0db | |||
| 654cb84827 | |||
| dc50efe8fc | |||
| 8670ce38c3 | |||
| d359be3ea1 | |||
| e97aa0d680 | |||
| ae8d995b2c | |||
| d57aaac09d | |||
| fcc8a9b9a9 | |||
| b51866e9d8 | |||
| 07d43e7720 | |||
| d8b6cfa8ac | |||
| 5d674f894f | |||
| 25df2a7280 | |||
| 2767274066 | |||
| a2f8c7bced | |||
| 9c2a9d62ad | |||
| 556090c16b | |||
| 86f9c03991 | |||
| c8764c149b | |||
| fe9a9c628c | |||
| 7e4b6d8fc8 | |||
| 940f7b1d00 | |||
| 52df73d14f | |||
| 8b03a74b1e | |||
| b4bca8f10a | |||
| af1f8df4b6 | |||
| 3576445a1c |
@@ -1 +1 @@
|
|||||||
wrestlingdev
|
wrestlingdev
|
||||||
@@ -1 +1 @@
|
|||||||
ruby-3.2.0
|
ruby-4.0.1
|
||||||
6
Gemfile
6
Gemfile
@@ -1,8 +1,8 @@
|
|||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
ruby '3.2.0'
|
ruby '4.0.1'
|
||||||
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
|
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
|
||||||
gem 'rails', '8.0.3'
|
gem 'rails', '8.1.2'
|
||||||
|
|
||||||
# Added in rails 7.1
|
# Added in rails 7.1
|
||||||
gem 'rails-html-sanitizer'
|
gem 'rails-html-sanitizer'
|
||||||
@@ -67,6 +67,7 @@ gem 'influxdb-rails'
|
|||||||
gem 'cancancan'
|
gem 'cancancan'
|
||||||
gem 'round_robin_tournament'
|
gem 'round_robin_tournament'
|
||||||
gem 'rb-readline'
|
gem 'rb-readline'
|
||||||
|
gem 'rqrcode'
|
||||||
# Replacing Delayed Job with Solid Queue
|
# Replacing Delayed Job with Solid Queue
|
||||||
# gem 'delayed_job_active_record'
|
# gem 'delayed_job_active_record'
|
||||||
gem 'solid_queue'
|
gem 'solid_queue'
|
||||||
@@ -91,4 +92,3 @@ group :development, :test do
|
|||||||
# rails-controller-testing is needed for assert_template
|
# rails-controller-testing is needed for assert_template
|
||||||
gem 'rails-controller-testing'
|
gem 'rails-controller-testing'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
261
Gemfile.lock
261
Gemfile.lock
@@ -1,29 +1,31 @@
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (8.0.3)
|
action_text-trix (2.1.16)
|
||||||
actionpack (= 8.0.3)
|
railties
|
||||||
activesupport (= 8.0.3)
|
actioncable (8.1.2)
|
||||||
|
actionpack (= 8.1.2)
|
||||||
|
activesupport (= 8.1.2)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
actionmailbox (8.0.3)
|
actionmailbox (8.1.2)
|
||||||
actionpack (= 8.0.3)
|
actionpack (= 8.1.2)
|
||||||
activejob (= 8.0.3)
|
activejob (= 8.1.2)
|
||||||
activerecord (= 8.0.3)
|
activerecord (= 8.1.2)
|
||||||
activestorage (= 8.0.3)
|
activestorage (= 8.1.2)
|
||||||
activesupport (= 8.0.3)
|
activesupport (= 8.1.2)
|
||||||
mail (>= 2.8.0)
|
mail (>= 2.8.0)
|
||||||
actionmailer (8.0.3)
|
actionmailer (8.1.2)
|
||||||
actionpack (= 8.0.3)
|
actionpack (= 8.1.2)
|
||||||
actionview (= 8.0.3)
|
actionview (= 8.1.2)
|
||||||
activejob (= 8.0.3)
|
activejob (= 8.1.2)
|
||||||
activesupport (= 8.0.3)
|
activesupport (= 8.1.2)
|
||||||
mail (>= 2.8.0)
|
mail (>= 2.8.0)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
actionpack (8.0.3)
|
actionpack (8.1.2)
|
||||||
actionview (= 8.0.3)
|
actionview (= 8.1.2)
|
||||||
activesupport (= 8.0.3)
|
activesupport (= 8.1.2)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
rack (>= 2.2.4)
|
rack (>= 2.2.4)
|
||||||
rack-session (>= 1.0.1)
|
rack-session (>= 1.0.1)
|
||||||
@@ -31,42 +33,43 @@ GEM
|
|||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.6)
|
rails-html-sanitizer (~> 1.6)
|
||||||
useragent (~> 0.16)
|
useragent (~> 0.16)
|
||||||
actiontext (8.0.3)
|
actiontext (8.1.2)
|
||||||
actionpack (= 8.0.3)
|
action_text-trix (~> 2.1.15)
|
||||||
activerecord (= 8.0.3)
|
actionpack (= 8.1.2)
|
||||||
activestorage (= 8.0.3)
|
activerecord (= 8.1.2)
|
||||||
activesupport (= 8.0.3)
|
activestorage (= 8.1.2)
|
||||||
|
activesupport (= 8.1.2)
|
||||||
globalid (>= 0.6.0)
|
globalid (>= 0.6.0)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (8.0.3)
|
actionview (8.1.2)
|
||||||
activesupport (= 8.0.3)
|
activesupport (= 8.1.2)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.11)
|
erubi (~> 1.11)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.6)
|
rails-html-sanitizer (~> 1.6)
|
||||||
activejob (8.0.3)
|
activejob (8.1.2)
|
||||||
activesupport (= 8.0.3)
|
activesupport (= 8.1.2)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (8.0.3)
|
activemodel (8.1.2)
|
||||||
activesupport (= 8.0.3)
|
activesupport (= 8.1.2)
|
||||||
activerecord (8.0.3)
|
activerecord (8.1.2)
|
||||||
activemodel (= 8.0.3)
|
activemodel (= 8.1.2)
|
||||||
activesupport (= 8.0.3)
|
activesupport (= 8.1.2)
|
||||||
timeout (>= 0.4.0)
|
timeout (>= 0.4.0)
|
||||||
activestorage (8.0.3)
|
activestorage (8.1.2)
|
||||||
actionpack (= 8.0.3)
|
actionpack (= 8.1.2)
|
||||||
activejob (= 8.0.3)
|
activejob (= 8.1.2)
|
||||||
activerecord (= 8.0.3)
|
activerecord (= 8.1.2)
|
||||||
activesupport (= 8.0.3)
|
activesupport (= 8.1.2)
|
||||||
marcel (~> 1.0)
|
marcel (~> 1.0)
|
||||||
activesupport (8.0.3)
|
activesupport (8.1.2)
|
||||||
base64
|
base64
|
||||||
benchmark (>= 0.3)
|
|
||||||
bigdecimal
|
bigdecimal
|
||||||
concurrent-ruby (~> 1.0, >= 1.3.1)
|
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||||
connection_pool (>= 2.2.5)
|
connection_pool (>= 2.2.5)
|
||||||
drb
|
drb
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
|
json
|
||||||
logger (>= 1.4.2)
|
logger (>= 1.4.2)
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
securerandom (>= 0.3)
|
securerandom (>= 0.3)
|
||||||
@@ -74,39 +77,39 @@ GEM
|
|||||||
uri (>= 0.13.1)
|
uri (>= 0.13.1)
|
||||||
ast (2.4.3)
|
ast (2.4.3)
|
||||||
base64 (0.3.0)
|
base64 (0.3.0)
|
||||||
bcrypt (3.1.20)
|
bcrypt (3.1.21)
|
||||||
benchmark (0.4.1)
|
bigdecimal (4.0.1)
|
||||||
bigdecimal (3.3.0)
|
bootsnap (1.23.0)
|
||||||
bootsnap (1.18.6)
|
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
brakeman (7.1.0)
|
brakeman (8.0.2)
|
||||||
racc
|
racc
|
||||||
builder (3.3.0)
|
builder (3.3.0)
|
||||||
bullet (8.0.8)
|
bullet (8.1.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
uniform_notifier (~> 1.11)
|
uniform_notifier (~> 1.11)
|
||||||
bundler-audit (0.9.2)
|
bundler-audit (0.9.3)
|
||||||
bundler (>= 1.2.0, < 3)
|
bundler (>= 1.2.0)
|
||||||
thor (~> 1.0)
|
thor (~> 1.0)
|
||||||
cancancan (3.6.1)
|
cancancan (3.6.1)
|
||||||
concurrent-ruby (1.3.5)
|
chunky_png (1.4.0)
|
||||||
connection_pool (2.5.4)
|
concurrent-ruby (1.3.6)
|
||||||
|
connection_pool (3.0.2)
|
||||||
crass (1.0.6)
|
crass (1.0.6)
|
||||||
daemons (1.4.1)
|
daemons (1.4.1)
|
||||||
date (3.4.1)
|
date (3.5.1)
|
||||||
drb (2.2.3)
|
drb (2.2.3)
|
||||||
erb (5.0.3)
|
erb (6.0.1)
|
||||||
erubi (1.13.1)
|
erubi (1.13.1)
|
||||||
et-orbi (1.4.0)
|
et-orbi (1.4.0)
|
||||||
tzinfo
|
tzinfo
|
||||||
fugit (1.11.2)
|
fugit (1.12.1)
|
||||||
et-orbi (~> 1, >= 1.2.11)
|
et-orbi (~> 1.4)
|
||||||
raabro (~> 1.4)
|
raabro (~> 1.4)
|
||||||
globalid (1.3.0)
|
globalid (1.3.0)
|
||||||
activesupport (>= 6.1)
|
activesupport (>= 6.1)
|
||||||
i18n (1.14.7)
|
i18n (1.14.8)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
importmap-rails (2.2.2)
|
importmap-rails (2.2.3)
|
||||||
actionpack (>= 6.0.0)
|
actionpack (>= 6.0.0)
|
||||||
activesupport (>= 6.0.0)
|
activesupport (>= 6.0.0)
|
||||||
railties (>= 6.0.0)
|
railties (>= 6.0.0)
|
||||||
@@ -114,33 +117,36 @@ GEM
|
|||||||
influxdb-rails (1.0.3)
|
influxdb-rails (1.0.3)
|
||||||
influxdb (~> 0.6, >= 0.6.4)
|
influxdb (~> 0.6, >= 0.6.4)
|
||||||
railties (>= 5.0)
|
railties (>= 5.0)
|
||||||
io-console (0.8.1)
|
io-console (0.8.2)
|
||||||
irb (1.15.2)
|
irb (1.17.0)
|
||||||
pp (>= 0.6.0)
|
pp (>= 0.6.0)
|
||||||
|
prism (>= 1.3.0)
|
||||||
rdoc (>= 4.0.0)
|
rdoc (>= 4.0.0)
|
||||||
reline (>= 0.4.2)
|
reline (>= 0.4.2)
|
||||||
jbuilder (2.14.1)
|
jbuilder (2.14.1)
|
||||||
actionview (>= 7.0.0)
|
actionview (>= 7.0.0)
|
||||||
activesupport (>= 7.0.0)
|
activesupport (>= 7.0.0)
|
||||||
jquery-rails (4.6.0)
|
jquery-rails (4.6.1)
|
||||||
rails-dom-testing (>= 1, < 3)
|
rails-dom-testing (>= 1, < 3)
|
||||||
railties (>= 4.2.0)
|
railties (>= 4.2.0)
|
||||||
thor (>= 0.14, < 2.0)
|
thor (>= 0.14, < 2.0)
|
||||||
json (2.15.1)
|
json (2.18.1)
|
||||||
language_server-protocol (3.17.0.5)
|
language_server-protocol (3.17.0.5)
|
||||||
lint_roller (1.1.0)
|
lint_roller (1.1.0)
|
||||||
logger (1.7.0)
|
logger (1.7.0)
|
||||||
loofah (2.24.1)
|
loofah (2.25.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.12.0)
|
nokogiri (>= 1.12.0)
|
||||||
mail (2.8.1)
|
mail (2.9.0)
|
||||||
|
logger
|
||||||
mini_mime (>= 0.1.1)
|
mini_mime (>= 0.1.1)
|
||||||
net-imap
|
net-imap
|
||||||
net-pop
|
net-pop
|
||||||
net-smtp
|
net-smtp
|
||||||
marcel (1.1.0)
|
marcel (1.1.0)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
minitest (5.25.5)
|
minitest (6.0.1)
|
||||||
|
prism (~> 1.5)
|
||||||
mission_control-jobs (1.1.0)
|
mission_control-jobs (1.1.0)
|
||||||
actioncable (>= 7.1)
|
actioncable (>= 7.1)
|
||||||
actionpack (>= 7.1)
|
actionpack (>= 7.1)
|
||||||
@@ -151,12 +157,12 @@ GEM
|
|||||||
railties (>= 7.1)
|
railties (>= 7.1)
|
||||||
stimulus-rails
|
stimulus-rails
|
||||||
turbo-rails
|
turbo-rails
|
||||||
mocha (2.7.1)
|
mocha (3.0.2)
|
||||||
ruby2_keywords (>= 0.0.5)
|
ruby2_keywords (>= 0.0.5)
|
||||||
msgpack (1.8.0)
|
msgpack (1.8.0)
|
||||||
mysql2 (0.5.7)
|
mysql2 (0.5.7)
|
||||||
bigdecimal
|
bigdecimal
|
||||||
net-imap (0.5.12)
|
net-imap (0.6.3)
|
||||||
date
|
date
|
||||||
net-protocol
|
net-protocol
|
||||||
net-pop (0.1.2)
|
net-pop (0.1.2)
|
||||||
@@ -165,64 +171,64 @@ GEM
|
|||||||
timeout
|
timeout
|
||||||
net-smtp (0.5.1)
|
net-smtp (0.5.1)
|
||||||
net-protocol
|
net-protocol
|
||||||
nio4r (2.7.4)
|
nio4r (2.7.5)
|
||||||
nokogiri (1.18.10-aarch64-linux-gnu)
|
nokogiri (1.19.0-aarch64-linux-gnu)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.18.10-aarch64-linux-musl)
|
nokogiri (1.19.0-aarch64-linux-musl)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.18.10-arm-linux-gnu)
|
nokogiri (1.19.0-arm-linux-gnu)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.18.10-arm-linux-musl)
|
nokogiri (1.19.0-arm-linux-musl)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.18.10-arm64-darwin)
|
nokogiri (1.19.0-arm64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.18.10-x86_64-darwin)
|
nokogiri (1.19.0-x86_64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.18.10-x86_64-linux-gnu)
|
nokogiri (1.19.0-x86_64-linux-gnu)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.18.10-x86_64-linux-musl)
|
nokogiri (1.19.0-x86_64-linux-musl)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
parallel (1.27.0)
|
parallel (1.27.0)
|
||||||
parser (3.3.9.0)
|
parser (3.3.10.1)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
racc
|
racc
|
||||||
pp (0.6.3)
|
pp (0.6.3)
|
||||||
prettyprint
|
prettyprint
|
||||||
prettyprint (0.2.0)
|
prettyprint (0.2.0)
|
||||||
prism (1.5.1)
|
prism (1.9.0)
|
||||||
propshaft (1.3.1)
|
propshaft (1.3.1)
|
||||||
actionpack (>= 7.0.0)
|
actionpack (>= 7.0.0)
|
||||||
activesupport (>= 7.0.0)
|
activesupport (>= 7.0.0)
|
||||||
rack
|
rack
|
||||||
psych (5.2.6)
|
psych (5.3.1)
|
||||||
date
|
date
|
||||||
stringio
|
stringio
|
||||||
puma (7.0.4)
|
puma (7.2.0)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
raabro (1.4.0)
|
raabro (1.4.0)
|
||||||
racc (1.8.1)
|
racc (1.8.1)
|
||||||
rack (3.2.2)
|
rack (3.2.4)
|
||||||
rack-session (2.1.1)
|
rack-session (2.1.1)
|
||||||
base64 (>= 0.1.0)
|
base64 (>= 0.1.0)
|
||||||
rack (>= 3.0.0)
|
rack (>= 3.0.0)
|
||||||
rack-test (2.2.0)
|
rack-test (2.2.0)
|
||||||
rack (>= 1.3)
|
rack (>= 1.3)
|
||||||
rackup (2.2.1)
|
rackup (2.3.1)
|
||||||
rack (>= 3)
|
rack (>= 3)
|
||||||
rails (8.0.3)
|
rails (8.1.2)
|
||||||
actioncable (= 8.0.3)
|
actioncable (= 8.1.2)
|
||||||
actionmailbox (= 8.0.3)
|
actionmailbox (= 8.1.2)
|
||||||
actionmailer (= 8.0.3)
|
actionmailer (= 8.1.2)
|
||||||
actionpack (= 8.0.3)
|
actionpack (= 8.1.2)
|
||||||
actiontext (= 8.0.3)
|
actiontext (= 8.1.2)
|
||||||
actionview (= 8.0.3)
|
actionview (= 8.1.2)
|
||||||
activejob (= 8.0.3)
|
activejob (= 8.1.2)
|
||||||
activemodel (= 8.0.3)
|
activemodel (= 8.1.2)
|
||||||
activerecord (= 8.0.3)
|
activerecord (= 8.1.2)
|
||||||
activestorage (= 8.0.3)
|
activestorage (= 8.1.2)
|
||||||
activesupport (= 8.0.3)
|
activesupport (= 8.1.2)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 8.0.3)
|
railties (= 8.1.2)
|
||||||
rails-controller-testing (1.0.5)
|
rails-controller-testing (1.0.5)
|
||||||
actionpack (>= 5.0.1.rc1)
|
actionpack (>= 5.0.1.rc1)
|
||||||
actionview (>= 5.0.1.rc1)
|
actionview (>= 5.0.1.rc1)
|
||||||
@@ -239,9 +245,9 @@ GEM
|
|||||||
rails_stdout_logging
|
rails_stdout_logging
|
||||||
rails_serve_static_assets (0.0.5)
|
rails_serve_static_assets (0.0.5)
|
||||||
rails_stdout_logging (0.0.5)
|
rails_stdout_logging (0.0.5)
|
||||||
railties (8.0.3)
|
railties (8.1.2)
|
||||||
actionpack (= 8.0.3)
|
actionpack (= 8.1.2)
|
||||||
activesupport (= 8.0.3)
|
activesupport (= 8.1.2)
|
||||||
irb (~> 1.13)
|
irb (~> 1.13)
|
||||||
rackup (>= 1.0.0)
|
rackup (>= 1.0.0)
|
||||||
rake (>= 12.2)
|
rake (>= 12.2)
|
||||||
@@ -249,17 +255,21 @@ GEM
|
|||||||
tsort (>= 0.2)
|
tsort (>= 0.2)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
rake (13.3.0)
|
rake (13.3.1)
|
||||||
rb-readline (0.5.5)
|
rb-readline (0.5.5)
|
||||||
rdoc (6.15.0)
|
rdoc (7.2.0)
|
||||||
erb
|
erb
|
||||||
psych (>= 4.0.0)
|
psych (>= 4.0.0)
|
||||||
tsort
|
tsort
|
||||||
regexp_parser (2.11.3)
|
regexp_parser (2.11.3)
|
||||||
reline (0.6.2)
|
reline (0.6.3)
|
||||||
io-console (~> 0.5)
|
io-console (~> 0.5)
|
||||||
round_robin_tournament (0.1.2)
|
round_robin_tournament (0.1.2)
|
||||||
rubocop (1.81.1)
|
rqrcode (3.2.0)
|
||||||
|
chunky_png (~> 1.0)
|
||||||
|
rqrcode_core (~> 2.0)
|
||||||
|
rqrcode_core (2.1.0)
|
||||||
|
rubocop (1.84.2)
|
||||||
json (~> 2.3)
|
json (~> 2.3)
|
||||||
language_server-protocol (~> 3.17.0.2)
|
language_server-protocol (~> 3.17.0.2)
|
||||||
lint_roller (~> 1.1.0)
|
lint_roller (~> 1.1.0)
|
||||||
@@ -267,15 +277,15 @@ GEM
|
|||||||
parser (>= 3.3.0.2)
|
parser (>= 3.3.0.2)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
regexp_parser (>= 2.9.3, < 3.0)
|
regexp_parser (>= 2.9.3, < 3.0)
|
||||||
rubocop-ast (>= 1.47.1, < 2.0)
|
rubocop-ast (>= 1.49.0, < 2.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 2.4.0, < 4.0)
|
unicode-display_width (>= 2.4.0, < 4.0)
|
||||||
rubocop-ast (1.47.1)
|
rubocop-ast (1.49.0)
|
||||||
parser (>= 3.3.7.2)
|
parser (>= 3.3.7.2)
|
||||||
prism (~> 1.4)
|
prism (~> 1.7)
|
||||||
ruby-progressbar (1.13.0)
|
ruby-progressbar (1.13.0)
|
||||||
ruby2_keywords (0.0.5)
|
ruby2_keywords (0.0.5)
|
||||||
sdoc (2.6.4)
|
sdoc (2.6.5)
|
||||||
rdoc (>= 5.0)
|
rdoc (>= 5.0)
|
||||||
securerandom (0.4.1)
|
securerandom (0.4.1)
|
||||||
solid_cable (3.0.12)
|
solid_cable (3.0.12)
|
||||||
@@ -283,50 +293,50 @@ GEM
|
|||||||
activejob (>= 7.2)
|
activejob (>= 7.2)
|
||||||
activerecord (>= 7.2)
|
activerecord (>= 7.2)
|
||||||
railties (>= 7.2)
|
railties (>= 7.2)
|
||||||
solid_cache (1.0.7)
|
solid_cache (1.0.10)
|
||||||
activejob (>= 7.2)
|
activejob (>= 7.2)
|
||||||
activerecord (>= 7.2)
|
activerecord (>= 7.2)
|
||||||
railties (>= 7.2)
|
railties (>= 7.2)
|
||||||
solid_queue (1.2.1)
|
solid_queue (1.3.1)
|
||||||
activejob (>= 7.1)
|
activejob (>= 7.1)
|
||||||
activerecord (>= 7.1)
|
activerecord (>= 7.1)
|
||||||
concurrent-ruby (>= 1.3.1)
|
concurrent-ruby (>= 1.3.1)
|
||||||
fugit (~> 1.11.0)
|
fugit (~> 1.11)
|
||||||
railties (>= 7.1)
|
railties (>= 7.1)
|
||||||
thor (>= 1.3.1)
|
thor (>= 1.3.1)
|
||||||
spring (4.4.0)
|
spring (4.4.2)
|
||||||
sqlite3 (2.7.4-aarch64-linux-gnu)
|
sqlite3 (2.9.0-aarch64-linux-gnu)
|
||||||
sqlite3 (2.7.4-aarch64-linux-musl)
|
sqlite3 (2.9.0-aarch64-linux-musl)
|
||||||
sqlite3 (2.7.4-arm-linux-gnu)
|
sqlite3 (2.9.0-arm-linux-gnu)
|
||||||
sqlite3 (2.7.4-arm-linux-musl)
|
sqlite3 (2.9.0-arm-linux-musl)
|
||||||
sqlite3 (2.7.4-arm64-darwin)
|
sqlite3 (2.9.0-arm64-darwin)
|
||||||
sqlite3 (2.7.4-x86_64-darwin)
|
sqlite3 (2.9.0-x86_64-darwin)
|
||||||
sqlite3 (2.7.4-x86_64-linux-gnu)
|
sqlite3 (2.9.0-x86_64-linux-gnu)
|
||||||
sqlite3 (2.7.4-x86_64-linux-musl)
|
sqlite3 (2.9.0-x86_64-linux-musl)
|
||||||
stimulus-rails (1.3.4)
|
stimulus-rails (1.3.4)
|
||||||
railties (>= 6.0.0)
|
railties (>= 6.0.0)
|
||||||
stringio (3.1.7)
|
stringio (3.2.0)
|
||||||
thor (1.4.0)
|
thor (1.5.0)
|
||||||
timeout (0.4.3)
|
timeout (0.6.0)
|
||||||
tsort (0.2.0)
|
tsort (0.2.0)
|
||||||
turbo-rails (2.0.17)
|
turbo-rails (2.0.23)
|
||||||
actionpack (>= 7.1.0)
|
actionpack (>= 7.1.0)
|
||||||
railties (>= 7.1.0)
|
railties (>= 7.1.0)
|
||||||
tzinfo (2.0.6)
|
tzinfo (2.0.6)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
tzinfo-data (1.2025.2)
|
tzinfo-data (1.2025.3)
|
||||||
tzinfo (>= 1.0.0)
|
tzinfo (>= 1.0.0)
|
||||||
unicode-display_width (3.2.0)
|
unicode-display_width (3.2.0)
|
||||||
unicode-emoji (~> 4.1)
|
unicode-emoji (~> 4.1)
|
||||||
unicode-emoji (4.1.0)
|
unicode-emoji (4.2.0)
|
||||||
uniform_notifier (1.18.0)
|
uniform_notifier (1.18.0)
|
||||||
uri (1.0.4)
|
uri (1.1.1)
|
||||||
useragent (0.16.11)
|
useragent (0.16.11)
|
||||||
websocket-driver (0.8.0)
|
websocket-driver (0.8.0)
|
||||||
base64
|
base64
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
websocket-extensions (0.1.5)
|
websocket-extensions (0.1.5)
|
||||||
zeitwerk (2.7.3)
|
zeitwerk (2.7.4)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
aarch64-linux-gnu
|
aarch64-linux-gnu
|
||||||
@@ -355,12 +365,13 @@ DEPENDENCIES
|
|||||||
mysql2
|
mysql2
|
||||||
propshaft
|
propshaft
|
||||||
puma
|
puma
|
||||||
rails (= 8.0.3)
|
rails (= 8.1.2)
|
||||||
rails-controller-testing
|
rails-controller-testing
|
||||||
rails-html-sanitizer
|
rails-html-sanitizer
|
||||||
rails_12factor
|
rails_12factor
|
||||||
rb-readline
|
rb-readline
|
||||||
round_robin_tournament
|
round_robin_tournament
|
||||||
|
rqrcode
|
||||||
rubocop
|
rubocop
|
||||||
sdoc
|
sdoc
|
||||||
solid_cable
|
solid_cable
|
||||||
@@ -373,7 +384,7 @@ DEPENDENCIES
|
|||||||
tzinfo-data
|
tzinfo-data
|
||||||
|
|
||||||
RUBY VERSION
|
RUBY VERSION
|
||||||
ruby 3.2.0p0
|
ruby 4.0.1p0
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.6.9
|
4.0.3
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -7,8 +7,8 @@ This application is being created to run a wrestling tournament.
|
|||||||
**Public Production Url:** [https://wrestlingdev.com](https://wrestlingdev.com)
|
**Public Production Url:** [https://wrestlingdev.com](https://wrestlingdev.com)
|
||||||
|
|
||||||
**App Info**
|
**App Info**
|
||||||
* Ruby 3.2.0
|
* Ruby 4.0.1
|
||||||
* Rails 8.0.2
|
* Rails 8.1.2
|
||||||
* DB MySQL/MariaDB
|
* DB MySQL/MariaDB
|
||||||
* Solid Cache -> MySQL/MariaDB for html partial caching
|
* Solid Cache -> MySQL/MariaDB for html partial caching
|
||||||
* Solid Queue -> MySQL/MariaDB for background job processing
|
* Solid Queue -> MySQL/MariaDB for background job processing
|
||||||
@@ -34,11 +34,14 @@ In development environments, background jobs run inline (synchronously) by defau
|
|||||||
|
|
||||||
To run a single test file:
|
To run a single test file:
|
||||||
1. Get a shell with ruby and rails: `bash bin/rails-dev-run.sh wrestlingdev-development`
|
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`
|
2. `rake test TEST=test/models/match_test.rb` OR `rails test test/models/match_test.rb`
|
||||||
|
|
||||||
To run a single test inside a file:
|
To run a single test inside a file:
|
||||||
1. Get a shell with ruby and rails: `bash bin/rails-dev-run.sh wrestlingdev-development`
|
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/'"`
|
2. `rake test TEST=test/models/match_test.rb TESTOPTS="--name='/test_Match_should_not_be_valid_if_an_incorrect_win_type_is_given/'"` OR `rails test test/models/match_test.rb --name=/test_Match_should_not_be_valid_if_an_incorrect_win_type_is_given/`
|
||||||
|
|
||||||
|
To run tests in verbose mode (outputs the time for each test file and the test file name)
|
||||||
|
`rails test -v`
|
||||||
|
|
||||||
## Develop with rvm
|
## Develop with rvm
|
||||||
With rvm installed, run `rvm install ruby-3.2.0`
|
With rvm installed, run `rvm install ruby-3.2.0`
|
||||||
@@ -149,7 +152,7 @@ SolidQueue plugin enabled in Puma
|
|||||||
```
|
```
|
||||||
|
|
||||||
I have deployed Mission Control as a UI for SolidQueue. The uri for mission control is `/jobs`.
|
I have deployed Mission Control as a UI for SolidQueue. The uri for mission control is `/jobs`.
|
||||||
For the development environment, the user/password is dev/secret. For the production environment, it is defined by environment variables.
|
For the development environment, the user/password is dev/secret. For the production environment, it is defined by environment variables WRESTLINGDEV_MISSION_CONTROL_USER/WRESTLINGDEV_MISSION_CONTROL_PASSWORD. You can see this in `config/environments/production.rb` and `config/environments/development.rb`.
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import "@hotwired/turbo-rails";
|
|||||||
import { createConsumer } from "@rails/actioncable"; // Import createConsumer directly
|
import { createConsumer } from "@rails/actioncable"; // Import createConsumer directly
|
||||||
import "jquery";
|
import "jquery";
|
||||||
import "bootstrap";
|
import "bootstrap";
|
||||||
import "datatables.net";
|
|
||||||
|
|
||||||
// Stimulus setup
|
// Stimulus setup
|
||||||
import { Application } from "@hotwired/stimulus";
|
import { Application } from "@hotwired/stimulus";
|
||||||
@@ -20,12 +19,14 @@ import WrestlerColorController from "controllers/wrestler_color_controller";
|
|||||||
import MatchScoreController from "controllers/match_score_controller";
|
import MatchScoreController from "controllers/match_score_controller";
|
||||||
import MatchDataController from "controllers/match_data_controller";
|
import MatchDataController from "controllers/match_data_controller";
|
||||||
import MatchSpectateController from "controllers/match_spectate_controller";
|
import MatchSpectateController from "controllers/match_spectate_controller";
|
||||||
|
import UpMatchesConnectionController from "controllers/up_matches_connection_controller";
|
||||||
|
|
||||||
// Register controllers
|
// Register controllers
|
||||||
application.register("wrestler-color", WrestlerColorController);
|
application.register("wrestler-color", WrestlerColorController);
|
||||||
application.register("match-score", MatchScoreController);
|
application.register("match-score", MatchScoreController);
|
||||||
application.register("match-data", MatchDataController);
|
application.register("match-data", MatchDataController);
|
||||||
application.register("match-spectate", MatchSpectateController);
|
application.register("match-spectate", MatchSpectateController);
|
||||||
|
application.register("up-matches-connection", UpMatchesConnectionController);
|
||||||
|
|
||||||
// Your existing Action Cable consumer setup
|
// Your existing Action Cable consumer setup
|
||||||
(function() {
|
(function() {
|
||||||
@@ -39,9 +40,9 @@ application.register("match-spectate", MatchSpectateController);
|
|||||||
}
|
}
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
|
||||||
console.log("Propshaft/Importmap application.js initialized with jQuery, Bootstrap, Stimulus, and DataTables.");
|
console.log("Propshaft/Importmap application.js initialized with jQuery, Bootstrap, and Stimulus.");
|
||||||
|
|
||||||
// If you have custom JavaScript files in app/javascript/ that were previously
|
// If you have custom JavaScript files in app/javascript/ that were previously
|
||||||
// handled by Sprockets `require_tree`, you'll need to import them here explicitly.
|
// handled by Sprockets `require_tree`, you'll need to import them here explicitly.
|
||||||
// For example:
|
// For example:
|
||||||
// import "./my_custom_logic";
|
// import "./my_custom_logic";
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ export default class extends Controller {
|
|||||||
|
|
||||||
connect() {
|
connect() {
|
||||||
console.log("Match data controller connected")
|
console.log("Match data controller connected")
|
||||||
|
this.isConnected = false
|
||||||
|
this.pendingLocalSync = { w1: false, w2: false }
|
||||||
|
|
||||||
this.w1 = {
|
this.w1 = {
|
||||||
name: "w1",
|
name: "w1",
|
||||||
@@ -69,6 +71,7 @@ export default class extends Controller {
|
|||||||
wrestler.updated_at = new Date().toISOString()
|
wrestler.updated_at = new Date().toISOString()
|
||||||
this.updateHtmlValues()
|
this.updateHtmlValues()
|
||||||
this.saveToLocalStorage(wrestler)
|
this.saveToLocalStorage(wrestler)
|
||||||
|
if (!this.isConnected) this.pendingLocalSync[wrestler.name] = true
|
||||||
|
|
||||||
// Send the update via Action Cable if subscribed
|
// Send the update via Action Cable if subscribed
|
||||||
if (this.matchSubscription) {
|
if (this.matchSubscription) {
|
||||||
@@ -109,6 +112,7 @@ export default class extends Controller {
|
|||||||
// Update the internal JS object
|
// Update the internal JS object
|
||||||
wrestler.stats = newValue
|
wrestler.stats = newValue
|
||||||
wrestler.updated_at = new Date().toISOString()
|
wrestler.updated_at = new Date().toISOString()
|
||||||
|
if (!this.isConnected) this.pendingLocalSync[wrestler.name] = true
|
||||||
|
|
||||||
// Save to localStorage
|
// Save to localStorage
|
||||||
this.saveToLocalStorage(wrestler)
|
this.saveToLocalStorage(wrestler)
|
||||||
@@ -334,15 +338,18 @@ export default class extends Controller {
|
|||||||
{
|
{
|
||||||
connected: () => {
|
connected: () => {
|
||||||
console.log(`[Stats AC] Connected to MatchStatsChannel for match ID: ${matchId}`)
|
console.log(`[Stats AC] Connected to MatchStatsChannel for match ID: ${matchId}`)
|
||||||
|
this.isConnected = true
|
||||||
if (this.statusIndicatorTarget) {
|
if (this.statusIndicatorTarget) {
|
||||||
this.statusIndicatorTarget.innerText = "Connected: Stats will update in real-time."
|
this.statusIndicatorTarget.innerText = "Connected: Stats will update in real-time."
|
||||||
this.statusIndicatorTarget.classList.remove('alert-info', 'alert-warning', 'alert-danger')
|
this.statusIndicatorTarget.classList.remove('alert-info', 'alert-warning', 'alert-danger')
|
||||||
this.statusIndicatorTarget.classList.add('alert-success')
|
this.statusIndicatorTarget.classList.add('alert-success')
|
||||||
}
|
}
|
||||||
|
this.sendCurrentStatsOnReconnect()
|
||||||
},
|
},
|
||||||
|
|
||||||
disconnected: () => {
|
disconnected: () => {
|
||||||
console.log(`[Stats AC] Disconnected from MatchStatsChannel`)
|
console.log(`[Stats AC] Disconnected from MatchStatsChannel`)
|
||||||
|
this.isConnected = false
|
||||||
if (this.statusIndicatorTarget) {
|
if (this.statusIndicatorTarget) {
|
||||||
this.statusIndicatorTarget.innerText = "Disconnected: Stats updates paused."
|
this.statusIndicatorTarget.innerText = "Disconnected: Stats updates paused."
|
||||||
this.statusIndicatorTarget.classList.remove('alert-info', 'alert-success', 'alert-danger')
|
this.statusIndicatorTarget.classList.remove('alert-info', 'alert-success', 'alert-danger')
|
||||||
@@ -356,15 +363,25 @@ export default class extends Controller {
|
|||||||
// Update w1 stats
|
// Update w1 stats
|
||||||
if (data.w1_stat !== undefined && this.w1StatTarget) {
|
if (data.w1_stat !== undefined && this.w1StatTarget) {
|
||||||
console.log(`[Stats AC] Updating w1_stat: ${data.w1_stat.substring(0, 30)}...`)
|
console.log(`[Stats AC] Updating w1_stat: ${data.w1_stat.substring(0, 30)}...`)
|
||||||
this.w1.stats = data.w1_stat
|
if (!this.pendingLocalSync.w1 || data.w1_stat === this.w1.stats) {
|
||||||
this.w1StatTarget.value = data.w1_stat
|
this.w1.stats = data.w1_stat
|
||||||
|
this.w1StatTarget.value = data.w1_stat
|
||||||
|
this.pendingLocalSync.w1 = false
|
||||||
|
} else {
|
||||||
|
console.log('[Stats AC] Skipping w1_stat overwrite due to pending local changes.')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update w2 stats
|
// Update w2 stats
|
||||||
if (data.w2_stat !== undefined && this.w2StatTarget) {
|
if (data.w2_stat !== undefined && this.w2StatTarget) {
|
||||||
console.log(`[Stats AC] Updating w2_stat: ${data.w2_stat.substring(0, 30)}...`)
|
console.log(`[Stats AC] Updating w2_stat: ${data.w2_stat.substring(0, 30)}...`)
|
||||||
this.w2.stats = data.w2_stat
|
if (!this.pendingLocalSync.w2 || data.w2_stat === this.w2.stats) {
|
||||||
this.w2StatTarget.value = data.w2_stat
|
this.w2.stats = data.w2_stat
|
||||||
|
this.w2StatTarget.value = data.w2_stat
|
||||||
|
this.pendingLocalSync.w2 = false
|
||||||
|
} else {
|
||||||
|
console.log('[Stats AC] Skipping w2_stat overwrite due to pending local changes.')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -381,4 +398,23 @@ export default class extends Controller {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
sendCurrentStatsOnReconnect() {
|
||||||
|
if (!this.matchSubscription) return
|
||||||
|
const payload = {}
|
||||||
|
if (typeof this.w1?.stats === 'string' && this.w1.stats.length > 0) {
|
||||||
|
payload.new_w1_stat = this.w1.stats
|
||||||
|
this.pendingLocalSync.w1 = true
|
||||||
|
}
|
||||||
|
if (typeof this.w2?.stats === 'string' && this.w2.stats.length > 0) {
|
||||||
|
payload.new_w2_stat = this.w2.stats
|
||||||
|
this.pendingLocalSync.w2 = true
|
||||||
|
}
|
||||||
|
if (Object.keys(payload).length > 0) {
|
||||||
|
console.log('[ActionCable] Reconnect sync: sending current stats payload:', payload)
|
||||||
|
this.matchSubscription.perform('send_stat', payload)
|
||||||
|
} else {
|
||||||
|
console.log('[ActionCable] Reconnect sync: no local stats to send.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -76,6 +76,11 @@ export default class extends Controller {
|
|||||||
this.statusIndicatorTarget.classList.remove('alert-danger', 'alert-secondary', 'text-danger', 'text-dark')
|
this.statusIndicatorTarget.classList.remove('alert-danger', 'alert-secondary', 'text-danger', 'text-dark')
|
||||||
this.statusIndicatorTarget.classList.add('alert-success')
|
this.statusIndicatorTarget.classList.add('alert-success')
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
this.matchSubscription.perform('request_sync')
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[Spectator AC] request_sync perform failed:', e)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
disconnected: () => {
|
disconnected: () => {
|
||||||
console.log(`[Spectator AC Callback] Disconnected: ${matchId}`)
|
console.log(`[Spectator AC Callback] Disconnected: ${matchId}`)
|
||||||
@@ -131,4 +136,4 @@ export default class extends Controller {
|
|||||||
this.finishedTarget.textContent = data.finished ? 'Yes' : 'No'
|
this.finishedTarget.textContent = data.finished ? 'Yes' : 'No'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import { Controller } from "@hotwired/stimulus"
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
static targets = ["stream", "statusIndicator"]
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
this.setupSubscription()
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
this.cleanupSubscription()
|
||||||
|
}
|
||||||
|
|
||||||
|
setupSubscription() {
|
||||||
|
this.cleanupSubscription()
|
||||||
|
this.setStatus("Connecting to server for real-time bout board updates...", "info")
|
||||||
|
|
||||||
|
if (!this.hasStreamTarget) {
|
||||||
|
this.setStatus("Error: Stream source not found.", "danger")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const signedStreamName = this.streamTarget.getAttribute("signed-stream-name")
|
||||||
|
if (!signedStreamName) {
|
||||||
|
this.setStatus("Error: Invalid stream source.", "danger")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!window.App || !window.App.cable) {
|
||||||
|
this.setStatus("Error: WebSockets unavailable. Bout board won't update in real-time. Refresh the page to update.", "danger")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.subscription = App.cable.subscriptions.create(
|
||||||
|
{
|
||||||
|
channel: "Turbo::StreamsChannel",
|
||||||
|
signed_stream_name: signedStreamName
|
||||||
|
},
|
||||||
|
{
|
||||||
|
connected: () => {
|
||||||
|
this.setStatus("Connected: Bout board updating in real-time.", "success")
|
||||||
|
},
|
||||||
|
disconnected: () => {
|
||||||
|
this.setStatus("Disconnected: Live bout board updates paused.", "warning")
|
||||||
|
},
|
||||||
|
rejected: () => {
|
||||||
|
this.setStatus("Error: Live bout board connection rejected.", "danger")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanupSubscription() {
|
||||||
|
if (!this.subscription) return
|
||||||
|
this.subscription.unsubscribe()
|
||||||
|
this.subscription = null
|
||||||
|
}
|
||||||
|
|
||||||
|
setStatus(message, type) {
|
||||||
|
if (!this.hasStatusIndicatorTarget) return
|
||||||
|
|
||||||
|
this.statusIndicatorTarget.innerText = message
|
||||||
|
this.statusIndicatorTarget.classList.remove("alert-secondary", "alert-info", "alert-success", "alert-warning", "alert-danger")
|
||||||
|
|
||||||
|
if (type === "success") this.statusIndicatorTarget.classList.add("alert-success")
|
||||||
|
else if (type === "warning") this.statusIndicatorTarget.classList.add("alert-warning")
|
||||||
|
else if (type === "danger") this.statusIndicatorTarget.classList.add("alert-danger")
|
||||||
|
else this.statusIndicatorTarget.classList.add("alert-info")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,4 +60,29 @@ class MatchChannel < ApplicationCable::Channel
|
|||||||
Rails.logger.info "[MatchChannel] No new stat data provided in send_stat for match #{@match.id}, not updating DB or broadcasting."
|
Rails.logger.info "[MatchChannel] No new stat data provided in send_stat for match #{@match.id}, not updating DB or broadcasting."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Called when client wants the latest stats immediately after reconnect
|
||||||
|
def request_sync
|
||||||
|
unless @match
|
||||||
|
Rails.logger.error "[MatchChannel] Error: request_sync called but @match is nil. Client params on sub: #{params[:match_id]}"
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
w1_stat: @match.w1_stat,
|
||||||
|
w2_stat: @match.w2_stat,
|
||||||
|
score: @match.score,
|
||||||
|
win_type: @match.win_type,
|
||||||
|
winner_name: @match.winner&.name,
|
||||||
|
winner_id: @match.winner_id,
|
||||||
|
finished: @match.finished
|
||||||
|
}.compact
|
||||||
|
|
||||||
|
if payload.present?
|
||||||
|
Rails.logger.info "[MatchChannel] request_sync transmit for match #{@match.id} with payload: #{payload.inspect}"
|
||||||
|
transmit(payload)
|
||||||
|
else
|
||||||
|
Rails.logger.info "[MatchChannel] request_sync payload empty for match #{@match.id}, not transmitting."
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ class MatAssignmentRulesController < ApplicationController
|
|||||||
before_action :set_mat_assignment_rule, only: [:edit, :update, :destroy]
|
before_action :set_mat_assignment_rule, only: [:edit, :update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@mat_assignment_rules = @tournament.mat_assignment_rules
|
@mat_assignment_rules = @tournament.mat_assignment_rules.includes(:mat)
|
||||||
@weights_by_id = @tournament.weights.index_by(&:id) # For quick lookup
|
@weights_by_id = @tournament.weights.index_by(&:id) # For quick lookup
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
class MatchesController < ApplicationController
|
class MatchesController < ApplicationController
|
||||||
before_action :set_match, only: [:show, :edit, :update, :stat, :spectate]
|
before_action :set_match, only: [:show, :edit, :update, :stat, :spectate, :edit_assignment, :update_assignment]
|
||||||
before_action :check_access, only: [:edit,:update, :stat]
|
before_action :check_access, only: [:edit, :update, :stat, :edit_assignment, :update_assignment]
|
||||||
|
|
||||||
# GET /matches/1
|
# GET /matches/1
|
||||||
# GET /matches/1.json
|
# GET /matches/1.json
|
||||||
@@ -21,7 +21,7 @@ class MatchesController < ApplicationController
|
|||||||
session[:return_path] = "/tournaments/#{@match.tournament.id}/matches"
|
session[:return_path] = "/tournaments/#{@match.tournament.id}/matches"
|
||||||
end
|
end
|
||||||
|
|
||||||
def stat
|
def stat
|
||||||
# @show_next_bout_button = false
|
# @show_next_bout_button = false
|
||||||
if params[:match]
|
if params[:match]
|
||||||
@match = Match.where(:id => params[:match]).includes(:wrestlers).first
|
@match = Match.where(:id => params[:match]).includes(:wrestlers).first
|
||||||
@@ -50,8 +50,21 @@ class MatchesController < ApplicationController
|
|||||||
end
|
end
|
||||||
@tournament = @match.tournament
|
@tournament = @match.tournament
|
||||||
end
|
end
|
||||||
session[:return_path] = "/tournaments/#{@tournament.id}/matches"
|
if @match&.mat
|
||||||
session[:error_return_path] = "/matches/#{@match.id}/stat"
|
@mat = @match.mat
|
||||||
|
queue_position = @mat.queue_position_for_match(@match)
|
||||||
|
@next_match = queue_position == 1 ? @mat.queue2_match : nil
|
||||||
|
@show_next_bout_button = queue_position == 1
|
||||||
|
if request.referer&.include?("/tournaments/#{@tournament.id}/matches")
|
||||||
|
session[:return_path] = "/tournaments/#{@tournament.id}/matches"
|
||||||
|
else
|
||||||
|
session[:return_path] = mat_path(@mat)
|
||||||
|
end
|
||||||
|
session[:error_return_path] = "/matches/#{@match.id}/stat"
|
||||||
|
else
|
||||||
|
session[:return_path] = "/tournaments/#{@tournament.id}/matches"
|
||||||
|
session[:error_return_path] = "/matches/#{@match.id}/stat"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET /matches/:id/spectate
|
# GET /matches/:id/spectate
|
||||||
@@ -71,6 +84,49 @@ class MatchesController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# GET /matches/1/edit_assignment
|
||||||
|
def edit_assignment
|
||||||
|
@tournament = @match.tournament
|
||||||
|
@mats = @tournament.mats.sort_by(&:name)
|
||||||
|
@current_mat = @match.mat
|
||||||
|
@current_queue_position = @current_mat&.queue_position_for_match(@match)
|
||||||
|
session[:return_path] = "/tournaments/#{@tournament.id}/matches"
|
||||||
|
end
|
||||||
|
|
||||||
|
# PATCH /matches/1/update_assignment
|
||||||
|
def update_assignment
|
||||||
|
@tournament = @match.tournament
|
||||||
|
mat_id = params.dig(:match, :mat_id)
|
||||||
|
queue_position = params.dig(:match, :queue_position)
|
||||||
|
|
||||||
|
if mat_id.blank?
|
||||||
|
Mat.where("queue1 = :match_id OR queue2 = :match_id OR queue3 = :match_id OR queue4 = :match_id", match_id: @match.id)
|
||||||
|
.find_each { |mat| mat.remove_match_from_queue_and_collapse!(@match.id) }
|
||||||
|
@match.update(mat_id: nil)
|
||||||
|
redirect_to session.delete(:return_path) || "/tournaments/#{@tournament.id}/matches", notice: "Match assignment cleared."
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if queue_position.blank?
|
||||||
|
redirect_to edit_assignment_match_path(@match), alert: "Queue position is required when selecting a mat."
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
unless %w[1 2 3 4].include?(queue_position.to_s)
|
||||||
|
redirect_to edit_assignment_match_path(@match), alert: "Queue position must be between 1 and 4."
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
mat = @tournament.mats.find_by(id: mat_id)
|
||||||
|
unless mat
|
||||||
|
redirect_to edit_assignment_match_path(@match), alert: "Selected mat was not found."
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
mat.assign_match_to_queue!(@match, queue_position)
|
||||||
|
redirect_to session.delete(:return_path) || "/tournaments/#{@tournament.id}/matches", notice: "Match assignment updated."
|
||||||
|
end
|
||||||
|
|
||||||
# PATCH/PUT /matches/1
|
# PATCH/PUT /matches/1
|
||||||
# PATCH/PUT /matches/1.json
|
# PATCH/PUT /matches/1.json
|
||||||
def update
|
def update
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
class MatsController < ApplicationController
|
class MatsController < ApplicationController
|
||||||
before_action :set_mat, only: [:show, :edit, :update, :destroy, :assign_next_match]
|
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_access, only: [:new,:create,:update,:destroy,:edit,:show, :assign_next_match]
|
||||||
before_action :check_for_matches, only: [:show]
|
|
||||||
|
|
||||||
# GET /mats/1
|
# GET /mats/1
|
||||||
# GET /mats/1.json
|
# GET /mats/1.json
|
||||||
def show
|
def show
|
||||||
bout_number_param = params[:bout_number] # Read the bout_number from the URL params
|
bout_number_param = params[:bout_number]
|
||||||
|
@queue_matches = @mat.queue_matches
|
||||||
if bout_number_param
|
@match = if bout_number_param
|
||||||
@show_next_bout_button = false
|
@queue_matches.compact.find { |m| m.bout_number == bout_number_param.to_i }
|
||||||
@match = @mat.unfinished_matches.find { |m| m.bout_number == bout_number_param.to_i }
|
|
||||||
else
|
else
|
||||||
@show_next_bout_button = true
|
@queue_matches[0]
|
||||||
@match = @mat.unfinished_matches.first
|
|
||||||
end
|
end
|
||||||
|
# If a requested bout is no longer queued, fall back to queue1.
|
||||||
@next_match = @mat.unfinished_matches.second # Second unfinished match on the mat
|
@match ||= @queue_matches[0]
|
||||||
|
@next_match = @queue_matches[1]
|
||||||
|
@show_next_bout_button = false
|
||||||
|
|
||||||
@wrestlers = []
|
@wrestlers = []
|
||||||
if @match
|
if @match
|
||||||
@@ -82,8 +81,8 @@ class MatsController < ApplicationController
|
|||||||
def assign_next_match
|
def assign_next_match
|
||||||
@tournament = @mat.tournament_id
|
@tournament = @mat.tournament_id
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @mat.assign_next_match
|
if @mat.advance_queue!
|
||||||
format.html { redirect_to "/tournaments/#{@mat.tournament.id}", notice: "Next Match on Mat #{@mat.name} successfully completed." }
|
format.html { redirect_to "/tournaments/#{@mat.tournament.id}", notice: "Mat #{@mat.name} queue advanced." }
|
||||||
format.json { head :no_content }
|
format.json { head :no_content }
|
||||||
else
|
else
|
||||||
format.html { redirect_to "/tournaments/#{@mat.tournament.id}", alert: "There was an error." }
|
format.html { redirect_to "/tournaments/#{@mat.tournament.id}", alert: "There was an error." }
|
||||||
@@ -142,11 +141,4 @@ class MatsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def check_for_matches
|
|
||||||
if @mat
|
|
||||||
if @mat.tournament.matches.empty?
|
|
||||||
redirect_to "/tournaments/#{@tournament.id}/no_matches"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
class StaticPagesController < ApplicationController
|
class StaticPagesController < ApplicationController
|
||||||
|
|
||||||
def my_tournaments
|
def my_tournaments
|
||||||
tournaments_created = current_user.tournaments
|
tournaments_created = current_user.tournaments.to_a
|
||||||
tournaments_delegated = current_user.delegated_tournaments
|
tournaments_delegated = current_user.delegated_tournaments.to_a
|
||||||
all_tournaments = tournaments_created + tournaments_delegated
|
all_tournaments = tournaments_created + tournaments_delegated
|
||||||
@tournaments = all_tournaments.sort_by{|t| t.days_until_start}
|
@tournaments = all_tournaments.sort_by{|t| t.days_until_start}
|
||||||
@schools = current_user.delegated_schools
|
@schools = current_user.delegated_schools.includes(:tournament)
|
||||||
end
|
end
|
||||||
|
|
||||||
def not_allowed
|
def not_allowed
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
class TournamentsController < ApplicationController
|
class TournamentsController < ApplicationController
|
||||||
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 :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,:qrcode]
|
||||||
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_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,:qrcode]
|
||||||
before_action :check_access_destroy, only: [:destroy,:delegate,:remove_delegate]
|
before_action :check_access_destroy, only: [:destroy,:delegate,:remove_delegate]
|
||||||
before_action :check_tournament_errors, only: [:generate_matches]
|
before_action :check_tournament_errors, only: [:generate_matches]
|
||||||
before_action :check_for_matches, only: [:all_results,:up_matches,:bracket,:all_brackets]
|
before_action :check_for_matches, only: [:all_results,:bracket,:all_brackets]
|
||||||
before_action :check_access_read, 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
|
def weigh_in_sheet
|
||||||
|
@schools = @tournament.schools.includes(wrestlers: :weight)
|
||||||
end
|
end
|
||||||
|
|
||||||
def calculate_team_scores
|
def calculate_team_scores
|
||||||
@@ -92,12 +92,9 @@ class TournamentsController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@users_delegates = []
|
@users_delegates = SchoolDelegate.includes(:user, :school)
|
||||||
@tournament.schools.each do |s|
|
.joins(:school)
|
||||||
s.delegates.each do |d|
|
.where(schools: { tournament_id: @tournament.id })
|
||||||
@users_delegates << d
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def delegate
|
def delegate
|
||||||
@@ -115,11 +112,63 @@ class TournamentsController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@users_delegates = @tournament.delegates
|
@users_delegates = @tournament.delegates.includes(:user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def matches
|
def matches
|
||||||
@matches = @tournament.matches.includes(:wrestlers,:schools).sort_by{|m| m.bout_number}
|
per_page = 50
|
||||||
|
@page = params[:page].to_i > 0 ? params[:page].to_i : 1
|
||||||
|
offset = (@page - 1) * per_page
|
||||||
|
matches_table = Match.arel_table
|
||||||
|
|
||||||
|
matches_scope = @tournament.matches.order(:bout_number)
|
||||||
|
|
||||||
|
if params[:search].present?
|
||||||
|
wrestlers_table = Wrestler.arel_table
|
||||||
|
schools_table = School.arel_table
|
||||||
|
search_terms = params[:search].downcase.split
|
||||||
|
|
||||||
|
search_terms.each do |term|
|
||||||
|
escaped_term = ActiveRecord::Base.sanitize_sql_like(term)
|
||||||
|
pattern = "%#{escaped_term}%"
|
||||||
|
|
||||||
|
matching_wrestler_ids = Wrestler
|
||||||
|
.joins(:weight)
|
||||||
|
.left_outer_joins(:school)
|
||||||
|
.where(weights: { tournament_id: @tournament.id })
|
||||||
|
.where(
|
||||||
|
wrestlers_table[:name].matches(pattern)
|
||||||
|
.or(schools_table[:name].matches(pattern))
|
||||||
|
)
|
||||||
|
.distinct
|
||||||
|
.select(:id)
|
||||||
|
|
||||||
|
term_scope = @tournament.matches.where(w1: matching_wrestler_ids)
|
||||||
|
.or(@tournament.matches.where(w2: matching_wrestler_ids))
|
||||||
|
|
||||||
|
if term.match?(/\A\d+\z/)
|
||||||
|
term_scope = term_scope.or(@tournament.matches.where(bout_number: term.to_i))
|
||||||
|
end
|
||||||
|
|
||||||
|
matches_scope = matches_scope.where(id: term_scope.select(:id))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@total_count = matches_scope.count
|
||||||
|
@total_pages = (@total_count / per_page.to_f).ceil
|
||||||
|
@per_page = per_page
|
||||||
|
|
||||||
|
loser1_not_bye = matches_table[:loser1_name].not_eq("BYE").or(matches_table[:loser1_name].eq(nil))
|
||||||
|
loser2_not_bye = matches_table[:loser2_name].not_eq("BYE").or(matches_table[:loser2_name].eq(nil))
|
||||||
|
|
||||||
|
non_bye_scope = matches_scope.where(loser1_not_bye).where(loser2_not_bye)
|
||||||
|
@matches_without_byes_count = non_bye_scope.count
|
||||||
|
@unfinished_matches_without_byes_count = non_bye_scope.where(finished: [nil, 0]).count
|
||||||
|
|
||||||
|
@matches = matches_scope
|
||||||
|
.includes({ wrestler1: :school }, { wrestler2: :school }, { weight: :matches })
|
||||||
|
.offset(offset)
|
||||||
|
.limit(per_page)
|
||||||
if @match
|
if @match
|
||||||
@w1 = @match.wrestler1
|
@w1 = @match.wrestler1
|
||||||
@w2 = @match.wrestler2
|
@w2 = @match.wrestler2
|
||||||
@@ -129,10 +178,18 @@ class TournamentsController < ApplicationController
|
|||||||
|
|
||||||
def weigh_in_weight
|
def weigh_in_weight
|
||||||
if params[:wrestler]
|
if params[:wrestler]
|
||||||
Wrestler.update(params[:wrestler].keys, params[:wrestler].values)
|
sanitized_wrestlers = params.require(:wrestler).to_unsafe_h.each_with_object({}) do |(wrestler_id, attributes), result|
|
||||||
|
permitted = ActionController::Parameters.new(attributes).permit(:offical_weight)
|
||||||
|
result[wrestler_id] = permitted
|
||||||
|
end
|
||||||
|
Wrestler.update(sanitized_wrestlers.keys, sanitized_wrestlers.values) if sanitized_wrestlers.present?
|
||||||
|
redirect_to "/tournaments/#{@tournament.id}/weigh_in/#{params[:weight]}", notice: "Weights were successfully recorded."
|
||||||
|
return
|
||||||
end
|
end
|
||||||
if params[:weight]
|
if params[:weight]
|
||||||
@weight = Weight.where(:id => params[:weight]).includes(:wrestlers).first
|
@weight = Weight.where(id: params[:weight])
|
||||||
|
.includes(wrestlers: [:school, :weight])
|
||||||
|
.first
|
||||||
@tournament_id = @tournament.id
|
@tournament_id = @tournament.id
|
||||||
@tournament_name = @tournament.name
|
@tournament_name = @tournament.name
|
||||||
@weights = @tournament.weights
|
@weights = @tournament.weights
|
||||||
@@ -159,8 +216,11 @@ class TournamentsController < ApplicationController
|
|||||||
def all_brackets
|
def all_brackets
|
||||||
@schools = @tournament.schools
|
@schools = @tournament.schools
|
||||||
@schools = @schools.sort_by{|s| s.page_score_string}.reverse!
|
@schools = @schools.sort_by{|s| s.page_score_string}.reverse!
|
||||||
@matches = @tournament.matches.includes(:wrestlers,:schools)
|
@weights = @tournament.weights.includes(:matches, wrestlers: :school)
|
||||||
@weights = @tournament.weights.includes(:matches,:wrestlers)
|
all_matches = @tournament.matches.includes(:weight, { wrestler1: :school }, { wrestler2: :school })
|
||||||
|
all_wrestlers = @tournament.wrestlers.includes(:school, :weight)
|
||||||
|
@matches_by_weight_id = all_matches.group_by(&:weight_id)
|
||||||
|
@wrestlers_by_weight_id = all_wrestlers.group_by(&:weight_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def bracket
|
def bracket
|
||||||
@@ -196,27 +256,37 @@ class TournamentsController < ApplicationController
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def qrcode
|
||||||
|
@tournament_url = tournament_url(@tournament)
|
||||||
|
@qrcode = RQRCode::QRCode.new(@tournament_url)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
def up_matches
|
def up_matches
|
||||||
# .where.not(loser1_name: 'BYE') won't return matches with NULL loser1_name
|
@matches = @tournament.up_matches_unassigned_matches
|
||||||
# so I was only getting back matches with Loser of BOUT_NUMBER
|
@mats = @tournament.up_matches_mats
|
||||||
@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
|
end
|
||||||
|
|
||||||
def bout_sheets
|
def bout_sheets
|
||||||
|
matches_scope = @tournament.matches
|
||||||
|
.where("loser1_name != ? OR loser1_name IS NULL", "BYE")
|
||||||
|
.where("loser2_name != ? OR loser2_name IS NULL", "BYE")
|
||||||
|
|
||||||
if params[:round]
|
if params[:round]
|
||||||
round = params[:round]
|
round = params[:round]
|
||||||
if round != "All"
|
if round != "All"
|
||||||
@matches = @tournament.matches.where("round = ?",round).sort_by{|match| match.bout_number}
|
@matches = matches_scope
|
||||||
|
.where(round: round)
|
||||||
|
.includes(:weight)
|
||||||
|
.order(:bout_number)
|
||||||
else
|
else
|
||||||
@matches = @tournament.matches.sort_by{|match| match.bout_number}
|
@matches = matches_scope
|
||||||
|
.includes(:weight)
|
||||||
|
.order(:bout_number)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
wrestler_ids = @matches.flat_map { |match| [match.w1, match.w2] }.compact.uniq
|
||||||
|
@wrestlers_by_id = Wrestler.includes(:school).where(id: wrestler_ids).index_by(&:id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,20 @@
|
|||||||
module ApplicationHelper
|
module ApplicationHelper
|
||||||
|
def hide_ads?
|
||||||
|
case controller_name
|
||||||
|
when "schools"
|
||||||
|
action_name == "show" && (user_signed_in? || school_permission_key_present?)
|
||||||
|
when "wrestlers"
|
||||||
|
%w[new edit].include?(action_name) && (user_signed_in? || school_permission_key_present?)
|
||||||
|
when "mats"
|
||||||
|
action_name == "show" && user_signed_in?
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def school_permission_key_present?
|
||||||
|
@school_permission_key.present? ||
|
||||||
|
params[:school_permission_key].present? ||
|
||||||
|
params.dig(:school, :school_permission_key).present?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
class AdvanceWrestlerJob < ApplicationJob
|
class AdvanceWrestlerJob < ApplicationJob
|
||||||
queue_as :default
|
queue_as :default
|
||||||
|
# associations are not available here so we had to pass tournament_id when creating the job
|
||||||
|
limits_concurrency to: 1, key: ->(_wrestler, _match, tournament_id) { "tournament:#{tournament_id}" }
|
||||||
|
|
||||||
def perform(wrestler, match)
|
def perform(wrestler, match, tournament_id)
|
||||||
# Get tournament from wrestler
|
# Get tournament from wrestler
|
||||||
tournament = wrestler.tournament
|
tournament = wrestler.tournament
|
||||||
|
|
||||||
@@ -29,4 +31,4 @@ class AdvanceWrestlerJob < ApplicationJob
|
|||||||
raise e
|
raise e
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
class CalculateSchoolScoreJob < ApplicationJob
|
class CalculateSchoolScoreJob < ApplicationJob
|
||||||
queue_as :default
|
queue_as :default
|
||||||
|
limits_concurrency to: 1, key: ->(school) { "tournament:#{school.tournament_id}" }
|
||||||
|
|
||||||
# Need for TournamentJobStatusIntegrationTest
|
# Need for TournamentJobStatusIntegrationTest
|
||||||
def self.perform_sync(school)
|
def self.perform_sync(school)
|
||||||
@@ -35,4 +36,4 @@ class CalculateSchoolScoreJob < ApplicationJob
|
|||||||
raise e
|
raise e
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
class GenerateTournamentMatchesJob < ApplicationJob
|
class GenerateTournamentMatchesJob < ApplicationJob
|
||||||
queue_as :default
|
queue_as :default
|
||||||
|
limits_concurrency to: 1, key: ->(tournament) { "tournament:#{tournament.id}" }
|
||||||
|
|
||||||
def perform(tournament)
|
def perform(tournament)
|
||||||
# Log information about the job
|
# Log information about the job
|
||||||
@@ -17,4 +18,4 @@ class GenerateTournamentMatchesJob < ApplicationJob
|
|||||||
raise # Re-raise the error so it's properly recorded
|
raise # Re-raise the error so it's properly recorded
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
class TournamentBackupJob < ApplicationJob
|
class TournamentBackupJob < ApplicationJob
|
||||||
queue_as :default
|
queue_as :default
|
||||||
|
limits_concurrency to: 1, key: ->(tournament, *) { "tournament:#{tournament.id}" }
|
||||||
|
|
||||||
def perform(tournament, reason = nil)
|
def perform(tournament, reason = nil)
|
||||||
# Log information about the job
|
# Log information about the job
|
||||||
@@ -29,4 +30,4 @@ class TournamentBackupJob < ApplicationJob
|
|||||||
raise e
|
raise e
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ class TournamentCleanupJob < ApplicationJob
|
|||||||
has_real_matches = tournament.matches.where(finished: 1).where.not(win_type: 'BYE').exists?
|
has_real_matches = tournament.matches.where(finished: 1).where.not(win_type: 'BYE').exists?
|
||||||
|
|
||||||
if has_real_matches
|
if has_real_matches
|
||||||
|
tournament.tournament_backups.destroy_all
|
||||||
|
|
||||||
# 1. Remove all school delegates
|
# 1. Remove all school delegates
|
||||||
tournament.schools.each do |school|
|
tournament.schools.each do |school|
|
||||||
school.delegates.destroy_all
|
school.delegates.destroy_all
|
||||||
@@ -33,4 +34,4 @@ class TournamentCleanupJob < ApplicationJob
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
class WrestlingdevImportJob < ApplicationJob
|
class WrestlingdevImportJob < ApplicationJob
|
||||||
queue_as :default
|
queue_as :default
|
||||||
|
limits_concurrency to: 1, key: ->(tournament, *) { "tournament:#{tournament.id}" }
|
||||||
|
|
||||||
def perform(tournament, import_data = nil)
|
def perform(tournament, import_data = nil)
|
||||||
# Log information about the job
|
# Log information about the job
|
||||||
@@ -30,4 +31,4 @@ class WrestlingdevImportJob < ApplicationJob
|
|||||||
raise e
|
raise e
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,53 +1,53 @@
|
|||||||
class Mat < ApplicationRecord
|
class Mat < ApplicationRecord
|
||||||
|
include ActionView::RecordIdentifier
|
||||||
belongs_to :tournament
|
belongs_to :tournament
|
||||||
has_many :matches, dependent: :destroy
|
has_many :matches, dependent: :nullify
|
||||||
has_many :mat_assignment_rules, dependent: :destroy
|
has_many :mat_assignment_rules, dependent: :destroy
|
||||||
|
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
|
|
||||||
before_destroy do
|
QUEUE_SLOTS = %w[queue1 queue2 queue3 queue4].freeze
|
||||||
if tournament.matches.size > 0
|
|
||||||
tournament.reset_mats
|
|
||||||
matsToAssign = tournament.mats.select{|m| m.id != self.id}
|
|
||||||
tournament.assign_mats(matsToAssign)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
after_create do
|
after_save :clear_queue_matches_cache
|
||||||
if tournament.matches.size > 0
|
after_commit :broadcast_up_matches_board, on: :update, if: :up_matches_queue_changed?
|
||||||
tournament.reset_mats
|
|
||||||
matsToAssign = tournament.mats
|
|
||||||
tournament.assign_mats(matsToAssign)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def assign_next_match
|
def assign_next_match
|
||||||
|
slot = first_empty_queue_slot
|
||||||
|
return true unless slot
|
||||||
|
|
||||||
match = next_eligible_match
|
match = next_eligible_match
|
||||||
self.matches.reload
|
return false unless match
|
||||||
if match and self.unfinished_matches.size < 4
|
|
||||||
match.mat_id = self.id
|
place_match_in_empty_slot!(match, slot)
|
||||||
if match.save
|
true
|
||||||
# Invalidate any wrestler caches
|
end
|
||||||
if match.w1
|
|
||||||
match.wrestler1.touch
|
def advance_queue!(finished_match = nil)
|
||||||
match.wrestler1.school.touch
|
self.class.transaction do
|
||||||
|
if finished_match
|
||||||
|
position = queue_position_for_match(finished_match)
|
||||||
|
if position == 1
|
||||||
|
shift_queue_forward!
|
||||||
|
fill_queue_slots!
|
||||||
|
elsif position
|
||||||
|
remove_match_from_queue_and_collapse!(finished_match.id)
|
||||||
|
else
|
||||||
|
fill_queue_slots!
|
||||||
end
|
end
|
||||||
if match.w2
|
|
||||||
match.wrestler2.touch
|
|
||||||
match.wrestler2.school.touch
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
else
|
else
|
||||||
return false
|
if queue1_match&.finished == 1
|
||||||
|
shift_queue_forward!
|
||||||
|
end
|
||||||
|
fill_queue_slots!
|
||||||
end
|
end
|
||||||
else
|
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
|
broadcast_current_match
|
||||||
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def next_eligible_match
|
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
|
# 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
|
filtered_matches = Match.where(tournament_id: tournament_id)
|
||||||
.where(finished: [nil, 0]) # finished is nil or 0
|
.where(finished: [nil, 0]) # finished is nil or 0
|
||||||
.where(mat_id: nil) # mat_id is nil
|
.where(mat_id: nil) # mat_id is nil
|
||||||
.where.not(bout_number: nil) # bout_number is not nil
|
.where.not(bout_number: nil) # bout_number is not nil
|
||||||
@@ -57,6 +57,11 @@ class Mat < ApplicationRecord
|
|||||||
filtered_matches = filtered_matches
|
filtered_matches = filtered_matches
|
||||||
.where("loser1_name != ? OR loser1_name IS NULL", "BYE")
|
.where("loser1_name != ? OR loser1_name IS NULL", "BYE")
|
||||||
.where("loser2_name != ? OR loser2_name IS NULL", "BYE")
|
.where("loser2_name != ? OR loser2_name IS NULL", "BYE")
|
||||||
|
|
||||||
|
# Filter out matches without a wrestlers
|
||||||
|
filtered_matches = filtered_matches
|
||||||
|
.where("w1 IS NOT NULL")
|
||||||
|
.where("w2 IS NOT NULL")
|
||||||
|
|
||||||
# Apply mat assignment rules
|
# Apply mat assignment rules
|
||||||
mat_assignment_rules.each do |rule|
|
mat_assignment_rules.each do |rule|
|
||||||
@@ -80,9 +85,205 @@ class Mat < ApplicationRecord
|
|||||||
filtered_matches.first
|
filtered_matches.first
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def queue_match_ids
|
||||||
|
QUEUE_SLOTS.map { |slot| public_send(slot) }
|
||||||
|
end
|
||||||
|
|
||||||
|
# used to prevent N+1 query on each mat
|
||||||
|
def queue_matches
|
||||||
|
slot_ids = queue_match_ids
|
||||||
|
if @queue_matches.nil? || @queue_match_slot_ids != slot_ids
|
||||||
|
ids = slot_ids.compact
|
||||||
|
@queue_matches = if ids.empty?
|
||||||
|
[nil, nil, nil, nil]
|
||||||
|
else
|
||||||
|
matches_by_id = Match.where(id: ids)
|
||||||
|
.includes({ wrestler1: :school }, { wrestler2: :school }, { weight: :matches })
|
||||||
|
.index_by(&:id)
|
||||||
|
slot_ids.map { |match_id| match_id ? matches_by_id[match_id] : nil }
|
||||||
|
end
|
||||||
|
@queue_match_slot_ids = slot_ids
|
||||||
|
end
|
||||||
|
@queue_matches
|
||||||
|
end
|
||||||
|
|
||||||
|
def queue1_match
|
||||||
|
queue_match_at(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def queue2_match
|
||||||
|
queue_match_at(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
def queue3_match
|
||||||
|
queue_match_at(3)
|
||||||
|
end
|
||||||
|
|
||||||
|
def queue4_match
|
||||||
|
queue_match_at(4)
|
||||||
|
end
|
||||||
|
|
||||||
|
def queue_position_for_match(match)
|
||||||
|
return nil unless match
|
||||||
|
return 1 if queue1 == match.id
|
||||||
|
return 2 if queue2 == match.id
|
||||||
|
return 3 if queue3 == match.id
|
||||||
|
return 4 if queue4 == match.id
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_match_from_queue_and_collapse!(match_id)
|
||||||
|
queue_ids = queue_match_ids
|
||||||
|
return if queue_ids.none? { |id| id == match_id }
|
||||||
|
|
||||||
|
queue_ids.map! { |id| id == match_id ? nil : id }
|
||||||
|
queue_ids = queue_ids.compact
|
||||||
|
queue_ids += [nil] * (4 - queue_ids.size)
|
||||||
|
|
||||||
|
update!(
|
||||||
|
queue1: queue_ids[0],
|
||||||
|
queue2: queue_ids[1],
|
||||||
|
queue3: queue_ids[2],
|
||||||
|
queue4: queue_ids[3]
|
||||||
|
)
|
||||||
|
|
||||||
|
fill_queue_slots!
|
||||||
|
broadcast_current_match
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_match_to_queue!(match, position)
|
||||||
|
position = position.to_i
|
||||||
|
raise ArgumentError, "Queue position must be 1-4" unless (1..4).cover?(position)
|
||||||
|
|
||||||
|
self.class.transaction do
|
||||||
|
match.update!(mat_id: id)
|
||||||
|
remove_match_from_other_mats!(match.id)
|
||||||
|
|
||||||
|
queue_ids = queue_match_ids.map { |id| id == match.id ? nil : id }
|
||||||
|
queue_ids = queue_ids.compact
|
||||||
|
|
||||||
|
queue_ids.insert(position - 1, match.id)
|
||||||
|
bumped_match_id = queue_ids.length > 4 ? queue_ids.pop : nil
|
||||||
|
|
||||||
|
queue_ids += [nil] * (4 - queue_ids.length)
|
||||||
|
|
||||||
|
update!(
|
||||||
|
queue1: queue_ids[0],
|
||||||
|
queue2: queue_ids[1],
|
||||||
|
queue3: queue_ids[2],
|
||||||
|
queue4: queue_ids[3]
|
||||||
|
)
|
||||||
|
|
||||||
|
bumped_match = Match.find_by(id: bumped_match_id)
|
||||||
|
if bumped_match && bumped_match.finished != 1
|
||||||
|
bumped_match.update!(mat_id: nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
broadcast_current_match
|
||||||
|
end
|
||||||
|
|
||||||
|
def clear_queue!
|
||||||
|
update!(queue1: nil, queue2: nil, queue3: nil, queue4: nil)
|
||||||
|
broadcast_current_match
|
||||||
|
end
|
||||||
|
|
||||||
def unfinished_matches
|
def unfinished_matches
|
||||||
matches.select{|m| m.finished != 1}.sort_by{|m| m.bout_number}
|
matches.select{|m| m.finished != 1}.sort_by{|m| m.bout_number}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def clear_queue_matches_cache
|
||||||
|
@queue_matches = nil
|
||||||
|
@queue_match_slot_ids = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def queue_match_at(position)
|
||||||
|
queue_matches[position - 1]
|
||||||
|
end
|
||||||
|
|
||||||
|
def first_empty_queue_slot
|
||||||
|
QUEUE_SLOTS.each_with_index do |slot, index|
|
||||||
|
return index + 1 if public_send(slot).nil?
|
||||||
|
end
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def shift_queue_forward!
|
||||||
|
update!(
|
||||||
|
queue1: queue2,
|
||||||
|
queue2: queue3,
|
||||||
|
queue3: queue4,
|
||||||
|
queue4: nil
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fill_queue_slots!
|
||||||
|
queue_ids = queue_match_ids
|
||||||
|
updated = false
|
||||||
|
|
||||||
|
QUEUE_SLOTS.each_with_index do |_slot, index|
|
||||||
|
next if queue_ids[index].present?
|
||||||
|
|
||||||
|
match = next_eligible_match
|
||||||
|
break unless match
|
||||||
|
|
||||||
|
queue_ids[index] = match.id
|
||||||
|
match.update!(mat_id: id)
|
||||||
|
updated = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if updated
|
||||||
|
update!(
|
||||||
|
queue1: queue_ids[0],
|
||||||
|
queue2: queue_ids[1],
|
||||||
|
queue3: queue_ids[2],
|
||||||
|
queue4: queue_ids[3]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_match_from_other_mats!(match_id)
|
||||||
|
self.class.where.not(id: id)
|
||||||
|
.where("queue1 = :match_id OR queue2 = :match_id OR queue3 = :match_id OR queue4 = :match_id", match_id: match_id)
|
||||||
|
.find_each do |mat|
|
||||||
|
mat.remove_match_from_queue_and_collapse!(match_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def place_match_in_empty_slot!(match, slot)
|
||||||
|
self.class.transaction do
|
||||||
|
match.update!(mat_id: id)
|
||||||
|
remove_match_from_other_mats!(match.id)
|
||||||
|
update!(slot_key(slot) => match.id)
|
||||||
|
end
|
||||||
|
broadcast_current_match
|
||||||
|
end
|
||||||
|
|
||||||
|
def slot_key(slot)
|
||||||
|
"queue#{slot}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def broadcast_current_match
|
||||||
|
Turbo::StreamsChannel.broadcast_update_to(
|
||||||
|
self,
|
||||||
|
target: dom_id(self, :current_match),
|
||||||
|
partial: "mats/current_match",
|
||||||
|
locals: {
|
||||||
|
mat: self,
|
||||||
|
match: queue1_match,
|
||||||
|
next_match: queue2_match,
|
||||||
|
show_next_bout_button: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def broadcast_up_matches_board
|
||||||
|
Tournament.broadcast_up_matches_board(tournament_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def up_matches_queue_changed?
|
||||||
|
saved_change_to_queue1? || saved_change_to_queue2? || saved_change_to_queue3? || saved_change_to_queue4?
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
class Match < ApplicationRecord
|
class Match < ApplicationRecord
|
||||||
|
include ActionView::RecordIdentifier
|
||||||
|
|
||||||
belongs_to :tournament, touch: true
|
belongs_to :tournament, touch: true
|
||||||
belongs_to :weight, touch: true
|
belongs_to :weight, touch: true
|
||||||
belongs_to :mat, touch: true, optional: true
|
belongs_to :mat, touch: true, optional: true
|
||||||
belongs_to :winner, class_name: 'Wrestler', foreign_key: 'winner_id', optional: true
|
belongs_to :winner, class_name: 'Wrestler', foreign_key: 'winner_id', optional: true
|
||||||
|
belongs_to :wrestler1, class_name: 'Wrestler', foreign_key: 'w1', optional: true
|
||||||
|
belongs_to :wrestler2, class_name: 'Wrestler', foreign_key: 'w2', optional: true
|
||||||
has_many :wrestlers, :through => :weight
|
has_many :wrestlers, :through => :weight
|
||||||
has_many :schools, :through => :wrestlers
|
has_many :schools, :through => :wrestlers
|
||||||
validate :score_validation, :win_type_validation, :bracket_position_validation, :overtime_type_validation
|
validate :score_validation, :win_type_validation, :bracket_position_validation, :overtime_type_validation
|
||||||
@@ -10,6 +14,11 @@ class Match < ApplicationRecord
|
|||||||
# Callback to update finished_at when a match is finished
|
# Callback to update finished_at when a match is finished
|
||||||
before_save :update_finished_at
|
before_save :update_finished_at
|
||||||
|
|
||||||
|
# update mat show with correct match if bout board is reset
|
||||||
|
# this is done with a turbo stream
|
||||||
|
after_commit :broadcast_mat_assignment_change, if: :saved_change_to_mat_id?, on: [:create, :update]
|
||||||
|
after_commit :broadcast_up_matches_board, on: :update, if: :saved_change_to_mat_id?
|
||||||
|
|
||||||
# Enqueue advancement and related actions after the DB transaction has committed.
|
# Enqueue advancement and related actions after the DB transaction has committed.
|
||||||
# Using after_commit ensures any background jobs enqueued inside these callbacks
|
# Using after_commit ensures any background jobs enqueued inside these callbacks
|
||||||
# will see the committed state of the match (e.g. finished == 1). Enqueuing
|
# will see the committed state of the match (e.g. finished == 1). Enqueuing
|
||||||
@@ -31,12 +40,14 @@ class Match < ApplicationRecord
|
|||||||
wrestler2.touch
|
wrestler2.touch
|
||||||
end
|
end
|
||||||
if self.finished == 1 && self.winner_id != nil
|
if self.finished == 1 && self.winner_id != nil
|
||||||
if self.mat
|
|
||||||
self.mat.assign_next_match
|
|
||||||
end
|
|
||||||
advance_wrestlers
|
advance_wrestlers
|
||||||
|
if self.mat
|
||||||
|
self.mat.advance_queue!(self)
|
||||||
|
end
|
||||||
|
self.tournament.refill_open_bout_board_queues
|
||||||
# School point calculation has move to the end of advance wrestler
|
# School point calculation has move to the end of advance wrestler
|
||||||
# calculate_school_points
|
# calculate_school_points
|
||||||
|
self.update(mat_id: nil)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -50,7 +61,7 @@ class Match < ApplicationRecord
|
|||||||
errors.add(:winner_id, "cannot be blank")
|
errors.add(:winner_id, "cannot be blank")
|
||||||
end
|
end
|
||||||
if win_type == "Pin" and ! score.match(/^[0-5]?[0-9]:[0-5][0-9]/)
|
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")
|
errors.add(:score, "needs to be in time format MM:SS when win type is Pin example: 2:23, 0:25, 10:03")
|
||||||
end
|
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]/)
|
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")
|
errors.add(:score, "needs to be in Number-Number format when win type is Decision, Tech Fall, and Major example: 10-2")
|
||||||
@@ -170,14 +181,6 @@ class Match < ApplicationRecord
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def wrestler1
|
|
||||||
wrestlers.select{|w| w.id == self.w1}.first
|
|
||||||
end
|
|
||||||
|
|
||||||
def wrestler2
|
|
||||||
wrestlers.select{|w| w.id == self.w2}.first
|
|
||||||
end
|
|
||||||
|
|
||||||
def w1_name
|
def w1_name
|
||||||
if self.w1 != nil
|
if self.w1 != nil
|
||||||
wrestler1.name
|
wrestler1.name
|
||||||
@@ -195,6 +198,7 @@ class Match < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def w1_bracket_name
|
def w1_bracket_name
|
||||||
|
first_round = first_round_for_weight
|
||||||
return_string = ""
|
return_string = ""
|
||||||
return_string_ending = ""
|
return_string_ending = ""
|
||||||
if self.w1 and self.winner_id == self.w1
|
if self.w1 and self.winner_id == self.w1
|
||||||
@@ -202,7 +206,7 @@ class Match < ApplicationRecord
|
|||||||
return_string_ending = return_string_ending + "</strong>"
|
return_string_ending = return_string_ending + "</strong>"
|
||||||
end
|
end
|
||||||
if self.w1 != nil
|
if self.w1 != nil
|
||||||
if self.round == 1
|
if self.round == first_round
|
||||||
return_string = return_string + "#{wrestler1.long_bracket_name}"
|
return_string = return_string + "#{wrestler1.long_bracket_name}"
|
||||||
else
|
else
|
||||||
return_string = return_string + "#{wrestler1.short_bracket_name}"
|
return_string = return_string + "#{wrestler1.short_bracket_name}"
|
||||||
@@ -214,6 +218,7 @@ class Match < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def w2_bracket_name
|
def w2_bracket_name
|
||||||
|
first_round = first_round_for_weight
|
||||||
return_string = ""
|
return_string = ""
|
||||||
return_string_ending = ""
|
return_string_ending = ""
|
||||||
if self.w2 and self.winner_id == self.w2
|
if self.w2 and self.winner_id == self.w2
|
||||||
@@ -221,7 +226,7 @@ class Match < ApplicationRecord
|
|||||||
return_string_ending = return_string_ending + "</strong>"
|
return_string_ending = return_string_ending + "</strong>"
|
||||||
end
|
end
|
||||||
if self.w2 != nil
|
if self.w2 != nil
|
||||||
if self.round == 1
|
if self.round == first_round
|
||||||
return_string = return_string + "#{wrestler2.long_bracket_name}"
|
return_string = return_string + "#{wrestler2.long_bracket_name}"
|
||||||
else
|
else
|
||||||
return_string = return_string + "#{wrestler2.short_bracket_name}"
|
return_string = return_string + "#{wrestler2.short_bracket_name}"
|
||||||
@@ -279,6 +284,17 @@ class Match < ApplicationRecord
|
|||||||
self.weight.max
|
self.weight.max
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def first_round_for_weight
|
||||||
|
return @first_round_for_weight if defined?(@first_round_for_weight)
|
||||||
|
|
||||||
|
@first_round_for_weight =
|
||||||
|
if association(:weight).loaded? && self.weight&.association(:matches)&.loaded?
|
||||||
|
self.weight.matches.map(&:round).compact.min
|
||||||
|
else
|
||||||
|
Match.where(weight_id: self.weight_id).minimum(:round)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def replace_loser_name_with_wrestler(w,loser_name)
|
def replace_loser_name_with_wrestler(w,loser_name)
|
||||||
if self.loser1_name == loser_name
|
if self.loser1_name == loser_name
|
||||||
self.w1 = w.id
|
self.w1 = w.id
|
||||||
@@ -334,4 +350,30 @@ class Match < ApplicationRecord
|
|||||||
self.finished_at = Time.current.utc
|
self.finished_at = Time.current.utc
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def broadcast_mat_assignment_change
|
||||||
|
old_mat_id, new_mat_id = saved_change_to_mat_id || previous_changes["mat_id"]
|
||||||
|
return unless old_mat_id || new_mat_id
|
||||||
|
|
||||||
|
[old_mat_id, new_mat_id].compact.uniq.each do |mat_id|
|
||||||
|
mat = Mat.find_by(id: mat_id)
|
||||||
|
next unless mat
|
||||||
|
|
||||||
|
Turbo::StreamsChannel.broadcast_update_to(
|
||||||
|
mat,
|
||||||
|
target: dom_id(mat, :current_match),
|
||||||
|
partial: "mats/current_match",
|
||||||
|
locals: {
|
||||||
|
mat: mat,
|
||||||
|
match: mat.queue1_match,
|
||||||
|
next_match: mat.queue2_match,
|
||||||
|
show_next_bout_button: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def broadcast_up_matches_board
|
||||||
|
Tournament.broadcast_up_matches_board(tournament_id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -69,8 +69,35 @@ class Tournament < ApplicationRecord
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def up_matches_unassigned_matches
|
||||||
|
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({ wrestler1: :school }, { wrestler2: :school }, { weight: :matches })
|
||||||
|
end
|
||||||
|
|
||||||
|
def up_matches_mats
|
||||||
|
mats.includes(:matches)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.broadcast_up_matches_board(tournament_id)
|
||||||
|
tournament = find_by(id: tournament_id)
|
||||||
|
return unless tournament
|
||||||
|
|
||||||
|
Turbo::StreamsChannel.broadcast_replace_to(
|
||||||
|
tournament,
|
||||||
|
target: "up_matches_board",
|
||||||
|
partial: "tournaments/up_matches_board",
|
||||||
|
locals: { tournament: tournament }
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def destroy_all_matches
|
def destroy_all_matches
|
||||||
matches.destroy_all
|
matches.destroy_all
|
||||||
|
mats.each(&:clear_queue!)
|
||||||
end
|
end
|
||||||
|
|
||||||
def matches_by_round(round)
|
def matches_by_round(round)
|
||||||
@@ -82,38 +109,26 @@ class Tournament < ApplicationRecord
|
|||||||
matches.maximum(:round) || 0 # Return 0 if no matches or max round is nil
|
matches.maximum(:round) || 0 # Return 0 if no matches or max round is nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def assign_mats(mats_to_assign)
|
|
||||||
if mats_to_assign.count > 0
|
|
||||||
until mats_to_assign.sort_by{|m| m.id}.last.matches.count == 4
|
|
||||||
mats_to_assign.sort_by{|m| m.id}.each do |m|
|
|
||||||
m.assign_next_match
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def reset_mats
|
def reset_mats
|
||||||
|
matches.reload
|
||||||
|
mats.reload
|
||||||
matches_to_reset = matches.select{|m| m.mat_id != nil}
|
matches_to_reset = matches.select{|m| m.mat_id != nil}
|
||||||
# matches_to_reset.update_all( {:mat_id => nil } )
|
# matches_to_reset.update_all( {:mat_id => nil } )
|
||||||
matches_to_reset.each do |m|
|
matches_to_reset.each do |m|
|
||||||
m.mat_id = nil
|
m.mat_id = nil
|
||||||
m.save
|
m.save
|
||||||
end
|
end
|
||||||
|
mats.each do |mat|
|
||||||
|
mat.clear_queue!
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def pointAdjustments
|
def pointAdjustments
|
||||||
point_adjustments = []
|
school_scope = Teampointadjust.where(school_id: schools.select(:id))
|
||||||
self.schools.each do |s|
|
wrestler_scope = Teampointadjust.where(wrestler_id: wrestlers.select(:id))
|
||||||
s.deductedPoints.each do |d|
|
|
||||||
point_adjustments << d
|
Teampointadjust.includes(:school, :wrestler)
|
||||||
end
|
.merge(school_scope.or(wrestler_scope))
|
||||||
end
|
|
||||||
self.wrestlers.each do |w|
|
|
||||||
w.deductedPoints.each do |d|
|
|
||||||
point_adjustments << d
|
|
||||||
end
|
|
||||||
end
|
|
||||||
point_adjustments
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_school_delegations
|
def remove_school_delegations
|
||||||
@@ -156,14 +171,14 @@ class Tournament < ApplicationRecord
|
|||||||
|
|
||||||
def double_elim_number_of_wrestlers_error
|
def double_elim_number_of_wrestlers_error
|
||||||
error_string = ""
|
error_string = ""
|
||||||
if self.tournament_type == "Double Elimination 1-6" or self.tournament_type == "Double Elimination 1-8"
|
if self.tournament_type == "Regular Double Elimination 1-6" or self.tournament_type == "Regular Double Elimination 1-8"
|
||||||
weights_with_too_many_wrestlers = weights.select{|w| w.wrestlers.size > 64}
|
weights_with_too_many_wrestlers = weights.select{|w| w.wrestlers.size > 64}
|
||||||
weight_with_too_few_wrestlers = weights.select{|w| w.wrestlers.size < 4}
|
weight_with_too_few_wrestlers = weights.select{|w| w.wrestlers.size < 2}
|
||||||
weights_with_too_many_wrestlers.each do |weight|
|
weights_with_too_many_wrestlers.each do |weight|
|
||||||
error_string = error_string + " The weight class #{weight.max} has more than 64 wrestlers."
|
error_string = error_string + " The weight class #{weight.max} has more than 64 wrestlers."
|
||||||
end
|
end
|
||||||
weight_with_too_few_wrestlers.each do |weight|
|
weight_with_too_few_wrestlers.each do |weight|
|
||||||
error_string = error_string + " The weight class #{weight.max} has less than 4 wrestlers."
|
error_string = error_string + " The weight class #{weight.max} has less than 2 wrestlers."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return error_string
|
return error_string
|
||||||
@@ -228,19 +243,24 @@ class Tournament < ApplicationRecord
|
|||||||
|
|
||||||
def reset_and_fill_bout_board
|
def reset_and_fill_bout_board
|
||||||
reset_mats
|
reset_mats
|
||||||
|
matches.reload
|
||||||
if mats.any?
|
refill_open_bout_board_queues
|
||||||
4.times do
|
end
|
||||||
# Iterate over each mat and assign the next available match
|
|
||||||
mats.each do |mat|
|
def refill_open_bout_board_queues
|
||||||
match_assigned = mat.assign_next_match
|
return unless mats.any?
|
||||||
# If no more matches are available, exit early
|
|
||||||
unless match_assigned
|
loop do
|
||||||
puts "No more eligible matches to assign."
|
assigned_any = false
|
||||||
return
|
# Fill in round-robin order by queue depth:
|
||||||
end
|
# all mats queue1 first, then queue2, then queue3, then queue4.
|
||||||
|
(1..4).each do |slot|
|
||||||
|
mats.reload.each do |mat|
|
||||||
|
next unless mat.public_send("queue#{slot}").nil?
|
||||||
|
assigned_any ||= mat.assign_next_match
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
break unless assigned_any
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -279,4 +299,4 @@ class Tournament < ApplicationRecord
|
|||||||
def connection_adapter
|
def connection_adapter
|
||||||
ActiveRecord::Base.connection.adapter_name
|
ActiveRecord::Base.connection.adapter_name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -53,19 +53,16 @@ class User < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def delegated_tournaments
|
def delegated_tournaments
|
||||||
tournaments_delegated = []
|
Tournament.joins(:delegates)
|
||||||
delegated_tournament_permissions.each do |t|
|
.where(tournament_delegates: { user_id: id })
|
||||||
tournaments_delegated << t.tournament
|
.distinct
|
||||||
end
|
|
||||||
tournaments_delegated
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def delegated_schools
|
def delegated_schools
|
||||||
schools_delegated = []
|
School.joins(:delegates)
|
||||||
delegated_school_permissions.each do |t|
|
.where(school_delegates: { user_id: id })
|
||||||
schools_delegated << t.school
|
.includes(:tournament)
|
||||||
end
|
.distinct
|
||||||
schools_delegated
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.search(search)
|
def self.search(search)
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ class Weight < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def calculate_bracket_size
|
def calculate_bracket_size
|
||||||
num_wrestlers = wrestlers.reload.size
|
num_wrestlers = wrestlers.size
|
||||||
return nil if num_wrestlers <= 0 # Handle invalid input
|
return nil if num_wrestlers <= 0 # Handle invalid input
|
||||||
|
|
||||||
# Find the smallest power of 2 greater than or equal to num_wrestlers
|
# Find the smallest power of 2 greater than or equal to num_wrestlers
|
||||||
|
|||||||
@@ -8,25 +8,101 @@ class AdvanceWrestler
|
|||||||
def advance
|
def advance
|
||||||
# Use perform_later which will execute based on centralized adapter config
|
# Use perform_later which will execute based on centralized adapter config
|
||||||
# This will be converted to inline execution in test environment by ActiveJob
|
# This will be converted to inline execution in test environment by ActiveJob
|
||||||
AdvanceWrestlerJob.perform_later(@wrestler, @last_match)
|
AdvanceWrestlerJob.perform_later(@wrestler, @last_match, @tournament.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def advance_raw
|
def advance_raw
|
||||||
@last_match.reload
|
@last_match = Match.find_by(id: @last_match&.id)
|
||||||
@wrestler.reload
|
@wrestler = Wrestler.includes(:school, :weight).find_by(id: @wrestler.id)
|
||||||
if @last_match && @last_match.finished?
|
return unless @last_match && @wrestler && @last_match.finished?
|
||||||
pool_to_bracket_advancement if @tournament.tournament_type == "Pool to bracket"
|
|
||||||
ModifiedDoubleEliminationAdvance.new(@wrestler, @last_match).bracket_advancement if @tournament.tournament_type.include? "Modified 16 Man Double Elimination"
|
context = preload_advancement_context
|
||||||
DoubleEliminationAdvance.new(@wrestler, @last_match).bracket_advancement if @tournament.tournament_type.include? "Regular Double Elimination"
|
matches_to_advance = []
|
||||||
|
|
||||||
|
if @tournament.tournament_type == "Pool to bracket"
|
||||||
|
matches_to_advance.concat(pool_to_bracket_advancement(context))
|
||||||
|
elsif @tournament.tournament_type.include?("Modified 16 Man Double Elimination")
|
||||||
|
service = ModifiedDoubleEliminationAdvance.new(@wrestler, @last_match, matches: context[:matches])
|
||||||
|
service.bracket_advancement
|
||||||
|
matches_to_advance.concat(service.matches_to_advance)
|
||||||
|
elsif @tournament.tournament_type.include?("Regular Double Elimination")
|
||||||
|
service = DoubleEliminationAdvance.new(@wrestler, @last_match, matches: context[:matches])
|
||||||
|
service.bracket_advancement
|
||||||
|
matches_to_advance.concat(service.matches_to_advance)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
persist_advancement_changes(context)
|
||||||
|
advance_pending_matches(matches_to_advance)
|
||||||
@wrestler.school.calculate_score
|
@wrestler.school.calculate_score
|
||||||
end
|
end
|
||||||
|
|
||||||
def pool_to_bracket_advancement
|
def preload_advancement_context
|
||||||
if @wrestler.weight.all_pool_matches_finished(@wrestler.pool) and (@wrestler.finished_bracket_matches.size < 1)
|
weight = Weight.includes(:matches, :wrestlers).find(@wrestler.weight_id)
|
||||||
PoolOrder.new(@wrestler.weight.wrestlers_in_pool(@wrestler.pool)).getPoolOrder
|
{
|
||||||
end
|
weight: weight,
|
||||||
PoolAdvance.new(@wrestler).advanceWrestler
|
matches: weight.matches.to_a,
|
||||||
|
wrestlers: weight.wrestlers.to_a
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
def persist_advancement_changes(context)
|
||||||
|
persist_matches(context[:matches])
|
||||||
|
persist_wrestlers(context[:wrestlers])
|
||||||
|
end
|
||||||
|
|
||||||
|
def persist_matches(matches)
|
||||||
|
timestamp = Time.current
|
||||||
|
updates = matches.filter_map do |m|
|
||||||
|
next unless m.changed?
|
||||||
|
|
||||||
|
{
|
||||||
|
id: m.id,
|
||||||
|
w1: m.w1,
|
||||||
|
w2: m.w2,
|
||||||
|
winner_id: m.winner_id,
|
||||||
|
win_type: m.win_type,
|
||||||
|
score: m.score,
|
||||||
|
finished: m.finished,
|
||||||
|
loser1_name: m.loser1_name,
|
||||||
|
loser2_name: m.loser2_name,
|
||||||
|
finished_at: m.finished_at,
|
||||||
|
updated_at: timestamp
|
||||||
|
}
|
||||||
|
end
|
||||||
|
Match.upsert_all(updates) if updates.any?
|
||||||
|
end
|
||||||
|
|
||||||
|
def persist_wrestlers(wrestlers)
|
||||||
|
timestamp = Time.current
|
||||||
|
updates = wrestlers.filter_map do |w|
|
||||||
|
next unless w.changed?
|
||||||
|
|
||||||
|
{
|
||||||
|
id: w.id,
|
||||||
|
pool_placement: w.pool_placement,
|
||||||
|
pool_placement_tiebreaker: w.pool_placement_tiebreaker,
|
||||||
|
updated_at: timestamp
|
||||||
|
}
|
||||||
|
end
|
||||||
|
Wrestler.upsert_all(updates) if updates.any?
|
||||||
|
end
|
||||||
|
|
||||||
|
def advance_pending_matches(matches_to_advance)
|
||||||
|
matches_to_advance.uniq(&:id).each do |match|
|
||||||
|
match.advance_wrestlers
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pool_to_bracket_advancement(context)
|
||||||
|
matches_to_advance = []
|
||||||
|
wrestlers_in_pool = context[:wrestlers].select { |w| w.pool == @wrestler.pool }
|
||||||
|
if @wrestler.weight.all_pool_matches_finished(@wrestler.pool) && (@wrestler.finished_bracket_matches.size < 1)
|
||||||
|
PoolOrder.new(wrestlers_in_pool).getPoolOrder
|
||||||
|
end
|
||||||
|
service = PoolAdvance.new(@wrestler, @last_match, matches: context[:matches], wrestlers: context[:wrestlers])
|
||||||
|
service.advanceWrestler
|
||||||
|
matches_to_advance.concat(service.matches_to_advance)
|
||||||
|
matches_to_advance
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
class DoubleEliminationAdvance
|
class DoubleEliminationAdvance
|
||||||
|
|
||||||
def initialize(wrestler,last_match)
|
attr_reader :matches_to_advance
|
||||||
|
|
||||||
|
def initialize(wrestler,last_match, matches: nil)
|
||||||
@wrestler = wrestler
|
@wrestler = wrestler
|
||||||
@last_match = last_match
|
@last_match = last_match
|
||||||
|
@matches = matches || @wrestler.weight.matches.to_a
|
||||||
|
@matches_to_advance = []
|
||||||
@next_match_position_number = (@last_match.bracket_position_number / 2.0)
|
@next_match_position_number = (@last_match.bracket_position_number / 2.0)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -48,7 +52,7 @@ class DoubleEliminationAdvance
|
|||||||
end
|
end
|
||||||
|
|
||||||
if next_match_bracket_position
|
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
|
next_match = @matches.find { |m| m.bracket_position == next_match_bracket_position && m.bracket_position_number == next_match_position_number.ceil && m.weight_id == @wrestler.weight_id }
|
||||||
end
|
end
|
||||||
|
|
||||||
if next_match
|
if next_match
|
||||||
@@ -59,18 +63,16 @@ class DoubleEliminationAdvance
|
|||||||
def update_new_match(match, wrestler_number)
|
def update_new_match(match, wrestler_number)
|
||||||
if wrestler_number == 2 or (match.loser1_name and match.loser1_name.include? "Loser of")
|
if wrestler_number == 2 or (match.loser1_name and match.loser1_name.include? "Loser of")
|
||||||
match.w2 = @wrestler.id
|
match.w2 = @wrestler.id
|
||||||
match.save
|
|
||||||
elsif wrestler_number == 1
|
elsif wrestler_number == 1
|
||||||
match.w1 = @wrestler.id
|
match.w1 = @wrestler.id
|
||||||
match.save
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_consolation_bye
|
def update_consolation_bye
|
||||||
bout = @wrestler.last_match.bout_number
|
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)
|
next_match = @matches.find { |m| m.weight_id == @wrestler.weight_id && (m.loser1_name == "Loser of #{bout}" || m.loser2_name == "Loser of #{bout}") }
|
||||||
if next_match.size > 0
|
if next_match
|
||||||
next_match.first.replace_loser_name_with_bye("Loser of #{bout}")
|
replace_loser_name_with_bye(next_match, "Loser of #{bout}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -84,27 +86,18 @@ class DoubleEliminationAdvance
|
|||||||
|
|
||||||
def losers_bracket_advancement
|
def losers_bracket_advancement
|
||||||
bout = @last_match.bout_number
|
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
|
next_match = @matches.find { |m| m.weight_id == @wrestler.weight_id && (m.loser1_name == "Loser of #{bout}" || m.loser2_name == "Loser of #{bout}") }
|
||||||
|
|
||||||
if next_match.present?
|
if next_match.present?
|
||||||
next_match.replace_loser_name_with_wrestler(@wrestler, "Loser of #{bout}")
|
replace_loser_name_with_wrestler(next_match, @wrestler, "Loser of #{bout}")
|
||||||
next_match.reload
|
|
||||||
|
|
||||||
if next_match.loser1_name == "BYE" || next_match.loser2_name == "BYE"
|
if next_match.loser1_name == "BYE" || next_match.loser2_name == "BYE"
|
||||||
next_match.winner_id = @wrestler.id
|
next_match.winner_id = @wrestler.id
|
||||||
next_match.win_type = "BYE"
|
next_match.win_type = "BYE"
|
||||||
next_match.score = ""
|
next_match.score = ""
|
||||||
next_match.finished = 1
|
next_match.finished = 1
|
||||||
# puts "Before save: winner_id=#{next_match.winner_id}"
|
next_match.finished_at = Time.current
|
||||||
|
@matches_to_advance << next_match
|
||||||
# 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
|
end
|
||||||
end
|
end
|
||||||
@@ -112,51 +105,69 @@ class DoubleEliminationAdvance
|
|||||||
|
|
||||||
def advance_double_byes
|
def advance_double_byes
|
||||||
weight = @wrestler.weight
|
weight = @wrestler.weight
|
||||||
weight.matches.select{|m| m.loser1_name == "BYE" and m.loser2_name == "BYE" and m.finished != 1}.each do |match|
|
@matches.select{|m| m.weight_id == weight.id && m.loser1_name == "BYE" and m.loser2_name == "BYE" and m.finished != 1}.each do |match|
|
||||||
match.finished = 1
|
match.finished = 1
|
||||||
|
match.finished_at = Time.current
|
||||||
match.score = ""
|
match.score = ""
|
||||||
match.win_type = "BYE"
|
match.win_type = "BYE"
|
||||||
next_match_position_number = (match.bracket_position_number / 2.0).ceil
|
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}
|
after_matches = @matches.select{|m| m.weight_id == weight.id && 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 }
|
next if after_matches.empty?
|
||||||
this_round_matches = weight.matches.select{|m| m.round == match.round and m.is_consolation_match == match.is_consolation_match }
|
next_matches = @matches.select{|m| m.weight_id == weight.id && m.round == after_matches.first.round and m.is_consolation_match == match.is_consolation_match }
|
||||||
|
this_round_matches = @matches.select{|m| m.weight_id == weight.id && m.round == match.round and m.is_consolation_match == match.is_consolation_match }
|
||||||
|
next_match = nil
|
||||||
|
|
||||||
if next_matches.size == this_round_matches.size
|
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 = next_matches.select{|m| m.bracket_position_number == match.bracket_position_number}.first
|
||||||
next_match.loser2_name = "BYE"
|
next_match.loser2_name = "BYE" if next_match
|
||||||
next_match.save
|
|
||||||
elsif next_matches.size < this_round_matches.size and next_matches.size > 0
|
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
|
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
|
if next_match && next_match.bracket_position_number == next_match_position_number
|
||||||
next_match.loser2_name = "BYE"
|
next_match.loser2_name = "BYE"
|
||||||
else
|
elsif next_match
|
||||||
next_match.loser1_name = "BYE"
|
next_match.loser1_name = "BYE"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
next_match.save
|
|
||||||
match.save
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_bye_for_placement
|
def set_bye_for_placement
|
||||||
weight = @wrestler.weight
|
weight = @wrestler.weight
|
||||||
fifth_finals = weight.matches.select{|match| match.bracket_position == '5/6'}.first
|
fifth_finals = @matches.select{|match| match.weight_id == weight.id && match.bracket_position == '5/6'}.first
|
||||||
seventh_finals = weight.matches.select{|match| match.bracket_position == '7/8'}.first
|
seventh_finals = @matches.select{|match| match.weight_id == weight.id && match.bracket_position == '7/8'}.first
|
||||||
if seventh_finals
|
if seventh_finals
|
||||||
conso_quarter = weight.matches.select{|match| match.bracket_position == 'Conso Quarter'}
|
conso_quarter = @matches.select{|match| match.weight_id == weight.id && match.bracket_position == 'Conso Quarter'}
|
||||||
conso_quarter.each do |match|
|
conso_quarter.each do |match|
|
||||||
if match.loser1_name == "BYE" or match.loser2_name == "BYE"
|
if match.loser1_name == "BYE" or match.loser2_name == "BYE"
|
||||||
seventh_finals.replace_loser_name_with_bye("Loser of #{match.bout_number}")
|
replace_loser_name_with_bye(seventh_finals, "Loser of #{match.bout_number}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if fifth_finals
|
if fifth_finals
|
||||||
conso_semis = weight.matches.select{|match| match.bracket_position == 'Conso Semis'}
|
conso_semis = @matches.select{|match| match.weight_id == weight.id && match.bracket_position == 'Conso Semis'}
|
||||||
conso_semis.each do |match|
|
conso_semis.each do |match|
|
||||||
if match.loser1_name == "BYE" or match.loser2_name == "BYE"
|
if match.loser1_name == "BYE" or match.loser2_name == "BYE"
|
||||||
fifth_finals.replace_loser_name_with_bye("Loser of #{match.bout_number}")
|
replace_loser_name_with_bye(fifth_finals, "Loser of #{match.bout_number}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def replace_loser_name_with_wrestler(match, wrestler, loser_name)
|
||||||
|
if match.loser1_name == loser_name
|
||||||
|
match.w1 = wrestler.id
|
||||||
|
end
|
||||||
|
if match.loser2_name == loser_name
|
||||||
|
match.w2 = wrestler.id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def replace_loser_name_with_bye(match, loser_name)
|
||||||
|
if match.loser1_name == loser_name
|
||||||
|
match.loser1_name = "BYE"
|
||||||
|
end
|
||||||
|
if match.loser2_name == loser_name
|
||||||
|
match.loser2_name = "BYE"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
class ModifiedDoubleEliminationAdvance
|
class ModifiedDoubleEliminationAdvance
|
||||||
|
|
||||||
def initialize(wrestler,last_match)
|
attr_reader :matches_to_advance
|
||||||
|
|
||||||
|
def initialize(wrestler,last_match, matches: nil)
|
||||||
@wrestler = wrestler
|
@wrestler = wrestler
|
||||||
@last_match = last_match
|
@last_match = last_match
|
||||||
|
@matches = matches || @wrestler.weight.matches.to_a
|
||||||
|
@matches_to_advance = []
|
||||||
@next_match_position_number = (@last_match.bracket_position_number / 2.0)
|
@next_match_position_number = (@last_match.bracket_position_number / 2.0)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -25,42 +29,41 @@ class ModifiedDoubleEliminationAdvance
|
|||||||
update_consolation_bye
|
update_consolation_bye
|
||||||
end
|
end
|
||||||
if @last_match.bracket_position == "Quarter"
|
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
|
new_match = @matches.find { |m| m.bracket_position == "Semis" && m.bracket_position_number == @next_match_position_number.ceil && m.weight_id == @wrestler.weight_id }
|
||||||
update_new_match(new_match, get_wrestler_number)
|
update_new_match(new_match, get_wrestler_number)
|
||||||
elsif @last_match.bracket_position == "Semis"
|
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
|
new_match = @matches.find { |m| m.bracket_position == "1/2" && m.bracket_position_number == @next_match_position_number.ceil && m.weight_id == @wrestler.weight_id }
|
||||||
update_new_match(new_match, get_wrestler_number)
|
update_new_match(new_match, get_wrestler_number)
|
||||||
elsif @last_match.bracket_position == "Conso Semis"
|
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
|
new_match = @matches.find { |m| m.bracket_position == "5/6" && m.bracket_position_number == @next_match_position_number.ceil && m.weight_id == @wrestler.weight_id }
|
||||||
update_new_match(new_match, get_wrestler_number)
|
update_new_match(new_match, get_wrestler_number)
|
||||||
elsif @last_match.bracket_position == "Conso Quarter"
|
elsif @last_match.bracket_position == "Conso Quarter"
|
||||||
# it's a special bracket where a semi loser is not dropping down
|
# 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
|
new_match = @matches.find { |m| m.bracket_position == "Conso Semis" && m.bracket_position_number == @next_match_position_number.ceil && m.weight_id == @wrestler.weight_id }
|
||||||
update_new_match(new_match, get_wrestler_number)
|
update_new_match(new_match, get_wrestler_number)
|
||||||
elsif @last_match.bracket_position == "Bracket Round of 16"
|
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
|
new_match = @matches.select { |m| m.bracket_position_number == @next_match_position_number.ceil && m.weight_id == @wrestler.weight_id && m.round > @last_match.round && m.bracket_position == "Quarter" }.sort_by(&:round).first
|
||||||
update_new_match(new_match, get_wrestler_number)
|
update_new_match(new_match, get_wrestler_number)
|
||||||
elsif @last_match.bracket_position == "Conso Round of 8"
|
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
|
new_match = @matches.select { |m| m.bracket_position_number == @last_match.bracket_position_number && m.weight_id == @wrestler.weight_id && m.round > @last_match.round && m.bracket_position == "Conso Quarter" }.sort_by(&:round).first
|
||||||
update_new_match(new_match, get_wrestler_number)
|
update_new_match(new_match, get_wrestler_number)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_new_match(match, wrestler_number)
|
def update_new_match(match, wrestler_number)
|
||||||
|
return unless match
|
||||||
if wrestler_number == 2 or (match.loser1_name and match.loser1_name.include? "Loser of")
|
if wrestler_number == 2 or (match.loser1_name and match.loser1_name.include? "Loser of")
|
||||||
match.w2 = @wrestler.id
|
match.w2 = @wrestler.id
|
||||||
match.save
|
|
||||||
elsif wrestler_number == 1
|
elsif wrestler_number == 1
|
||||||
match.w1 = @wrestler.id
|
match.w1 = @wrestler.id
|
||||||
match.save
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_consolation_bye
|
def update_consolation_bye
|
||||||
bout = @wrestler.last_match.bout_number
|
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)
|
next_match = @matches.find { |m| m.weight_id == @wrestler.weight_id && (m.loser1_name == "Loser of #{bout}" || m.loser2_name == "Loser of #{bout}") }
|
||||||
if next_match.size > 0
|
if next_match
|
||||||
next_match.first.replace_loser_name_with_bye("Loser of #{bout}")
|
replace_loser_name_with_bye(next_match, "Loser of #{bout}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -74,27 +77,18 @@ class ModifiedDoubleEliminationAdvance
|
|||||||
|
|
||||||
def losers_bracket_advancement
|
def losers_bracket_advancement
|
||||||
bout = @last_match.bout_number
|
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
|
next_match = @matches.find { |m| m.weight_id == @wrestler.weight_id && (m.loser1_name == "Loser of #{bout}" || m.loser2_name == "Loser of #{bout}") }
|
||||||
|
|
||||||
if next_match.present?
|
if next_match.present?
|
||||||
next_match.replace_loser_name_with_wrestler(@wrestler, "Loser of #{bout}")
|
replace_loser_name_with_wrestler(next_match, @wrestler, "Loser of #{bout}")
|
||||||
next_match.reload
|
|
||||||
|
|
||||||
if next_match.loser1_name == "BYE" || next_match.loser2_name == "BYE"
|
if next_match.loser1_name == "BYE" || next_match.loser2_name == "BYE"
|
||||||
next_match.winner_id = @wrestler.id
|
next_match.winner_id = @wrestler.id
|
||||||
next_match.win_type = "BYE"
|
next_match.win_type = "BYE"
|
||||||
next_match.score = ""
|
next_match.score = ""
|
||||||
next_match.finished = 1
|
next_match.finished = 1
|
||||||
# puts "Before save: winner_id=#{next_match.winner_id}"
|
next_match.finished_at = Time.current
|
||||||
|
@matches_to_advance << next_match
|
||||||
# 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
|
end
|
||||||
end
|
end
|
||||||
@@ -102,43 +96,53 @@ class ModifiedDoubleEliminationAdvance
|
|||||||
|
|
||||||
def advance_double_byes
|
def advance_double_byes
|
||||||
weight = @wrestler.weight
|
weight = @wrestler.weight
|
||||||
weight.matches.select{|m| m.loser1_name == "BYE" and m.loser2_name == "BYE" and m.finished != 1}.each do |match|
|
@matches.select{|m| m.weight_id == weight.id && m.loser1_name == "BYE" and m.loser2_name == "BYE" and m.finished != 1}.each do |match|
|
||||||
match.finished = 1
|
match.finished = 1
|
||||||
|
match.finished_at = Time.current
|
||||||
match.score = ""
|
match.score = ""
|
||||||
match.win_type = "BYE"
|
match.win_type = "BYE"
|
||||||
next_match_position_number = (match.bracket_position_number / 2.0).ceil
|
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}
|
after_matches = @matches.select{|m| m.weight_id == weight.id && 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 }
|
next if after_matches.empty?
|
||||||
this_round_matches = weight.matches.select{|m| m.round == match.round and m.is_consolation_match == match.is_consolation_match }
|
next_matches = @matches.select{|m| m.weight_id == weight.id && m.round == after_matches.first.round and m.is_consolation_match == match.is_consolation_match }
|
||||||
|
this_round_matches = @matches.select{|m| m.weight_id == weight.id && m.round == match.round and m.is_consolation_match == match.is_consolation_match }
|
||||||
|
next_match = nil
|
||||||
|
|
||||||
if next_matches.size == this_round_matches.size
|
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 = next_matches.select{|m| m.bracket_position_number == match.bracket_position_number}.first
|
||||||
next_match.loser2_name = "BYE"
|
next_match.loser2_name = "BYE" if next_match
|
||||||
next_match.save
|
|
||||||
elsif next_matches.size < this_round_matches.size and next_matches.size > 0
|
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
|
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
|
if next_match && next_match.bracket_position_number == next_match_position_number
|
||||||
next_match.loser2_name = "BYE"
|
next_match.loser2_name = "BYE"
|
||||||
else
|
elsif next_match
|
||||||
next_match.loser1_name = "BYE"
|
next_match.loser1_name = "BYE"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
next_match.save
|
|
||||||
match.save
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_bye_for_placement
|
def set_bye_for_placement
|
||||||
weight = @wrestler.weight
|
weight = @wrestler.weight
|
||||||
seventh_finals = weight.matches.select{|match| match.bracket_position == '7/8'}.first
|
seventh_finals = @matches.select{|match| match.weight_id == weight.id && match.bracket_position == '7/8'}.first
|
||||||
if seventh_finals
|
if seventh_finals
|
||||||
conso_quarter = weight.matches.select{|match| match.bracket_position == 'Conso Semis'}
|
conso_quarter = @matches.select{|match| match.weight_id == weight.id && match.bracket_position == 'Conso Semis'}
|
||||||
conso_quarter.each do |match|
|
conso_quarter.each do |match|
|
||||||
if match.loser1_name == "BYE" or match.loser2_name == "BYE"
|
if match.loser1_name == "BYE" or match.loser2_name == "BYE"
|
||||||
seventh_finals.replace_loser_name_with_bye("Loser of #{match.bout_number}")
|
replace_loser_name_with_bye(seventh_finals, "Loser of #{match.bout_number}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def replace_loser_name_with_wrestler(match, wrestler, loser_name)
|
||||||
|
match.w1 = wrestler.id if match.loser1_name == loser_name
|
||||||
|
match.w2 = wrestler.id if match.loser2_name == loser_name
|
||||||
|
end
|
||||||
|
|
||||||
|
def replace_loser_name_with_bye(match, loser_name)
|
||||||
|
match.loser1_name = "BYE" if match.loser1_name == loser_name
|
||||||
|
match.loser2_name = "BYE" if match.loser2_name == loser_name
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
class PoolAdvance
|
class PoolAdvance
|
||||||
|
|
||||||
def initialize(wrestler)
|
attr_reader :matches_to_advance
|
||||||
|
|
||||||
|
def initialize(wrestler, last_match, matches: nil, wrestlers: nil)
|
||||||
@wrestler = wrestler
|
@wrestler = wrestler
|
||||||
@last_match = @wrestler.last_match
|
@last_match = last_match
|
||||||
|
@matches = matches || @wrestler.weight.matches.to_a
|
||||||
|
@wrestlers = wrestlers || @wrestler.weight.wrestlers.to_a
|
||||||
|
@matches_to_advance = []
|
||||||
end
|
end
|
||||||
|
|
||||||
def advanceWrestler
|
def advanceWrestler
|
||||||
@@ -17,15 +22,15 @@ class PoolAdvance
|
|||||||
def poolToBracketAdvancment
|
def poolToBracketAdvancment
|
||||||
pool = @wrestler.pool
|
pool = @wrestler.pool
|
||||||
# This has to always run because the last match in a pool might not be a pool winner or runner up
|
# This has to always run because the last match in a pool might not be a pool winner or runner up
|
||||||
winner = Wrestler.where("weight_id = ? and pool_placement = 1 and pool = ?",@wrestler.weight.id, pool).first
|
winner = @wrestlers.find { |w| w.weight_id == @wrestler.weight.id && w.pool_placement == 1 && w.pool == pool }
|
||||||
runner_up = Wrestler.where("weight_id = ? and pool_placement = 2 and pool = ?",@wrestler.weight.id, pool).first
|
runner_up = @wrestlers.find { |w| w.weight_id == @wrestler.weight.id && w.pool_placement == 2 && w.pool == pool }
|
||||||
if runner_up
|
if runner_up
|
||||||
runner_up_match = Match.where("weight_id = ? and (loser1_name = ? or loser2_name = ?)",@wrestler.weight.id, "Runner Up Pool #{pool}", "Runner Up Pool #{pool}").first
|
runner_up_match = @matches.find { |m| m.weight_id == @wrestler.weight.id && (m.loser1_name == "Runner Up Pool #{pool}" || m.loser2_name == "Runner Up Pool #{pool}") }
|
||||||
runner_up_match.replace_loser_name_with_wrestler(runner_up,"Runner Up Pool #{pool}")
|
replace_loser_name_with_wrestler(runner_up_match, runner_up, "Runner Up Pool #{pool}") if runner_up_match
|
||||||
end
|
end
|
||||||
if winner
|
if winner
|
||||||
winner_match = Match.where("weight_id = ? and (loser1_name = ? or loser2_name = ?)",@wrestler.weight.id, "Winner Pool #{pool}", "Winner Pool #{pool}").first
|
winner_match = @matches.find { |m| m.weight_id == @wrestler.weight.id && (m.loser1_name == "Winner Pool #{pool}" || m.loser2_name == "Winner Pool #{pool}") }
|
||||||
winner_match.replace_loser_name_with_wrestler(winner,"Winner Pool #{pool}")
|
replace_loser_name_with_wrestler(winner_match, winner, "Winner Pool #{pool}") if winner_match
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -45,36 +50,40 @@ class PoolAdvance
|
|||||||
|
|
||||||
def winner_advance
|
def winner_advance
|
||||||
if @wrestler.last_match.bracket_position == "Quarter"
|
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
|
new_match = @matches.find { |m| m.bracket_position == "Semis" && m.bracket_position_number == @wrestler.next_match_position_number.ceil && m.weight_id == @wrestler.weight_id }
|
||||||
updateNewMatch(new_match)
|
updateNewMatch(new_match)
|
||||||
end
|
end
|
||||||
if @wrestler.last_match.bracket_position == "Semis"
|
if @wrestler.last_match.bracket_position == "Semis"
|
||||||
new_match = Match.where("bracket_position = ? AND bracket_position_number = ? AND weight_id = ?","1/2",@wrestler.next_match_position_number.ceil,@wrestler.weight_id).first
|
new_match = @matches.find { |m| m.bracket_position == "1/2" && m.bracket_position_number == @wrestler.next_match_position_number.ceil && m.weight_id == @wrestler.weight_id }
|
||||||
updateNewMatch(new_match)
|
updateNewMatch(new_match)
|
||||||
end
|
end
|
||||||
if @wrestler.last_match.bracket_position == "Conso Semis"
|
if @wrestler.last_match.bracket_position == "Conso Semis"
|
||||||
new_match = Match.where("bracket_position = ? AND bracket_position_number = ? AND weight_id = ?","5/6",@wrestler.next_match_position_number.ceil,@wrestler.weight_id).first
|
new_match = @matches.find { |m| m.bracket_position == "5/6" && m.bracket_position_number == @wrestler.next_match_position_number.ceil && m.weight_id == @wrestler.weight_id }
|
||||||
updateNewMatch(new_match)
|
updateNewMatch(new_match)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def updateNewMatch(match)
|
def updateNewMatch(match)
|
||||||
|
return unless match
|
||||||
if @wrestler.next_match_position_number == @wrestler.next_match_position_number.ceil
|
if @wrestler.next_match_position_number == @wrestler.next_match_position_number.ceil
|
||||||
match.w2 = @wrestler.id
|
match.w2 = @wrestler.id
|
||||||
match.save
|
|
||||||
end
|
end
|
||||||
if @wrestler.next_match_position_number != @wrestler.next_match_position_number.ceil
|
if @wrestler.next_match_position_number != @wrestler.next_match_position_number.ceil
|
||||||
match.w1 = @wrestler.id
|
match.w1 = @wrestler.id
|
||||||
match.save
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def loser_advance
|
def loser_advance
|
||||||
bout = @wrestler.last_match.bout_number
|
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)
|
next_match = @matches.find { |m| m.weight_id == @wrestler.weight_id && (m.loser1_name == "Loser of #{bout}" || m.loser2_name == "Loser of #{bout}") }
|
||||||
if next_match.size > 0
|
if next_match
|
||||||
next_match.first.replace_loser_name_with_wrestler(@wrestler,"Loser of #{bout}")
|
replace_loser_name_with_wrestler(next_match, @wrestler, "Loser of #{bout}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def replace_loser_name_with_wrestler(match, wrestler, loser_name)
|
||||||
|
match.w1 = wrestler.id if match.loser1_name == loser_name
|
||||||
|
match.w2 = wrestler.id if match.loser2_name == loser_name
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ class PoolOrder
|
|||||||
end
|
end
|
||||||
|
|
||||||
def getPoolOrder
|
def getPoolOrder
|
||||||
# clear caching for weight for bracket page
|
|
||||||
@wrestlers.first.weight.touch
|
|
||||||
setOriginalPoints
|
setOriginalPoints
|
||||||
while checkForTies(@wrestlers) == true
|
while checkForTies(@wrestlers) == true
|
||||||
getWrestlersOrderByPoolAdvancePoints.each do |wrestler|
|
getWrestlersOrderByPoolAdvancePoints.each do |wrestler|
|
||||||
@@ -18,7 +16,6 @@ class PoolOrder
|
|||||||
getWrestlersOrderByPoolAdvancePoints.each_with_index do |wrestler, index|
|
getWrestlersOrderByPoolAdvancePoints.each_with_index do |wrestler, index|
|
||||||
placement = index + 1
|
placement = index + 1
|
||||||
wrestler.pool_placement = placement
|
wrestler.pool_placement = placement
|
||||||
wrestler.save
|
|
||||||
end
|
end
|
||||||
@wrestlers.sort_by{|w| w.poolAdvancePoints}.reverse!
|
@wrestlers.sort_by{|w| w.poolAdvancePoints}.reverse!
|
||||||
end
|
end
|
||||||
@@ -29,7 +26,6 @@ class PoolOrder
|
|||||||
|
|
||||||
def setOriginalPoints
|
def setOriginalPoints
|
||||||
@wrestlers.each do |w|
|
@wrestlers.each do |w|
|
||||||
matches = w.reload.all_matches
|
|
||||||
w.pool_placement_tiebreaker = nil
|
w.pool_placement_tiebreaker = nil
|
||||||
w.pool_placement = nil
|
w.pool_placement = nil
|
||||||
w.poolAdvancePoints = w.pool_wins.size
|
w.poolAdvancePoints = w.pool_wins.size
|
||||||
|
|||||||
55
app/services/school_services/calculate_school_score.rb
Normal file
55
app/services/school_services/calculate_school_score.rb
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
class CalculateSchoolScore
|
||||||
|
def initialize(school)
|
||||||
|
@school = school
|
||||||
|
end
|
||||||
|
|
||||||
|
def calculate
|
||||||
|
school = preload_school_context
|
||||||
|
score = calculate_score_value(school)
|
||||||
|
persist_school_score(school.id, score)
|
||||||
|
score
|
||||||
|
end
|
||||||
|
|
||||||
|
def calculate_value
|
||||||
|
school = preload_school_context
|
||||||
|
calculate_score_value(school)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def preload_school_context
|
||||||
|
School
|
||||||
|
.includes(
|
||||||
|
:deductedPoints,
|
||||||
|
wrestlers: [
|
||||||
|
:deductedPoints,
|
||||||
|
{ matches_as_w1: :winner },
|
||||||
|
{ matches_as_w2: :winner },
|
||||||
|
{ weight: [:matches, { tournament: { weights: :wrestlers } }] }
|
||||||
|
]
|
||||||
|
)
|
||||||
|
.find(@school.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def calculate_score_value(school)
|
||||||
|
total_points_scored_by_wrestlers(school) - total_points_deducted(school)
|
||||||
|
end
|
||||||
|
|
||||||
|
def total_points_scored_by_wrestlers(school)
|
||||||
|
school.wrestlers.sum { |wrestler| CalculateWrestlerTeamScore.new(wrestler).totalScore }
|
||||||
|
end
|
||||||
|
|
||||||
|
def total_points_deducted(school)
|
||||||
|
school.deductedPoints.sum(&:points)
|
||||||
|
end
|
||||||
|
|
||||||
|
def persist_school_score(school_id, score)
|
||||||
|
School.upsert_all([
|
||||||
|
{
|
||||||
|
id: school_id,
|
||||||
|
score: score,
|
||||||
|
updated_at: Time.current
|
||||||
|
}
|
||||||
|
])
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -3,30 +3,30 @@ class DoubleEliminationGenerateLoserNames
|
|||||||
@tournament = tournament
|
@tournament = tournament
|
||||||
end
|
end
|
||||||
|
|
||||||
# Entry point: assign loser placeholders and advance any byes
|
# Compatibility wrapper. Returns transformed rows and does not persist.
|
||||||
def assign_loser_names
|
def assign_loser_names(match_rows = nil)
|
||||||
|
rows = match_rows || @tournament.matches.where(tournament_id: @tournament.id).map { |m| m.attributes.symbolize_keys }
|
||||||
@tournament.weights.each do |weight|
|
@tournament.weights.each do |weight|
|
||||||
assign_loser_names_for_weight(weight)
|
next unless weight.calculate_bracket_size > 2
|
||||||
advance_bye_matches_championship(weight)
|
|
||||||
advance_bye_matches_consolation(weight)
|
assign_loser_names_in_memory(weight, rows)
|
||||||
|
assign_bye_outcomes_in_memory(weight, rows)
|
||||||
end
|
end
|
||||||
|
rows
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
def assign_loser_names_in_memory(weight, match_rows)
|
||||||
|
|
||||||
# Assign loser names for a single weight bracket
|
|
||||||
def assign_loser_names_for_weight(weight)
|
|
||||||
bracket_size = weight.calculate_bracket_size
|
bracket_size = weight.calculate_bracket_size
|
||||||
matches = weight.matches.reload
|
return if bracket_size <= 2
|
||||||
num_placers = @tournament.number_of_placers
|
|
||||||
|
rows = match_rows.select { |row| row[:weight_id] == weight.id }
|
||||||
|
num_placers = @tournament.number_of_placers
|
||||||
|
|
||||||
# Build dynamic round definitions
|
|
||||||
champ_rounds = dynamic_championship_rounds(bracket_size)
|
champ_rounds = dynamic_championship_rounds(bracket_size)
|
||||||
conso_rounds = dynamic_consolation_rounds(bracket_size)
|
conso_rounds = dynamic_consolation_rounds(bracket_size)
|
||||||
first_round = { bracket_position: first_round_label(bracket_size) }
|
first_round = { bracket_position: first_round_label(bracket_size) }
|
||||||
champ_full = [first_round] + champ_rounds
|
champ_full = [first_round] + champ_rounds
|
||||||
|
|
||||||
# Map championship losers into consolation slots
|
|
||||||
mappings = []
|
mappings = []
|
||||||
champ_full[0...-1].each_with_index do |champ_info, i|
|
champ_full[0...-1].each_with_index do |champ_info, i|
|
||||||
map_idx = i.zero? ? 0 : (2 * i - 1)
|
map_idx = i.zero? ? 0 : (2 * i - 1)
|
||||||
@@ -34,128 +34,109 @@ class DoubleEliminationGenerateLoserNames
|
|||||||
|
|
||||||
mappings << {
|
mappings << {
|
||||||
championship_bracket_position: champ_info[:bracket_position],
|
championship_bracket_position: champ_info[:bracket_position],
|
||||||
consolation_bracket_position: conso_rounds[map_idx][:bracket_position],
|
consolation_bracket_position: conso_rounds[map_idx][:bracket_position],
|
||||||
both_wrestlers: i.zero?,
|
both_wrestlers: i.zero?,
|
||||||
champ_round_index: i
|
champ_round_index: i
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Apply loser-name mappings
|
|
||||||
mappings.each do |map|
|
mappings.each do |map|
|
||||||
champ = matches.select { |m| m.bracket_position == map[:championship_bracket_position] }
|
champ = rows.select { |r| r[:bracket_position] == map[:championship_bracket_position] }
|
||||||
.sort_by(&:bracket_position_number)
|
.sort_by { |r| r[:bracket_position_number] }
|
||||||
conso = matches.select { |m| m.bracket_position == map[:consolation_bracket_position] }
|
conso = rows.select { |r| r[:bracket_position] == map[:consolation_bracket_position] }
|
||||||
.sort_by(&:bracket_position_number)
|
.sort_by { |r| r[:bracket_position_number] }
|
||||||
|
conso.reverse! if map[:champ_round_index].odd?
|
||||||
current_champ_round_index = map[:champ_round_index]
|
|
||||||
if current_champ_round_index.odd?
|
|
||||||
conso.reverse!
|
|
||||||
end
|
|
||||||
|
|
||||||
idx = 0
|
idx = 0
|
||||||
# Determine if this mapping is for losers from the first championship round
|
is_first_feed = map[:champ_round_index].zero?
|
||||||
is_first_champ_round_feed = map[:champ_round_index].zero?
|
|
||||||
|
|
||||||
conso.each do |cm|
|
conso.each do |cm|
|
||||||
champ_match1 = champ[idx]
|
champ_match1 = champ[idx]
|
||||||
if champ_match1
|
if champ_match1
|
||||||
if is_first_champ_round_feed && ((champ_match1.w1 && champ_match1.w2.nil?) || (champ_match1.w1.nil? && champ_match1.w2))
|
if is_first_feed && single_competitor_match_row?(champ_match1)
|
||||||
cm.loser1_name = "BYE"
|
cm[:loser1_name] = "BYE"
|
||||||
else
|
else
|
||||||
cm.loser1_name = "Loser of #{champ_match1.bout_number}"
|
cm[:loser1_name] = "Loser of #{champ_match1[:bout_number]}"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
cm.loser1_name = nil # Should not happen if bracket generation is correct
|
cm[:loser1_name] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if map[:both_wrestlers] # This is true only if is_first_champ_round_feed
|
if map[:both_wrestlers]
|
||||||
idx += 1 # Increment for the second championship match
|
idx += 1
|
||||||
champ_match2 = champ[idx]
|
champ_match2 = champ[idx]
|
||||||
if champ_match2
|
if champ_match2
|
||||||
# BYE check is only relevant for the first championship round feed
|
if is_first_feed && single_competitor_match_row?(champ_match2)
|
||||||
if is_first_champ_round_feed && ((champ_match2.w1 && champ_match2.w2.nil?) || (champ_match2.w1.nil? && champ_match2.w2))
|
cm[:loser2_name] = "BYE"
|
||||||
cm.loser2_name = "BYE"
|
|
||||||
else
|
else
|
||||||
cm.loser2_name = "Loser of #{champ_match2.bout_number}"
|
cm[:loser2_name] = "Loser of #{champ_match2[:bout_number]}"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
cm.loser2_name = nil # Should not happen
|
cm[:loser2_name] = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
idx += 1 # Increment for the next consolation match or next pair from championship
|
idx += 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# 5th/6th place
|
if bracket_size >= 5 && num_placers >= 6 && weight.wrestlers.size > 4
|
||||||
if bracket_size >= 5 && num_placers >= 6
|
conso_semis = rows.select { |r| r[:bracket_position] == "Conso Semis" }.sort_by { |r| r[:bracket_position_number] }
|
||||||
conso_semis = matches.select { |m| m.bracket_position == "Conso Semis" }
|
m56 = rows.find { |r| r[:bracket_position] == "5/6" }
|
||||||
.sort_by(&:bracket_position_number)
|
if conso_semis.size >= 2 && m56
|
||||||
if conso_semis.size >= 2
|
m56[:loser1_name] = "Loser of #{conso_semis[0][:bout_number]}"
|
||||||
m56 = matches.find { |m| m.bracket_position == "5/6" }
|
m56[:loser2_name] = "Loser of #{conso_semis[1][:bout_number]}"
|
||||||
m56.loser1_name = "Loser of #{conso_semis[0].bout_number}"
|
|
||||||
m56.loser2_name = "Loser of #{conso_semis[1].bout_number}" if m56
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# 7th/8th place
|
if bracket_size >= 7 && num_placers >= 8 && weight.wrestlers.size > 6
|
||||||
if bracket_size >= 7 && num_placers >= 8
|
conso_quarters = rows.select { |r| r[:bracket_position] == "Conso Quarter" }.sort_by { |r| r[:bracket_position_number] }
|
||||||
conso_quarters = matches.select { |m| m.bracket_position == "Conso Quarter" }
|
m78 = rows.find { |r| r[:bracket_position] == "7/8" }
|
||||||
.sort_by(&:bracket_position_number)
|
if conso_quarters.size >= 2 && m78
|
||||||
if conso_quarters.size >= 2
|
m78[:loser1_name] = "Loser of #{conso_quarters[0][:bout_number]}"
|
||||||
m78 = matches.find { |m| m.bracket_position == "7/8" }
|
m78[:loser2_name] = "Loser of #{conso_quarters[1][:bout_number]}"
|
||||||
m78.loser1_name = "Loser of #{conso_quarters[0].bout_number}"
|
|
||||||
m78.loser2_name = "Loser of #{conso_quarters[1].bout_number}" if m78
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
matches.each(&:save!)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Advance first-round byes in championship bracket
|
def assign_bye_outcomes_in_memory(weight, match_rows)
|
||||||
def advance_bye_matches_championship(weight)
|
|
||||||
matches = weight.matches.reload
|
|
||||||
first_round = matches.map(&:round).min
|
|
||||||
matches.select { |m| m.round == first_round }
|
|
||||||
.sort_by(&:bracket_position_number)
|
|
||||||
.each { |m| handle_bye(m) }
|
|
||||||
end
|
|
||||||
|
|
||||||
# Advance first-round byes in consolation bracket
|
|
||||||
def advance_bye_matches_consolation(weight)
|
|
||||||
matches = weight.matches.reload
|
|
||||||
bracket_size = weight.calculate_bracket_size
|
bracket_size = weight.calculate_bracket_size
|
||||||
first_conso = dynamic_consolation_rounds(bracket_size).first
|
return if bracket_size <= 2
|
||||||
|
|
||||||
matches.select { |m| m.round == first_conso[:round] && m.bracket_position == first_conso[:bracket_position] }
|
rows = match_rows.select { |r| r[:weight_id] == weight.id }
|
||||||
.sort_by(&:bracket_position_number)
|
first_round = rows.map { |r| r[:round] }.compact.min
|
||||||
.each { |m| handle_bye(m) }
|
rows.select { |r| r[:round] == first_round }.each { |row| apply_bye_to_row(row) }
|
||||||
end
|
|
||||||
|
|
||||||
# Mark bye match, set finished, and advance
|
first_conso = dynamic_consolation_rounds(bracket_size).first
|
||||||
def handle_bye(match)
|
if first_conso
|
||||||
if [match.w1, match.w2].compact.size == 1
|
rows.select { |r| r[:round] == first_conso[:round] && r[:bracket_position] == first_conso[:bracket_position] }
|
||||||
match.finished = 1
|
.each { |row| apply_bye_to_row(row) }
|
||||||
match.win_type = 'BYE'
|
|
||||||
if match.w1
|
|
||||||
match.winner_id = match.w1
|
|
||||||
match.loser2_name = 'BYE'
|
|
||||||
else
|
|
||||||
match.winner_id = match.w2
|
|
||||||
match.loser1_name = 'BYE'
|
|
||||||
end
|
|
||||||
match.score = ''
|
|
||||||
match.save!
|
|
||||||
match.advance_wrestlers
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helpers for dynamic bracket labels
|
def apply_bye_to_row(row)
|
||||||
|
return unless single_competitor_match_row?(row)
|
||||||
|
|
||||||
|
row[:finished] = 1
|
||||||
|
row[:win_type] = "BYE"
|
||||||
|
if row[:w1]
|
||||||
|
row[:winner_id] = row[:w1]
|
||||||
|
row[:loser2_name] = "BYE"
|
||||||
|
else
|
||||||
|
row[:winner_id] = row[:w2]
|
||||||
|
row[:loser1_name] = "BYE"
|
||||||
|
end
|
||||||
|
row[:score] = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
def single_competitor_match_row?(row)
|
||||||
|
[row[:w1], row[:w2]].compact.size == 1
|
||||||
|
end
|
||||||
|
|
||||||
def first_round_label(size)
|
def first_round_label(size)
|
||||||
case size
|
case size
|
||||||
when 2 then 'Final'
|
when 2 then "Final"
|
||||||
when 4 then 'Semis'
|
when 4 then "Semis"
|
||||||
when 8 then 'Quarter'
|
when 8 then "Quarter"
|
||||||
else "Bracket Round of #{size}"
|
else "Bracket Round of #{size}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -170,36 +151,36 @@ class DoubleEliminationGenerateLoserNames
|
|||||||
def dynamic_consolation_rounds(size)
|
def dynamic_consolation_rounds(size)
|
||||||
total_log2 = Math.log2(size).to_i
|
total_log2 = Math.log2(size).to_i
|
||||||
return [] if total_log2 <= 1
|
return [] if total_log2 <= 1
|
||||||
|
|
||||||
max_j_val = (2 * (total_log2 - 1) - 1)
|
max_j_val = (2 * (total_log2 - 1) - 1)
|
||||||
(1..max_j_val).map do |j|
|
(1..max_j_val).map do |j|
|
||||||
current_participants = size / (2**((j.to_f / 2).ceil))
|
current_participants = size / (2**((j.to_f / 2).ceil))
|
||||||
{
|
{
|
||||||
bracket_position: consolation_label(current_participants, j, size),
|
bracket_position: consolation_label(current_participants, j, size),
|
||||||
round: j
|
round: j
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def bracket_label(participants)
|
def bracket_label(participants)
|
||||||
case participants
|
case participants
|
||||||
when 2 then '1/2'
|
when 2 then "1/2"
|
||||||
when 4 then 'Semis'
|
when 4 then "Semis"
|
||||||
when 8 then 'Quarter'
|
when 8 then "Quarter"
|
||||||
else "Bracket Round of #{participants}"
|
else "Bracket Round of #{participants}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def consolation_label(participants, j, bracket_size)
|
def consolation_label(participants, j, bracket_size)
|
||||||
max_j_for_bracket = (2 * (Math.log2(bracket_size).to_i - 1) - 1)
|
max_j_for_bracket = (2 * (Math.log2(bracket_size).to_i - 1) - 1)
|
||||||
|
|
||||||
if participants == 2 && j == max_j_for_bracket
|
if participants == 2 && j == max_j_for_bracket
|
||||||
return '3/4'
|
"3/4"
|
||||||
elsif participants == 4
|
elsif participants == 4
|
||||||
return j.odd? ? 'Conso Quarter' : 'Conso Semis'
|
j.odd? ? "Conso Quarter" : "Conso Semis"
|
||||||
else
|
else
|
||||||
suffix = j.odd? ? ".1" : ".2"
|
suffix = j.odd? ? ".1" : ".2"
|
||||||
return "Conso Round of #{participants}#{suffix}"
|
"Conso Round of #{participants}#{suffix}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,29 +1,33 @@
|
|||||||
class DoubleEliminationMatchGeneration
|
class DoubleEliminationMatchGeneration
|
||||||
def initialize(tournament)
|
def initialize(tournament, weights: nil)
|
||||||
@tournament = tournament
|
@tournament = tournament
|
||||||
|
@weights = weights
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_matches
|
def generate_matches
|
||||||
#
|
build_match_rows
|
||||||
# PHASE 1: Generate matches (with local round definitions).
|
end
|
||||||
#
|
|
||||||
@tournament.weights.each do |weight|
|
def build_match_rows
|
||||||
generate_matches_for_weight(weight)
|
rows_by_weight_id = {}
|
||||||
|
|
||||||
|
generation_weights.each do |weight|
|
||||||
|
rows_by_weight_id[weight.id] = generate_match_rows_for_weight(weight)
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
align_rows_to_largest_bracket(rows_by_weight_id)
|
||||||
# PHASE 2: Align all rounds to match the largest bracket’s definitions.
|
rows_by_weight_id.values.flatten
|
||||||
#
|
|
||||||
align_all_rounds_to_largest_bracket
|
|
||||||
end
|
end
|
||||||
|
|
||||||
###########################################################################
|
###########################################################################
|
||||||
# PHASE 1: Generate all matches for each bracket, using a single definition.
|
# PHASE 1: Generate all matches for each bracket, using a single definition.
|
||||||
###########################################################################
|
###########################################################################
|
||||||
def generate_matches_for_weight(weight)
|
def generate_match_rows_for_weight(weight)
|
||||||
bracket_size = weight.calculate_bracket_size
|
bracket_size = weight.calculate_bracket_size
|
||||||
bracket_info = define_bracket_matches(bracket_size)
|
bracket_info = define_bracket_matches(bracket_size)
|
||||||
return unless bracket_info
|
return [] unless bracket_info
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
|
||||||
# 1) Round one matchups
|
# 1) Round one matchups
|
||||||
bracket_info[:round_one_matchups].each_with_index do |matchup, idx|
|
bracket_info[:round_one_matchups].each_with_index do |matchup, idx|
|
||||||
@@ -32,7 +36,7 @@ class DoubleEliminationMatchGeneration
|
|||||||
bracket_pos_number = idx + 1
|
bracket_pos_number = idx + 1
|
||||||
round_number = matchup[:round]
|
round_number = matchup[:round]
|
||||||
|
|
||||||
create_matchup_from_seed(
|
rows << create_matchup_from_seed(
|
||||||
seed1,
|
seed1,
|
||||||
seed2,
|
seed2,
|
||||||
bracket_position,
|
bracket_position,
|
||||||
@@ -49,7 +53,7 @@ class DoubleEliminationMatchGeneration
|
|||||||
round_number = round_info[:round]
|
round_number = round_info[:round]
|
||||||
|
|
||||||
matches_this_round.times do |i|
|
matches_this_round.times do |i|
|
||||||
create_matchup(
|
rows << create_matchup(
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
bracket_position,
|
bracket_position,
|
||||||
@@ -67,7 +71,7 @@ class DoubleEliminationMatchGeneration
|
|||||||
round_number = round_info[:round]
|
round_number = round_info[:round]
|
||||||
|
|
||||||
matches_this_round.times do |i|
|
matches_this_round.times do |i|
|
||||||
create_matchup(
|
rows << create_matchup(
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
bracket_position,
|
bracket_position,
|
||||||
@@ -79,12 +83,14 @@ class DoubleEliminationMatchGeneration
|
|||||||
|
|
||||||
# 5/6, 7/8 placing logic
|
# 5/6, 7/8 placing logic
|
||||||
if weight.wrestlers.size >= 5 && @tournament.number_of_placers >= 6 && matches_this_round == 1
|
if weight.wrestlers.size >= 5 && @tournament.number_of_placers >= 6 && matches_this_round == 1
|
||||||
create_matchup(nil, nil, "5/6", 1, round_number, weight)
|
rows << create_matchup(nil, nil, "5/6", 1, round_number, weight)
|
||||||
end
|
end
|
||||||
if weight.wrestlers.size >= 7 && @tournament.number_of_placers >= 8 && matches_this_round == 1
|
if weight.wrestlers.size >= 7 && @tournament.number_of_placers >= 8 && matches_this_round == 1
|
||||||
create_matchup(nil, nil, "7/8", 1, round_number, weight)
|
rows << create_matchup(nil, nil, "7/8", 1, round_number, weight)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
rows
|
||||||
end
|
end
|
||||||
|
|
||||||
# Single bracket definition dynamically generated for any power-of-two bracket size.
|
# Single bracket definition dynamically generated for any power-of-two bracket size.
|
||||||
@@ -173,18 +179,18 @@ class DoubleEliminationMatchGeneration
|
|||||||
###########################################################################
|
###########################################################################
|
||||||
# PHASE 2: Overwrite rounds in all smaller brackets to match the largest one.
|
# PHASE 2: Overwrite rounds in all smaller brackets to match the largest one.
|
||||||
###########################################################################
|
###########################################################################
|
||||||
def align_all_rounds_to_largest_bracket
|
def align_rows_to_largest_bracket(rows_by_weight_id)
|
||||||
largest_weight = @tournament.weights.max_by { |w| w.calculate_bracket_size }
|
largest_weight = generation_weights.max_by { |w| w.calculate_bracket_size }
|
||||||
return unless largest_weight
|
return unless largest_weight
|
||||||
|
|
||||||
position_to_round = {}
|
position_to_round = {}
|
||||||
largest_weight.tournament.matches.where(weight_id: largest_weight.id).each do |m|
|
rows_by_weight_id.fetch(largest_weight.id, []).each do |row|
|
||||||
position_to_round[m.bracket_position] ||= m.round
|
position_to_round[row[:bracket_position]] ||= row[:round]
|
||||||
end
|
end
|
||||||
|
|
||||||
@tournament.matches.find_each do |match|
|
rows_by_weight_id.each_value do |rows|
|
||||||
if position_to_round.key?(match.bracket_position)
|
rows.each do |row|
|
||||||
match.update(round: position_to_round[match.bracket_position])
|
row[:round] = position_to_round[row[:bracket_position]] if position_to_round.key?(row[:bracket_position])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -192,8 +198,12 @@ class DoubleEliminationMatchGeneration
|
|||||||
###########################################################################
|
###########################################################################
|
||||||
# Helper methods
|
# Helper methods
|
||||||
###########################################################################
|
###########################################################################
|
||||||
|
def generation_weights
|
||||||
|
@weights || @tournament.weights.to_a
|
||||||
|
end
|
||||||
|
|
||||||
def wrestler_with_seed(seed, weight)
|
def wrestler_with_seed(seed, weight)
|
||||||
Wrestler.where("weight_id = ? AND bracket_line = ?", weight.id, seed).first&.id
|
weight.wrestlers.find { |w| w.bracket_line == seed }&.id
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_matchup_from_seed(w1_seed, w2_seed, bracket_position, bracket_position_number, round, weight)
|
def create_matchup_from_seed(w1_seed, w2_seed, bracket_position, bracket_position_number, round, weight)
|
||||||
@@ -208,14 +218,15 @@ class DoubleEliminationMatchGeneration
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create_matchup(w1, w2, bracket_position, bracket_position_number, round, weight)
|
def create_matchup(w1, w2, bracket_position, bracket_position_number, round, weight)
|
||||||
weight.tournament.matches.create!(
|
{
|
||||||
w1: w1,
|
w1: w1,
|
||||||
w2: w2,
|
w2: w2,
|
||||||
|
tournament_id: weight.tournament_id,
|
||||||
weight_id: weight.id,
|
weight_id: weight.id,
|
||||||
round: round,
|
round: round,
|
||||||
bracket_position: bracket_position,
|
bracket_position: bracket_position,
|
||||||
bracket_position_number: bracket_position_number
|
bracket_position_number: bracket_position_number
|
||||||
)
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Calculates the sequence of seeds for the first round of a power-of-two bracket.
|
# Calculates the sequence of seeds for the first round of a power-of-two bracket.
|
||||||
|
|||||||
@@ -10,62 +10,183 @@ class GenerateTournamentMatches
|
|||||||
|
|
||||||
def generate_raw
|
def generate_raw
|
||||||
standardStartingActions
|
standardStartingActions
|
||||||
PoolToBracketMatchGeneration.new(@tournament).generatePoolToBracketMatches if @tournament.tournament_type == "Pool to bracket"
|
generation_context = preload_generation_context
|
||||||
ModifiedSixteenManMatchGeneration.new(@tournament).generate_matches if @tournament.tournament_type.include? "Modified 16 Man Double Elimination"
|
seed_wrestlers_in_memory(generation_context)
|
||||||
DoubleEliminationMatchGeneration.new(@tournament).generate_matches if @tournament.tournament_type.include? "Regular Double Elimination"
|
match_rows = build_match_rows(generation_context)
|
||||||
|
post_process_match_rows_in_memory(generation_context, match_rows)
|
||||||
|
persist_generation_rows(generation_context, match_rows)
|
||||||
postMatchCreationActions
|
postMatchCreationActions
|
||||||
PoolToBracketMatchGeneration.new(@tournament).assignLoserNames if @tournament.tournament_type == "Pool to bracket"
|
advance_bye_matches_after_insert
|
||||||
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
|
end
|
||||||
|
|
||||||
def standardStartingActions
|
def standardStartingActions
|
||||||
@tournament.curently_generating_matches = 1
|
@tournament.curently_generating_matches = 1
|
||||||
@tournament.save
|
@tournament.save
|
||||||
WipeTournamentMatches.new(@tournament).setUpMatchGeneration
|
WipeTournamentMatches.new(@tournament).setUpMatchGeneration
|
||||||
TournamentSeeding.new(@tournament).set_seeds
|
end
|
||||||
|
|
||||||
|
def preload_generation_context
|
||||||
|
weights = @tournament.weights.includes(:wrestlers).order(:max).to_a
|
||||||
|
wrestlers = weights.flat_map(&:wrestlers)
|
||||||
|
{
|
||||||
|
weights: weights,
|
||||||
|
wrestlers: wrestlers,
|
||||||
|
wrestlers_by_weight_id: wrestlers.group_by(&:weight_id)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def seed_wrestlers_in_memory(generation_context)
|
||||||
|
TournamentSeeding.new(@tournament).set_seeds(weights: generation_context[:weights], persist: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_match_rows(generation_context)
|
||||||
|
return PoolToBracketMatchGeneration.new(
|
||||||
|
@tournament,
|
||||||
|
weights: generation_context[:weights],
|
||||||
|
wrestlers_by_weight_id: generation_context[:wrestlers_by_weight_id]
|
||||||
|
).generatePoolToBracketMatches if @tournament.tournament_type == "Pool to bracket"
|
||||||
|
|
||||||
|
return ModifiedSixteenManMatchGeneration.new(@tournament, weights: generation_context[:weights]).generate_matches if @tournament.tournament_type.include? "Modified 16 Man Double Elimination"
|
||||||
|
|
||||||
|
return DoubleEliminationMatchGeneration.new(@tournament, weights: generation_context[:weights]).generate_matches if @tournament.tournament_type.include? "Regular Double Elimination"
|
||||||
|
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
def persist_generation_rows(generation_context, match_rows)
|
||||||
|
persist_wrestlers(generation_context[:wrestlers])
|
||||||
|
persist_matches(match_rows)
|
||||||
|
end
|
||||||
|
|
||||||
|
def post_process_match_rows_in_memory(generation_context, match_rows)
|
||||||
|
move_finals_rows_to_last_round(match_rows) unless @tournament.tournament_type.include?("Regular Double Elimination")
|
||||||
|
assign_bouts_in_memory(match_rows, generation_context[:weights])
|
||||||
|
assign_loser_names_in_memory(generation_context, match_rows)
|
||||||
|
assign_bye_outcomes_in_memory(generation_context, match_rows)
|
||||||
|
end
|
||||||
|
|
||||||
|
def persist_wrestlers(wrestlers)
|
||||||
|
return if wrestlers.blank?
|
||||||
|
|
||||||
|
timestamp = Time.current
|
||||||
|
rows = wrestlers.map do |w|
|
||||||
|
{
|
||||||
|
id: w.id,
|
||||||
|
bracket_line: w.bracket_line,
|
||||||
|
pool: w.pool,
|
||||||
|
updated_at: timestamp
|
||||||
|
}
|
||||||
|
end
|
||||||
|
Wrestler.upsert_all(rows)
|
||||||
|
end
|
||||||
|
|
||||||
|
def persist_matches(match_rows)
|
||||||
|
return if match_rows.blank?
|
||||||
|
|
||||||
|
timestamp = Time.current
|
||||||
|
rows_with_timestamps = match_rows.map do |row|
|
||||||
|
row.to_h.symbolize_keys.merge(created_at: timestamp, updated_at: timestamp)
|
||||||
|
end
|
||||||
|
|
||||||
|
all_keys = rows_with_timestamps.flat_map(&:keys).uniq
|
||||||
|
normalized_rows = rows_with_timestamps.map do |row|
|
||||||
|
all_keys.each_with_object({}) { |key, normalized| normalized[key] = row[key] }
|
||||||
|
end
|
||||||
|
|
||||||
|
Match.insert_all!(normalized_rows)
|
||||||
end
|
end
|
||||||
|
|
||||||
def postMatchCreationActions
|
def postMatchCreationActions
|
||||||
moveFinalsMatchesToLastRound if ! @tournament.tournament_type.include? "Regular Double Elimination"
|
|
||||||
assignBouts
|
|
||||||
@tournament.reset_and_fill_bout_board
|
@tournament.reset_and_fill_bout_board
|
||||||
@tournament.curently_generating_matches = nil
|
@tournament.curently_generating_matches = nil
|
||||||
@tournament.save!
|
@tournament.save!
|
||||||
|
Tournament.broadcast_up_matches_board(@tournament.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def move_finals_rows_to_last_round(match_rows)
|
||||||
|
finals_round = match_rows.map { |row| row[:round] }.compact.max
|
||||||
|
return unless finals_round
|
||||||
|
|
||||||
|
match_rows.each do |row|
|
||||||
|
row[:round] = finals_round if ["1/2", "3/4", "5/6", "7/8"].include?(row[:bracket_position])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_bouts_in_memory(match_rows, weights)
|
||||||
|
bout_counts = Hash.new(0)
|
||||||
|
weight_max_by_id = weights.each_with_object({}) { |w, memo| memo[w.id] = w.max }
|
||||||
|
|
||||||
|
match_rows
|
||||||
|
.sort_by { |row| [row[:round].to_i, weight_max_by_id[row[:weight_id]].to_f, row[:weight_id].to_i, row[:bracket_position_number].to_i] }
|
||||||
|
.each do |row|
|
||||||
|
round = row[:round].to_i
|
||||||
|
row[:bout_number] = round * 1000 + bout_counts[round]
|
||||||
|
bout_counts[round] += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_loser_names_in_memory(generation_context, match_rows)
|
||||||
|
if @tournament.tournament_type == "Pool to bracket"
|
||||||
|
service = PoolToBracketGenerateLoserNames.new(@tournament)
|
||||||
|
generation_context[:weights].each { |weight| service.assign_loser_names_in_memory(weight, match_rows) }
|
||||||
|
elsif @tournament.tournament_type.include?("Modified 16 Man Double Elimination")
|
||||||
|
service = ModifiedSixteenManGenerateLoserNames.new(@tournament)
|
||||||
|
generation_context[:weights].each { |weight| service.assign_loser_names_in_memory(weight, match_rows) }
|
||||||
|
elsif @tournament.tournament_type.include?("Regular Double Elimination")
|
||||||
|
service = DoubleEliminationGenerateLoserNames.new(@tournament)
|
||||||
|
generation_context[:weights].each { |weight| service.assign_loser_names_in_memory(weight, match_rows) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_bye_outcomes_in_memory(generation_context, match_rows)
|
||||||
|
if @tournament.tournament_type.include?("Modified 16 Man Double Elimination")
|
||||||
|
service = ModifiedSixteenManGenerateLoserNames.new(@tournament)
|
||||||
|
generation_context[:weights].each { |weight| service.assign_bye_outcomes_in_memory(weight, match_rows) }
|
||||||
|
elsif @tournament.tournament_type.include?("Regular Double Elimination")
|
||||||
|
service = DoubleEliminationGenerateLoserNames.new(@tournament)
|
||||||
|
generation_context[:weights].each { |weight| service.assign_bye_outcomes_in_memory(weight, match_rows) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def advance_bye_matches_after_insert
|
||||||
|
Match.where(tournament_id: @tournament.id, finished: 1, win_type: "BYE")
|
||||||
|
.where.not(winner_id: nil)
|
||||||
|
.find_each(&:advance_wrestlers)
|
||||||
end
|
end
|
||||||
|
|
||||||
def assignBouts
|
def assignBouts
|
||||||
bout_counts = Hash.new(0)
|
bout_counts = Hash.new(0)
|
||||||
@tournament.matches.reload
|
timestamp = Time.current
|
||||||
@tournament.matches.sort_by{|m| [m.round, m.weight_max]}.each do |m|
|
ordered_matches = Match.joins(:weight)
|
||||||
m.bout_number = m.round * 1000 + bout_counts[m.round]
|
.where(tournament_id: @tournament.id)
|
||||||
bout_counts[m.round] += 1
|
.order("matches.round ASC, weights.max ASC, matches.id ASC")
|
||||||
m.save!
|
.pluck("matches.id", "matches.round")
|
||||||
|
|
||||||
|
updates = []
|
||||||
|
ordered_matches.each do |match_id, round|
|
||||||
|
updates << {
|
||||||
|
id: match_id,
|
||||||
|
bout_number: round * 1000 + bout_counts[round],
|
||||||
|
updated_at: timestamp
|
||||||
|
}
|
||||||
|
bout_counts[round] += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Match.upsert_all(updates) if updates.any?
|
||||||
end
|
end
|
||||||
|
|
||||||
def moveFinalsMatchesToLastRound
|
def moveFinalsMatchesToLastRound
|
||||||
finalsRound = @tournament.reload.total_rounds
|
finalsRound = @tournament.reload.total_rounds
|
||||||
finalsMatches = @tournament.matches.reload.select{|m| m.bracket_position == "1/2" || m.bracket_position == "3/4" || m.bracket_position == "5/6" || m.bracket_position == "7/8"}
|
@tournament.matches
|
||||||
finalsMatches. each do |m|
|
.where(bracket_position: ["1/2", "3/4", "5/6", "7/8"])
|
||||||
m.round = finalsRound
|
.update_all(round: finalsRound, updated_at: Time.current)
|
||||||
m.save
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def unAssignMats
|
def unAssignMats
|
||||||
matches = @tournament.matches.reload
|
@tournament.matches.update_all(mat_id: nil, updated_at: Time.current)
|
||||||
matches.each do |m|
|
|
||||||
m.mat_id = nil
|
|
||||||
m.save!
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def unAssignBouts
|
def unAssignBouts
|
||||||
bout_counts = Hash.new(0)
|
@tournament.matches.update_all(bout_number: nil, updated_at: Time.current)
|
||||||
@tournament.matches.each do |m|
|
|
||||||
m.bout_number = nil
|
|
||||||
m.save!
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,95 +1,91 @@
|
|||||||
class ModifiedSixteenManGenerateLoserNames
|
class ModifiedSixteenManGenerateLoserNames
|
||||||
def initialize( tournament )
|
def initialize(tournament)
|
||||||
@tournament = tournament
|
@tournament = tournament
|
||||||
|
end
|
||||||
|
|
||||||
|
# Compatibility wrapper. Returns transformed rows and does not persist.
|
||||||
|
def assign_loser_names(match_rows = nil)
|
||||||
|
rows = match_rows || @tournament.matches.where(tournament_id: @tournament.id).map { |m| m.attributes.symbolize_keys }
|
||||||
|
@tournament.weights.each do |weight|
|
||||||
|
assign_loser_names_in_memory(weight, rows)
|
||||||
|
assign_bye_outcomes_in_memory(weight, rows)
|
||||||
|
end
|
||||||
|
rows
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_loser_names_in_memory(weight, match_rows)
|
||||||
|
rows = match_rows.select { |row| row[:weight_id] == weight.id }
|
||||||
|
round_16 = rows.select { |r| r[:bracket_position] == "Bracket Round of 16" }
|
||||||
|
conso_8 = rows.select { |r| r[:bracket_position] == "Conso Round of 8" }.sort_by { |r| r[:bracket_position_number] }
|
||||||
|
|
||||||
|
conso_8.each do |row|
|
||||||
|
if row[:bracket_position_number] == 1
|
||||||
|
m1 = round_16.find { |m| m[:bracket_position_number] == 1 }
|
||||||
|
m2 = round_16.find { |m| m[:bracket_position_number] == 2 }
|
||||||
|
row[:loser1_name] = "Loser of #{m1[:bout_number]}" if m1
|
||||||
|
row[:loser2_name] = "Loser of #{m2[:bout_number]}" if m2
|
||||||
|
elsif row[:bracket_position_number] == 2
|
||||||
|
m3 = round_16.find { |m| m[:bracket_position_number] == 3 }
|
||||||
|
m4 = round_16.find { |m| m[:bracket_position_number] == 4 }
|
||||||
|
row[:loser1_name] = "Loser of #{m3[:bout_number]}" if m3
|
||||||
|
row[:loser2_name] = "Loser of #{m4[:bout_number]}" if m4
|
||||||
|
elsif row[:bracket_position_number] == 3
|
||||||
|
m5 = round_16.find { |m| m[:bracket_position_number] == 5 }
|
||||||
|
m6 = round_16.find { |m| m[:bracket_position_number] == 6 }
|
||||||
|
row[:loser1_name] = "Loser of #{m5[:bout_number]}" if m5
|
||||||
|
row[:loser2_name] = "Loser of #{m6[:bout_number]}" if m6
|
||||||
|
elsif row[:bracket_position_number] == 4
|
||||||
|
m7 = round_16.find { |m| m[:bracket_position_number] == 7 }
|
||||||
|
m8 = round_16.find { |m| m[:bracket_position_number] == 8 }
|
||||||
|
row[:loser1_name] = "Loser of #{m7[:bout_number]}" if m7
|
||||||
|
row[:loser2_name] = "Loser of #{m8[:bout_number]}" if m8
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def assign_loser_names
|
quarters = rows.select { |r| r[:bracket_position] == "Quarter" }
|
||||||
matches_by_weight = nil
|
conso_quarters = rows.select { |r| r[:bracket_position] == "Conso Quarter" }.sort_by { |r| r[:bracket_position_number] }
|
||||||
@tournament.weights.each do |w|
|
conso_quarters.each do |row|
|
||||||
matches_by_weight = @tournament.matches.where(weight_id: w.id)
|
source = case row[:bracket_position_number]
|
||||||
conso_round_2(matches_by_weight)
|
when 1 then quarters.find { |q| q[:bracket_position_number] == 4 }
|
||||||
conso_round_3(matches_by_weight)
|
when 2 then quarters.find { |q| q[:bracket_position_number] == 3 }
|
||||||
third_fourth(matches_by_weight)
|
when 3 then quarters.find { |q| q[:bracket_position_number] == 2 }
|
||||||
seventh_eighth(matches_by_weight)
|
when 4 then quarters.find { |q| q[:bracket_position_number] == 1 }
|
||||||
save_matches(matches_by_weight)
|
end
|
||||||
matches_by_weight = @tournament.matches.where(weight_id: w.id).reload
|
row[:loser1_name] = "Loser of #{source[:bout_number]}" if source
|
||||||
advance_bye_matches_championship(matches_by_weight)
|
|
||||||
save_matches(matches_by_weight)
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def conso_round_2(matches)
|
semis = rows.select { |r| r[:bracket_position] == "Semis" }
|
||||||
matches.select{|m| m.bracket_position == "Conso Round of 8"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
third_fourth = rows.find { |r| r[:bracket_position] == "3/4" }
|
||||||
if match.bracket_position_number == 1
|
if third_fourth
|
||||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 1 and m.bracket_position == "Bracket Round of 16"}.first.bout_number}"
|
third_fourth[:loser1_name] = "Loser of #{semis.first[:bout_number]}" if semis.first
|
||||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position_number == 2 and m.bracket_position == "Bracket Round of 16"}.first.bout_number}"
|
third_fourth[:loser2_name] = "Loser of #{semis.second[:bout_number]}" if semis.second
|
||||||
elsif match.bracket_position_number == 2
|
end
|
||||||
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.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.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)
|
conso_semis = rows.select { |r| r[:bracket_position] == "Conso Semis" }
|
||||||
matches.select{|m| m.bracket_position == "Conso Quarter"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
seventh_eighth = rows.find { |r| r[:bracket_position] == "7/8" }
|
||||||
if match.bracket_position_number == 1
|
if seventh_eighth
|
||||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 4 and m.bracket_position == "Quarter"}.first.bout_number}"
|
seventh_eighth[:loser1_name] = "Loser of #{conso_semis.first[:bout_number]}" if conso_semis.first
|
||||||
elsif match.bracket_position_number == 2
|
seventh_eighth[:loser2_name] = "Loser of #{conso_semis.second[:bout_number]}" if conso_semis.second
|
||||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position_number == 3 and m.bracket_position == "Quarter"}.first.bout_number}"
|
end
|
||||||
elsif match.bracket_position_number == 3
|
end
|
||||||
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 third_fourth(matches)
|
def assign_bye_outcomes_in_memory(weight, match_rows)
|
||||||
matches.select{|m| m.bracket_position == "3/4"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
rows = match_rows.select { |r| r[:weight_id] == weight.id && r[:bracket_position] == "Bracket Round of 16" }
|
||||||
match.loser1_name = "Loser of #{matches.select{|m| m.bracket_position == "Semis"}.first.bout_number}"
|
rows.each { |row| apply_bye_to_row(row) }
|
||||||
match.loser2_name = "Loser of #{matches.select{|m| m.bracket_position == "Semis"}.second.bout_number}"
|
end
|
||||||
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)
|
def apply_bye_to_row(row)
|
||||||
matches.select{|m| m.bracket_position == "Bracket Round of 16"}.sort_by{|m| m.bracket_position_number}.each do |match|
|
return unless [row[:w1], row[:w2]].compact.size == 1
|
||||||
if match.w1 == nil or match.w2 == nil
|
|
||||||
match.finished = 1
|
row[:finished] = 1
|
||||||
match.win_type = "BYE"
|
row[:win_type] = "BYE"
|
||||||
if match.w1 != nil
|
if row[:w1]
|
||||||
match.winner_id = match.w1
|
row[:winner_id] = row[:w1]
|
||||||
match.loser2_name = "BYE"
|
row[:loser2_name] = "BYE"
|
||||||
match.score = ""
|
else
|
||||||
match.save
|
row[:winner_id] = row[:w2]
|
||||||
match.advance_wrestlers
|
row[:loser1_name] = "BYE"
|
||||||
elsif match.w2 != nil
|
end
|
||||||
match.winner_id = match.w2
|
row[:score] = ""
|
||||||
match.loser1_name = "BYE"
|
end
|
||||||
match.score = ""
|
end
|
||||||
match.save
|
|
||||||
match.advance_wrestlers
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def save_matches(matches)
|
|
||||||
matches.each do |m|
|
|
||||||
m.save!
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|||||||
@@ -1,70 +1,75 @@
|
|||||||
class ModifiedSixteenManMatchGeneration
|
class ModifiedSixteenManMatchGeneration
|
||||||
def initialize( tournament )
|
def initialize( tournament, weights: nil )
|
||||||
@tournament = tournament
|
@tournament = tournament
|
||||||
@number_of_placers = @tournament.number_of_placers
|
@number_of_placers = @tournament.number_of_placers
|
||||||
|
@weights = weights
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_matches
|
def generate_matches
|
||||||
@tournament.weights.each do |weight|
|
rows = []
|
||||||
generate_matches_for_weight(weight)
|
generation_weights.each do |weight|
|
||||||
|
rows.concat(generate_match_rows_for_weight(weight))
|
||||||
end
|
end
|
||||||
|
rows
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_matches_for_weight(weight)
|
def generate_match_rows_for_weight(weight)
|
||||||
round_one(weight)
|
rows = []
|
||||||
round_two(weight)
|
round_one(weight, rows)
|
||||||
round_three(weight)
|
round_two(weight, rows)
|
||||||
round_four(weight)
|
round_three(weight, rows)
|
||||||
round_five(weight)
|
round_four(weight, rows)
|
||||||
|
round_five(weight, rows)
|
||||||
|
rows
|
||||||
end
|
end
|
||||||
|
|
||||||
def round_one(weight)
|
def round_one(weight, rows)
|
||||||
create_matchup_from_seed(1,16, "Bracket Round of 16", 1, 1,weight)
|
rows << 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)
|
rows << 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)
|
rows << 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)
|
rows << 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)
|
rows << 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)
|
rows << 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)
|
rows << 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)
|
rows << create_matchup_from_seed(2,15, "Bracket Round of 16", 8, 1,weight)
|
||||||
end
|
end
|
||||||
|
|
||||||
def round_two(weight)
|
def round_two(weight, rows)
|
||||||
create_matchup(nil,nil,"Quarter",1,2,weight)
|
rows << create_matchup(nil,nil,"Quarter",1,2,weight)
|
||||||
create_matchup(nil,nil,"Quarter",2,2,weight)
|
rows << create_matchup(nil,nil,"Quarter",2,2,weight)
|
||||||
create_matchup(nil,nil,"Quarter",3,2,weight)
|
rows << create_matchup(nil,nil,"Quarter",3,2,weight)
|
||||||
create_matchup(nil,nil,"Quarter",4,2,weight)
|
rows << create_matchup(nil,nil,"Quarter",4,2,weight)
|
||||||
create_matchup(nil,nil,"Conso Round of 8",1,2,weight)
|
rows << create_matchup(nil,nil,"Conso Round of 8",1,2,weight)
|
||||||
create_matchup(nil,nil,"Conso Round of 8",2,2,weight)
|
rows << create_matchup(nil,nil,"Conso Round of 8",2,2,weight)
|
||||||
create_matchup(nil,nil,"Conso Round of 8",3,2,weight)
|
rows << create_matchup(nil,nil,"Conso Round of 8",3,2,weight)
|
||||||
create_matchup(nil,nil,"Conso Round of 8",4,2,weight)
|
rows << create_matchup(nil,nil,"Conso Round of 8",4,2,weight)
|
||||||
end
|
end
|
||||||
|
|
||||||
def round_three(weight)
|
def round_three(weight, rows)
|
||||||
create_matchup(nil,nil,"Semis",1,3,weight)
|
rows << create_matchup(nil,nil,"Semis",1,3,weight)
|
||||||
create_matchup(nil,nil,"Semis",2,3,weight)
|
rows << create_matchup(nil,nil,"Semis",2,3,weight)
|
||||||
create_matchup(nil,nil,"Conso Quarter",1,3,weight)
|
rows << create_matchup(nil,nil,"Conso Quarter",1,3,weight)
|
||||||
create_matchup(nil,nil,"Conso Quarter",2,3,weight)
|
rows << create_matchup(nil,nil,"Conso Quarter",2,3,weight)
|
||||||
create_matchup(nil,nil,"Conso Quarter",3,3,weight)
|
rows << create_matchup(nil,nil,"Conso Quarter",3,3,weight)
|
||||||
create_matchup(nil,nil,"Conso Quarter",4,3,weight)
|
rows << create_matchup(nil,nil,"Conso Quarter",4,3,weight)
|
||||||
end
|
end
|
||||||
|
|
||||||
def round_four(weight)
|
def round_four(weight, rows)
|
||||||
create_matchup(nil,nil,"Conso Semis",1,4,weight)
|
rows << create_matchup(nil,nil,"Conso Semis",1,4,weight)
|
||||||
create_matchup(nil,nil,"Conso Semis",2,4,weight)
|
rows << create_matchup(nil,nil,"Conso Semis",2,4,weight)
|
||||||
end
|
end
|
||||||
|
|
||||||
def round_five(weight)
|
def round_five(weight, rows)
|
||||||
create_matchup(nil,nil,"1/2",1,5,weight)
|
rows << create_matchup(nil,nil,"1/2",1,5,weight)
|
||||||
create_matchup(nil,nil,"3/4",1,5,weight)
|
rows << create_matchup(nil,nil,"3/4",1,5,weight)
|
||||||
create_matchup(nil,nil,"5/6",1,5,weight)
|
rows << create_matchup(nil,nil,"5/6",1,5,weight)
|
||||||
if @number_of_placers >= 8
|
if @number_of_placers >= 8
|
||||||
create_matchup(nil,nil,"7/8",1,5,weight)
|
rows << create_matchup(nil,nil,"7/8",1,5,weight)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def wrestler_with_seed(seed,weight)
|
def wrestler_with_seed(seed,weight)
|
||||||
wrestler = Wrestler.where("weight_id = ? and bracket_line = ?", weight.id, seed).first
|
wrestler = weight.wrestlers.find { |w| w.bracket_line == seed }
|
||||||
if wrestler
|
if wrestler
|
||||||
return wrestler.id
|
return wrestler.id
|
||||||
else
|
else
|
||||||
@@ -79,13 +84,18 @@ class ModifiedSixteenManMatchGeneration
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create_matchup(w1, w2, bracket_position, bracket_position_number,round,weight)
|
def create_matchup(w1, w2, bracket_position, bracket_position_number,round,weight)
|
||||||
@tournament.matches.create(
|
{
|
||||||
w1: w1,
|
w1: w1,
|
||||||
w2: w2,
|
w2: w2,
|
||||||
|
tournament_id: @tournament.id,
|
||||||
weight_id: weight.id,
|
weight_id: weight.id,
|
||||||
round: round,
|
round: round,
|
||||||
bracket_position: bracket_position,
|
bracket_position: bracket_position,
|
||||||
bracket_position_number: bracket_position_number
|
bracket_position_number: bracket_position_number
|
||||||
)
|
}
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
def generation_weights
|
||||||
|
@weights || @tournament.weights.to_a
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|||||||
@@ -12,18 +12,19 @@ class PoolBracketGeneration
|
|||||||
end
|
end
|
||||||
|
|
||||||
def generateBracketMatches()
|
def generateBracketMatches()
|
||||||
|
@rows = []
|
||||||
if @pool_bracket_type == "twoPoolsToSemi"
|
if @pool_bracket_type == "twoPoolsToSemi"
|
||||||
return twoPoolsToSemi()
|
twoPoolsToSemi()
|
||||||
elsif @pool_bracket_type == "twoPoolsToFinal"
|
elsif @pool_bracket_type == "twoPoolsToFinal"
|
||||||
return twoPoolsToFinal()
|
twoPoolsToFinal()
|
||||||
elsif @pool_bracket_type == "fourPoolsToQuarter"
|
elsif @pool_bracket_type == "fourPoolsToQuarter"
|
||||||
return fourPoolsToQuarter()
|
fourPoolsToQuarter()
|
||||||
elsif @pool_bracket_type == "fourPoolsToSemi"
|
elsif @pool_bracket_type == "fourPoolsToSemi"
|
||||||
return fourPoolsToSemi()
|
fourPoolsToSemi()
|
||||||
elsif @pool_bracket_type == "eightPoolsToQuarter"
|
elsif @pool_bracket_type == "eightPoolsToQuarter"
|
||||||
return eightPoolsToQuarter()
|
eightPoolsToQuarter()
|
||||||
end
|
end
|
||||||
return []
|
@rows
|
||||||
end
|
end
|
||||||
|
|
||||||
def twoPoolsToSemi()
|
def twoPoolsToSemi()
|
||||||
@@ -86,14 +87,15 @@ class PoolBracketGeneration
|
|||||||
end
|
end
|
||||||
|
|
||||||
def createMatchup(w1_name, w2_name, bracket_position, bracket_position_number)
|
def createMatchup(w1_name, w2_name, bracket_position, bracket_position_number)
|
||||||
@tournament.matches.create(
|
@rows << {
|
||||||
loser1_name: w1_name,
|
loser1_name: w1_name,
|
||||||
loser2_name: w2_name,
|
loser2_name: w2_name,
|
||||||
|
tournament_id: @tournament.id,
|
||||||
weight_id: @weight.id,
|
weight_id: @weight.id,
|
||||||
round: @round,
|
round: @round,
|
||||||
bracket_position: bracket_position,
|
bracket_position: bracket_position,
|
||||||
bracket_position_number: bracket_position_number
|
bracket_position_number: bracket_position_number
|
||||||
)
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,35 +1,46 @@
|
|||||||
class PoolGeneration
|
class PoolGeneration
|
||||||
def initialize(weight)
|
def initialize(weight, wrestlers: nil)
|
||||||
@weight = weight
|
@weight = weight
|
||||||
@tournament = @weight.tournament
|
@tournament = @weight.tournament
|
||||||
@pool = 1
|
@pool = 1
|
||||||
|
@wrestlers = wrestlers
|
||||||
end
|
end
|
||||||
|
|
||||||
def generatePools
|
def generatePools
|
||||||
GeneratePoolNumbers.new(@weight).savePoolNumbers
|
GeneratePoolNumbers.new(@weight).savePoolNumbers(wrestlers: wrestlers_for_weight, persist: false)
|
||||||
|
rows = []
|
||||||
pools = @weight.pools
|
pools = @weight.pools
|
||||||
while @pool <= pools
|
while @pool <= pools
|
||||||
roundRobin
|
rows.concat(roundRobin)
|
||||||
@pool += 1
|
@pool += 1
|
||||||
end
|
end
|
||||||
|
rows
|
||||||
end
|
end
|
||||||
|
|
||||||
def roundRobin
|
def roundRobin
|
||||||
wrestlers = @weight.wrestlers_in_pool(@pool)
|
rows = []
|
||||||
|
wrestlers = wrestlers_for_weight.select { |w| w.pool == @pool }
|
||||||
pool_matches = RoundRobinTournament.schedule(wrestlers).reverse
|
pool_matches = RoundRobinTournament.schedule(wrestlers).reverse
|
||||||
pool_matches.each_with_index do |b, index|
|
pool_matches.each_with_index do |b, index|
|
||||||
round = index + 1
|
round = index + 1
|
||||||
bouts = b.map
|
bouts = b.map
|
||||||
bouts.each do |bout|
|
bouts.each do |bout|
|
||||||
if bout[0] != nil and bout[1] != nil
|
if bout[0] != nil and bout[1] != nil
|
||||||
@tournament.matches.create(
|
rows << {
|
||||||
w1: bout[0].id,
|
w1: bout[0].id,
|
||||||
w2: bout[1].id,
|
w2: bout[1].id,
|
||||||
|
tournament_id: @tournament.id,
|
||||||
weight_id: @weight.id,
|
weight_id: @weight.id,
|
||||||
bracket_position: "Pool",
|
bracket_position: "Pool",
|
||||||
round: round)
|
round: round
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
rows
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def wrestlers_for_weight
|
||||||
|
@wrestlers || @weight.wrestlers.to_a
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,80 +1,97 @@
|
|||||||
class PoolToBracketGenerateLoserNames
|
class PoolToBracketGenerateLoserNames
|
||||||
def initialize( tournament )
|
def initialize(tournament)
|
||||||
@tournament = tournament
|
@tournament = tournament
|
||||||
end
|
|
||||||
|
|
||||||
def assignLoserNamesWeight(weight)
|
|
||||||
matches_by_weight = @tournament.matches.where(weight_id: weight.id)
|
|
||||||
if weight.pool_bracket_type == "twoPoolsToSemi"
|
|
||||||
twoPoolsToSemiLoser(matches_by_weight)
|
|
||||||
elsif (weight.pool_bracket_type == "fourPoolsToQuarter") or (weight.pool_bracket_type == "eightPoolsToQuarter")
|
|
||||||
fourPoolsToQuarterLoser(matches_by_weight)
|
|
||||||
elsif weight.pool_bracket_type == "fourPoolsToSemi"
|
|
||||||
fourPoolsToSemiLoser(matches_by_weight)
|
|
||||||
end
|
|
||||||
saveMatches(matches_by_weight)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def assignLoserNames
|
# Compatibility wrapper. Returns transformed rows and does not persist.
|
||||||
matches_by_weight = nil
|
def assignLoserNamesWeight(weight, match_rows = nil)
|
||||||
@tournament.weights.each do |w|
|
rows = match_rows || @tournament.matches.where(weight_id: weight.id).map { |m| m.attributes.symbolize_keys }
|
||||||
matches_by_weight = @tournament.matches.where(weight_id: w.id)
|
assign_loser_names_in_memory(weight, rows)
|
||||||
if w.pool_bracket_type == "twoPoolsToSemi"
|
rows
|
||||||
twoPoolsToSemiLoser(matches_by_weight)
|
|
||||||
elsif (w.pool_bracket_type == "fourPoolsToQuarter") or (w.pool_bracket_type == "eightPoolsToQuarter")
|
|
||||||
fourPoolsToQuarterLoser(matches_by_weight)
|
|
||||||
elsif w.pool_bracket_type == "fourPoolsToSemi"
|
|
||||||
fourPoolsToSemiLoser(matches_by_weight)
|
|
||||||
end
|
|
||||||
saveMatches(matches_by_weight)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def twoPoolsToSemiLoser(matches_by_weight)
|
|
||||||
match1 = matches_by_weight.select{|m| m.loser1_name == "Winner Pool 1"}.first
|
|
||||||
match2 = matches_by_weight.select{|m| m.loser1_name == "Winner Pool 2"}.first
|
|
||||||
matchChange = matches_by_weight.select{|m| m.bracket_position == "3/4"}.first
|
|
||||||
matchChange.loser1_name = "Loser of #{match1.bout_number}"
|
|
||||||
matchChange.loser2_name = "Loser of #{match2.bout_number}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def fourPoolsToQuarterLoser(matches_by_weight)
|
# Compatibility wrapper. Returns transformed rows and does not persist.
|
||||||
quarters = matches_by_weight.select{|m| m.bracket_position == "Quarter"}
|
def assignLoserNames
|
||||||
consoSemis = matches_by_weight.select{|m| m.bracket_position == "Conso Semis"}
|
@tournament.weights.each_with_object([]) do |weight, all_rows|
|
||||||
semis = matches_by_weight.select{|m| m.bracket_position == "Semis"}
|
all_rows.concat(assignLoserNamesWeight(weight))
|
||||||
thirdFourth = matches_by_weight.select{|m| m.bracket_position == "3/4"}.first
|
end
|
||||||
seventhEighth = matches_by_weight.select{|m| m.bracket_position == "7/8"}.first
|
end
|
||||||
consoSemis.each do |m|
|
|
||||||
if m.bracket_position_number == 1
|
def assign_loser_names_in_memory(weight, match_rows)
|
||||||
m.loser1_name = "Loser of #{quarters.select{|m| m.bracket_position_number == 1}.first.bout_number}"
|
rows = match_rows.select { |row| row[:weight_id] == weight.id }
|
||||||
m.loser2_name = "Loser of #{quarters.select{|m| m.bracket_position_number == 2}.first.bout_number}"
|
if weight.pool_bracket_type == "twoPoolsToSemi"
|
||||||
elsif m.bracket_position_number == 2
|
two_pools_to_semi_loser_rows(rows)
|
||||||
m.loser1_name = "Loser of #{quarters.select{|m| m.bracket_position_number == 3}.first.bout_number}"
|
elsif (weight.pool_bracket_type == "fourPoolsToQuarter") || (weight.pool_bracket_type == "eightPoolsToQuarter")
|
||||||
m.loser2_name = "Loser of #{quarters.select{|m| m.bracket_position_number == 4}.first.bout_number}"
|
four_pools_to_quarter_loser_rows(rows)
|
||||||
|
elsif weight.pool_bracket_type == "fourPoolsToSemi"
|
||||||
|
four_pools_to_semi_loser_rows(rows)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def two_pools_to_semi_loser_rows(rows)
|
||||||
|
match1 = rows.find { |m| m[:loser1_name] == "Winner Pool 1" }
|
||||||
|
match2 = rows.find { |m| m[:loser1_name] == "Winner Pool 2" }
|
||||||
|
match_change = rows.find { |m| m[:bracket_position] == "3/4" }
|
||||||
|
return unless match1 && match2 && match_change
|
||||||
|
|
||||||
|
match_change[:loser1_name] = "Loser of #{match1[:bout_number]}"
|
||||||
|
match_change[:loser2_name] = "Loser of #{match2[:bout_number]}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def four_pools_to_quarter_loser_rows(rows)
|
||||||
|
quarters = rows.select { |m| m[:bracket_position] == "Quarter" }
|
||||||
|
conso_semis = rows.select { |m| m[:bracket_position] == "Conso Semis" }
|
||||||
|
semis = rows.select { |m| m[:bracket_position] == "Semis" }
|
||||||
|
third_fourth = rows.find { |m| m[:bracket_position] == "3/4" }
|
||||||
|
seventh_eighth = rows.find { |m| m[:bracket_position] == "7/8" }
|
||||||
|
|
||||||
|
conso_semis.each do |m|
|
||||||
|
if m[:bracket_position_number] == 1
|
||||||
|
q1 = quarters.find { |q| q[:bracket_position_number] == 1 }
|
||||||
|
q2 = quarters.find { |q| q[:bracket_position_number] == 2 }
|
||||||
|
m[:loser1_name] = "Loser of #{q1[:bout_number]}" if q1
|
||||||
|
m[:loser2_name] = "Loser of #{q2[:bout_number]}" if q2
|
||||||
|
elsif m[:bracket_position_number] == 2
|
||||||
|
q3 = quarters.find { |q| q[:bracket_position_number] == 3 }
|
||||||
|
q4 = quarters.find { |q| q[:bracket_position_number] == 4 }
|
||||||
|
m[:loser1_name] = "Loser of #{q3[:bout_number]}" if q3
|
||||||
|
m[:loser2_name] = "Loser of #{q4[:bout_number]}" if q4
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
thirdFourth.loser1_name = "Loser of #{semis.select{|m| m.bracket_position_number == 1}.first.bout_number}"
|
|
||||||
thirdFourth.loser2_name = "Loser of #{semis.select{|m| m.bracket_position_number == 2}.first.bout_number}"
|
if third_fourth
|
||||||
consoSemis = matches_by_weight.select{|m| m.bracket_position == "Conso Semis"}
|
s1 = semis.find { |s| s[:bracket_position_number] == 1 }
|
||||||
seventhEighth.loser1_name = "Loser of #{consoSemis.select{|m| m.bracket_position_number == 1}.first.bout_number}"
|
s2 = semis.find { |s| s[:bracket_position_number] == 2 }
|
||||||
seventhEighth.loser2_name = "Loser of #{consoSemis.select{|m| m.bracket_position_number == 2}.first.bout_number}"
|
third_fourth[:loser1_name] = "Loser of #{s1[:bout_number]}" if s1
|
||||||
|
third_fourth[:loser2_name] = "Loser of #{s2[:bout_number]}" if s2
|
||||||
|
end
|
||||||
|
|
||||||
|
if seventh_eighth
|
||||||
|
c1 = conso_semis.find { |c| c[:bracket_position_number] == 1 }
|
||||||
|
c2 = conso_semis.find { |c| c[:bracket_position_number] == 2 }
|
||||||
|
seventh_eighth[:loser1_name] = "Loser of #{c1[:bout_number]}" if c1
|
||||||
|
seventh_eighth[:loser2_name] = "Loser of #{c2[:bout_number]}" if c2
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def fourPoolsToSemiLoser(matches_by_weight)
|
def four_pools_to_semi_loser_rows(rows)
|
||||||
semis = matches_by_weight.select{|m| m.bracket_position == "Semis"}
|
semis = rows.select { |m| m[:bracket_position] == "Semis" }
|
||||||
thirdFourth = matches_by_weight.select{|m| m.bracket_position == "3/4"}.first
|
conso_semis = rows.select { |m| m[:bracket_position] == "Conso Semis" }
|
||||||
consoSemis = matches_by_weight.select{|m| m.bracket_position == "Conso Semis"}
|
third_fourth = rows.find { |m| m[:bracket_position] == "3/4" }
|
||||||
seventhEighth = matches_by_weight.select{|m| m.bracket_position == "7/8"}.first
|
seventh_eighth = rows.find { |m| m[:bracket_position] == "7/8" }
|
||||||
thirdFourth.loser1_name = "Loser of #{semis.select{|m| m.bracket_position_number == 1}.first.bout_number}"
|
|
||||||
thirdFourth.loser2_name = "Loser of #{semis.select{|m| m.bracket_position_number == 2}.first.bout_number}"
|
if third_fourth
|
||||||
seventhEighth.loser1_name = "Loser of #{consoSemis.select{|m| m.bracket_position_number == 1}.first.bout_number}"
|
s1 = semis.find { |s| s[:bracket_position_number] == 1 }
|
||||||
seventhEighth.loser2_name = "Loser of #{consoSemis.select{|m| m.bracket_position_number == 2}.first.bout_number}"
|
s2 = semis.find { |s| s[:bracket_position_number] == 2 }
|
||||||
|
third_fourth[:loser1_name] = "Loser of #{s1[:bout_number]}" if s1
|
||||||
|
third_fourth[:loser2_name] = "Loser of #{s2[:bout_number]}" if s2
|
||||||
|
end
|
||||||
|
|
||||||
|
if seventh_eighth
|
||||||
|
c1 = conso_semis.find { |c| c[:bracket_position_number] == 1 }
|
||||||
|
c2 = conso_semis.find { |c| c[:bracket_position_number] == 2 }
|
||||||
|
seventh_eighth[:loser1_name] = "Loser of #{c1[:bout_number]}" if c1
|
||||||
|
seventh_eighth[:loser2_name] = "Loser of #{c2[:bout_number]}" if c2
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
def saveMatches(matches)
|
|
||||||
matches.each do |m|
|
|
||||||
m.save!
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|||||||
@@ -1,44 +1,92 @@
|
|||||||
class PoolToBracketMatchGeneration
|
class PoolToBracketMatchGeneration
|
||||||
def initialize( tournament )
|
def initialize(tournament, weights: nil, wrestlers_by_weight_id: nil)
|
||||||
@tournament = tournament
|
@tournament = tournament
|
||||||
|
@weights = weights
|
||||||
|
@wrestlers_by_weight_id = wrestlers_by_weight_id
|
||||||
end
|
end
|
||||||
|
|
||||||
def generatePoolToBracketMatches
|
def generatePoolToBracketMatches
|
||||||
@tournament.weights.order(:max).each do |weight|
|
rows = []
|
||||||
PoolGeneration.new(weight).generatePools()
|
generation_weights.each do |weight|
|
||||||
last_match = @tournament.matches.where(weight: weight).order(round: :desc).limit(1).first
|
wrestlers = wrestlers_for_weight(weight)
|
||||||
highest_round = last_match.round
|
pool_rows = PoolGeneration.new(weight, wrestlers: wrestlers).generatePools
|
||||||
PoolBracketGeneration.new(weight, highest_round).generateBracketMatches()
|
rows.concat(pool_rows)
|
||||||
|
|
||||||
|
highest_round = pool_rows.map { |row| row[:round] }.max || 0
|
||||||
|
bracket_rows = PoolBracketGeneration.new(weight, highest_round).generateBracketMatches
|
||||||
|
rows.concat(bracket_rows)
|
||||||
end
|
end
|
||||||
movePoolSeedsToFinalPoolRound
|
|
||||||
|
movePoolSeedsToFinalPoolRound(rows)
|
||||||
|
rows
|
||||||
end
|
end
|
||||||
|
|
||||||
def movePoolSeedsToFinalPoolRound
|
def movePoolSeedsToFinalPoolRound(match_rows)
|
||||||
@tournament.weights.each do |w|
|
generation_weights.each do |w|
|
||||||
setOriginalSeedsToWrestleLastPoolRound(w)
|
setOriginalSeedsToWrestleLastPoolRound(w, match_rows)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def setOriginalSeedsToWrestleLastPoolRound(weight)
|
def setOriginalSeedsToWrestleLastPoolRound(weight, match_rows)
|
||||||
pool = 1
|
pool = 1
|
||||||
until pool > weight.pools
|
wrestlers = wrestlers_for_weight(weight)
|
||||||
wrestler1 = weight.pool_wrestlers_sorted_by_bracket_line(pool).first
|
weight_pools = weight.pools
|
||||||
wrestler2 = weight.pool_wrestlers_sorted_by_bracket_line(pool).second
|
until pool > weight_pools
|
||||||
match = wrestler1.pool_matches.sort_by{|m| m.round}.last
|
pool_wrestlers = wrestlers.select { |w| w.pool == pool }.sort_by(&:bracket_line)
|
||||||
if match.w1 != wrestler2.id or match.w2 != wrestler2.id
|
wrestler1 = pool_wrestlers.first
|
||||||
if match.w1 == wrestler1.id
|
wrestler2 = pool_wrestlers.second
|
||||||
SwapWrestlers.new.swap_wrestlers_bracket_lines(match.w2,wrestler2.id)
|
if wrestler1 && wrestler2
|
||||||
elsif match.w2 == wrestler1.id
|
pool_matches = match_rows.select { |row| row[:weight_id] == weight.id && row[:bracket_position] == "Pool" && (row[:w1] == wrestler1.id || row[:w2] == wrestler1.id) }
|
||||||
SwapWrestlers.new.swap_wrestlers_bracket_lines(match.w1,wrestler2.id)
|
match = pool_matches.max_by { |row| row[:round] }
|
||||||
end
|
if match && (match[:w1] != wrestler2.id || match[:w2] != wrestler2.id)
|
||||||
|
if match[:w1] == wrestler1.id
|
||||||
|
swap_wrestlers_in_memory(match_rows, wrestlers, match[:w2], wrestler2.id)
|
||||||
|
elsif match[:w2] == wrestler1.id
|
||||||
|
swap_wrestlers_in_memory(match_rows, wrestlers, match[:w1], wrestler2.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
pool += 1
|
pool += 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def swap_wrestlers_in_memory(match_rows, wrestlers, wrestler1_id, wrestler2_id)
|
||||||
|
w1 = wrestlers.find { |w| w.id == wrestler1_id }
|
||||||
|
w2 = wrestlers.find { |w| w.id == wrestler2_id }
|
||||||
|
return unless w1 && w2
|
||||||
|
|
||||||
|
w1_bracket_line, w1_pool = w1.bracket_line, w1.pool
|
||||||
|
w1.bracket_line, w1.pool = w2.bracket_line, w2.pool
|
||||||
|
w2.bracket_line, w2.pool = w1_bracket_line, w1_pool
|
||||||
|
|
||||||
|
swap_match_rows(match_rows, wrestler1_id, wrestler2_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def swap_match_rows(match_rows, wrestler1_id, wrestler2_id)
|
||||||
|
match_rows.each do |row|
|
||||||
|
row[:w1] = swap_id(row[:w1], wrestler1_id, wrestler2_id)
|
||||||
|
row[:w2] = swap_id(row[:w2], wrestler1_id, wrestler2_id)
|
||||||
|
row[:winner_id] = swap_id(row[:winner_id], wrestler1_id, wrestler2_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def swap_id(value, wrestler1_id, wrestler2_id)
|
||||||
|
return wrestler2_id if value == wrestler1_id
|
||||||
|
return wrestler1_id if value == wrestler2_id
|
||||||
|
|
||||||
|
value
|
||||||
|
end
|
||||||
|
|
||||||
|
def generation_weights
|
||||||
|
@weights || @tournament.weights.order(:max).to_a
|
||||||
|
end
|
||||||
|
|
||||||
|
def wrestlers_for_weight(weight)
|
||||||
|
@wrestlers_by_weight_id&.fetch(weight.id, nil) || weight.wrestlers.to_a
|
||||||
|
end
|
||||||
|
|
||||||
def assignLoserNames
|
def assignLoserNames
|
||||||
PoolToBracketGenerateLoserNames.new(@tournament).assignLoserNames
|
PoolToBracketGenerateLoserNames.new(@tournament).assignLoserNames
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -37,7 +37,11 @@ class TournamentBackupService
|
|||||||
attributes: @tournament.attributes,
|
attributes: @tournament.attributes,
|
||||||
schools: @tournament.schools.map(&:attributes),
|
schools: @tournament.schools.map(&:attributes),
|
||||||
weights: @tournament.weights.map(&:attributes),
|
weights: @tournament.weights.map(&:attributes),
|
||||||
mats: @tournament.mats.map(&:attributes),
|
mats: @tournament.mats.map do |mat|
|
||||||
|
mat.attributes.merge(
|
||||||
|
"queue_bout_numbers" => mat.queue_matches.map { |match| match&.bout_number }
|
||||||
|
)
|
||||||
|
end,
|
||||||
mat_assignment_rules: @tournament.mat_assignment_rules.map do |rule|
|
mat_assignment_rules: @tournament.mat_assignment_rules.map do |rule|
|
||||||
rule.attributes.merge(
|
rule.attributes.merge(
|
||||||
mat: Mat.find_by(id: rule.mat_id)&.attributes.slice("name"),
|
mat: Mat.find_by(id: rule.mat_id)&.attributes.slice("name"),
|
||||||
|
|||||||
@@ -3,30 +3,36 @@ class TournamentSeeding
|
|||||||
@tournament = tournament
|
@tournament = tournament
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_seeds
|
def set_seeds(weights: nil, persist: true)
|
||||||
@tournament.weights.each do |weight|
|
weights_to_seed = weights || @tournament.weights.includes(:wrestlers)
|
||||||
|
updated_wrestlers = []
|
||||||
|
|
||||||
|
weights_to_seed.each do |weight|
|
||||||
wrestlers = weight.wrestlers
|
wrestlers = weight.wrestlers
|
||||||
bracket_size = weight.calculate_bracket_size
|
bracket_size = weight.calculate_bracket_size
|
||||||
|
|
||||||
wrestlers = reset_bracket_line_for_lines_higher_than_bracket_size(wrestlers, bracket_size)
|
wrestlers = reset_bracket_line_for_lines_higher_than_bracket_size(wrestlers, bracket_size)
|
||||||
wrestlers = set_original_seed_to_bracket_line(wrestlers)
|
wrestlers = set_original_seed_to_bracket_line(wrestlers)
|
||||||
wrestlers = random_seeding(wrestlers, bracket_size)
|
wrestlers = random_seeding(wrestlers, bracket_size)
|
||||||
wrestlers.each(&:save)
|
updated_wrestlers.concat(wrestlers)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
persist_bracket_lines(updated_wrestlers) if persist
|
||||||
|
updated_wrestlers
|
||||||
end
|
end
|
||||||
|
|
||||||
def random_seeding(wrestlers, bracket_size)
|
def random_seeding(wrestlers, bracket_size)
|
||||||
half_of_bracket = bracket_size / 2
|
half_of_bracket = bracket_size / 2
|
||||||
available_bracket_lines = (1..bracket_size).to_a
|
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
|
# 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 = wrestlers.select{|w| w.bracket_line != nil }
|
||||||
wrestlers_with_bracket_lines.each do |wrestler|
|
wrestlers_with_bracket_lines.each do |wrestler|
|
||||||
available_bracket_lines.delete(wrestler.bracket_line)
|
available_bracket_lines.delete(wrestler.bracket_line)
|
||||||
first_half_available_bracket_lines.delete(wrestler.bracket_line)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
available_bracket_lines_to_use = set_random_seeding_bracket_line_order(available_bracket_lines)
|
||||||
|
|
||||||
wrestlers_without_bracket_lines = wrestlers.select{|w| w.bracket_line == nil }
|
wrestlers_without_bracket_lines = wrestlers.select{|w| w.bracket_line == nil }
|
||||||
if @tournament.tournament_type == "Pool to bracket"
|
if @tournament.tournament_type == "Pool to bracket"
|
||||||
wrestlers_without_bracket_lines.shuffle.each do |wrestler|
|
wrestlers_without_bracket_lines.shuffle.each do |wrestler|
|
||||||
@@ -38,15 +44,10 @@ class TournamentSeeding
|
|||||||
else
|
else
|
||||||
# Iterrate over the list randomly
|
# Iterrate over the list randomly
|
||||||
wrestlers_without_bracket_lines.shuffle.each do |wrestler|
|
wrestlers_without_bracket_lines.shuffle.each do |wrestler|
|
||||||
if first_half_available_bracket_lines.size > 0
|
if available_bracket_lines_to_use.size > 0
|
||||||
random_available_bracket_line = first_half_available_bracket_lines.sample
|
bracket_line_to_use = available_bracket_lines_to_use.first
|
||||||
wrestler.bracket_line = random_available_bracket_line
|
wrestler.bracket_line = bracket_line_to_use
|
||||||
available_bracket_lines.delete(random_available_bracket_line)
|
available_bracket_lines_to_use.delete(bracket_line_to_use)
|
||||||
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
|
end
|
||||||
end
|
end
|
||||||
@@ -81,4 +82,39 @@ class TournamentSeeding
|
|||||||
end
|
end
|
||||||
return wrestlers
|
return wrestlers
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_random_seeding_bracket_line_order(available_bracket_lines)
|
||||||
|
# This method prevents double BYEs in round 1
|
||||||
|
# It also evenly distributes matches from the top half of the bracket to the bottom half
|
||||||
|
# It does both of these while keeping the randomness of the line assignment
|
||||||
|
odd_or_even = [0, 1]
|
||||||
|
odd_or_even_sample = odd_or_even.sample
|
||||||
|
|
||||||
|
# sort by odd or even based on the sample above
|
||||||
|
if odd_or_even_sample == 1
|
||||||
|
# odd numbers first
|
||||||
|
result = available_bracket_lines.sort_by { |n| n.even? ? 1 : 0 }
|
||||||
|
else
|
||||||
|
# even numbers first
|
||||||
|
result = available_bracket_lines.sort_by { |n| n.odd? ? 1 : 0 }
|
||||||
|
end
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def persist_bracket_lines(wrestlers)
|
||||||
|
return if wrestlers.blank?
|
||||||
|
|
||||||
|
timestamp = Time.current
|
||||||
|
updates = wrestlers.map do |wrestler|
|
||||||
|
{
|
||||||
|
id: wrestler.id,
|
||||||
|
bracket_line: wrestler.bracket_line,
|
||||||
|
updated_at: timestamp
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
Wrestler.upsert_all(updates)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ class WipeTournamentMatches
|
|||||||
end
|
end
|
||||||
|
|
||||||
def wipeMatches
|
def wipeMatches
|
||||||
@tournament.matches.destroy_all
|
@tournament.destroy_all_matches
|
||||||
end
|
end
|
||||||
|
|
||||||
def resetSchoolScores
|
def resetSchoolScores
|
||||||
@tournament.schools.update_all("score = 0.0")
|
@tournament.schools.update_all("score = 0.0")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -41,20 +41,20 @@ class WrestlingdevImporter
|
|||||||
@tournament.matches.destroy_all
|
@tournament.matches.destroy_all
|
||||||
@tournament.mat_assignment_rules.destroy_all # Explicitly destroy rules (might be redundant if Mat cascades)
|
@tournament.mat_assignment_rules.destroy_all # Explicitly destroy rules (might be redundant if Mat cascades)
|
||||||
@tournament.delegates.destroy_all
|
@tournament.delegates.destroy_all
|
||||||
@tournament.tournament_backups.destroy_all
|
|
||||||
@tournament.tournament_job_statuses.destroy_all
|
@tournament.tournament_job_statuses.destroy_all
|
||||||
# Note: Teampointadjusts are deleted via School/Wrestler cascade
|
# Note: Teampointadjusts are deleted via School/Wrestler cascade
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_data
|
def parse_data
|
||||||
parse_tournament(@import_data["tournament"]["attributes"])
|
parse_tournament(@import_data["tournament"]["attributes"])
|
||||||
parse_schools(@import_data["tournament"]["schools"])
|
parse_schools(@import_data["tournament"]["schools"])
|
||||||
parse_weights(@import_data["tournament"]["weights"])
|
parse_weights(@import_data["tournament"]["weights"])
|
||||||
parse_mats(@import_data["tournament"]["mats"])
|
parse_mats(@import_data["tournament"]["mats"])
|
||||||
parse_wrestlers(@import_data["tournament"]["wrestlers"])
|
parse_wrestlers(@import_data["tournament"]["wrestlers"])
|
||||||
parse_matches(@import_data["tournament"]["matches"])
|
parse_matches(@import_data["tournament"]["matches"])
|
||||||
parse_mat_assignment_rules(@import_data["tournament"]["mat_assignment_rules"])
|
apply_mat_queues
|
||||||
end
|
parse_mat_assignment_rules(@import_data["tournament"]["mat_assignment_rules"])
|
||||||
|
end
|
||||||
|
|
||||||
def parse_tournament(attributes)
|
def parse_tournament(attributes)
|
||||||
attributes.except!("id")
|
attributes.except!("id")
|
||||||
@@ -75,12 +75,18 @@ class WrestlingdevImporter
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_mats(mats)
|
def parse_mats(mats)
|
||||||
mats.each do |mat_attributes|
|
@mat_queue_bout_numbers = {}
|
||||||
mat_attributes.except!("id")
|
mats.each do |mat_attributes|
|
||||||
Mat.create(mat_attributes.merge(tournament_id: @tournament.id))
|
mat_name = mat_attributes["name"]
|
||||||
end
|
queue_bout_numbers = mat_attributes["queue_bout_numbers"]
|
||||||
end
|
mat_attributes.except!("id", "queue1", "queue2", "queue3", "queue4", "queue_bout_numbers", "tournament_id")
|
||||||
|
Mat.create(mat_attributes.merge(tournament_id: @tournament.id))
|
||||||
|
if mat_name && queue_bout_numbers
|
||||||
|
@mat_queue_bout_numbers[mat_name] = queue_bout_numbers
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def parse_mat_assignment_rules(mat_assignment_rules)
|
def parse_mat_assignment_rules(mat_assignment_rules)
|
||||||
mat_assignment_rules.each do |rule_attributes|
|
mat_assignment_rules.each do |rule_attributes|
|
||||||
@@ -135,9 +141,9 @@ class WrestlingdevImporter
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_matches(matches)
|
def parse_matches(matches)
|
||||||
matches.each do |match_attributes|
|
matches.each do |match_attributes|
|
||||||
next unless match_attributes # Skip if match_attributes is nil
|
next unless match_attributes # Skip if match_attributes is nil
|
||||||
|
|
||||||
weight = Weight.find_by(max: match_attributes.dig("weight", "max"), tournament_id: @tournament.id)
|
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)
|
mat = Mat.find_by(name: match_attributes.dig("mat", "name"), tournament_id: @tournament.id)
|
||||||
@@ -156,6 +162,53 @@ class WrestlingdevImporter
|
|||||||
w2: w2&.id,
|
w2: w2&.id,
|
||||||
winner_id: winner&.id
|
winner_id: winner&.id
|
||||||
))
|
))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
def apply_mat_queues
|
||||||
|
if @mat_queue_bout_numbers.blank?
|
||||||
|
Mat.where(tournament_id: @tournament.id).find_each do |mat|
|
||||||
|
match_ids = mat.matches.where(finished: [nil, 0]).order(:bout_number).limit(4).pluck(:id)
|
||||||
|
mat.update(
|
||||||
|
queue1: match_ids[0],
|
||||||
|
queue2: match_ids[1],
|
||||||
|
queue3: match_ids[2],
|
||||||
|
queue4: match_ids[3]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
@mat_queue_bout_numbers.each do |mat_name, bout_numbers|
|
||||||
|
mat = Mat.find_by(name: mat_name, tournament_id: @tournament.id)
|
||||||
|
next unless mat
|
||||||
|
|
||||||
|
matches = Array(bout_numbers).map do |bout_number|
|
||||||
|
Match.find_by(bout_number: bout_number, tournament_id: @tournament.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
mat.update(
|
||||||
|
queue1: matches[0]&.id,
|
||||||
|
queue2: matches[1]&.id,
|
||||||
|
queue3: matches[2]&.id,
|
||||||
|
queue4: matches[3]&.id
|
||||||
|
)
|
||||||
|
|
||||||
|
matches.compact.each do |match|
|
||||||
|
match.update(mat_id: mat.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Mat.where(tournament_id: @tournament.id)
|
||||||
|
.where(queue1: nil, queue2: nil, queue3: nil, queue4: nil)
|
||||||
|
.find_each do |mat|
|
||||||
|
match_ids = mat.matches.where(finished: [nil, 0]).order(:bout_number).limit(4).pluck(:id)
|
||||||
|
mat.update(
|
||||||
|
queue1: match_ids[0],
|
||||||
|
queue2: match_ids[1],
|
||||||
|
queue3: match_ids[2],
|
||||||
|
queue4: match_ids[3]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ class GeneratePoolNumbers
|
|||||||
@weight = weight
|
@weight = weight
|
||||||
end
|
end
|
||||||
|
|
||||||
def savePoolNumbers
|
def savePoolNumbers(wrestlers: nil, persist: true)
|
||||||
@weight.wrestlers.each do |wrestler|
|
wrestlers_to_update = wrestlers || @weight.wrestlers.to_a
|
||||||
|
wrestlers_to_update.each do |wrestler|
|
||||||
wrestler.pool = get_wrestler_pool_number(@weight.pools, wrestler.bracket_line)
|
wrestler.pool = get_wrestler_pool_number(@weight.pools, wrestler.bracket_line)
|
||||||
wrestler.save
|
|
||||||
end
|
end
|
||||||
|
persist_pool_numbers(wrestlers_to_update) if persist
|
||||||
|
wrestlers_to_update
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_wrestler_pool_number(number_of_pools, wrestler_seed)
|
def get_wrestler_pool_number(number_of_pools, wrestler_seed)
|
||||||
@@ -36,4 +38,20 @@ class GeneratePoolNumbers
|
|||||||
|
|
||||||
pool
|
pool
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def persist_pool_numbers(wrestlers)
|
||||||
|
return if wrestlers.blank?
|
||||||
|
|
||||||
|
timestamp = Time.current
|
||||||
|
rows = wrestlers.map do |w|
|
||||||
|
{
|
||||||
|
id: w.id,
|
||||||
|
pool: w.pool,
|
||||||
|
updated_at: timestamp
|
||||||
|
}
|
||||||
|
end
|
||||||
|
Wrestler.upsert_all(rows)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|||||||
@@ -54,29 +54,20 @@ class CalculateWrestlerTeamScore
|
|||||||
def byePoints
|
def byePoints
|
||||||
points = 0
|
points = 0
|
||||||
if @tournament.tournament_type == "Pool to bracket"
|
if @tournament.tournament_type == "Pool to bracket"
|
||||||
if @wrestler.pool_wins.size >= 1 and @wrestler.has_a_pool_bye == true
|
if pool_bye_points_eligible?
|
||||||
points += 2
|
points += 2
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if @tournament.tournament_type.include? "Regular Double Elimination"
|
if @tournament.tournament_type.include? "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 @wrestler.championship_advancement_wins.any? &&
|
||||||
# if they have a win in the championship round or if they got a bye all the way to finals and won the finals
|
@wrestler.championship_byes.any? &&
|
||||||
points += @wrestler.championship_byes.size * 2
|
any_bye_round_had_wrestled_match?(@wrestler.championship_byes)
|
||||||
|
points += 2
|
||||||
end
|
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 @wrestler.consolation_advancement_wins.any? &&
|
||||||
# if they have a win in the consolation round or if they got a bye all the way to 3rd/4th match and won
|
@wrestler.consolation_byes.any? &&
|
||||||
points += @wrestler.consolation_byes.size * 1
|
any_bye_round_had_wrestled_match?(@wrestler.consolation_byes)
|
||||||
end
|
points += 1
|
||||||
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
|
||||||
end
|
end
|
||||||
return points
|
return points
|
||||||
@@ -86,4 +77,30 @@ class CalculateWrestlerTeamScore
|
|||||||
(@wrestler.pin_wins.size * 2) + (@wrestler.tech_wins.size * 1.5) + (@wrestler.major_wins.size * 1)
|
(@wrestler.pin_wins.size * 2) + (@wrestler.tech_wins.size * 1.5) + (@wrestler.major_wins.size * 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def pool_bye_points_eligible?
|
||||||
|
return false unless @wrestler.pool_wins.size >= 1
|
||||||
|
return false unless @wrestler.weight.pools.to_i > 1
|
||||||
|
|
||||||
|
wrestler_pool_size = @wrestler.weight.wrestlers_in_pool(@wrestler.pool).size
|
||||||
|
largest_pool_size = (1..@wrestler.weight.pools).map { |pool_number| @wrestler.weight.wrestlers_in_pool(pool_number).size }.max
|
||||||
|
|
||||||
|
wrestler_pool_size < largest_pool_size
|
||||||
|
end
|
||||||
|
|
||||||
|
def any_bye_round_had_wrestled_match?(bye_matches)
|
||||||
|
bye_matches.any? do |bye_match|
|
||||||
|
next false if bye_match.round.nil?
|
||||||
|
|
||||||
|
@wrestler.weight.matches.any? do |match|
|
||||||
|
next false if match.id == bye_match.id
|
||||||
|
next false if match.round != bye_match.round
|
||||||
|
next false if match.is_consolation_match != bye_match.is_consolation_match
|
||||||
|
|
||||||
|
match.finished == 1 && match.win_type.present? && match.win_type != "BYE"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ json.cache! ["api_tournament", @tournament] do
|
|||||||
|
|
||||||
json.mats @mats do |mat|
|
json.mats @mats do |mat|
|
||||||
json.name mat.name
|
json.name mat.name
|
||||||
json.unfinished_matches mat.unfinished_matches do |match|
|
json.unfinished_matches mat.queue_matches.compact do |match|
|
||||||
json.bout_number match.bout_number
|
json.bout_number match.bout_number
|
||||||
json.w1_name match.w1_name
|
json.w1_name match.w1_name
|
||||||
json.w2_name match.w2_name
|
json.w2_name match.w2_name
|
||||||
|
|||||||
@@ -38,9 +38,10 @@
|
|||||||
<li><strong>Pages</strong></li>
|
<li><strong>Pages</strong></li>
|
||||||
<li></span> <%= link_to "Edit Tournament Info", edit_tournament_path(@tournament) %></li>
|
<li></span> <%= link_to "Edit Tournament Info", edit_tournament_path(@tournament) %></li>
|
||||||
<li><%= link_to "Weigh In Page" , "/tournaments/#{@tournament.id}/weigh_in" %></li>
|
<li><%= link_to "Weigh In Page" , "/tournaments/#{@tournament.id}/weigh_in" %></li>
|
||||||
<li><%= link_to "All Matches" , "/tournaments/#{@tournament.id}/matches" %></li>
|
<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 "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 "QR Code (Full Screen)" , "/tournaments/#{@tournament.id}/qrcode?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 "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 'Manage Backups', tournament_tournament_backups_path(@tournament) %></li>
|
||||||
<li><%= link_to "Reset Bout Board", reset_bout_board_tournament_path(@tournament), data: { turbo_method: :post, turbo_confirm: "Are you sure you want to reset the bout board?" } %></li>
|
<li><%= link_to "Reset Bout Board", reset_bout_board_tournament_path(@tournament), data: { turbo_method: :post, turbo_confirm: "Are you sure you want to reset the bout board?" } %></li>
|
||||||
@@ -60,7 +61,7 @@
|
|||||||
<li><%= link_to "Create Boys Middle School Weights (80-245)" , "/tournaments/#{@tournament.id}/create_custom_weights?customValue=#{Weight::MS_WEIGHT_CLASSES}",data: { turbo_method: :get, turbo_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: { turbo_method: :get, turbo_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: { turbo_method: :get, turbo_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: { turbo_method: :get, turbo_confirm: 'Are you sure? This will delete all current weights.' } %></li>
|
||||||
<li><strong>Tournament Actions</strong></li>
|
<li><strong>Tournament Actions</strong></li>
|
||||||
<li><%= link_to "Calculate Team Scores" , "/tournaments/#{@tournament.id}/calculate_team_scores", :method => :put %></li>
|
<li><%= link_to "Calculate Team Scores" , "/tournaments/#{@tournament.id}/calculate_team_scores", data: { turbo_method: :put } %></li>
|
||||||
<li><%= link_to "Generate Brackets" , "/tournaments/#{@tournament.id}/generate_matches", data: { turbo_method: :get, turbo_confirm: 'Are you sure? This will delete all current matches.' } %></li>
|
<li><%= link_to "Generate Brackets" , "/tournaments/#{@tournament.id}/generate_matches", data: { turbo_method: :get, turbo_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>
|
<li><%= link_to "Export Data" , "/tournaments/#{@tournament.id}/export?print=true", target: :_blank %></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -36,7 +36,11 @@
|
|||||||
|
|
||||||
<div id="page-content">
|
<div id="page-content">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12"><%= render 'layouts/underheader' %></div>
|
<div class="col-md-12">
|
||||||
|
<% unless hide_ads? %>
|
||||||
|
<%= render 'layouts/underheader' %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row no-margin">
|
<div class="row no-margin">
|
||||||
<div class="col-md-12" style="padding-left: 2%;">
|
<div class="col-md-12" style="padding-left: 2%;">
|
||||||
@@ -58,4 +62,3 @@
|
|||||||
</body>
|
</body>
|
||||||
<% end %>
|
<% end %>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,19 @@
|
|||||||
|
|
||||||
<div id="cable-status-indicator" data-match-data-target="statusIndicator" class="alert alert-secondary" style="padding: 5px; margin-bottom: 10px; border-radius: 4px;"></div>
|
<div id="cable-status-indicator" data-match-data-target="statusIndicator" class="alert alert-secondary" style="padding: 5px; margin-bottom: 10px; border-radius: 4px;"></div>
|
||||||
<h4>Bout <strong><%= @match.bout_number %></strong></h4>
|
<h4>Bout <strong><%= @match.bout_number %></strong></h4>
|
||||||
<% if @show_next_bout_button && @next_match %>
|
<% if @mat %>
|
||||||
<%= link_to "Skip to Next Match for Mat #{@mat.name}", mat_path(@mat, bout_number: @next_match.bout_number), class: "btn btn-primary" %>
|
<% queue_matches = @queue_matches || @mat.queue_matches %>
|
||||||
|
<div style="margin-bottom: 10px;">
|
||||||
|
<% queue_matches.each_with_index do |queue_match, index| %>
|
||||||
|
<% queue_label = "Queue #{index + 1}" %>
|
||||||
|
<% if queue_match %>
|
||||||
|
<% button_class = queue_match.id == @match.id ? "btn btn-success btn-sm" : "btn btn-primary btn-sm" %>
|
||||||
|
<%= link_to "#{queue_label}: Bout #{queue_match.bout_number}", mat_path(@mat, bout_number: queue_match.bout_number), class: button_class %>
|
||||||
|
<% else %>
|
||||||
|
<button type="button" class="btn btn-default btn-sm" disabled><%= "#{queue_label}: Not assigned" %></button>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<h4>Bracket Position: <strong><%= @match.bracket_position %></strong></h4>
|
<h4>Bracket Position: <strong><%= @match.bracket_position %></strong></h4>
|
||||||
|
|
||||||
|
|||||||
34
app/views/matches/edit_assignment.html.erb
Normal file
34
app/views/matches/edit_assignment.html.erb
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<h1>Assign Mat/Queue for Match <%= @match.bout_number %></h1>
|
||||||
|
|
||||||
|
<% if @current_mat %>
|
||||||
|
<p>Current Assignment: Mat <%= @current_mat.name %><%= @current_queue_position ? " (Queue #{@current_queue_position})" : "" %></p>
|
||||||
|
<% else %>
|
||||||
|
<p>Current Assignment: Unassigned</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= form_with model: @match, url: update_assignment_match_path(@match), method: :patch do |f| %>
|
||||||
|
<div class="field">
|
||||||
|
<%= f.label :mat_id, "Mat" %><br>
|
||||||
|
<%= f.collection_select :mat_id, @mats, :id, :name, { include_blank: "Unassigned" } %>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div class="field">
|
||||||
|
<%= f.label :queue_position, "Queue Position" %><br>
|
||||||
|
<%= f.select :queue_position,
|
||||||
|
options_for_select(
|
||||||
|
[
|
||||||
|
["On Mat (Queue 1)", 1],
|
||||||
|
["On Deck (Queue 2)", 2],
|
||||||
|
["In The Hole (Queue 3)", 3],
|
||||||
|
["Warm Up (Queue 4)", 4]
|
||||||
|
],
|
||||||
|
@current_queue_position
|
||||||
|
),
|
||||||
|
include_blank: "Select position"
|
||||||
|
%>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div class="actions">
|
||||||
|
<%= f.submit "Update Assignment", class: "btn btn-success" %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
39
app/views/mats/_current_match.html.erb
Normal file
39
app/views/mats/_current_match.html.erb
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<% @mat = mat %>
|
||||||
|
<% @queue_matches = local_assigns[:queue_matches] || mat.queue_matches %>
|
||||||
|
<% @match = local_assigns[:match] || @queue_matches[0] %>
|
||||||
|
<% @match ||= @queue_matches[0] %>
|
||||||
|
<% @next_match = local_assigns[:next_match] || @queue_matches[1] %>
|
||||||
|
<% @show_next_bout_button = local_assigns.key?(:show_next_bout_button) ? local_assigns[:show_next_bout_button] : true %>
|
||||||
|
|
||||||
|
<% @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 %>
|
||||||
|
|
||||||
|
<% if @match %>
|
||||||
|
<%= render "matches/matchstats" %>
|
||||||
|
<% else %>
|
||||||
|
<p>No matches assigned to this mat.</p>
|
||||||
|
<% end %>
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
<h3>Mat <%= @mat.name %></h3>
|
<h3>Mat <%= @mat.name %></h3>
|
||||||
<h3>Tournament: <%= @mat.tournament.name %></h3>
|
<h3>Tournament: <%= @mat.tournament.name %></h3>
|
||||||
|
|
||||||
<% if @match %>
|
<%= turbo_stream_from @mat %>
|
||||||
<%= render 'matches/matchstats' %>
|
|
||||||
<% else %>
|
|
||||||
<p>No matches assigned to this mat.</p>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
|
<%= turbo_frame_tag dom_id(@mat, :current_match) do %>
|
||||||
|
<%= render "mats/current_match",
|
||||||
|
mat: @mat,
|
||||||
|
match: @match,
|
||||||
|
next_match: @next_match,
|
||||||
|
show_next_bout_button: @show_next_bout_button %>
|
||||||
|
<% end %>
|
||||||
|
|||||||
13
app/views/schools/_wrestler_row_cells.html.erb
Normal file
13
app/views/schools/_wrestler_row_cells.html.erb
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<% if local_assigns[:school_permission_key].present? %>
|
||||||
|
<% wrestler_path_with_key = wrestler_path(wrestler) %>
|
||||||
|
<% wrestler_path_with_key += "?school_permission_key=#{school_permission_key}" %>
|
||||||
|
<td><%= link_to wrestler.name, wrestler_path_with_key %></td>
|
||||||
|
<% else %>
|
||||||
|
<td><%= link_to wrestler.name, wrestler_path(wrestler) %></td>
|
||||||
|
<% end %>
|
||||||
|
<td><%= wrestler.weight.max %></td>
|
||||||
|
<td><%= wrestler.season_win %>-<%= wrestler.season_loss %> <%= wrestler.criteria %></td>
|
||||||
|
<td><%= wrestler.original_seed %></td>
|
||||||
|
<td><%= wrestler.total_team_points - wrestler.total_points_deducted %></td>
|
||||||
|
<td><%= "Yes" if wrestler.extra? %></td>
|
||||||
|
<td><%= wrestler.next_match_bout_number %> <%= wrestler.next_match_mat_name %></td>
|
||||||
@@ -54,19 +54,8 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<% @wrestlers.sort_by { |w| w.weight.max }.each do |wrestler| %>
|
<% @wrestlers.sort_by { |w| w.weight.max }.each do |wrestler| %>
|
||||||
<% if params[:school_permission_key].present? %>
|
<% if params[:school_permission_key].present? %>
|
||||||
<!-- No caching when school_permission_key is present -->
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<%= render "schools/wrestler_row_cells", wrestler: wrestler, school_permission_key: params[:school_permission_key] %>
|
||||||
<% wrestler_path_with_key = wrestler_path(wrestler) %>
|
|
||||||
<% wrestler_path_with_key += "?school_permission_key=#{params[:school_permission_key]}" if params[:school_permission_key].present? %>
|
|
||||||
<%= link_to wrestler.name, wrestler_path_with_key %>
|
|
||||||
</td>
|
|
||||||
<td><%= wrestler.weight.max %></td>
|
|
||||||
<td><%= wrestler.season_win %>-<%= wrestler.season_loss %> <%= wrestler.criteria %></td>
|
|
||||||
<td><%= wrestler.original_seed %></td>
|
|
||||||
<td><%= wrestler.total_team_points - wrestler.total_points_deducted %></td>
|
|
||||||
<td><%= "Yes" if wrestler.extra? %></td>
|
|
||||||
<td><%= wrestler.next_match_bout_number %> <%= wrestler.next_match_mat_name %></td>
|
|
||||||
|
|
||||||
<% if can? :manage, wrestler.school %>
|
<% if can? :manage, wrestler.school %>
|
||||||
<td>
|
<td>
|
||||||
@@ -76,36 +65,31 @@
|
|||||||
<% delete_wrestler_path_with_key = wrestler_path(wrestler) %>
|
<% delete_wrestler_path_with_key = wrestler_path(wrestler) %>
|
||||||
<% delete_wrestler_path_with_key += "?school_permission_key=#{params[:school_permission_key]}" if params[:school_permission_key].present? %>
|
<% delete_wrestler_path_with_key += "?school_permission_key=#{params[:school_permission_key]}" if params[:school_permission_key].present? %>
|
||||||
|
|
||||||
<%= link_to '', edit_wrestler_path_with_key, class: "fas fa-edit" %>
|
<%= link_to edit_wrestler_path_with_key, class: "text-decoration-none" do %>
|
||||||
<%= link_to '', delete_wrestler_path_with_key, data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete #{wrestler.name}? This will delete all of his matches." }, class: "fas fa-trash-alt" %>
|
<span class="fas fa-edit" aria-hidden="true"></span>
|
||||||
|
<% end %>
|
||||||
|
<%= link_to delete_wrestler_path_with_key, data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete #{wrestler.name}? This will delete all of his matches." }, class: "text-decoration-none" do %>
|
||||||
|
<span class="fas fa-trash-alt" aria-hidden="true"></span>
|
||||||
|
<% end %>
|
||||||
</td>
|
</td>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tr>
|
</tr>
|
||||||
<% else %>
|
<% else %>
|
||||||
<!-- Use caching only when school_permission_key is NOT present -->
|
<tr>
|
||||||
<% cache ["#{wrestler.id}_school_show", @school] do %>
|
<% cache ["school_show_wrestler_cells", wrestler] do %>
|
||||||
<tr>
|
<%= render "schools/wrestler_row_cells", wrestler: wrestler %>
|
||||||
<td><%= link_to wrestler.name, wrestler_path(wrestler) %></td>
|
<% end %>
|
||||||
<td><%= wrestler.weight.max %></td>
|
<% if can? :manage, wrestler.school %>
|
||||||
<td><%= wrestler.season_win %>-<%= wrestler.season_loss %> <%= wrestler.criteria %></td>
|
<td>
|
||||||
<td><%= wrestler.original_seed %></td>
|
<%= link_to edit_wrestler_path(wrestler), class: "text-decoration-none" do %>
|
||||||
<td><%= wrestler.total_team_points - wrestler.total_points_deducted %></td>
|
<span class="fas fa-edit" aria-hidden="true"></span>
|
||||||
<td><%= "Yes" if wrestler.extra? %></td>
|
<% end %>
|
||||||
<td><%= wrestler.next_match_bout_number %> <%= wrestler.next_match_mat_name %></td>
|
<%= link_to wrestler_path(wrestler), data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete #{wrestler.name}? This will delete all of his matches." }, class: "text-decoration-none" do %>
|
||||||
<% end %>
|
<span class="fas fa-trash-alt" aria-hidden="true"></span>
|
||||||
<% if can? :manage, wrestler.school %>
|
<% end %>
|
||||||
<td>
|
</td>
|
||||||
<% edit_wrestler_path_with_key = edit_wrestler_path(wrestler) %>
|
<% end %>
|
||||||
<% edit_wrestler_path_with_key += "?school_permission_key=#{params[:school_permission_key]}" if params[:school_permission_key].present? %>
|
</tr>
|
||||||
|
|
||||||
<% delete_wrestler_path_with_key = wrestler_path(wrestler) %>
|
|
||||||
<% delete_wrestler_path_with_key += "?school_permission_key=#{params[:school_permission_key]}" if params[:school_permission_key].present? %>
|
|
||||||
|
|
||||||
<%= link_to '', edit_wrestler_path_with_key, class: "fas fa-edit" %>
|
|
||||||
<%= link_to '', delete_wrestler_path_with_key, data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete #{wrestler.name}? This will delete all of his matches." }, class: "fas fa-trash-alt" %>
|
|
||||||
</td>
|
|
||||||
<% end %>
|
|
||||||
</tr>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
<li>Win by major: 1pt extra</li>
|
<li>Win by major: 1pt extra</li>
|
||||||
<li>Win by tech fall: 1.5pt extra</li>
|
<li>Win by tech fall: 1.5pt extra</li>
|
||||||
<li>Win by fall, default, dq: 2pt extra</li>
|
<li>Win by fall, default, dq: 2pt extra</li>
|
||||||
<li>BYE points: 2pt (if you win at least 1 match in a pool with a BYE)</li>
|
<li>BYE points: 2pt (if you win at least 1 match in a pool with a BYE). - This only applies if your pool has more BYEs than other pools in your bracket. This does not apply to weight classes with 1 pool.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>See placement points below (based on the largest bracket of the tournament)</p>
|
<p>See placement points below (based on the largest bracket of the tournament)</p>
|
||||||
<h4>Pool Types</h4>
|
<h4>Pool Types</h4>
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
<li>Win by major: 1pt extra</li>
|
<li>Win by major: 1pt extra</li>
|
||||||
<li>Win by tech: 1.5pt extra</li>
|
<li>Win by tech: 1.5pt extra</li>
|
||||||
<li>Win by fall, default, dq, etc: 2pt extra</li>
|
<li>Win by fall, default, dq, etc: 2pt extra</li>
|
||||||
<li>BYE points: 2pts if you have a bye in the championship bracket and win the next match. 1pt if you have a bye in the consolation bracket and win the next match.</li>
|
<li>BYE points: 2pts if you have a bye in the championship bracket and win the next match. 1pt if you have a bye in the consolation bracket and win the next match. - This only applies if you received a bye in a round with at least 1 match in your backet.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
<h3>Modified 16 Man Double Elimination Information</h3>
|
<h3>Modified 16 Man Double Elimination Information</h3>
|
||||||
@@ -142,7 +142,7 @@
|
|||||||
<br>
|
<br>
|
||||||
<h3>Future Plans</h3>
|
<h3>Future Plans</h3>
|
||||||
<br>
|
<br>
|
||||||
<p>Future development plans to support 32 and 64 man regulard double elimination, modified (5 per day match rule) 32 man double elimination, and true second double elimination brackets are underway.</p>
|
<p>Future development plans are underway to make the application more flexible, make changes after weigh ins easier, and to add functionality for a live scoreboard.</p>
|
||||||
<br>
|
<br>
|
||||||
<h3>Contact</h3>
|
<h3>Contact</h3>
|
||||||
<br>
|
<br>
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
<% if @tournaments.size > 0 %>
|
<% if @tournaments.size > 0 %>
|
||||||
<h3>My Tournaments</h3>
|
<h3>My Tournaments</h3>
|
||||||
<script>
|
|
||||||
// $(document).ready(function() {
|
|
||||||
// $('#tournamentList').dataTable();
|
|
||||||
// pagingType: "bootstrap";
|
|
||||||
// } );
|
|
||||||
</script>
|
|
||||||
<table class="table table-hover" id="tournamentList">
|
<table class="table table-hover" id="tournamentList">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ and will also delete all of your current data. It's best to use the create backu
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<br><br>
|
<br><br>
|
||||||
<h3>Import Manual Backup</h3>
|
<% if ENV["RAILS_ENV"] == "development" %>
|
||||||
<p>Paste the backup text here. Note, if this is formatted wrong, you'll need to restore a backup from above to fix it and you'll see an error in your background jobs.</p>
|
<%= form_for(:tournament, url: import_manual_tournament_tournament_backups_path(@tournament)) do |f| %>
|
||||||
<%= form_for(:tournament, url: import_manual_tournament_tournament_backups_path(@tournament)) do |f| %>
|
<div class="field">
|
||||||
<div class="field">
|
<%= f.label 'Import text' %><br>
|
||||||
<%= f.label 'Import text' %><br>
|
<%= f.text_area :import_text, cols: "30", rows: "20" %>
|
||||||
<%= f.text_area :import_text, cols: "30", rows: "20" %>
|
</div>
|
||||||
</div>
|
<%= submit_tag "Import", class: "btn btn-success", data: { turbo_confirm: 'Are you sure? This will delete everything for the current tournament and restore it with the backup text pasted below.' } %>
|
||||||
<%= submit_tag "Import", class: "btn btn-success", data: { confirm: 'Are you sure? This will delete everything for the current tournament and restore it with the backup text pasted below.' } %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
@@ -1,9 +1,15 @@
|
|||||||
<% @final_match.each do |match| %>
|
<% @final_match.each do |match| %>
|
||||||
<div class="round">
|
<% cache ["bracket_final_match", match, match.wrestler1, match.wrestler2, @winner_place, params[:print].to_s] do %>
|
||||||
<div class="game">
|
<div class="round">
|
||||||
<div class="game-top "><%= match.w1_bracket_name.html_safe %> <span></span></div>
|
<div class="game">
|
||||||
<div class="bout-number"><p><%= link_to match.bout_number, spectate_match_path(match) %> <%= match.bracket_score_string %></p><p><%= @winner_place %> Place Winner</p></div>
|
<div class="game-top "><%= match.w1_bracket_name.html_safe %> <span></span></div>
|
||||||
<div class="game-bottom "><%= match.w2_bracket_name.html_safe %><span></span></div>
|
<% if params[:print] %>
|
||||||
</div>
|
<div class="bout-number"><p><%= match.bout_number %> <%= match.bracket_score_string %></p><p><%= @winner_place %> Place Winner</p></div>
|
||||||
</div>
|
<% else %>
|
||||||
|
<div class="bout-number"><p><%= link_to match.bout_number, spectate_match_path(match) %> <%= match.bracket_score_string %></p><p><%= @winner_place %> Place Winner</p></div>
|
||||||
|
<% end %>
|
||||||
|
<div class="game-bottom "><%= match.w2_bracket_name.html_safe %><span></span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,18 +1,26 @@
|
|||||||
<style>
|
<style>
|
||||||
table.smallText tr td { font-size: 10px; }
|
table.smallText tr td { font-size: 10px; }
|
||||||
|
table.smallText {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
table.smallText th,
|
||||||
|
table.smallText td {
|
||||||
|
border: 1px solid #000;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Bracket Layout Specifics
|
* Bracket Layout Specifics
|
||||||
*/
|
*/
|
||||||
.bracket {
|
.bracket {
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 10px;
|
font-size: 10.5px;
|
||||||
|
gap: 2px;
|
||||||
}
|
}
|
||||||
.game {
|
.game {
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
min-height: 50px;
|
min-height: 58px;
|
||||||
/*background-color: #ddd;*/
|
/*background-color: #ddd;*/
|
||||||
border: 1px solid #ddd;
|
border: 1.5px solid #000; /* Dark border so boxes stay visible when printed */
|
||||||
margin: 5px;
|
margin: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*.game:after {
|
/*.game:after {
|
||||||
@@ -56,14 +64,15 @@ table.smallText tr td { font-size: 10px; }
|
|||||||
}
|
}
|
||||||
|
|
||||||
.game-top {
|
.game-top {
|
||||||
border-bottom:1px solid #ddd;
|
border-bottom:1.5px solid #000;
|
||||||
padding: 2px;
|
padding: 3px 4px;
|
||||||
min-height: 12px;
|
min-height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bout-number {
|
.bout-number {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
/*padding-top: 15px;*/
|
line-height: 1.35;
|
||||||
|
padding: 1px 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Style links within bout-number like default links */
|
/* Style links within bout-number like default links */
|
||||||
@@ -77,15 +86,29 @@ table.smallText tr td { font-size: 10px; }
|
|||||||
}
|
}
|
||||||
|
|
||||||
.bracket-winner {
|
.bracket-winner {
|
||||||
border-bottom:1px solid #ddd;
|
border-bottom:1.5px solid #000;
|
||||||
padding: 2px;
|
padding: 3px 4px;
|
||||||
min-height: 12px;
|
min-height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-bottom {
|
.game-bottom {
|
||||||
border-top:1px solid #ddd;
|
border-top:1.5px solid #000;
|
||||||
padding: 2px;
|
padding: 3px 4px;
|
||||||
min-height: 12px;
|
min-height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
.game,
|
||||||
|
.game-top,
|
||||||
|
.game-bottom,
|
||||||
|
.bracket-winner,
|
||||||
|
table.smallText,
|
||||||
|
table.smallText th,
|
||||||
|
table.smallText td {
|
||||||
|
border-color: #000 !important;
|
||||||
|
-webkit-print-color-adjust: exact;
|
||||||
|
print-color-adjust: exact;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<% if @tournament.tournament_type == "Pool to bracket" %>
|
<% if @tournament.tournament_type == "Pool to bracket" %>
|
||||||
@@ -95,8 +118,6 @@ table.smallText tr td { font-size: 10px; }
|
|||||||
<table class='smallText'>
|
<table class='smallText'>
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top" style="padding: 10px;">
|
<td valign="top" style="padding: 10px;">
|
||||||
<% @matches = @tournament.matches.select{|m| m.weight_id == @weight.id} %>
|
|
||||||
<% @wrestlers = Wrestler.where(weight_id: @weight.id) %>
|
|
||||||
<% @pools = @weight.pool_rounds(@matches) %>
|
<% @pools = @weight.pool_rounds(@matches) %>
|
||||||
<%= render 'pool' %>
|
<%= render 'pool' %>
|
||||||
</td>
|
</td>
|
||||||
@@ -131,4 +152,4 @@ table.smallText tr td { font-size: 10px; }
|
|||||||
<% elsif @tournament.tournament_type.include? "Regular Double Elimination" %>
|
<% elsif @tournament.tournament_type.include? "Regular Double Elimination" %>
|
||||||
<%= render 'double_elimination_bracket' %>
|
<%= render 'double_elimination_bracket' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
<div class="round">
|
<div class="round">
|
||||||
<% @round_matches.sort_by{|m| m.bracket_position_number}.each do |match| %>
|
<% @round_matches.sort_by{|m| m.bracket_position_number}.each do |match| %>
|
||||||
<div class="game">
|
<% cache ["bracket_round_match", match, match.wrestler1, match.wrestler2, params[:print].to_s] do %>
|
||||||
<div class="game-top "><%= match.w1_bracket_name.html_safe %> <span></span></div>
|
<div class="game">
|
||||||
<div class="bout-number"><%= link_to match.bout_number, spectate_match_path(match) %> <%= match.bracket_score_string %> </div>
|
<div class="game-top "><%= match.w1_bracket_name.html_safe %> <span></span></div>
|
||||||
<div class="game-bottom "><%= match.w2_bracket_name.html_safe %><span></span></div>
|
<% if params[:print] %>
|
||||||
</div>
|
<div class="bout-number"><%= match.bout_number %> <%= match.bracket_score_string %> </div>
|
||||||
|
<% else %>
|
||||||
|
<div class="bout-number"><%= link_to match.bout_number, spectate_match_path(match) %> <%= match.bracket_score_string %> </div>
|
||||||
|
<% end %>
|
||||||
|
<div class="bout-number">Round <%= match.round %></div>
|
||||||
|
<div class="bout-number"><%= match.bracket_position %></div>
|
||||||
|
<div class="game-bottom "><%= match.w2_bracket_name.html_safe %><span></span></div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
6
app/views/tournaments/_team_score_row.html.erb
Normal file
6
app/views/tournaments/_team_score_row.html.erb
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<% cache ["team_score_row", school, rank] do %>
|
||||||
|
<tr>
|
||||||
|
<td><%= rank %>. <%= school.name %> (<%= school.abbreviation %>)</td>
|
||||||
|
<td><%= school.page_score_string %></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
38
app/views/tournaments/_up_matches_board.html.erb
Normal file
38
app/views/tournaments/_up_matches_board.html.erb
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<div id="up_matches_board">
|
||||||
|
<h3>Upcoming Matches</h3>
|
||||||
|
<table class="table table-striped table-bordered table-condensed">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Mat </th>
|
||||||
|
<th>On Mat</th>
|
||||||
|
<th>On Deck</th>
|
||||||
|
<th>In The Hole</th>
|
||||||
|
<th>Warm Up</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<% (local_assigns[:mats] || tournament.up_matches_mats).each do |m| %>
|
||||||
|
<%= render "tournaments/up_matches_mat_row", mat: m %>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<br>
|
||||||
|
<h3>Matches not assigned</h3>
|
||||||
|
<br>
|
||||||
|
<table class="table table-striped table-bordered table-condensed" id="matchList">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Round</th>
|
||||||
|
<th>Bout Number</th>
|
||||||
|
<th>Weight Class</th>
|
||||||
|
<th>Matchup</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<%= render partial: "tournaments/up_matches_unassigned_row", collection: (local_assigns[:matches] || tournament.up_matches_unassigned_matches), as: :match %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
35
app/views/tournaments/_up_matches_mat_row.html.erb
Normal file
35
app/views/tournaments/_up_matches_mat_row.html.erb
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<% queue1_match, queue2_match, queue3_match, queue4_match = mat.queue_matches %>
|
||||||
|
<% queue_match_dependencies = [queue1_match, queue2_match, queue3_match, queue4_match].compact.flat_map { |match| [match, match.wrestler1, match.wrestler2] } %>
|
||||||
|
<% cache ["up_matches_mat_row", mat, *queue_match_dependencies] do %>
|
||||||
|
<tr>
|
||||||
|
<td><%= mat.name %></td>
|
||||||
|
<td>
|
||||||
|
<% if queue1_match %><strong><%= queue1_match.bout_number %></strong> (<%= queue1_match.bracket_position %>)<br>
|
||||||
|
<%= queue1_match.weight_max %> lbs
|
||||||
|
<br><%= queue1_match.w1_bracket_name %> vs. <br>
|
||||||
|
<%= queue1_match.w2_bracket_name %>
|
||||||
|
<% end %>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<% if queue2_match %><strong><%= queue2_match.bout_number %></strong> (<%= queue2_match.bracket_position %>)<br>
|
||||||
|
<%= queue2_match.weight_max %> lbs
|
||||||
|
<br><%= queue2_match.w1_bracket_name %> vs. <br>
|
||||||
|
<%= queue2_match.w2_bracket_name %>
|
||||||
|
<% end %>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<% if queue3_match %><strong><%= queue3_match.bout_number %></strong> (<%= queue3_match.bracket_position %>)<br>
|
||||||
|
<%= queue3_match.weight_max %> lbs
|
||||||
|
<br><%= queue3_match.w1_bracket_name %> vs. <br>
|
||||||
|
<%= queue3_match.w2_bracket_name %>
|
||||||
|
<% end %>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<% if queue4_match %><strong><%= queue4_match.bout_number %></strong> (<%= queue4_match.bracket_position %>)<br>
|
||||||
|
<%= queue4_match.weight_max %> lbs
|
||||||
|
<br><%= queue4_match.w1_bracket_name %> vs. <br>
|
||||||
|
<%= queue4_match.w2_bracket_name %>
|
||||||
|
<% end %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<% cache ["up_matches_unassigned_row", match, match.wrestler1, match.wrestler2] do %>
|
||||||
|
<tr>
|
||||||
|
<td>Round <%= match.round %></td>
|
||||||
|
<td><%= match.bout_number %></td>
|
||||||
|
<td><%= match.weight_max %></td>
|
||||||
|
<td><%= match.w1_bracket_name %> vs. <%= match.w2_bracket_name %></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
@@ -1,20 +1,20 @@
|
|||||||
<style>
|
<style>
|
||||||
/* General styles for pages */
|
/* General styles for pages */
|
||||||
@page {
|
@page {
|
||||||
margin: 0.5in; /* Universal margin for all pages */
|
margin: 0.35in;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
width: 7.5in; /* Portrait width (8.5in - margins) */
|
width: 7.8in; /* 8.5in - 2 * 0.35in */
|
||||||
height: 10in; /* Portrait height (11in - margins) */
|
height: 10.3in; /* 11in - 2 * 0.35in */
|
||||||
margin: auto;
|
margin: auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-landscape {
|
.page-landscape {
|
||||||
width: 10in; /* Landscape width (11in - margins) */
|
width: 10.3in; /* 11in - 2 * 0.35in */
|
||||||
height: 7.5in; /* Landscape height (8.5in - margins) */
|
height: 7.8in; /* 8.5in - 2 * 0.35in */
|
||||||
margin: auto;
|
margin: auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -26,6 +26,11 @@
|
|||||||
transform-origin: top left;
|
transform-origin: top left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bracket-container h4 {
|
||||||
|
margin-top: 0.15rem;
|
||||||
|
margin-bottom: 0.45rem;
|
||||||
|
}
|
||||||
|
|
||||||
/* Print-specific styles */
|
/* Print-specific styles */
|
||||||
@media print {
|
@media print {
|
||||||
/* Set orientation for portrait pages */
|
/* Set orientation for portrait pages */
|
||||||
@@ -51,6 +56,10 @@
|
|||||||
transform-origin: top left;
|
transform-origin: top left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bracket {
|
||||||
|
page-break-inside: avoid;
|
||||||
|
}
|
||||||
|
|
||||||
/* Optional: Hide elements not needed in print */
|
/* Optional: Hide elements not needed in print */
|
||||||
.no-print {
|
.no-print {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -62,15 +71,10 @@
|
|||||||
function scaleContent() {
|
function scaleContent() {
|
||||||
document.querySelectorAll('.page, .page-landscape').forEach(page => {
|
document.querySelectorAll('.page, .page-landscape').forEach(page => {
|
||||||
const container = page.querySelector('.bracket-container');
|
const container = page.querySelector('.bracket-container');
|
||||||
const isLandscape = page.classList.contains('page-landscape');
|
|
||||||
|
|
||||||
// Page dimensions (1 inch = 96px)
|
// Use the actual page box size (already accounts for @page margins)
|
||||||
const pageWidth = isLandscape ? 10 * 96 : 7.5 * 96;
|
const availableWidth = page.clientWidth;
|
||||||
const pageHeight = isLandscape ? 7.5 * 96 : 10 * 96;
|
const availableHeight = page.clientHeight;
|
||||||
|
|
||||||
// Subtract margins (0.5 inch margin)
|
|
||||||
const availableWidth = pageWidth - (0.5 * 96 * 2);
|
|
||||||
const availableHeight = pageHeight - (0.5 * 96 * 2);
|
|
||||||
|
|
||||||
// Measure content dimensions
|
// Measure content dimensions
|
||||||
const contentWidth = container.scrollWidth;
|
const contentWidth = container.scrollWidth;
|
||||||
@@ -80,8 +84,8 @@
|
|||||||
const scaleX = availableWidth / contentWidth;
|
const scaleX = availableWidth / contentWidth;
|
||||||
const scaleY = availableHeight / contentHeight;
|
const scaleY = availableHeight / contentHeight;
|
||||||
|
|
||||||
// Use a slightly relaxed scaling to avoid over-aggressive shrinking
|
// Keep a tiny buffer so borders/text don't clip at print edges
|
||||||
const scale = Math.min(scaleX, scaleY, 1); // Ensure scale does not exceed 100% (1)
|
const scale = Math.min(scaleX, scaleY, 1) * 0.99;
|
||||||
|
|
||||||
// Apply the scale
|
// Apply the scale
|
||||||
container.style.transform = `scale(${scale})`;
|
container.style.transform = `scale(${scale})`;
|
||||||
@@ -91,9 +95,9 @@
|
|||||||
const scaledWidth = contentWidth * scale;
|
const scaledWidth = contentWidth * scale;
|
||||||
const scaledHeight = contentHeight * scale;
|
const scaledHeight = contentHeight * scale;
|
||||||
|
|
||||||
// Center the content within the page
|
// Center the content within the available page box
|
||||||
const horizontalPadding = (pageWidth - scaledWidth) / 2;
|
const horizontalPadding = (availableWidth - scaledWidth) / 2;
|
||||||
const verticalPadding = (pageHeight - scaledHeight) / 2;
|
const verticalPadding = (availableHeight - scaledHeight) / 2;
|
||||||
|
|
||||||
// Apply margin adjustments
|
// Apply margin adjustments
|
||||||
container.style.marginLeft = `${Math.max(0, horizontalPadding)}px`;
|
container.style.marginLeft = `${Math.max(0, horizontalPadding)}px`;
|
||||||
@@ -119,16 +123,17 @@
|
|||||||
<% @weights.sort_by{|w| w.max}.each do |weight| %>
|
<% @weights.sort_by{|w| w.max}.each do |weight| %>
|
||||||
<% if @tournament.tournament_type == "Pool to bracket" %>
|
<% if @tournament.tournament_type == "Pool to bracket" %>
|
||||||
<!-- Need to define what the tournaments#bracket controller defines -->
|
<!-- Need to define what the tournaments#bracket controller defines -->
|
||||||
<% @matches = @tournament.matches.select{|m| m.weight_id == weight.id} %>
|
<% @matches = @matches_by_weight_id[weight.id] || [] %>
|
||||||
<% @wrestlers = Wrestler.where(weight_id: weight.id) %>
|
<% @wrestlers = @wrestlers_by_weight_id[weight.id] || [] %>
|
||||||
<% @pools = weight.pool_rounds(@matches) %>
|
<% @pools = weight.pool_rounds(@matches) %>
|
||||||
<% @weight = weight %>
|
<% @weight = weight %>
|
||||||
<%= render 'bracket_partial' %>
|
<%= render 'bracket_partial' %>
|
||||||
<% elsif @tournament.tournament_type.include? "Modified 16 Man Double Elimination" or @tournament.tournament_type.include? "Regular Double Elimination" %>
|
<% elsif @tournament.tournament_type.include? "Modified 16 Man Double Elimination" or @tournament.tournament_type.include? "Regular Double Elimination" %>
|
||||||
<!-- Need to define what the tournaments#bracket controller defines -->
|
<!-- Need to define what the tournaments#bracket controller defines -->
|
||||||
<% @matches = weight.matches %>
|
<% @matches = @matches_by_weight_id[weight.id] || [] %>
|
||||||
|
<% @wrestlers = @wrestlers_by_weight_id[weight.id] || [] %>
|
||||||
<% @weight = weight %>
|
<% @weight = weight %>
|
||||||
<%= render 'bracket_partial' %>
|
<%= render 'bracket_partial' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -54,28 +54,28 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<% @matches.each do |match| %>
|
<% @matches.each do |match| %>
|
||||||
<% if match.w1 && match.w2 %>
|
<% w1 = @wrestlers_by_id[match.w1] %>
|
||||||
<% w1 = Wrestler.find(match.w1) %>
|
<% w2 = @wrestlers_by_id[match.w2] %>
|
||||||
<% w2 = Wrestler.find(match.w2) %>
|
<% w1_name = w1&.name || match.loser1_name %>
|
||||||
<% end %>
|
<% w2_name = w2&.name || match.loser2_name %>
|
||||||
|
|
||||||
<div class="pagebreak">
|
<div class="pagebreak">
|
||||||
<p><strong>Bout Number:</strong> <%= match.bout_number %> <strong>Weight Class:</strong> <%= match.weight.max %> <strong>Round:</strong> <%= match.round %> <strong>Bracket Position:</strong> <%= match.bracket_position %></p>
|
<p><strong>Bout Number:</strong> <%= match.bout_number %> <strong>Weight Class:</strong> <%= match.weight.max %> <strong>Round:</strong> <%= match.round %> <strong>Bracket Position:</strong> <%= match.bracket_position %></p>
|
||||||
<p><strong>Key: </strong>Takedown: T3, Escape: E1, Reversal: R2, Nearfall: N2 or N3 or N4, Stalling: S, Caution: C, Penalty Point: P1</p>
|
<p><strong>Key: </strong>Takedown: T3, Escape: E1, Reversal: R2, Nearfall: N2 or N3 or N4, Stalling: S, Caution: C, Penalty Point: P1</p>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="small-row">
|
<tr class="small-row">
|
||||||
<th class="fixed-width">Circle Winner</th>
|
<th class="fixed-width">Circle Winner</th>
|
||||||
<th>
|
<th>
|
||||||
<p><%= match.w1_name %>-<%= w1&.school&.name %></p>
|
<p><%= w1_name %>-<%= w1&.school&.name %></p>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<p><%= match.w2_name %>-<%= w2&.school&.name %></p>
|
<p><%= w2_name %>-<%= w2&.school&.name %></p>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="small-row">
|
<tr class="small-row">
|
||||||
<td class="fixed-width"></td>
|
<td class="fixed-width"></td>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<% cache ["#{@weight.id}_bracket", @weight] do %>
|
<% cache ["#{@weight.id}_bracket", @weight, params[:print].to_s] do %>
|
||||||
<%= render 'bracket_partial' %>
|
<%= render 'bracket_partial' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if @tournament.tournament_type == "Pool to bracket" %>
|
<% if @tournament.tournament_type == "Pool to bracket" %>
|
||||||
<%= render 'pool_bracket_director_actions' %>
|
<%= render 'pool_bracket_director_actions' %>
|
||||||
<% elsif @tournament.tournament_type.include? "Modified 16 Man Double Elimination" or @tournament.tournament_type.include? "Regular Double Elimination" %>
|
<% elsif @tournament.tournament_type.include? "Modified 16 Man Double Elimination" or @tournament.tournament_type.include? "Regular Double Elimination" %>
|
||||||
<%= render 'bracket_director_actions' %>
|
<%= render 'bracket_director_actions' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,23 +1,33 @@
|
|||||||
{
|
<%
|
||||||
"tournament": {
|
wrestlers_by_id = @tournament.wrestlers.index_by(&:id)
|
||||||
"attributes": <%= @tournament.attributes.to_json %>,
|
weights_by_id = @tournament.weights.index_by(&:id)
|
||||||
|
mats_by_id = @tournament.mats.index_by(&:id)
|
||||||
|
sorted_matches = @tournament.matches.sort_by(&:bout_number)
|
||||||
|
%>
|
||||||
|
{
|
||||||
|
"tournament": {
|
||||||
|
"attributes": <%= @tournament.attributes.to_json %>,
|
||||||
"schools": <%= @tournament.schools.map(&:attributes).to_json %>,
|
"schools": <%= @tournament.schools.map(&:attributes).to_json %>,
|
||||||
"weights": <%= @tournament.weights.map(&:attributes).to_json %>,
|
"weights": <%= @tournament.weights.map(&:attributes).to_json %>,
|
||||||
"mats": <%= @tournament.mats.map(&:attributes).to_json %>,
|
"mats": <%= @tournament.mats.map { |mat| mat.attributes.merge(
|
||||||
|
{
|
||||||
|
"queue_bout_numbers": mat.queue_matches.map { |match| match&.bout_number }
|
||||||
|
}
|
||||||
|
) }.to_json %>,
|
||||||
"wrestlers": <%= @tournament.wrestlers.map { |wrestler| wrestler.attributes.merge(
|
"wrestlers": <%= @tournament.wrestlers.map { |wrestler| wrestler.attributes.merge(
|
||||||
{
|
{
|
||||||
"school": wrestler.school&.attributes,
|
"school": wrestler.school&.attributes,
|
||||||
"weight": wrestler.weight&.attributes
|
"weight": wrestler.weight&.attributes
|
||||||
}
|
}
|
||||||
) }.to_json %>,
|
) }.to_json %>,
|
||||||
"matches": <%= @tournament.matches.sort_by(&:bout_number).map { |match| match.attributes.merge(
|
"matches": <%= sorted_matches.map { |match| match.attributes.merge(
|
||||||
{
|
{
|
||||||
"w1_name": Wrestler.find_by(id: match.w1)&.name,
|
"w1_name": wrestlers_by_id[match.w1]&.name,
|
||||||
"w2_name": Wrestler.find_by(id: match.w2)&.name,
|
"w2_name": wrestlers_by_id[match.w2]&.name,
|
||||||
"winner_name": Wrestler.find_by(id: match.winner_id)&.name,
|
"winner_name": wrestlers_by_id[match.winner_id]&.name,
|
||||||
"weight": Weight.find_by(id: match.weight_id)&.attributes,
|
"weight": weights_by_id[match.weight_id]&.attributes,
|
||||||
"mat": Mat.find_by(id: match.mat_id)&.attributes
|
"mat": mats_by_id[match.mat_id]&.attributes
|
||||||
}
|
}
|
||||||
) }.to_json %>
|
) }.to_json %>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
|
|
||||||
|
|
||||||
<h1>All <%= @tournament.name %> matches</h1>
|
<h1>All <%= @tournament.name %> matches</h1>
|
||||||
<script>
|
|
||||||
$(document).ready(function() {
|
<% matches_path = "/tournaments/#{@tournament.id}/matches" %>
|
||||||
$('#matchesList').dataTable();
|
|
||||||
pagingType: "bootstrap";
|
<%= form_tag(matches_path, method: :get, id: "search-form") do %>
|
||||||
} );
|
<%= text_field_tag :search, params[:search], placeholder: "Search wrestler, school, or bout #" %>
|
||||||
</script>
|
<%= submit_tag "Search" %>
|
||||||
</br>
|
<% end %>
|
||||||
|
|
||||||
|
<p>Search by wrestler name, school name, or bout number.</p>
|
||||||
|
|
||||||
|
<br>
|
||||||
<table class="table table-striped table-bordered table-condensed" id="matchesList">
|
<table class="table table-striped table-bordered table-condensed" id="matchesList">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -28,9 +30,56 @@
|
|||||||
<td><%= match.finished %></td>
|
<td><%= match.finished %></td>
|
||||||
<td><%= link_to 'Show', match, :class=>"btn btn-default btn-sm" %>
|
<td><%= link_to 'Show', match, :class=>"btn btn-default btn-sm" %>
|
||||||
<%= link_to 'Edit Wrestlers', edit_match_path(match), :class=>"btn btn-primary btn-sm" %>
|
<%= link_to 'Edit Wrestlers', edit_match_path(match), :class=>"btn btn-primary btn-sm" %>
|
||||||
|
<%= link_to 'Edit Mat/Queue', edit_assignment_match_path(match), :class=>"btn btn-primary btn-sm" %>
|
||||||
<%= link_to 'Stat Match', "/matches/#{match.id}/stat", :class=>"btn btn-primary btn-sm" %>
|
<%= link_to 'Stat Match', "/matches/#{match.id}/stat", :class=>"btn btn-primary btn-sm" %>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<% if @total_pages.present? && @total_pages > 1 %>
|
||||||
|
<nav aria-label="Matches pagination">
|
||||||
|
<ul class="pagination">
|
||||||
|
<% if @page > 1 %>
|
||||||
|
<li class="page-item">
|
||||||
|
<%= link_to "Previous", { controller: "tournaments", action: "matches", id: @tournament.id, page: @page - 1, search: params[:search] }, class: "page-link" %>
|
||||||
|
</li>
|
||||||
|
<% else %>
|
||||||
|
<li class="page-item disabled"><span class="page-link">Previous</span></li>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% window = 5
|
||||||
|
left = [1, @page - window / 2].max
|
||||||
|
right = [@total_pages, left + window - 1].min
|
||||||
|
left = [1, right - window + 1].max
|
||||||
|
%>
|
||||||
|
<% (left..right).each do |p| %>
|
||||||
|
<% if p == @page %>
|
||||||
|
<li class="page-item active"><span class="page-link"><%= p %></span></li>
|
||||||
|
<% else %>
|
||||||
|
<li class="page-item"><%= link_to p, { controller: "tournaments", action: "matches", id: @tournament.id, page: p, search: params[:search] }, class: "page-link" %></li>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if @page < @total_pages %>
|
||||||
|
<li class="page-item">
|
||||||
|
<%= link_to "Next", { controller: "tournaments", action: "matches", id: @tournament.id, page: @page + 1, search: params[:search] }, class: "page-link" %>
|
||||||
|
</li>
|
||||||
|
<% else %>
|
||||||
|
<li class="page-item disabled"><span class="page-link">Next</span></li>
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<p class="text-muted">
|
||||||
|
<% start_index = ((@page - 1) * @per_page) + 1
|
||||||
|
end_index = [@page * @per_page, @total_count].min
|
||||||
|
%>
|
||||||
|
Showing <%= start_index %> - <%= end_index %> of <%= @total_count %> matches
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<p>Total matches without byes: <%= @matches_without_byes_count %></p>
|
||||||
|
<p>Unfinished matches: <%= @unfinished_matches_without_byes_count %></p>
|
||||||
|
|||||||
50
app/views/tournaments/qrcode.html.erb
Normal file
50
app/views/tournaments/qrcode.html.erb
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<style>
|
||||||
|
.qr-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-page h1 {
|
||||||
|
margin: 0 0 24px 0;
|
||||||
|
font-size: 40px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-code {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-code svg {
|
||||||
|
width: min(80vmin, 720px);
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="qr-page">
|
||||||
|
<h1><%= @tournament.name %> Brackets and Results Available Here</h1>
|
||||||
|
<div class="qr-code">
|
||||||
|
<%= raw @qrcode.as_svg(
|
||||||
|
offset: 0,
|
||||||
|
color: "000",
|
||||||
|
shape_rendering: "crispEdges",
|
||||||
|
module_size: 8,
|
||||||
|
standalone: true
|
||||||
|
) %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -70,9 +70,13 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<% if can? :manage, school %>
|
<% if can? :manage, school %>
|
||||||
<%= link_to '', edit_school_path(school), :class=>"fas fa-edit" %>
|
<%= link_to edit_school_path(school), class: "text-decoration-none" do %>
|
||||||
|
<span class="fas fa-edit" aria-hidden="true"></span>
|
||||||
|
<% end %>
|
||||||
<% if can? :manage, @tournament %>
|
<% if can? :manage, @tournament %>
|
||||||
<%= link_to '', school, data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete #{school.name}?" }, :class=>"fas fa-trash-alt" %>
|
<%= link_to school, data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete #{school.name}?" }, class: "text-decoration-none" do %>
|
||||||
|
<span class="fas fa-trash-alt" aria-hidden="true"></span>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</td>
|
</td>
|
||||||
@@ -105,8 +109,12 @@
|
|||||||
<td><%= weight.bracket_size %></td>
|
<td><%= weight.bracket_size %></td>
|
||||||
<% if can? :manage, @tournament %>
|
<% if can? :manage, @tournament %>
|
||||||
<td>
|
<td>
|
||||||
<%= link_to '', edit_weight_path(weight), :class=>"fas fa-edit" %>
|
<%= link_to edit_weight_path(weight), class: "text-decoration-none" do %>
|
||||||
<%= link_to '', weight, data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete the #{weight.max} weight class?" }, :class=>"fas fa-trash-alt" %>
|
<span class="fas fa-edit" aria-hidden="true"></span>
|
||||||
|
<% end %>
|
||||||
|
<%= link_to weight, data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete the #{weight.max} weight class?" }, class: "text-decoration-none" do %>
|
||||||
|
<span class="fas fa-trash-alt" aria-hidden="true"></span>
|
||||||
|
<% end %>
|
||||||
</td>
|
</td>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -130,7 +138,9 @@
|
|||||||
<td><%= link_to "Mat #{mat.name}", mat %></td>
|
<td><%= link_to "Mat #{mat.name}", mat %></td>
|
||||||
<% if can? :manage, @tournament %>
|
<% if can? :manage, @tournament %>
|
||||||
<td>
|
<td>
|
||||||
<%= link_to '', mat, data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete Mat #{mat.name}?" }, :class=>"fas fa-trash-alt" %>
|
<%= link_to mat, data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete Mat #{mat.name}?" }, class: "text-decoration-none" do %>
|
||||||
|
<span class="fas fa-trash-alt" aria-hidden="true"></span>
|
||||||
|
<% end %>
|
||||||
<%= link_to '', "/mats/#{mat.id}/assign_next_match", data: { turbo_method: :post }, :class=>"fas fa-solid fa-arrow-right" %>
|
<%= link_to '', "/mats/#{mat.id}/assign_next_match", data: { turbo_method: :post }, :class=>"fas fa-solid fa-arrow-right" %>
|
||||||
</td>
|
</td>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
|
<% team_scores_last_updated = @schools.map(&:updated_at).compact.max&.utc&.to_fs(:nsec) %>
|
||||||
<% cache ["#{@tournament.id}_team_scores", @tournament] do %>
|
<% cache ["team_scores", @tournament.id, @schools.size, team_scores_last_updated] do %>
|
||||||
|
|
||||||
<table class="pagebreak table table-striped table-bordered">
|
<table class="pagebreak table table-striped table-bordered">
|
||||||
<h3>Team Scores</h3>
|
<h3>Team Scores</h3>
|
||||||
<thead>
|
<thead>
|
||||||
@@ -11,12 +10,9 @@
|
|||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
<% @schools.each do |school| %>
|
<% @schools.each_with_index do |school, index| %>
|
||||||
<tr>
|
<%= render "tournaments/team_score_row", school: school, rank: index + 1 %>
|
||||||
<td><%= @schools.index(school) + 1 %>. <%= school.name %> (<%= school.abbreviation %>)</td>
|
|
||||||
<td><%= school.page_score_string %></td>
|
|
||||||
</tr>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,67 +1,19 @@
|
|||||||
<% cache ["#{@tournament.id}_up_matches", @tournament] do %>
|
<div data-controller="up-matches-connection">
|
||||||
<script>
|
<% if params[:print] != "true" %>
|
||||||
// $(document).ready(function() {
|
<div style="margin-bottom: 10px;">
|
||||||
// $('#matchList').dataTable();
|
<%= link_to "Show Bout Board in Full Screen", up_matches_path(@tournament, print: true), class: "btn btn-primary" %>
|
||||||
// } );
|
</div>
|
||||||
</script>
|
<% end %>
|
||||||
<script>
|
|
||||||
setTimeout("location.reload(true);",30000);
|
|
||||||
</script>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
<h5 style="color:red">This page reloads every 30s</h5>
|
|
||||||
<br>
|
|
||||||
<h3>Upcoming Matches</h3>
|
|
||||||
<br>
|
|
||||||
<table class="table table-striped table-bordered table-condensed">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Mat </th>
|
|
||||||
<th>On Mat</th>
|
|
||||||
<th>On Deck</th>
|
|
||||||
<th>In The Hole</th>
|
|
||||||
<th>Warm Up</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
<%= turbo_stream_from @tournament, data: { up_matches_connection_target: "stream" } %>
|
||||||
<% @mats.each.map do |m| %>
|
<div
|
||||||
<tr>
|
id="up-matches-cable-status-indicator"
|
||||||
<td><%= m.name %></td>
|
data-up-matches-connection-target="statusIndicator"
|
||||||
<td><% if m.unfinished_matches.first %><strong><%=m.unfinished_matches.first.bout_number%></strong> - <%= m.unfinished_matches.first.weight_max %><br><%= m.unfinished_matches.first.w1_bracket_name %> vs. <%= m.unfinished_matches.first.w2_bracket_name %><% end %></td>
|
class="alert alert-secondary"
|
||||||
<td><% if m.unfinished_matches.second %><strong><%=m.unfinished_matches.second.bout_number%></strong> - <%= m.unfinished_matches.second.weight_max %><br><%= m.unfinished_matches.second.w1_bracket_name %> vs. <%= m.unfinished_matches.second.w2_bracket_name %><% end %></td>
|
style="padding: 5px; margin-bottom: 10px; border-radius: 4px;"
|
||||||
<td><% if m.unfinished_matches.third %><strong><%=m.unfinished_matches.third.bout_number%></strong> - <%= m.unfinished_matches.third.weight_max %><br><%= m.unfinished_matches.third.w1_bracket_name %> vs. <%= m.unfinished_matches.third.w2_bracket_name %><% end %></td>
|
>
|
||||||
<td><% if m.unfinished_matches.fourth %><strong><%=m.unfinished_matches.fourth.bout_number%></strong> - <%= m.unfinished_matches.fourth.weight_max %><br><%= m.unfinished_matches.fourth.w1_bracket_name %> vs. <%= m.unfinished_matches.fourth.w2_bracket_name %><% end %></td>
|
Connecting to server for real-time up matches updates...
|
||||||
</tr>
|
</div>
|
||||||
<% end %>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<h3>Matches not assigned</h3>
|
|
||||||
<br>
|
|
||||||
<table class="table table-striped table-bordered table-condensed" id="matchList">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Round</th>
|
|
||||||
<th>Bout Number</th>
|
|
||||||
<th>Weight Class</th>
|
|
||||||
<th>Matchup</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
<%= render "up_matches_board", tournament: @tournament, mats: @mats, matches: @matches %>
|
||||||
<% if @matches.size > 0 %>
|
</div>
|
||||||
<% @matches.each.map do |m| %>
|
|
||||||
<tr>
|
|
||||||
<td>Round <%= m.round %></td>
|
|
||||||
<td><%= m.bout_number %></td>
|
|
||||||
<td><%= m.weight_max %></td>
|
|
||||||
<td><%= m.w1_bracket_name %> vs. <%= m.w2_bracket_name %></td>
|
|
||||||
</tr>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
<% end %>
|
|
||||||
|
|||||||
@@ -12,9 +12,10 @@
|
|||||||
height: 1in;
|
height: 1in;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<% @tournament.schools.each do |school| %>
|
<% @schools.each do |school| %>
|
||||||
<table class="table table-striped table-bordered table-condensed pagebreak">
|
<table class="table table-striped table-bordered table-condensed pagebreak">
|
||||||
<h5><%= school.name %></h4>
|
<h5><%= school.name %></h4>
|
||||||
|
<p><strong>Weigh In Ref:</strong> <%= @tournament.weigh_in_ref %></p>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
@@ -27,9 +28,9 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td><%= wrestler.name %></td>
|
<td><%= wrestler.name %></td>
|
||||||
<td><%= wrestler.weight.max %></td>
|
<td><%= wrestler.weight.max %></td>
|
||||||
<td></td>
|
<td><%= wrestler.offical_weight %></td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<table class="table table-striped table-bordered">
|
<table class="table table-striped table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
@@ -9,19 +9,19 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<%= form_tag @wrestlers_update_path do %>
|
<%= form_tag "/tournaments/#{@tournament.id}/weigh_in/#{@weight.id}", method: :post do %>
|
||||||
<% @wrestlers.order("original_seed asc").each do |wrestler| %>
|
<% @wrestlers.order("original_seed asc").each do |wrestler| %>
|
||||||
<% if wrestler.weight_id == @weight.id %>
|
<% if wrestler.weight_id == @weight.id %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= wrestler.name %></td>
|
<td><%= wrestler.name %></td>
|
||||||
<td><%= wrestler.school.name %></td>
|
<td><%= wrestler.school.name %></td>
|
||||||
<td><%= wrestler.original_seed %></td>
|
<td><%= wrestler.original_seed %></td>
|
||||||
<td><%= wrestler.weight.max %></td>
|
<td><%= wrestler.weight.max %></td>
|
||||||
<td>
|
<td>
|
||||||
<% if user_signed_in? %>
|
<% if user_signed_in? %>
|
||||||
<%= fields_for "wrestler[]", wrestler do |w| %>
|
<%= fields_for "wrestler[#{wrestler.id}]", wrestler do |w| %>
|
||||||
<%= w.number_field :offical_weight, :step => 'any' %>
|
<%= w.number_field :offical_weight, :step => 'any' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= wrestler.offical_weight %>
|
<%= wrestler.offical_weight %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
10
app/views/weights/_readonly_wrestler_row.html.erb
Normal file
10
app/views/weights/_readonly_wrestler_row.html.erb
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<% cache ["weight_show_wrestler_row", wrestler] do %>
|
||||||
|
<tr>
|
||||||
|
<td><%= link_to wrestler.name, wrestler %></td>
|
||||||
|
<td><%= wrestler.school.name %></td>
|
||||||
|
<td><%= wrestler.original_seed %></td>
|
||||||
|
<td><%= wrestler.season_win %>-<%= wrestler.season_loss %></td>
|
||||||
|
<td><%= wrestler.criteria %> Win <%= wrestler.season_win_percentage %>%</td>
|
||||||
|
<td><%= "Yes" if wrestler.extra? %></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
@@ -1,48 +1,51 @@
|
|||||||
<h3>Weight Class:<%= @weight.max %> <% if can? :manage, @tournament %><%= link_to " Edit", edit_weight_path(@weight), :class=>"fas fa-edit" %><% end %></h3>
|
<h3>Weight Class:<%= @weight.max %> <% if can? :manage, @tournament %><%= link_to edit_weight_path(@weight), class: "text-decoration-none" do %><span class="fas fa-edit" aria-hidden="true"></span><% end %><% end %></h3>
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
<table class="table table-hover table-condensed">
|
<%= form_tag @wrestlers_update_path do %>
|
||||||
<thead>
|
<table class="table table-hover table-condensed">
|
||||||
<tr>
|
<thead>
|
||||||
<th>Name</th>
|
<tr>
|
||||||
<th>School</th>
|
<th>Name</th>
|
||||||
<th>Seed</th>
|
<th>School</th>
|
||||||
<th>Record</th>
|
<th>Seed</th>
|
||||||
<th>Seed Criteria</th>
|
<th>Record</th>
|
||||||
<th>Extra?</th>
|
<th>Seed Criteria</th>
|
||||||
</tr>
|
<th>Extra?</th>
|
||||||
</thead>
|
</tr>
|
||||||
<tbody>
|
</thead>
|
||||||
<%= form_tag @wrestlers_update_path do %>
|
<tbody>
|
||||||
<% @wrestlers.sort_by{|w| [w.original_seed ? 0 : 1, w.original_seed || 0]}.each do |wrestler| %>
|
<% sorted_wrestlers = @wrestlers.sort_by{|w| [w.original_seed ? 0 : 1, w.original_seed || 0]} %>
|
||||||
<% if wrestler.weight_id == @weight.id %>
|
<% if can? :manage, @tournament %>
|
||||||
<tr>
|
<% sorted_wrestlers.each do |wrestler| %>
|
||||||
<td><%= link_to "#{wrestler.name}", wrestler %></td>
|
<% if wrestler.weight_id == @weight.id %>
|
||||||
<td><%= wrestler.school.name %></td>
|
<tr>
|
||||||
<td>
|
<td><%= link_to wrestler.name, wrestler %></td>
|
||||||
<% if can? :manage, @tournament %>
|
<td><%= wrestler.school.name %></td>
|
||||||
<%= fields_for "wrestler[]", wrestler do |w| %>
|
<td>
|
||||||
<%= w.text_field :original_seed %>
|
<%= fields_for "wrestler[]", wrestler do |w| %>
|
||||||
<% end %>
|
<%= w.text_field :original_seed %>
|
||||||
<% else %>
|
|
||||||
<%= wrestler.original_seed %>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
</td>
|
</td>
|
||||||
<td><%= wrestler.season_win %>-<%= wrestler.season_loss %></td>
|
<td><%= wrestler.season_win %>-<%= wrestler.season_loss %></td>
|
||||||
<td><%= wrestler.criteria %> Win <%= wrestler.season_win_percentage %>%</td>
|
<td><%= wrestler.criteria %> Win <%= wrestler.season_win_percentage %>%</td>
|
||||||
<td><% if wrestler.extra? == true %>
|
<td><%= "Yes" if wrestler.extra? %></td>
|
||||||
Yes
|
<td>
|
||||||
<% end %></td>
|
<%= link_to wrestler, data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete #{wrestler.name}? THIS WILL DELETE ALL MATCHES." }, class: "text-decoration-none" do %>
|
||||||
<% if can? :manage, @tournament %>
|
<span class="fas fa-trash-alt" aria-hidden="true"></span>
|
||||||
<td>
|
<% end %>
|
||||||
<%= link_to '', wrestler, data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete #{wrestler.name}? THIS WILL DELETE ALL MATCHES." } , :class=>"fas fa-trash-alt" %>
|
</td>
|
||||||
</td>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tr>
|
<% end %>
|
||||||
<% end %>
|
<% else %>
|
||||||
<% end %>
|
<% sorted_wrestlers.each do |wrestler| %>
|
||||||
</tbody>
|
<% if wrestler.weight_id == @weight.id %>
|
||||||
</table>
|
<%= render "weights/readonly_wrestler_row", wrestler: wrestler %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
<br><p>*All wrestlers without a seed (determined by tournament director) will be assigned a random bracket line.</p>
|
<br><p>*All wrestlers without a seed (determined by tournament director) will be assigned a random bracket line.</p>
|
||||||
<% if can? :manage, @tournament %>
|
<% if can? :manage, @tournament %>
|
||||||
<br>
|
<br>
|
||||||
|
|||||||
6
bin/bundler-audit
Executable file
6
bin/bundler-audit
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
require_relative "../config/boot"
|
||||||
|
require "bundler/audit/cli"
|
||||||
|
|
||||||
|
ARGV.concat %w[ --config config/bundler-audit.yml ] if ARGV.empty? || ARGV.include?("check")
|
||||||
|
Bundler::Audit::CLI.start
|
||||||
6
bin/ci
Executable file
6
bin/ci
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
require_relative "../config/boot"
|
||||||
|
require "active_support/continuous_integration"
|
||||||
|
|
||||||
|
CI = ActiveSupport::ContinuousIntegration
|
||||||
|
require_relative "../config/ci.rb"
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
require "rubygems"
|
require "rubygems"
|
||||||
require "bundler/setup"
|
require "bundler/setup"
|
||||||
|
|
||||||
# explicit rubocop config increases performance slightly while avoiding config confusion.
|
# Explicit RuboCop config increases performance slightly while avoiding config confusion.
|
||||||
ARGV.unshift("--config", File.expand_path("../.rubocop.yml", __dir__))
|
ARGV.unshift("--config", File.expand_path("../.rubocop.yml", __dir__))
|
||||||
|
|
||||||
load Gem.bin_path("rubocop", "rubocop")
|
load Gem.bin_path("rubocop", "rubocop")
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ project_dir="$(dirname $( dirname $(readlink -f ${BASH_SOURCE[0]})))"
|
|||||||
cd ${project_dir}
|
cd ${project_dir}
|
||||||
bundle exec rake db:migrate RAILS_ENV=test
|
bundle exec rake db:migrate RAILS_ENV=test
|
||||||
CI=true brakeman
|
CI=true brakeman
|
||||||
bundle exec bundle-audit check --update
|
bundle audit
|
||||||
bundle exec rake test
|
rails test -v
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ FileUtils.chdir APP_ROOT do
|
|||||||
|
|
||||||
puts "\n== Preparing database =="
|
puts "\n== Preparing database =="
|
||||||
system! "bin/rails db:prepare"
|
system! "bin/rails db:prepare"
|
||||||
|
system! "bin/rails db:reset" if ARGV.include?("--reset")
|
||||||
|
|
||||||
puts "\n== Removing old logs and tempfiles =="
|
puts "\n== Removing old logs and tempfiles =="
|
||||||
system! "bin/rails log:clear tmp:clear"
|
system! "bin/rails log:clear tmp:clear"
|
||||||
|
|||||||
@@ -25,9 +25,6 @@ module Wrestling
|
|||||||
config.active_record.schema_format = :ruby
|
config.active_record.schema_format = :ruby
|
||||||
config.active_record.dump_schemas = :all
|
config.active_record.dump_schemas = :all
|
||||||
|
|
||||||
# Fix deprecation warning for to_time in Rails 8.1
|
|
||||||
config.active_support.to_time_preserves_timezone = :zone
|
|
||||||
|
|
||||||
# Please, add to the `ignore` list any other `lib` subdirectories that do
|
# Please, add to the `ignore` list any other `lib` subdirectories that do
|
||||||
# not contain `.rb` files, or that should not be reloaded or eager loaded.
|
# not contain `.rb` files, or that should not be reloaded or eager loaded.
|
||||||
# Common ones are `templates`, `generators`, or `middleware`, for example.
|
# Common ones are `templates`, `generators`, or `middleware`, for example.
|
||||||
@@ -56,6 +53,6 @@ module Wrestling
|
|||||||
# Valid values are 7.0 or 7.1
|
# Valid values are 7.0 or 7.1
|
||||||
config.active_support.cache_format_version = 7.1
|
config.active_support.cache_format_version = 7.1
|
||||||
|
|
||||||
config.load_defaults 8.0
|
config.load_defaults 8.1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
5
config/bundler-audit.yml
Normal file
5
config/bundler-audit.yml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Audit all gems listed in the Gemfile for known security problems by running bin/bundler-audit.
|
||||||
|
# CVEs that are not relevant to the application can be enumerated on the ignore list below.
|
||||||
|
|
||||||
|
ignore:
|
||||||
|
- CVE-THAT-DOES-NOT-APPLY
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
# Async adapter only works within the same process, so for manually triggering cable updates from a console,
|
|
||||||
# and seeing results in the browser, you must do so from the web console (running inside the dev process),
|
|
||||||
# not a terminal started via bin/rails console! Add "console" to any action or any ERB template view
|
|
||||||
# to make the web console appear.
|
|
||||||
development:
|
development:
|
||||||
adapter: async
|
adapter: solid_cable
|
||||||
|
connects_to:
|
||||||
|
database:
|
||||||
|
writing: cable
|
||||||
|
polling_interval: 0.1.seconds
|
||||||
|
message_retention: 1.day
|
||||||
|
|
||||||
test:
|
test:
|
||||||
adapter: test
|
adapter: test
|
||||||
|
|||||||
24
config/ci.rb
Normal file
24
config/ci.rb
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Run using bin/ci
|
||||||
|
|
||||||
|
CI.run do
|
||||||
|
step "Setup", "bin/setup --skip-server"
|
||||||
|
|
||||||
|
step "Style: Ruby", "bin/rubocop"
|
||||||
|
|
||||||
|
step "Security: Gem audit", "bin/bundler-audit"
|
||||||
|
step "Security: Importmap vulnerability audit", "bin/importmap audit"
|
||||||
|
step "Security: Brakeman code analysis", "bin/brakeman --quiet --no-pager --exit-on-warn --exit-on-error"
|
||||||
|
step "Tests: Rails", "bin/rails test"
|
||||||
|
step "Tests: Seeds", "env RAILS_ENV=test bin/rails db:seed:replant"
|
||||||
|
|
||||||
|
# Optional: Run system tests
|
||||||
|
# step "Tests: System", "bin/rails test:system"
|
||||||
|
|
||||||
|
# Optional: set a green GitHub commit status to unblock PR merge.
|
||||||
|
# Requires the `gh` CLI and `gh extension install basecamp/gh-signoff`.
|
||||||
|
# if success?
|
||||||
|
# step "Signoff: All systems go. Ready for merge and deploy.", "gh signoff"
|
||||||
|
# else
|
||||||
|
# failure "Signoff: CI failed. Do not merge or deploy.", "Fix the issues and try again."
|
||||||
|
# end
|
||||||
|
end
|
||||||
@@ -11,9 +11,8 @@ pin "@rails/actioncable", to: "actioncable.esm.js" # For Action Cable
|
|||||||
# and pin it directly, e.g., pin "jquery", to: "jquery.min.js"
|
# and pin it directly, e.g., pin "jquery", to: "jquery.min.js"
|
||||||
pin "jquery", to: "jquery.js"
|
pin "jquery", to: "jquery.js"
|
||||||
|
|
||||||
# Pin Bootstrap and DataTables from vendor/assets/javascripts/
|
# Pin Bootstrap from vendor/assets/javascripts/
|
||||||
pin "bootstrap", to: "bootstrap.min.js"
|
pin "bootstrap", to: "bootstrap.min.js"
|
||||||
pin "datatables.net", to: "jquery.dataTables.min.js" # Assuming this is how you want to import it
|
|
||||||
|
|
||||||
# If Bootstrap requires Popper.js, and you have it in vendor/assets/javascripts/
|
# If Bootstrap requires Popper.js, and you have it in vendor/assets/javascripts/
|
||||||
# pin "@popperjs/core", to: "popper.min.js" # Or the actual filename if different
|
# pin "@popperjs/core", to: "popper.min.js" # Or the actual filename if different
|
||||||
@@ -22,4 +21,4 @@ pin "datatables.net", to: "jquery.dataTables.min.js" # Assuming this is how you
|
|||||||
pin_all_from "app/assets/javascripts/controllers", under: "controllers"
|
pin_all_from "app/assets/javascripts/controllers", under: "controllers"
|
||||||
|
|
||||||
# Pin all JS files from app/assets/javascripts directory
|
# Pin all JS files from app/assets/javascripts directory
|
||||||
pin_all_from "app/assets/javascripts", under: "assets/javascripts"
|
pin_all_from "app/assets/javascripts", under: "assets/javascripts"
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ Wrestling::Application.routes.draw do
|
|||||||
member do
|
member do
|
||||||
get :stat
|
get :stat
|
||||||
get :spectate
|
get :spectate
|
||||||
|
get :edit_assignment
|
||||||
|
patch :update_assignment
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -71,6 +73,7 @@ Wrestling::Application.routes.draw do
|
|||||||
get 'tournaments/:id/bout_sheets' => 'tournaments#bout_sheets'
|
get 'tournaments/:id/bout_sheets' => 'tournaments#bout_sheets'
|
||||||
get 'tournaments/:id/no_matches' => 'tournaments#no_matches'
|
get 'tournaments/:id/no_matches' => 'tournaments#no_matches'
|
||||||
get 'tournaments/:id/matches' => 'tournaments#matches'
|
get 'tournaments/:id/matches' => 'tournaments#matches'
|
||||||
|
get 'tournaments/:id/qrcode' => 'tournaments#qrcode'
|
||||||
get 'tournaments/:id/delegate' => 'tournaments#delegate', :as => :tournament_delegate
|
get 'tournaments/:id/delegate' => 'tournaments#delegate', :as => :tournament_delegate
|
||||||
post 'tournaments/:id/delegate' => 'tournaments#delegate', :as => :set_tournament_delegate
|
post 'tournaments/:id/delegate' => 'tournaments#delegate', :as => :set_tournament_delegate
|
||||||
delete 'tournaments/:id/:delegate/remove_delegate' => 'tournaments#remove_delegate', :as => :delete_delegate_path
|
delete 'tournaments/:id/:delegate/remove_delegate' => 'tournaments#remove_delegate', :as => :delete_delegate_path
|
||||||
|
|||||||
49
db/migrate/20260129120000_add_queues_to_mats.rb
Normal file
49
db/migrate/20260129120000_add_queues_to_mats.rb
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
class AddQueuesToMats < ActiveRecord::Migration[7.0]
|
||||||
|
class Mat < ActiveRecord::Base
|
||||||
|
self.table_name = "mats"
|
||||||
|
has_many :matches, class_name: "AddQueuesToMats::Match", foreign_key: "mat_id"
|
||||||
|
end
|
||||||
|
|
||||||
|
class Match < ActiveRecord::Base
|
||||||
|
self.table_name = "matches"
|
||||||
|
end
|
||||||
|
|
||||||
|
def up
|
||||||
|
add_column :mats, :queue1, :bigint
|
||||||
|
add_column :mats, :queue2, :bigint
|
||||||
|
add_column :mats, :queue3, :bigint
|
||||||
|
add_column :mats, :queue4, :bigint
|
||||||
|
|
||||||
|
add_index :mats, :queue1
|
||||||
|
add_index :mats, :queue2
|
||||||
|
add_index :mats, :queue3
|
||||||
|
add_index :mats, :queue4
|
||||||
|
|
||||||
|
say_with_time "Backfilling mat queues from unfinished matches" do
|
||||||
|
Mat.reset_column_information
|
||||||
|
Match.reset_column_information
|
||||||
|
|
||||||
|
Mat.find_each do |mat|
|
||||||
|
match_ids = mat.matches.where(finished: [nil, 0]).order(:bout_number).limit(4).pluck(:id)
|
||||||
|
mat.update_columns(
|
||||||
|
queue1: match_ids[0],
|
||||||
|
queue2: match_ids[1],
|
||||||
|
queue3: match_ids[2],
|
||||||
|
queue4: match_ids[3]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_index :mats, :queue1
|
||||||
|
remove_index :mats, :queue2
|
||||||
|
remove_index :mats, :queue3
|
||||||
|
remove_index :mats, :queue4
|
||||||
|
|
||||||
|
remove_column :mats, :queue1
|
||||||
|
remove_column :mats, :queue2
|
||||||
|
remove_column :mats, :queue3
|
||||||
|
remove_column :mats, :queue4
|
||||||
|
end
|
||||||
|
end
|
||||||
10
db/schema.rb
10
db/schema.rb
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[8.0].define(version: 2025_04_15_173921) do
|
ActiveRecord::Schema[8.0].define(version: 2026_01_29_120000) do
|
||||||
create_table "mat_assignment_rules", force: :cascade do |t|
|
create_table "mat_assignment_rules", force: :cascade do |t|
|
||||||
t.bigint "tournament_id"
|
t.bigint "tournament_id"
|
||||||
t.bigint "mat_id"
|
t.bigint "mat_id"
|
||||||
@@ -56,6 +56,14 @@ ActiveRecord::Schema[8.0].define(version: 2025_04_15_173921) do
|
|||||||
t.bigint "tournament_id"
|
t.bigint "tournament_id"
|
||||||
t.datetime "created_at", precision: nil
|
t.datetime "created_at", precision: nil
|
||||||
t.datetime "updated_at", precision: nil
|
t.datetime "updated_at", precision: nil
|
||||||
|
t.bigint "queue1"
|
||||||
|
t.bigint "queue2"
|
||||||
|
t.bigint "queue3"
|
||||||
|
t.bigint "queue4"
|
||||||
|
t.index ["queue1"], name: "index_mats_on_queue1"
|
||||||
|
t.index ["queue2"], name: "index_mats_on_queue2"
|
||||||
|
t.index ["queue3"], name: "index_mats_on_queue3"
|
||||||
|
t.index ["queue4"], name: "index_mats_on_queue4"
|
||||||
t.index ["tournament_id"], name: "index_mats_on_tournament_id"
|
t.index ["tournament_id"], name: "index_mats_on_tournament_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM ruby:3.2.0
|
FROM ruby:4.0.1
|
||||||
|
|
||||||
# Accept build arguments for user/group IDs
|
# Accept build arguments for user/group IDs
|
||||||
ARG USER_ID=1000
|
ARG USER_ID=1000
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM ruby:3.2.0-slim
|
FROM ruby:4.0.1-slim
|
||||||
|
|
||||||
#HEALTHCHECK --start-period=60s CMD curl http://127.0.0.1/
|
#HEALTHCHECK --start-period=60s CMD curl http://127.0.0.1/
|
||||||
|
|
||||||
@@ -15,6 +15,8 @@ RUN apt-get -qq update --fix-missing \
|
|||||||
libsqlite3-dev \
|
libsqlite3-dev \
|
||||||
wget \
|
wget \
|
||||||
default-libmysqlclient-dev \
|
default-libmysqlclient-dev \
|
||||||
|
libyaml-dev \
|
||||||
|
pkg-config \
|
||||||
nodejs \
|
nodejs \
|
||||||
tzdata \
|
tzdata \
|
||||||
git \
|
git \
|
||||||
|
|||||||
@@ -35,53 +35,69 @@ namespace :tournament do
|
|||||||
end
|
end
|
||||||
|
|
||||||
sleep(10)
|
sleep(10)
|
||||||
@tournament.reload # Ensure matches association is fresh before iterating
|
loop do
|
||||||
@tournament.matches.reload.sort_by(&:bout_number).each do |match|
|
@tournament.reload
|
||||||
if match.reload.loser1_name != "BYE" and match.reload.loser2_name != "BYE" and match.reload.finished != 1
|
@tournament.refill_open_bout_board_queues
|
||||||
# Wait until both wrestlers are assigned
|
|
||||||
while (match.w1.nil? || match.w2.nil?)
|
|
||||||
puts "Waiting for wrestlers in match #{match.bout_number}..."
|
|
||||||
sleep(5) # Wait for 5 seconds before checking again
|
|
||||||
match.reload
|
|
||||||
end
|
|
||||||
puts "Finishing match with bout number #{match.bout_number}..."
|
|
||||||
|
|
||||||
# Choose a random winner
|
mats_with_queue1 = @tournament.mats.select do |mat|
|
||||||
wrestlers = [match.w1, match.w2]
|
match = mat.queue1_match
|
||||||
match.winner_id = wrestlers.sample
|
match && match.finished != 1 && match.loser1_name != "BYE" && match.loser2_name != "BYE"
|
||||||
|
|
||||||
# Choose a random win type
|
|
||||||
win_type = WIN_TYPES.sample
|
|
||||||
match.win_type = win_type
|
|
||||||
|
|
||||||
# Assign score based on win type
|
|
||||||
match.score = case win_type
|
|
||||||
when "Decision"
|
|
||||||
low_score = rand(0..10)
|
|
||||||
high_score = low_score + rand(1..7)
|
|
||||||
"#{high_score}-#{low_score}"
|
|
||||||
when "Major"
|
|
||||||
low_score = rand(0..10)
|
|
||||||
high_score = low_score + rand(8..14)
|
|
||||||
"#{high_score}-#{low_score}"
|
|
||||||
when "Tech Fall"
|
|
||||||
low_score = rand(0..10)
|
|
||||||
high_score = low_score + rand(15..19)
|
|
||||||
"#{high_score}-#{low_score}"
|
|
||||||
when "Pin"
|
|
||||||
pin_times = ["0:30","1:12","5:37","2:34","3:54","4:23","5:56","0:12","1:00"]
|
|
||||||
pin_times.sample
|
|
||||||
else
|
|
||||||
"" # Default score
|
|
||||||
end
|
|
||||||
|
|
||||||
# Mark match as finished
|
|
||||||
match.finished = 1
|
|
||||||
match.save!
|
|
||||||
# sleep to prevent mysql locks when assign_next_match to a mat runs
|
|
||||||
sleep(0.5)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
break if mats_with_queue1.empty?
|
||||||
|
|
||||||
|
mat = mats_with_queue1.sample
|
||||||
|
match = mat.queue1_match
|
||||||
|
|
||||||
|
# Wait until both wrestlers are assigned for the selected queue1 match.
|
||||||
|
while match && (match.w1.nil? || match.w2.nil?)
|
||||||
|
puts "Waiting for wrestlers in match #{match.bout_number} on mat #{mat.name}..."
|
||||||
|
sleep(5)
|
||||||
|
@tournament.reload
|
||||||
|
@tournament.refill_open_bout_board_queues
|
||||||
|
match = mat.reload.queue1_match
|
||||||
|
end
|
||||||
|
|
||||||
|
next unless match
|
||||||
|
next if match.finished == 1 || match.loser1_name == "BYE" || match.loser2_name == "BYE"
|
||||||
|
|
||||||
|
puts "Finishing queue1 match on mat #{mat.name} with bout number #{match.bout_number}..."
|
||||||
|
|
||||||
|
# Choose a random winner
|
||||||
|
wrestlers = [match.w1, match.w2]
|
||||||
|
match.winner_id = wrestlers.sample
|
||||||
|
|
||||||
|
# Choose a random win type
|
||||||
|
win_type = WIN_TYPES.sample
|
||||||
|
match.win_type = win_type
|
||||||
|
|
||||||
|
# Assign score based on win type
|
||||||
|
match.score = case win_type
|
||||||
|
when "Decision"
|
||||||
|
low_score = rand(0..10)
|
||||||
|
high_score = low_score + rand(1..7)
|
||||||
|
"#{high_score}-#{low_score}"
|
||||||
|
when "Major"
|
||||||
|
low_score = rand(0..10)
|
||||||
|
high_score = low_score + rand(8..14)
|
||||||
|
"#{high_score}-#{low_score}"
|
||||||
|
when "Tech Fall"
|
||||||
|
low_score = rand(0..10)
|
||||||
|
high_score = low_score + rand(15..19)
|
||||||
|
"#{high_score}-#{low_score}"
|
||||||
|
when "Pin"
|
||||||
|
pin_times = ["0:30","1:12","5:37","2:34","3:54","4:23","5:56","0:12","1:00"]
|
||||||
|
pin_times.sample
|
||||||
|
else
|
||||||
|
""
|
||||||
|
end
|
||||||
|
|
||||||
|
# Mark match as finished
|
||||||
|
match.finished = 1
|
||||||
|
match.save!
|
||||||
|
# sleep to prevent mysql locks when queue advancement runs
|
||||||
|
sleep(0.5)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -35,12 +35,35 @@
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
letter-spacing: -0.0025em;
|
letter-spacing: -0.0025em;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
min-height: 100vh;
|
min-height: 100dvh;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
-webkit-text-size-adjust: 100%;
|
-webkit-text-size-adjust: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#error-description {
|
||||||
|
fill: #d30001;
|
||||||
|
}
|
||||||
|
|
||||||
|
#error-id {
|
||||||
|
fill: #f0eff0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
body {
|
||||||
|
background: #101010;
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#error-description {
|
||||||
|
fill: #FF6161;
|
||||||
|
}
|
||||||
|
|
||||||
|
#error-id {
|
||||||
|
fill: #2c2c2c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
@@ -83,13 +106,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
main article br {
|
main article br {
|
||||||
|
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
@media(min-width: 48em) {
|
@media(min-width: 48em) {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@@ -102,10 +123,10 @@
|
|||||||
|
|
||||||
<main>
|
<main>
|
||||||
<header>
|
<header>
|
||||||
<svg height="172" viewBox="0 0 480 172" width="480" xmlns="http://www.w3.org/2000/svg"><path d="m124.48 3.00509-45.6889 100.02991h26.2239v-28.1168h38.119v28.1168h21.628v35.145h-21.628v30.82h-37.308v-30.82h-72.1833v-31.901l50.2851-103.27391zm115.583 168.69891c-40.822 0-64.884-35.146-64.884-85.7015 0-50.5554 24.062-85.700907 64.884-85.700907 40.823 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.061 85.7015-64.884 85.7015zm0-133.2831c-17.572 0-22.709 21.8984-22.709 47.5816 0 25.6835 5.137 47.5815 22.709 47.5815 17.303 0 22.71-21.898 22.71-47.5815 0-25.6832-5.407-47.5816-22.71-47.5816zm140.456 133.2831c-40.823 0-64.884-35.146-64.884-85.7015 0-50.5554 24.061-85.700907 64.884-85.700907 40.822 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.062 85.7015-64.884 85.7015zm0-133.2831c-17.573 0-22.71 21.8984-22.71 47.5816 0 25.6835 5.137 47.5815 22.71 47.5815 17.302 0 22.709-21.898 22.709-47.5815 0-25.6832-5.407-47.5816-22.709-47.5816z" fill="#f0eff0"/><path d="m123.606 85.4445c3.212 1.0523 5.538 4.2089 5.538 8.0301 0 6.1472-4.209 9.5254-11.298 9.5254h-15.617v-34.0033h14.565c7.089 0 11.353 3.1566 11.353 9.2484 0 3.6551-2.049 6.3134-4.541 7.1994zm-12.904-2.9905h5.095c2.603 0 3.988-.9968 3.988-3.1013 0-2.1044-1.385-3.0459-3.988-3.0459h-5.095zm0 6.6456v6.5902h5.981c2.492 0 3.877-1.3291 3.877-3.2674 0-2.049-1.385-3.3228-3.877-3.3228zm43.786 13.9004h-8.362v-1.274c-.831.831-3.323 1.717-5.981 1.717-4.929 0-9.083-2.769-9.083-8.0301 0-4.818 4.154-7.9193 9.581-7.9193 2.049 0 4.486.6646 5.483 1.3845v-1.606c0-1.606-.942-2.9905-3.046-2.9905-1.606 0-2.548.7199-2.935 1.8275h-8.197c.72-4.8181 4.985-8.6393 11.409-8.6393 7.088 0 11.131 3.7659 11.131 10.2453zm-8.362-6.9779v-1.4399c-.554-1.0522-2.049-1.7167-3.655-1.7167-1.717 0-3.434.7199-3.434 2.3813 0 1.7168 1.717 2.4367 3.434 2.4367 1.606 0 3.101-.6645 3.655-1.6614zm27.996 6.9779v-1.994c-1.163 1.329-3.599 2.548-6.147 2.548-7.199 0-11.131-5.8151-11.131-13.0145s3.932-13.0143 11.131-13.0143c2.548 0 4.984 1.2184 6.147 2.5475v-13.0697h8.695v35.997zm0-9.1931v-6.5902c-.664-1.3291-2.159-2.326-3.821-2.326-2.99 0-4.763 2.4368-4.763 5.6488s1.773 5.5934 4.763 5.5934c1.717 0 3.157-.9415 3.821-2.326zm35.471-2.049h-3.101v11.2421h-8.806v-34.0033h15.285c7.31 0 12.35 4.1535 12.35 11.5744 0 5.1503-2.603 8.6947-6.757 10.2453l7.975 12.1836h-9.858zm-3.101-15.2849v8.1962h5.538c3.156 0 4.596-1.606 4.596-4.0981s-1.44-4.0981-4.596-4.0981zm36.957 17.8323h8.03c-.886 5.7597-5.206 9.2487-11.685 9.2487-7.643 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.316-13.0143 12.515-13.0143 7.643 0 11.962 5.095 11.962 12.5159v2.1598h-16.115c.277 2.9905 1.827 4.5965 4.32 4.5965 1.772 0 3.156-.7753 3.655-2.4921zm-3.822-10.0237c-2.049 0-3.433 1.2737-3.987 3.5997h7.532c-.111-2.0491-1.385-3.5997-3.545-3.5997zm30.98 27.5234v-10.799c-1.163 1.329-3.6 2.548-6.147 2.548-7.2 0-11.132-5.9259-11.132-13.0145 0-7.144 3.932-13.0143 11.132-13.0143 2.547 0 4.984 1.2184 6.147 2.5475v-1.9937h8.695v33.726zm0-17.9981v-6.5902c-.665-1.3291-2.105-2.326-3.821-2.326-2.991 0-4.763 2.4368-4.763 5.6488s1.772 5.5934 4.763 5.5934c1.661 0 3.156-.9415 3.821-2.326zm36.789-15.7279v24.921h-8.695v-2.16c-1.329 1.551-3.821 2.714-6.646 2.714-5.482 0-8.75-3.5999-8.75-9.1379v-16.3371h8.64v14.288c0 2.1045.996 3.5997 3.212 3.5997 1.606 0 3.101-1.0522 3.544-2.769v-15.1187zm19.084 16.2263h8.03c-.886 5.7597-5.206 9.2487-11.685 9.2487-7.643 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.316-13.0143 12.515-13.0143 7.643 0 11.963 5.095 11.963 12.5159v2.1598h-16.116c.277 2.9905 1.828 4.5965 4.32 4.5965 1.772 0 3.156-.7753 3.655-2.4921zm-3.822-10.0237c-2.049 0-3.433 1.2737-3.987 3.5997h7.532c-.111-2.0491-1.385-3.5997-3.545-3.5997zm13.428 11.0206h8.474c.387 1.3845 1.606 2.1598 3.156 2.1598 1.44 0 2.548-.5538 2.548-1.7168 0-.9414-.72-1.2737-1.939-1.5506l-4.873-.9969c-4.154-.886-6.867-2.8797-6.867-7.2547 0-5.3165 4.762-8.4178 10.633-8.4178 6.812 0 10.522 3.1567 11.297 8.0855h-8.03c-.277-1.0522-1.052-1.9937-3.046-1.9937-1.273 0-2.326.5538-2.326 1.6614 0 .7753.554 1.163 1.717 1.3845l4.929 1.163c4.541 1.0522 6.978 3.4335 6.978 7.4763 0 5.3168-4.818 8.2518-10.91 8.2518-6.369 0-10.965-2.88-11.741-8.2518zm27.538-.8861v-9.5807h-3.655v-6.7564h3.655v-6.8671h8.584v6.8671h5.205v6.7564h-5.205v8.307c0 1.9383.941 2.769 2.658 2.769.941 0 1.993-.2216 2.769-.5538v7.3654c-.997.443-2.88.775-4.818.775-5.871 0-9.193-2.769-9.193-9.0819z" fill="#d30001"/></svg>
|
<svg height="172" viewBox="0 0 480 172" width="480" xmlns="http://www.w3.org/2000/svg"><path d="m124.48 3.00509-45.6889 100.02991h26.2239v-28.1168h38.119v28.1168h21.628v35.145h-21.628v30.82h-37.308v-30.82h-72.1833v-31.901l50.2851-103.27391zm115.583 168.69891c-40.822 0-64.884-35.146-64.884-85.7015 0-50.5554 24.062-85.700907 64.884-85.700907 40.823 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.061 85.7015-64.884 85.7015zm0-133.2831c-17.572 0-22.709 21.8984-22.709 47.5816 0 25.6835 5.137 47.5815 22.709 47.5815 17.303 0 22.71-21.898 22.71-47.5815 0-25.6832-5.407-47.5816-22.71-47.5816zm140.456 133.2831c-40.823 0-64.884-35.146-64.884-85.7015 0-50.5554 24.061-85.700907 64.884-85.700907 40.822 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.062 85.7015-64.884 85.7015zm0-133.2831c-17.573 0-22.71 21.8984-22.71 47.5816 0 25.6835 5.137 47.5815 22.71 47.5815 17.302 0 22.709-21.898 22.709-47.5815 0-25.6832-5.407-47.5816-22.709-47.5816z" id="error-id"/><path d="m123.606 85.4445c3.212 1.0523 5.538 4.2089 5.538 8.0301 0 6.1472-4.209 9.5254-11.298 9.5254h-15.617v-34.0033h14.565c7.089 0 11.353 3.1566 11.353 9.2484 0 3.6551-2.049 6.3134-4.541 7.1994zm-12.904-2.9905h5.095c2.603 0 3.988-.9968 3.988-3.1013 0-2.1044-1.385-3.0459-3.988-3.0459h-5.095zm0 6.6456v6.5902h5.981c2.492 0 3.877-1.3291 3.877-3.2674 0-2.049-1.385-3.3228-3.877-3.3228zm43.786 13.9004h-8.362v-1.274c-.831.831-3.323 1.717-5.981 1.717-4.929 0-9.083-2.769-9.083-8.0301 0-4.818 4.154-7.9193 9.581-7.9193 2.049 0 4.486.6646 5.483 1.3845v-1.606c0-1.606-.942-2.9905-3.046-2.9905-1.606 0-2.548.7199-2.935 1.8275h-8.197c.72-4.8181 4.985-8.6393 11.409-8.6393 7.088 0 11.131 3.7659 11.131 10.2453zm-8.362-6.9779v-1.4399c-.554-1.0522-2.049-1.7167-3.655-1.7167-1.717 0-3.434.7199-3.434 2.3813 0 1.7168 1.717 2.4367 3.434 2.4367 1.606 0 3.101-.6645 3.655-1.6614zm27.996 6.9779v-1.994c-1.163 1.329-3.599 2.548-6.147 2.548-7.199 0-11.131-5.8151-11.131-13.0145s3.932-13.0143 11.131-13.0143c2.548 0 4.984 1.2184 6.147 2.5475v-13.0697h8.695v35.997zm0-9.1931v-6.5902c-.664-1.3291-2.159-2.326-3.821-2.326-2.99 0-4.763 2.4368-4.763 5.6488s1.773 5.5934 4.763 5.5934c1.717 0 3.157-.9415 3.821-2.326zm35.471-2.049h-3.101v11.2421h-8.806v-34.0033h15.285c7.31 0 12.35 4.1535 12.35 11.5744 0 5.1503-2.603 8.6947-6.757 10.2453l7.975 12.1836h-9.858zm-3.101-15.2849v8.1962h5.538c3.156 0 4.596-1.606 4.596-4.0981s-1.44-4.0981-4.596-4.0981zm36.957 17.8323h8.03c-.886 5.7597-5.206 9.2487-11.685 9.2487-7.643 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.316-13.0143 12.515-13.0143 7.643 0 11.962 5.095 11.962 12.5159v2.1598h-16.115c.277 2.9905 1.827 4.5965 4.32 4.5965 1.772 0 3.156-.7753 3.655-2.4921zm-3.822-10.0237c-2.049 0-3.433 1.2737-3.987 3.5997h7.532c-.111-2.0491-1.385-3.5997-3.545-3.5997zm30.98 27.5234v-10.799c-1.163 1.329-3.6 2.548-6.147 2.548-7.2 0-11.132-5.9259-11.132-13.0145 0-7.144 3.932-13.0143 11.132-13.0143 2.547 0 4.984 1.2184 6.147 2.5475v-1.9937h8.695v33.726zm0-17.9981v-6.5902c-.665-1.3291-2.105-2.326-3.821-2.326-2.991 0-4.763 2.4368-4.763 5.6488s1.772 5.5934 4.763 5.5934c1.661 0 3.156-.9415 3.821-2.326zm36.789-15.7279v24.921h-8.695v-2.16c-1.329 1.551-3.821 2.714-6.646 2.714-5.482 0-8.75-3.5999-8.75-9.1379v-16.3371h8.64v14.288c0 2.1045.996 3.5997 3.212 3.5997 1.606 0 3.101-1.0522 3.544-2.769v-15.1187zm19.084 16.2263h8.03c-.886 5.7597-5.206 9.2487-11.685 9.2487-7.643 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.316-13.0143 12.515-13.0143 7.643 0 11.963 5.095 11.963 12.5159v2.1598h-16.116c.277 2.9905 1.828 4.5965 4.32 4.5965 1.772 0 3.156-.7753 3.655-2.4921zm-3.822-10.0237c-2.049 0-3.433 1.2737-3.987 3.5997h7.532c-.111-2.0491-1.385-3.5997-3.545-3.5997zm13.428 11.0206h8.474c.387 1.3845 1.606 2.1598 3.156 2.1598 1.44 0 2.548-.5538 2.548-1.7168 0-.9414-.72-1.2737-1.939-1.5506l-4.873-.9969c-4.154-.886-6.867-2.8797-6.867-7.2547 0-5.3165 4.762-8.4178 10.633-8.4178 6.812 0 10.522 3.1567 11.297 8.0855h-8.03c-.277-1.0522-1.052-1.9937-3.046-1.9937-1.273 0-2.326.5538-2.326 1.6614 0 .7753.554 1.163 1.717 1.3845l4.929 1.163c4.541 1.0522 6.978 3.4335 6.978 7.4763 0 5.3168-4.818 8.2518-10.91 8.2518-6.369 0-10.965-2.88-11.741-8.2518zm27.538-.8861v-9.5807h-3.655v-6.7564h3.655v-6.8671h8.584v6.8671h5.205v6.7564h-5.205v8.307c0 1.9383.941 2.769 2.658 2.769.941 0 1.993-.2216 2.769-.5538v7.3654c-.997.443-2.88.775-4.818.775-5.871 0-9.193-2.769-9.193-9.0819z" id="error-description"/></svg>
|
||||||
</header>
|
</header>
|
||||||
<article>
|
<article>
|
||||||
<p><strong>The server cannot process the request due to a client error.</strong> Please check the request and try again. If you’re the application owner check the logs for more information.</p>
|
<p><strong>The server cannot process the request due to a client error.</strong> Please check the request and try again. If you're the application owner check the logs for more information.</p>
|
||||||
</article>
|
</article>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
|
|
||||||
<title>The page you were looking for doesn’t exist (404 Not found)</title>
|
<title>The page you were looking for doesn't exist (404 Not found)</title>
|
||||||
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="initial-scale=1, width=device-width">
|
<meta name="viewport" content="initial-scale=1, width=device-width">
|
||||||
@@ -35,12 +35,35 @@
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
letter-spacing: -0.0025em;
|
letter-spacing: -0.0025em;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
min-height: 100vh;
|
min-height: 100dvh;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
-webkit-text-size-adjust: 100%;
|
-webkit-text-size-adjust: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#error-description {
|
||||||
|
fill: #d30001;
|
||||||
|
}
|
||||||
|
|
||||||
|
#error-id {
|
||||||
|
fill: #f0eff0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
body {
|
||||||
|
background: #101010;
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#error-description {
|
||||||
|
fill: #FF6161;
|
||||||
|
}
|
||||||
|
|
||||||
|
#error-id {
|
||||||
|
fill: #2c2c2c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
@@ -83,13 +106,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
main article br {
|
main article br {
|
||||||
|
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
@media(min-width: 48em) {
|
@media(min-width: 48em) {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@@ -102,10 +123,10 @@
|
|||||||
|
|
||||||
<main>
|
<main>
|
||||||
<header>
|
<header>
|
||||||
<svg height="172" viewBox="0 0 480 172" width="480" xmlns="http://www.w3.org/2000/svg"><path d="m124.48 3.00509-45.6889 100.02991h26.2239v-28.1168h38.119v28.1168h21.628v35.145h-21.628v30.82h-37.308v-30.82h-72.1833v-31.901l50.2851-103.27391zm115.583 168.69891c-40.822 0-64.884-35.146-64.884-85.7015 0-50.5554 24.062-85.700907 64.884-85.700907 40.823 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.061 85.7015-64.884 85.7015zm0-133.2831c-17.572 0-22.709 21.8984-22.709 47.5816 0 25.6835 5.137 47.5815 22.709 47.5815 17.303 0 22.71-21.898 22.71-47.5815 0-25.6832-5.407-47.5816-22.71-47.5816zm165.328-35.41581-45.689 100.02991h26.224v-28.1168h38.119v28.1168h21.628v35.145h-21.628v30.82h-37.308v-30.82h-72.184v-31.901l50.285-103.27391z" fill="#f0eff0"/><path d="m157.758 68.9967v34.0033h-7.199l-14.233-19.8814v19.8814h-8.584v-34.0033h8.307l13.125 18.7184v-18.7184zm28.454 21.5428c0 7.6978-5.15 13.0145-12.737 13.0145-7.532 0-12.738-5.3167-12.738-13.0145s5.206-13.0143 12.738-13.0143c7.587 0 12.737 5.3165 12.737 13.0143zm-8.528 0c0-3.4336-1.496-5.8703-4.209-5.8703-2.659 0-4.154 2.4367-4.154 5.8703s1.495 5.8149 4.154 5.8149c2.713 0 4.209-2.3813 4.209-5.8149zm13.184 3.8766v-9.5807h-3.655v-6.7564h3.655v-6.8671h8.584v6.8671h5.205v6.7564h-5.205v8.307c0 1.9383.941 2.769 2.658 2.769.941 0 1.994-.2216 2.769-.5538v7.3654c-.997.443-2.88.775-4.818.775-5.87 0-9.193-2.769-9.193-9.0819zm37.027 8.5839h-8.806v-34.0033h23.924v7.6978h-15.118v6.7564h13.9v7.5316h-13.9zm41.876-12.4605c0 7.6978-5.15 13.0145-12.737 13.0145-7.532 0-12.738-5.3167-12.738-13.0145s5.206-13.0143 12.738-13.0143c7.587 0 12.737 5.3165 12.737 13.0143zm-8.529 0c0-3.4336-1.495-5.8703-4.208-5.8703-2.659 0-4.154 2.4367-4.154 5.8703s1.495 5.8149 4.154 5.8149c2.713 0 4.208-2.3813 4.208-5.8149zm35.337-12.4605v24.921h-8.695v-2.16c-1.329 1.551-3.821 2.714-6.646 2.714-5.482 0-8.75-3.5999-8.75-9.1379v-16.3371h8.64v14.288c0 2.1045.997 3.5997 3.212 3.5997 1.606 0 3.101-1.0522 3.544-2.769v-15.1187zm4.076 24.921v-24.921h8.694v2.1598c1.385-1.5506 3.822-2.7136 6.701-2.7136 5.538 0 8.806 3.5997 8.806 9.1377v16.3371h-8.639v-14.2327c0-2.049-1.053-3.5443-3.268-3.5443-1.717 0-3.156.9969-3.6 2.7136v15.0634zm44.113 0v-1.994c-1.163 1.329-3.6 2.548-6.147 2.548-7.2 0-11.132-5.8151-11.132-13.0145s3.932-13.0143 11.132-13.0143c2.547 0 4.984 1.2184 6.147 2.5475v-13.0697h8.695v35.997zm0-9.1931v-6.5902c-.665-1.3291-2.16-2.326-3.821-2.326-2.991 0-4.763 2.4368-4.763 5.6488s1.772 5.5934 4.763 5.5934c1.717 0 3.156-.9415 3.821-2.326z" fill="#d30001"/></svg>
|
<svg height="172" viewBox="0 0 480 172" width="480" xmlns="http://www.w3.org/2000/svg"><path d="m124.48 3.00509-45.6889 100.02991h26.2239v-28.1168h38.119v28.1168h21.628v35.145h-21.628v30.82h-37.308v-30.82h-72.1833v-31.901l50.2851-103.27391zm115.583 168.69891c-40.822 0-64.884-35.146-64.884-85.7015 0-50.5554 24.062-85.700907 64.884-85.700907 40.823 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.061 85.7015-64.884 85.7015zm0-133.2831c-17.572 0-22.709 21.8984-22.709 47.5816 0 25.6835 5.137 47.5815 22.709 47.5815 17.303 0 22.71-21.898 22.71-47.5815 0-25.6832-5.407-47.5816-22.71-47.5816zm165.328-35.41581-45.689 100.02991h26.224v-28.1168h38.119v28.1168h21.628v35.145h-21.628v30.82h-37.308v-30.82h-72.184v-31.901l50.285-103.27391z" id="error-id"/><path d="m157.758 68.9967v34.0033h-7.199l-14.233-19.8814v19.8814h-8.584v-34.0033h8.307l13.125 18.7184v-18.7184zm28.454 21.5428c0 7.6978-5.15 13.0145-12.737 13.0145-7.532 0-12.738-5.3167-12.738-13.0145s5.206-13.0143 12.738-13.0143c7.587 0 12.737 5.3165 12.737 13.0143zm-8.528 0c0-3.4336-1.496-5.8703-4.209-5.8703-2.659 0-4.154 2.4367-4.154 5.8703s1.495 5.8149 4.154 5.8149c2.713 0 4.209-2.3813 4.209-5.8149zm13.184 3.8766v-9.5807h-3.655v-6.7564h3.655v-6.8671h8.584v6.8671h5.205v6.7564h-5.205v8.307c0 1.9383.941 2.769 2.658 2.769.941 0 1.994-.2216 2.769-.5538v7.3654c-.997.443-2.88.775-4.818.775-5.87 0-9.193-2.769-9.193-9.0819zm37.027 8.5839h-8.806v-34.0033h23.924v7.6978h-15.118v6.7564h13.9v7.5316h-13.9zm41.876-12.4605c0 7.6978-5.15 13.0145-12.737 13.0145-7.532 0-12.738-5.3167-12.738-13.0145s5.206-13.0143 12.738-13.0143c7.587 0 12.737 5.3165 12.737 13.0143zm-8.529 0c0-3.4336-1.495-5.8703-4.208-5.8703-2.659 0-4.154 2.4367-4.154 5.8703s1.495 5.8149 4.154 5.8149c2.713 0 4.208-2.3813 4.208-5.8149zm35.337-12.4605v24.921h-8.695v-2.16c-1.329 1.551-3.821 2.714-6.646 2.714-5.482 0-8.75-3.5999-8.75-9.1379v-16.3371h8.64v14.288c0 2.1045.997 3.5997 3.212 3.5997 1.606 0 3.101-1.0522 3.544-2.769v-15.1187zm4.076 24.921v-24.921h8.694v2.1598c1.385-1.5506 3.822-2.7136 6.701-2.7136 5.538 0 8.806 3.5997 8.806 9.1377v16.3371h-8.639v-14.2327c0-2.049-1.053-3.5443-3.268-3.5443-1.717 0-3.156.9969-3.6 2.7136v15.0634zm44.113 0v-1.994c-1.163 1.329-3.6 2.548-6.147 2.548-7.2 0-11.132-5.8151-11.132-13.0145s3.932-13.0143 11.132-13.0143c2.547 0 4.984 1.2184 6.147 2.5475v-13.0697h8.695v35.997zm0-9.1931v-6.5902c-.665-1.3291-2.16-2.326-3.821-2.326-2.991 0-4.763 2.4368-4.763 5.6488s1.772 5.5934 4.763 5.5934c1.717 0 3.156-.9415 3.821-2.326z" id="error-description"/></svg>
|
||||||
</header>
|
</header>
|
||||||
<article>
|
<article>
|
||||||
<p><strong>The page you were looking for doesn’t exist.</strong> You may have mistyped the address or the page may have moved. If you’re the application owner check the logs for more information.</p>
|
<p><strong>The page you were looking for doesn't exist.</strong> You may have mistyped the address or the page may have moved. If you're the application owner check the logs for more information.</p>
|
||||||
</article>
|
</article>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|||||||
@@ -35,12 +35,35 @@
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
letter-spacing: -0.0025em;
|
letter-spacing: -0.0025em;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
min-height: 100vh;
|
min-height: 100dvh;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
-webkit-text-size-adjust: 100%;
|
-webkit-text-size-adjust: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#error-description {
|
||||||
|
fill: #d30001;
|
||||||
|
}
|
||||||
|
|
||||||
|
#error-id {
|
||||||
|
fill: #f0eff0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
body {
|
||||||
|
background: #101010;
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#error-description {
|
||||||
|
fill: #FF6161;
|
||||||
|
}
|
||||||
|
|
||||||
|
#error-id {
|
||||||
|
fill: #2c2c2c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
@@ -83,13 +106,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
main article br {
|
main article br {
|
||||||
|
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
@media(min-width: 48em) {
|
@media(min-width: 48em) {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@@ -102,7 +123,7 @@
|
|||||||
|
|
||||||
<main>
|
<main>
|
||||||
<header>
|
<header>
|
||||||
<svg height="172" viewBox="0 0 480 172" width="480" xmlns="http://www.w3.org/2000/svg"><path d="m124.48 3.00509-45.6889 100.02991h26.2239v-28.1168h38.119v28.1168h21.628v35.145h-21.628v30.82h-37.308v-30.82h-72.1833v-31.901l50.2851-103.27391zm115.583 168.69891c-40.822 0-64.884-35.146-64.884-85.7015 0-50.5554 24.062-85.700907 64.884-85.700907 40.823 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.061 85.7015-64.884 85.7015zm0-133.2831c-17.572 0-22.709 21.8984-22.709 47.5816 0 25.6835 5.137 47.5815 22.709 47.5815 17.303 0 22.71-21.898 22.71-47.5815 0-25.6832-5.407-47.5816-22.71-47.5816zm202.906 9.7326h-41.093c-2.433-7.2994-7.84-12.4361-17.302-12.4361-16.221 0-25.413 17.5728-25.954 34.8752v1.3517c5.137-7.0291 16.221-12.4361 30.82-12.4361 33.524 0 54.881 24.0612 54.881 53.7998 0 33.253-23.791 58.396-61.64 58.396-21.628 0-39.741-10.003-50.825-27.576-9.733-14.599-13.788-32.442-13.788-54.3406 0-51.9072 24.331-89.485807 66.236-89.485807 32.712 0 53.258 18.654107 58.665 47.851907zm-82.727 66.2355c0 13.247 9.463 22.439 22.71 22.439 12.977 0 22.439-9.192 22.439-22.439 0-13.517-9.462-22.7091-22.439-22.7091-13.247 0-22.71 9.1921-22.71 22.7091z" fill="#f0eff0"/><path d="m100.761 68.9967v34.0033h-7.1991l-14.2326-19.8814v19.8814h-8.5839v-34.0033h8.307l13.125 18.7184v-18.7184zm28.454 21.5428c0 7.6978-5.15 13.0145-12.737 13.0145-7.532 0-12.738-5.3167-12.738-13.0145s5.206-13.0143 12.738-13.0143c7.587 0 12.737 5.3165 12.737 13.0143zm-8.529 0c0-3.4336-1.495-5.8703-4.208-5.8703-2.659 0-4.154 2.4367-4.154 5.8703s1.495 5.8149 4.154 5.8149c2.713 0 4.208-2.3813 4.208-5.8149zm13.185 3.8766v-9.5807h-3.655v-6.7564h3.655v-6.8671h8.584v6.8671h5.205v6.7564h-5.205v8.307c0 1.9383.941 2.769 2.658 2.769.941 0 1.994-.2216 2.769-.5538v7.3654c-.997.443-2.88.775-4.818.775-5.87 0-9.193-2.769-9.193-9.0819zm39.02-25.4194h9.083l12.958 34.0033h-9.027l-2.436-6.5902h-12.35l-2.381 6.5902h-8.806zm4.431 10.5222-3.489 9.5807h6.978zm17.44 11.0206c0-7.6978 5.095-13.0143 12.572-13.0143 6.701 0 10.854 3.9874 11.574 9.8023h-8.418c-.221-1.4953-1.384-2.6029-3.156-2.6029-2.437 0-3.988 2.2706-3.988 5.8149s1.551 5.7595 3.988 5.7595c1.772 0 2.935-1.0522 3.156-2.5475h8.418c-.72 5.7596-4.873 9.8025-11.574 9.8025-7.477 0-12.572-5.3167-12.572-13.0145zm25.676 0c0-7.6978 5.095-13.0143 12.572-13.0143 6.701 0 10.854 3.9874 11.574 9.8023h-8.418c-.221-1.4953-1.384-2.6029-3.156-2.6029-2.437 0-3.988 2.2706-3.988 5.8149s1.551 5.7595 3.988 5.7595c1.772 0 2.935-1.0522 3.156-2.5475h8.418c-.72 5.7596-4.873 9.8025-11.574 9.8025-7.477 0-12.572-5.3167-12.572-13.0145zm42.013 3.7658h8.031c-.887 5.7597-5.206 9.2487-11.686 9.2487-7.642 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.317-13.0143 12.516-13.0143 7.643 0 11.962 5.095 11.962 12.5159v2.1598h-16.115c.277 2.9905 1.827 4.5965 4.319 4.5965 1.773 0 3.157-.7753 3.655-2.4921zm-3.821-10.0237c-2.049 0-3.433 1.2737-3.987 3.5997h7.532c-.111-2.0491-1.385-3.5997-3.545-3.5997zm23.4 16.7244v10.799h-8.694v-33.726h8.694v1.9937c1.163-1.3291 3.6-2.5475 6.148-2.5475 7.199 0 11.131 5.8703 11.131 13.0143 0 7.0886-3.932 13.0145-11.131 13.0145-2.548 0-4.985-1.219-6.148-2.548zm0-13.7893v6.5902c.665 1.3845 2.16 2.326 3.822 2.326 2.99 0 4.762-2.3814 4.762-5.5934s-1.772-5.6488-4.762-5.6488c-1.717 0-3.157.9969-3.822 2.326zm21.892 7.1994v-9.5807h-3.655v-6.7564h3.655v-6.8671h8.584v6.8671h5.206v6.7564h-5.206v8.307c0 1.9383.941 2.769 2.658 2.769.942 0 1.994-.2216 2.769-.5538v7.3654c-.997.443-2.88.775-4.818.775-5.87 0-9.193-2.769-9.193-9.0819zm39.458 8.5839h-8.363v-1.274c-.83.831-3.322 1.717-5.981 1.717-4.928 0-9.082-2.769-9.082-8.0301 0-4.818 4.154-7.9193 9.581-7.9193 2.049 0 4.486.6646 5.482 1.3845v-1.606c0-1.606-.941-2.9905-3.045-2.9905-1.606 0-2.548.7199-2.936 1.8275h-8.196c.72-4.8181 4.984-8.6393 11.408-8.6393 7.089 0 11.132 3.7659 11.132 10.2453zm-8.363-6.9779v-1.4399c-.553-1.0522-2.049-1.7167-3.655-1.7167-1.716 0-3.433.7199-3.433 2.3813 0 1.7168 1.717 2.4367 3.433 2.4367 1.606 0 3.102-.6645 3.655-1.6614zm20.742 4.9839v1.994h-8.694v-35.997h8.694v13.0697c1.163-1.3291 3.6-2.5475 6.148-2.5475 7.199 0 11.131 5.8149 11.131 13.0143s-3.932 13.0145-11.131 13.0145c-2.548 0-4.985-1.219-6.148-2.548zm0-13.7893v6.5902c.665 1.3845 2.105 2.326 3.822 2.326 2.99 0 4.762-2.3814 4.762-5.5934s-1.772-5.6488-4.762-5.6488c-1.662 0-3.157.9969-3.822 2.326zm28.759-20.2137v35.997h-8.695v-35.997zm19.172 27.3023h8.03c-.886 5.7597-5.206 9.2487-11.685 9.2487-7.643 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.316-13.0143 12.516-13.0143 7.642 0 11.962 5.095 11.962 12.5159v2.1598h-16.116c.277 2.9905 1.828 4.5965 4.32 4.5965 1.772 0 3.157-.7753 3.655-2.4921zm-3.821-10.0237c-2.049 0-3.434 1.2737-3.988 3.5997h7.532c-.111-2.0491-1.384-3.5997-3.544-3.5997z" fill="#d30001"/></svg>
|
<svg height="172" viewBox="0 0 480 172" width="480" xmlns="http://www.w3.org/2000/svg"><path d="m124.48 3.00509-45.6889 100.02991h26.2239v-28.1168h38.119v28.1168h21.628v35.145h-21.628v30.82h-37.308v-30.82h-72.1833v-31.901l50.2851-103.27391zm115.583 168.69891c-40.822 0-64.884-35.146-64.884-85.7015 0-50.5554 24.062-85.700907 64.884-85.700907 40.823 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.061 85.7015-64.884 85.7015zm0-133.2831c-17.572 0-22.709 21.8984-22.709 47.5816 0 25.6835 5.137 47.5815 22.709 47.5815 17.303 0 22.71-21.898 22.71-47.5815 0-25.6832-5.407-47.5816-22.71-47.5816zm202.906 9.7326h-41.093c-2.433-7.2994-7.84-12.4361-17.302-12.4361-16.221 0-25.413 17.5728-25.954 34.8752v1.3517c5.137-7.0291 16.221-12.4361 30.82-12.4361 33.524 0 54.881 24.0612 54.881 53.7998 0 33.253-23.791 58.396-61.64 58.396-21.628 0-39.741-10.003-50.825-27.576-9.733-14.599-13.788-32.442-13.788-54.3406 0-51.9072 24.331-89.485807 66.236-89.485807 32.712 0 53.258 18.654107 58.665 47.851907zm-82.727 66.2355c0 13.247 9.463 22.439 22.71 22.439 12.977 0 22.439-9.192 22.439-22.439 0-13.517-9.462-22.7091-22.439-22.7091-13.247 0-22.71 9.1921-22.71 22.7091z" id="error-id"/><path d="m100.761 68.9967v34.0033h-7.1991l-14.2326-19.8814v19.8814h-8.5839v-34.0033h8.307l13.125 18.7184v-18.7184zm28.454 21.5428c0 7.6978-5.15 13.0145-12.737 13.0145-7.532 0-12.738-5.3167-12.738-13.0145s5.206-13.0143 12.738-13.0143c7.587 0 12.737 5.3165 12.737 13.0143zm-8.529 0c0-3.4336-1.495-5.8703-4.208-5.8703-2.659 0-4.154 2.4367-4.154 5.8703s1.495 5.8149 4.154 5.8149c2.713 0 4.208-2.3813 4.208-5.8149zm13.185 3.8766v-9.5807h-3.655v-6.7564h3.655v-6.8671h8.584v6.8671h5.205v6.7564h-5.205v8.307c0 1.9383.941 2.769 2.658 2.769.941 0 1.994-.2216 2.769-.5538v7.3654c-.997.443-2.88.775-4.818.775-5.87 0-9.193-2.769-9.193-9.0819zm39.02-25.4194h9.083l12.958 34.0033h-9.027l-2.436-6.5902h-12.35l-2.381 6.5902h-8.806zm4.431 10.5222-3.489 9.5807h6.978zm17.44 11.0206c0-7.6978 5.095-13.0143 12.572-13.0143 6.701 0 10.854 3.9874 11.574 9.8023h-8.418c-.221-1.4953-1.384-2.6029-3.156-2.6029-2.437 0-3.988 2.2706-3.988 5.8149s1.551 5.7595 3.988 5.7595c1.772 0 2.935-1.0522 3.156-2.5475h8.418c-.72 5.7596-4.873 9.8025-11.574 9.8025-7.477 0-12.572-5.3167-12.572-13.0145zm25.676 0c0-7.6978 5.095-13.0143 12.572-13.0143 6.701 0 10.854 3.9874 11.574 9.8023h-8.418c-.221-1.4953-1.384-2.6029-3.156-2.6029-2.437 0-3.988 2.2706-3.988 5.8149s1.551 5.7595 3.988 5.7595c1.772 0 2.935-1.0522 3.156-2.5475h8.418c-.72 5.7596-4.873 9.8025-11.574 9.8025-7.477 0-12.572-5.3167-12.572-13.0145zm42.013 3.7658h8.031c-.887 5.7597-5.206 9.2487-11.686 9.2487-7.642 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.317-13.0143 12.516-13.0143 7.643 0 11.962 5.095 11.962 12.5159v2.1598h-16.115c.277 2.9905 1.827 4.5965 4.319 4.5965 1.773 0 3.157-.7753 3.655-2.4921zm-3.821-10.0237c-2.049 0-3.433 1.2737-3.987 3.5997h7.532c-.111-2.0491-1.385-3.5997-3.545-3.5997zm23.4 16.7244v10.799h-8.694v-33.726h8.694v1.9937c1.163-1.3291 3.6-2.5475 6.148-2.5475 7.199 0 11.131 5.8703 11.131 13.0143 0 7.0886-3.932 13.0145-11.131 13.0145-2.548 0-4.985-1.219-6.148-2.548zm0-13.7893v6.5902c.665 1.3845 2.16 2.326 3.822 2.326 2.99 0 4.762-2.3814 4.762-5.5934s-1.772-5.6488-4.762-5.6488c-1.717 0-3.157.9969-3.822 2.326zm21.892 7.1994v-9.5807h-3.655v-6.7564h3.655v-6.8671h8.584v6.8671h5.206v6.7564h-5.206v8.307c0 1.9383.941 2.769 2.658 2.769.942 0 1.994-.2216 2.769-.5538v7.3654c-.997.443-2.88.775-4.818.775-5.87 0-9.193-2.769-9.193-9.0819zm39.458 8.5839h-8.363v-1.274c-.83.831-3.322 1.717-5.981 1.717-4.928 0-9.082-2.769-9.082-8.0301 0-4.818 4.154-7.9193 9.581-7.9193 2.049 0 4.486.6646 5.482 1.3845v-1.606c0-1.606-.941-2.9905-3.045-2.9905-1.606 0-2.548.7199-2.936 1.8275h-8.196c.72-4.8181 4.984-8.6393 11.408-8.6393 7.089 0 11.132 3.7659 11.132 10.2453zm-8.363-6.9779v-1.4399c-.553-1.0522-2.049-1.7167-3.655-1.7167-1.716 0-3.433.7199-3.433 2.3813 0 1.7168 1.717 2.4367 3.433 2.4367 1.606 0 3.102-.6645 3.655-1.6614zm20.742 4.9839v1.994h-8.694v-35.997h8.694v13.0697c1.163-1.3291 3.6-2.5475 6.148-2.5475 7.199 0 11.131 5.8149 11.131 13.0143s-3.932 13.0145-11.131 13.0145c-2.548 0-4.985-1.219-6.148-2.548zm0-13.7893v6.5902c.665 1.3845 2.105 2.326 3.822 2.326 2.99 0 4.762-2.3814 4.762-5.5934s-1.772-5.6488-4.762-5.6488c-1.662 0-3.157.9969-3.822 2.326zm28.759-20.2137v35.997h-8.695v-35.997zm19.172 27.3023h8.03c-.886 5.7597-5.206 9.2487-11.685 9.2487-7.643 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.316-13.0143 12.516-13.0143 7.642 0 11.962 5.095 11.962 12.5159v2.1598h-16.116c.277 2.9905 1.828 4.5965 4.32 4.5965 1.772 0 3.157-.7753 3.655-2.4921zm-3.821-10.0237c-2.049 0-3.434 1.2737-3.988 3.5997h7.532c-.111-2.0491-1.384-3.5997-3.544-3.5997z" id="error-description"/></svg>
|
||||||
</header>
|
</header>
|
||||||
<article>
|
<article>
|
||||||
<p><strong>Your browser is not supported.</strong><br> Please upgrade your browser to continue.</p>
|
<p><strong>Your browser is not supported.</strong><br> Please upgrade your browser to continue.</p>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user