View | Details | Raw Unified | Return to bug 14590
Collapse All | Expand All

(-)a/C4/Form/MessagingPreferences.pm (-2 / +32 lines)
Lines 77-85 sub handle_form_action { Link Here
77
    # TODO: If a "NONE" box and another are checked somehow (javascript failed), we should pay attention to the "NONE" box
77
    # TODO: If a "NONE" box and another are checked somehow (javascript failed), we should pay attention to the "NONE" box
78
    my $prefs_set = 0;
78
    my $prefs_set = 0;
79
    OPTION: foreach my $option ( @$messaging_options ) {
79
    OPTION: foreach my $option ( @$messaging_options ) {
80
        my $updater = { %{ $target_params }, 
80
        my $updater = { borrowernumber          => $target_params->{'borrowernumber'},
81
                        message_attribute_id    => $option->{'message_attribute_id'} };
81
                        message_attribute_id    => $option->{'message_attribute_id'} };
82
        
82
        
83
        my @transport_methods = $query->param($option->{'message_attribute_id'});
84
        # Messaging preference validation. Make sure there is a valid contact information
85
        # provided for every transport method. Otherwise remove the transport method,
86
        # because the message cannot be delivered with this method!
87
        if ((defined $query->param('email') && !$query->param('email') ||
88
            !defined $query->param('email') && !$target_params->{'email'} && exists $target_params->{'email'})
89
            && (my $transport_id = (List::MoreUtils::firstidx { $_ eq "email" } @transport_methods)) >-1) {
90
91
            splice(@transport_methods, $transport_id, 1);# splice the email transport method for this message
92
        }
93
        if ((defined $query->param('phone') && !$query->param('phone') ||
94
            !defined $query->param('phone') && !$target_params->{'phone'} && exists $target_params->{'phone'})
95
            && (my $transport_id = (List::MoreUtils::firstidx { $_ eq "phone" } @transport_methods)) >-1) {
96
97
            splice(@transport_methods, $transport_id, 1);# splice the phone transport method for this message
98
        }
99
        if ((defined $query->param('SMSnumber') && !$query->param('SMSnumber') ||
100
            !defined $query->param('SMSnumber') && !$target_params->{'smsalertnumber'} && exists $target_params->{'smsalertnumber'})
101
            && (my $transport_id = (List::MoreUtils::firstidx { $_ eq "sms" } @transport_methods)) >-1) {
102
103
            splice(@transport_methods, $transport_id, 1);# splice the sms transport method for this message
104
        }
105
106
        if (@transport_methods > 0) {
107
            $query->param($option->{'message_attribute_id'}, @transport_methods);
108
        } else {
109
            $query->delete($option->{'message_attribute_id'});
110
        }
111
83
        # find the desired transports
112
        # find the desired transports
84
        @{$updater->{'message_transport_types'}} = $query->param( $option->{'message_attribute_id'} );
113
        @{$updater->{'message_transport_types'}} = $query->param( $option->{'message_attribute_id'} );
85
        next OPTION unless $updater->{'message_transport_types'};
114
        next OPTION unless $updater->{'message_transport_types'};
Lines 108-114 sub handle_form_action { Link Here
108
        C4::Members::Messaging::SetMessagingPreferencesFromDefaults( $target_params );
137
        C4::Members::Messaging::SetMessagingPreferencesFromDefaults( $target_params );
109
    }
138
    }
110
    # show the success message
139
    # show the success message
111
    $template->param( settings_updated => 1 );
140
    $template->param( settings_updated => 1 ) if (defined $template);
141
112
}
142
}
113
143
114
=head2 set_form_values
144
=head2 set_form_values
(-)a/C4/Members.pm (+9 lines)
Lines 656-661 sub ModMember { Link Here
656
            $data{password} = hash_password($data{password});
656
            $data{password} = hash_password($data{password});
657
        }
657
        }
658
    }
658
    }
659
659
    my $old_categorycode = GetBorrowerCategorycode( $data{borrowernumber} );
660
    my $old_categorycode = GetBorrowerCategorycode( $data{borrowernumber} );
660
661
661
    # get only the columns of a borrower
662
    # get only the columns of a borrower
Lines 689-694 sub ModMember { Link Here
689
            }
690
            }
690
        }
691
        }
691
692
693
        # Validate messaging preferences if any of the following field has been removed
694
        if ((not Koha::Validation::validate_email($data{email}) or
695
             not Koha::Validation::validate_phonenumber($data{phone})) and
696
             not exists $data{smsalertnumber}) {
697
            # Make sure there are no misconfigured preferences - if there is, delete them.
698
            C4::Members::Messaging::DeleteAllMisconfiguredPreferences($data{borrowernumber});
699
        }
700
692
        # If NorwegianPatronDBEnable is enabled, we set syncstatus to something that a
701
        # If NorwegianPatronDBEnable is enabled, we set syncstatus to something that a
693
        # cronjob will use for syncing with NL
702
        # cronjob will use for syncing with NL
694
        if ( C4::Context->preference('NorwegianPatronDBEnable') && C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
703
        if ( C4::Context->preference('NorwegianPatronDBEnable') && C4::Context->preference('NorwegianPatronDBEnable') == 1 ) {
(-)a/C4/Members/Messaging.pm (+123 lines)
Lines 20-25 package C4::Members::Messaging; Link Here
20
use strict;
20
use strict;
21
use warnings;
21
use warnings;
22
use C4::Context;
22
use C4::Context;
23
use Koha::Validation;
23
24
24
use vars qw($VERSION);
25
use vars qw($VERSION);
25
26
Lines 257-262 sub SetMessagingPreferencesFromDefaults { Link Here
257
        $default_pref->{borrowernumber}          = $params->{borrowernumber};
258
        $default_pref->{borrowernumber}          = $params->{borrowernumber};
258
        SetMessagingPreference( $default_pref );
259
        SetMessagingPreference( $default_pref );
259
    }
260
    }
261
    # Finally, delete all misconfigured preferences
262
    DeleteAllMisconfiguredPreferences($params->{borrowernumber});
263
}
264
265
=head2 DeleteAllMisconfiguredPreferences
266
267
  C4::Members::Messaging::DeleteAllMisconfiguredPreferences( [ $borrowernumber ] );
