Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for match dates #526

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions app/assets/stylesheets/leagues.sass
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,19 @@ table.matches-table
font-size: 0.8rem

&.home-team
width: 45%
width: 25%
text-align: right

&.vs
width: 2%

&.away-team
width: 45%
width: 25%
text-align: left

&.date
width: 20%

&.match-page
width: 4%
font-size: 0.8rem
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module Leagues
module Matches
module ScheduleEditPermissions
extend ActiveSupport::Concern
include ::Leagues::MatchPermissions

def user_can_create_schedule_edit?
return true if user_can_edit_league?
return false unless @league.allow_rescheduling
return false unless @match.status == 'pending'
user_can_home_team? || user_can_away_team?
end

def user_can_decide_schedule_edit?(edit: nil)
edit ||= @edit

return false unless edit.pending?
return true if user_can_edit_league?
return false unless @match.status == 'pending'
edit.home_team? ? user_can_home_team? : user_can_away_team?
end
end
end
end
55 changes: 55 additions & 0 deletions app/controllers/leagues/matches/schedule_edits_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module Leagues
module Matches
class ScheduleEditsController < ApplicationController
include ScheduleEditPermissions

before_action only: :create do
@match = League::Match.find(params[:match_id])
@league = @match.league
end
before_action only: [:approve, :deny] do
@edit = League::Match::ScheduleEdit.find(params[:id])
@match = @edit.match
@league = @match.league
end
before_action :require_can_create, only: :create
before_action :require_can_decide, only: [:approve, :deny]

def create
@edit = ScheduleEdits::CreationService.call(@match, current_user, edit_params)

redirect_to match_path(@match)
end

def approve
ScheduleEdits::ApprovalService.call(@edit, current_user)

redirect_to match_path(@match)
end

def deny
ScheduleEdits::DenialService.call(@edit, current_user)

redirect_to match_path(@match)
end

private

def edit_params
params.require(:schedule_edit).permit(:scheduled_at)
end

def redirect_to_match
redirect_back(fallback_location: match_path(@match))
end

def require_can_create
redirect_to_match unless user_can_create_schedule_edit?
end

def require_can_decide
redirect_to_match unless user_can_decide_schedule_edit?
end
end
end
end
5 changes: 3 additions & 2 deletions app/controllers/leagues/matches_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def show
match_show_includes

@comm = League::Match::Comm.new(match: @match)
@edit = League::Match::ScheduleEdit.new(match: @match)
end

def edit
Expand Down Expand Up @@ -153,14 +154,14 @@ def report_scores_by_team_params

def match_params
params.require(:match).permit(:home_team_id, :away_team_id, :has_winner, :allow_round_draws,
:round_name, :round_number, :notice,
:round_name, :round_number, :notice, :scheduled_at,
pick_bans_attributes: [:id, :_destroy, :kind, :team, :deferrable],
rounds_attributes: [:id, :_destroy, :map_id])
end

def create_round_params
params.require(:match).permit(:division_id, :generate_kind, :has_winner, :allow_round_draws,
:round_name, :round_number, :notice,
:round_name, :round_number, :notice, :scheduled_at,
pick_bans_attributes: [:id, :_destroy, :kind, :team, :deferrable],
rounds_attributes: [:id, :_destroy, :map_id])
end
Expand Down
3 changes: 2 additions & 1 deletion app/controllers/leagues_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ def destroy

