-# helper functions
-sub verbose { print loc(@_), "\n" if $opts{debug} || $opts{verbose}; 1 }
-sub debug { print loc(@_), "\n" if $opts{debug}; 1 }
-sub error { $RT::Logger->error(loc(@_)); verbose(@_); 1 }
-sub warning { $RT::Logger->warning(loc(@_)); verbose(@_); 1 }
-
-my $now = $opts{epoch} || time;
-verbose "Using time [_1]", scalar localtime($now);
-
-my $from = get_from();
-debug "Sending email from [_1]", $from;
-
-# look through each user for her subscriptions
-my $Users = RT::Users->new($RT::SystemUser);
-$Users->LimitToPrivileged;
-
-while (defined(my $user = $Users->Next)) {
- if ($user->PrincipalObj->Disabled) {
- debug "Skipping over "
- . $user->Name
- . " due to having a disabled account.";
- next;
- }
-
- my ($hour, $dow, $dom) = hour_dow_dom_in($user->Timezone || RT->Config->Get('Timezone'));
- $hour .= ':00';
- debug "Checking [_1]'s subscriptions: hour [_2], dow [_3], dom [_4]",
- $user->Name, $hour, $dow, $dom;
-
- my $currentuser = RT::CurrentUser->new;
- $currentuser->LoadByName($user->Name);
-
- # look through this user's subscriptions, are any supposed to be generated
- # right now?
- for my $subscription ($user->Attributes->Named('Subscription')) {
- my $counter = $subscription->SubValue('Counter') || 0;
-
- if (!$opts{all}) {
- debug "Checking against subscription with frequency [_1], hour [_2], dow [_3], dom [_4]",
- $subscription->SubValue('Frequency'), $subscription->SubValue('Hour'),
- $subscription->SubValue('Dow'), $subscription->SubValue('Dom');
-
- next if $subscription->SubValue('Frequency') eq 'never';
-
- # correct hour?
- next if $subscription->SubValue('Hour') ne $hour;
-
- # if weekly, correct day of week?
- if ( $subscription->SubValue('Frequency') eq 'weekly' ) {
- next if $subscription->SubValue('Dow') ne $dow;
- my $fow = $subscription->SubValue('Fow') || 1;
- if ( $counter % $fow ) {
- $subscription->SetSubValues( Counter => $counter + 1 )
- unless $opts{'dryrun'};
- next;
- }
- }
-
- # if monthly, correct day of month?
- elsif ($subscription->SubValue('Frequency') eq 'monthly') {
- next if $subscription->SubValue('Dom') != $dom;
- }
-
- elsif ($subscription->SubValue('Frequency') eq 'm-f') {
- next if $dow eq 'Sunday' || $dow eq 'Saturday';
- }
- }
-
- my $email = $subscription->SubValue('Recipient')
- || $user->EmailAddress;
-
- eval { send_dashboard($currentuser, $email, $subscription) };
- if ( $@ ) {
- error 'Caught exception: ' . $@;
- }
- else {
- $subscription->SetSubValues(
- Counter => $counter + 1 )
- unless $opts{'dryrun'};
- }
- }
-}
-
-sub send_dashboard {
- my ($currentuser, $email, $subscription) = @_;
-
- my $rows = $subscription->SubValue('Rows');
-
- my $dashboard = RT::Dashboard->new($currentuser);
-
- my ($ok, $msg) = $dashboard->LoadById($subscription->SubValue('DashboardId'));
-
- # failed to load dashboard. perhaps it was deleted or it changed privacy
- if (!$ok) {
- warning "Unable to load dashboard [_1] of subscription [_2] for user [_3]: [_4]",
- $subscription->SubValue('DashboardId'),
- $subscription->Id,
- $currentuser->Name,
- $msg;
-
- my $ok = RT::Interface::Email::SendEmailUsingTemplate(
- From => $from,
- To => $email,
- Template => 'Error: Missing dashboard',
- Arguments => {
- SubscriptionObj => $subscription,
- },
- );
-
- # only delete the subscription if the email looks like it went through
- if ($ok) {
- my ($deleted, $msg) = $subscription->Delete();
- if ($deleted) {
- verbose("Deleted an obsolete subscription: [_1]", $msg);
- }
- else {
- warning("Unable to delete an obsolete subscription: [_1]", $msg);
- }
- }
- else {
- warning("Unable to notify [_1] of an obsolete subscription", $currentuser->Name);
- }
-
- return;
- }
-
- verbose 'Creating dashboard "[_1]" for user "[_2]":',
- $dashboard->Name,
- $currentuser->Name;
-
- if ($opts{'dryrun'}) {
- print << "SUMMARY";
- Dashboard: @{[ $dashboard->Name ]}
- User: @{[ $currentuser->Name ]} <$email>
-SUMMARY
- return;
- }
-
- $HTML::Mason::Commands::session{CurrentUser} = $currentuser;
- my $contents = run_component(
- '/Dashboards/Render.html',
- id => $dashboard->Id,
- Preview => 0,
- );
-
- for (@{ RT->Config->Get('EmailDashboardRemove') || [] }) {
- $contents =~ s/$_//g;
- }
-
- debug "Got [_1] characters of output.", length $contents;
-
- $contents = HTML::RewriteAttributes::Links->rewrite(
- $contents,
- RT->Config->Get('WebURL') . '/Dashboards/Render.html',
- );
-
- email_dashboard($currentuser, $email, $dashboard, $subscription, $contents);
-}
-
-sub email_dashboard {
- my ($currentuser, $email, $dashboard, $subscription, $content) = @_;
-
- verbose 'Sending dashboard "[_1]" to user [_2] <[_3]>',
- $dashboard->Name,
- $currentuser->Name,
- $email;
-
- my $subject = sprintf '[%s] ' . RT->Config->Get('DashboardSubject'),
- RT->Config->Get('rtname'),
- ucfirst($subscription->SubValue('Frequency')),
- $dashboard->Name;
-
- my $entity = build_email($content, $from, $email, $subject);
-
- my $ok = RT::Interface::Email::SendEmail(
- Entity => $entity,
- );
-
- debug "Done sending dashboard to [_1] <[_2]>",
- $currentuser->Name, $email
- and return if $ok;
-
- error 'Failed to email dashboard to user [_1] <[_2]>',
- $currentuser->Name, $email;
-}
-
-sub build_email {
- my ($content, $from, $to, $subject) = @_;
- my @parts;
- my %cid_of;
-
- $content = HTML::RewriteAttributes::Resources->rewrite($content, sub {
- my $uri = shift;
-
- # already attached this object
- return "cid:$cid_of{$uri}" if $cid_of{$uri};
-
- $cid_of{$uri} = time() . $$ . int(rand(1e6));
- my ($data, $filename, $mimetype, $encoding) = get_resource($uri);
-
- # downgrade non-text strings, because all strings are utf8 by
- # default, which is wrong for non-text strings.
- if ( $mimetype !~ m{text/} ) {
- utf8::downgrade( $data, 1 ) or warning "downgrade $data failed";
- }
-
- push @parts, MIME::Entity->build(
- Top => 0,
- Data => $data,
- Type => $mimetype,
- Encoding => $encoding,
- Disposition => 'inline',
- Name => $filename,
- 'Content-Id' => $cid_of{$uri},
- );
-
- return "cid:$cid_of{$uri}";
- },
- inline_css => sub {
- my $uri = shift;
- my ($content) = get_resource($uri);
- return $content;
- },
- inline_imports => 1,
- );
-
- my $entity = MIME::Entity->build(
- From => $from,
- To => $to,
- Subject => $subject,
- Type => "multipart/mixed",
- );
-
- $entity->attach(
- Data => Encode::encode_utf8($content),
- Type => 'text/html',
- Charset => 'UTF-8',
- Disposition => 'inline',
- );
-
- for my $part (@parts) {
- $entity->add_part($part);
- }