268
269
Deletes all misconfigured preferences for ALL borrowers that have invalid contact information for
270
the transport types. Given a borrowernumber, deletes misconfigured preferences only for this borrower.
271
272
return: returns array of arrayrefs to the deleted preferences (borrower_message_preference_id and message_transport_type)
273
274
=cut
275
276
sub DeleteAllMisconfiguredPreferences {
277
    my $borrowernumber = shift;
278
279
    my @deleted_prefs;
280
281
    push(@deleted_prefs, DeleteMisconfiguredPreference("email", "email", "email", $borrowernumber));
282
    push(@deleted_prefs, DeleteMisconfiguredPreference("phone", "phone", "phone", $borrowernumber));
283
    push(@deleted_prefs, DeleteMisconfiguredPreference("sms", "smsalertnumber", "phone", $borrowernumber));
284
285
    return @deleted_prefs;
286
}
287
288
=head2 DeleteMisconfiguredPreference
289
290
  C4::Members::Messaging::DeleteMisconfiguredPreference( $type, $contact, $validator [, $borrowernumber ] );
291
292
Takes a messaging preference type and the primary contact method for it, and a string to define
293
the Koha::Validation that should be used to determine whether the preference is misconfigured.
294
295
A messaging preference is misconfigured when it is linked with invalid contact information.
296
E.g. messaging type email expects the user to have a valid e-mail address in order to work.
297
298
Deletes misconfigured preferences for ALL borrowers that have invalid contact information for
299
that transport type. Given a borrowernumber, deletes misconfigured preferences only for this borrower.
300
301
return: returns array of arrayrefs to the deleted preferences (borrower_message_preference_id and message_transport_type)
302
303
=cut
304
305
sub DeleteMisconfiguredPreference {
306
    my ($type, $contact, $validator, $borrowernumber) = @_;
307
308
    if (not defined $type or not defined $contact or not defined $validator) {
309
        return 0;
310
    }
311
312
    my @misconfigured_prefs;
313
314
    # Get all messaging preferences and borrower's contact information
315
    my $dbh = C4::Context->dbh();
316
    my $query = "
317
318
        SELECT
319
                    borrower_message_preferences.borrower_message_preference_id,
320
                    borrower_message_transport_preferences.message_transport_type,
321
                    borrowers.$contact
322
323
        FROM
324
                    borrower_message_preferences,
325
                    borrower_message_transport_preferences,
326
                    borrowers
327
328
        WHERE
329
                    borrower_message_preferences.borrower_message_preference_id
330
                    =
331
                    borrower_message_transport_preferences.borrower_message_preference_id
332
333
        AND
334
                    borrowers.borrowernumber = borrower_message_preferences.borrowernumber
335
336
        AND
337
                    borrower_message_transport_preferences.message_transport_type = ?
338
    ";
339
340
    $query .= " AND borrowers.borrowernumber = ?" if defined $borrowernumber;
341
342
    my $sth = $dbh->prepare($query);
343
344
    if (defined $borrowernumber){
345
        $sth->execute($type, $borrowernumber);
346
    } else {
347
        $sth->execute($type);
348
    }
349
350
    while (my $ref = $sth->fetchrow_arrayref) {
351
        if ($$ref[1] eq $type) {
352
            if (not defined $$ref[2] or defined $$ref[2] and $$ref[2] eq "") {
353
                my $valid_contact = 0; # delete prefs if empty contact
354
                # push the misconfigured preferences into an array
355
                push(@misconfigured_prefs, $$ref[0]) unless $valid_contact and $$ref[2];
356
            }
357
            else {
358
                my ($valid_contact, $err, $err_msg) = Koha::Validation::use_validator($validator, $$ref[2]);
359
                # push the misconfigured preferences into an array
360
                push(@misconfigured_prefs, $$ref[0]) unless $valid_contact and $$ref[2];
361
            }
362
        }
363
    }
364
365
    $sth = $dbh->prepare("
366
367
    DELETE FROM
368
                    borrower_message_transport_preferences
369
370
    WHERE
371
                    borrower_message_preference_id = ? AND message_transport_type = ?
372
    ");
373
374
    my @deleted_prefs;
375
    foreach my $id (@misconfigured_prefs){
376
        # delete the misconfigured pref
377
        $sth->execute($id, $type);
378
        # push it into array that we will return
379
        push (@deleted_prefs, [$id,$type]);
380
    }
381
382
    return @deleted_prefs;
260
}
383
}
261
384
262
=head1 TABLES
385
=head1 TABLES
(-)a/Koha/Borrower/Modifications.pm (+9 lines)
Lines 26-31 use Modern::Perl; Link Here
26
26
27
use C4::Context;
27
use C4::Context;
28
use C4::Debug;
28
use C4::Debug;
29
use C4::Form::MessagingPreferences;
29
30
30
sub new {
31
sub new {
31
    my ( $class, %args ) = @_;
32
    my ( $class, %args ) = @_;
Lines 191-196 sub ApproveModifications { Link Here
191
        borrowernumber => $data->{borrowernumber},
192
        borrowernumber => $data->{borrowernumber},
192
    });
193
    });
