lp1777677 Test Notification Method
authorKyle Huckins <khuckins@catalyte.io>
Thu, 12 Jul 2018 15:40:33 +0000 (15:40 +0000)
committerGalen Charlton <gmc@equinoxinitiative.org>
Fri, 11 Sep 2020 19:51:31 +0000 (15:51 -0400)
- Create fire_test_notification subroutine to create, fire, and
return event
- Add Test Notification UI buttons to preferences and patron edit screen.
- Add Toast to inform of success or failure of sending test notification
- Add Strings to patron interface to handle ngToast notifications
- Add Test Notification to OPAC preferences UI for email
and default sms number.
- Abort Test Notification event if no user is found.

Signed-off-by: Kyle Huckins <khuckins@catalyte.io>
Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Signed-off-by: Chris Sharp <csharp@georgialibraries.org>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>

13 files changed:
Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm
Open-ILS/src/sql/Pg/400.schema.action_trigger.sql
Open-ILS/src/sql/Pg/950.data.seed-values.sql
Open-ILS/src/sql/Pg/upgrade/XXXX.data.lp1777677-action-triggers-test-notification.sql [new file with mode: 0644]
Open-ILS/src/templates/opac/myopac/prefs.tt2
Open-ILS/src/templates/opac/myopac/prefs_notify.tt2
Open-ILS/src/templates/opac/myopac/test_notification.tt2 [new file with mode: 0644]
Open-ILS/src/templates/opac/parts/header.tt2
Open-ILS/src/templates/opac/parts/js.tt2
Open-ILS/src/templates/staff/circ/patron/index.tt2
Open-ILS/src/templates/staff/circ/patron/t_edit.tt2
Open-ILS/web/js/ui/default/opac/test_notification.js [new file with mode: 0644]
Open-ILS/web/js/ui/default/staff/circ/patron/regctl.js

index 21c608a..b703f79 100644 (file)
@@ -4353,6 +4353,25 @@ sub check_password_strength_custom {
     return 1;
 }
 
