1
0
mirror of https://github.com/jcwimer/wrestlingApp synced 2026-03-24 17:04:43 +00:00

Added a feature to generate uuid links for coaches to submit their school lineups.

This commit is contained in:
2025-02-18 16:39:10 -05:00
parent 934b34d0b7
commit 91e1939e69
20 changed files with 725 additions and 272 deletions

View File

@@ -10,14 +10,19 @@ class ApplicationController < ActionController::Base
end
rescue_from CanCan::AccessDenied do |exception|
# flash[:error] = "Access denied!"
redirect_to '/static_pages/not_allowed'
end
protected
# In Rails 4.2 and above
def verified_request?
super || valid_authenticity_token?(session, request.headers['X-XSRF-TOKEN'])
end
# Override current_ability to pass school_permission_key
# @school_permission_key needs to be defined on the controller
def current_ability
@current_ability ||= Ability.new(current_user, @school_permission_key)
end
end

View File

@@ -2,7 +2,7 @@ class SchoolsController < ApplicationController
before_action :set_school, only: [:import_baumspage_roster, :show, :edit, :update, :destroy, :stats]
before_action :check_access_director, only: [:new,:create,:destroy]
before_action :check_access_delegate, only: [:import_baumspage_roster, :update,:edit]
before_action :check_read_access, only: [:show]
before_action :check_read_access, only: [:show, :stats]
def stats
@tournament = @school.tournament
@@ -93,24 +93,37 @@ class SchoolsController < ApplicationController
end
def check_access_director
if params[:tournament]
if params[:tournament].present?
@tournament = Tournament.find(params[:tournament])
elsif params[:school]
elsif params[:school].present?
@tournament = Tournament.find(params[:school]["tournament_id"])
elsif @school
@tournament = @school.tournament
elsif school_params
@tournament = Tournament.find(school_params[:tournament_id])
end
authorize! :manage, @tournament
end
def check_access_delegate
if params[:school].present?
if school_params[:school_permission_key].present?
@school_permission_key = params[:school_permission_key]
end
end
if params[:school_permission_key].present?
@school_permission_key = params[:school_permission_key]
end
authorize! :manage, @school
end
def check_read_access
# set @school_permission_key for use in ability
if params[:school_permission_key].present?
@school_permission_key = params[:school_permission_key]
end
authorize! :read, @school
end
end

View File