193
    if( $rs->update($data) ) {
194
    if( $rs->update($data) ) {
195
        # Validate messaging preferences if any of the following field has been removed
196
        if ((not Koha::Validation::validate_email($data->{email}) or
197
             not Koha::Validation::validate_phonenumber($data->{phone}) or
198
             not Koha::Validation::validate_phonenumber($data->{'smsalertnumber'}))) {
199
            # Make sure there are no misconfigured preferences - if there is, delete them.
200
            C4::Members::Messaging::DeleteAllMisconfiguredPreferences($borrowernumber);
201
        }
202
194
        $self->DelModifications( { borrowernumber => $borrowernumber } );
203
        $self->DelModifications( { borrowernumber => $borrowernumber } );
195
    }
204
    }
196
}
205
}
(-)a/koha-tmpl/intranet-tmpl/prog/en/js/messaging-preference.js (+91 lines)
Line 0 Link Here
1
/**
2
 *
3
 * Used in: koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt
4
 *
5
 * This component is also used in OPAC: koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-messaging.tt
6
 * For modifications, edit also OPAC version in: koha-tmpl/opac-tmpl/bootstrap/en/js/messaging-preference.js
7
 *
8
 * Disables and clears checkboxes from messaging preferences
9
 * if there is either invalid or nonexistent contact information
10
 * for the message transfer type.
11
 *
12
 * @param {HTMLInputElement} elem
13
 *  The contact field
14
 * @param {string} id_attr
15
 *  Checkboxes' id attribute so that we can recognize them
16
 */
17
// Settings for messaging-preference.js
18
var patron_messaging_checkbox_preferences = {
19
    email: {
20
        checked_checkboxes: null,
21
        is_enabled: true,
22
        disabled_checkboxes: null
23
    },
24
    sms: {
25
        checked_checkboxes: null,
26
        is_enabled: true,
27
        disabled_checkboxes: null
28
    },
29
    phone: {
30
        checked_checkboxes: null,
31
        is_enabled: true,
32
        disabled_checkboxes: null
33
    }
34
};
35
36
function disableCheckboxesWithInvalidPreferences(elem, id_attr) {
37
    // Get checkbox preferences for the element
38
    var checkbox_prefs = eval("patron_messaging_checkbox_preferences." + id_attr);
39
    // Check if element is empty or not valid
40
41
    if (!$(elem).length || $(elem).val().length == 0 ||  !$(elem).valid()) {
42
43
        if (checkbox_prefs.is_enabled) {
44
            // Save the state of checked checkboxes
45
            checkbox_prefs.checked_checkboxes = $("input[type='checkbox'][id^=" + id_attr + "][value=" + id_attr + "]:checked");
46
47
            // Save the state of automatically disabled checkboxes
48
            // (We don't want to enable them once the e-mail is valid!)
49
            checkbox_prefs.disabled_checkboxes = $("input[type='checkbox'][id^=" + id_attr + "][value=" + id_attr + "]:disabled");
50
51
            // Clear patron messaging preferences checkboxes
52
            $("input[type='checkbox'][id^=" + id_attr + "][value=" + id_attr + "]").removeAttr("checked");
53
54
            // Then disable checkboxes from patron messaging perferences
55
            $("input[type='checkbox'][id^=" + id_attr + "][value=" + id_attr + "]").attr("disabled", "disabled");
56
57
            // Color table cell's background emphasize the disabled state of the checkbox
58
            $("input[type='checkbox'][id^=" + id_attr + "][value=" + id_attr + "]").parent().css("background-color", "#E8F0F8");
59
60
            // Show notice about missing contact in messaging preferences box
61
            $("#required-" + id_attr).css("display", "block");
62
63
            checkbox_prefs.is_enabled = false;
64
        }
65
    } else {
66
67
        if (!checkbox_prefs.is_enabled) {
68
            // Enable patron messaging preferences checkboxes
69
            $("input[type='checkbox'][id^=" + id_attr + "][value=" + id_attr + "]").removeAttr("disabled");
70
71
            // Disable the checkboxes that were disabled by default
72
            checkbox_prefs.disabled_checkboxes.each(function() {
73
                $(this).attr("disabled", "disabled");
74
                $(this).removeAttr("checked");
75
            });
76
77
            // Restore the state of checkboxes
78
            checkbox_prefs.checked_checkboxes.each(function() {
79
                $(this).attr("checked", "checked");
80
            });
81
82
            // Remove the background color from table cell
83
            $("input[type='checkbox'][id^=" + id_attr + "][value=" + id_attr + "]").parent().css("background-color", "#FFF");
84
85
            // Remove notice about missing contact from messaging preferences box
86
            $("#required-" + id_attr).css("display", "none");
87
88
            checkbox_prefs.is_enabled = true;
89
        }
90
    }
91
}
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt (-17 / +48 lines)
Lines 37-43 Link Here
37
37
38
        var MSG_INCORRECT_PHONE = _("Please enter a valid phone number.");
38
        var MSG_INCORRECT_PHONE = _("Please enter a valid phone number.");