+__PACKAGE__->register_method(
+    method    => "fire_test_notification",
+    api_name  => "open-ils.actor.event.test_notification"
+);
+
+sub fire_test_notification {
+    my($self, $conn, $auth, $args) = @_;
+    my $e = new_editor(authtoken => $auth);
+    return $e->event unless $e->checkauth;
+    return $e->event unless $$args{home_ou};
+    return $e->die_event unless $e->allowed('UPDATE_USER', $$args{home_ou});
+
+    my $event_hook = $$args{event_def_type} or return $e->event;
+    my $usr = $e->retrieve_actor_user($$args{target});
+
+    return $e->event unless $usr;
+
+    return $U->fire_object_event(undef, $event_hook, $usr, $e->requestor->ws_ou);
+}
 
 
 __PACKAGE__->register_method(
index 9388dbb..9f990a3 100644 (file)
@@ -58,6 +58,8 @@ INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('checkout.du
 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('hold.shelf_expire.emergency_closing','aech','Hold shelf expire time was adjusted by the Emergency Closing handler');
 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('booking.due.emergency_closing','aecr','Booking reservation return date was adjusted by the Emergency Closing handler');
 INSERT INTO action_trigger.hook (key,core_type,description) VALUES ('bre.edit','bre','A bib record was edited');
+INSERT INTO action_trigger.hook (key, core_type, description) VALUES ('au.email.test', 'au', 'A test email has been requested for this user');
+INSERT INTO action_trigger.hook (key, core_type, description) VALUES ('au.sms_text.test', 'au', 'A test SMS has been requested for this user');
 
 -- and much more, I'm sure
 
index bf1ad50..78a8b3c 100644 (file)
@@ -17204,6 +17204,78 @@ INSERT INTO action_trigger.environment (
     'circ_lib'
 );
 
+INSERT INTO action_trigger.event_definition (active, owner, name, hook, validator, reactor, delay, template)
+VALUES (
+    't', 1, 'Send Test Email', 'au.email.test', 'NOOP_True', 'SendEmail', '00:01:00',
+$$
+[%- USE date -%]
+[%- user = target -%]
+[%- lib = target.home_ou -%]
+To: [%- user.email %]
+From: [%- helpers.get_org_setting(target.home_ou.id, 'org.bounced_emails') || lib.email || params.sender_email || default_sender %]
+Date: [%- date.format(date.now, '%a, %d %b %Y %T -0000', gmt => 1) %]
+Reply-To: [%- lib.email || params.sender_email || default_sender %]
+Subject: Email Test Notification
+Auto-Submitted: auto-generated
+
+Dear [% user.first_given_name %] [% user.family_name %],
+
+This is a test of the email associated with your account at [%- lib.name -%]. If you are receiving this message, your email information is correct.
+
+Sincerely,
+[% lib.name %]
+
+Contact your library for more information:
+
+[% lib.name %]
+[%- SET addr = lib.mailing_address -%]
+[%- IF !addr -%] [%- SET addr = lib.billing_address -%] [%- END %]
+[% addr.street1 %] [% addr.street2 %]
+[% addr.city %], [% addr.state %]
+[% addr.post_code %]
+[% lib.phone %]
+
+$$);
+INSERT INTO action_trigger.environment (event_def, path)
+VALUES (currval('action_trigger.event_definition_id_seq'), 'home_ou'),
+       (currval('action_trigger.event_definition_id_seq'), 'home_ou.mailing_address'),
+       (currval('action_trigger.event_definition_id_seq'), 'home_ou.billing_address');
+
+INSERT INTO action_trigger.event_definition (active, owner, name, hook, validator, reactor, delay, template)
+VALUES (
+    't', 1, 'Send Test SMS', 'au.sms_text.test', 'NOOP_True', 'SendSMS', '00:01:00',
+$$
+[%- USE date -%]
+[%- user = target -%]
+[%- lib = user.home_ou -%]
+[%- sms_number = helpers.get_user_setting(target.id, 'opac.default_sms_notify') -%]
+[%- sms_carrier = helpers.get_user_setting(target.id, 'opac.default_sms_carrier') -%]
+From: [%- helpers.get_org_setting(target.home_ou.id, 'org.bounced_emails') || lib.email || params.sender_email || default_sender %]
+To: [%- helpers.get_sms_gateway_email(sms_carrier,sms_number) %]
+Subject: Test SMS
+
+This is a test confirming your default SMS information at [% lib.name %].
+
+Sincerely,
+[% lib.name %]
+
+Contact your library for more information:
+
+[% lib.name %]
+[%- SET addr = lib.mailing_address -%]
+[%- IF !addr -%] [%- SET addr = lib.billing_address -%] [%- END %]
+[% addr.street1 %] [% addr.street2 %]
+[% addr.city %], [% addr.state %]
+[% addr.post_code %]
+[% lib.phone %]
+
+$$);
+INSERT INTO action_trigger.environment (event_def, path)
+VALUES (currval('action_trigger.event_definition_id_seq'), 'home_ou'),
+       (currval('action_trigger.event_definition_id_seq'), 'home_ou.mailing_address'),
+       (currval('action_trigger.event_definition_id_seq'), 'home_ou.billing_address');
+
+
 INSERT INTO config.org_unit_setting_type
 (name, grp, label, description, datatype)
 VALUES
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.lp1777677-action-triggers-test-notification.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.lp1777677-action-triggers-test-notification.sql
new file mode 100644 (file)
index 0000000..30f8364
--- /dev/null
@@ -0,0 +1,85 @@
+BEGIN;
+
+SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+
+
+INSERT into action_trigger.hook (key, core_type, description) VALUES (
+    'au.email.test', 'au', 'A test email has been requested for this user'
+),
+(
+    'au.sms_text.test', 'au', 'A test SMS has been requested for this user'
+);
+
+INSERT INTO action_trigger.event_definition (active, owner, name, hook, validator, reactor, delay, template)
+VALUES (
+    't', 1, 'Send Test Email', 'au.email.test', 'NOOP_True', 'SendEmail', '00:01:00', 
+$$
+[%- USE date -%]
+[%- user = target -%]
+[%- lib = target.home_ou -%]
+To: [%- user.email %]
+From: [%- helpers.get_org_setting(target.home_ou.id, 'org.bounced_emails') || lib.email || params.sender_email || default_sender %]
+Date: [%- date.format(date.now, '%a, %d %b %Y %T -0000', gmt => 1) %]
+Reply-To: [%- lib.email || params.sender_email || default_sender %]
+Subject: Email Test Notification
+Auto-Submitted: auto-generated
+
+Dear [% user.first_given_name %] [% user.family_name %],
+
+This is a test of the email associated with your account at [%- lib.name -%]. If you are receiving this message, your email information is correct.
+
+Sincerely,
+[% lib.name %]
+
+Contact your library for more information:
+
+[% lib.name %]
+[%- SET addr = lib.mailing_address -%]
+[%- IF !addr -%] [%- SET addr = lib.billing_address -%] [%- END %]
+[% addr.street1 %] [% addr.street2 %]
+[% addr.city %], [% addr.state %]
+[% addr.post_code %]
+[% lib.phone %]
+$$);
+
+INSERT INTO action_trigger.environment (event_def, path)
+VALUES (currval('action_trigger.event_definition_id_seq'), 'home_ou'),
+       (currval('action_trigger.event_definition_id_seq'), 'home_ou.mailing_address'),
+       (currval('action_trigger.event_definition_id_seq'), 'home_ou.billing_address');
+
+INSERT INTO action_trigger.event_definition (active, owner, name, hook, validator, reactor, delay, template)
+VALUES (
+    't', 1, 'Send Test SMS', 'au.sms_text.test', 'NOOP_True', 'SendSMS', '00:01:00', 
+$$
+[%- USE date -%]
+[%- user = target -%]
+[%- lib = user.home_ou -%]
+[%- sms_number = helpers.get_user_setting(target.id, 'opac.default_sms_notify') -%]
+[%- sms_carrier = helpers.get_user_setting(target.id, 'opac.default_sms_carrier') -%]
+From: [%- helpers.get_org_setting(target.home_ou.id, 'org.bounced_emails') || lib.email || params.sender_email || default_sender %]
+To: [%- helpers.get_sms_gateway_email(sms_carrier,sms_number) %]
+Subject: Test SMS
+
+This is a test confirming your default SMS information at [% lib.name %].
+
+Sincerely,
+[% lib.name %]
+
+Contact your library for more information:
+
+[% lib.name %]
+[%- SET addr = lib.mailing_address -%]
+[%- IF !addr -%] [%- SET addr = lib.billing_address -%] [%- END %]
+[% addr.street1 %] [% addr.street2 %]
+[% addr.city %], [% addr.state %]
+[% addr.post_code %]
+[% lib.phone %]
+$$);
+
+INSERT INTO action_trigger.environment (event_def, path)
+VALUES (currval('action_trigger.event_definition_id_seq'), 'home_ou'),
+       (currval('action_trigger.event_definition_id_seq'), 'home_ou.mailing_address'),
+       (currval('action_trigger.event_definition_id_seq'), 'home_ou.billing_address');
+
+
+COMMIT;
\ No newline at end of file
index dc90c7e..724116c 100644 (file)
@@ -1,7 +1,8 @@
 [%  PROCESS "opac/parts/header.tt2";
     WRAPPER "opac/parts/myopac/prefs_base.tt2";
     myopac_page = "prefs";
-    prefs_page = 'prefs' %]
+    prefs_page = 'prefs';
+    can_call_action_trigger = 'true' %]
 
 <h3 class="sr-only">[% l('Account Preferences') %]</h3>
 <div id="acct_info_main">
@@ -23,6 +24,7 @@
                 ) | html %]</td>
 
                 <td></td>