@@ -1,6 +1,6 @@
class TournamentsController < ApplicationController
before_action :set_tournament, only: [: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,:brackets,:generate_matches,:bracket,:all_brackets]
before_action :check_access_manage, only: [: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: [: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,:brackets,:generate_matches,:bracket,:all_brackets]
before_action :check_access_manage, only: [:delete_school_keys, :generate_school_keys,:reset_bout_board,:calculate_team_scores,:swap,:weigh_in_sheet,:teampointadjust,:remove_teampointadjust,:remove_school_delegate,:school_delegate,:weigh_in,:weigh_in_weight,:create_custom_weights,:update,:edit,:generate_matches,:matches]
before_action :check_access_destroy, only: [:destroy,:delegate,:remove_delegate]
before_action :check_tournament_errors, only: [:generate_matches]
before_action :check_for_matches, only: [:up_matches,:bracket,:all_brackets]
@@ -281,6 +281,18 @@ class TournamentsController < ApplicationController
redirect_to tournament_path(@tournament), notice: "Successfully reset the bout board."
end
def generate_school_keys
@tournament.schools.each do |school|
school.update(permission_key: SecureRandom.uuid)
end
redirect_to school_delegate_path(@tournament), notice: "School permission keys generated successfully."
end
def delete_school_keys
@tournament.schools.update_all(permission_key: nil)
redirect_to school_delegate_path(@tournament), notice: "All school permission keys have been deleted."
end
private
# Use callbacks to share common setup or constraints between actions.
def set_tournament

View File

@@ -1,9 +1,7 @@
class WrestlersController < ApplicationController
before_action :set_wrestler, only: [:show, :edit, :update, :destroy, :update_pool]
before_action :check_access, only: [:new,:create,:update,:destroy,:edit,:update_pool]
before_action :check_access, only: [:new, :create, :update, :destroy, :edit, :update_pool]
before_action :check_read_access, only: [:show]
# GET /wrestlers/1
# GET /wrestlers/1.json
@@ -16,133 +14,145 @@ class WrestlersController < ApplicationController
# GET /wrestlers/new
def new
@wrestler = Wrestler.new
if params[:school]
@school = School.find(params[:school])
end
if @school
@tournament = Tournament.find(@school.tournament_id)
end
if @tournament
@weights = Weight.where(tournament_id: @tournament.id).sort_by{|w| w.max}
end
@school = School.find_by(id: params[:school]) if params[:school]
# Save the key into an instance variable so the view can use it.
@school_permission_key = params[:school_permission_key].presence
@tournament = @school.tournament if @school
@weights = @tournament.weights.sort_by(&:max) if @tournament
end
# GET /wrestlers/1/edit
def edit
@tournament = @wrestler.tournament
@weight = @wrestler.weight
@weights = @school.tournament.weights.sort_by{|w| w.max}
@school = @wrestler.school
@weights = @school.tournament.weights.sort_by(&:max)
end
# POST /wrestlers
# POST /wrestlers.json
def create
@wrestler = Wrestler.new(wrestler_params)
@school = School.find(wrestler_params[:school_id])
@weights = @school.tournament.weights
@school = School.find_by(id: wrestler_params[:school_id])
# IMPORTANT: Get the key from wrestler_params (not from params directly)
@school_permission_key = wrestler_params[:school_permission_key].presence
@weights = @school.tournament.weights if @school
# Remove the key from attributes so it isnt assigned to the model.
@wrestler = Wrestler.new(wrestler_params.except(:school_permission_key))
respond_to do |format|
if @wrestler.save
if session[:return_path]
format.html { redirect_to session.delete(:return_path), notice: 'Wrestler was successfully created.' }
else
format.html { redirect_to @school, notice: 'Wrestler was successfully created.' }
format.json { render action: 'show', status: :created, location: @wrestler }
end
redirect_path = session[:return_path] || school_path(@school)
format.html { redirect_to append_permission_key(redirect_path), notice: 'Wrestler was successfully created.' }
format.json { render :show, status: :created, location: @wrestler }
else
format.html { render action: 'new' }
format.html { render :new }
format.json { render json: @wrestler.errors, status: :unprocessable_entity }
end
end
end
end
# PATCH/PUT /wrestlers/1
# PATCH/PUT /wrestlers/1.json
def update
@tournament = @wrestler.tournament
@weight = @wrestler.weight
@weights = @tournament.weights.sort_by{|w| w.max}
@school = @wrestler.school
@weights = @tournament.weights.sort_by(&:max)
respond_to do |format|
if @wrestler.update(wrestler_params)
if session[:return_path]
format.html { redirect_to session.delete(:return_path), notice: 'Wrestler was successfully updated.' }
else
format.html { redirect_to @school, notice: 'Wrestler was successfully updated.' }
format.json { render action: 'show', status: :created, location: @wrestler }
end
if @wrestler.update(wrestler_params.except(:school_permission_key))
redirect_path = session[:return_path] || school_path(@school)
format.html { redirect_to append_permission_key(redirect_path), notice: 'Wrestler was successfully updated.' }
format.json { render :show, status: :ok, location: @wrestler }
else
format.html { render action: 'edit' }
format.html { render :edit }
format.json { render json: @wrestler.errors, status: :unprocessable_entity }
end
end
end
def update_pool
@tournament = @wrestler.tournament
@weight = @wrestler.weight
@weights = @tournament.weights.sort_by{|w| w.max}
@school = @wrestler.school
if params[:wrestler]['pool']
@wrestler.pool = params[:wrestler]['pool']
respond_to do |format|
message = "Wrestler has successfully been switched to a new pool. Matches for that weight are now in a weird state. Please re-generate matches when you are done with all of your changes."
if @wrestler.update(wrestler_params)
format.html { redirect_to "/tournaments/#{@tournament.id}/brackets/#{@wrestler.weight.id}/", notice: message }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: @wrestler.errors, status: :unprocessable_entity }
end
end
end
end
end
# DELETE /wrestlers/1
# DELETE /wrestlers/1.json
def destroy
@school = @wrestler.school
@wrestler.destroy
message = "Wrestler was successfully deleted. This action has removed all matches. Please re-generate matches if you already had matches."
respond_to do |format|
message = "Wrestler was successfully deleted. This action has removed all matches. Please re-generate matches if you already had matches."
if session[:return_path]
format.html { redirect_to session.delete(:return_path), notice: message }
else
format.html { redirect_to @school, notice: message }
format.json { head :no_content }
end
redirect_path = session[:return_path] || school_path(@school)
format.html { redirect_to append_permission_key(redirect_path), notice: message }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_wrestler
@wrestler = Wrestler.where(:id => params[:id]).includes(:school, :weight, :tournament, :matches).first
def set_wrestler
@wrestler = Wrestler.includes(:school, :weight, :tournament, :matches).find_by(id: params[:id])
end
def wrestler_params
params.require(:wrestler).permit(:name, :school_id, :weight_id, :seed, :original_seed, :season_win,
:season_loss, :criteria, :extra, :offical_weight, :pool, :school_permission_key)
end
def check_access
if params[:school].present?
@school = School.find(params[:school])
#@tournament = Tournament.find(@school.tournament.id)
elsif params[:wrestler].present?
if params[:wrestler]["school_id"].present?
@school = School.find(params[:wrestler]["school_id"])
if wrestler_params[:school_permission_key].present?
@school_permission_key = wrestler_params[:school_permission_key]
end
else
@wrestler = Wrestler.find(params[:wrestler]["id"])
@school = @wrestler.school
end
elsif @wrestler
@school = @wrestler.school
end
# Never trust parameters from the scary internet, only allow the white list through.
def wrestler_params
params.require(:wrestler).permit(:name, :school_id, :weight_id, :seed, :original_seed, :season_win, :season_loss,:criteria,:extra,:offical_weight,:pool)
# set @school_permission_key for use in ability
if params[:school_permission_key].present?
@school_permission_key = params[:school_permission_key]
end
def check_access
if params[:school]
@school = School.find(params[:school])
#@tournament = Tournament.find(@school.tournament.id)
elsif params[:wrestler]
if params[:wrestler]["school_id"]
@school = School.find(params[:wrestler]["school_id"])
else
@wrestler = Wrestler.find(params[:wrestler]["id"])
@school = @wrestler.school
end
#@tournament = Tournament.find(@school.tournament.id)
elsif @wrestler
@school = @wrestler.school
#@tournament = @wrestler.tournament
elsif wrestler_params
@school = School.find(wrestler_params[:school_id])
end
authorize! :manage, @school
authorize! :manage, @school
end
def check_read_access
if params[:school]
@school = School.find(params[:school])
elsif params[:wrestler].present?
if params[:wrestler]["school_id"].present?
@school = School.find(params[:wrestler]["school_id"])
else
@wrestler = Wrestler.find(params[:wrestler]["id"])
@school = @wrestler.school
end
if wrestler_params[:school_permission_key].present?
@school_permission_key = wrestler_params[:school_permission_key]
end
elsif @wrestler
@school = @wrestler.school
end
# set @school_permission_key for use in ability
if params[:school_permission_key].present?
@school_permission_key = params[:school_permission_key]
end
authorize! :read, @school
end
# Helper method to append school_permission_key to redirects if it exists.
def append_permission_key(path)
return path unless @school_permission_key.present?
# If path is an ActiveRecord object, convert to URL.
path = school_path(path) if path.is_a?(School)
uri = URI.parse(path)
query_params = Rack::Utils.parse_nested_query(uri.query || "")
query_params["school_permission_key"] = @school_permission_key
uri.query = query_params.to_query
uri.to_s
end
end