39
        $.validator.addMethod('phone', function(value) {
39
        $.validator.addMethod('phone', function(value) {
40
            value = value.trim();
41
            if (!value.trim()) {
40
            if (!value.trim()) {
42
                return 1;
41
                return 1;
43
            }
42
            }
Lines 82-116 Link Here
82
                $("body, form input[type='submit'], form button[type='submit'], form a").addClass('waiting');
81
                $("body, form input[type='submit'], form button[type='submit'], form a").addClass('waiting');
83
                if (form.beenSubmitted)
82
                if (form.beenSubmitted)
84
                    return false;
83
                    return false;
85
                else
84
                else {
86
                    form.beenSubmitted = true;
85
                        form.beenSubmitted = true;
87
                    [% IF ValidateEmailAddress %]
86
                        [% IF ValidateEmailAddress %]
88
                        $("#email, #emailpro, #B_email").each(function(){
87
                        $("#email, #emailpro, #B_email").each(function(){
89
                            $(this).val($.trim($(this).val()));
88
                            $(this).val($.trim($(this).val()));
90
                        });
89
                        });
91
                    [% END %]
90
                        [% END %]
92
                    [% IF ValidatePhoneNumber %]
91
                        [% IF ValidatePhoneNumber %]
93
                        $("#phone, #phonepro, #B_phone, #SMSnumber").each(function(){
92
                        $("#phone, #phonepro, #B_phone, #SMSnumber").each(function(){
94
                            $(this).val($.trim($(this).val()));
93
                            $(this).val($.trim($(this).val()));
95
                        });
94
                        });
96
                    [% END %]
95
                        [% END %]
97
                    form.submit();
96
                        form.submit();
97
                    }
98
                }
98
                }
99
        });
99
        });
100
100
101
        [% IF ValidateEmailAddress %]
101
        [% IF ValidateEmailAddress %]
102
        $("#email, #emailpro, #B_email").on("change", function(){
102
            [% IF !email %]
103
            $(this).val($.trim($(this).val()));
103
                disableCheckboxesWithInvalidPreferences($("#email"), "email");
104
        });
104
            [% END %]
105
            $("#email").on("input", function(){
106
                disableCheckboxesWithInvalidPreferences($(this), "email");
107
            });
108
            $("#email, #emailpro, #B_email").on("change", function(){
109
                $(this).val($.trim($(this).val()));
110
                disableCheckboxesWithInvalidPreferences($(this), "email");
111
            });
105
        [% END %]
112
        [% END %]
113
106
        [% IF ValidatePhoneNumber %]
114
        [% IF ValidatePhoneNumber %]
107
        $("#SMSnumber").on("change", function(){
115
            [% IF !smsalertnumber %]
108
            $(this).val($.trim($(this).val()));
116
                disableCheckboxesWithInvalidPreferences($("#SMSnumber"), "sms");
109
        });
117
            [% END %]
110
        $("#phone, #phonepro, #B_phone").on("change", function(){
118
            [% IF !phone %]
111
            $(this).val($.trim($(this).val()));
119
                disableCheckboxesWithInvalidPreferences($("#phone"), "phone");
112
        });
120
            [% END %]
121
            $("#SMSnumber").on("input", function(){
122
                disableCheckboxesWithInvalidPreferences($(this), "sms");
123
            });
124
            $("#SMSnumber").on("change", function(){
125
                $(this).val($.trim($(this).val()));
126
                disableCheckboxesWithInvalidPreferences($(this), "sms");
127
            });
128
            $("#phone").on("input", function(){
129
                disableCheckboxesWithInvalidPreferences($(this), "phone");
130
            });
131
            $("#phone, #phonepro, #B_phone").on("change", function(){
132
                $(this).val($.trim($(this).val()));
133
                disableCheckboxesWithInvalidPreferences($(this), "phone");
134
            });
113
        [% END %]
135
        [% END %]
136
114
        var mrform = $("#manual_restriction_form");
137
        var mrform = $("#manual_restriction_form");
115
        var mrlink = $("#add_manual_restriction");
138
        var mrlink = $("#add_manual_restriction");
116
        mrform.hide();
139
        mrform.hide();
Lines 214-219 Link Here
214
//]]>
237
//]]>
215
</script>
238
</script>
216
<script type="text/javascript" src="[% themelang %]/js/members.js"></script>
239
<script type="text/javascript" src="[% themelang %]/js/members.js"></script>
240
<script type="text/javascript" src="[% themelang %]/js/messaging-preference.js"></script>
217
</head>
241
</head>
218
<body id="pat_memberentrygen" class="pat">
242
<body id="pat_memberentrygen" class="pat">
219
[% INCLUDE 'header.inc' %]
243
[% INCLUDE 'header.inc' %]
Lines 1157-1162 Link Here
1157
    </script>
1181
    </script>
1158
    [% END %]
1182
    [% END %]
1159
    <input type="hidden" name="setting_messaging_prefs" value="1" />
1183
    <input type="hidden" name="setting_messaging_prefs" value="1" />
1184
    [% IF ( ValidateEmailAddress ) %]
1185
    <p id="required-email" style="[% IF email %]display:none;[% END %]"><label for="email">Primary email</label> is required in order to set Email preferences.</p>
1186
    [% END %]
1187
    [% IF ( ValidatePhoneNumber ) %]
1188
    [% IF ( TalkingTechItivaPhone ) %]<p id="required-phone" style="[% IF phone %]display:none;[% END %]"><label for="phone">Primary phone</label> is required in order to set Phone preferences.</p>[% END %]
1189
    [% IF ( SMSSendDriver ) %]<p id="required-sms" style="[% IF smsalertnumber %]display:none;[% END %]"><label for="SMSnumber">SMS Number</label> is required in order to set SMS preferences.</p>[% END %]
1190
    [% END %]
1160
    [% INCLUDE 'messaging-preference-form.inc' %]
1191
    [% INCLUDE 'messaging-preference-form.inc' %]
1161
    [% IF ( SMSSendDriver ) %]
1192
    [% IF ( SMSSendDriver ) %]
1162
        <p><label for="SMSnumber">SMS number:</label>
1193
        <p><label for="SMSnumber">SMS number:</label>
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-messaging.tt (-3 / +22 lines)
Lines 24-29 Link Here
24
            <div class="span10">
24
            <div class="span10">
25
                <div id="usermessaging">
25
                <div id="usermessaging">
26
                    <h3>Your messaging settings</h3>
