# Description: Receives events from Redmine # Author: Andriy Lesyuk new Orangutan::Monkey( monkey => 'redmonkey', message => '^([+=\-])(issue|journal|entry|watcher):([0-9]+)(?:/[a-z]*)?$', handler => sub { my ($monkey, $item, $op, $type, $id, $retries) = @_; my $postpone = 0; if ($type eq 'issue') { my $issue = $main::query->GetIssue($id); if (defined($issue)) { utf8::decode($issue->{'subject'}); utf8::decode($issue->{'project_name'}); my %watchers = ( ); $watchers{$issue->{'author_name'}}++; if ($issue->{'assigned_to_name'}) { $watchers{$issue->{'assigned_to_name'}}++; } if ($main::query->GetWatchers($id, { id => $issue->{'project_id'} })) { while (defined(my $watcher = $main::query->Next)) { $watchers{$watcher->{'login'}}++; } } if (($op eq '+') && ((time - $issue->{'created_on'}) > 3600)) { $main::logger->Log("received late notification for issue #%d", $id); } foreach my $username (keys %watchers) { my $user = $main::users->GetUserLogin($username); if (defined($user)) { if ($op eq '+') { $user->FireEvent('issue', 'add', $issue); } elsif ($op eq '-') { $user->FireEvent('issue', 'remove', $issue); } } } } else { if ($op eq '-') { $main::logger->Log("issue #%d has been already removed", $id); } else { $postpone = 1; } } } elsif ($type eq 'journal') { my $journal = $main::query->GetJournal($id); if (defined($journal)) { utf8::decode($journal->{'notes'}); my $issue = $main::query->GetIssue($journal->{'issue_id'}); if (defined($issue)) { utf8::decode($issue->{'subject'}); utf8::decode($issue->{'project_name'}); my %watchers = ( ); $watchers{$issue->{'author_name'}}++; if ($issue->{'assigned_to_name'}) { $watchers{$issue->{'assigned_to_name'}}++; } if ($main::query->GetWatchers($journal->{'issue_id'})) { while (defined(my $watcher = $main::query->Next)) { $watchers{$watcher->{'login'}}++; } } my @details = ( ); if (($journal->{'count'} > 0) && $main::query->GetJournalDetails($id)) { while (defined(my $details = $main::query->Next)) { utf8::decode($details->{'old_value'}); utf8::decode($details->{'value'}); utf8::decode($details->{'value_name'}); push(@details, $details); } } my $operation; if ($op eq '+') { $operation = 'add'; } elsif ($op eq '=') { $operation = 'change'; } elsif ($op eq '-') { $operation = 'remove'; } if ($operation eq 'add') { $journal->{'status'} = 'add'; } elsif (($operation eq 'change') && $journal->{'notes'}) { $journal->{'status'} = 'change'; $journal->{'updated_on'} = $issue->{'updated_on'}; } else { $journal->{'status'} = 'remove'; if ($operation eq 'change') { $journal->{'removed_on'} = $issue->{'updated_on'}; } else { $journal->{'removed_on'} = time; } } if (($op eq '+') && ((time - $journal->{'created_on'}) > 3600)) { $main::logger->Log("received late notification for journal %d", $id); } foreach my $username (keys %watchers) { my $user = $main::users->GetUserLogin($username); if (defined($user)) { $user->FireEvent('issue', 'change', $operation, $issue, $journal, @details); } } } } else { if ($op eq '-') { $main::logger->Log("journal %d has been already removed", $id); } else { $postpone = 1; } } } elsif ($type eq 'entry') { my $event = $main::query->GetEntry($id); if ($event) { my $user = $main::users->GetUserID($event->{'user_id'}); if (defined($user)) { my $start_time = undef; my $end_time = undef; if (defined($event->{'start_time'})) { $start_time = new Orangutan::Date($event->{'start_time'}); } if (defined($event->{'end_time'})) { $end_time = new Orangutan::Date($event->{'end_time'}); } my $task = new Orangutan::Task( id => $event->{'id'}, start => $start_time, name => $event->{'comments'}, issue => $event->{'issue_id'}, project => { id => $event->{'project_id'}, name => $event->{'project'} }, activity => { id => $event->{'activity_id'}, name => $event->{'activity'} }, end => $end_time, duration => $event->{'hours'}, date => new Orangutan::Date($event->{'spent_on'}) ); $task->Set(TASK_SUBMITTED); if (($op eq '+') && ((time - $event->{'created_on'}) > 3600)) { $main::logger->Log("received late notification for time entry %d", $id); } if ($op eq '+') { $user->FireEvent('task', 'add', $task); } elsif ($op eq '=') { $user->FireEvent('task', 'change', $task); } elsif ($op eq '-') { $user->FireEvent('task', 'remove', $task); } } } else { if ($op eq '-') { $main::logger->Log("time entry %d has been already removed", $id); } else { $postpone = 1; } } } elsif ($type eq 'watcher') { my $watcher = $main::query->GetWatcher($id); if (defined($watcher)) { my $user = $main::users->GetUserID($watcher->{'user_id'}); if (defined($user) && (($watcher->{'watchable_type'} eq 'Project') || ($watcher->{'watchable_type'} eq 'Issue'))) { my $watched = undef; if ($watcher->{'watchable_type'} eq 'Project') { $watched = $main::query->GetProject($watcher->{'watchable_id'}); if (defined($watched)) { utf8::decode($watched->{'name'}); } } elsif ($watcher->{'watchable_type'} eq 'Issue') { $watched = $main::query->GetIssue($watcher->{'watchable_id'}); if (defined($watched)) { utf8::decode($watched->{'subject'}); } } if (defined($watched)) { if ($op eq '+') { $user->FireEvent('watcher', 'add', $watcher, $watched); } elsif ($op eq '-') { $user->FireEvent('watcher', 'remove', $watcher, $watched); } } else { $main::logger->Log("watching non-existent %s #%d", lc($watcher->{'watchable_type'}), $watcher->{'watchable_id'}); } } } else { if ($op eq '-') { $main::logger->Log("watcher entry %d has been already removed", $id); } else { $postpone = 1; } } } if ($postpone) { if (!defined($retries) || ($retries < 5)) { my $delay = defined($retries) ? $retries * 5 : 1; my $queries = $monkey->GetField('queries'); if (defined($queries)) { my $i = 0; while ($i < scalar @{$queries}) { if ((time + $delay) >= $queries->[$i][5]) { last; } $i++; } splice(@{$queries}, $i, 0, [ $item, $op, $type, $id, $retries, time + $delay ]); } else { $queries = [ [ $item, $op, $type, $id, $retries, time + $delay ] ]; $monkey->SetField('queries', $queries); } my $schedule = $main::users->GetSchedule($monkey, 'retry'); if (defined($schedule)) { if ($schedule->[2] > $queries->[0][5]) { $main::users->CancelSchedule($monkey, 'retry'); $main::users->Schedule($queries->[0][5], $monkey, 'retry'); } } else { $main::users->Schedule($queries->[0][5], $monkey, 'retry'); } } else { if ($type eq 'issue') { $main::logger->Log("failed to fetch issue #%d (%d retries)", $id, $retries); } elsif ($type eq 'journal') { $main::logger->Log("failed to fetch journal %d (%d retries)", $id, $retries); } elsif ($type eq 'entry') { $main::logger->Log("failed to fetch time entry %d (%d retries)", $id, $retries); } elsif ($type eq 'watcher') { $main::logger->Log("failed to fetch watcher entry %d (%d retries)", $id, $retries); } } } }, schedule => sub { my ($monkey, $scheduler, $arg) = @_; my $queries = $monkey->GetField('queries'); if (defined($queries)) { while (scalar @{$queries} > 0) { if ($queries->[0][5] <= time) { my $query = shift(@{$queries}); if (!defined($query->[4])) { $query->[4] = 1; } else { $query->[4]++; } $monkey->CallHandler(@{$query}); } else { last; } } if (scalar @{$queries} > 0) { $main::users->Schedule($queries->[0][5], $monkey, 'retry'); } else { $monkey->UnsetField('queries'); } } } ); # kate: syntax perl