View File

@@ -1,95 +1,74 @@
class Ability
include CanCan::Ability
def initialize(user)
# Define abilities for the passed in user here. For example:
#
# user ||= User.new # guest user (not logged in)
# if user.admin?
# can :manage, :all
# else
# can :read, :all
# end
#
# The first argument to `can` is the action you are giving the user
# permission to do.
# If you pass :manage it will apply to every action. Other common actions
# here are :read, :create, :update and :destroy.
#
# The second argument is the resource the user can perform the action on.
# If you pass :all it will apply to every resource. Otherwise pass a Ruby
# class of the resource.
#
# The third argument is an optional hash of conditions to further filter the
# objects.
# For example, here the user can only update published articles.
#
# can :update, Article, :published => true
#
# See the wiki for details:
# https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities
if !user.nil?
#Can manage tournament if tournament owner
can :manage, Tournament, :user_id => user.id
#Can manage but cannot destroy tournament if tournament delegate
def initialize(user, school_permission_key = nil)
if user
# LOGGED IN USER PERMISSIONS
# TOURNAMENT PERMISSIONS
# Can manage but cannot destroy tournament if tournament delegate
can :manage, Tournament do |tournament|
tournament.delegates.map(&:user_id).include? user.id
tournament.user_id == user.id ||
tournament.delegates.map(&:user_id).include?(user.id)
end
# can destroy tournament if tournament owner
can :destroy, Tournament do |tournament|
tournament.user_id == user.id
end
# tournament delegates cannot destroy - explicitly deny
cannot :destroy, Tournament do |tournament|
tournament.delegates.map(&:user_id).include? user.id
tournament.delegates.map(&:user_id).include?(user.id)
end
# Can read tournament if tournament owner or tournament delegate
# Can read tournament if tournament.is_public, tournament owner, or tournament delegate
can :read, Tournament do |tournament|
if tournament.is_public
true
elsif tournament.delegates.map(&:user_id).include? user.id or tournament.user_id == user.id
true
else
false
end
tournament.is_public ||
tournament.delegates.map(&:user_id).include?(user.id) ||
tournament.user_id == user.id
end
#Can manage school if tournament owner
# SCHOOL PERMISSIONS
# wrestler permissions are included with school permissions
# Can manage school if is school delegate, is tournament delegate, or is tournament director
can :manage, School do |school|
school.delegates.map(&:user_id).include?(user.id) ||
school.tournament.delegates.map(&:user_id).include?(user.id) ||
school.tournament.user_id == user.id
end
#Can manage school if tournament delegate
can :manage, School do |school|
school.tournament.delegates.map(&:user_id).include? user.id
end
#Can manage but cannot destroy school if school delegate
can :manage, School do |school|
school.delegates.map(&:user_id).include? user.id
end
cannot :destroy, School do |school|
school.delegates.map(&:user_id).include? user.id
end
# Can read school if school delegate, tournament delegate, or tournament director
# Can read school if tournament.is_public OR is school delegate, is tournament delegate, or is tournament director
can :read, School do |school|
if school.tournament.is_public
true
elsif school.delegates.map(&:user_id).include? user.id or school.tournament.delegates.map(&:user_id).include? user.id or school.tournament.user_id == user.id
true
else
false
end
school.tournament.is_public ||
school.delegates.map(&:user_id).include?(user.id) ||
school.tournament.delegates.map(&:user_id).include?(user.id) ||
school.tournament.user_id == user.id
end
# Default for non logged in users
else
# NON LOGGED IN USER PERMISSIONS
# TOURNAMENT PERMISSIONS
# Can read tournament if tournament is public
can :read, Tournament do |tournament|
if tournament.is_public
true
else
false
end
tournament.is_public
end
# Can read school if tournament is public
# SCHOOL PERMISSIONS
# wrestler permissions are included with school permissions
# Can read school if tournament is public or a valid school permission key is provided
can :read, School do |school|
if school.tournament.is_public
true
else
false
end
school.tournament.is_public ||
(school_permission_key.present? && school.permission_key == school_permission_key)
end
# Can read school if a valid school permission key is provided
# school_permission_key comes from app/controllers/application_controller.rb
can :manage, School do |school|
(school_permission_key.present? && school.permission_key == school_permission_key)
end
end
end