26
                    <h3>Your messaging settings</h3>
27
                        [% IF ( ValidateEmailAddress ) %]<div id="required-email" class="alert" style="[% IF BORROWER_INF.email %]display:none;[% END %]"><h4>Primary email</h4> is required in order to set Email preferences.</div>[% END %]
28
                        [% IF ( TalkingTechItivaPhone AND ValidatePhoneNumber ) %]<div id="required-phone" class="alert" style="[% IF BORROWER_INF.phone %]display:none;[% END %]"><h4>Primary phone</h4> is required in order to set Phone preferences.</div>[% END %]
29
                        [% IF ( SMSSendDriver AND ValidatePhoneNumber ) %]<div id="required-sms" class="alert" style="[% IF BORROWER_INF.smsalertnumber %]display:none;[% END %]"><h4>SMS number</h4> is required in order to set SMS preferences.</div>[% END %]
27
                    [% IF ( settings_updated ) %]
30
                    [% IF ( settings_updated ) %]
28
                        <div class="alert alert-success"><h4>Settings updated</h4></div>
31
                        <div class="alert alert-success"><h4>Settings updated</h4></div>
29
                    [% END %]
32
                    [% END %]
Lines 201-214 Link Here
201
        }
204
        }
202
    });
205
    });
203
206
207
    [% IF ( ValidateEmailAddress ) %]
208
        [% IF !BORROWER_INF.email %]
209
        disableCheckboxesWithInvalidPreferences($("#email"), "email");
210
        [% END %]
211
    [% END %]
204
    [% IF ( ValidatePhoneNumber ) %]
212
    [% IF ( ValidatePhoneNumber ) %]
205
    $("#SMSnumber").on("change", function(){
213
        [% IF !BORROWER_INF.smsalertnumber %]
214
        disableCheckboxesWithInvalidPreferences($("#SMSnumber"), "sms");
215
        [% END %]
216
        [% IF !BORROWER_INF.phone %]
217
        disableCheckboxesWithInvalidPreferences($("#phone"), "phone");
218
        [% END %]
219
220
        $("#SMSnumber").on("input", function(){
221
            disableCheckboxesWithInvalidPreferences($(this), "sms");
222
        });
223
        $("#SMSnumber").on("change", function(){
206
            $(this).val($.trim($(this).val()));
224
            $(this).val($.trim($(this).val()));
207
    });
225
            disableCheckboxesWithInvalidPreferences($(this), "sms");
226
        });
208
    [% END %]
227
    [% END %]
209
210
  });
228
  });
211
//]]>
229
//]]>
212
</script>
230
</script>
213
<script type="text/javascript" src="/opac-tmpl/bootstrap/lib/jquery/plugins/jquery.validate.min.js"></script>
231
<script type="text/javascript" src="/opac-tmpl/bootstrap/lib/jquery/plugins/jquery.validate.min.js"></script>
232
<script type="text/javascript" src="[% interface %]/[% theme %]/js/messaging-preference.js"></script>
214
[% END %]
233
[% END %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/js/messaging-preference.js (+91 lines)
Line 0 Link Here
1
/**
2
 *
3
 * Used in: koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-messaging.tt
4
 *
5
 * This component is also used in Staff client: koha-tmpl/intranet-tmpl/prog/en/modules/memberentrygen.tt
6
 * For modifications, edit also Staff client version in: koha-tmpl/intranet-tmpl/prog/en/js/messaging-preference.js
7
 *
8
 * Disables and clears checkboxes from messaging preferences
9
 * if there is either invalid or nonexistent contact information
10
 * for the message transfer type.
11
 *
12
 * @param {HTMLInputElement} elem
13
 *  The contact field
14
 * @param {string} id_attr
15
 *  Checkboxes' id attribute so that we can recognize them
16
 */
17
// Settings for messaging-preference.js
18
var patron_messaging_checkbox_preferences = {
19
    email: {
20
        checked_checkboxes: null,
21
        is_enabled: true,
22
        disabled_checkboxes: null
23
    },
24
    sms: {
25
        checked_checkboxes: null,
26
        is_enabled: true,
27
        disabled_checkboxes: null
28
    },
29
    phone: {
30
        checked_checkboxes: null,
31
        is_enabled: true,
32
        disabled_checkboxes: null
33
    }
34
};
35
36
function disableCheckboxesWithInvalidPreferences(elem, id_attr) {
37
    // Get checkbox preferences for the element
38
    var checkbox_prefs = eval("patron_messaging_checkbox_preferences." + id_attr);
39
    // Check if element is empty or not valid
40
41
    if (!$(elem).length || $(elem).val().length == 0 ||  !$(elem).valid()) {
42
43
        if (checkbox_prefs.is_enabled) {
44
            // Save the state of checked checkboxes
45
            checkbox_prefs.checked_checkboxes = $("input[type='checkbox'][id^=" + id_attr + "][value=" + id_attr + "]:checked");
46
47
            // Save the state of automatically disabled checkboxes
48
            // (We don't want to enable them once the e-mail is valid!)
49
            checkbox_prefs.disabled_checkboxes = $("input[type='checkbox'][id^=" + id_attr + "][value=" + id_attr + "]:disabled");
50
51
            // Clear patron messaging preferences checkboxes
52
            $("input[type='checkbox'][id^=" + id_attr + "][value=" + id_attr + "]").removeAttr("checked");
53
54
            // Then disable checkboxes from patron messaging perferences
55
            $("input[type='checkbox'][id^=" + id_attr + "][value=" + id_attr + "]").attr("disabled", "disabled");
56
57
            // Color table cell's background emphasize the disabled state of the checkbox
58
            $("input[type='checkbox'][id^=" + id_attr + "][value=" + id_attr + "]").parent().css("background-color", "#E8F0F8");
59
60
            // Show notice about missing contact in messaging preferences box
61
            $("#required-" + id_attr).css("display", "block");
62
63
            checkbox_prefs.is_enabled = false;
64
        }
65
    } else {
66
67
        if (!checkbox_prefs.is_enabled) {
68
            // Enable patron messaging preferences checkboxes
69
            $("input[type='checkbox'][id^=" + id_attr + "][value=" + id_attr + "]").removeAttr("disabled");
70
71
            // Disable the checkboxes that were disabled by default
72
            checkbox_prefs.disabled_checkboxes.each(function() {
73
                $(this).attr("disabled", "disabled");
74
                $(this).removeAttr("checked");
75
            });
76
77
            // Restore the state of checkboxes
78
            checkbox_prefs.checked_checkboxes.each(function() {
79
                $(this).attr("checked", "checked");
80
            });
81
82
            // Remove the background color from table cell
83
            $("input[type='checkbox'][id^=" + id_attr + "][value=" + id_attr + "]").parent().css("background-color", "#FFF");
84
85
            // Remove notice about missing contact from messaging preferences box
86
            $("#required-" + id_attr).css("display", "none");
87
88
            checkbox_prefs.is_enabled = true;
89
        }
90
    }
91
}
(-)a/members/memberentry.pl (-1 / +1 lines)
Lines 437-443 if ((!$nok) and $nodouble and ($op eq 'insert' or $op eq 'save')){ Link Here
437
            C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, $extended_patron_attributes);
437
            C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, $extended_patron_attributes);
