From ae8d995b2c901bbde504ea5dbaf3e5b137a96875 Mon Sep 17 00:00:00 2001 From: Jacob Cody Wimer Date: Wed, 11 Feb 2026 18:23:14 -0500 Subject: [PATCH] Added a QR code page that generates a QR code for tournament directors to print out. --- Gemfile | 2 +- Gemfile.lock | 6 +++ app/controllers/tournaments_controller.rb | 9 +++- app/views/layouts/_tournament-navbar.html.erb | 7 +-- app/views/tournaments/qrcode.html.erb | 50 +++++++++++++++++++ config/routes.rb | 1 + .../tournaments_controller_test.rb | 45 +++++++++++++++++ 7 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 app/views/tournaments/qrcode.html.erb diff --git a/Gemfile b/Gemfile index 5c1c362..bdf6c37 100644 --- a/Gemfile +++ b/Gemfile @@ -67,6 +67,7 @@ gem 'influxdb-rails' gem 'cancancan' gem 'round_robin_tournament' gem 'rb-readline' +gem 'rqrcode' # Replacing Delayed Job with Solid Queue # gem 'delayed_job_active_record' gem 'solid_queue' @@ -91,4 +92,3 @@ group :development, :test do # rails-controller-testing is needed for assert_template gem 'rails-controller-testing' end - diff --git a/Gemfile.lock b/Gemfile.lock index 7cdd3aa..04fe013 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -91,6 +91,7 @@ GEM bundler (>= 1.2.0) thor (~> 1.0) cancancan (3.6.1) + chunky_png (1.4.0) concurrent-ruby (1.3.6) connection_pool (3.0.2) crass (1.0.6) @@ -264,6 +265,10 @@ GEM reline (0.6.3) io-console (~> 0.5) round_robin_tournament (0.1.2) + rqrcode (3.2.0) + chunky_png (~> 1.0) + rqrcode_core (~> 2.0) + rqrcode_core (2.1.0) rubocop (1.84.1) json (~> 2.3) language_server-protocol (~> 3.17.0.2) @@ -366,6 +371,7 @@ DEPENDENCIES rails_12factor rb-readline round_robin_tournament + rqrcode rubocop sdoc solid_cable diff --git a/app/controllers/tournaments_controller.rb b/app/controllers/tournaments_controller.rb index fef35b5..abf1b60 100644 --- a/app/controllers/tournaments_controller.rb +++ b/app/controllers/tournaments_controller.rb @@ -1,6 +1,6 @@ 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 :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 :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,:qrcode] before_action :check_access_destroy, only: [:destroy,:delegate,:remove_delegate] before_action :check_tournament_errors, only: [:generate_matches] before_action :check_for_matches, only: [:all_results,:up_matches,:bracket,:all_brackets] @@ -196,6 +196,11 @@ class TournamentsController < ApplicationController end + def qrcode + @tournament_url = tournament_url(@tournament) + @qrcode = RQRCode::QRCode.new(@tournament_url) + end + def up_matches # .where.not(loser1_name: 'BYE') won't return matches with NULL loser1_name diff --git a/app/views/layouts/_tournament-navbar.html.erb b/app/views/layouts/_tournament-navbar.html.erb index e56096d..57f3c9b 100644 --- a/app/views/layouts/_tournament-navbar.html.erb +++ b/app/views/layouts/_tournament-navbar.html.erb @@ -38,9 +38,10 @@
  • Pages
  • <%= link_to "Edit Tournament Info", edit_tournament_path(@tournament) %>
  • <%= link_to "Weigh In Page" , "/tournaments/#{@tournament.id}/weigh_in" %>
  • -
  • <%= link_to "All Matches" , "/tournaments/#{@tournament.id}/matches" %>
  • -
  • <%= link_to "Full Screen Bout Board" , "/tournaments/#{@tournament.id}/up_matches?print=true" , target: :_blank %>
  • -
  • <%= link_to "Deduct Team Points" , "/tournaments/#{@tournament.id}/teampointadjust" %>
  • +
  • <%= link_to "All Matches" , "/tournaments/#{@tournament.id}/matches" %>
  • +
  • <%= link_to "Full Screen Bout Board" , "/tournaments/#{@tournament.id}/up_matches?print=true" , target: :_blank %>
  • +
  • <%= link_to "QR Code (Full Screen)" , "/tournaments/#{@tournament.id}/qrcode?print=true" , target: :_blank %>
  • +
  • <%= link_to "Deduct Team Points" , "/tournaments/#{@tournament.id}/teampointadjust" %>
  • <%= link_to "View All Mat Assignment Rules", tournament_mat_assignment_rules_path(@tournament) %>
  • <%= link_to 'Manage Backups', tournament_tournament_backups_path(@tournament) %>
  • <%= 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?" } %>
  • diff --git a/app/views/tournaments/qrcode.html.erb b/app/views/tournaments/qrcode.html.erb new file mode 100644 index 0000000..93153d0 --- /dev/null +++ b/app/views/tournaments/qrcode.html.erb @@ -0,0 +1,50 @@ + + +
    +

    <%= @tournament.name %> Brackets and Results Available Here

    +
    + <%= raw @qrcode.as_svg( + offset: 0, + color: "000", + shape_rendering: "crispEdges", + module_size: 8, + standalone: true + ) %> +
    +
    diff --git a/config/routes.rb b/config/routes.rb index bf27071..f1dbe93 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -73,6 +73,7 @@ Wrestling::Application.routes.draw do get 'tournaments/:id/bout_sheets' => 'tournaments#bout_sheets' get 'tournaments/:id/no_matches' => 'tournaments#no_matches' get 'tournaments/:id/matches' => 'tournaments#matches' + get 'tournaments/:id/qrcode' => 'tournaments#qrcode' get 'tournaments/:id/delegate' => 'tournaments#delegate', :as => :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 diff --git a/test/controllers/tournaments_controller_test.rb b/test/controllers/tournaments_controller_test.rb index dd35a09..884d56d 100644 --- a/test/controllers/tournaments_controller_test.rb +++ b/test/controllers/tournaments_controller_test.rb @@ -27,6 +27,10 @@ class TournamentsControllerTest < ActionController::TestCase def get_up_matches get :up_matches, params: { id: 1 } end + + def get_qrcode(params = {}) + get :qrcode, params: { id: 1 }.merge(params) + end def get_edit get :edit, params: { id: 1 } @@ -192,6 +196,47 @@ class TournamentsControllerTest < ActionController::TestCase assert_redirected_to '/static_pages/not_allowed' end + test "logged in non owner and non delegate cannot access qrcode" do + sign_in_non_owner + get_qrcode + redirect + end + + test "non logged in user cannot access qrcode" do + get_qrcode + redirect + end + + test "non logged in user with valid school permission key cannot access qrcode" do + @school.update(permission_key: "valid-key") + get_qrcode(school_permission_key: "valid-key") + redirect + end + + test "non logged in user with invalid school permission key cannot access qrcode" do + @school.update(permission_key: "valid-key") + get_qrcode(school_permission_key: "invalid-key") + redirect + end + + test "logged in owner can access qrcode" do + sign_in_owner + get_qrcode + success + end + + test "logged in tournament delegate can access qrcode" do + sign_in_delegate + get_qrcode + success + end + + test "logged in school delegate cannot access qrcode" do + sign_in_school_delegate + get_qrcode + redirect + end + test "logged in user should not post update tournament if not owner" do sign_in_non_owner post_update