X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2Fsaved_search.pm;h=fd82439e2b77c02f9f3f4ca1d10f782bff51c967;hp=075d759f60bb6745be1421f720f94216cfb10764;hb=389b6f1116c3309c2ee57a6c295ed1a793503095;hpb=94a16efc8164c9ba8a9bc027ba9485027a6a8b7b diff --git a/FS/FS/saved_search.pm b/FS/FS/saved_search.pm index 075d759f6..fd82439e2 100644 --- a/FS/FS/saved_search.pm +++ b/FS/FS/saved_search.pm @@ -1,13 +1,15 @@ package FS::saved_search; -use base qw( FS::option_Common FS::Record ); +use base qw( FS::Record ); use strict; use FS::Record qw( qsearch qsearchs ); use FS::Conf; +use FS::Log; +use FS::Misc qw(send_email); +use MIME::Entity; use Class::Load 'load_class'; use URI::Escape; use DateTime; -use Try::Tiny; =head1 NAME @@ -56,6 +58,10 @@ A descriptive name. The path to the page within the Mason document space. +=item params + +The query string for the search. + =item disabled 'Y' to hide the search from the user's Reports / Saved menu. @@ -128,6 +134,7 @@ sub check { #|| $self->ut_foreign_keyn('usernum', 'access_user', 'usernum') || $self->ut_text('searchname') || $self->ut_text('path') + || $self->ut_textn('params') # URL-escaped, so ut_textn || $self->ut_flag('disabled') || $self->ut_enum('freq', [ '', 'daily', 'weekly', 'monthly' ]) || $self->ut_numbern('last_sent') @@ -138,6 +145,14 @@ sub check { $self->SUPER::check; } +sub replace_check { + my ($new, $old) = @_; + if ($new->usernum != $old->usernum) { + return "can't change owner of a saved search"; + } + ''; +} + =item next_send_date Returns the next date this report should be sent next. If it's not set for @@ -168,8 +183,6 @@ Returns the CGI query string for the parameters to this report. =cut -# multivalued options are newline-separated in the database - sub query_string { my $self = shift; @@ -177,12 +190,7 @@ sub query_string { $type = 'html-print' if $type eq '' || $type eq 'html'; $type = '.xls' if $type eq 'xls'; my $query = "_type=$type"; - my %options = $self->options; - foreach my $k (keys %options) { - foreach my $v (split("\n", $options{$k})) { - $query .= ';' . uri_escape($k) . '=' . uri_escape($v); - } - } + $query .= ';' . $self->params if $self->params; $query; } @@ -194,6 +202,7 @@ Returns the report content as an HTML or Excel file. sub render { my $self = shift; + my $log = FS::Log->new('FS::saved_search::render'); my $outbuf; # delayed loading @@ -210,11 +219,10 @@ sub render { local $FS::CurrentUser::CurrentUser = $self->access_user; local $FS::Mason::Request::QUERY_STRING = $self->query_string; - local $FS::Mason::Request::FSURL = ''; #? -# local $ENV{SERVER_NAME} = 'localhost'; #? -# local $ENV{SCRIPT_NAME} = '/freeside'. $self->path; + local $FS::Mason::Request::FSURL = $self->access_user->option('rooturl'); - my $mason_request = $fs_interp->make_request(comp => $self->path); + my $mason_request = $fs_interp->make_request(comp => '/' . $self->path); + $mason_request->notes('inline_stylesheet', 1); local $@; eval { $mason_request->exec(); }; @@ -224,9 +232,9 @@ sub render { $error = $error->message; } - warn "Error rendering " . $self->path . + $log->error("Error rendering " . $self->path . " for " . $self->access_user->username . - ":\n$error\n"; + ":\n$error\n"); # send it to the user anyway, so there's a way to diagnose the error $outbuf = '

Error

There was an error generating the report "'.$self->searchname.'".

@@ -234,7 +242,75 @@ sub render {

' . $_ . '

'; } - return $outbuf; + my %mime = ( + Data => $outbuf, + Type => $mason_request->notes('header-content-type') + || 'text/html', + Disposition => 'inline', + ); + if (my $disp = $mason_request->notes('header-content-disposition') ) { + $disp =~ /^(attachment|inline)\s*;\s*filename=(.*)$/; + $mime{Disposition} = $1; + my $filename = $2; + $filename =~ s/^"(.*)"$/$1/; + $mime{Filename} = $filename; + } + if ($mime{Type} =~ /^text/) { + $mime{Encoding} = 'quoted-printable'; + } else { + $mime{Encoding} = 'base64'; + } + return MIME::Entity->build(%mime); +} + +=item send + +Sends the search by email. If anything fails, logs and returns an error. + +=cut + +sub send { + my $self = shift; + my $log = FS::Log->new('FS::saved_search::send'); + my $conf = FS::Conf->new; + my $user = $self->access_user; + my $username = $user->username; + my $user_email = $user->option('email_address'); + my $error; + if (!$user_email) { + $error = "User '$username' has no email address."; + $log->error($error); + return $error; + } + $log->debug('Rendering saved search'); + my $part = $self->render; + + my %email_param = ( + 'from' => $conf->config('invoice_from'), + 'to' => $user_email, + 'subject' => $self->searchname, + 'nobody' => 1, + 'mimeparts' => [ $part ], + ); + + $log->debug('Sending to '.$user_email); + $error = send_email(%email_param); + + # update the timestamp + $self->set('last_sent', time); + $error ||= $self->replace; + if ($error) { + $log->error($error); + return $error; + } + +} + +sub queueable_send { + my $searchnum = shift; + my $self = FS::saved_search->by_key($searchnum) + or die "searchnum $searchnum not found\n"; + $self->send; } =back