LEAGUE_PARAMS = [
:name, :description, :format_id, :category,
:signuppable, :hide_rosters, :roster_locked, :matches_submittable, :transfers_require_approval, :allow_disbanding,
:signuppable, :hide_rosters, :roster_locked, :matches_submittable, :transfers_require_approval,
:allow_disbanding, :allow_rescheduling,
:forfeit_all_matches_when_roster_disbands,
:min_players, :max_players,
:schedule_locked, :schedule,
Expand Down
1 change: 1 addition & 0 deletions app/helpers/leagues/matches_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module Leagues
module MatchesHelper
include MatchPermissions
include Matches::PickBanPermissions
include Matches::ScheduleEditPermissions

def user_on_either_teams?(match = nil)
match ||= @match
Expand Down
1 change: 1 addition & 0 deletions app/models/league.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class League < ApplicationRecord
validates :schedule_locked, inclusion: { in: [true, false] }
validates :forfeit_all_matches_when_roster_disbands, inclusion: { in: [true, false] }
validates :hide_rosters, inclusion: { in: [true, false] }
validates :allow_rescheduling, inclusion: { in: [true, false] }

validates :min_players, presence: true, numericality: { greater_than: 0 }
validates :max_players, presence: true, numericality: { greater_than_or_equal_to: 0 }
Expand Down
8 changes: 8 additions & 0 deletions app/models/league/match.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ class Match < ApplicationRecord

has_many :comms, class_name: 'Match::Comm', dependent: :destroy

has_many :schedule_edits, class_name: 'Match::ScheduleEdit', dependent: :destroy

delegate :division, :league, to: :home_team, allow_nil: true

validates :rounds, associated: true # Make *really* sure all rounds are valid
Expand Down Expand Up @@ -71,6 +73,12 @@ def bye?
!away_team_id
end

def users
users = home_team.users
users.union(away_team.users) unless bye?
users
end

def picking_completed?
pick_bans.pending.empty?
end
Expand Down
55 changes: 55 additions & 0 deletions app/models/league/match/schedule_edit.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
class League
class Match
class ScheduleEdit < ApplicationRecord
belongs_to :match
belongs_to :created_by, class_name: 'User'
belongs_to :decided_by, class_name: 'User', optional: true
enum deciding_team: [:home_team, :away_team]

validate :validate_approved_iff_decided_by

scope :ordered, -> { order(:updated_at) }
scope :pending, -> { where(approved: nil) }

def approve(user)
transaction do
match.update!(scheduled_at: scheduled_at)
update!(decided_by: user, approved: true)
end
end

def deny(user)
update!(decided_by: user, approved: false)
end

def deciding_roster
match.send(team_decide.first)
end

def requesting_roster
match.send(team_decide.last)
end

def pending?
approved.nil?
end

private

def team_decide
if home_team?
[:home_team, :away_team]
else
[:away_team, :home_team]
end
end

def validate_approved_iff_decided_by
errors.add(:decided_by, 'must have decided_by when decided') \
if decided_by.nil? && !approved.nil?
errors.add(:approved, 'must be decided when decided_by is set') \
if approved.nil? && !decided_by.nil?
end
end
end
end
35 changes: 35 additions & 0 deletions app/presenters/league/match/schedule_edit_presenter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class League
class Match
class ScheduleEditPresenter < BasePresenter
presents :edit

# rubocop:disable Rails/OutputSafety
def to_s
if edit.approved.nil?
safe_join([created_by.link, raw(' requested reschedule to <b>'), scheduled_at,
raw('</b>')])
else
safe_join([decided_by.link, ' ', status, raw(' reschedule to <b>'), scheduled_at,
raw('</b> as requested by '), created_by.link])
end
end
# rubocop:enable Rails/OutputSafety

def created_by
@created_by ||= present(edit.created_by)
end

def decided_by
@decided_by ||= present(edit.decided_by)
end

def status
edit.approved? ? 'approved' : 'denied'
end

def scheduled_at
edit.scheduled_at.strftime('%c')
end
end
end
end
4 changes: 4 additions & 0 deletions app/presenters/league/match_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ def bracket_data
result
end

def scheduled_at
match.scheduled_at.strftime('%c')
end

private

def score_results
Expand Down
2 changes: 1 addition & 1 deletion app/serializers/api/v1/leagues/match_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class MatchSerializer < ActiveModel::Serializer
type :match

attributes :id, :forfeit_by, :status, :round_name, :round_number, :notice
attributes :created_at
attributes :created_at, :scheduled_at

belongs_to :league
has_one :home_team, serializer: RosterSerializer
Expand Down
16 changes: 11 additions & 5 deletions app/services/leagues/matches/creation_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,17 @@ def users_to_notify(match)
end

def notify_message(match)
if match.bye?
"You have a match BYE for #{match.home_team.name}."
else
"You have an upcoming match: #{match.home_team.name} vs #{match.away_team.name}."
end
msg = if match.bye?
"You have a match BYE for #{match.home_team.name}"
else
"You have an upcoming match: #{match.home_team.name} vs #{match.away_team.name}"
end

msg << if match.scheduled_at
" scheduled for #{match.scheduled_at.strftime('%c')}."
else
'.'
end
end
end
end
Expand Down
24 changes: 24 additions & 0 deletions app/services/leagues/matches/schedule_edits/approval_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module Leagues
module Matches
module ScheduleEdits
module ApprovalService
include BaseService
extend ScheduleEditServicer

def call(edit, user)
edit.transaction do
# Deny other proposed match dates
edit.match.schedule_edits
.pending
.where.not(id: edit.id)
.each { |e| e.deny(user) }
edit.approve(user)

notify(edit.match.users, reschedule_msg(user, 'approved', edit),
match_path(edit.match))
end
end
end
end
end
end
35 changes: 35 additions & 0 deletions app/services/leagues/matches/schedule_edits/creation_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module Leagues
module Matches
module ScheduleEdits
module CreationService
include BaseService
extend ScheduleEditServicer

# rubocop:disable Metrics/MethodLength
def call(match, user, params)
team = if match.bye? || user.can?(:edit, match.away_team.team)
:home_team
else
:away_team
end

edit_params = params.merge(created_by: user, deciding_team: team)
edit = match.schedule_edits.new(edit_params)
edit.transaction do
# Cancel any existing proposed match dates
match.schedule_edits
.pending
.where(created_by: user)
.where.not(id: edit.id)
.each { |e| e.deny(user) }
edit.save!
notify_captains(edit, edit.deciding_roster, reschedule_msg(user, 'requested', edit))
end

edit
end
# rubocop:enable Metrics/MethodLength
end
end
end
end
17 changes: 17 additions & 0 deletions app/services/leagues/matches/schedule_edits/denial_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Leagues
module Matches
module ScheduleEdits
module DenialService
include BaseService
extend ScheduleEditServicer

def call(edit, user)
edit.transaction do
edit.deny(user)
notify_captains(edit, edit.requesting_roster, reschedule_msg(user, 'denied', edit))
end
end
end
end
end
end
Loading