diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 8a1a07f9b..874437862 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -31,6 +31,7 @@ - rfe #9907: Inbox: Notifications - rfe #9134: Pluggable Storage to support Amazon S3 and Cloudfront - Added PayPal paydriver. (Thanks to Paul Wrightson) + - rfe #9908: Inbox: SMS delivery 7.7.5 - Adding StoryManager. diff --git a/docs/upgrades/upgrade_7.7.5-7.7.6.pl b/docs/upgrades/upgrade_7.7.5-7.7.6.pl index b96575eb7..c9a213b6b 100644 --- a/docs/upgrades/upgrade_7.7.5-7.7.6.pl +++ b/docs/upgrades/upgrade_7.7.5-7.7.6.pl @@ -39,6 +39,9 @@ addListingsCacheTimeoutToMatrix( $session ); addSurveyFeedbackTemplateColumn( $session ); installCopySender($session); installNotificationsSettings($session); +installSMSUserProfileFields($session); +installSMSSettings($session); +upgradeSMSMailQueue($session); addPayDrivers($session); finish($session); @@ -163,6 +166,49 @@ sub installNotificationsSettings { $session->setting->add('inboxNotificationTemplateId', 'b1316COmd9xRv4fCI3LLGA'); } +<<<<<<< .mine +sub installSMSUserProfileFields { + my $session = shift; + WebGUI::ProfileField->create( + $session, + 'receiveInboxEmailNotifications', + { + label => q!WebGUI::International::get('receive inbox emails','Message_Center')!, + visible => 1, + required => 0, + protected => 1, + editable => 1, + fieldType => 'yesNo', + dataDefault => 1, + }, + 4, + ); + WebGUI::ProfileField->create( + $session, + 'receiveInboxSmsNotifications', + { + label => q!WebGUI::International::get('receive inbox sms','Message_Center')!, + visible => 1, + required => 0, + protected => 1, + editable => 1, + fieldType => 'yesNo', + dataDefault => 0, + }, + 4, + ); +} + +sub installSMSSettings { + my $session = shift; + $session->setting->add('smsGateway', ''); +} + +sub upgradeSMSMailQueue { + my $session = shift; + $session->db->write('alter table mailQueue add column isInbox TINYINT(4) default 0'); +} + #---------------------------------------------------------------------------- # Describe what our function does sub addPayDrivers { diff --git a/lib/WebGUI/Mail/Send.pm b/lib/WebGUI/Mail/Send.pm index d40f6a0c6..c3401724b 100644 --- a/lib/WebGUI/Mail/Send.pm +++ b/lib/WebGUI/Mail/Send.pm @@ -267,16 +267,28 @@ A unique id for this message, in case you want to see what replies come in for i If this is a reply to a previous message, then you should specify the messageId of the previous message here. +=head3 isInbox + +A flag indicating that this email message is from the Inbox, and should follow per user settings +for delivery. + =cut sub create { my $class = shift; my $session = shift; my $headers = shift; + my $isInbox = shift; if ($headers->{toUser}) { my $user = WebGUI::User->new($session, $headers->{toUser}); if (defined $user) { - my $email = $user->profileField("email"); + my $email; + if ($isInbox) { + $email = $user->getInboxAddresses; + } + else { + $email = $user->profileField("email"); + } if ($email) { if ($headers->{to}) { $headers->{to} .= ','.$email; @@ -286,9 +298,9 @@ sub create { } } } - my $from = $headers->{from} || $session->setting->get('comanyName') . " <".$session->setting->get("companyEmail").">"; + my $from = $headers->{from} || $session->setting->get('comanyName') . " <".$session->setting->get("companyEmail").">"; my $type = $headers->{contentType} || "multipart/mixed"; - my $replyTo = $headers->{replyTo} || $session->setting->get("mailReturnPath"); + my $replyTo = $headers->{replyTo} || $session->setting->get("mailReturnPath"); # format of Message-Id should be '' my $id = $headers->{messageId} || "WebGUI-" . $session->id->generate; @@ -326,7 +338,7 @@ sub create { delete $headers->{toGroup}; $message->attach(Data=>"This message was intended for ".$to." but was overridden in the config file.\n\n"); } - bless {_message=>$message, _session=>$session, _toGroup=>$headers->{toGroup} }, $class; + bless {_message=>$message, _session=>$session, _toGroup=>$headers->{toGroup}, _isInbox => $isInbox }, $class; } #------------------------------------------------------------------- @@ -469,10 +481,10 @@ sub send { else { my $smtp = Net::SMTP->new($smtpServer); # connect to an SMTP server if (defined $smtp) { - $smtp->mail($mail->head->get("X-Return-Path")); - $smtp->to(split(",",$mail->head->get("to"))); - $smtp->cc(split(",",$mail->head->get("cc"))); - $smtp->bcc(split(",",$mail->head->get("bcc"))); + $smtp->mail($mail->head->get('X-Return-Path')); + $smtp->to( split(',', $mail->head->get('to') )); + $smtp->cc( split(',', $mail->head->get('cc') )); + $smtp->bcc( split(',', $mail->head->get('bcc') )); $smtp->data(); # Start the mail $smtp->datasend($mail->stringify); $smtp->dataend(); # Finish sending the mail @@ -492,15 +504,21 @@ sub send { if ($group) { my $group = WebGUI::Group->new($self->session, $group); return $status if !defined $group; - $mail->head->replace("bcc", undef); - $mail->head->replace("cc", undef); - foreach my $userId (@{$group->getAllUsers(1)}) { + $mail->head->replace('bcc', undef); + $mail->head->replace('cc', undef); + USER: foreach my $userId (@{$group->getAllUsers(1)}) { my $user = WebGUI::User->new($self->session, $userId); - next unless $user->status eq 'Active'; ##Don't send this to invalid user accounts - if ($user->profileField("email")) { - $mail->head->replace("To",$user->profileField("email")); - $self->queue; + next USER unless $user->status eq 'Active'; ##Don't send this to invalid user accounts + my $emailAddress; + if ($self->{_isInbox}) { + $emailAddress = $user->getInboxAddresses; } + else { + $emailAddress = $user->profileField('email'); + } + next USER unless $emailAddress; + $mail->head->replace('To', $emailAddress); + $self->queue; } #Delete the group if it is flagged as an AdHocMailGroup $group->delete if ($group->isAdHocMailGroup); diff --git a/lib/WebGUI/Operation/Settings.pm b/lib/WebGUI/Operation/Settings.pm index aeafba539..e57ad25a0 100644 --- a/lib/WebGUI/Operation/Settings.pm +++ b/lib/WebGUI/Operation/Settings.pm @@ -295,6 +295,14 @@ sub definition { hoverHelp=>$i18n->get('mail return path help'), defaultValue=>$setting->get("mailReturnPath") }); + push(@fields, { + tab => 'messaging', + fieldType => 'email', + name => 'smsGateway', + label => $i18n->get('sms gateway'), + hoverHelp => $i18n->get('sms gateway help'), + defaultValue => $setting->get('smsGateway'), + }); # misc push(@fields, { tab=>"misc", diff --git a/lib/WebGUI/User.pm b/lib/WebGUI/User.pm index bb6ac9460..b72c233ad 100644 --- a/lib/WebGUI/User.pm +++ b/lib/WebGUI/User.pm @@ -504,6 +504,34 @@ sub getGroupIdsRecursive { #------------------------------------------------------------------- +=head2 getInboxAddresses ( ) + +Return a string with addresses that the user wants to receive Inbox +notifications. If the user does not want Inbox notifications, then +the string will be empty. + +=cut + +sub getInboxAddresses { + my $self = shift; + my $emails = ''; + if ( $self->profileField('receiveInboxEmailNotifications') + && $self->profileField('email')) { + $emails = $self->profileField('email'); + } + if ( $self->profileField('receiveInboxSmsNotifications') + && $self->profileField('cellPhone') + && $self->session->setting->get('smsGateway')) { + $emails .= ',' if $emails; + my $phoneNumber = $self->profileField('cellPhone'); + $phoneNumber =~ tr/0-9//dc; ##remove nonnumbers + $emails = join '', $emails, $phoneNumber, '@', $self->session->setting->get('smsGateway'); + } + return $emails; +} + +#------------------------------------------------------------------- + =head2 getProfileFieldPrivacySetting ( [field ]) Returns the privacy setting for the field passed in. If no field is passed in the entire hash is returned diff --git a/lib/WebGUI/i18n/English/WebGUI.pm b/lib/WebGUI/i18n/English/WebGUI.pm index 42ea8bab8..e734aaea5 100644 --- a/lib/WebGUI/i18n/English/WebGUI.pm +++ b/lib/WebGUI/i18n/English/WebGUI.pm @@ -4359,12 +4359,13 @@ Users may override this setting in their profile. 'recaptcha public key' => { message => 'reCAPTCHA Public Key' }, + 'Ad Space control name' => { message => q|Ad Space|, lastUpdated => 0, context => q|name for the Ad Space control| }, - + 'global head tags label' => { message => 'Global Head Tags', lastUpdated => 0, @@ -4376,6 +4377,17 @@ Users may override this setting in their profile. context => 'Description of setting', }, + 'sms gateway' => { + message => q|SMS gateway|, + context => q|email to SMS/text email address for this site.|, + lastUpdated => 1235685248, + }, + + 'sms gateway help' => { + message => q|The email address that this site would use to send an SMS message.|, + lastUpdated => 1235695517, + }, + }; 1; diff --git a/t/Mail/Send.t b/t/Mail/Send.t index 2e9a5abd5..df8023316 100644 --- a/t/Mail/Send.t +++ b/t/Mail/Send.t @@ -16,6 +16,7 @@ use FindBin; use lib "$FindBin::Bin/../lib"; use JSON qw( from_json to_json ); use Test::More; +use Test::Deep; use File::Spec; use Data::Dumper; use MIME::Parser; @@ -69,7 +70,7 @@ if ($hasServer) { #---------------------------------------------------------------------------- # Tests -plan tests => 11; # Increment this number for each test you create +plan tests => 18; # Increment this number for each test you create #---------------------------------------------------------------------------- # Test create @@ -272,6 +273,134 @@ SKIP: { } +#---------------------------------------------------------------------------- +# +# Test sending an Inbox message to a user who has various notifications configured +# +#---------------------------------------------------------------------------- + +my $inboxUser = WebGUI::User->create($session); +WebGUI::Test->usersToDelete($inboxUser); +$inboxUser->username('red'); +$inboxUser->profileField('receiveInboxEmailNotifications', 1); +$inboxUser->profileField('receiveInboxSmsNotifications', 0); +$inboxUser->profileField('email', 'ellis_boyd_redding@shawshank.gov'); +$inboxUser->profileField('cellPhone', '55555'); +$session->setting->set('smsGateway', 'textme.com'); + +my $emailUser = WebGUI::User->create($session); +WebGUI::Test->usersToDelete($emailUser); +$emailUser->username('heywood'); +$emailUser->profileField('email', 'heywood@shawshank.gov'); + +my $lonelyUser = WebGUI::User->create($session); +WebGUI::Test->usersToDelete($lonelyUser); +$lonelyUser->profileField('receiveInboxEmailNotifications', 0); +$lonelyUser->profileField('receiveInboxSmsNotifications', 0); +$lonelyUser->profileField('email', 'jake@shawshank.gov'); + +my $inboxGroup = WebGUI::Group->new($session, 'new'); +WebGUI::Test->groupsToDelete($inboxGroup); +$inboxGroup->addUsers([$emailUser->userId, $inboxUser->userId, $lonelyUser->userId]); + +SKIP: { + my $numtests = 1; # Number of tests in this block + + # Must be able to write the config, or we'll die + skip "Cannot test email notifications", $numtests unless $smtpServerOk; + + # Send the mail + $mail = WebGUI::Mail::Send->create( $session, { + toUser => $inboxUser->userId, + }, + 'fromInbox', + ); + $mail->addText( 'sent via email' ); + + my $received = sendToServer( $mail ) ; + + # Test the mail + is($received->{to}->[0], '', 'send, toUser with email address'); + + $inboxUser->profileField('receiveInboxEmailNotifications', 0); + $inboxUser->profileField('receiveInboxSmsNotifications', 1); + + # Send the mail + $mail = WebGUI::Mail::Send->create( $session, { + toUser => $inboxUser->userId, + }, + 'fromInbox', + ); + $mail->addText( 'sent via SMS' ); + + my $received = sendToServer( $mail ) ; + + # Test the mail + is($received->{to}->[0], '<55555@textme.com>', 'send, toUser with SMS address'); + + $inboxUser->profileField('receiveInboxEmailNotifications', 1); + $inboxUser->profileField('receiveInboxSmsNotifications', 1); + + # Send the mail + $mail = WebGUI::Mail::Send->create( $session, { + toUser => $inboxUser->userId, + }, + 'fromInbox', + ); + $mail->addText( 'sent via SMS' ); + + my $received = sendToServer( $mail ) ; + + # Test the mail + cmp_bag( + $received->{to}, + ['<55555@textme.com>', '',], + 'send, toUser with SMS and email addresses' + ); + +} + +#---------------------------------------------------------------------------- +# +# Test sending an Inbox message to a group with various user profile settings +# +#---------------------------------------------------------------------------- + +my @mailIds; +@mailIds = $session->db->buildArray('select messageId from mailQueue'); +my $startingMessages = scalar @mailIds; + +$mail = WebGUI::Mail::Send->create( $session, { + toGroup => $inboxGroup->getId, + }, + 'fromInbox', +); +$mail->addText('Mail::Send test message'); +@mailIds = $session->db->buildArray('select messageId from mailQueue'); +is(scalar @mailIds, $startingMessages, 'creating a message does not queue a message'); + +$mail->send; +@mailIds = $session->db->buildArray('select messageId from mailQueue'); +is(scalar @mailIds, $startingMessages+2, 'sending a message with a group added two messages'); + +@mailIds = $session->db->buildArray("select messageId from mailQueue where message like ?",['%Mail::Send test message%']); +is(scalar @mailIds, $startingMessages+2, 'sending a message with a group added the right two messages'); + +my @emailAddresses = (); +foreach my $mailId (@mailIds) { + my $mail = WebGUI::Mail::Send->retrieve($session, $mailId); + push @emailAddresses, $mail->getMimeEntity->head->get('to'); +} + +cmp_bag( + \@emailAddresses, + [ + 'heywood@shawshank.gov'."\n", + 'ellis_boyd_redding@shawshank.gov,55555@textme.com'."\n", + ], + 'send: when the original is sent, new messages are created for each user in the group, following their user profile settings' +); + # TODO: Test the emailToLog config setting #---------------------------------------------------------------------------- # Cleanup diff --git a/t/User.t b/t/User.t index 7d86e5ee7..bd554348d 100644 --- a/t/User.t +++ b/t/User.t @@ -20,7 +20,7 @@ use WebGUI::Cache; use WebGUI::User; use WebGUI::ProfileField; -use Test::More tests => 194; # increment this value for each test you create +use Test::More tests => 203; # increment this value for each test you create use Test::Deep; use Data::Dumper; @@ -804,6 +804,47 @@ ok(! $neighbor->canViewField('email', $admin), "... returns 0 when the field's p ok(! $neighbor->canViewField('email', $buster), "... returns 0 when the field's privacy setting is friends, even for some other user"); $friend->deleteFromGroups([$neighbor->friends->getId]); +################################################################ +# +# getInboxAddresses +# +################################################################ + +my $origSmsGateway = $session->setting->get('smsGateway'); +$session->setting->set('smsGateway', ''); +my $inmate = WebGUI::User->create($session); +WebGUI::Test->usersToDelete($inmate); +$inmate->profileField('email', ''); +$inmate->profileField('cellPhone', ''); +$inmate->profileField('receiveInboxEmailNotifications', 0); +$inmate->profileField('receiveInboxSmsNotifications', 0); +is ($inmate->getInboxAddresses, '', 'getInboxAddresses: with no profile info, returns blank'); + +$inmate->profileField('receiveInboxEmailNotifications', 1); +is ($inmate->getInboxAddresses, '', 'getInboxAddresses: with receiveInboxEmailNotifications=1, but not email address, returns blank'); + +$inmate->profileField('email', 'andy@shawshank.com'); +is ($inmate->getInboxAddresses, 'andy@shawshank.com', 'getInboxAddresses: email address only'); + +$inmate->profileField('receiveInboxSmsNotifications', 1); +is ($inmate->getInboxAddresses, 'andy@shawshank.com', 'getInboxAddresses: receive only email address, with receiveInboSMSNotifications=1 but no other profile info'); + +$inmate->profileField('cellPhone', '37927'); +is ($inmate->getInboxAddresses, 'andy@shawshank.com', 'getInboxAddresses: receive only email address, with receiveInboSMSNotifications=1 and cell phone but no gateway'); + +$inmate->profileField('cellPhone', ''); +$session->setting->set('smsGateway', 'textme.com'); +is ($inmate->getInboxAddresses, 'andy@shawshank.com', 'getInboxAddresses: receive only email address, with receiveInboSMSNotifications=1 and gateway but no cell phone'); + +$inmate->profileField('cellPhone', '37927'); +is ($inmate->getInboxAddresses, 'andy@shawshank.com,37927@textme.com', 'getInboxAddresses: receive only email address, with receiveInboSMSNotifications=1 and gateway but no cell phone'); + +$inmate->profileField('receiveInboxEmailNotifications', 0); +is ($inmate->getInboxAddresses, '37927@textme.com', 'getInboxAddresses: can get SMS and no email, even with email info present'); + +$inmate->profileField('receiveInboxSmsNotifications', 0); +is ($inmate->getInboxAddresses, '', 'getInboxAddresses: can get no SMS and no email, even with profile info present'); + END { foreach my $testGroup ($expiredGroup, values %groupSet) { if (defined $testGroup and ref $testGroup eq 'WebGUI::Group') { @@ -822,6 +863,8 @@ END { $newProfileField->delete() if $newProfileField; + $session->setting->set('smsGateway', $origSmsGateway); + $testCache->flush; }