+                <td></td>
             </tr>
             [% IF ctx.user.pref_first_given_name || ctx.user.pref_second_given_name || ctx.user.pref_family_name %]
             <tr>
@@ -39,6 +41,7 @@
                 ) | html %]</td>
 
                 <td></td>
+                <td></td>
             </tr>
             [%  END %]
 
                 <td class='color_4 light_border'>[% l("Day Phone") %]</td>
                 <td class='light_border'>[% ctx.user.day_phone | html %]</td>
                 <td></td>
+                <td></td>
             </tr>
 
             <tr>
                 <td class='color_4 light_border'>[% l("Evening Phone") %]</td>
                 <td class='light_border'>[% ctx.user.evening_phone | html %]</td>
                 <td></td>
+                <td></td>
             </tr>
 
             <tr>
                 <td class='color_4 light_border'>[% l("Other Phone") %]</td>
                 <td class='light_border'>[% ctx.user.other_phone | html %]</td>
                 <td></td>
+                <td></td>
             </tr>
 
             <tr>
@@ -66,6 +72,7 @@
                    </div>[% l("Username") %]
                 </td>
                 <td class='light_border'>[% ctx.user.usrname | html %]</td>
+                <td></td>
                 [%- IF ctx.username_change_disallowed %]
                 <td></td>
                 [%- ELSE %]