438
        }
438
        }
439
        if (C4::Context->preference('EnhancedMessagingPreferences') and $input->param('setting_messaging_prefs')) {
439
        if (C4::Context->preference('EnhancedMessagingPreferences') and $input->param('setting_messaging_prefs')) {
440
            C4::Form::MessagingPreferences::handle_form_action($input, { borrowernumber => $borrowernumber }, $template);
440
            C4::Form::MessagingPreferences::handle_form_action($input, \%data, $template);
441
        }
441
        }
442
	}
442
	}
443
	print scalar ($destination eq "circ") ? 
443
	print scalar ($destination eq "circ") ? 
(-)a/misc/maintenance/deleteMisconfiguredMessagingPrefs.pl (+215 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
#-----------------------------------
4
# Copyright 2015 Vaara-kirjastot
5
#
6
# This file is part of Koha.
7
#
8
# Koha is free software; you can redistribute it and/or modify it under the
9
# terms of the GNU General Public License as published by the Free Software
10
# Foundation; either version 2 of the License, or (at your option) any later
11
# version.
12
#
13
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
14
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License along
18
# with Koha; if not, write to the Free Software Foundation, Inc.,
19
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
#-----------------------------------
21
22
use strict;
23
use warnings;
24
use C4::Context;
25
use DBI;
26
use Email::Valid;
27
use POSIX qw(strftime);
28
use Getopt::Long;
29
use C4::Members::Messaging;
30
31
my $helptext = "
32
This script deletes misconfigured messaging preferences from the Koha database. A preference is
33
misconfigured if the user has no valid contact information for that type of transport method.
34
E.g user wants messages via e-mail while he has not provided an e-mail address.
35
36
Options:
37
    -h|--help           Prints this help documentation.
38
    -b|--backup:s       Filename for backup file. Required in 'restore' mode and optional in 'delete' mode.
39
                        Default value is messaging-prefs-backup_<date and time>. In 'delete' mode, if nothing
40
                        gets deleted, the file will not be created.
41
    -d|--delete         Activates the deletion mode (cannot be used simultaneously with mode 'restore').
42
    -r|--restore        Activates the restore mode (cannot be used simultaneously with mode 'delete').
43
    -m|--methods=s{1,3} Optional. Specifies the transfer methods/types. The three types are: email phone sms.
44
                        If not provided, all three types are used.
45
46
Examples:
47
    ./deleteMisconfiguredMessagingPrefs.pl -d -b
48
    ./deleteMisconfiguredMessagingPrefs.pl -d -t email phone -b
49
    ./deleteMisconfiguredMessagingPrefs.pl -d -t email phone sms -b my_backup_file
50
    ./deleteMisconfiguredMessagingPrefs.pl -r -b my_backup_file
51
\n";
52
53
my ($help, $delete, $filename, $restore, @methods);
54
55
GetOptions(
56
    'h|help' => \$help,
57
    'd|delete' => \$delete,
58
    'r|restore' => \$restore,
59
    'b|backup:s' => \$filename,
60
    'm|methods=s{1,3}' => \@methods
61
);
62
63
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
64
my $are_we_doing_backups = 0;
65
66
67
if ($help || $restore && $delete || !$restore && !$delete) {
68
    die $helptext;
69
}
70
if ($delete and $filename eq "" or length($filename) > 0) {
71
    $are_we_doing_backups = 1;
72
    $filename = (strftime "messaging-prefs-backup_%Y-%m-%d_%H-%M-%S", localtime) if ($filename eq "");
73
    # first, make sure we can do backups
74
    open(my $file, ">>", $filename) or die "Could not open file for writing.\n";
75
}
76
77
78
79
80
81
82
83
84
85
86
87
88
if ($delete) {
89
    my @deleted_prefs;
90
91
    # check if user has specified messaging transport methods
92
    if (@methods > 0 && @methods < 4) {
93
        my $correct_modes = 0;
94
95
        foreach my $type (@methods){
96
97
            if ($type eq "email" or $type eq "phone" or $type eq "sms") {
98
                print "Deleting misconfigured $type messaging preferences\n";
99
100
                # method exists, don't need to print warning anymore
101
                $correct_modes = 1;
102
103
                # which contact info field (primary email / primary phone / smsalertnumber)
104
                # should we check?
105
                my $contact;
106
                $contact = "email" if $type eq "email";
107
                $contact = "phone" if $type eq "phone";
108
                $contact = "smsalertnumber" if $type eq "sms";
109
110
                # which validator should we use?
111
                my $validator;
112
                $validator = "email" if $type eq "email";
113
                $validator = "phone" if $type eq "phone" or $type eq "sms";
114
115
                # delete the misconfigured prefs and keep a counting them
116
                push(@deleted_prefs, C4::Members::Messaging::DeleteMisconfiguredPreference($type, $contact, $validator));
117
            }
118
        }
119
120
        die "Missing or invalid in parameter --type values. See help.\n$helptext" if $correct_modes == 0;
121
122
    } else {
123
124
        # user did not specify any methods. so let's delete them all!
125
        print "Deleting all misconfigured messaging preferences\n";
126
        push(@deleted_prefs, C4::Members::Messaging::DeleteAllMisconfiguredPreferences());
127
128
    }
129
130
    BackupDeletedPrefs(@deleted_prefs) if $are_we_doing_backups;
131
132
    print "Deleted ".scalar(@deleted_prefs)." misconfigured messaging preferences in total.\n";
133
}
134
elsif ($restore){
135
    if (@methods > 0) {
136
        my $correct_modes = 0;
137
        for (my $i=0; $i < @methods; $i++){
138
            if ($methods[$i] ne "email" and $methods[$i] ne "phone" and $methods[$i] ne "sms") {
139
                print "Invalid type $methods[$i]. Valid types are: email phone sms\n";
140
                splice(@methods, $i);
141
            }
142
        }
143
        die "Missing parameter --type values. See help.\n$helptext" if @methods == 0;
144
        RestoreDeletedPreferences(@methods);
145
    } else {
146
        RestoreDeletedPreferences();
147
    }
148
}
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# restoring deleted prefs
165
166
sub BackupDeletedPrefs {
167
    my @deleted = @_;
168
169
    open(my $fh, ">>", $filename) or die "Could not open file for writing.\n";
170
171
    for (my $i=0; $i < @deleted; $i++){
172
        say $fh $deleted[$i][0].",".$deleted[$i][1];
173
    }
174
}
175
sub RestoreDeletedPreferences {
176
    my $count = 0;
177
    my @methods = @_;
178
179
    my $dbh = C4::Context->dbh();
180
    open(my $fh, "<", $filename) or die "Could not open file for writing.\n";
181
182
    my $query = "INSERT INTO borrower_message_transport_preferences (borrower_message_preference_id, message_transport_type) VALUES (?,?)";
183
    my $sth = $dbh->prepare($query);
184
185
    # check if user has specified methods (types)
186
    if (@methods > 0) {
187
        while (my $line = <$fh>) {
188
            my @vars = split(',',$line);
189
            my @remlinebreak = split('\\n', $vars[1]);
190
            my $pref_id = $vars[0];
191
            my $type = $remlinebreak[0];
192
193
            if (grep(/$type/,@methods)) {
194
                $sth->execute($pref_id, $type) or $count--;
195
                $count++;
196
            }
197
        }
198
    } else {
199
        # simply walk through each line and restore every single line
200
        while (my $line = <$fh>) {
201
            my @vars = split(',',$line);
202
            next if @vars == 0;
203
            my @remlinebreak = split('\\n', $vars[1]);
204
            next if not defined $remlinebreak[0];
205
            my $pref_id = $vars[0];
206
            my $type = $remlinebreak[0];
207
208
            $sth->execute($pref_id, $type) or $count--;
209
            $count++;
210
        }
211
    }
212
213
    print "Restored $count preferences.\n";
214
215
}
(-)a/opac/opac-messaging.pl (-1 / +1 lines)
Lines 65-71 if ( defined $query->param('modify') && $query->param('modify') eq 'yes' ) { Link Here
65
        $borrower = GetMemberDetails( $borrowernumber );
65
        $borrower = GetMemberDetails( $borrowernumber );
66
    }
66
    }