View File

@@ -21,6 +21,10 @@
<% end %>
<br>
<% if params[:school_permission_key].present? %>
<%= f.hidden_field :school_permission_key, value: params[:school_permission_key] %>
<% end %>
<div class="actions">
<%= f.submit 'Submit', :class=>"btn btn-success" %>
</div>

View File

@@ -1,68 +1,115 @@
<p>
<strong>Name:</strong>
<%= @school.name %>
<% if can? :manage, @school %><%= link_to " Edit", edit_school_path(@school),:class=>"fas fa-edit" %><% end %>
</p>
<p>
<strong>Name:</strong>
<%= @school.name %>
<% if can? :manage, @school %>
<% edit_school_path_with_key = edit_school_path(@school) %>
<% edit_school_path_with_key += "?school_permission_key=#{params[:school_permission_key]}" if params[:school_permission_key].present? %>
<%= link_to " Edit", edit_school_path_with_key, class: "fas fa-edit" %>
<% end %>
</p>
<p>
<strong>Team Points Deducted:</strong>
<%= @school.total_points_deducted %>
</p>
<p>
<strong>Score:</strong>
<%= @school.score %>
</p>
<p>
<strong>Team Points Deducted:</strong>
<%= @school.total_points_deducted %>
</p>
<p>
<strong>Tournament:</strong>
<%= @school.tournament.name %>
</p>
<%= link_to "#{@school.name} Stat Summary", "/schools/#{@school.id}/stats",:class=>"btn btn-sm btn-primary" %>
<br>
<br>
<h3>Roster</h3>
<p>(Click wrestler to see their score breakdown and match list)</p>
<table class="table table-hover table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Weight</th>
<th>Record/Seed Criteria</th>
<th>Seed</th>
<th>Team Points Scored</th>
<th>Extra?</th>
<th>Next Bout/Mat</th>
<% if can? :manage, @school %><th><%= link_to " New Wrestler" , "/wrestlers/new?school=#{@school.id}", :class=>"fas fa-plus"%></th><% end %>
</tr>
</thead>
<p>
<strong>Score:</strong>
<%= @school.score %>
</p>
<tbody>
<% @wrestlers.sort_by{|w| w.weight.max}.each do |wrestler| %>
<p>
<strong>Tournament:</strong>
<%= @school.tournament.name %>
</p>
<% stat_summary_path_with_key = "/schools/#{@school.id}/stats" %>
<% stat_summary_path_with_key += "?school_permission_key=#{params[:school_permission_key]}" if params[:school_permission_key].present? %>
<%= link_to "#{@school.name} Stat Summary", stat_summary_path_with_key, class: "btn btn-sm btn-primary" %>
<br><br>
<h3>Roster</h3>
<p>(Click wrestler to see their score breakdown and match list)</p>
<table class="table table-hover table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Weight</th>
<th>Record/Seed Criteria</th>
<th>Seed</th>
<th>Team Points Scored</th>
<th>Extra?</th>
<th>Next Bout/Mat</th>
<% new_wrestler_path_with_key = new_wrestler_path(school: @school.id) %>
<% new_wrestler_path_with_key += "&school_permission_key=#{params[:school_permission_key]}" if params[:school_permission_key].present? %>
<% if can? :manage, @school %>
<th><%= link_to " New Wrestler", new_wrestler_path_with_key, class: "fas fa-plus" %></th>
<% end %>
</tr>
</thead>
<tbody>
<% @wrestlers.sort_by { |w| w.weight.max }.each do |wrestler| %>
<% if params[:school_permission_key].present? %>
<!-- No caching when school_permission_key is present -->
<tr>
<td>
<% 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 %>
<td>
<% edit_wrestler_path_with_key = edit_wrestler_path(wrestler) %>
<% edit_wrestler_path_with_key += "?school_permission_key=#{params[:school_permission_key]}" if params[:school_permission_key].present? %>
<% 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, method: :delete, data: { 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>
<% else %>
<!-- Use caching only when school_permission_key is NOT present -->
<% cache ["#{wrestler.id}_school_show", @school] do %>
<tr>
<td><%= link_to "#{wrestler.name}", wrestler %></td>
<td><%= link_to wrestler.name, wrestler_path(wrestler) %></td>
<td><%= wrestler.weight.max %></td>
<td><%= wrestler.season_win %>-<%= wrestler.season_loss %> <%= wrestler.criteria %></td>
<td>
<%= wrestler.original_seed %>
</td>
<td><%= wrestler.original_seed %></td>
<td><%= wrestler.total_team_points - wrestler.total_points_deducted %></td>
<td><% if wrestler.extra? == true %>
Yes
<% end %>
</td>
<td><%= "Yes" if wrestler.extra? %></td>
<td><%= wrestler.next_match_bout_number %> <%= wrestler.next_match_mat_name %></td>
<% end %>
<td><%= wrestler.next_match_bout_number %> <%= wrestler.next_match_mat_name %></td>
<% if can? :manage, wrestler.school %>
<td>
<%= link_to '', edit_wrestler_path(wrestler),:class=>"fas fa-edit" %>
<%= link_to '', wrestler, method: :delete, data: { confirm: "Are you sure you want to delete #{wrestler.name}? This will delete all of his matches." }, :class=>"fas fa-trash-alt" %>
<% edit_wrestler_path_with_key = edit_wrestler_path(wrestler) %>
<% edit_wrestler_path_with_key += "?school_permission_key=#{params[:school_permission_key]}" if params[:school_permission_key].present? %>
<% 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, method: :delete, data: { 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 %>
</tbody>
</table>
<% end %>
</tbody>
</table>
<% if can? :manage, @school %>
<%= render 'baums_roster_import' %>

View File

@@ -1,4 +1,7 @@
<%= link_to "Back to #{@school.name}", "/schools/#{@school.id}", :class=>"btn btn-default" %>
<% back_to_school_path = school_path(@school) %>
<% back_to_school_path += "?school_permission_key=#{params[:school_permission_key]}" if params[:school_permission_key].present? %>
<%= link_to "Back to #{@school.name}", back_to_school_path, class: "btn btn-default" %>
<% cache ["#{@school.id}_Stats", @school] do %>
<br>
<br>

View File

@@ -17,6 +17,7 @@
<% @winner_place = "1st" %>
<%= render 'bracket_final' %>
</div>
<! -- Only use a 2nd page for consolation bracket if bracket is bigger than 16 -->
<% if @weight.wrestlers.size > 16 %>
</div>
</div>
@@ -24,6 +25,7 @@
<div class="page">
<div class="bracket-container">
<% end %>
<! -- End if for only use a 2nd page for consolation bracket if bracket is bigger than 16 -->
<h4><%= @tournament.name %> - <%= @weight.max %> Bracket</h4>
<h4>Consolation Bracket</h4>
<div class="bracket">
@@ -41,13 +43,15 @@
<% @winner_place = "3rd" %>
<%= render 'bracket_final' %>
</div>
<% if @weight.wrestlers.size >= 6 && @tournament.number_of_placers >= 6 %>
<h4>5/6 place match</h4>
<div class="bracket">
<% @final_match = @matches.select{|m|m.bracket_position == "5/6"} %>
<% @winner_place = "5th" %>
<%= render 'bracket_final' %>
</div>
<% if @tournament.number_of_placers >= 8 %>
<% end %>
<% if @weight.wrestlers.size >= 8 && @tournament.number_of_placers >= 8 %>
<h4>7/8 place match</h4>
<div class="bracket">
<% @final_match = @matches.select{|m|m.bracket_position == "7/8"} %>

View File

@@ -1,4 +1,35 @@
<h1>Search results</h1> <%= form_tag(school_delegate_path, :method => "get", id: "search-form") do %>
<h1>School Lineup Permission Links</h1>
<p>Instead of forcing coaches to log into the app, you can generate links for their school that you can email them to submit their lineups. Be sure to delete these after the deadline for lineup submissions.</p>
<%= button_to "Generate School Permission Key Links", generate_school_keys_tournament_path(@tournament), method: :post, class: "btn btn-success" %>
<%= button_to "Delete School Permission Key Links", delete_school_keys_tournament_path(@tournament), method: :post, class: "btn btn-danger" %>
<br><br>
<% if @tournament.schools.where.not(permission_key: nil).exists? %>
<h2>Links for Schools with Permission Keys</h2>
<table class="table table-striped">
<thead>
<tr>
<th>School Name</th>
<th>Permission Link</th>
</tr>
</thead>
<tbody>
<% @tournament.schools.where.not(permission_key: nil).each do |school| %>
<tr>
<td><%= school.name %></td>
<td>
<% full_url = "#{request.base_url}/schools/#{school.id}?school_permission_key=#{school.permission_key}" %>
<a href="<%= full_url %>"><%= full_url %></a>
</td>
</tr>
<% end %>
</tbody>
</table>
<% end %>
<br><br>
<h1>School Delegation for User Accounts</h1>
<p>If you'd like coaches to have to log into the app, you can have them create an account first then search for that account here and assign their account to a school for lineup submission. Be sure to delete these after the deadline for lineup submissions.</p>
<h2>Search results</h2> <%= form_tag(school_delegate_path, :method => "get", id: "search-form") do %>
<%= text_field_tag :search, params[:search], placeholder: "Search users" %>
<%= submit_tag "Search" %>
<% end %>
@@ -33,7 +64,7 @@
<% end %>
<% if @users_delegates %>
<h1>Delegated users schools</h1>
<h2>Delegated users schools</h2>
<table class="table table-striped table-bordered table-condensed">
<thead>
<tr>
@@ -53,4 +84,4 @@
<% end %>
</tbody>
</table>
<% end %>
<% end %>

View File

@@ -1,13 +1,11 @@
<%= form_for(@wrestler) do |f| %>
<% if @wrestler.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@wrestler.errors.count, "error") %> prohibited this wrestler from being saved:</h2>
<ul>
<% @wrestler.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
<% @wrestler.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
@@ -16,43 +14,37 @@
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<% if can? :manage, @wrestler.tournament %>
<div class="field">
<%= f.label 'School' %><br>
<%= f.collection_select :school_id, @school.tournament.schools, :id, :name %>
</div>
<% if can? :manage, @wrestler.tournament %>
<div class="field">
<%= f.label 'School' %><br>
<%= f.collection_select :school_id, @school.tournament.schools, :id, :name %>
</div>
<% else %>
<%= f.hidden_field :school_id, :value => @school.id %>
<%= f.hidden_field :school_id, value: @school.id %>
<% end %>
<div class="field">
<%= f.label 'Weight Class' %><br>
<%= f.collection_select :weight_id, @weights, :id, :max %>
</div>
<div class="field">
<%= f.label "Season Wins" %><br>
<%= f.number_field :season_win %>
</div>
<div class="field">
<%= f.label "Season Losses" %><br>
<%= f.number_field :season_loss %>
</div>
<div class="field">
<%= f.label "Seed Criteria" %><br>
<%= f.text_field :criteria %>
</div>
<div class="field">
<%= f.label "Check box if extra" %> <%= f.check_box :extra %>
</div>
</br>
</br>
<!-- Render the hidden field if a permission key is present -->
<% if @school_permission_key.present? %>
<%= f.hidden_field :school_permission_key, value: @school_permission_key %>
<% end %>
<div class="actions">
<%= f.submit :class=>"btn btn-success"%>
<%= f.submit class: "btn btn-success" %>
</div>
<% end %>

View File

@@ -1,4 +1,7 @@
<%= link_to "Back to #{@school.name}", "/schools/#{@school.id}", :class=>"btn btn-default" %>
<% back_to_school_path = school_path(@school) %>
<% back_to_school_path += "?school_permission_key=#{params[:school_permission_key]}" if params[:school_permission_key].present? %>
<%= link_to "Back to #{@school.name}", back_to_school_path, class: "btn btn-default" %>
<br>
<br>
<h1>Editing wrestler</h1>

View File

@@ -1,4 +1,7 @@
<%= link_to "Back to #{@school.name}", "/schools/#{@school.id}", :class=>"btn btn-default" %>
<% back_to_school_path = school_path(@school) %>
<% back_to_school_path += "?school_permission_key=#{params[:school_permission_key]}" if params[:school_permission_key].present? %>
<%= link_to "Back to #{@school.name}", back_to_school_path, class: "btn btn-default" %>
<br>
<br>
<h1>New wrestler</h1>

View File

@@ -1,4 +1,7 @@
<%= link_to "Back to #{@school.name}", "/schools/#{@school.id}", :class=>"btn btn-sm btn-default" %>
<% back_to_school_path = school_path(@wrestler.school) %>
<% back_to_school_path += "?school_permission_key=#{params[:school_permission_key]}" if params[:school_permission_key].present? %>
<%= link_to "Back to #{@wrestler.school.name}", back_to_school_path, class: "btn btn-default" %>
<br>
<br>
<p>

View File

@@ -81,6 +81,13 @@ Wrestling::Application.routes.draw do
get "/matches/:id/stat" => "matches#stat", :as => :stat_match_path
resources :tournaments do
member do
post :generate_school_keys
post :delete_school_keys
end
end
# Example of regular route:
# get 'products/:id' => 'catalog#view'

View File

@@ -0,0 +1,6 @@
class AddUuidToSchools < ActiveRecord::Migration[7.2]
def change
add_column :schools, :permission_key, :string
add_index :schools, :permission_key, unique: true
end
end

View File

@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.2].define(version: 2025_01_26_004721) do
ActiveRecord::Schema[7.2].define(version: 2025_01_30_172404) do
create_table "delayed_jobs", force: :cascade do |t|
t.integer "priority", default: 0, null: false
t.integer "attempts", default: 0, null: false
@@ -88,6 +88,8 @@ ActiveRecord::Schema[7.2].define(version: 2025_01_26_004721) do
t.datetime "updated_at", precision: nil
t.integer "tournament_id"
t.decimal "score", precision: 15, scale: 1
t.string "permission_key"
t.index ["permission_key"], name: "index_schools_on_permission_key", unique: true
t.index ["tournament_id"], name: "index_schools_on_tournament_id"
end

