From 3c1b9a8754af733b5fdafec09bdc8e3113619249 Mon Sep 17 00:00:00 2001 From: Matthew Horsfall Date: Fri, 21 Aug 2020 20:53:41 -0400 Subject: [PATCH 1/2] Rototron: Reconfigure how unavailable and manual overrides react Previously, if you marked yourself unavailable on a day, but someone else marked you manually configured for that day, you'd be assigned that day. That doesn't seem quite right. Now, instead, explicit unavailable wins --- lib/Synergy/Reactor/Rototron.pm | 23 +++++++++++++ lib/Synergy/Rototron.pm | 60 ++++++++++++++++++++++++++------- 2 files changed, 71 insertions(+), 12 deletions(-) diff --git a/lib/Synergy/Reactor/Rototron.pm b/lib/Synergy/Reactor/Rototron.pm index fc03767b..79a0d8b6 100644 --- a/lib/Synergy/Reactor/Rototron.pm +++ b/lib/Synergy/Reactor/Rototron.pm @@ -161,6 +161,29 @@ sub handle_manual_assignment ($self, $event) { $assign_to = $target->username; } + my (@okay, @errors); + + for my $date (@dates) { + my $debug = []; + if ($self->availability_checker->user_is_available_on($assign_to, $date, $debug)) { + push @okay, $date; + } else { + push @errors, @$debug; + } + } + + @dates = @okay; + + unless (@dates) { + $event->reply("$username was not available for any of those dates:\n" . join("\n", @errors)); + + return; + } + + if (@errors) { + $event->reply("$username was not available for these dates:\n" . join("\n", @errors)); + } + $self->availability_checker->update_manual_assignments({ $rotor_name => { map {; $_->ymd => $assign_to } @dates }, }); diff --git a/lib/Synergy/Rototron.pm b/lib/Synergy/Rototron.pm index 385a6ee2..bc1c8ca8 100644 --- a/lib/Synergy/Rototron.pm +++ b/lib/Synergy/Rototron.pm @@ -457,14 +457,24 @@ package Synergy::Rototron::Rotor { if (my $username = $self->manual_assignment_for($rotor, $day)) { my ($user) = grep {; $_->{username} eq $username } $self->_full_staff->@*; - return $user if $user; - - $Logger->log([ - "no user named %s, but that name is assigned for %s on %s", - $username, - $rotor->name, - $day->ymd, - ]); + + if ($user && $self->user_is_blocked_on($user->{username}, $day)) { + $Logger->log([ + "user %s manually assigned but they are marked unavailable for %s on %s, skipping", + $user->{username}, + $rotor->name, + $day->ymd, + ]); + } elsif ($user) { + return $user; + } else { + $Logger->log([ + "no user named %s, but that name is assigned for %s on %s", + $username, + $rotor->name, + $day->ymd, + ]); + } } my $weekn = _week_of_date($day); @@ -665,16 +675,42 @@ package Synergy::Rototron::AvailabilityChecker { return; } - sub user_is_available_on ($self, $username, $dt) { + sub user_is_available_on ($self, $username, $dt, $debug = []) { my $ymd = $dt->ymd; + unless ($self->user_typically_works_on($username, $dt)) { + push @$debug, "$username does not work on " . $dt->ymd; + return 0; + } + + if ($self->user_has_leave_on($username, $dt)) { + push @$debug, "$username has leave scheduled on " . $dt->ymd; + return 0; + } + + if ($self->user_is_blocked_on($username, $dt)) { + push @$debug, "$username is marked unavailable on " . $dt->ymd; + return 0; + } + + return 1; + } + + sub user_typically_works_on ($self, $username, $dt) { if (my $user = $self->user_directory->user_named($username)) { - return 0 unless $user->hours_for_dow($dt->day_of_week); + return 1 if $user->hours_for_dow($dt->day_of_week); } + return 0; + } + + sub user_has_leave_on ($self, $username, $dt) { my $leave = $self->_leave_days; - return 0 if $leave->{$username}{$dt->ymd}; + return 1 if $leave->{$username}{$dt->ymd}; + } + + sub user_is_blocked_on ($self, $username, $dt) { my ($count) = $self->_dbh->selectrow_array( q{SELECT COUNT(*) FROM blocked_days WHERE username = ? AND date = ?}, undef, @@ -682,7 +718,7 @@ package Synergy::Rototron::AvailabilityChecker { $dt->ymd, ); - return $count == 0; + return $count ? 1 : 0; } sub set_user_unavailable_on ($self, $username, $dt, $reason = undef) { From 49b2553e73ee53cd31da1c2209b4c1f793ef4a80 Mon Sep 17 00:00:00 2001 From: Matthew Horsfall Date: Fri, 21 Aug 2020 21:13:51 -0400 Subject: [PATCH 2/2] 'assign rotor': Allow /force to override unavailability --- lib/Synergy/Reactor/Rototron.pm | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/Synergy/Reactor/Rototron.pm b/lib/Synergy/Reactor/Rototron.pm index 79a0d8b6..e0dd356e 100644 --- a/lib/Synergy/Reactor/Rototron.pm +++ b/lib/Synergy/Reactor/Rototron.pm @@ -116,19 +116,21 @@ after register_with_hub => sub ($self, @) { }; sub handle_manual_assignment ($self, $event) { - my ($username, $rotor_name, $from, $to); + my ($username, $rotor_name, $from, $to, $force); my $ymd_re = qr{ [0-9]{4} - [0-9]{2} - [0-9]{2} }x; - if ($event->text =~ /^assign rotor (\S+) to (\S+) on ($ymd_re)\z/) { + if ($event->text =~ /^assign rotor (\S+) to (\S+) on ($ymd_re) (\/f(?:orce))?\z/) { $rotor_name = $1; $username = $2; $from = parse_date_for_user($3, $event->from_user); $to = parse_date_for_user($3, $event->from_user); - } elsif ($event->text =~ /^assign rotor (\S+) to (\S+) from ($ymd_re) to ($ymd_re)\z/) { + $force = $4; + } elsif ($event->text =~ /^assign rotor (\S+) to (\S+) from ($ymd_re) to ($ymd_re) (\/f(?:orce))?\z/) { $rotor_name = $1; $username = $2; $from = parse_date_for_user($3, $event->from_user); $to = parse_date_for_user($4, $event->from_user); + $force = $5; } else { return; } @@ -164,11 +166,19 @@ sub handle_manual_assignment ($self, $event) { my (@okay, @errors); for my $date (@dates) { - my $debug = []; - if ($self->availability_checker->user_is_available_on($assign_to, $date, $debug)) { - push @okay, $date; + if ($force) { + # Remove any 'unavailable on' overrides + $self->availability_checker->set_user_available_on( + $assign_to, + $date, + ); } else { - push @errors, @$debug; + my $debug = []; + if ($self->availability_checker->user_is_available_on($assign_to, $date, $debug)) { + push @okay, $date; + } else { + push @errors, @$debug; + } } } @@ -176,12 +186,14 @@ sub handle_manual_assignment ($self, $event) { unless (@dates) { $event->reply("$username was not available for any of those dates:\n" . join("\n", @errors)); + $event->reply("retry with /force at the end to override"); return; } if (@errors) { $event->reply("$username was not available for these dates:\n" . join("\n", @errors)); + $event->reply("retry with /force at the end to override"); } $self->availability_checker->update_manual_assignments({