@@ -76,6 +83,7 @@
             <tr>
                 <td class='color_4 light_border'>[% l("Password") %]</td>
                 <td class='light_border'>[% l("(not shown)") %]</td>
+                <td></td>
                 [%- IF disable_password_change == 'true' %]
                 <td></td>
                 [%- ELSE %]
             <tr>
                 <td class='color_4 light_border'>[% l("Email Address") %]</td>
                 <td class='light_border'>[% ctx.user.email | html %]</td>
+                <td class='light_border'>
+                [%- IF ctx.user.email %]
+                <a href="#" onclick="sendTestNotification(
+                        [% ctx.user.id %], [% ctx.user.home_ou.id %], 'email', '[% ctx.authtoken %]'
+                    )"
+                    title="[% l('Send Test Email') %]">[% l('Send Test Email') %]</a></td>
+                [%- END %]
                 [%- IF disable_email_change == 'true' %]
                 <td></td>
                 [%- ELSE %]
                     title="[% l('Update Email Address') %]">[% l('Change') %]</a></td>
                 [%- END %]
             </tr>
-
+            <tr id="test_notification_banner" style="display:none">
+                <td colspan="4">
+                    [% INCLUDE "opac/myopac/test_notification.tt2" %]
+                </td>
+            </tr>
+            <tr>
             [% IF ctx.user.ident_value %]<tr class="hide_me">
                 <td class='color_4 light_border'>
                 [% l("Primary Identification") %]</td>
                     %]
                 </td>
                 <td></td>
+                <td></td>
             </tr>[% END %]
 
             <tr>
                 <td class='color_4 light_border'>[% l("Active Barcode") %]</td>
                 <td class='light_border'>[% ctx.user.card.barcode %]</td>
                 <td></td>
+                <td></td>
             </tr>
 
             <tr>
                     %]
                 </td>
                 <td></td>
+                <td></td>
             </tr>
             <tr>
                 <td class='color_4 light_border'>[% l("Account Creation Date") %]</td>
                 <td class='light_border'>[% date.format(ctx.parse_datetime(ctx.user.create_date), DATE_FORMAT) %]</td>
                 <td></td>
+                <td></td>
             </tr>
             <tr>
                 <td class='color_4 light_border'>[% l("Account Expiration Date") %]</td>
                     [% END %]
                 </td>
                 <td></td>
+                <td></td>
             </tr>
         </tbody>
     </table><br />
index 7b17ada..346b744 100644 (file)
@@ -1,7 +1,8 @@
 [%  PROCESS "opac/parts/header.tt2";
     WRAPPER "opac/parts/myopac/prefs_base.tt2";
     myopac_page = "prefs";
-    prefs_page = 'prefs_notify' %]
+    prefs_page = 'prefs_notify'
+    can_call_action_trigger = 'true' %]
 
 <h3 class="sr-only">[% l('Notification Preferences') %]</h3>
     [% IF ctx.affectedChgs %]
                         <td>
                             <input onchange="record_change(event)" id='[% setting %]' name='[% setting %]' type="text"
                                 [% IF ctx.user_setting_map.$setting; %] value='[% ctx.user_setting_map.$setting | html %]' [% END %]/>
