| 1 | ################################################################################ |
1 | ################################################################################ |
| 2 | # WeBWorK Online Homework Delivery System |
2 | # WeBWorK Online Homework Delivery System |
| 3 | # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/ |
3 | # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/ |
| 4 | # $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/SendMail.pm,v 1.38 2004/09/16 19:44:44 apizer Exp $ |
4 | # $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/SendMail.pm,v 1.39 2004/12/18 16:09:54 gage Exp $ |
| 5 | # |
5 | # |
| 6 | # This program is free software; you can redistribute it and/or modify it under |
6 | # This program is free software; you can redistribute it and/or modify it under |
| 7 | # the terms of either: (a) the GNU General Public License as published by the |
7 | # the terms of either: (a) the GNU General Public License as published by the |
| 8 | # Free Software Foundation; either version 2, or (at your option) any later |
8 | # Free Software Foundation; either version 2, or (at your option) any later |
| 9 | # version, or (b) the "Artistic License" which comes with this package. |
9 | # version, or (b) the "Artistic License" which comes with this package. |
| … | |
… | |
| 26 | use strict; |
26 | use strict; |
| 27 | use warnings; |
27 | use warnings; |
| 28 | use CGI qw(); |
28 | use CGI qw(); |
| 29 | #use HTML::Entities; |
29 | #use HTML::Entities; |
| 30 | use Mail::Sender; |
30 | use Mail::Sender; |
|
|
31 | use Text::Wrap qw(wrap); |
| 31 | use WeBWorK::HTML::ScrollingRecordList qw/scrollingRecordList/; |
32 | use WeBWorK::HTML::ScrollingRecordList qw/scrollingRecordList/; |
| 32 | use WeBWorK::Utils::FilterRecords qw/filterRecords/; |
33 | use WeBWorK::Utils::FilterRecords qw/filterRecords/; |
| 33 | |
34 | |
| 34 | #my $REFRESH_RESIZE_BUTTON = "Set preview to: "; # handle submit value idiocy |
35 | #my $REFRESH_RESIZE_BUTTON = "Set preview to: "; # handle submit value idiocy |
| 35 | my $UPDATE_SETTINGS_BUTTON = "Update settings and refresh page"; # handle submit value idiocy |
36 | my $UPDATE_SETTINGS_BUTTON = "Update settings and refresh page"; # handle submit value idiocy |
| … | |
… | |
| 260 | # bail if there is no message body |
261 | # bail if there is no message body |
| 261 | |
262 | |
| 262 | $from = $r->param('from'); |
263 | $from = $r->param('from'); |
| 263 | $replyTo = $r->param('replyTo'); |
264 | $replyTo = $r->param('replyTo'); |
| 264 | $subject = $r->param('subject'); |
265 | $subject = $r->param('subject'); |
| 265 | my $body = $r->param('body'); |
266 | my $body = $r->param('body'); |
| 266 | # Sanity check: body must contain non-white space |
267 | # Sanity check: body must contain non-white space |
| 267 | $self->addbadmessage(CGI::p('You didn\'t enter any message.')) unless ($r->param('body') =~ /\S/); |
268 | $self->addbadmessage(CGI::p('You didn\'t enter any message.')) unless ($r->param('body') =~ /\S/); |
| 268 | $r_text = \$body; |
269 | $r_text = \$body; |
| 269 | |
270 | |
| 270 | } |
271 | } |
| … | |
… | |
| 365 | } elsif ($action eq 'Preview message') { |
366 | } elsif ($action eq 'Preview message') { |
| 366 | $self->{response} = 'preview'; |
367 | $self->{response} = 'preview'; |
| 367 | |
368 | |
| 368 | } elsif ($action eq 'Send Email') { |
369 | } elsif ($action eq 'Send Email') { |
| 369 | $self->{response} = 'send_email'; |
370 | $self->{response} = 'send_email'; |
| 370 | |
371 | |
|
|
372 | # check that recipients have been selected. |
| 371 | my @recipients = @{$self->{ra_send_to}}; |
373 | my @recipients = @{$self->{ra_send_to}}; |
| 372 | $self->addbadmessage(CGI::p("No recipients selected ")) unless @recipients; |
374 | $self->addbadmessage(CGI::p("No recipients selected ")) unless @recipients; |
| 373 | # get merge file |
375 | # check merge file |
| 374 | my $merge_file = ( defined($self->{merge_file}) ) ? $self->{merge_file} : 'None'; |
376 | my $merge_file = ( defined($self->{merge_file}) ) ? $self->{merge_file} : 'None'; |
| 375 | my $delimiter = ','; |
377 | my $delimiter = ','; |
| 376 | my $rh_merge_data = $self->read_scoring_file("$merge_file", "$delimiter"); |
378 | my $rh_merge_data = $self->read_scoring_file("$merge_file", "$delimiter"); |
| 377 | unless (ref($rh_merge_data) ) { |
379 | unless (ref($rh_merge_data) ) { |
| 378 | $self->addbadmessage(CGI::p("No merge data file")); |
380 | $self->addbadmessage(CGI::p("No merge data file")); |
| 379 | $self->addbadmessage(CGI::p("Can't read merge file $merge_file. No message sent")); |
381 | $self->addbadmessage(CGI::p("Can't read merge file $merge_file. No message sent")); |
| 380 | return; |
382 | return; |
| 381 | } ; |
383 | } ; |
|
|
384 | if (@recipients) { |
|
|
385 | $self->{rh_merge_data} = $rh_merge_data; |
|
|
386 | $self->{smtpServer} = $ce->{mail}->{smtpServer}; |
|
|
387 | my $post_connection_action = sub { |
|
|
388 | my $r = shift; |
|
|
389 | my $result_message = $self->mail_message_to_recipients(); |
|
|
390 | $self->email_notification($result_message); |
|
|
391 | }; |
|
|
392 | $r->post_connection($post_connection_action) ; |
| 382 | |
393 | } |
| 383 | |
|
|
| 384 | foreach my $recipient (@recipients) { |
394 | # foreach my $recipient (@recipients) { |
| 385 | #warn "FIXME sending email to $recipient"; |
395 | # #warn "FIXME sending email to $recipient"; |
| 386 | my $ur = $self->{db}->getUser($recipient); #checked |
396 | # my $ur = $self->{db}->getUser($recipient); #checked |
| 387 | die "record for user $recipient not found" unless $ur; |
397 | # die "record for user $recipient not found" unless $ur; |
| 388 | unless ($ur->email_address) { |
398 | # unless ($ur->email_address) { |
| 389 | $self->addbadmessage(CGI::p("user $recipient does not have an email address -- skipping")); |
399 | # $self->addbadmessage(CGI::p("user $recipient does not have an email address -- skipping")); |
| 390 | next; |
400 | # next; |
| 391 | } |
401 | # } |
| 392 | my ($msg, $preview_header); |
402 | # my ($msg, $preview_header); |
| 393 | eval{ ($msg,$preview_header) = $self->process_message($ur,$rh_merge_data); }; |
403 | # eval{ ($msg,$preview_header) = $self->process_message($ur,$rh_merge_data); }; |
| 394 | $self->addbadmessage(CGI::p("There were errors in processing user $ur, merge file $merge_file. $@")) if $@; |
404 | # $self->addbadmessage(CGI::p("There were errors in processing user $ur, merge file $merge_file. $@")) if $@; |
| 395 | my $mailer = Mail::Sender->new({ |
405 | # my $mailer = Mail::Sender->new({ |
| 396 | from => $from, |
406 | # from => $from, |
| 397 | to => $ur->email_address, |
407 | # to => $ur->email_address, |
| 398 | smtp => $ce->{mail}->{smtpServer}, |
408 | # smtp => $ce->{mail}->{smtpServer}, |
| 399 | subject => $subject, |
409 | # subject => $subject, |
| 400 | headers => "X-Remote-Host: ".$r->get_remote_host(), |
410 | # headers => "X-Remote-Host: ".$r->get_remote_host(), |
| 401 | }); |
411 | # }); |
| 402 | unless (ref $mailer) { |
412 | # unless (ref $mailer) { |
| 403 | $self->addbadmessage(CGI::p("Failed to create a mailer for user $recipient: $Mail::Sender::Error")); |
413 | # $self->addbadmessage(CGI::p("Failed to create a mailer for user $recipient: $Mail::Sender::Error")); |
| 404 | next; |
414 | # next; |
| 405 | } |
415 | # } |
| 406 | unless (ref $mailer->Open()) { |
416 | # unless (ref $mailer->Open()) { |
| 407 | $self->addbadmessage(CGI::p("Failed to open the mailer for user $recipient: $Mail::Sender::Error")); |
417 | # $self->addbadmessage(CGI::p("Failed to open the mailer for user $recipient: $Mail::Sender::Error")); |
| 408 | next; |
418 | # next; |
| 409 | } |
419 | # } |
| 410 | my $MAIL = $mailer->GetHandle() or $self->addbadmessage(CGI::p("Couldn't get handle")); |
420 | # my $MAIL = $mailer->GetHandle() or $self->addbadmessage(CGI::p("Couldn't get handle")); |
| 411 | print $MAIL $msg || $self->addbadmessage(CGI::p("Couldn't print to $MAIL")); |
421 | # print $MAIL $msg || $self->addbadmessage(CGI::p("Couldn't print to $MAIL")); |
| 412 | close $MAIL || $self->addbadmessage(CGI::p("Couldn't close $MAIL")); |
422 | # close $MAIL || $self->addbadmessage(CGI::p("Couldn't close $MAIL")); |
| 413 | #warn "FIXME mailed to ", $ur->email_address, "from $from subject $subject"; |
423 | # #warn "FIXME mailed to ", $ur->email_address, "from $from subject $subject"; |
| 414 | |
424 | # |
| 415 | } |
425 | # } |
| 416 | |
426 | |
| 417 | } else { |
427 | } else { |
| 418 | $self->addbadmessage(CGI::p("Didn't recognize button $action")); |
428 | $self->addbadmessage(CGI::p("Didn't recognize button $action")); |
| 419 | } |
429 | } |
| 420 | |
430 | |
| … | |
… | |
| 443 | unless $authz->hasPermissions($user, "send_mail"); |
453 | unless $authz->hasPermissions($user, "send_mail"); |
| 444 | |
454 | |
| 445 | if ($response eq 'preview') { |
455 | if ($response eq 'preview') { |
| 446 | $self->print_preview($setID); |
456 | $self->print_preview($setID); |
| 447 | } elsif (($response eq 'send_email')){ |
457 | } elsif (($response eq 'send_email')){ |
| 448 | $self->addgoodmessage(CGI::p("Email sent to ". scalar(@{$self->{ra_send_to}})." students.")); |
458 | my $message = CGI::i("Email is being sent to ". scalar(@{$self->{ra_send_to}})." recipients. You will be notified" |
| 449 | $self->{message} .= CGI::i("Email sent to ". scalar(@{$self->{ra_send_to}})." students."); |
459 | ." when the task is completed. This may take several minutes if the class is large." |
|
|
460 | ); |
|
|
461 | $self->addgoodmessage($message); |
|
|
462 | $self->{message} .= $message; |
|
|
463 | |
| 450 | $self->print_form($setID); |
464 | $self->print_form($setID); |
| 451 | } else { |
465 | } else { |
| 452 | $self->print_form($setID); |
466 | $self->print_form($setID); |
| 453 | } |
467 | } |
| 454 | |
468 | |
| … | |
… | |
| 801 | sub get_merge_file_names { |
815 | sub get_merge_file_names { |
| 802 | my $self = shift; |
816 | my $self = shift; |
| 803 | return 'None', $self->read_dir($self->{ce}->{courseDirs}->{scoring}, '\\.csv$'); #FIXME ? check that only readable files are listed. |
817 | return 'None', $self->read_dir($self->{ce}->{courseDirs}->{scoring}, '\\.csv$'); #FIXME ? check that only readable files are listed. |
| 804 | } |
818 | } |
| 805 | |
819 | |
|
|
820 | sub mail_message_to_recipients { |
|
|
821 | my $self = shift; |
|
|
822 | my $subject = $self->{subject}; |
|
|
823 | my $from = $self->{from}; |
|
|
824 | my @recipients = @{$self->{ra_send_to}}; |
|
|
825 | my $rh_merge_data = $self->{rh_merge_data}; |
|
|
826 | my $merge_file = $self->{merge_file}; |
|
|
827 | my $result_message = ''; |
|
|
828 | my $failed_messages = 0; |
|
|
829 | foreach my $recipient (@recipients) { |
|
|
830 | # warn "FIXME sending email to $recipient"; |
|
|
831 | my $error_messages = ''; |
|
|
832 | my $ur = $self->{db}->getUser($recipient); #checked |
|
|
833 | unless ($ur) { |
|
|
834 | $error_messages .= "Record for user $recipient not found\n"; |
|
|
835 | next; |
|
|
836 | } |
|
|
837 | unless ($ur->email_address) { |
|
|
838 | $error_messages .="User $recipient does not have an email address -- skipping\n"; |
|
|
839 | next; |
|
|
840 | } |
|
|
841 | my ($msg, $preview_header); |
|
|
842 | eval{ ($msg,$preview_header) = $self->process_message($ur,$rh_merge_data); }; |
|
|
843 | $error_messages .= "There were errors in processing user $ur, merge file $merge_file. \n$@\n" if $@; |
|
|
844 | my $mailer = Mail::Sender->new({ |
|
|
845 | from => $from, |
|
|
846 | to => $ur->email_address, |
|
|
847 | smtp => $self->{smtpServer}, |
|
|
848 | subject => $subject, |
|
|
849 | headers => "X-Remote-Host: ".$self->r->get_remote_host(), |
|
|
850 | }); |
|
|
851 | unless (ref $mailer) { |
|
|
852 | $error_messages .= "Failed to create a mailer for user $recipient: $Mail::Sender::Error\n"; |
|
|
853 | next; |
|
|
854 | } |
|
|
855 | unless (ref $mailer->Open()) { |
|
|
856 | $error_messages .= "Failed to open the mailer for user $recipient: $Mail::Sender::Error\n"; |
|
|
857 | next; |
|
|
858 | } |
|
|
859 | my $MAIL = $mailer->GetHandle() || ($error_messages .= "Couldn't get mailer handle \n"); |
|
|
860 | print $MAIL $msg || ($error_messages .= "Couldn't print to $MAIL"); |
|
|
861 | close $MAIL || ($error_messages .= "Couldn't close $MAIL"); |
|
|
862 | #warn "FIXME mailed to $recipient: ", $ur->email_address, " from $from subject $subject Errors: $error_messages"; |
|
|
863 | $failed_messages++ if $error_messages; |
|
|
864 | $result_message .= $error_messages; |
|
|
865 | } |
|
|
866 | my $courseName = $self->r->urlpath->arg("courseID"); |
|
|
867 | my $number_of_recipients = scalar(@recipients) - $failed_messages; |
|
|
868 | $result_message = <<EndText.$result_message; |
|
|
869 | |
|
|
870 | A message with the subject line |
|
|
871 | $subject |
|
|
872 | has been sent to |
|
|
873 | $number_of_recipients recipient(s) in the class $courseName. |
|
|
874 | There were $failed_messages message(s) that could not be delivered. |
|
|
875 | |
|
|
876 | EndText |
| 806 | |
877 | |
|
|
878 | } |
|
|
879 | sub email_notification { |
|
|
880 | my $self = shift; |
|
|
881 | my $result_message = shift; |
|
|
882 | # find info on mailer and sender |
|
|
883 | # use the defaultFrom address. |
|
|
884 | |
|
|
885 | # find info on instructor recipient and message |
|
|
886 | my $subject="WeBWorK email sent"; |
|
|
887 | |
|
|
888 | my $mailing_errors = ""; |
|
|
889 | # open MAIL handle |
|
|
890 | my $mailer = Mail::Sender->new({ |
|
|
891 | from => $self->{defaultFrom}, |
|
|
892 | to => $self->{defaultFrom}, |
|
|
893 | smtp => $self->{smtpServer}, |
|
|
894 | subject => $subject, |
|
|
895 | headers => "X-Remote-Host: ".$self->r->get_remote_host(), |
|
|
896 | }); |
|
|
897 | unless (ref $mailer) { |
|
|
898 | $mailing_errors .= "Failed to create a mailer: $Mail::Sender::Error"; |
|
|
899 | return ""; |
|
|
900 | } |
|
|
901 | unless (ref $mailer->Open()) { |
|
|
902 | $mailing_errors .= "Failed to open the mailer: $Mail::Sender::Error"; |
|
|
903 | return ""; |
|
|
904 | } |
|
|
905 | my $MAIL = $mailer->GetHandle(); |
|
|
906 | # print message |
|
|
907 | print $MAIL $result_message; |
|
|
908 | # clean up |
|
|
909 | close $MAIL; |
|
|
910 | |
|
|
911 | warn "instructor message sent to ", $self->{defaultFrom}; |
|
|
912 | |
|
|
913 | } |
| 807 | sub getRecord { |
914 | sub getRecord { |
| 808 | my $self = shift; |
915 | my $self = shift; |
| 809 | my $line = shift; |
916 | my $line = shift; |
| 810 | my $delimiter = shift; |
917 | my $delimiter = shift; |
| 811 | $delimiter = ',' unless defined($delimiter); |
918 | $delimiter = ',' unless defined($delimiter); |