View File

@@ -4,9 +4,11 @@ class SchoolsControllerTest < ActionController::TestCase
include Devise::Test::ControllerHelpers
setup do
@tournament = Tournament.find(1)
@tournament = Tournament.find(1)
# @tournament.generateMatchups
@school = @tournament.schools.first
@school = @tournament.schools.first
@school.update(permission_key: SecureRandom.uuid) # Generate a valid school_permission_key
@school_permission_key = @school.permission_key
end
def create
@@ -17,20 +19,20 @@ class SchoolsControllerTest < ActionController::TestCase
get :new, params: { tournament: @tournament.id }
end
def get_show
get :show, params: { id: @school.id }
def get_show(extra_params = {})
get :show, params: { id: @school.id }.merge(extra_params)
end
def post_update
patch :update, params: { id: @school.id, school: {name: @school.name, tournament_id: @school.tournament_id} }
def post_update(extra_params = {})
patch :update, params: { id: @school.id, school: { name: @school.name, tournament_id: @school.tournament_id } }.merge(extra_params)
end
def destroy
delete :destroy, params: { id: @school.id }
def destroy(extra_params = {})
delete :destroy, params: { id: @school.id }.merge(extra_params)
end
def get_edit
get :edit, params: { id: @school.id }
def get_edit(extra_params = {})
get :edit, params: { id: @school.id }.merge(extra_params)
end
def sign_in_owner
@@ -288,6 +290,150 @@ Some Guy
get_show
success
end
test "non logged in user can get stats page when tournament is public" do
@tournament.is_public = true
@tournament.save
get :stats, params: { id: @school.id }
success
end
test "logged in school delegate can get stats page when tournament is not public" do
@tournament.is_public = false
@tournament.save
sign_in_school_delegate
get :stats, params: { id: @school.id }
success
end
test "logged in tournament owner can get stats page when tournament is not public" do
@tournament.is_public = false
@tournament.save
sign_in_owner
get :stats, params: { id: @school.id }
success
end
test "logged in tournament delegate can get stats page when tournament is not public" do
@tournament.is_public = false
@tournament.save
sign_in_tournament_delegate
get :stats, params: { id: @school.id }
success
end
test "logged in non owner cannot get stats page when tournament is not public" do
@tournament.is_public = false
@tournament.save
sign_in_non_owner
get :stats, params: { id: @school.id }
redirect
end
test "non logged in user cannot get stats page when tournament is not public" do
@tournament.is_public = false
@tournament.save
sign_in_non_owner
get :stats, params: { id: @school.id }
redirect
end
test "stats page without school_permission_key does not include it in 'Back to School' link" do
get :stats, params: { id: @school.id }
success
# The link is typically: /schools/:id?school_permission_key=valid_key
# 'Back to Central Crossing' or similar text
assert_select "a[href=?]", school_path(id: @school.id), text: /Back to/
end
test "wrestler links do not contain school_permission_key when not used" do
@tournament.update(is_public: false)
sign_in_owner
get_show
assert_select "a[href=?]", new_wrestler_path(school: @school.id), text: "New Wrestler"
@school.wrestlers.each do |wrestler|
# Check only for the DELETE link, specifying 'data-method="delete"' to exclude profile links
assert_select "a[href=?][data-method=delete]", wrestler_path(wrestler), count: 1
# Check edit link
assert_select "a[href=?]", edit_wrestler_path(wrestler), count: 1
end
end
# END SHOW PAGE PERMISSIONS
# School permission key tests
test "non logged in user can get show page when using valid school_permission_key" do
@tournament.update(is_public: false)
get_show(school_permission_key: @school_permission_key)
success
end
test "non logged in user cannot get show page when using invalid school_permission_key" do
@tournament.update(is_public: false)
get_show(school_permission_key: "invalid-key")
redirect
end
test "non logged in user can edit school with valid school_permission_key" do
@tournament.update(is_public: false)
get_edit(school_permission_key: @school_permission_key)
success
end
test "non logged in user cannot edit school with invalid school_permission_key" do
@tournament.update(is_public: false)
get_edit(school_permission_key: "invalid-key")
redirect
end
test "non logged in user can update school with valid school_permission_key" do
@tournament.update(is_public: false)
post_update(school_permission_key: @school_permission_key)
assert_redirected_to tournament_path(@school.tournament_id)
end
test "non logged in user cannot update school with invalid school_permission_key" do
@tournament.update(is_public: false)
post_update(school_permission_key: "invalid-key")
redirect
end
test "non logged in user cannot delete school with invalid school_permission_key" do
@tournament.update(is_public: false)
destroy(school_permission_key: "invalid-key")
redirect
end
test "non logged in user cannot delete school with valid school_permission_key" do
@tournament.update(is_public: false)
destroy(school_permission_key: @school_permission_key)
redirect
end
# Ensure school_permission_key is used in wrestler links
test "wrestler links contain school_permission_key when used" do
@tournament.update(is_public: false)
get_show(school_permission_key: @school_permission_key)
assert_select "a[href=?]", new_wrestler_path(school: @school.id, school_permission_key: @school_permission_key), text: "New Wrestler"
@school.wrestlers.each do |wrestler|
assert_select "a[href=?]", edit_wrestler_path(wrestler, school_permission_key: @school_permission_key)
assert_select "a[href=?]", wrestler_path(wrestler, school_permission_key: @school_permission_key), method: :delete
end
end
test "stats page with school_permission_key includes it in 'Back to School' link" do
get :stats, params: { id: @school.id, school_permission_key: @school_permission_ke }
success
# The link is typically: /schools/:id?school_permission_key=valid_key
# 'Back to Central Crossing' or similar text
assert_select "a[href=?]", school_path(id: @school.id, school_permission_key: @school_permission_ke), text: /Back to/
end
# End school permission key tests
end