+                            [% IF ctx.user_setting_map.$setting; %]
+                            <a href="#" onclick="sendTestNotification(
+                                [% ctx.user.id %], [% ctx.user.home_ou.id %], 'email', '[% ctx.authtoken %]'
+                            )"
+                            title="[% l('Send Test Text Message') %]">[% l('Send Test Text Message') %]</a><br />
                             [% l('Hint: use the full 10 digits of your phone #, no spaces, no dashes'); %]
+                            [% END %]
+                        </td>
+                    </tr>
+                    <tr id="test_notification_banner" style="display:none">
+                        <td colspan="4">
+                            [% INCLUDE "opac/myopac/test_notification.tt2" %]
                         </td>
                     </tr>
                     [% END %]
diff --git a/Open-ILS/src/templates/opac/myopac/test_notification.tt2 b/Open-ILS/src/templates/opac/myopac/test_notification.tt2
new file mode 100644 (file)
index 0000000..a092924
--- /dev/null
@@ -0,0 +1,14 @@
+<div class="color_4">
+    [% l('Notification Sent') %]
+</div>
+<div>
+    [% l('If you do not receive a notification, contact your Library for more information.') %]
+</div>
+
+<div>[% ctx.user.home_ou.name %]</div>
+[%- IF ctx.user.home_ou.phone; %]
+    <div>[% ctx.user.home_ou.phone %]</div>
+[%- END %]
+[%- IF ctx.user.home_ou.email %]
+    <div>[% ctx.user.home_ou.email %]</div>
+[%- END %]
\ No newline at end of file
index 5f397c3..2bf7bb0 100644 (file)
         want_dojo = 1;
     END;
 
+    # ... and for interfaces that require manual trigger of action triggers
+    IF can_call_action_trigger == 'true';
+        want_dojo = 1;
+    END;
+
     # Especially useful for image 'alt' tags and link title tags,
     # where the content may need to be unique (making it longer)
     # but should not exceed 75 chars for ideal screen reader support.
index 28b043d..295ec45 100644 (file)
     [% INCLUDE "opac/parts/ebook_api/base_js.tt2" %]
     [% INCLUDE "opac/parts/ebook_api/login_js.tt2" IF (ctx.page == 'login') %]
 [% END %]
