# Type: Input and output (event based) # Category: Task # Description: Handles unfinished tasks # Events: status # Fields: action, time, endtime # Uses: YesNo # Timeout: 30 min # Copied: Yes # Author: Andriy Lesyuk use Orangutan::Task; sub UnfinishedTask_Submit($$;$) { my ($user, $task, $events) = @_; my $message = undef; if (!defined($task->GetActivity('id'))) { my $default_activity = $main::query->GetDefaultActivity($task->GetProject('id')); if (defined($default_activity)) { $task->SetActivity( id => $default_activity->{'id'}, name => $default_activity->{'name'} ); my $format = Orangutan::Context::Random( 'Using activity %s because none was specified...', 'Note that I used activity "%s"...' ); $message = sprintf($format, $default_activity->{'name'}); } } if ($task->GetStart->WorkDayStart->Date != $task->GetEnd->WorkDayStart->Date) { my $copy = new Orangutan::Task($task); $task->SetEnd($task->GetStart->WorkDayEnd); $user->SubmitTask; $user->SetTask($copy); $copy->SetStart($copy->GetEnd->WorkDayStart); $user->SubmitTask; if (defined($events)) { push(@{$events}, $task, $copy); } } else { $user->SubmitTask; if (defined($events)) { push(@{$events}, $task); } } return $message; } new Orangutan::Context( request => sub { my ($context, $user) = @_; my $task = $user->GetTask; if (defined($task) && defined($task->GetActivity('id'))) { my $yesno = $user->GetResponse('YesNo'); if ($yesno) { my $time = new Orangutan::Date; my $date = $context->GetField('time'); my $status = $context->GetField('status'); my $action = $context->GetField('action'); if ($action eq 'stop') { my $message = Orangutan::Context::Random( 'Seems you forgot to tell me that you had finished your task. ', 'Your previous task have not been finished. ' ); if (defined($date)) { my $format; if (defined($status)) { if ($status eq 'away') { $format = Orangutan::Context::Random( 'You went away at %02d:%02d', 'You left at %02d:%02d' ); } else { $format = 'I saw you online last time at %02d:%02d'; } } else { $format = Orangutan::Context::Random( 'You disconnected at %02d:%02d', 'You logged out at %02d:%02d', 'You left at %02d:%02d' ); } $message .= sprintf($format, $date->GetTime); my $days = int(($time->DayStart->Date - $date->DayStart->Date) / 86400); if ($days == 1) { $message .= ' yesterday'; } elsif ($days > 1) { $message .= sprintf(' %d days ago', $days); } $message .= '. '; $message .= Orangutan::Context::Random( 'Should I stop this task using that time?', 'I will stop this task using that time?' ); } else { $context->SetField('time', $time); $message .= Orangutan::Context::Random( 'Should I stop this task using current time as end time?', 'I will stop this task using current time as end time?' ); } $yesno->InsertForeignHandler($context, 1800); return $message; } elsif ($action eq 'break') { my $format; if (defined($status) && ($status eq 'away')) { $format = Orangutan::Context::Random( 'You went away at %02d:%02d ', 'You left at %02d:%02d ' ); } else { $format = Orangutan::Context::Random( 'You had been disconnected at %02d:%02d ', 'You disconnected at %02d:%02d ' ); } my $message = sprintf($format, $date->GetTime); $message .= 'that is '; my $diff = $time->Date - $date->Date; if ($diff >= 86400) { if ($diff >= (2 * 86400)) { $message .= sprintf('%d days ', int($diff / 86400)); } else { $message .= sprintf('%d day ', int($diff / 86400)); } } if (($diff % 86400) >= 3600) { if (($diff % 86400) >= (2 * 3600)) { $message .= sprintf('%d hours ', int(($diff % 86400) / 3600)); } else { $message .= sprintf('%d hour ', int(($diff % 86400) / 3600)); } } $message .= sprintf('%d minutes ago. ', int(($diff % 3600) / 60)); $message .= Orangutan::Context::Random( 'Should I stop the task on that time and reopen it?', 'Should I break the task?', 'Should I record a break?' ); $yesno->InsertForeignHandler($context, 1800); return $message; } } else { $user->SendMessage('Wanted to ask you something but forgot what exactly...'); return undef; } } else { return undef; } }, response => [ '^Stop(?: it)? and reopen(?: it)?!*\.*$', '^Break(?: it)?(?: (?:at|in|on|using) ([0-9]{1,2}(?:[:-][0-9]{2})? *(?:(?:a\.?|p\.?)m\.?)?))?!*\.*$', '^(?:Just )?(?:stop|close)(?: it)?!*\.*$' ], handler => sub { my ($context, $user, $item, $answer) = @_; $context->UnsetField('stop'); $context->UnsetField('break'); my $task = $user->GetTask; if (defined($task)) { my $date = $context->GetField('time'); if (($item > 0) && defined($answer)) { my $newdate = new Orangutan::Date($answer, $task->GetStart->Date); if ($newdate) { if ($newdate->Date == $task->GetStart->Date) { $user->SendMessage([ 'This is the same time when the task started! Ignoring it!..', 'Zero task time?.. Funny! Ignoring time specified...' ]); } else { $date = $newdate; } } else { $user->SendMessage([ "Can't use this time... Ignoring it...", 'The time you specified is invalid...' ]); } } my $action = $context->GetField('action'); if (($item >= 3) || (($item < 0) && ($action eq 'stop'))) { if (($item > 0) || ($answer eq 'Y')) { if ($main::query->GetEntries($user, $task->GetStart, $date) == 0) { $task->SetEnd($date); my $message = UnfinishedTask_Submit($user, $task); $user->FireEvent('task', 'end', $task); $main::config->Context('Ok')->Tell($user); if (defined($message)) { $user->SendMessage($message); } } else { $user->SendMessage([ 'Wow! This task conflicts with another task in Redmine!..', "Oops! I can't! There are conflicts..." ]); } } else { $main::config->Context('Ok')->Tell($user); my $now = new Orangutan::Date; if (defined($date) && (($now->DayStart->Date - $date->DayStart->Date) > 0)) { $user->SendMessage([ 'Please stop it manually then.', 'Be sure to stop this task.', "Don't forget to stop it." ]); } } } elsif (($item >= 1) || (($item < 0) && ($action eq 'break'))) { my $message = undef; if (($item > 0) || ($answer eq 'Y')) { if ($main::query->GetEntries($user, $task->GetStart, $date) == 0) { my $copy = new Orangutan::Task($task); $task->SetEnd($date); $message = UnfinishedTask_Submit($user, $task); $user->SetTask($copy); $copy->SetStart($context->GetField('endtime')); $user->FireEvent('task', 'break', $task, $copy); } else { $user->SendMessage([ 'Oh, no! The task conflicts with another task in Redmine... :(', "Can't break it - it conflicts with another task in Redmine!" ]); } } $main::config->Context('Ok')->Tell($user); if (defined($message)) { $user->SendMessage($message); } } else { $user->SendMessage('Geeze... My creator is an idiot!'); } } my $yesno = $user->GetResponse('YesNo'); if ($yesno) { $yesno->RemoveForeignHandler($context); } return undef; }, ontimeout => sub { my ($context, $user) = @_; $context->UnsetField('stop'); $context->UnsetField('break'); my $task = $user->GetTask; if (defined($task)) { my $time = new Orangutan::Date; my $date = $context->GetField('time'); my $action = $context->GetField('action'); my $lastmessage = $user->GetLastMessageTime; if (($action eq 'stop') || !$user->IsWorkTime($time) || # if default action is stop or it is not work time or... ($task->GetStart->Elapsed > 28800) || # if the task lasts for more than 8 hours (($context->GetField('aways') > 1) && # if there were status changes and defined($lastmessage) && (($time->Date - $lastmessage) >= 1800))) { # last message was more than 30 min ago if ($main::query->GetEntries($user, $task->GetStart, $date) == 0) { my @events = ( ); $task->SetEnd($date); my $message = UnfinishedTask_Submit($user, $task, \@events); $context->SetField('stop', \@events); $user->FireEvent('task', 'end', $task); if ($action ne 'stop') { $user->SendMessage([ 'Seems you are not really there... So stopping the task...', 'Well... I believe I should stop the task... Doing this...' ]); } else { $user->SendMessage([ 'Well... I do stop the task...', 'Ok... Stopping the task' ]); } if (defined($message)) { $user->SendMessage($message); } } } else { if ($main::query->GetEntries($user, $task->GetStart, $date) == 0) { my @events = ( ); my $copy = new Orangutan::Task($task); $task->SetEnd($date); my $message = UnfinishedTask_Submit($user, $task, \@events); $user->SetTask($copy); $copy->SetStart($context->GetField('endtime')); $context->SetField('break', \@events); $user->FireEvent('task', 'break', $task, $copy); $user->SendMessage([ 'Ok... Stopping the task and opening it again.', 'Ok... Breaking the task' ]); if (defined($message)) { $user->SendMessage($message); } } } } my $yesno = $user->GetResponse('YesNo'); if ($yesno) { $yesno->RemoveForeignHandler($context); } return undef; }, onstatus => sub { my ($context, $user, $type, $status) = @_; my $task = $user->GetTask; if (defined($task)) { my $previous = $user->GetStatus; if (defined($previous) && ($previous eq 'shutdown')) { $previous = undef; } if (!defined($previous) || (defined($status) && ($previous eq 'away') && ($status eq 'online'))) { my $time = new Orangutan::Date; my $entry = defined($previous) ? $user->GetHistoryEntry : $user->GetHistoryEntry('away'); if ((defined($entry) && ($entry->{'date'}->Date > $task->GetStart->Date) && (($entry->{'date'}->Date - $task->GetStart->Date) < 86400)) || (!defined($entry) && ($time->Date > $task->GetStart->Date) && (($time->Date - $task->GetStart->Date) < 86400))) { # check limit my $minutes = ($user->GetOption('BreakTime') || 5) * 60; if (!defined($entry) || # no previous date or was offline more than an hour or away more than 4 hours (!defined($previous) && (($time->Date - $entry->{'date'}->Date) > 3600))) { my $unfinished = $user->GetResponse($context->GetID); if ($unfinished) { $unfinished->SetField('aways', $unfinished->GetField('aways') + 1); } else { $unfinished = $user->AddRequestResponse($context); $unfinished->SetField('action', 'stop'); if (defined($entry)) { $unfinished->SetField('time', $entry->{'date'}); $unfinished->SetField('status', $entry->{'status'}); } else { $unfinished->UnsetField('time'); $unfinished->UnsetField('status'); } $unfinished->SetField('aways', 0); } $unfinished->SetField('endtime', $time); } elsif (($time->Date - $entry->{'date'}->Date) > $minutes) { my $unfinished = $user->GetResponse($context->GetID); if ($unfinished) { $unfinished->SetField('aways', $unfinished->GetField('aways') + 1); } else { $unfinished = $user->AddRequestResponse($context); $unfinished->SetField('action', 'break'); $unfinished->SetField('time', $entry->{'date'}); $unfinished->SetField('status', $entry->{'status'}); $unfinished->SetField('aways', 0); } $unfinished->SetField('endtime', $time); } } } } }, ontask => sub { my ($context, $user, $type, $status) = @_; if (($status ne 'add') && ($status ne 'change') && ($status ne 'remove') && ($status ne 'break')) { if ($user->GetResponse($context->GetID)) { $user->RemoveRequestResponse($context); } } }, undo => sub { my ($context, $user) = @_; my $tasks; if (defined($tasks = $context->GetField('stop'))) { foreach my $task (@{$tasks}) { $user->RemovePreviousTask($task->GetID); $user->FireEvent('task', 'remove', $task); } my $currtask = $tasks->[0]; $currtask->SetID; $currtask->UnsetEnd; $currtask->Unset(TASK_SUBMITTED); $user->SetTask($currtask); $user->FireEvent('task', 'start', $currtask); my $message = Orangutan::Context::Random('Oh...', 'Oops.', ':('); $message .= ' Sorry... '; $message .= Orangutan::Context::Random( 'I thought you are not there...', 'Your task is opened again...', 'Recovered it back.' ); $user->SendMessage($message); } elsif (defined($tasks = $context->GetField('break'))) { foreach my $task (@{$tasks}) { $user->RemovePreviousTask($task->GetID); $user->FireEvent('task', 'remove', $task); } my $task = $user->GetTask; $user->RemoveTask; $user->FireEvent('task', 'cancel', $task); my $currtask = $tasks->[0]; $currtask->SetID; $currtask->UnsetEnd; $currtask->Unset(TASK_SUBMITTED); $user->SetTask($currtask); $user->FireEvent('task', 'start', $currtask); my $message = Orangutan::Context::Random('Oh...', 'Oops.', 'Ouch!'); $message .= ' Sorry... '; $message .= Orangutan::Context::Random( 'I thought you were away... :S', 'The break has been removed.', 'Removed the break...' ); $user->SendMessage($message); } else { $user->SendMessage([ 'Something wrong happened - cannot fix it!', "Hm... I'm not able to fix things...", "Sorry. Can't undo... :(" ]); } }, timeout => 1800, weight => undef ); # kate: syntax perl