View File

@@ -800,4 +800,57 @@ class TournamentsControllerTest < ActionController::TestCase
get :generate_matches, params: { id: @tournament.id }
success
end
test "tournament owner can create school keys" do
sign_in_owner
post :generate_school_keys, params: { id: @tournament.id }
assert_redirected_to school_delegate_path(@tournament)
assert_equal "School permission keys generated successfully.", flash[:notice]
end
test "tournament owner can delete school keys" do
sign_in_owner
post :delete_school_keys, params: { id: @tournament.id }
# Update this path/notices if your controller redirects differently
assert_redirected_to school_delegate_path(@tournament)
assert_equal "All school permission keys have been deleted.", flash[:notice]
end
test "tournament delegate can create school keys" do
sign_in_delegate
post :generate_school_keys, params: { id: @tournament.id }
assert_redirected_to school_delegate_path(@tournament)
assert_equal "School permission keys generated successfully.", flash[:notice]
end
test "tournament delegate can delete school keys" do
sign_in_delegate
post :delete_school_keys, params: { id: @tournament.id }
assert_redirected_to school_delegate_path(@tournament)
assert_equal "All school permission keys have been deleted.", flash[:notice]
end
test "logged in non-owner cannot create school keys" do
sign_in_non_owner
post :generate_school_keys, params: { id: @tournament.id }
redirect
end
test "logged in non-owner cannot delete school keys" do
sign_in_non_owner
post :delete_school_keys, params: { id: @tournament.id }
redirect
end
test "non logged in user cannot create school keys" do
# no sign_in
post :generate_school_keys, params: { id: @tournament.id }
redirect
end
test "non logged in user cannot delete school keys" do
# no sign_in
post :delete_school_keys, params: { id: @tournament.id }
redirect
end
end