-
+<script src='[% ctx.media_prefix %]/js/ui/default/opac/test_notification.js'></script>
 <!-- provide a JS friendly org unit hash -->
 <script type="text/javascript">
 var aou_hash = {
index a36c758..39cc783 100644 (file)
@@ -77,7 +77,9 @@ angular.module('egCoreMod').run(['egStrings', function(s) {
   s.PAGE_TITLE_PATRON_HOLDS = "[% l('Holds') %]";
   s.PAGE_TITLE_PATRON_ITEMS_OUT = "[% l('Items Out') %]";
   s.PAGE_TITLE_PATRON_EDIT = "[% l('Edit') %]";
-  s.MERGE_SELF_NOT_ALLOWED = "[% l('Logged in account cannot be merged') %]"
+  s.MERGE_SELF_NOT_ALLOWED = "[% l('Logged in account cannot be merged') %]";
+  s.TEST_NOTIFY_SUCCESS = "[% l('Test Notification sent') %]";
+  s.TEST_NOTIFY_FAIL = "[% l('Test Notification failed to send') %]"
 }]);
 </script>
 
index 1a8bb24..d147b45 100644 (file)
@@ -461,7 +461,10 @@ within the "form" by name for validation.
 <div class="row reg-field-row" ng-show="show_field('au.email')">
   [% draw_field_label('au', 'email') %]
   [% draw_form_input('au', 'email', '', 'email') %]
-  <div class="col-md-6 patron-reg-example">
+  <div class="col-md-3" ng-if="patron.email && !patron.isnew">
+    <button class="btn btn-default" ng-click="send_test_message({test_type:'email'})">[% l('Send Test Email') %]</button>
+  </div>
+  <div class="col-md-3 patron-reg-example">
     <button ng-show="patron.email && !patron.isnew" 
       class="btn btn-default" 
       ng-click="invalidate_field('email')">[% l('Invalidate') %]</button>
@@ -783,6 +786,9 @@ within the "form" by name for validation.
       ng-blur="handle_field_changed(user_settings, 'opac.default_sms_notify')"
       type='text'/>
   </div>
+  <div class="col-md-3" ng-if="user_settings['opac.default_sms_notify'] && !patron.isnew">
+    <button class="btn btn-default" ng-click="send_test_message({test_type:'sms_text'})">[% l('Send Test Text') %]</button>
+  </div>
 </div>
 
 <div class="row reg-field-row" ng-if="org_settings['sms.enable']">
diff --git a/Open-ILS/web/js/ui/default/opac/test_notification.js b/Open-ILS/web/js/ui/default/opac/test_notification.js
new file mode 100644 (file)
index 0000000..84ea8b4
--- /dev/null
@@ -0,0 +1,21 @@
+function sendTestNotification(user_id, home_ou, event_def_type, authtoken) {
+    var hook = 'au.' + event_def_type + '.test';
+    
+    var args = {
+        target: user_id,
+        home_ou: home_ou,
+        event_def_type: hook
+    };
+    
+    new OpenSRF.ClientSession('open-ils.actor').request({
+        method: 'open-ils.actor.event.test_notification',
+        params: [authtoken, args],
+        oncomplete: function(r) {
+            var resp = r.recv();
+            if (resp) {
+                var banner = document.getElementById('test_notification_banner');
+                banner.style.display = 'table-row';
+            }
+        }
+    }).send();
+}
\ No newline at end of file
index e161105..0d7269b 100644 (file)
@@ -656,6 +656,18 @@ angular.module('egCoreMod')
         });
     }
 
+    service.send_test_message = function(patron, args) {
+        var hook = 'au.' + args.test_type + '.test';
+
+        return egCore.net.request(
+            'open-ils.actor',
+            'open-ils.actor.event.test_notification',
+            egCore.auth.token(), {event_def_type: hook, target: patron.id, home_ou: patron.home_ou}
+        ).then(function(res) {
+            return res;
+        });
+    }
+
     service.dupe_patron_search = function(patron, type, value) {
         var search;
 
@@ -1252,10 +1264,10 @@ angular.module('egCoreMod')
 .controller('PatronRegCtrl',
        ['$scope','$routeParams','$q','$uibModal','$window','egCore',
         'patronSvc','patronRegSvc','egUnloadPrompt','egAlertDialog',
-        'egWorkLog', '$timeout',
+        'egWorkLog', '$timeout','ngToast',
 function($scope , $routeParams , $q , $uibModal , $window , egCore ,
          patronSvc , patronRegSvc , egUnloadPrompt, egAlertDialog ,
-         egWorkLog, $timeout) {
+         egWorkLog, $timeout, ngToast) {
 
     $scope.page_data_loaded = false;
     $scope.hold_notify_type = { phone : null, email : null, sms : null };
@@ -1959,6 +1971,17 @@ function($scope , $routeParams , $q , $uibModal , $window , egCore ,
         });
     }
 
+    $scope.send_test_message = function(args) {
+        patronRegSvc.send_test_message($scope.patron, args).then(function(res) {
+            if (res && res.template_output() && res.template_output().is_error() == 'f') {
+                 ngToast.success(egCore.strings.TEST_NOTIFY_SUCCESS);
+            } else {
+                ngToast.warning(egCore.strings.TEST_NOTIFY_FAIL);
+                if (res) console.log(res);
+            }
+        });
+    }
+
     address_alert = function(addr) {
         var args = {
             street1: addr.street1,