diff --git a/lib/Synergy/Reactor/Rototron.pm b/lib/Synergy/Reactor/Rototron.pm index fc03767b..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; } @@ -161,6 +163,39 @@ sub handle_manual_assignment ($self, $event) { $assign_to = $target->username; } + my (@okay, @errors); + + for my $date (@dates) { + if ($force) { + # Remove any 'unavailable on' overrides + $self->availability_checker->set_user_available_on( + $assign_to, + $date, + ); + } else { + 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)); + $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({ $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) {