View File

@@ -5,8 +5,9 @@ class WrestlersControllerTest < ActionController::TestCase
setup do
@tournament = Tournament.find(1)
# @tournament.generateMatchups
@tournament.update(is_public: true)
@school = @tournament.schools.first
@school.update(permission_key: SecureRandom.uuid)
@wrestler = @school.wrestlers.first
end
@@ -168,10 +169,139 @@ class WrestlersControllerTest < ActionController::TestCase
redirect
end
test "view wrestler" do
# View wrestler based on tournament.is_public
test "a non logged in user can view wrestler when tournament is_public is true" do
get :show, params: { id: @wrestler.id }
success
end
test "a non logged in user cannot view wrestler when tournament is_public is false" do
@tournament.update(is_public: false)
get :show, params: { id: @wrestler.id }
redirect
end
test "a logged in user non tournament owner cannot view wrestler when tournament is_public is false" do
@tournament.update(is_public: false)
sign_in_non_owner
get :show, params: { id: @wrestler.id }
redirect
end
test "a logged in user tournament owner can view wrestler when tournament is_public is false" do
@tournament.update(is_public: false)
sign_in_owner
get :show, params: { id: @wrestler.id }
success
end
test "a logged in user school delgate can view wrestler when tournament is_public is false" do
@tournament.update(is_public: false)
sign_in_school_delegate
get :show, params: { id: @wrestler.id }
success
end
test "a logged in user tournament delgate can view wrestler when tournament is_public is false" do
@tournament.update(is_public: false)
sign_in_tournament_delegate
get :show, params: { id: @wrestler.id }
success
end
# school permission key tests
test "a non logged in user with VALID school permission key can view wrestler when tournament is_public is false" do
valid_key = @school.permission_key
@tournament.update(is_public: false)
get :show, params: { id: @wrestler.id, school_permission_key: valid_key }
success
end
test "a non logged in user with INVALID school permission key cannot view wrestler when tournament is_public is false" do
@tournament.update(is_public: false)
get :show, params: { id: @wrestler.id, school_permission_key: "INVALID-KEY" }
redirect
end
test "non logged in user with VALID key can get edit wrestler page" do
valid_key = @school.permission_key
get :edit, params: { id: @wrestler.id, school_permission_key: valid_key }
success
end
test "non logged in user with INVALID key cannot get edit wrestler page" do
get :edit, params: { id: @wrestler.id, school_permission_key: "INVALID-KEY" }
redirect
end
test "non logged in user with VALID key can post update wrestler" do
valid_key = @school.permission_key
# The form includes school_permission_key as part of wrestler_params
patch :update, params: { id: @wrestler.id, wrestler: { name: "New Name", school_id: @school.id, school_permission_key: valid_key } }
assert_redirected_to school_path(@school.id, school_permission_key: valid_key)
end
test "non logged in user with INVALID key cannot post update wrestler" do
patch :update, params: { id: @wrestler.id, wrestler: { name: "New Name", school_id: @school.id }, school_permission_key: "INVALID-KEY" }
redirect
end
test "non logged in user with VALID key can create a new wrestler" do
valid_key = @school.permission_key
get :new, params: { school: @school.id, school_permission_key: valid_key }
success
# The form includes school_permission_key as part of wrestler_params
post :create, params: { wrestler: { name: "Test from Key", weight_id: 1, school_id: @school.id, school_permission_key: valid_key }}
assert_redirected_to school_path(@school.id, school_permission_key: valid_key)
end
test "non logged in user with INVALID key cannot create a new wrestler" do
get :new, params: { school: @school.id, school_permission_key: "INVALID-KEY" }
redirect
post :create, params: { wrestler: { name: "Test from Key", weight_id: 1, school_id: @school.id }, school_permission_key: "INVALID-KEY" }
redirect
end
test "non logged in user with VALID key can destroy a wrestler" do
valid_key = @school.permission_key
delete :destroy, params: { id: @wrestler.id, school_permission_key: valid_key }
assert_redirected_to school_path(@school.id, school_permission_key: valid_key)
end
test "non logged in user with INVALID key cannot destroy a wrestler" do
delete :destroy, params: { id: @wrestler.id, school_permission_key: "INVALID-KEY" }
redirect
end
test "non logged in user with VALID key can view a wrestler" do
valid_key = @school.permission_key
get :show, params: { id: @wrestler.id, school_permission_key: valid_key }
success
end
test "non logged in user with INVALID key cannot view a wrestler" do
@tournament.update(is_public: false)
get :show, params: { id: @wrestler.id, school_permission_key: "INVALID-KEY" }
redirect
end
test "show page with valid school_permission_key includes it in 'Back to School' link" do
valid_key = @school.permission_key
get :show, params: { id: @wrestler.id, school_permission_key: valid_key }
success
# The link is typically: /schools/:id?school_permission_key=valid_key
# 'Back to Central Crossing' or similar text
assert_select "a[href=?]", school_path(@school, school_permission_key: valid_key), text: /Back to/
end
test "show page with NO key does not include it in 'Back to School' link" do
get :show, params: { id: @wrestler.id }
success
assert_select "a[href=?]", school_path(@school), text: /Back to/
end
end