From 9e17665b768972f9debc7254cd19ce7a7ed1f741 Mon Sep 17 00:00:00 2001 From: Robin Sheat Date: Wed, 5 Oct 2011 19:02:48 +1300 Subject: [PATCH] Bug 6973 - have list and cart sending go via message_queue This forces the emailing of lists and carts to be placed in the message queue, rather than sent directly from the script. This allows improved centralised configuration and control of the email system. Note that an effect of this is that rather than going out immediately, emails from OPAC users sending carts will only get sent when the process_message_queue script runs. (this is intended to apply on top of the other bug 6973 patch) --- C4/Letters.pm | 108 ++++++++++++--- installer/data/mysql/kohastructure.sql | 2 + installer/data/mysql/updatedatabase.pl | 2 + opac/opac-sendbasket.pl | 39 +++--- opac/opac-sendshelf.pl | 242 +++++++++++++++++--------------- 5 files changed, 238 insertions(+), 155 deletions(-) diff --git a/C4/Letters.pm b/C4/Letters.pm index 59a4fa6..0fccad4 100644 --- a/C4/Letters.pm +++ b/C4/Letters.pm @@ -44,6 +44,7 @@ BEGIN { @EXPORT = qw( &GetLetters &getletter &addalert &getalert &delalert &findrelatedto &SendAlerts GetPrintMessages ); + @EXPORT_OK = qw( EnqueueLetter ); } =head1 NAME @@ -562,16 +563,72 @@ places a letter in the message_queue database table, which will eventually get processed (sent) by the process_message_queue.pl cronjob when it calls SendQueuedMessages. -return true on success + +=head 3 ARGUMENTS + +=over 4 + +=item C: the borrower to receive this message + +=item C: see below + +=item C: 'email' or 'sms' + +=item C: the email to send the message to, if a borrowernumber is +not supplied. + +=item C: the address to put in the 'From' field of the email + +=item C: if you want a custom reply-to, put it here + +=item C: most notices can get automatically BCCed to somewhere. +This doesn't do that for this message. + +=back + +C is a hashref containing: + +=over 4 + +=item C: the subject line + +=item C<content>: the body of the message + +=item C<metadata>: unused? + +=item C<code>: the code for the letter, unused in the context of queued +messages + +=item C<content-type>: the content type of the message, defaults to +'text/plain; charset="UTF-8"' on sending as email + +=back + +Not all of these are needed in all situations. + +=head3 RETURNS + +True if the enqueueing succeeded, false otherwise. =cut sub EnqueueLetter ($) { my $params = shift or return undef; - return unless exists $params->{'letter'}; - return unless exists $params->{'borrowernumber'}; - return unless exists $params->{'message_transport_type'}; + unless ( exists $params->{'letter'} ) { + carp "Need a message to send\n"; + return; + } + unless ( exists $params->{'borrowernumber'} + || $params->{to_address} ) + { + carp "Need a borrowernumber or a to_address to send to\n"; + return; + } + unless ( exists $params->{'message_transport_type'} ) { + carp "Need to supply a message transport type\n"; + return; + } # If we have any attachments we should encode then into the body. if ( $params->{'attachments'} ) { @@ -586,23 +643,27 @@ sub EnqueueLetter ($) { my $dbh = C4::Context->dbh(); my $statement = << 'ENDSQL'; INSERT INTO message_queue -( borrowernumber, subject, content, metadata, letter_code, message_transport_type, status, time_queued, to_address, from_address, content_type ) +( borrowernumber, subject, content, metadata, letter_code, content_type, +message_transport_type, status, time_queued, to_address, from_address, +reply_to_address, no_local_bcc ) VALUES -( ?, ?, ?, ?, ?, ?, ?, NOW(), ?, ?, ? ) +( ?, ?, ?, ?, ?, ?, ?, ?, NOW(), ?, ?, ?, ? ) ENDSQL my $sth = $dbh->prepare($statement); my $result = $sth->execute( - $params->{'borrowernumber'}, # borrowernumber - $params->{'letter'}->{'title'}, # subject - $params->{'letter'}->{'content'}, # content - $params->{'letter'}->{'metadata'} || '', # metadata - $params->{'letter'}->{'code'} || '', # letter_code - $params->{'message_transport_type'}, # message_transport_type - 'pending', # status - $params->{'to_address'}, # to_address - $params->{'from_address'}, # from_address - $params->{'letter'}->{'content-type'}, # content_type + $params->{'borrowernumber'}, # borrowernumber + $params->{'letter'}->{'title'}, # subject + $params->{'letter'}->{'content'}, # content + $params->{'letter'}->{'metadata'} || '', # metadata + $params->{'letter'}->{'code'} || '', # letter_code + $params->{'letter'}->{'content-type'}, # content_type + $params->{'message_transport_type'}, # message_transport_type + 'pending', # status + $params->{'to_address'}, # to_address + $params->{'from_address'}, # from_address + $params->{'reply_to_address'}, # reply_to_address + $params->{'no_local_bcc'}, # no_local_bcc ); return $result; } @@ -766,7 +827,7 @@ sub _get_unsent_messages (;$) { my $dbh = C4::Context->dbh(); my $statement = << 'ENDSQL'; -SELECT message_id, borrowernumber, subject, content, message_transport_type, status, time_queued, from_address, to_address, content_type +SELECT message_id, borrowernumber, subject, content, message_transport_type, status, time_queued, from_address, to_address, reply_to_address, content_type FROM message_queue WHERE status = ? ENDSQL @@ -827,11 +888,16 @@ sub _send_message_by_email ($;$$$) { Message => $content, 'content-type' => $message->{'content_type'} || 'text/plain; charset="UTF-8"', ); - $sendmail_params{'Auth'} = {user => $username, pass => $password, method => $method} if $username; - if ( my $bcc = C4::Context->preference('OverdueNoticeBcc') ) { - $sendmail_params{ Bcc } = $bcc; + $sendmail_params{'Reply-To'} = $message->{reply_to_address} + if $message->{reply_to_address}; + $sendmail_params{'Auth'} = + { user => $username, pass => $password, method => $method } + if $username; + if ( my $bcc = C4::Context->preference('OverdueNoticeBcc') + && !$message->{no_local_bcc} ) + { + $sendmail_params{Bcc} = $bcc; } - if ( sendmail( %sendmail_params ) ) { _set_message_status( { message_id => $message->{'message_id'}, diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 3a51df5..0618bf2 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -2197,6 +2197,8 @@ CREATE TABLE `message_queue` ( `to_address` mediumtext, `from_address` mediumtext, `content_type` text, + `reply_to_address` mediumtext, --- an optional reply-to address for the message + `no_local_bcc` tinyint(1) DEFAULT NULL, --- whether a copy should be sent to the address set in OverdueNoticeBcc KEY `message_id` (`message_id`), KEY `borrowernumber` (`borrowernumber`), KEY `message_transport_type` (`message_transport_type`), diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index 3436f3e..6b75ec6 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -4449,6 +4449,8 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) { $DBversion = 'XXX'; if (C4::Context->preference("Version") < TransformToNum($DBversion)) { $dbh->do("INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacSendReplyTo',0,'Decides whether to use the patron\\'s email address as the reply-to when they\\'re sending carts and lists',NULL,'YesNo');"); + $dbh->do("ALTER TABLE message_queue ADD COLUMN reply_to_address MEDIUMTEXT"); + $dbh->do("ALTER TABLE message_queue ADD COLUMN no_local_bcc BOOLEAN"); print "Upgrade to $DBversion done (add OpacSendReplyTo syspref (enh 6973))\n"; SetVersion($DBversion); } diff --git a/opac/opac-sendbasket.pl b/opac/opac-sendbasket.pl index 36954f8..06057c3 100755 --- a/opac/opac-sendbasket.pl +++ b/opac/opac-sendbasket.pl @@ -22,7 +22,6 @@ use CGI; use Encode qw(encode); use Carp; -use Mail::Sendmail; use MIME::QuotedPrint; use MIME::Base64; use C4::Biblio; @@ -30,6 +29,7 @@ use C4::Items; use C4::Auth; use C4::Output; use C4::Biblio; +use C4::Letters qw/ EnqueueLetter /; use C4::Members; my $query = new CGI; @@ -52,17 +52,20 @@ my $dbh = C4::Context->dbh; if ( $email_add ) { my $email_from = C4::Context->preference('KohaAdminEmailAddress'); my $user = GetMember( borrowernumber => $borrowernumber ); - my $sender_email - = C4::Context->preference('OpacSendReplyTo') - ? GetPreferredEmailAddress($user) || $email_from - : $email_from; + my $sender_email = + C4::Context->preference('OpacSendReplyTo') + ? GetPreferredEmailAddress($user) || $email_from + : $email_from; my $comment = $query->param('comment'); my %mail = ( - To => $email_add, - From => $email_from, - 'Reply-To' => $sender_email, + to_address => $email_add, + from_address => $email_from, + reply_to_address => $sender_email, ); + # This gets filled up with the message content + my %letter; + my ( $template2, $borrowernumber, $cookie ) = get_template_and_user( { template_name => "opac-sendbasket.tmpl", @@ -120,9 +123,9 @@ if ( $email_add ) { # Analysing information and getting mail properties if ( $template_res =~ /<SUBJECT>\n(.*)\n<END_SUBJECT>/s ) { - $mail{'subject'} = $1; + $letter{'title'} = $1; } - else { $mail{'subject'} = "no subject"; } + else { $letter{'title'} = "no subject"; } my $email_header = ""; if ( $template_res =~ /<HEADER>\n(.*)\n<END_HEADER>/s ) { @@ -146,10 +149,10 @@ if ( $email_add ) { # # # Writing mail # $mail{body} = - $mail{'content-type'} = "multipart/mixed; boundary=\"$boundary\""; + $letter{'content-type'} = "multipart/mixed; boundary=\"$boundary\""; my $isofile = encode_base64(encode("UTF-8", $iso2709)); $boundary = '--' . $boundary; - $mail{body} = <<END_OF_BODY; + $letter{content} = <<END_OF_BODY; $boundary Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable @@ -165,14 +168,14 @@ $isofile $boundary-- END_OF_BODY - # Sending mail - if ( sendmail %mail ) { - # do something if it works.... - $template->param( SENT => "1" ); + $mail{letter} = \%letter; + $mail{message_transport_type} = 'email'; + $mail{no_local_bcc} = 1; + if ( EnqueueLetter( \%mail ) ) { + $template->param( SENT => "1" ); } else { - # do something if it doesnt work.... - carp "Error sending mail: $Mail::Sendmail::error \n"; + carp "Error queueing mail\n"; $template->param( error => 1 ); } $template->param( email_add => $email_add ); diff --git a/opac/opac-sendshelf.pl b/opac/opac-sendshelf.pl index 1a8c66c..155c157 100755 --- a/opac/opac-sendshelf.pl +++ b/opac/opac-sendshelf.pl @@ -24,7 +24,6 @@ use CGI; use Encode qw(encode); use Carp; -use Mail::Sendmail; use MIME::QuotedPrint; use MIME::Base64; use C4::Auth; @@ -32,11 +31,12 @@ use C4::Biblio; use C4::Items; use C4::Output; use C4::VirtualShelves; +use C4::Letters qw/ EnqueueLetter /; use C4::Members; my $query = new CGI; -my ( $template, $borrowernumber, $cookie ) = get_template_and_user ( +my ( $template, $borrowernumber, $cookie ) = get_template_and_user( { template_name => "opac-sendshelfform.tmpl", query => $query, @@ -46,108 +46,116 @@ my ( $template, $borrowernumber, $cookie ) = get_template_and_user ( } ); -my $shelfid = $query->param('shelfid'); -my $email = $query->param('email'); - -my $dbh = C4::Context->dbh; - -if ( ShelfPossibleAction( (defined($borrowernumber) ? $borrowernumber : -1), $shelfid, 'view' ) ) { - -if ( $email ) { - my $email_from = C4::Context->preference('KohaAdminEmailAddress'); - my $sender_email - = C4::Context->preference('OpacSendReplyTo') - ? GetPreferredEmailAddress($user) || $email_from - : $email_from; - my $comment = $query->param('comment'); - - my %mail = ( - To => $email, - From => $email_from, - 'Reply-To' => $sender_email, - ); - - my ( $template2, $borrowernumber, $cookie ) = get_template_and_user( - { - template_name => "opac-sendshelf.tmpl", - query => $query, - type => "opac", - authnotrequired => 1, - flagsrequired => { borrow => 1 }, +my $shelfid = $query->param('shelfid'); +my $email_add = $query->param('email'); + +my $dbh = C4::Context->dbh; + +if ( + ShelfPossibleAction( + ( defined($borrowernumber) ? $borrowernumber : -1 ), $shelfid, + 'view' + ) + ) +{ + + if ($email_add) { + my $email_from = C4::Context->preference('KohaAdminEmailAddress'); + my $user = GetMember( borrowernumber => $borrowernumber ); + my $sender_email = + C4::Context->preference('OpacSendReplyTo') + ? GetPreferredEmailAddress($user) || $email_from + : $email_from; + my $comment = $query->param('comment'); +warn "Sendreplyto is: ".C4::Context->preference('OpacSendReplyTo'); + my %mail = ( + to_address => $email_add, + from_address => $email_from, + reply_to_address => $sender_email, + ); + my %letter; + + my ( $template2, $borrowernumber, $cookie ) = get_template_and_user( + { + template_name => "opac-sendshelf.tmpl", + query => $query, + type => "opac", + authnotrequired => 1, + flagsrequired => { borrow => 1 }, + } + ); + + my @shelf = GetShelf($shelfid); + my ( $items, $totitems ) = GetShelfContents($shelfid); + my $marcflavour = C4::Context->preference('marcflavour'); + my $iso2709; + my @results; + + # retrieve biblios from shelf + foreach my $biblio (@$items) { + my $biblionumber = $biblio->{biblionumber}; + + my $dat = GetBiblioData($biblionumber); + my $record = GetMarcBiblio($biblionumber); + my $marcnotesarray = GetMarcNotes( $record, $marcflavour ); + my $marcauthorsarray = GetMarcAuthors( $record, $marcflavour ); + my $marcsubjctsarray = GetMarcSubjects( $record, $marcflavour ); + + my @items = GetItemsInfo($biblionumber); + + $dat->{MARCNOTES} = $marcnotesarray; + $dat->{MARCSUBJCTS} = $marcsubjctsarray; + $dat->{MARCAUTHORS} = $marcauthorsarray; + $dat->{'biblionumber'} = $biblionumber; + $dat->{ITEM_RESULTS} = \@items; + + $iso2709 .= $record->as_usmarc(); + + push( @results, $dat ); } - ); - - my @shelf = GetShelf($shelfid); - my ($items, $totitems) = GetShelfContents($shelfid); - my $marcflavour = C4::Context->preference('marcflavour'); - my $iso2709; - my @results; - - # retrieve biblios from shelf - foreach my $biblio (@$items) { - my $biblionumber = $biblio->{biblionumber}; - - my $dat = GetBiblioData($biblionumber); - my $record = GetMarcBiblio($biblionumber); - my $marcnotesarray = GetMarcNotes( $record, $marcflavour ); - my $marcauthorsarray = GetMarcAuthors( $record, $marcflavour ); - my $marcsubjctsarray = GetMarcSubjects( $record, $marcflavour ); - - my @items = GetItemsInfo( $biblionumber ); - - $dat->{MARCNOTES} = $marcnotesarray; - $dat->{MARCSUBJCTS} = $marcsubjctsarray; - $dat->{MARCAUTHORS} = $marcauthorsarray; - $dat->{'biblionumber'} = $biblionumber; - $dat->{ITEM_RESULTS} = \@items; - - $iso2709 .= $record->as_usmarc(); - - push( @results, $dat ); - } - - my $user = GetMember(borrowernumber => $borrowernumber); - - $template2->param( - BIBLIO_RESULTS => \@results, - email_sender => $email_from, - comment => $comment, - shelfname => $shelf[1], - firstname => $user->{firstname}, - surname => $user->{surname}, - ); - # Getting template result - my $template_res = $template2->output(); - my $body; - - # Analysing information and getting mail properties - if ( $template_res =~ /<SUBJECT>\n(.*)\n<END_SUBJECT>/s ) { - $mail{'subject'} = $1; - } - else { $mail{'subject'} = "no subject"; } + $template2->param( + BIBLIO_RESULTS => \@results, + email_sender => $email_from, + comment => $comment, + shelfname => $shelf[1], + firstname => $user->{firstname}, + surname => $user->{surname}, + ); + + # Getting template result + my $template_res = $template2->output(); + my $body; + + # Analysing information and getting mail properties + if ( $template_res =~ /<SUBJECT>\n(.*)\n<END_SUBJECT>/s ) { + $letter{'title'} = $1; + } + else { $letter{'title'} = "no subject"; } - my $email_header = ""; - if ( $template_res =~ /<HEADER>\n(.*)\n<END_HEADER>/s ) { - $email_header = $1; - } + my $email_header = ""; + if ( $template_res =~ /<HEADER>\n(.*)\n<END_HEADER>/s ) { + $email_header = $1; + } - my $email_file = "basket.txt"; - if ( $template_res =~ /<FILENAME>\n(.*)\n<END_FILENAME>/s ) { - $email_file = $1; - } + my $email_file = "basket.txt"; + if ( $template_res =~ /<FILENAME>\n(.*)\n<END_FILENAME>/s ) { + $email_file = $1; + } - if ( $template_res =~ /<MESSAGE>\n(.*)\n<END_MESSAGE>/s ) { $body = encode_qp($1); } + if ( $template_res =~ /<MESSAGE>\n(.*)\n<END_MESSAGE>/s ) { + $body = encode_qp($1); + } - my $boundary = "====" . time() . "===="; + my $boundary = "====" . time() . "===="; - # We set and put the multipart content - $mail{'content-type'} = "multipart/mixed; boundary=\"$boundary\""; + # We set and put the multipart content + $letter{'content-type'} = "multipart/mixed; boundary=\"$boundary\""; - my $isofile = encode_base64(encode("UTF-8", $iso2709)); - $boundary = '--' . $boundary; + my $isofile = encode_base64( encode( "UTF-8", $iso2709 ) ); + $boundary = '--' . $boundary; - $mail{body} = <<END_OF_BODY; + $letter{content} = <<END_OF_BODY; $boundary Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable @@ -163,31 +171,33 @@ $isofile $boundary-- END_OF_BODY - # Sending mail - if ( sendmail %mail ) { - # do something if it works.... - $template->param( SENT => "1" ); + $mail{letter} = \%letter; + $mail{message_transport_type} = 'email'; + $mail{no_local_bcc} = 1; + if ( EnqueueLetter( \%mail ) ) { + $template->param( SENT => "1" ); + } + else { + carp "Error queueing mail\n"; + $template->param( error => 1 ); + } + $template->param( email_add => $email_add ); + output_html_with_http_headers $query, $cookie, $template->output; } else { - # do something if it doesnt work.... - carp "Error sending mail: $Mail::Sendmail::error \n"; - $template->param( error => 1 ); + $template->param( + shelfid => $shelfid, + url => "/cgi-bin/koha/opac-sendshelf.pl", + ); + output_html_with_http_headers $query, $cookie, $template->output; } - - $template->param( email => $email ); - output_html_with_http_headers $query, $cookie, $template->output; - - -}else{ - $template->param( shelfid => $shelfid, - url => "/cgi-bin/koha/opac-sendshelf.pl", - ); - output_html_with_http_headers $query, $cookie, $template->output; } - -} else { - $template->param( invalidlist => 1, - url => "/cgi-bin/koha/opac-sendshelf.pl", +else { + $template->param( + invalidlistshelfid => 1, + $shelfid, + url => "/cgi-bin/koha/opac-sendshelf.pl", ); output_html_with_http_headers $query, $cookie, $template->output; } + -- 1.7.4.1