67
67
68
    C4::Form::MessagingPreferences::handle_form_action($query, { borrowernumber => $borrowernumber }, $template);
68
    C4::Form::MessagingPreferences::handle_form_action($query, $borrower, $template);
69
}
69
}
70
70
71
C4::Form::MessagingPreferences::set_form_values({ borrowernumber     => $borrower->{'borrowernumber'} }, $template);
71
C4::Form::MessagingPreferences::set_form_values({ borrowernumber     => $borrower->{'borrowernumber'} }, $template);
(-)a/t/db_dependent/MessagingPreferencesValidation.t (-1 / +180 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/env perl
2
3
# Copyright 2015 Open Source Freedom Fighters
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
$ENV{KOHA_PAGEOBJECT_DEBUG} = 1;
20
use Modern::Perl;
21
22
use Test::More;
23
use Try::Tiny; #Even Selenium::Remote::Driver uses Try::Tiny :)
24
25
use Koha::Auth::PermissionManager;
26
27
use t::lib::Page::Mainpage;
28
use t::lib::Page::Opac::OpacMain;
29
use t::lib::Page::Opac::OpacMemberentry;
30
use t::lib::Page::Members::Memberentry;
31
use t::lib::Page::Members::Moremember;
32
33
use t::lib::TestObjects::BorrowerFactory;
34
use t::lib::TestObjects::SystemPreferenceFactory;
35
36
##Setting up the test context
37
my $testContext = {};
38
39
my $password = '1234';
40
my $borrowerFactory = t::lib::TestObjects::BorrowerFactory->new();
41
my $borrowers = $borrowerFactory->createTestGroup([
42
            {firstname  => 'Testone',
43
             surname    => 'Testtwo',
44
             cardnumber => '1A01',
45
             branchcode => 'CPL',
46
             userid     => 'normal_user',
47
             password   => $password,
48
            },
49
            {firstname  => 'Testthree',
50
             surname    => 'Testfour',
51
             cardnumber => 'superuberadmin',
52
             branchcode => 'CPL',
53
             userid     => 'god',
54
             password   => $password,
55
            },
56
        ], undef, $testContext);
57
58
my $systempreferences = t::lib::TestObjects::SystemPreferenceFactory->createTestGroup([
59
            {preference => 'ValidateEmailAddress',
60
             value      => 1
61
            },
62
            {preference => 'ValidatePhoneNumber',
63
             value      => 'ipn',
64
            },
65
            {preference => 'TalkingTechItivaPhoneNotification',
66
             value      => 1
67
            },
68
            {preference => 'SMSSendDriver',
69
             value      => 'test'
70
            },
71
        ], undef, $testContext);
72
73
my $permissionManager = Koha::Auth::PermissionManager->new();
74
$permissionManager->grantPermissions($borrowers->{'superuberadmin'}, {superlibrarian => 'superlibrarian'});
75
76
eval {
77
78
    # staff client
79
    my $memberentry = t::lib::Page::Members::Memberentry->new({borrowernumber => $borrowers->{'superuberadmin'}->borrowernumber, op => 'modify', destination => 'circ', categorycode => 'PT'});
80
    # opac
81
    my $main = t::lib::Page::Opac::OpacMain->new({borrowernumber => $borrowers->{'superuberadmin'}->borrowernumber});
82
83
    # set valid contacts and check preferences checkboxes
84
    $memberentry->doPasswordLogin($borrowers->{'superuberadmin'}->userid(), $password)
85
    ->setEmail("valid\@email.com")
86
    ->checkPreferences(1, "email")
87
    ->setPhone("+3585012345678")
88
    ->checkPreferences(1, "phone")
89
    ->setSMSNumber("+3585012345678")
90
    ->checkPreferences(1, "sms")
91
    ->submitForm(1) # expecting success
92
    ->navigateToDetails()
93
    # make sure everything is now checked on moremember.pl details page
94
    ->checkMessagingPreferencesSet(1, "email", "sms", "phone");
95
96
    $main # check that they are also checked in OPAC
97
    ->doPasswordLogin($borrowers->{'superuberadmin'}->userid(), $password)
98
    ->navigateYourMessaging()
99
    ->checkMessagingPreferencesSet(1, "email", "sms", "phone");
100
101
    # go to edit patron and set invalid contacts.
102
    $memberentry
103
    ->navigateEditPatron()
104
    ->setEmail("invalidemail.com")
105
    ->checkPreferences(0, "email")
106
    ->setPhone("+3585012asd345678")
107
    ->checkPreferences(0, "phone")
108
    ->setSMSNumber("+358501asd2345678")
109
    ->checkPreferences(0, "sms")
110
    # check messaging preferences: they should be unchecked
111
    ->checkMessagingPreferencesSet(0, "email", "sms", "phone")
112
    ->submitForm(0) # also confirm that we cant submit the preferences
113
    ->navigateToDetails()
114
115
    # go to library use and just simply submit the form without any changes
116
    ->navigateToLibraryUseEdit()
117
    ->submitForm(1)
118
    # all the preferences should be still set
119
    ->navigateToDetails()
120
    ->checkMessagingPreferencesSet(1, "email", "sms", "phone")
121
122
    # go to smsnumber edit and make sure everything is checked
123
    ->navigateToSMSnumberEdit()
124
    ->checkMessagingPreferencesSet(1, "email", "sms", "phone")
125
    ->submitForm(1)
126
    ->navigateToDetails()
127
    ->checkMessagingPreferencesSet(1, "email", "sms", "phone")
128
129
    # go to patron information edit and clear email and phone
130
    ->navigateToPatronInformationEdit()
131
    ->clearMessagingContactFields("email", "phone")
132
    ->submitForm(1)
133
    ->navigateToDetails()
134
    # this should remove our messaging preferences for phone and email
135
    ->checkMessagingPreferencesSet(0, "email", "phone")
136
    ->checkMessagingPreferencesSet(1, "sms"); # ... but not for sms (it's still set)
137
138
    $main # check the preferences also from OPAC
139
    ->navigateYourMessaging()
140
    ->checkMessagingPreferencesSet(0, "email", "phone")
141
    ->checkMessagingPreferencesSet(1, "sms");
142
143
    # go to smsnumber edit and see that email and phone are disabled
144
    $memberentry
145
    ->navigateToSMSnumberEdit()
146
    ->checkMessagingPreferencesSet(0, "email", "phone")
147
    ->clearMessagingContactFields("SMSnumber") # uncheck all sms preferences
148
    ->submitForm(1)
149
    ->navigateToDetails()
150
    ->checkMessagingPreferencesSet(0, "email", "phone", "sms");
151
152
    $main # check the preferences also from OPAC
153
    ->navigateYourMessaging()
154
    ->checkMessagingPreferencesSet(0, "email", "phone", "sms");
155
156
};
157
if ($@) { #Catch all leaking errors and gracefully terminate.
158
    warn $@;
159
    tearDown();
160
    exit 1;
161
}
162
163
##All tests done, tear down test context
164
tearDown();
165
done_testing;
166
167
sub tearDown {
168
    t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext);
169
}
170
171
172
173
174
175
176
177
178
######################################################
179
    ###  STARTING TEST IMPLEMENTATIONS         ###
180
######################################################

Return to bug 14590