From 70190be778bf8c1489d38f58725d8cfaf52ecf98 Mon Sep 17 00:00:00 2001 From: Lari Taskula Date: Fri, 21 Oct 2016 17:26:24 +0300 Subject: [PATCH] Bug 17499: Add Koha-objects for messaging preferences This patch adds Koha-objects for messaging preferences. Adds simple validation for messaging preferences. The validation includes - throw exception if both borrowernumber or categorycode is given for a new pref - throw exception if patron for the given borrowernumber is not found - throw exception if category for the given categorycode is not found - throw exception if days in advance cannot be configured but is given - throw exception if days in advance configuration is invalid (value between 0-30) - throw exception if digest is not available but attempted to set on - throw exception if digest must be enabled but attempted to set off - throw exception on duplicate messaging preference Adds a method for getting available messaging options. Adds a method for setting default messaging preferenes. $patron->set_default_messaging_preferences (where $patron is a Koha::Patron) ...or... Koha::Patron::Message::Preference->new_from_default({ borrowernumber => 123, categorycode => "ABC", message_attribute_id => 1, }); Since messaging preference is a feature that has multiple related database tables, usage via Koha-objects is sometimes frustrating. This patch adds easy access to message transport types via $preference->message_transport_types (for getting) $preference->set({ message_transport_types => ['email', 'sms'] }) (for setting) (also supports other calling conventions, see documentation for more) Adds optional parameter message_name for Koha::Patron::Message::Preferences->find and ->search. Simplifies the Koha-object usage by allowing developer to skip joins and / or querying the message name via attribute_id from message_attributes table. Includes test coverage for basic usage. To test: 1. prove t/db_dependent/Koha/Patron/Message/* Following Bug 17499, check also Bug 18595 that replaces C4::Members::Messaging with these new Koha-objects. Signed-off-by: Dominic Pichette --- ...4620-Contact-information-validations.patch | 648 +++++ ...ow-up-Link-URL-in-system-preference-.patch | 23 + ...Koha-objects-for-messaging-preferenc.patch | 2422 +++++++++++++++++ Koha/Exceptions.pm | 8 +- Koha/Patron.pm | 42 + Koha/Patron/Message/Attribute.pm | 50 + Koha/Patron/Message/Attributes.pm | 55 + Koha/Patron/Message/Preference.pm | 451 +++ Koha/Patron/Message/Preferences.pm | 146 + Koha/Patron/Message/Transport.pm | 50 + Koha/Patron/Message/Transport/Preference.pm | 51 + Koha/Patron/Message/Transport/Preferences.pm | 56 + Koha/Patron/Message/Transport/Type.pm | 51 + Koha/Patron/Message/Transport/Types.pm | 56 + Koha/Patron/Message/Transports.pm | 55 + ..._14620-Contact-information-validation.perl | 7 + .../Koha/Patron/Message/Attributes.t | 74 + .../Koha/Patron/Message/Preferences.t | 719 +++++ .../Patron/Message/Transport/Preferences.t | 179 ++ .../Koha/Patron/Message/Transport/Types.t | 54 + .../Koha/Patron/Message/Transports.t | 119 + 21 files changed, 5315 insertions(+), 1 deletion(-) create mode 100644 Bug-14620-Contact-information-validations.patch create mode 100644 Bug-14620-follow-up-Link-URL-in-system-preference-.patch create mode 100644 Bug-17499-Add-Koha-objects-for-messaging-preferenc.patch create mode 100644 Koha/Patron/Message/Attribute.pm create mode 100644 Koha/Patron/Message/Attributes.pm create mode 100644 Koha/Patron/Message/Preference.pm create mode 100644 Koha/Patron/Message/Preferences.pm create mode 100644 Koha/Patron/Message/Transport.pm create mode 100644 Koha/Patron/Message/Transport/Preference.pm create mode 100644 Koha/Patron/Message/Transport/Preferences.pm create mode 100644 Koha/Patron/Message/Transport/Type.pm create mode 100644 Koha/Patron/Message/Transport/Types.pm create mode 100644 Koha/Patron/Message/Transports.pm create mode 100644 installer/data/mysql/atomicupdate/Bug_14620-Contact-information-validation.perl create mode 100644 t/db_dependent/Koha/Patron/Message/Attributes.t create mode 100644 t/db_dependent/Koha/Patron/Message/Preferences.t create mode 100644 t/db_dependent/Koha/Patron/Message/Transport/Preferences.t create mode 100644 t/db_dependent/Koha/Patron/Message/Transport/Types.t create mode 100644 t/db_dependent/Koha/Patron/Message/Transports.t diff --git a/Bug-14620-Contact-information-validations.patch b/Bug-14620-Contact-information-validations.patch new file mode 100644 index 0000000000..85bf1d4a59 --- /dev/null +++ b/Bug-14620-Contact-information-validations.patch @@ -0,0 +1,648 @@ +From 42e664f126d763a63db655df9a6807113d0f3dde Mon Sep 17 00:00:00 2001 +From: Lari Taskula +Date: Tue, 4 Apr 2017 14:00:31 +0000 +Subject: [PATCH] Bug 14620: Contact information validations + +This patch adds a phone number validation by regex and centralizes +different validation methods into Koha::Validation class. + +Introduces a new system preference, ValidatePhoneNumber, that takes a +regular expression and uses it to validate phone numbers both client +and server side. + +Unit tests to test: +1. prove t/db_dependent/Koha/Validation.t + +To test: +1. Apply the patches and run updatedatabase.pl to install the new + system preference +2. Set system preference ValidatePhoneNumber to any regex you like + (there is an example in the description of the preference) +3. Navigate to edit user contact informations in Staff client and OPAC. +4. Insert invalid email (e.g. "invalid") and invalid phone number ("+123invalid") + and send the form. +5. Confirm that form will not be submitted and errors will be given. +6. Disable JavaScript and test that these errors will also be provided by the + server. +--- + Koha/Validation.pm | 80 ++++++++++++++++++++++ + .../Bug_14620-Contact-information-validation.perl | 7 ++ + installer/data/mysql/sysprefs.sql | 1 + + .../prog/en/modules/admin/preferences/patrons.pref | 9 +++ + .../prog/en/modules/members/memberentrygen.tt | 25 +++++++ + koha-tmpl/intranet-tmpl/prog/js/members.js | 28 ++++++++ + .../bootstrap/en/modules/opac-memberentry.tt | 37 ++++++++++ + .../bootstrap/en/modules/opac-messaging.tt | 44 ++++++++++++ + members/memberentry.pl | 32 +++++---- + opac/opac-memberentry.pl | 21 ++++-- + opac/opac-messaging.pl | 13 +++- + t/db_dependent/Koha/Validation.t | 76 ++++++++++++++++++++ + 12 files changed, 353 insertions(+), 20 deletions(-) + create mode 100644 Koha/Validation.pm + create mode 100644 installer/data/mysql/atomicupdate/Bug_14620-Contact-information-validation.perl + create mode 100644 t/db_dependent/Koha/Validation.t + +diff --git a/Koha/Validation.pm b/Koha/Validation.pm +new file mode 100644 +index 0000000000..94006d88bd +--- /dev/null ++++ b/Koha/Validation.pm +@@ -0,0 +1,80 @@ ++package Koha::Validation; ++ ++# Copyright 2017 Koha-Suomi Oy ++# ++# This file is part of Koha. ++# ++# Koha is free software; you can redistribute it and/or modify it under the ++# terms of the GNU General Public License as published by the Free Software ++# Foundation; either version 2 of the License, or (at your option) any later ++# version. ++# ++# Koha is distributed in the hope that it will be useful, but WITHOUT ANY ++# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ++# A PARTICULAR PURPOSE. See the GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License along ++# with Koha; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++use Modern::Perl; ++ ++use C4::Context; ++use Email::Valid; ++ ++=head1 NAME ++ ++Koha::Validation - validates inputs ++ ++=head1 SYNOPSIS ++ ++ use Koha::Validation ++ ++=head1 DESCRIPTION ++ ++This module lets you validate given inputs. ++ ++=head2 METHODS ++ ++=head3 email ++ ++Koha::Validation::email("email@address.com"); ++ ++Validates given email. ++ ++returns: 1 if the given email is valid (or empty), 0 otherwise. ++ ++=cut ++ ++sub email { ++ my $address = shift; ++ ++ return 1 unless $address; ++ return 0 if $address =~ /(^(\s))|((\s)$)/; ++ ++ return (not defined Email::Valid->address($address)) ? 0:1; ++} ++ ++=head3 phone ++ ++Koha::Validation::validate_phonenumber(123456789); ++ ++Validates given phone number. ++ ++returns: 1 if the given phone number is valid (or empty), 0 otherwise. ++ ++=cut ++ ++sub phone { ++ my $phonenumber = shift; ++ ++ return 1 unless $phonenumber; ++ return 0 if $phonenumber =~ /(^(\s))|((\s)$)/; ++ ++ my $regex = C4::Context->preference("ValidatePhoneNumber"); ++ $regex = qr/$regex/; ++ ++ return ($phonenumber !~ /$regex/) ? 0:1; ++} ++ ++1; +diff --git a/installer/data/mysql/atomicupdate/Bug_14620-Contact-information-validation.perl b/installer/data/mysql/atomicupdate/Bug_14620-Contact-information-validation.perl +new file mode 100644 +index 0000000000..d816b0ca80 +--- /dev/null ++++ b/installer/data/mysql/atomicupdate/Bug_14620-Contact-information-validation.perl +@@ -0,0 +1,7 @@ ++$DBversion = 'XXX'; # will be replaced by the RM ++if( CheckVersion( $DBversion ) ) { ++ $dbh->do("INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES ('ValidatePhoneNumber','','','Regex for validation of patron phone numbers.','Textarea')"); ++ ++ SetVersion( $DBversion ); ++ print "Upgrade to $DBversion done (Bug 14620 - description)\n"; ++} +diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql +index bc08b5a5d3..04bd7fd810 100644 +--- a/installer/data/mysql/sysprefs.sql ++++ b/installer/data/mysql/sysprefs.sql +@@ -576,6 +576,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` + ('UseQueryParser','0',NULL,'If enabled, try to use QueryParser for queries.','YesNo'), + ('UseTransportCostMatrix','0','','Use Transport Cost Matrix when filling holds','YesNo'), + ('UseWYSIWYGinSystemPreferences','0','','Show WYSIWYG editor when editing certain HTML system preferences.','YesNo'), ++('ValidatePhoneNumber','','','Regex for validation of patron phone numbers.','Textarea'), + ('viewISBD','1','','Allow display of ISBD view of bibiographic records','YesNo'), + ('viewLabeledMARC','0','','Allow display of labeled MARC view of bibiographic records','YesNo'), + ('viewMARC','1','','Allow display of MARC view of bibiographic records','YesNo'), +diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref +index 3a95ba71aa..867bfe45e7 100644 +--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref ++++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref +@@ -219,3 +219,12 @@ Patrons: + - pref: FailedLoginAttempts + class: integer + - failed login attempts. ++ - ++ - Use the following regex / ++ - pref: ValidatePhoneNumber ++ type: textarea ++ class: code ++ - / to validate patrons' phone numbers. ++ - Example ^((\+)?[1-9]{1,2})?([-\s\.])?((\(\d{1,4}\))|\d{1,4})(([-\s\.])?[0-9]{1,12}){1,2}$ ++ - (Source of example http://regexlib.com/REDetails.aspx?regexp_id=3009) ++ - Leave blank to accept any phone number. +diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt +index 091486efca..874da57ace 100644 +--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt ++++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt +@@ -62,6 +62,19 @@ $(document).ready(function() { + $(".toggler").toggle(); + }); + ++ ++ var MSG_INCORRECT_PHONE = _("Please enter a valid phone number."); ++ $.validator.addMethod('phone', function(value) { ++ value = value.trim(); ++ if (!value.trim()) { ++ return 1; ++ } ++ else { ++ return (value.match(/[% ValidatePhoneNumber %]/)); ++ } ++ }, ++ MSG_INCORRECT_PHONE); ++ + $("#save_quick_add").click(function(){ + $("#quick_add_form").validate(); + if( $("#quick_add_form").valid()){ +@@ -201,6 +214,18 @@ $(document).ready(function() { + [% IF ERROR_bad_email_alternative %] +
  • The alternative email is invalid.
  • + [% END %] ++ [% IF ERROR_bad_phone %] ++
  • The primary phone is invalid.
  • ++ [% END %] ++ [% IF ERROR_bad_phone_secondary %] ++
  • The secondary phone is invalid.
  • ++ [% END %] ++ [% IF ERROR_bad_phone_alternative %] ++
  • The alternative phone is invalid.
  • ++ [% END %] ++ [% IF ERROR_bad_smsnumber %] ++
  • The SMS number is invalid.
  • ++ [% END %] + + + [% END %] +diff --git a/koha-tmpl/intranet-tmpl/prog/js/members.js b/koha-tmpl/intranet-tmpl/prog/js/members.js +index 2ced2eca8b..bfb8376820 100644 +--- a/koha-tmpl/intranet-tmpl/prog/js/members.js ++++ b/koha-tmpl/intranet-tmpl/prog/js/members.js +@@ -333,6 +333,21 @@ $(document).ready(function(){ + }, + B_email: { + email: true ++ }, ++ phone: { ++ phone: true ++ }, ++ phonepro: { ++ phone: true ++ }, ++ mobile: { ++ phone: true ++ }, ++ SMSnumber: { ++ phone: true ++ }, ++ B_phone: { ++ phone: true + } + }, + submitHandler: function(form) { +@@ -341,10 +356,23 @@ $(document).ready(function(){ + return false; + else + form.beenSubmitted = true; ++ $("#email, #emailpro, #B_email").each(function(){ ++ $(this).val($.trim($(this).val())); ++ }); ++ $("#phone, #phonepro, #B_phone, #SMSnumber").each(function(){ ++ $(this).val($.trim($(this).val())); ++ }); + form.submit(); + } + }); + ++ $("#email, #emailpro, #B_email").each(function(){ ++ $(this).val($.trim($(this).val())); ++ }); ++ $("#phone, #phonepro, #B_phone, #SMSnumber").each(function(){ ++ $(this).val($.trim($(this).val())); ++ }); ++ + var mrform = $("#manual_restriction_form"); + var mrlink = $("#add_manual_restriction"); + mrform.hide(); +diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt +index d3b89bfdbb..efa392235d 100644 +--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt ++++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt +@@ -64,6 +64,10 @@ + [% IF field == "email" %]
  • Contact information: primary email address
  • [% END %] + [% IF field == "emailpro" %]
  • Contact information: secondary email address
  • [% END %] + [% IF field == "B_email" %]
  • Alternate address information: email address
  • [% END %] ++ [% IF field == "phone" %]
  • Contact information: primary phone
  • [% END %] ++ [% IF field == "phonepro" %]
  • Contact information: secondary phone
  • [% END %] ++ [% IF field == "mobile" %]
  • Contact information: other phone
  • [% END %] ++ [% IF field == "B_phone" %]
  • Alternate address information: phone
  • [% END %] + [% IF field == "password_match" %]
  • Passwords do not match! password
  • [% END %] + [% IF field == "password_invalid" %]
  • Password does not meet minimum requirements! password
  • [% END %] + [% IF field == "password_spaces" %]
  • Password contains leading and/or trailing spaces! password
  • [% END %] +@@ -943,6 +947,17 @@ + $('label.required').removeClass('required'); + [% END %] + ++ var MSG_INCORRECT_PHONE = _("Please enter a valid phone number."); ++ $.validator.addMethod('phone', function(value) { ++ if (!value.trim()) { ++ return 1; ++ } ++ else { ++ return (value.match(/[% ValidatePhoneNumber %]/)); ++ } ++ }, ++ MSG_INCORRECT_PHONE); ++ + $("#memberentry-form").validate({ + rules: { + borrower_email: { +@@ -953,6 +968,18 @@ + }, + borrower_B_email: { + email: true ++ }, ++ borrower_phone: { ++ phone: true ++ }, ++ borrower_phonepro: { ++ phone: true ++ }, ++ borrower_mobile: { ++ phone: true ++ }, ++ borrower_B_phone: { ++ phone: true + } + }, + submitHandler: function(form) { +@@ -961,6 +988,12 @@ + } + else { + form.beenSubmitted = true; ++ $("#borrower_email, #borrower_emailpro, #borrower_B_email").each(function(){ ++ $(this).val($.trim($(this).val())); ++ }); ++ $("#borrower_phone, #borrower_phonepro, #borrower_B_phone").each(function(){ ++ $(this).val($.trim($(this).val())); ++ }); + form.submit(); + } + }, +@@ -975,6 +1008,10 @@ + } + }); + ++ $("#borrower_email, #borrower_emailpro, #borrower_B_email, #borrower_phone, #borrower_phonepro, #borrower_B_phone").on("change", function(){ ++ $(this).val($.trim($(this).val())); ++ }); ++ + [% IF borrower.guarantorid && !Koha.Preference('OPACPrivacy') && Koha.Preference('AllowPatronToSetCheckoutsVisibilityForGuarantor') %] + $('#update_privacy_guarantor_checkouts').click( function() { + $.post( "/cgi-bin/koha/svc/patron/show_checkouts_to_relatives", { privacy_guarantor_checkouts: $('#privacy_guarantor_checkouts').val() }, null, 'json') +diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-messaging.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-messaging.tt +index 801389c97c..a28918f6ba 100644 +--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-messaging.tt ++++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-messaging.tt +@@ -28,6 +28,9 @@ + [% IF ( settings_updated ) %] +

    Settings updated

    + [% END %] ++ [% IF ( invalid_smsnumber ) %] ++

    Invalid SMS number

    ++ [% END %] +
    + + +@@ -184,7 +187,48 @@ + } + }); + $("#info_digests").tooltip(); ++ ++ var MSG_INCORRECT_PHONE = _("Please enter a valid phone number."); ++ $.validator.addMethod('phone', function(value) { ++ if (!value.trim()) { ++ return 1; ++ } ++ else { ++ return (value.match(/[% ValidatePhoneNumber %]/)); ++ } ++ }, ++ MSG_INCORRECT_PHONE); ++ ++ $("form[name='opacmessaging']").validate({ ++ rules: { ++ SMSnumber: { ++ phone: true ++ } ++ }, ++ submitHandler: function(form) { ++ $("body, form input[type='submit'], form button[type='submit'], form a").addClass('waiting'); ++ if (form.beenSubmitted) { ++ return false; ++ } ++ else { ++ form.beenSubmitted = true; ++ $("#SMSnumber").each(function(){ ++ $(this).val($.trim($(this).val())); ++ }); ++ form.submit(); ++ } ++ }, ++ errorPlacement: function(error, element) { ++ error.insertAfter(element.closest("li")).wrap('
  • '); ++ error.addClass('alert-error'); ++ error.width("auto"); ++ } ++ }); ++ $("#SMSnumber").on("change", function(){ ++ $(this).val($.trim($(this).val())); ++ }); + }); + //]]> + ++ + [% END %] +diff --git a/members/memberentry.pl b/members/memberentry.pl +index c58b2a9bff..24857089fa 100755 +--- a/members/memberentry.pl ++++ b/members/memberentry.pl +@@ -47,7 +47,7 @@ use Koha::Patron::Categories; + use Koha::Patron::HouseboundRole; + use Koha::Patron::HouseboundRoles; + use Koha::Token; +-use Email::Valid; ++use Koha::Validation; + use Module::Load; + if ( C4::Context->preference('NorwegianPatronDBEnable') && C4::Context->preference('NorwegianPatronDBEnable') == 1 ) { + load Koha::NorwegianPatronDB, qw( NLGetSyncDataFromBorrowernumber ); +@@ -363,19 +363,13 @@ if ($op eq 'save' || $op eq 'insert'){ + push @errors, "ERROR_short_password" if( $password && $minpw && $password ne '****' && (length($password) < $minpw) ); + + # Validate emails +- my $emailprimary = $input->param('email'); +- my $emailsecondary = $input->param('emailpro'); +- my $emailalt = $input->param('B_email'); +- +- if ($emailprimary) { +- push (@errors, "ERROR_bad_email") if (!Email::Valid->address($emailprimary)); +- } +- if ($emailsecondary) { +- push (@errors, "ERROR_bad_email_secondary") if (!Email::Valid->address($emailsecondary)); +- } +- if ($emailalt) { +- push (@errors, "ERROR_bad_email_alternative") if (!Email::Valid->address($emailalt)); +- } ++ push (@errors, "ERROR_bad_email") if ($input->param('email') && !Koha::Validation::email($input->param('email'))); ++ push (@errors, "ERROR_bad_email_secondary") if ($input->param('emailpro') && !Koha::Validation::email($input->param('emailpro'))); ++ push (@errors, "ERROR_bad_email_alternative") if ($input->param('B_email') && !Koha::Validation::email($input->param('B_email'))); ++ # Validate phone numbers ++ push (@errors, "ERROR_bad_phone") if ($input->param('phone') && !Koha::Validation::phone($input->param('phone'))); ++ push (@errors, "ERROR_bad_phone_secondary") if ($input->param('phonepro') && !Koha::Validation::phone($input->param('phonepro'))); ++ push (@errors, "ERROR_bad_phone_alternative") if ($input->param('B_phone') && !Koha::Validation::phone($input->param('B_phone'))); + + if (C4::Context->preference('ExtendedPatronAttributes')) { + $extended_patron_attributes = parse_extended_patron_attributes($input); +@@ -403,7 +397,11 @@ if ( ($op eq 'modify' || $op eq 'insert' || $op eq 'save'|| $op eq 'duplicate') + # BZ 14683: Do not mixup mobile [read: other phone] with smsalertnumber + my $sms = $input->param('SMSnumber'); + if ( defined $sms ) { +- $newdata{smsalertnumber} = $sms; ++ if (Koha::Validation::phone($sms)){ ++ $newdata{smsalertnumber} = $sms; ++ } else { ++ push (@errors, "ERROR_bad_smsnumber"); ++ } + } + + ### Error checks should happen before this line. +@@ -720,6 +718,10 @@ if (C4::Context->preference('ExtendedPatronAttributes')) { + patron_attributes_form($template, $borrowernumber); + } + ++$template->param( ++ ValidatePhoneNumber => C4::Context->preference('ValidatePhoneNumber') || '.*', ++); ++ + if (C4::Context->preference('EnhancedMessagingPreferences')) { + if ($op eq 'add') { + C4::Form::MessagingPreferences::set_form_values({ categorycode => $categorycode }, $template); +diff --git a/opac/opac-memberentry.pl b/opac/opac-memberentry.pl +index 9784a3deef..7dba2d9575 100755 +--- a/opac/opac-memberentry.pl ++++ b/opac/opac-memberentry.pl +@@ -29,7 +29,6 @@ use C4::Members; + use C4::Members::Attributes qw( GetBorrowerAttributes ); + use C4::Form::MessagingPreferences; + use C4::Scrubber; +-use Email::Valid; + use Koha::DateUtils; + use Koha::Libraries; + use Koha::Patron::Attribute::Types; +@@ -39,6 +38,7 @@ use Koha::Patron::Modification; + use Koha::Patron::Modifications; + use Koha::Patrons; + use Koha::Token; ++use Koha::Validation; + + my $cgi = new CGI; + my $dbh = C4::Context->dbh; +@@ -88,6 +88,7 @@ $template->param( + mandatory => $mandatory, + libraries => \@libraries, + OPACPatronDetails => C4::Context->preference('OPACPatronDetails'), ++ ValidatePhoneNumber => C4::Context->preference('ValidatePhoneNumber') || '.*', + ); + + my $attributes = ParsePatronAttributes($borrowernumber,$cgi); +@@ -390,7 +391,7 @@ sub CheckForInvalidFields { + my $borrower = shift; + my @invalidFields; + if ($borrower->{'email'}) { +- unless ( Email::Valid->address($borrower->{'email'}) ) { ++ unless ( Koha::Validation::email($borrower->{'email'}) ) { + push(@invalidFields, "email"); + } elsif ( C4::Context->preference("PatronSelfRegistrationEmailMustBeUnique") ) { + my $patrons_with_same_email = Koha::Patrons->search( +@@ -410,10 +411,22 @@ sub CheckForInvalidFields { + } + } + if ($borrower->{'emailpro'}) { +- push(@invalidFields, "emailpro") if (!Email::Valid->address($borrower->{'emailpro'})); ++ push(@invalidFields, "emailpro") if (!Koha::Validation::email($borrower->{'emailpro'})); + } + if ($borrower->{'B_email'}) { +- push(@invalidFields, "B_email") if (!Email::Valid->address($borrower->{'B_email'})); ++ push(@invalidFields, "B_email") if (!Koha::Validation::email($borrower->{'B_email'})); ++ } ++ if ($borrower->{'mobile'}) { ++ push(@invalidFields, "mobile") if (!Koha::Validation::phone($borrower->{'mobile'})); ++ } ++ if ($borrower->{'phone'}) { ++ push(@invalidFields, "phone") if (!Koha::Validation::phone($borrower->{'phone'})); ++ } ++ if ($borrower->{'phonepro'}) { ++ push(@invalidFields, "phonepro") if (!Koha::Validation::phone($borrower->{'phonepro'})); ++ } ++ if ($borrower->{'B_phone'}) { ++ push(@invalidFields, "B_phone") if (!Koha::Validation::phone($borrower->{'B_phone'})); + } + if ( defined $borrower->{'password'} + and $borrower->{'password'} ne $borrower->{'password2'} ) +diff --git a/opac/opac-messaging.pl b/opac/opac-messaging.pl +index 906d56fe4e..f360b4bcd7 100755 +--- a/opac/opac-messaging.pl ++++ b/opac/opac-messaging.pl +@@ -31,6 +31,7 @@ use C4::Members; + use C4::Members::Messaging; + use C4::Form::MessagingPreferences; + use Koha::SMS::Providers; ++use Koha::Validation; + + my $query = CGI->new(); + +@@ -53,10 +54,20 @@ my ( $template, $borrowernumber, $cookie ) = get_template_and_user( + my $borrower = Koha::Patrons->find( $borrowernumber )->unblessed; + my $messaging_options = C4::Members::Messaging::GetMessagingOptions(); + ++my $validate_phone = C4::Context->preference('ValidatePhoneNumber'); ++ ++$template->param( ++ ValidatePhoneNumber => $validate_phone || '.*', ++); ++ + if ( defined $query->param('modify') && $query->param('modify') eq 'yes' ) { + my $sms = $query->param('SMSnumber'); + my $sms_provider_id = $query->param('sms_provider_id'); +- if ( defined $sms && ( $borrower->{'smsalertnumber'} // '' ) ne $sms ++ ++ my $valid_sms = Koha::Validation::phone($sms); ++ $template->param( invalid_smsnumber => 1 ) unless $valid_sms; ++ ++ if ( defined $sms && $valid_sms && ( $borrower->{'smsalertnumber'} // '' ) ne $sms + or ( $borrower->{sms_provider_id} // '' ) ne $sms_provider_id ) { + ModMember( + borrowernumber => $borrowernumber, +diff --git a/t/db_dependent/Koha/Validation.t b/t/db_dependent/Koha/Validation.t +new file mode 100644 +index 0000000000..481ea8583d +--- /dev/null ++++ b/t/db_dependent/Koha/Validation.t +@@ -0,0 +1,76 @@ ++#!/usr/bin/perl ++# ++# Copyright 2017 Koha-Suomi Oy ++# ++# This file is part of Koha. ++# ++# Koha is free software; you can redistribute it and/or modify it under the ++# terms of the GNU General Public License as published by the Free Software ++# Foundation; either version 3 of the License, or (at your option) any later ++# version. ++# ++# Koha is distributed in the hope that it will be useful, but WITHOUT ANY ++# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ++# A PARTICULAR PURPOSE. See the GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License along ++# with Koha; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++use Modern::Perl; ++ ++use Test::More tests => 3; ++ ++use t::lib::Mocks; ++ ++BEGIN { ++ use_ok('Koha::Validation'); ++} ++ ++subtest 'email() tests' => sub { ++ plan tests => 2; ++ ++ is(Koha::Validation::email('test'), 0, "'test' is invalid e-mail address'"); ++ is(Koha::Validation::email('test@example.com'), 1, '\'test@example.com\' is ' ++ .'valid e-mail address'); ++}; ++ ++subtest 'phone() tests' => sub { ++ plan tests => 3; ++ ++ t::lib::Mocks::mock_preference('ValidatePhoneNumber', ''); ++ ++ is(Koha::Validation::phone('test'), 1, 'Phone number validation is switched ' ++ .'off, so \'test\' is a valid phone number'); ++ ++ # An example: Finnish Phone number validation regex ++ subtest 'Finnish phone number validation regex' => sub { ++ t::lib::Mocks::mock_preference('ValidatePhoneNumber', ++ '^((90[0-9]{3})?0|\+358\s?)(?!(100|20(0|2(0|[2-3])|9[8-9])|300|600|70' ++ .'0|708|75(00[0-3]|(1|2)\d{2}|30[0-2]|32[0-2]|75[0-2]|98[0-2])))(4|50|' ++ .'10[1-9]|20(1|2(1|[4-9])|[3-9])|29|30[1-9]|71|73|75(00[3-9]|30[3-9]|3' ++ .'2[3-9]|53[3-9]|83[3-9])|2|3|5|6|8|9|1[3-9])\s?(\d\s?){4,19}\d$' ++ ); ++ ++ is(Koha::Validation::phone('1234'), 0, '1234 is invalid phone number.'); ++ is(Koha::Validation::phone('+358501234567'), 1, '+358501234567 is valid ' ++ .'phone number.'); ++ is(Koha::Validation::phone('+1-202-555-0198'), 0, '+1-202-555-0198 is ' ++ .'invalid phone number.'); ++ }; ++ ++ subtest 'International phone number validation regex' => sub { ++ t::lib::Mocks::mock_preference('ValidatePhoneNumber', ++ '^((\+)?[1-9]{1,2})?([-\s\.])?((\(\d{1,4}\))|\d{1,4})(([-\s\.])?[0-9]' ++ .'{1,12}){1,2}$' ++ ); ++ ++ is(Koha::Validation::phone('nope'), 0, 'nope is invalid phone number.'); ++ is(Koha::Validation::phone('1234'), 1, '1234 is valid phone number.'); ++ is(Koha::Validation::phone('+358501234567'), 1, '+358501234567 is valid ' ++ .'phone number.'); ++ is(Koha::Validation::phone('+1-202-555-0198'), 1, '+1-202-555-0198 is ' ++ .'valid phone number.'); ++ }; ++ ++}; +-- +2.11.0 \ No newline at end of file diff --git a/Bug-14620-follow-up-Link-URL-in-system-preference-.patch b/Bug-14620-follow-up-Link-URL-in-system-preference-.patch new file mode 100644 index 0000000000..27daa54007 --- /dev/null +++ b/Bug-14620-follow-up-Link-URL-in-system-preference-.patch @@ -0,0 +1,23 @@ +From 820a58e04f9ee72a9c1144ad4d5191894c3f57e8 Mon Sep 17 00:00:00 2001 +From: Katrin Fischer +Date: Sat, 7 Oct 2017 23:40:24 +0200 +Subject: [PATCH] Bug 14620: (follow-up) Link URL in system preference + description + +--- + koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref +index 867bfe45e7..e9efda3cb4 100644 +--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref ++++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref +@@ -226,5 +226,5 @@ Patrons: + class: code + - / to validate patrons' phone numbers. + - Example ^((\+)?[1-9]{1,2})?([-\s\.])?((\(\d{1,4}\))|\d{1,4})(([-\s\.])?[0-9]{1,12}){1,2}$ +- - (Source of example http://regexlib.com/REDetails.aspx?regexp_id=3009) ++ - (Source of example RegExLib.com) + - Leave blank to accept any phone number. +-- +2.11.0 \ No newline at end of file diff --git a/Bug-17499-Add-Koha-objects-for-messaging-preferenc.patch b/Bug-17499-Add-Koha-objects-for-messaging-preferenc.patch new file mode 100644 index 0000000000..74f605b0b0 --- /dev/null +++ b/Bug-17499-Add-Koha-objects-for-messaging-preferenc.patch @@ -0,0 +1,2422 @@ +From 5cb18bd6b778730cd86e44f2920e75b167854b3c Mon Sep 17 00:00:00 2001 +From: Lari Taskula +Date: Fri, 21 Oct 2016 17:26:24 +0300 +Subject: [PATCH] Bug 17499: Add Koha-objects for messaging preferences + +This patch adds Koha-objects for messaging preferences. + +Adds simple validation for messaging preferences. + +The validation includes +- throw exception if both borrowernumber or categorycode is given for a new pref +- throw exception if patron for the given borrowernumber is not found +- throw exception if category for the given categorycode is not found +- throw exception if days in advance cannot be configured but is given +- throw exception if days in advance configuration is invalid (value between 0-30) +- throw exception if digest is not available but attempted to set on +- throw exception if digest must be enabled but attempted to set off +- throw exception on duplicate messaging preference + +Adds a method for getting available messaging options. + +Adds a method for setting default messaging preferenes. + $patron->set_default_messaging_preferences (where $patron is a Koha::Patron) + ...or... + Koha::Patron::Message::Preference->new_from_default({ + borrowernumber => 123, + categorycode => "ABC", + message_attribute_id => 1, + }); + +Since messaging preference is a feature that has multiple related database tables, +usage via Koha-objects is sometimes frustrating. This patch adds easy access to +message transport types via + $preference->message_transport_types (for getting) + $preference->set({ message_transport_types => ['email', 'sms'] }) (for setting) + (also supports other calling conventions, see documentation for more) + +Adds optional parameter message_name for Koha::Patron::Message::Preferences->find +and ->search. Simplifies the Koha-object usage by allowing developer to skip joins +and / or querying the message name via attribute_id from message_attributes table. + +Includes test coverage for basic usage. + +To test: +1. prove t/db_dependent/Koha/Patron/Message/* + +Following Bug 17499, check also Bug 18595 that replaces C4::Members::Messaging +with these new Koha-objects. + +Signed-off-by: Dominic Pichette +--- + Koha/Exceptions.pm | 8 +- + Koha/Patron.pm | 42 ++ + Koha/Patron/Message/Attribute.pm | 50 ++ + Koha/Patron/Message/Attributes.pm | 55 ++ + Koha/Patron/Message/Preference.pm | 451 +++++++++++++ + Koha/Patron/Message/Preferences.pm | 146 +++++ + Koha/Patron/Message/Transport.pm | 50 ++ + Koha/Patron/Message/Transport/Preference.pm | 51 ++ + Koha/Patron/Message/Transport/Preferences.pm | 56 ++ + Koha/Patron/Message/Transport/Type.pm | 51 ++ + Koha/Patron/Message/Transport/Types.pm | 56 ++ + Koha/Patron/Message/Transports.pm | 55 ++ + t/db_dependent/Koha/Patron/Message/Attributes.t | 74 +++ + t/db_dependent/Koha/Patron/Message/Preferences.t | 719 +++++++++++++++++++++ + .../Koha/Patron/Message/Transport/Preferences.t | 179 +++++ + .../Koha/Patron/Message/Transport/Types.t | 54 ++ + t/db_dependent/Koha/Patron/Message/Transports.t | 119 ++++ + 17 files changed, 2215 insertions(+), 1 deletion(-) + create mode 100644 Koha/Patron/Message/Attribute.pm + create mode 100644 Koha/Patron/Message/Attributes.pm + create mode 100644 Koha/Patron/Message/Preference.pm + create mode 100644 Koha/Patron/Message/Preferences.pm + create mode 100644 Koha/Patron/Message/Transport.pm + create mode 100644 Koha/Patron/Message/Transport/Preference.pm + create mode 100644 Koha/Patron/Message/Transport/Preferences.pm + create mode 100644 Koha/Patron/Message/Transport/Type.pm + create mode 100644 Koha/Patron/Message/Transport/Types.pm + create mode 100644 Koha/Patron/Message/Transports.pm + create mode 100644 t/db_dependent/Koha/Patron/Message/Attributes.t + create mode 100644 t/db_dependent/Koha/Patron/Message/Preferences.t + create mode 100644 t/db_dependent/Koha/Patron/Message/Transport/Preferences.t + create mode 100644 t/db_dependent/Koha/Patron/Message/Transport/Types.t + create mode 100644 t/db_dependent/Koha/Patron/Message/Transports.t + +diff --git a/Koha/Exceptions.pm b/Koha/Exceptions.pm +index 528a151..c212653 100644 +--- a/Koha/Exceptions.pm ++++ b/Koha/Exceptions.pm +@@ -27,7 +27,13 @@ use Exception::Class ( + }, + 'Koha::Exceptions::MissingParameter' => { + isa => 'Koha::Exceptions::Exception', +- description => 'A required parameter is missing' ++ description => 'A required parameter is missing', ++ fields => ['parameter'], ++ }, ++ 'Koha::Exceptions::TooManyParameters' => { ++ isa => 'Koha::Exceptions::Exception', ++ description => 'Too many parameters given', ++ fields => ['parameter'], + }, + 'Koha::Exceptions::WrongParameter' => { + isa => 'Koha::Exceptions::Exception', +diff --git a/Koha/Patron.pm b/Koha/Patron.pm +index daa972c..a00f05c 100644 +--- a/Koha/Patron.pm ++++ b/Koha/Patron.pm +@@ -33,6 +33,7 @@ use Koha::Patron::Categories; + use Koha::Patron::HouseboundProfile; + use Koha::Patron::HouseboundRole; + use Koha::Patron::Images; ++use Koha::Patron::Message::Preferences; + use Koha::Patrons; + use Koha::Virtualshelves; + use Koha::Club::Enrollments; +@@ -656,6 +657,47 @@ sub account_locked { + and $self->login_attempts >= $FailedLoginAttempts )? 1 : 0; + } + ++=head3 set_default_messaging_preferences ++ ++ $patron->set_default_messaging_preferences ++ ++Sets default messaging preferences on patron. ++ ++See Koha::Patron::Message::Preference(s) for more documentation, especially on ++thrown exceptions. ++ ++=cut ++ ++sub set_default_messaging_preferences { ++ my ($self, $categorycode) = @_; ++ ++ my $options = Koha::Patron::Message::Preferences->get_options; ++ ++ foreach my $option (@$options) { ++ # Check that this option has preference configuration for this category ++ unless (Koha::Patron::Message::Preferences->search({ ++ message_attribute_id => $option->{message_attribute_id}, ++ categorycode => $categorycode || $self->categorycode, ++ })->count) { ++ next; ++ } ++ ++ # Delete current setting ++ Koha::Patron::Message::Preferences->search({ ++ borrowernumber => $self->borrowernumber, ++ message_attribute_id => $option->{message_attribute_id}, ++ })->delete; ++ ++ Koha::Patron::Message::Preference->new_from_default({ ++ borrowernumber => $self->borrowernumber, ++ categorycode => $categorycode || $self->categorycode, ++ message_attribute_id => $option->{message_attribute_id}, ++ }); ++ } ++ ++ return $self; ++} ++ + =head3 type + + =cut +diff --git a/Koha/Patron/Message/Attribute.pm b/Koha/Patron/Message/Attribute.pm +new file mode 100644 +index 0000000..9d9004c +--- /dev/null ++++ b/Koha/Patron/Message/Attribute.pm +@@ -0,0 +1,50 @@ ++package Koha::Patron::Message::Attribute; ++ ++# Copyright Koha-Suomi Oy 2016 ++# ++# This file is part of Koha. ++# ++# Koha is free software; you can redistribute it and/or modify it under the ++# terms of the GNU General Public License as published by the Free Software ++# Foundation; either version 3 of the License, or (at your option) any later ++# version.a ++# ++# Koha is distributed in the hope that it will be useful, but WITHOUT ANY ++# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ++# A PARTICULAR PURPOSE. See the GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License along ++# with Koha; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++use Modern::Perl; ++ ++use Koha::Database; ++ ++use base qw(Koha::Object); ++ ++=head1 NAME ++ ++Koha::Patron::Message::Attribute - Koha Patron Message Attribute object class ++ ++=head1 API ++ ++=head2 Class Methods ++ ++=cut ++ ++=head3 type ++ ++=cut ++ ++sub _type { ++ return 'MessageAttribute'; ++} ++ ++=head1 AUTHOR ++ ++Lari Taskula ++ ++=cut ++ ++1; +diff --git a/Koha/Patron/Message/Attributes.pm b/Koha/Patron/Message/Attributes.pm +new file mode 100644 +index 0000000..a2df4e6 +--- /dev/null ++++ b/Koha/Patron/Message/Attributes.pm +@@ -0,0 +1,55 @@ ++package Koha::Patron::Message::Attributes; ++ ++# Copyright Koha-Suomi Oy 2016 ++# ++# This file is part of Koha. ++# ++# Koha is free software; you can redistribute it and/or modify it under the ++# terms of the GNU General Public License as published by the Free Software ++# Foundation; either version 3 of the License, or (at your option) any later ++# version. ++# ++# Koha is distributed in the hope that it will be useful, but WITHOUT ANY ++# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ++# A PARTICULAR PURPOSE. See the GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License along ++# with Koha; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++use Modern::Perl; ++ ++use Koha::Database; ++use Koha::Patron::Message::Attribute; ++ ++use base qw(Koha::Objects); ++ ++=head1 NAME ++ ++Koha::Patron::Message::Attributes - Koha Patron Message Attributes object class ++ ++=head1 API ++ ++=head2 Class Methods ++ ++=cut ++ ++=head3 type ++ ++=cut ++ ++sub _type { ++ return 'MessageAttribute'; ++} ++ ++sub object_class { ++ return 'Koha::Patron::Message::Attribute'; ++} ++ ++=head1 AUTHOR ++ ++Lari Taskula ++ ++=cut ++ ++1; +diff --git a/Koha/Patron/Message/Preference.pm b/Koha/Patron/Message/Preference.pm +new file mode 100644 +index 0000000..db96b2a +--- /dev/null ++++ b/Koha/Patron/Message/Preference.pm +@@ -0,0 +1,451 @@ ++package Koha::Patron::Message::Preference; ++ ++# Copyright Koha-Suomi Oy 2016 ++# ++# This file is part of Koha. ++# ++# Koha is free software; you can redistribute it and/or modify it under the ++# terms of the GNU General Public License as published by the Free Software ++# Foundation; either version 3 of the License, or (at your option) any later ++# version.a ++# ++# Koha is distributed in the hope that it will be useful, but WITHOUT ANY ++# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ++# A PARTICULAR PURPOSE. See the GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License along ++# with Koha; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++use Modern::Perl; ++ ++use Koha::Database; ++use Koha::Exceptions; ++use Koha::Patron::Categories; ++use Koha::Patron::Message::Attributes; ++use Koha::Patron::Message::Preferences; ++use Koha::Patron::Message::Transport::Preferences; ++use Koha::Patron::Message::Transport::Types; ++use Koha::Patron::Message::Transports; ++use Koha::Patrons; ++ ++use base qw(Koha::Object); ++ ++=head1 NAME ++ ++Koha::Patron::Message::Preference - Koha Patron Message Preference object class ++ ++=head1 API ++ ++=head2 Class Methods ++ ++=cut ++ ++=head3 new ++ ++my $preference = Koha::Patron::Message::Preference->new({ ++ borrowernumber => 123, ++ #categorycode => 'ABC', ++ message_attribute_id => 4, ++ message_transport_types => ['email', 'sms'], # see documentation below ++ wants_digest => 1, ++ days_in_advance => 7, ++}); ++ ++Takes either borrowernumber or categorycode, but not both. ++ ++days_in_advance may not be available. See message_attributes table for takes_days ++configuration. ++ ++wants_digest may not be available. See message_transports table for is_digest ++configuration. ++ ++You can instantiate a new object without custom validation errors, but when ++storing, validation may throw exceptions. See C for more ++documentation. ++ ++C is a parameter that is not actually a column in this ++Koha-object. Given this parameter, the message transport types will be added as ++related transport types for this object. For get and set, you can access them via ++subroutine C in this class. ++ ++=cut ++ ++sub new { ++ my ($class, $params) = @_; ++ ++ my $types = $params->{'message_transport_types'}; ++ delete $params->{'message_transport_types'}; ++ ++ my $self = $class->SUPER::new($params); ++ ++ $self->_set_message_transport_types($types); ++ ++ return $self; ++} ++ ++=head3 new_from_default ++ ++my $preference = Koha::Patron::Message::Preference->new_from_default({ ++ borrowernumber => 123, ++ categorycode => 'ABC', # if not given, patron's categorycode will be used ++ message_attribute_id => 1, ++}); ++ ++NOTE: This subroutine initializes and STORES the object (in order to set ++message transport types for the preference), so no need to call ->store when ++preferences are initialized via this method. ++ ++Stores default messaging preference for C to patron for given ++C. ++ ++Throws Koha::Exceptions::MissingParameter if any of following is missing: ++- borrowernumber ++- message_attribute_id ++ ++Throws Koha::Exceptions::ObjectNotFound if default preferences are not found. ++ ++=cut ++ ++sub new_from_default { ++ my ($class, $params) = @_; ++ ++ my @required = qw(borrowernumber message_attribute_id); ++ foreach my $p (@required) { ++ Koha::Exceptions::MissingParameter->throw( ++ error => 'Missing required parameter.', ++ parameter => $p, ++ ) unless exists $params->{$p}; ++ } ++ unless ($params->{'categorycode'}) { ++ my $patron = Koha::Patrons->find($params->{borrowernumber}); ++ $params->{'categorycode'} = $patron->categorycode; ++ } ++ ++ my $default = Koha::Patron::Message::Preferences->find({ ++ categorycode => $params->{'categorycode'}, ++ message_attribute_id => $params->{'message_attribute_id'}, ++ }); ++ Koha::Exceptions::ObjectNotFound->throw( ++ error => 'Default messaging preference for given categorycode and' ++ .' message_attribute_id cannot be found.', ++ ) unless $default; ++ $default = $default->unblessed; ++ ++ # Add a new messaging preference for patron ++ my $self = $class->SUPER::new({ ++ borrowernumber => $params->{'borrowernumber'}, ++ message_attribute_id => $default->{'message_attribute_id'}, ++ days_in_advance => $default->{'days_in_advance'}, ++ wants_digest => $default->{'wants_digest'}, ++ })->store; ++ ++ # Set default messaging transport types ++ my $default_transport_types = ++ Koha::Patron::Message::Transport::Preferences->search({ ++ borrower_message_preference_id => ++ $default->{'borrower_message_preference_id'} ++ }); ++ while (my $transport = $default_transport_types->next) { ++ Koha::Patron::Message::Transport::Preference->new({ ++ borrower_message_preference_id => $self->borrower_message_preference_id, ++ message_transport_type => $transport->message_transport_type, ++ })->store; ++ } ++ ++ return $self; ++} ++ ++=head3 message_name ++ ++$preference->message_name ++ ++Gets message_name for this messaging preference. ++ ++Setter not implemented. ++ ++=cut ++ ++sub message_name { ++ my ($self) = @_; ++ ++ if ($self->{'_message_name'}) { ++ return $self->{'_message_name'}; ++ } ++ $self->{'_message_name'} = Koha::Patron::Message::Attributes->find({ ++ message_attribute_id => $self->message_attribute_id, ++ })->message_name; ++ return $self->{'_message_name'}; ++} ++ ++=head3 message_transport_types ++ ++$preference->message_transport_types ++Returns a HASHREF of message transport types for this messaging preference, e.g. ++if ($preference->message_transport_types->{'email'}) { ++ # email is one of the transport preferences ++} ++ ++$preference->message_transport_types('email', 'sms'); ++Sets the given message transport types for this messaging preference ++ ++=cut ++ ++sub message_transport_types { ++ my $self = shift; ++ ++ unless (@_) { ++ if ($self->{'_message_transport_types'}) { ++ return $self->{'_message_transport_types'}; ++ } ++ map { ++ my $transport = Koha::Patron::Message::Transports->find({ ++ message_attribute_id => $self->message_attribute_id, ++ message_transport_type => $_->message_transport_type, ++ is_digest => $self->wants_digest ++ }); ++ unless ($transport) { ++ my $logger = Koha::Logger->get; ++ $logger->warn( ++ $self->message_name . ' has no transport with '. ++ $_->message_transport_type . ' (digest: '. ++ ($self->wants_digest ? 'yes':'no').').' ++ ); ++ } ++ $self->{'_message_transport_types'}->{$_->message_transport_type} ++ = $transport ? $transport->letter_code : ' '; ++ } ++ Koha::Patron::Message::Transport::Preferences->search({ ++ borrower_message_preference_id => $self->borrower_message_preference_id, ++ })->as_list; ++ return $self->{'_message_transport_types'} || {}; ++ } ++ else { ++ $self->_set_message_transport_types(@_); ++ return $self; ++ } ++} ++ ++=head3 set ++ ++$preference->set({ ++ message_transport_types => ['sms', 'phone'], ++ wants_digest => 0, ++})->store; ++ ++Sets preference object values and additionally message_transport_types if given. ++ ++=cut ++ ++sub set { ++ my ($self, $params) = @_; ++ ++ my $mtt = $params->{'message_transport_types'}; ++ delete $params->{'message_transport_types'}; ++ ++ $self->SUPER::set($params) if $params; ++ if ($mtt) { ++ $self->message_transport_types($mtt); ++ } ++ ++ return $self; ++} ++ ++=head3 store ++ ++Makes a validation before actual Koha::Object->store so that proper exceptions ++can be thrown. See C for documentation about exceptions. ++ ++=cut ++ ++sub store { ++ my $self = shift; ++ ++ $self->validate->SUPER::store(@_); ++ ++ # store message transport types ++ if (exists $self->{'_message_transport_types'}) { ++ Koha::Patron::Message::Transport::Preferences->search({ ++ borrower_message_preference_id => ++ $self->borrower_message_preference_id, ++ })->delete; ++ foreach my $type (keys %{$self->{'_message_transport_types'}}) { ++ Koha::Patron::Message::Transport::Preference->new({ ++ borrower_message_preference_id => ++ $self->borrower_message_preference_id, ++ message_transport_type => $type, ++ })->store; ++ } ++ } ++ ++ return $self; ++} ++ ++=head3 validate ++ ++Makes a basic validation for object. ++ ++Throws following exceptions regarding parameters. ++- Koha::Exceptions::MissingParameter ++- Koha::Exceptions::TooManyParameters ++- Koha::Exceptions::BadParameter ++ ++See $_->parameter to identify the parameter causing the exception. ++ ++Throws Koha::Exceptions::DuplicateObject if this preference already exists. ++ ++Returns Koha::Patron::Message::Preference object. ++ ++=cut ++ ++sub validate { ++ my ($self) = @_; ++ ++ if ($self->borrowernumber && $self->categorycode) { ++ Koha::Exceptions::TooManyParameters->throw( ++ error => 'Both borrowernumber and category given, only one accepted', ++ parameter => ['borrowernumber', 'categorycode'], ++ ); ++ } ++ if (!$self->borrowernumber && !$self->categorycode) { ++ Koha::Exceptions::MissingParameter->throw( ++ error => 'borrowernumber or category required, none given', ++ parameter => ['borrowernumber', 'categorycode'], ++ ); ++ } ++ if ($self->borrowernumber) { ++ Koha::Exceptions::BadParameter->throw( ++ error => 'Patron not found.', ++ parameter => 'borrowernumber', ++ ) unless Koha::Patrons->find($self->borrowernumber); ++ } ++ if ($self->categorycode) { ++ Koha::Exceptions::BadParameter->throw( ++ error => 'Category not found.', ++ parameter => 'categorycode', ++ ) unless Koha::Patron::Categories->find($self->categorycode); ++ } ++ ++ if (!$self->in_storage) { ++ my $previous = Koha::Patron::Message::Preferences->search({ ++ borrowernumber => $self->borrowernumber, ++ categorycode => $self->categorycode, ++ message_attribute_id => $self->message_attribute_id, ++ }); ++ if ($previous->count) { ++ Koha::Exceptions::DuplicateObject->throw( ++ error => 'A preference for this borrower/category and' ++ .' message_attribute_id already exists', ++ ); ++ } ++ } ++ ++ my $attr = Koha::Patron::Message::Attributes->find( ++ $self->message_attribute_id ++ ); ++ unless ($attr) { ++ Koha::Exceptions::BadParameter->throw( ++ error => 'Message attribute with id '.$self->message_attribute_id ++ .' not found', ++ parameter => 'message_attribute_id' ++ ); ++ } ++ if (defined $self->days_in_advance) { ++ if ($attr && $attr->takes_days == 0) { ++ Koha::Exceptions::BadParameter->throw( ++ error => 'days_in_advance cannot be defined for '. ++ $attr->message_name . '.', ++ parameter => 'days_in_advance', ++ ); ++ } ++ elsif ($self->days_in_advance < 0 || $self->days_in_advance > 30) { ++ Koha::Exceptions::BadParameter->throw( ++ error => 'days_in_advance has to be a value between 0-30 for '. ++ $attr->message_name . '.', ++ parameter => 'days_in_advance', ++ ); ++ } ++ } ++ if (defined $self->wants_digest) { ++ my $transports = Koha::Patron::Message::Transports->search({ ++ message_attribute_id => $self->message_attribute_id, ++ is_digest => $self->wants_digest ? 1 : 0, ++ }); ++ Koha::Exceptions::BadParameter->throw( ++ error => (!$self->wants_digest ? 'Digest must be selected' ++ : 'Digest cannot be selected') ++ . ' for '.$attr->message_name.'.', ++ parameter => 'wants_digest', ++ ) if $transports->count == 0; ++ } ++ ++ return $self; ++} ++ ++sub _set_message_transport_types { ++ my $self = shift; ++ ++ return unless $_[0]; ++ ++ $self->{'_message_transport_types'} = undef; ++ my $types = ref $_[0] eq "ARRAY" ? $_[0] : [@_]; ++ return unless $types; ++ $self->_validate_message_transport_types({ message_transport_types => $types }); ++ foreach my $type (@$types) { ++ unless (exists $self->{'_message_transport_types'}->{$type}) { ++ my $transport = Koha::Patron::Message::Transports->find({ ++ message_attribute_id => $self->message_attribute_id, ++ message_transport_type => $type ++ }); ++ unless ($transport) { ++ Koha::Exceptions::BadParameter->throw( ++ error => 'No transport configured for '.$self->message_name. ++ " transport type $type.", ++ parameter => 'message_transport_types' ++ ); ++ } ++ $self->{'_message_transport_types'}->{$type} ++ = $transport->letter_code; ++ } ++ } ++ return $self; ++} ++ ++sub _validate_message_transport_types { ++ my ($self, $params) = @_; ++ ++ if (ref($params) eq 'HASH' && $params->{'message_transport_types'}) { ++ if (ref($params->{'message_transport_types'}) ne 'ARRAY') { ++ $params->{'message_transport_types'} = [$params->{'message_transport_types'}]; ++ } ++ my $types = $params->{'message_transport_types'}; ++ ++ foreach my $type (@{$types}) { ++ unless (Koha::Patron::Message::Transport::Types->find({ ++ message_transport_type => $type ++ })) { ++ Koha::Exceptions::BadParameter->throw( ++ error => "Message transport type '$type' does not exist", ++ parameter => 'message_transport_types', ++ ); ++ } ++ } ++ return $types; ++ } ++} ++ ++=head3 type ++ ++=cut ++ ++sub _type { ++ return 'BorrowerMessagePreference'; ++} ++ ++=head1 AUTHOR ++ ++Lari Taskula ++ ++=cut ++ ++1; +diff --git a/Koha/Patron/Message/Preferences.pm b/Koha/Patron/Message/Preferences.pm +new file mode 100644 +index 0000000..fa8e974 +--- /dev/null ++++ b/Koha/Patron/Message/Preferences.pm +@@ -0,0 +1,146 @@ ++package Koha::Patron::Message::Preferences; ++ ++# Copyright Koha-Suomi Oy 2016 ++# ++# This file is part of Koha. ++# ++# Koha is free software; you can redistribute it and/or modify it under the ++# terms of the GNU General Public License as published by the Free Software ++# Foundation; either version 3 of the License, or (at your option) any later ++# version. ++# ++# Koha is distributed in the hope that it will be useful, but WITHOUT ANY ++# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ++# A PARTICULAR PURPOSE. See the GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License along ++# with Koha; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++use Modern::Perl; ++ ++use Koha::Database; ++use Koha::Patron::Message::Attributes; ++use Koha::Patron::Message::Preference; ++use Koha::Patron::Message::Transports; ++ ++use base qw(Koha::Objects); ++ ++=head1 NAME ++ ++Koha::Patron::Message::Preferences - Koha Patron Message Preferences object class ++ ++=head1 API ++ ++=head2 Class Methods ++ ++=cut ++ ++=head3 find_with_message_name ++ ++Koha::Patron::Message::Preferences->find_with_message_name({ ++ borrowernumber => 123, ++ message_name => 'Hold_Filled', ++}); ++ ++Converts C into C and continues find. ++ ++=cut ++ ++sub find_with_message_name { ++ my ($self, $id) = @_; ++ ++ if (ref($id) eq "HASH" && $id->{'message_name'}) { ++ my $attr = Koha::Patron::Message::Attributes->find({ ++ message_name => $id->{'message_name'}, ++ }); ++ $id->{'message_attribute_id'} = ($attr) ? ++ $attr->message_attribute_id : undef; ++ delete $id->{'message_name'}; ++ } ++ ++ return $self->SUPER::find($id); ++} ++ ++=head3 get_options ++ ++my $messaging_options = Koha::Patron::Message::Preferences->get_options ++ ++Returns an ARRAYref of HASHrefs on available messaging options. ++ ++=cut ++ ++sub get_options { ++ my ($self) = @_; ++ ++ my $transports = Koha::Patron::Message::Transports->search(undef, ++ { ++ join => ['message_attribute'], ++ '+select' => ['message_attribute.message_name', 'message_attribute.takes_days'], ++ '+as' => ['message_name', 'takes_days'], ++ }); ++ ++ my $choices; ++ while (my $transport = $transports->next) { ++ my $name = $transport->get_column('message_name'); ++ $choices->{$name}->{'message_attribute_id'} = $transport->message_attribute_id; ++ $choices->{$name}->{'message_name'} = $name; ++ $choices->{$name}->{'takes_days'} = $transport->get_column('takes_days'); ++ $choices->{$name}->{'has_digest'} ||= 1 if $transport->is_digest; ++ $choices->{$name}->{'has_digest_off'} ||= 1 if !$transport->is_digest; ++ $choices->{$name}->{'transport_'.$transport->get_column('message_transport_type')} = ' '; ++ } ++ ++ my @return = values %$choices; ++ @return = sort { $a->{message_attribute_id} <=> $b->{message_attribute_id} } @return; ++ ++ return \@return; ++} ++ ++=head3 search_with_message_name ++ ++Koha::Patron::Message::Preferences->search_with_message_name({ ++ borrowernumber => 123, ++ message_name => 'Hold_Filled', ++}); ++ ++Converts C into C and continues search. Use ++Koha::Patron::Message::Preferences->search with a proper join for more complicated ++searches. ++ ++=cut ++ ++sub search_with_message_name { ++ my ($self, $params, $attributes) = @_; ++ ++ if (ref($params) eq "HASH" && $params->{'message_name'}) { ++ my $attr = Koha::Patron::Message::Attributes->find({ ++ message_name => $params->{'message_name'}, ++ }); ++ $params->{'message_attribute_id'} = ($attr) ? ++ $attr->message_attribute_id : undef; ++ delete $params->{'message_name'}; ++ } ++ ++ return $self->SUPER::search($params, $attributes); ++} ++ ++=head3 type ++ ++=cut ++ ++sub _type { ++ return 'BorrowerMessagePreference'; ++} ++ ++sub object_class { ++ return 'Koha::Patron::Message::Preference'; ++} ++ ++=head1 AUTHOR ++ ++Lari Taskula ++ ++=cut ++ ++1; +diff --git a/Koha/Patron/Message/Transport.pm b/Koha/Patron/Message/Transport.pm +new file mode 100644 +index 0000000..ca0906e +--- /dev/null ++++ b/Koha/Patron/Message/Transport.pm +@@ -0,0 +1,50 @@ ++package Koha::Patron::Message::Transport; ++ ++# Copyright Koha-Suomi Oy 2016 ++# ++# This file is part of Koha. ++# ++# Koha is free software; you can redistribute it and/or modify it under the ++# terms of the GNU General Public License as published by the Free Software ++# Foundation; either version 3 of the License, or (at your option) any later ++# version.a ++# ++# Koha is distributed in the hope that it will be useful, but WITHOUT ANY ++# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ++# A PARTICULAR PURPOSE. See the GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License along ++# with Koha; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++use Modern::Perl; ++ ++use Koha::Database; ++ ++use base qw(Koha::Object); ++ ++=head1 NAME ++ ++Koha::Patron::Message::Transport - Koha Patron Message Transport object class ++ ++=head1 API ++ ++=head2 Class Methods ++ ++=cut ++ ++=head3 type ++ ++=cut ++ ++sub _type { ++ return 'MessageTransport'; ++} ++ ++=head1 AUTHOR ++ ++Lari Taskula ++ ++=cut ++ ++1; +diff --git a/Koha/Patron/Message/Transport/Preference.pm b/Koha/Patron/Message/Transport/Preference.pm +new file mode 100644 +index 0000000..fe0ddeb +--- /dev/null ++++ b/Koha/Patron/Message/Transport/Preference.pm +@@ -0,0 +1,51 @@ ++package Koha::Patron::Message::Transport::Preference; ++ ++# Copyright Koha-Suomi Oy 2016 ++# ++# This file is part of Koha. ++# ++# Koha is free software; you can redistribute it and/or modify it under the ++# terms of the GNU General Public License as published by the Free Software ++# Foundation; either version 3 of the License, or (at your option) any later ++# version.a ++# ++# Koha is distributed in the hope that it will be useful, but WITHOUT ANY ++# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ++# A PARTICULAR PURPOSE. See the GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License along ++# with Koha; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++use Modern::Perl; ++ ++use Koha::Database; ++ ++use base qw(Koha::Object); ++ ++=head1 NAME ++ ++Koha::Patron::Message::Transport::Preference - Koha Patron Message Transport ++Preference object class ++ ++=head1 API ++ ++=head2 Class Methods ++ ++=cut ++ ++=head3 type ++ ++=cut ++ ++sub _type { ++ return 'BorrowerMessageTransportPreference'; ++} ++ ++=head1 AUTHOR ++ ++Lari Taskula ++ ++=cut ++ ++1; +diff --git a/Koha/Patron/Message/Transport/Preferences.pm b/Koha/Patron/Message/Transport/Preferences.pm +new file mode 100644 +index 0000000..aabd851 +--- /dev/null ++++ b/Koha/Patron/Message/Transport/Preferences.pm +@@ -0,0 +1,56 @@ ++package Koha::Patron::Message::Transport::Preferences; ++ ++# Copyright Koha-Suomi Oy 2016 ++# ++# This file is part of Koha. ++# ++# Koha is free software; you can redistribute it and/or modify it under the ++# terms of the GNU General Public License as published by the Free Software ++# Foundation; either version 3 of the License, or (at your option) any later ++# version. ++# ++# Koha is distributed in the hope that it will be useful, but WITHOUT ANY ++# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ++# A PARTICULAR PURPOSE. See the GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License along ++# with Koha; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++use Modern::Perl; ++ ++use Koha::Database; ++use Koha::Patron::Message::Transport::Preference; ++ ++use base qw(Koha::Objects); ++ ++=head1 NAME ++ ++Koha::Patron::Message::Transport::Preferences - Koha Patron Message Transport ++Preferences object class ++ ++=head1 API ++ ++=head2 Class Methods ++ ++=cut ++ ++=head3 type ++ ++=cut ++ ++sub _type { ++ return 'BorrowerMessageTransportPreference'; ++} ++ ++sub object_class { ++ return 'Koha::Patron::Message::Transport::Preference'; ++} ++ ++=head1 AUTHOR ++ ++Lari Taskula ++ ++=cut ++ ++1; +diff --git a/Koha/Patron/Message/Transport/Type.pm b/Koha/Patron/Message/Transport/Type.pm +new file mode 100644 +index 0000000..4a52a10 +--- /dev/null ++++ b/Koha/Patron/Message/Transport/Type.pm +@@ -0,0 +1,51 @@ ++package Koha::Patron::Message::Transport::Type; ++ ++# Copyright Koha-Suomi Oy 2016 ++# ++# This file is part of Koha. ++# ++# Koha is free software; you can redistribute it and/or modify it under the ++# terms of the GNU General Public License as published by the Free Software ++# Foundation; either version 3 of the License, or (at your option) any later ++# version.a ++# ++# Koha is distributed in the hope that it will be useful, but WITHOUT ANY ++# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ++# A PARTICULAR PURPOSE. See the GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License along ++# with Koha; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++use Modern::Perl; ++ ++use Koha::Database; ++ ++use base qw(Koha::Object); ++ ++=head1 NAME ++ ++Koha::Patron::Message::Transport::Type - Koha Patron Message Transport Type ++object class ++ ++=head1 API ++ ++=head2 Class Methods ++ ++=cut ++ ++=head3 type ++ ++=cut ++ ++sub _type { ++ return 'MessageTransportType'; ++} ++ ++=head1 AUTHOR ++ ++Lari Taskula ++ ++=cut ++ ++1; +diff --git a/Koha/Patron/Message/Transport/Types.pm b/Koha/Patron/Message/Transport/Types.pm +new file mode 100644 +index 0000000..2633ea3 +--- /dev/null ++++ b/Koha/Patron/Message/Transport/Types.pm +@@ -0,0 +1,56 @@ ++package Koha::Patron::Message::Transport::Types; ++ ++# Copyright Koha-Suomi Oy 2016 ++# ++# This file is part of Koha. ++# ++# Koha is free software; you can redistribute it and/or modify it under the ++# terms of the GNU General Public License as published by the Free Software ++# Foundation; either version 3 of the License, or (at your option) any later ++# version. ++# ++# Koha is distributed in the hope that it will be useful, but WITHOUT ANY ++# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ++# A PARTICULAR PURPOSE. See the GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License along ++# with Koha; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++use Modern::Perl; ++ ++use Koha::Database; ++use Koha::Patron::Message::Transport::Type; ++ ++use base qw(Koha::Objects); ++ ++=head1 NAME ++ ++Koha::Patron::Message::Transport::Types - Koha Patron Message Transport Types ++object class ++ ++=head1 API ++ ++=head2 Class Methods ++ ++=cut ++ ++=head3 type ++ ++=cut ++ ++sub _type { ++ return 'MessageTransportType'; ++} ++ ++sub object_class { ++ return 'Koha::Patron::Message::Transport::Type'; ++} ++ ++=head1 AUTHOR ++ ++Lari Taskula ++ ++=cut ++ ++1; +diff --git a/Koha/Patron/Message/Transports.pm b/Koha/Patron/Message/Transports.pm +new file mode 100644 +index 0000000..b6aee32 +--- /dev/null ++++ b/Koha/Patron/Message/Transports.pm +@@ -0,0 +1,55 @@ ++package Koha::Patron::Message::Transports; ++ ++# Copyright Koha-Suomi Oy 2016 ++# ++# This file is part of Koha. ++# ++# Koha is free software; you can redistribute it and/or modify it under the ++# terms of the GNU General Public License as published by the Free Software ++# Foundation; either version 3 of the License, or (at your option) any later ++# version. ++# ++# Koha is distributed in the hope that it will be useful, but WITHOUT ANY ++# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ++# A PARTICULAR PURPOSE. See the GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License along ++# with Koha; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++use Modern::Perl; ++ ++use Koha::Database; ++use Koha::Patron::Message::Transport; ++ ++use base qw(Koha::Objects); ++ ++=head1 NAME ++ ++Koha::Patron::Message::Transports - Koha Patron Message Transports object class ++ ++=head1 API ++ ++=head2 Class Methods ++ ++=cut ++ ++=head3 type ++ ++=cut ++ ++sub _type { ++ return 'MessageTransport'; ++} ++ ++sub object_class { ++ return 'Koha::Patron::Message::Transport'; ++} ++ ++=head1 AUTHOR ++ ++Lari Taskula ++ ++=cut ++ ++1; +diff --git a/t/db_dependent/Koha/Patron/Message/Attributes.t b/t/db_dependent/Koha/Patron/Message/Attributes.t +new file mode 100644 +index 0000000..836b4f0 +--- /dev/null ++++ b/t/db_dependent/Koha/Patron/Message/Attributes.t +@@ -0,0 +1,74 @@ ++#!/usr/bin/perl ++ ++# Copyright 2017 Koha-Suomi Oy ++# ++# This file is part of Koha ++# ++# Koha is free software; you can redistribute it and/or modify it ++# under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# Koha is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with Koha; if not, see . ++ ++use Modern::Perl; ++ ++use Test::More tests => 2; ++ ++use Koha::Database; ++ ++my $schema = Koha::Database->new->schema; ++ ++subtest 'Test class imports' => sub { ++ plan tests => 2; ++ ++ use_ok('Koha::Patron::Message::Attribute'); ++ use_ok('Koha::Patron::Message::Attributes'); ++}; ++ ++subtest 'Test Koha::Patron::Message::Attributes' => sub { ++ plan tests => 6; ++ ++ $schema->storage->txn_begin; ++ ++ Koha::Patron::Message::Attribute->new({ ++ message_name => 'Test_Attribute' ++ })->store; ++ Koha::Patron::Message::Attribute->new({ ++ message_name => 'Test_Attribute2', ++ takes_days => 1 ++ })->store; ++ ++ my $attribute = Koha::Patron::Message::Attributes->find({ ++ message_name => 'Test_Attribute' }); ++ my $attribute2 = Koha::Patron::Message::Attributes->find({ ++ message_name => 'Test_Attribute2' }); ++ ++ is($attribute->message_name, 'Test_Attribute', ++ 'Added a new messaging attribute.'); ++ is($attribute->takes_days, 0, ++ 'For that messaging attribute, takes_days is disabled by default.'); ++ is($attribute2->message_name, 'Test_Attribute2', ++ 'Added another messaging attribute.'); ++ is($attribute2->takes_days, 1, ++ 'takes_days is enabled for that message attribute (as expected).'); ++ ++ $attribute->delete; ++ $attribute2->delete; ++ is(Koha::Patron::Message::Attributes->find({ ++ message_name => 'Test_Attribute' }), undef, ++ 'Deleted the first message attribute.'); ++ is(Koha::Patron::Message::Attributes->find({ ++ message_name => 'Test_Attribute2' }), undef, ++ 'Deleted the second message attribute.'); ++ ++ $schema->storage->txn_rollback; ++}; ++ ++1; +diff --git a/t/db_dependent/Koha/Patron/Message/Preferences.t b/t/db_dependent/Koha/Patron/Message/Preferences.t +new file mode 100644 +index 0000000..bd88c63 +--- /dev/null ++++ b/t/db_dependent/Koha/Patron/Message/Preferences.t +@@ -0,0 +1,719 @@ ++#!/usr/bin/perl ++ ++# Copyright 2017 Koha-Suomi Oy ++# ++# This file is part of Koha ++# ++# Koha is free software; you can redistribute it and/or modify it ++# under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# Koha is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with Koha; if not, see . ++ ++use Modern::Perl; ++ ++use Test::More tests => 7; ++ ++use t::lib::Mocks; ++use t::lib::TestBuilder; ++ ++use C4::Context; ++ ++use Koha::Notice::Templates; ++use Koha::Patron::Categories; ++use Koha::Patron::Message::Attributes; ++use Koha::Patron::Message::Transport::Types; ++use Koha::Patron::Message::Transports; ++use Koha::Patrons; ++ ++use File::Temp qw/tempfile/; ++use Log::Log4perl; ++ ++my $schema = Koha::Database->new->schema; ++my $builder = t::lib::TestBuilder->new; ++ ++subtest 'Test class imports' => sub { ++ plan tests => 2; ++ ++ use_ok('Koha::Patron::Message::Preference'); ++ use_ok('Koha::Patron::Message::Preferences'); ++}; ++ ++subtest 'Test Koha::Patron::Message::Preferences' => sub { ++ plan tests => 2; ++ ++ $schema->storage->txn_begin; ++ ++ my $attribute = build_a_test_attribute(); ++ my $letter = build_a_test_letter(); ++ my $mtt = build_a_test_transport_type(); ++ Koha::Patron::Message::Transport->new({ ++ message_attribute_id => $attribute->message_attribute_id, ++ message_transport_type => $mtt->message_transport_type, ++ is_digest => 0, ++ letter_module => $letter->module, ++ letter_code => $letter->code, ++ })->store; ++ ++ subtest 'Test for a patron' => sub { ++ plan tests => 3; ++ ++ my $patron = build_a_test_patron(); ++ Koha::Patron::Message::Preference->new({ ++ borrowernumber => $patron->borrowernumber, ++ message_attribute_id => $attribute->message_attribute_id, ++ wants_digest => 0, ++ days_in_advance => undef, ++ })->store; ++ ++ my $preference = Koha::Patron::Message::Preferences->find({ ++ borrowernumber => $patron->borrowernumber, ++ message_attribute_id => $attribute->message_attribute_id ++ }); ++ ok($preference->borrower_message_preference_id > 0, ++ 'Added a new messaging preference for patron.'); ++ ++ subtest 'Test set not throwing an exception on duplicate object' => sub { ++ plan tests => 1; ++ ++ Koha::Patron::Message::Attributes->find({ ++ message_attribute_id => $attribute->message_attribute_id ++ })->set({ takes_days => 1 })->store; ++ $preference->set({ days_in_advance => 1 })->store; ++ is(ref($preference), 'Koha::Patron::Message::Preference', ++ 'Updating the preference does not cause duplicate object exception'); ++ }; ++ ++ $preference->delete; ++ is(Koha::Patron::Message::Preferences->search({ ++ borrowernumber => $patron->borrowernumber, ++ message_attribute_id => $attribute->message_attribute_id ++ })->count, 0, 'Deleted the messaging preference.'); ++ }; ++ ++ subtest 'Test for a category' => sub { ++ my $category = build_a_test_category(); ++ Koha::Patron::Message::Preference->new({ ++ categorycode => $category->categorycode, ++ message_attribute_id => $attribute->message_attribute_id, ++ wants_digest => 0, ++ days_in_advance => undef, ++ })->store; ++ ++ my $preference = Koha::Patron::Message::Preferences->find({ ++ categorycode => $category->categorycode, ++ message_attribute_id => $attribute->message_attribute_id ++ }); ++ ok($preference->borrower_message_preference_id > 0, ++ 'Added a new messaging preference for category.'); ++ ++ $preference->delete; ++ is(Koha::Patron::Message::Preferences->search({ ++ categorycode => $category->categorycode, ++ message_attribute_id => $attribute->message_attribute_id ++ })->count, 0, 'Deleted the messaging preference.'); ++ }; ++ ++ $schema->storage->txn_rollback; ++}; ++ ++subtest 'Test Koha::Patron::Message::Preferences->get_options' => sub { ++ plan tests => 2; ++ ++ subtest 'Test method availability and return value' => sub { ++ plan tests => 3; ++ ++ ok(Koha::Patron::Message::Preferences->can('get_options'), ++ 'Method get_options is available.'); ++ ok(my $options = Koha::Patron::Message::Preferences->get_options, ++ 'Called get_options successfully.'); ++ is(ref($options), 'ARRAY', 'get_options returns a ARRAYref'); ++ }; ++ ++ subtest 'Make sure options are correct' => sub { ++ $schema->storage->txn_begin; ++ my $options = Koha::Patron::Message::Preferences->get_options; ++ ++ foreach my $option (@$options) { ++ my $n = $option->{'message_name'}; ++ my $attr = Koha::Patron::Message::Attributes->find($option->{'message_attribute_id'}); ++ is($option->{'message_attribute_id'}, $attr->message_attribute_id, ++ '$n: message_attribute_id is set'); ++ is($option->{'message_name'}, $attr->message_name, '$n: message_name is set'); ++ is($option->{'takes_days'}, $attr->takes_days, '$n: takes_days is set'); ++ my $transports = Koha::Patron::Message::Transports->search({ ++ message_attribute_id => $option->{'message_attribute_id'}, ++ is_digest => $option->{'has_digest'} || 0, ++ }); ++ while (my $trnzport = $transports->next) { ++ is($option->{'has_digest'} || 0, $trnzport->is_digest, '$n: has_digest is set for '.$trnzport->message_transport_type); ++ is($option->{'transport_'.$trnzport->message_transport_type}, ' ', '$n: transport_'.$trnzport->message_transport_type.' is set'); ++ } ++ } ++ ++ $schema->storage->txn_rollback; ++ }; ++}; ++ ++subtest 'Add preferences from defaults' => sub { ++ plan tests => 3; ++ ++ $schema->storage->txn_begin; ++ ++ my $patron = build_a_test_patron(); ++ my ($default, $mtt1, $mtt2) = build_a_test_category_preference({ ++ patron => $patron, ++ }); ++ ok(Koha::Patron::Message::Preference->new_from_default({ ++ borrowernumber => $patron->borrowernumber, ++ categorycode => $patron->categorycode, ++ message_attribute_id => $default->message_attribute_id, ++ })->store, 'Added a default preference to patron.'); ++ ok(my $pref = Koha::Patron::Message::Preferences->find({ ++ borrowernumber => $patron->borrowernumber, ++ message_attribute_id => $default->message_attribute_id, ++ }), 'Found the default preference from patron.'); ++ is(Koha::Patron::Message::Transport::Preferences->search({ ++ borrower_message_preference_id => $pref->borrower_message_preference_id ++ })->count, 2, 'Found the two transport types that we set earlier'); ++ ++ $schema->storage->txn_rollback; ++}; ++ ++subtest 'Test Koha::Patron::Message::Preference->message_transport_types' => sub { ++ plan tests => 4; ++ ++ ok(Koha::Patron::Message::Preference->can('message_transport_types'), ++ 'Method message_transport_types available'); ++ ++ subtest 'get message_transport_types' => sub { ++ plan tests => 5; ++ ++ $schema->storage->txn_begin; ++ ++ my $patron = build_a_test_patron(); ++ my ($preference, $mtt1, $mtt2) = build_a_test_complete_preference({ ++ patron => $patron ++ }); ++ Koha::Patron::Message::Transport::Preferences->search({ ++ borrower_message_preference_id => $preference->borrower_message_preference_id, ++ })->delete; ++ Koha::Patron::Message::Transport::Preference->new({ ++ borrower_message_preference_id => $preference->borrower_message_preference_id, ++ message_transport_type => $mtt1->message_transport_type, ++ })->store; ++ Koha::Patron::Message::Transport::Preference->new({ ++ borrower_message_preference_id => $preference->borrower_message_preference_id, ++ message_transport_type => $mtt2->message_transport_type, ++ })->store; ++ my $stored_transports = Koha::Patron::Message::Transport::Preferences->search({ ++ borrower_message_preference_id => $preference->borrower_message_preference_id, ++ }); ++ my $transport1 = Koha::Patron::Message::Transports->find({ ++ message_attribute_id => $preference->message_attribute_id, ++ message_transport_type => $mtt1->message_transport_type, ++ }); ++ my $transport2 = Koha::Patron::Message::Transports->find({ ++ message_attribute_id => $preference->message_attribute_id, ++ message_transport_type => $mtt2->message_transport_type, ++ }); ++ my $transports = $preference->message_transport_types; ++ is(keys %{$transports}, $stored_transports->count, ++ '->message_transport_types gets correct amount of transport types.'); ++ is($transports->{$stored_transports->next->message_transport_type}, ++ $transport1->letter_code, 'Found correct message transport type and letter code.'); ++ is($transports->{$stored_transports->next->message_transport_type}, ++ $transport2->letter_code, 'Found correct message transport type and letter code.'); ++ ok(!$preference->message_transport_types->{'nonexistent'}, ++ 'Didn\'t find nonexistent transport type.'); ++ ++ subtest 'test logging of warnings by invalid message transport type' => sub { ++ plan tests => 2; ++ ++ my $log = mytempfile(); ++ my $conf = mytempfile( <<"HERE" ++log4perl.logger.opac = WARN, OPAC ++log4perl.appender.OPAC=Log::Log4perl::Appender::TestBuffer ++log4perl.appender.OPAC.filename=$log ++log4perl.appender.OPAC.mode=append ++log4perl.appender.OPAC.layout=SimpleLayout ++log4perl.logger.intranet = WARN, INTRANET ++log4perl.appender.INTRANET=Log::Log4perl::Appender::TestBuffer ++log4perl.appender.INTRANET.filename=$log ++log4perl.appender.INTRANET.mode=append ++log4perl.appender.INTRANET.layout=SimpleLayout ++HERE ++ ); ++ t::lib::Mocks::mock_config('log4perl_conf', $conf); ++ my $appenders = Log::Log4perl->appenders; ++ my $appender = Log::Log4perl->appenders->{OPAC}; ++ ++ my $pref = Koha::Patron::Message::Preferences->find( ++ $preference->borrower_message_preference_id ++ ); ++ my $transports = $pref->message_transport_types; ++ is($appender, undef, 'Nothing in buffer yet'); ++ ++ my $mtt_new = build_a_test_transport_type(); ++ Koha::Patron::Message::Transport::Preference->new({ ++ borrower_message_preference_id => ++ $pref->borrower_message_preference_id, ++ message_transport_type => $mtt_new->message_transport_type, ++ })->store; ++ $pref = Koha::Patron::Message::Preferences->find( ++ $pref->borrower_message_preference_id ++ ); ++ $transports = $pref->message_transport_types; ++ $appender = Log::Log4perl->appenders->{OPAC}; ++ my $name = $pref->message_name; ++ my $tt = $mtt_new->message_transport_type; ++ like($appender->buffer, qr/WARN - $name has no transport with $tt/, ++ 'Logged invalid message transport type'); ++ }; ++ ++ $schema->storage->txn_rollback; ++ }; ++ ++ subtest 'set message_transport_types' => sub { ++ plan tests => 6; ++ ++ $schema->storage->txn_begin; ++ ++ my $patron = build_a_test_patron(); ++ my ($preference, $mtt1, $mtt2) = build_a_test_complete_preference({ ++ patron => $patron ++ }); ++ ++ my $mtt1_str = $mtt1->message_transport_type; ++ my $mtt2_str = $mtt2->message_transport_type; ++ # 1/3, use message_transport_types(list) ++ Koha::Patron::Message::Transport::Preferences->search({ ++ borrower_message_preference_id => $preference->borrower_message_preference_id, ++ })->delete; ++ ok($preference->message_transport_types($mtt1_str, $mtt2_str)->store, ++ '1/3 Set returned true.'); ++ my $stored_transports = Koha::Patron::Message::Transport::Preferences->search({ ++ borrower_message_preference_id => $preference->borrower_message_preference_id, ++ '-or' => [ ++ message_transport_type => $mtt1_str, ++ message_transport_type => $mtt2_str ++ ] ++ }); ++ is($stored_transports->count, 2, 'Two transports selected'); ++ ++ # 2/3, use message_transport_types(ARRAYREF) ++ Koha::Patron::Message::Transport::Preferences->search({ ++ borrower_message_preference_id => $preference->borrower_message_preference_id, ++ })->delete; ++ ok($preference->message_transport_types([$mtt1_str, $mtt2_str])->store, ++ '2/3 Set returned true.'); ++ $stored_transports = Koha::Patron::Message::Transport::Preferences->search({ ++ borrower_message_preference_id => $preference->borrower_message_preference_id, ++ '-or' => [ ++ message_transport_type => $mtt1_str, ++ message_transport_type => $mtt2_str ++ ] ++ }); ++ is($stored_transports->count, 2, 'Two transports selected'); ++ ++ # 3/3, use set({ message_transport_types => ARRAYREF }) ++ Koha::Patron::Message::Transport::Preferences->search({ ++ borrower_message_preference_id => $preference->borrower_message_preference_id, ++ })->delete; ++ ok($preference->set({ ++ message_transport_types => [$mtt1_str, $mtt2_str]})->store, ++ '3/3 Set returned true.'); ++ $stored_transports = Koha::Patron::Message::Transport::Preferences->search({ ++ borrower_message_preference_id => $preference->borrower_message_preference_id, ++ '-or' => [ ++ message_transport_type => $mtt1_str, ++ message_transport_type => $mtt2_str ++ ] ++ }); ++ is($stored_transports->count, 2, 'Two transports selected'); ++ ++ $schema->storage->txn_rollback; ++ }; ++ ++ subtest 'new message_transport_types' => sub { ++ plan tests => 3; ++ ++ $schema->storage->txn_begin; ++ ++ my $patron = build_a_test_patron(); ++ my $letter = build_a_test_letter(); ++ my $attribute = build_a_test_attribute(); ++ my $mtt = build_a_test_transport_type(); ++ Koha::Patron::Message::Transport->new({ ++ message_attribute_id => $attribute->message_attribute_id, ++ message_transport_type => $mtt->message_transport_type, ++ is_digest => 0, ++ letter_module => $letter->module, ++ letter_code => $letter->code, ++ })->store; ++ ok(my $preference = Koha::Patron::Message::Preference->new({ ++ borrowernumber => $patron->borrowernumber, ++ message_attribute_id => $attribute->message_attribute_id, ++ wants_digest => 0, ++ days_in_advance => undef, ++ message_transport_types => $mtt->message_transport_type, ++ })->store, 'Added a new messaging preference and transport types to patron.'); ++ ok($preference->message_transport_types->{$mtt->message_transport_type}, ++ 'The transport type is stored in the object.'); ++ my $stored_transports = Koha::Patron::Message::Transport::Preferences->search({ ++ borrower_message_preference_id => $preference->borrower_message_preference_id, ++ }); ++ is($stored_transports->next->message_transport_type, $mtt->message_transport_type, ++ 'The transport type is stored in the database.'); ++ ++ $schema->storage->txn_rollback; ++ }; ++}; ++ ++subtest 'Test Koha::Patron::Message::Preference->message_name' => sub { ++ plan tests => 1; ++ ++ $schema->storage->txn_begin; ++ ++ my $patron = build_a_test_patron(); ++ my $attribute = build_a_test_attribute(); ++ my ($preference, $mtt1, $mtt2) = build_a_test_complete_preference({ ++ patron => $patron, ++ attr => $attribute, ++ }); ++ my $message_name_pref = Koha::Patron::Message::Preferences->search_with_message_name({ ++ borrowernumber => $patron->{'borrowernumber'}, ++ message_name => $attribute->message_name, ++ })->next; ++ is($message_name_pref->message_name, $attribute->message_name, "Found preference with message_name"); ++ ++ $schema->storage->txn_rollback; ++}; ++ ++subtest 'Test adding a new preference with invalid parameters' => sub { ++ plan tests => 4; ++ ++ subtest 'Missing parameters' => sub { ++ plan tests => 1; ++ ++ eval { Koha::Patron::Message::Preference->new->store }; ++ is(ref $@, 'Koha::Exceptions::MissingParameter', ++ 'Adding a message preference without parameters' ++ .' => Koha::Exceptions::MissingParameter'); ++ }; ++ ++ subtest 'Too many parameters' => sub { ++ plan tests => 1; ++ ++ $schema->storage->txn_begin; ++ ++ my $patron = build_a_test_patron(); ++ eval { Koha::Patron::Message::Preference->new({ ++ borrowernumber => $patron->borrowernumber, ++ categorycode => $patron->categorycode, ++ })->store }; ++ is(ref $@, 'Koha::Exceptions::TooManyParameters', ++ 'Adding a message preference for both borrowernumber and categorycode' ++ .' => Koha::Exceptions::TooManyParameters'); ++ ++ $schema->storage->txn_rollback; ++ }; ++ ++ subtest 'Bad parameter' => sub { ++ plan tests => 22; ++ ++ $schema->storage->txn_begin; ++ ++ eval { Koha::Patron::Message::Preference->new({ ++ borrowernumber => -999, ++ })->store }; ++ is(ref $@, 'Koha::Exceptions::BadParameter', ++ 'Adding a message preference with invalid borrowernumber' ++ .' => Koha::Exceptions::BadParameter'); ++ is ($@->parameter, 'borrowernumber', 'The previous exception tells us it' ++ .' was the borrowernumber.'); ++ ++ eval { Koha::Patron::Message::Preference->new({ ++ categorycode => 'nonexistent', ++ })->store }; ++ is(ref $@, 'Koha::Exceptions::BadParameter', ++ 'Adding a message preference with invalid categorycode' ++ .' => Koha::Exceptions::BadParameter'); ++ is($@->parameter, 'categorycode', 'The previous exception tells us it' ++ .' was the categorycode.'); ++ ++ my $attribute = build_a_test_attribute({ takes_days => 0 }); ++ my $patron = build_a_test_patron(); ++ eval { Koha::Patron::Message::Preference->new({ ++ borrowernumber => $patron->borrowernumber, ++ message_attribute_id => $attribute->message_attribute_id, ++ days_in_advance => 10, ++ })->store }; ++ is(ref $@, 'Koha::Exceptions::BadParameter', ++ 'Adding a message preference with days in advance option when not' ++ .' available => Koha::Exceptions::BadParameter'); ++ is($@->parameter, 'days_in_advance', 'The previous exception tells us it' ++ .' was the days_in_advance.'); ++ ++ $attribute->set({ takes_days => 1 })->store; ++ eval { Koha::Patron::Message::Preference->new({ ++ borrowernumber => $patron->borrowernumber, ++ message_attribute_id => $attribute->message_attribute_id, ++ days_in_advance => 31, ++ })->store }; ++ is(ref $@, 'Koha::Exceptions::BadParameter', ++ 'Adding a message preference with days in advance option too large' ++ .' => Koha::Exceptions::BadParameter'); ++ is($@->parameter, 'days_in_advance', 'The previous exception tells us it' ++ .' was the days_in_advance.'); ++ ++ eval { Koha::Patron::Message::Preference->new({ ++ borrowernumber => $patron->borrowernumber, ++ message_transport_types => ['nonexistent'] ++ })->store }; ++ is (ref $@, 'Koha::Exceptions::BadParameter', ++ 'Adding a message preference with invalid message_transport_type' ++ .' => Koha::Exceptions::BadParameter'); ++ is ($@->parameter, 'message_transport_types', 'The previous exception ' ++ .'tells us it was the message_transport_types.'); ++ ++ my $mtt_new = build_a_test_transport_type(); ++ eval { ++ Koha::Patron::Message::Preference->new({ ++ borrowernumber => $patron->borrowernumber, ++ message_attribute_id => $attribute->message_attribute_id, ++ message_transport_types => [$mtt_new->message_transport_type], ++ wants_digest => 1, ++ })->store }; ++ is (ref $@, 'Koha::Exceptions::BadParameter', ++ 'Adding a message preference with invalid message_transport_type' ++ .' => Koha::Exceptions::BadParameter'); ++ is ($@->parameter, 'message_transport_types', 'The previous exception ' ++ .'tells us it was the message_transport_types.'); ++ like ($@->error, qr/^No transport configured/, 'Exception is because of ' ++ .'given message_transport_type is not a valid option.'); ++ ++ eval { ++ Koha::Patron::Message::Preference->new({ ++ borrowernumber => $patron->borrowernumber, ++ message_attribute_id => $attribute->message_attribute_id, ++ message_transport_types => [], ++ wants_digest => 1, ++ })->store }; ++ is (ref $@, 'Koha::Exceptions::BadParameter', ++ 'Adding a message preference with invalid message_transport_type' ++ .' => Koha::Exceptions::BadParameter'); ++ is ($@->parameter, 'wants_digest', 'The previous exception tells us it' ++ .' was the wants_digest'); ++ like ($@->error, qr/^Digest cannot be selected/, 'Exception s because of' ++ .' given digest is not available for this transport.'); ++ ++ eval { ++ Koha::Patron::Message::Preference->new({ ++ borrowernumber => $patron->borrowernumber, ++ message_attribute_id => $attribute->message_attribute_id, ++ message_transport_types => [], ++ wants_digest => 0, ++ })->store }; ++ is (ref $@, 'Koha::Exceptions::BadParameter', ++ 'Adding a message preference with invalid message_transport_type' ++ .' => Koha::Exceptions::BadParameter'); ++ is ($@->parameter, 'wants_digest', 'The previous exception tells us it' ++ .' was the wants_digest'); ++ like ($@->error, qr/^Digest must be selected/, 'Exception s because of' ++ .' digest has to be on for this transport.'); ++ ++ eval { ++ Koha::Patron::Message::Preference->new({ ++ borrowernumber => $patron->borrowernumber, ++ message_attribute_id => -1, ++ message_transport_types => [], ++ })->store }; ++ is (ref $@, 'Koha::Exceptions::BadParameter', ++ 'Adding a message preference with invalid message_transport_type' ++ .' => Koha::Exceptions::BadParameter'); ++ is ($@->parameter, 'message_attribute_id', 'The previous exception tells' ++ .' us it was the message_attribute_id'); ++ like ($@->error, qr/^Message attribute with id -1 not found/, 'Exception ' ++ .' is because of given message attribute id is not found.'); ++ ++ $schema->storage->txn_rollback; ++ }; ++ ++ subtest 'Duplicate object' => sub { ++ plan tests => 2; ++ ++ $schema->storage->txn_begin; ++ ++ my $attribute = build_a_test_attribute(); ++ my $letter = build_a_test_letter(); ++ my $mtt = build_a_test_transport_type(); ++ Koha::Patron::Message::Transport->new({ ++ message_attribute_id => $attribute->message_attribute_id, ++ message_transport_type => $mtt->message_transport_type, ++ is_digest => 0, ++ letter_module => $letter->module, ++ letter_code => $letter->code, ++ })->store; ++ my $patron = build_a_test_patron(); ++ my $preference = Koha::Patron::Message::Preference->new({ ++ borrowernumber => $patron->borrowernumber, ++ message_attribute_id => $attribute->message_attribute_id, ++ wants_digest => 0, ++ days_in_advance => undef, ++ })->store; ++ ok($preference->borrower_message_preference_id, ++ 'Added a new messaging preference for patron.'); ++ eval { Koha::Patron::Message::Preference->new({ ++ borrowernumber => $patron->borrowernumber, ++ message_attribute_id => $attribute->message_attribute_id, ++ wants_digest => 0, ++ days_in_advance => undef, ++ })->store }; ++ is(ref $@, 'Koha::Exceptions::DuplicateObject', ++ 'Adding a duplicate preference' ++ .' => Koha::Exceptions::DuplicateObject'); ++ ++ $schema->storage->txn_rollback; ++ }; ++}; ++ ++sub build_a_test_attribute { ++ my ($params) = @_; ++ ++ $params->{takes_days} = $params->{takes_days} && $params->{takes_days} > 0 ++ ? 1 : 0; ++ ++ my $attribute = $builder->build({ ++ source => 'MessageAttribute', ++ value => $params, ++ }); ++ ++ return Koha::Patron::Message::Attributes->find( ++ $attribute->{message_attribute_id} ++ ); ++} ++ ++sub build_a_test_category { ++ my $categorycode = $builder->build({ ++ source => 'Category' })->{categorycode}; ++ ++ return Koha::Patron::Categories->find($categorycode); ++} ++ ++sub build_a_test_letter { ++ my ($params) = @_; ++ ++ my $mtt = $params->{mtt} ? $params->{mtt} : 'email'; ++ my $branchcode = $builder->build({ ++ source => 'Branch' })->{branchcode}; ++ my $letter = $builder->build({ ++ source => 'Letter', ++ value => { ++ branchcode => '', ++ is_html => 0, ++ message_transport_type => $mtt ++ } ++ }); ++ ++ return Koha::Notice::Templates->find({ ++ module => $letter->{module}, ++ code => $letter->{code}, ++ branchcode => $letter->{branchcode}, ++ }); ++} ++ ++sub build_a_test_patron { ++ my $categorycode = $builder->build({ ++ source => 'Category' })->{categorycode}; ++ my $branchcode = $builder->build({ ++ source => 'Branch' })->{branchcode}; ++ my $borrowernumber = $builder->build({ ++ source => 'Borrower' })->{borrowernumber}; ++ ++ return Koha::Patrons->find($borrowernumber); ++} ++ ++sub build_a_test_transport_type { ++ my $mtt = $builder->build({ ++ source => 'MessageTransportType' }); ++ ++ return Koha::Patron::Message::Transport::Types->find( ++ $mtt->{message_transport_type} ++ ); ++} ++ ++sub build_a_test_category_preference { ++ my ($params) = @_; ++ ++ my $patron = $params->{patron}; ++ my $attr = $params->{attr} ++ ? $params->{attr} ++ : build_a_test_attribute($params->{days_in_advance}); ++ ++ my $letter = $params->{letter} ? $params->{letter} : build_a_test_letter(); ++ my $mtt1 = $params->{mtt1} ? $params->{mtt1} : build_a_test_transport_type(); ++ my $mtt2 = $params->{mtt2} ? $params->{mtt2} : build_a_test_transport_type(); ++ ++ Koha::Patron::Message::Transport->new({ ++ message_attribute_id => $attr->message_attribute_id, ++ message_transport_type => $mtt1->message_transport_type, ++ is_digest => $params->{digest} ? 1 : 0, ++ letter_module => $letter->module, ++ letter_code => $letter->code, ++ })->store; ++ ++ Koha::Patron::Message::Transport->new({ ++ message_attribute_id => $attr->message_attribute_id, ++ message_transport_type => $mtt2->message_transport_type, ++ is_digest => $params->{digest} ? 1 : 0, ++ letter_module => $letter->module, ++ letter_code => $letter->code, ++ })->store; ++ ++ my $default = Koha::Patron::Message::Preference->new({ ++ categorycode => $patron->categorycode, ++ message_attribute_id => $attr->message_attribute_id, ++ wants_digest => $params->{digest} ? 1 : 0, ++ days_in_advance => $params->{days_in_advance} ++ ? $params->{days_in_advance} : undef, ++ })->store; ++ ++ Koha::Patron::Message::Transport::Preference->new({ ++ borrower_message_preference_id => $default->borrower_message_preference_id, ++ message_transport_type => $mtt1->message_transport_type, ++ })->store; ++ Koha::Patron::Message::Transport::Preference->new({ ++ borrower_message_preference_id => $default->borrower_message_preference_id, ++ message_transport_type => $mtt2->message_transport_type, ++ })->store; ++ ++ return ($default, $mtt1, $mtt2); ++} ++ ++sub build_a_test_complete_preference { ++ my ($params) = @_; ++ ++ my ($default, $mtt1, $mtt2) = build_a_test_category_preference($params); ++ my $patron = $params->{patron}; ++ $patron->set_default_messaging_preferences; ++ return (Koha::Patron::Message::Preferences->search({ ++ borrowernumber => $patron->borrowernumber ++ })->next, $mtt1, $mtt2); ++} ++ ++sub mytempfile { ++ my ( $fh, $fn ) = tempfile( SUFFIX => '.logger.test', UNLINK => 1 ); ++ print $fh $_[0]//''; ++ close $fh; ++ return $fn; ++} ++ ++1; +diff --git a/t/db_dependent/Koha/Patron/Message/Transport/Preferences.t b/t/db_dependent/Koha/Patron/Message/Transport/Preferences.t +new file mode 100644 +index 0000000..0cdf809 +--- /dev/null ++++ b/t/db_dependent/Koha/Patron/Message/Transport/Preferences.t +@@ -0,0 +1,179 @@ ++#!/usr/bin/perl ++ ++# Copyright 2017 Koha-Suomi Oy ++# ++# This file is part of Koha ++# ++# Koha is free software; you can redistribute it and/or modify it ++# under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# Koha is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with Koha; if not, see . ++ ++use Modern::Perl; ++ ++use Test::More tests => 2; ++ ++use t::lib::Mocks; ++use t::lib::TestBuilder; ++ ++use Koha::Notice::Templates; ++use Koha::Patron::Categories; ++use Koha::Patron::Message::Attributes; ++use Koha::Patron::Message::Preferences; ++use Koha::Patron::Message::Transport::Types; ++use Koha::Patron::Message::Transports; ++use Koha::Patrons; ++ ++my $schema = Koha::Database->new->schema; ++my $builder = t::lib::TestBuilder->new; ++ ++subtest 'Test class imports' => sub { ++ plan tests => 2; ++ ++ use_ok('Koha::Patron::Message::Transport::Preference'); ++ use_ok('Koha::Patron::Message::Transport::Preferences'); ++}; ++ ++subtest 'Test Koha::Patron::Message::Transport::Preferences' => sub { ++ plan tests => 2; ++ ++ $schema->storage->txn_begin; ++ ++ my $attribute = build_a_test_attribute(); ++ my $mtt = build_a_test_transport_type(); ++ my $letter = build_a_test_letter({ ++ mtt => $mtt->message_transport_type ++ }); ++ Koha::Patron::Message::Transport->new({ ++ message_attribute_id => $attribute->message_attribute_id, ++ message_transport_type => $mtt->message_transport_type, ++ is_digest => 0, ++ letter_module => $letter->module, ++ letter_code => $letter->code, ++ })->store; ++ ++ subtest 'For a patron' => sub { ++ my $patron = build_a_test_patron(); ++ my $preference = Koha::Patron::Message::Preference->new({ ++ borrowernumber => $patron->borrowernumber, ++ message_attribute_id => $attribute->message_attribute_id, ++ wants_digest => 0, ++ days_in_advance => undef, ++ })->store; ++ ++ my $pref_id = $preference->borrower_message_preference_id; ++ my $transport_pref = Koha::Patron::Message::Transport::Preference->new({ ++ borrower_message_preference_id => $pref_id, ++ message_transport_type => $mtt->message_transport_type, ++ })->store; ++ is(ref($transport_pref), 'Koha::Patron::Message::Transport::Preference', ++ 'Added a new messaging transport preference for patron.'); ++ ++ $transport_pref->delete; ++ is(Koha::Patron::Message::Transport::Preferences->search({ ++ borrower_message_preference_id => $pref_id, ++ message_transport_type => $mtt->message_transport_type, ++ })->count, 0, 'Deleted the messaging transport preference.'); ++ }; ++ ++ subtest 'For a category' => sub { ++ my $category = build_a_test_category(); ++ my $preference = Koha::Patron::Message::Preference->new({ ++ categorycode => $category->categorycode, ++ message_attribute_id => $attribute->message_attribute_id, ++ wants_digest => 0, ++ days_in_advance => undef, ++ })->store; ++ ++ my $pref_id = $preference->borrower_message_preference_id; ++ my $transport_pref = Koha::Patron::Message::Transport::Preference->new({ ++ borrower_message_preference_id => $pref_id, ++ message_transport_type => $mtt->message_transport_type, ++ })->store; ++ is(ref($transport_pref), 'Koha::Patron::Message::Transport::Preference', ++ 'Added a new messaging transport preference for category.'); ++ ++ $transport_pref->delete; ++ is(Koha::Patron::Message::Transport::Preferences->search({ ++ borrower_message_preference_id => $pref_id, ++ message_transport_type => $mtt->message_transport_type, ++ })->count, 0, 'Deleted the messaging transport preference.'); ++ }; ++ ++ $schema->storage->txn_rollback; ++}; ++ ++sub build_a_test_attribute { ++ my ($params) = @_; ++ ++ $params->{takes_days} = $params->{takes_days} && $params->{takes_days} > 0 ++ ? 1 : 0; ++ ++ my $attribute = $builder->build({ ++ source => 'MessageAttribute', ++ value => $params, ++ }); ++ ++ return Koha::Patron::Message::Attributes->find( ++ $attribute->{message_attribute_id} ++ ); ++} ++ ++sub build_a_test_category { ++ my $categorycode = $builder->build({ ++ source => 'Category' })->{categorycode}; ++ ++ return Koha::Patron::Categories->find($categorycode); ++} ++ ++sub build_a_test_letter { ++ my ($params) = @_; ++ ++ my $mtt = $params->{mtt} ? $params->{mtt} : 'email'; ++ my $branchcode = $builder->build({ ++ source => 'Branch' })->{branchcode}; ++ my $letter = $builder->build({ ++ source => 'Letter', ++ value => { ++ branchcode => '', ++ is_html => 0, ++ message_transport_type => $mtt ++ } ++ }); ++ ++ return Koha::Notice::Templates->find({ ++ module => $letter->{module}, ++ code => $letter->{code}, ++ branchcode => $letter->{branchcode}, ++ }); ++} ++ ++sub build_a_test_patron { ++ my $categorycode = $builder->build({ ++ source => 'Category' })->{categorycode}; ++ my $branchcode = $builder->build({ ++ source => 'Branch' })->{branchcode}; ++ my $borrowernumber = $builder->build({ ++ source => 'Borrower' })->{borrowernumber}; ++ ++ return Koha::Patrons->find($borrowernumber); ++} ++ ++sub build_a_test_transport_type { ++ my $mtt = $builder->build({ ++ source => 'MessageTransportType' }); ++ ++ return Koha::Patron::Message::Transport::Types->find( ++ $mtt->{message_transport_type} ++ ); ++} ++ ++1; +diff --git a/t/db_dependent/Koha/Patron/Message/Transport/Types.t b/t/db_dependent/Koha/Patron/Message/Transport/Types.t +new file mode 100644 +index 0000000..cbba32b +--- /dev/null ++++ b/t/db_dependent/Koha/Patron/Message/Transport/Types.t +@@ -0,0 +1,54 @@ ++#!/usr/bin/perl ++ ++# Copyright 2017 Koha-Suomi Oy ++# ++# This file is part of Koha ++# ++# Koha is free software; you can redistribute it and/or modify it ++# under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# Koha is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with Koha; if not, see . ++ ++use Modern::Perl; ++ ++use Test::More tests => 2; ++ ++use Koha::Database; ++ ++my $schema = Koha::Database->new->schema; ++ ++subtest 'Test class imports' => sub { ++ plan tests => 2; ++ ++ use_ok('Koha::Patron::Message::Transport::Type'); ++ use_ok('Koha::Patron::Message::Transport::Types'); ++}; ++ ++subtest 'Test Koha::Patron::Message::Transport::Types' => sub { ++ plan tests => 2; ++ ++ $schema->storage->txn_begin; ++ ++ my $transport_type = Koha::Patron::Message::Transport::Type->new({ ++ message_transport_type => 'test' ++ })->store; ++ ++ is($transport_type->message_transport_type, 'test', ++ 'Added a new message transport type.'); ++ ++ $transport_type->delete; ++ is(Koha::Patron::Message::Transport::Types->find('test'), undef, ++ 'Deleted the message transport type.'); ++ ++ $schema->storage->txn_rollback; ++}; ++ ++1; +diff --git a/t/db_dependent/Koha/Patron/Message/Transports.t b/t/db_dependent/Koha/Patron/Message/Transports.t +new file mode 100644 +index 0000000..b9296fd +--- /dev/null ++++ b/t/db_dependent/Koha/Patron/Message/Transports.t +@@ -0,0 +1,119 @@ ++#!/usr/bin/perl ++ ++# Copyright 2017 Koha-Suomi Oy ++# ++# This file is part of Koha ++# ++# Koha is free software; you can redistribute it and/or modify it ++# under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# Koha is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with Koha; if not, see . ++ ++use Modern::Perl; ++ ++use Test::More tests => 2; ++ ++use t::lib::TestBuilder; ++ ++use Koha::Notice::Templates; ++use Koha::Patron::Message::Attributes; ++use Koha::Patron::Message::Transport::Types; ++ ++my $schema = Koha::Database->new->schema; ++my $builder = t::lib::TestBuilder->new; ++ ++subtest 'Test class imports' => sub { ++ plan tests => 2; ++ ++ use_ok('Koha::Patron::Message::Transport'); ++ use_ok('Koha::Patron::Message::Transports'); ++}; ++ ++subtest 'Test Koha::Patron::Message::Transports' => sub { ++ plan tests => 2; ++ ++ $schema->storage->txn_begin; ++ ++ my $attribute = build_a_test_attribute(); ++ my $mtt = build_a_test_transport_type(); ++ my $letter = build_a_test_letter({ ++ mtt => $mtt->message_transport_type ++ }); ++ ++ my $transport = Koha::Patron::Message::Transport->new({ ++ message_attribute_id => $attribute->message_attribute_id, ++ message_transport_type => $mtt->message_transport_type, ++ is_digest => 0, ++ letter_module => $letter->module, ++ letter_code => $letter->code, ++ })->store; ++ ++ is($transport->message_attribute_id, $attribute->message_attribute_id, ++ 'Added a new messaging transport.'); ++ ++ $transport->delete; ++ is(Koha::Patron::Message::Transports->search({ ++ message_attribute_id => $attribute->message_attribute_id, ++ message_transport_type => $mtt->message_transport_type, ++ is_digest => 0 ++ })->count, 0, 'Deleted the messaging transport.'); ++ ++ $schema->storage->txn_rollback; ++}; ++ ++sub build_a_test_attribute { ++ my ($params) = @_; ++ ++ $params->{takes_days} = $params->{takes_days} && $params->{takes_days} > 0 ++ ? 1 : 0; ++ ++ my $attribute = $builder->build({ ++ source => 'MessageAttribute', ++ value => $params, ++ }); ++ ++ return Koha::Patron::Message::Attributes->find( ++ $attribute->{message_attribute_id} ++ ); ++} ++ ++sub build_a_test_letter { ++ my ($params) = @_; ++ ++ my $mtt = $params->{mtt} ? $params->{mtt} : 'email'; ++ my $branchcode = $builder->build({ ++ source => 'Branch' })->{branchcode}; ++ my $letter = $builder->build({ ++ source => 'Letter', ++ value => { ++ branchcode => '', ++ is_html => 0, ++ message_transport_type => $mtt ++ } ++ }); ++ ++ return Koha::Notice::Templates->find({ ++ module => $letter->{module}, ++ code => $letter->{code}, ++ branchcode => $letter->{branchcode}, ++ }); ++} ++ ++sub build_a_test_transport_type { ++ my $mtt = $builder->build({ ++ source => 'MessageTransportType' }); ++ ++ return Koha::Patron::Message::Transport::Types->find( ++ $mtt->{message_transport_type} ++ ); ++} ++ ++1; +-- +2.7.4 \ No newline at end of file diff --git a/Koha/Exceptions.pm b/Koha/Exceptions.pm index 72a56cc3af..4b58bd2a36 100644 --- a/Koha/Exceptions.pm +++ b/Koha/Exceptions.pm @@ -24,7 +24,13 @@ use Exception::Class ( }, 'Koha::Exceptions::MissingParameter' => { isa => 'Koha::Exceptions::Exception', - description => 'A required parameter is missing' + description => 'A required parameter is missing', + fields => ['parameter'], + }, + 'Koha::Exceptions::TooManyParameters' => { + isa => 'Koha::Exceptions::Exception', + description => 'Too many parameters given', + fields => ['parameter'], }, 'Koha::Exceptions::NoChanges' => { isa => 'Koha::Exceptions::Exception', diff --git a/Koha/Patron.pm b/Koha/Patron.pm index f0ab2d4d3e..367567f2f3 100644 --- a/Koha/Patron.pm +++ b/Koha/Patron.pm @@ -39,6 +39,7 @@ use Koha::Patron::Categories; use Koha::Patron::HouseboundProfile; use Koha::Patron::HouseboundRole; use Koha::Patron::Images; +use Koha::Patron::Message::Preferences; use Koha::Patrons; use Koha::Virtualshelves; use Koha::Club::Enrollments; @@ -1417,6 +1418,47 @@ sub _anonymize_column { $self->$col($val); } +=head3 set_default_messaging_preferences + + $patron->set_default_messaging_preferences + +Sets default messaging preferences on patron. + +See Koha::Patron::Message::Preference(s) for more documentation, especially on +thrown exceptions. + +=cut + +sub set_default_messaging_preferences { + my ($self, $categorycode) = @_; + + my $options = Koha::Patron::Message::Preferences->get_options; + + foreach my $option (@$options) { + # Check that this option has preference configuration for this category + unless (Koha::Patron::Message::Preferences->search({ + message_attribute_id => $option->{message_attribute_id}, + categorycode => $categorycode || $self->categorycode, + })->count) { + next; + } + + # Delete current setting + Koha::Patron::Message::Preferences->search({ + borrowernumber => $self->borrowernumber, + message_attribute_id => $option->{message_attribute_id}, + })->delete; + + Koha::Patron::Message::Preference->new_from_default({ + borrowernumber => $self->borrowernumber, + categorycode => $categorycode || $self->categorycode, + message_attribute_id => $option->{message_attribute_id}, + }); + } + + return $self; +} + =head2 Internal methods =head3 _type diff --git a/Koha/Patron/Message/Attribute.pm b/Koha/Patron/Message/Attribute.pm new file mode 100644 index 0000000000..9d9004c249 --- /dev/null +++ b/Koha/Patron/Message/Attribute.pm @@ -0,0 +1,50 @@ +package Koha::Patron::Message::Attribute; + +# Copyright Koha-Suomi Oy 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version.a +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::Patron::Message::Attribute - Koha Patron Message Attribute object class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'MessageAttribute'; +} + +=head1 AUTHOR + +Lari Taskula + +=cut + +1; diff --git a/Koha/Patron/Message/Attributes.pm b/Koha/Patron/Message/Attributes.pm new file mode 100644 index 0000000000..a2df4e62d9 --- /dev/null +++ b/Koha/Patron/Message/Attributes.pm @@ -0,0 +1,55 @@ +package Koha::Patron::Message::Attributes; + +# Copyright Koha-Suomi Oy 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; +use Koha::Patron::Message::Attribute; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::Patron::Message::Attributes - Koha Patron Message Attributes object class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'MessageAttribute'; +} + +sub object_class { + return 'Koha::Patron::Message::Attribute'; +} + +=head1 AUTHOR + +Lari Taskula + +=cut + +1; diff --git a/Koha/Patron/Message/Preference.pm b/Koha/Patron/Message/Preference.pm new file mode 100644 index 0000000000..db96b2aee3 --- /dev/null +++ b/Koha/Patron/Message/Preference.pm @@ -0,0 +1,451 @@ +package Koha::Patron::Message::Preference; + +# Copyright Koha-Suomi Oy 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version.a +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; +use Koha::Exceptions; +use Koha::Patron::Categories; +use Koha::Patron::Message::Attributes; +use Koha::Patron::Message::Preferences; +use Koha::Patron::Message::Transport::Preferences; +use Koha::Patron::Message::Transport::Types; +use Koha::Patron::Message::Transports; +use Koha::Patrons; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::Patron::Message::Preference - Koha Patron Message Preference object class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 new + +my $preference = Koha::Patron::Message::Preference->new({ + borrowernumber => 123, + #categorycode => 'ABC', + message_attribute_id => 4, + message_transport_types => ['email', 'sms'], # see documentation below + wants_digest => 1, + days_in_advance => 7, +}); + +Takes either borrowernumber or categorycode, but not both. + +days_in_advance may not be available. See message_attributes table for takes_days +configuration. + +wants_digest may not be available. See message_transports table for is_digest +configuration. + +You can instantiate a new object without custom validation errors, but when +storing, validation may throw exceptions. See C for more +documentation. + +C is a parameter that is not actually a column in this +Koha-object. Given this parameter, the message transport types will be added as +related transport types for this object. For get and set, you can access them via +subroutine C in this class. + +=cut + +sub new { + my ($class, $params) = @_; + + my $types = $params->{'message_transport_types'}; + delete $params->{'message_transport_types'}; + + my $self = $class->SUPER::new($params); + + $self->_set_message_transport_types($types); + + return $self; +} + +=head3 new_from_default + +my $preference = Koha::Patron::Message::Preference->new_from_default({ + borrowernumber => 123, + categorycode => 'ABC', # if not given, patron's categorycode will be used + message_attribute_id => 1, +}); + +NOTE: This subroutine initializes and STORES the object (in order to set +message transport types for the preference), so no need to call ->store when +preferences are initialized via this method. + +Stores default messaging preference for C to patron for given +C. + +Throws Koha::Exceptions::MissingParameter if any of following is missing: +- borrowernumber +- message_attribute_id + +Throws Koha::Exceptions::ObjectNotFound if default preferences are not found. + +=cut + +sub new_from_default { + my ($class, $params) = @_; + + my @required = qw(borrowernumber message_attribute_id); + foreach my $p (@required) { + Koha::Exceptions::MissingParameter->throw( + error => 'Missing required parameter.', + parameter => $p, + ) unless exists $params->{$p}; + } + unless ($params->{'categorycode'}) { + my $patron = Koha::Patrons->find($params->{borrowernumber}); + $params->{'categorycode'} = $patron->categorycode; + } + + my $default = Koha::Patron::Message::Preferences->find({ + categorycode => $params->{'categorycode'}, + message_attribute_id => $params->{'message_attribute_id'}, + }); + Koha::Exceptions::ObjectNotFound->throw( + error => 'Default messaging preference for given categorycode and' + .' message_attribute_id cannot be found.', + ) unless $default; + $default = $default->unblessed; + + # Add a new messaging preference for patron + my $self = $class->SUPER::new({ + borrowernumber => $params->{'borrowernumber'}, + message_attribute_id => $default->{'message_attribute_id'}, + days_in_advance => $default->{'days_in_advance'}, + wants_digest => $default->{'wants_digest'}, + })->store; + + # Set default messaging transport types + my $default_transport_types = + Koha::Patron::Message::Transport::Preferences->search({ + borrower_message_preference_id => + $default->{'borrower_message_preference_id'} + }); + while (my $transport = $default_transport_types->next) { + Koha::Patron::Message::Transport::Preference->new({ + borrower_message_preference_id => $self->borrower_message_preference_id, + message_transport_type => $transport->message_transport_type, + })->store; + } + + return $self; +} + +=head3 message_name + +$preference->message_name + +Gets message_name for this messaging preference. + +Setter not implemented. + +=cut + +sub message_name { + my ($self) = @_; + + if ($self->{'_message_name'}) { + return $self->{'_message_name'}; + } + $self->{'_message_name'} = Koha::Patron::Message::Attributes->find({ + message_attribute_id => $self->message_attribute_id, + })->message_name; + return $self->{'_message_name'}; +} + +=head3 message_transport_types + +$preference->message_transport_types +Returns a HASHREF of message transport types for this messaging preference, e.g. +if ($preference->message_transport_types->{'email'}) { + # email is one of the transport preferences +} + +$preference->message_transport_types('email', 'sms'); +Sets the given message transport types for this messaging preference + +=cut + +sub message_transport_types { + my $self = shift; + + unless (@_) { + if ($self->{'_message_transport_types'}) { + return $self->{'_message_transport_types'}; + } + map { + my $transport = Koha::Patron::Message::Transports->find({ + message_attribute_id => $self->message_attribute_id, + message_transport_type => $_->message_transport_type, + is_digest => $self->wants_digest + }); + unless ($transport) { + my $logger = Koha::Logger->get; + $logger->warn( + $self->message_name . ' has no transport with '. + $_->message_transport_type . ' (digest: '. + ($self->wants_digest ? 'yes':'no').').' + ); + } + $self->{'_message_transport_types'}->{$_->message_transport_type} + = $transport ? $transport->letter_code : ' '; + } + Koha::Patron::Message::Transport::Preferences->search({ + borrower_message_preference_id => $self->borrower_message_preference_id, + })->as_list; + return $self->{'_message_transport_types'} || {}; + } + else { + $self->_set_message_transport_types(@_); + return $self; + } +} + +=head3 set + +$preference->set({ + message_transport_types => ['sms', 'phone'], + wants_digest => 0, +})->store; + +Sets preference object values and additionally message_transport_types if given. + +=cut + +sub set { + my ($self, $params) = @_; + + my $mtt = $params->{'message_transport_types'}; + delete $params->{'message_transport_types'}; + + $self->SUPER::set($params) if $params; + if ($mtt) { + $self->message_transport_types($mtt); + } + + return $self; +} + +=head3 store + +Makes a validation before actual Koha::Object->store so that proper exceptions +can be thrown. See C for documentation about exceptions. + +=cut + +sub store { + my $self = shift; + + $self->validate->SUPER::store(@_); + + # store message transport types + if (exists $self->{'_message_transport_types'}) { + Koha::Patron::Message::Transport::Preferences->search({ + borrower_message_preference_id => + $self->borrower_message_preference_id, + })->delete; + foreach my $type (keys %{$self->{'_message_transport_types'}}) { + Koha::Patron::Message::Transport::Preference->new({ + borrower_message_preference_id => + $self->borrower_message_preference_id, + message_transport_type => $type, + })->store; + } + } + + return $self; +} + +=head3 validate + +Makes a basic validation for object. + +Throws following exceptions regarding parameters. +- Koha::Exceptions::MissingParameter +- Koha::Exceptions::TooManyParameters +- Koha::Exceptions::BadParameter + +See $_->parameter to identify the parameter causing the exception. + +Throws Koha::Exceptions::DuplicateObject if this preference already exists. + +Returns Koha::Patron::Message::Preference object. + +=cut + +sub validate { + my ($self) = @_; + + if ($self->borrowernumber && $self->categorycode) { + Koha::Exceptions::TooManyParameters->throw( + error => 'Both borrowernumber and category given, only one accepted', + parameter => ['borrowernumber', 'categorycode'], + ); + } + if (!$self->borrowernumber && !$self->categorycode) { + Koha::Exceptions::MissingParameter->throw( + error => 'borrowernumber or category required, none given', + parameter => ['borrowernumber', 'categorycode'], + ); + } + if ($self->borrowernumber) { + Koha::Exceptions::BadParameter->throw( + error => 'Patron not found.', + parameter => 'borrowernumber', + ) unless Koha::Patrons->find($self->borrowernumber); + } + if ($self->categorycode) { + Koha::Exceptions::BadParameter->throw( + error => 'Category not found.', + parameter => 'categorycode', + ) unless Koha::Patron::Categories->find($self->categorycode); + } + + if (!$self->in_storage) { + my $previous = Koha::Patron::Message::Preferences->search({ + borrowernumber => $self->borrowernumber, + categorycode => $self->categorycode, + message_attribute_id => $self->message_attribute_id, + }); + if ($previous->count) { + Koha::Exceptions::DuplicateObject->throw( + error => 'A preference for this borrower/category and' + .' message_attribute_id already exists', + ); + } + } + + my $attr = Koha::Patron::Message::Attributes->find( + $self->message_attribute_id + ); + unless ($attr) { + Koha::Exceptions::BadParameter->throw( + error => 'Message attribute with id '.$self->message_attribute_id + .' not found', + parameter => 'message_attribute_id' + ); + } + if (defined $self->days_in_advance) { + if ($attr && $attr->takes_days == 0) { + Koha::Exceptions::BadParameter->throw( + error => 'days_in_advance cannot be defined for '. + $attr->message_name . '.', + parameter => 'days_in_advance', + ); + } + elsif ($self->days_in_advance < 0 || $self->days_in_advance > 30) { + Koha::Exceptions::BadParameter->throw( + error => 'days_in_advance has to be a value between 0-30 for '. + $attr->message_name . '.', + parameter => 'days_in_advance', + ); + } + } + if (defined $self->wants_digest) { + my $transports = Koha::Patron::Message::Transports->search({ + message_attribute_id => $self->message_attribute_id, + is_digest => $self->wants_digest ? 1 : 0, + }); + Koha::Exceptions::BadParameter->throw( + error => (!$self->wants_digest ? 'Digest must be selected' + : 'Digest cannot be selected') + . ' for '.$attr->message_name.'.', + parameter => 'wants_digest', + ) if $transports->count == 0; + } + + return $self; +} + +sub _set_message_transport_types { + my $self = shift; + + return unless $_[0]; + + $self->{'_message_transport_types'} = undef; + my $types = ref $_[0] eq "ARRAY" ? $_[0] : [@_]; + return unless $types; + $self->_validate_message_transport_types({ message_transport_types => $types }); + foreach my $type (@$types) { + unless (exists $self->{'_message_transport_types'}->{$type}) { + my $transport = Koha::Patron::Message::Transports->find({ + message_attribute_id => $self->message_attribute_id, + message_transport_type => $type + }); + unless ($transport) { + Koha::Exceptions::BadParameter->throw( + error => 'No transport configured for '.$self->message_name. + " transport type $type.", + parameter => 'message_transport_types' + ); + } + $self->{'_message_transport_types'}->{$type} + = $transport->letter_code; + } + } + return $self; +} + +sub _validate_message_transport_types { + my ($self, $params) = @_; + + if (ref($params) eq 'HASH' && $params->{'message_transport_types'}) { + if (ref($params->{'message_transport_types'}) ne 'ARRAY') { + $params->{'message_transport_types'} = [$params->{'message_transport_types'}]; + } + my $types = $params->{'message_transport_types'}; + + foreach my $type (@{$types}) { + unless (Koha::Patron::Message::Transport::Types->find({ + message_transport_type => $type + })) { + Koha::Exceptions::BadParameter->throw( + error => "Message transport type '$type' does not exist", + parameter => 'message_transport_types', + ); + } + } + return $types; + } +} + +=head3 type + +=cut + +sub _type { + return 'BorrowerMessagePreference'; +} + +=head1 AUTHOR + +Lari Taskula + +=cut + +1; diff --git a/Koha/Patron/Message/Preferences.pm b/Koha/Patron/Message/Preferences.pm new file mode 100644 index 0000000000..fa8e974ee0 --- /dev/null +++ b/Koha/Patron/Message/Preferences.pm @@ -0,0 +1,146 @@ +package Koha::Patron::Message::Preferences; + +# Copyright Koha-Suomi Oy 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; +use Koha::Patron::Message::Attributes; +use Koha::Patron::Message::Preference; +use Koha::Patron::Message::Transports; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::Patron::Message::Preferences - Koha Patron Message Preferences object class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 find_with_message_name + +Koha::Patron::Message::Preferences->find_with_message_name({ + borrowernumber => 123, + message_name => 'Hold_Filled', +}); + +Converts C into C and continues find. + +=cut + +sub find_with_message_name { + my ($self, $id) = @_; + + if (ref($id) eq "HASH" && $id->{'message_name'}) { + my $attr = Koha::Patron::Message::Attributes->find({ + message_name => $id->{'message_name'}, + }); + $id->{'message_attribute_id'} = ($attr) ? + $attr->message_attribute_id : undef; + delete $id->{'message_name'}; + } + + return $self->SUPER::find($id); +} + +=head3 get_options + +my $messaging_options = Koha::Patron::Message::Preferences->get_options + +Returns an ARRAYref of HASHrefs on available messaging options. + +=cut + +sub get_options { + my ($self) = @_; + + my $transports = Koha::Patron::Message::Transports->search(undef, + { + join => ['message_attribute'], + '+select' => ['message_attribute.message_name', 'message_attribute.takes_days'], + '+as' => ['message_name', 'takes_days'], + }); + + my $choices; + while (my $transport = $transports->next) { + my $name = $transport->get_column('message_name'); + $choices->{$name}->{'message_attribute_id'} = $transport->message_attribute_id; + $choices->{$name}->{'message_name'} = $name; + $choices->{$name}->{'takes_days'} = $transport->get_column('takes_days'); + $choices->{$name}->{'has_digest'} ||= 1 if $transport->is_digest; + $choices->{$name}->{'has_digest_off'} ||= 1 if !$transport->is_digest; + $choices->{$name}->{'transport_'.$transport->get_column('message_transport_type')} = ' '; + } + + my @return = values %$choices; + @return = sort { $a->{message_attribute_id} <=> $b->{message_attribute_id} } @return; + + return \@return; +} + +=head3 search_with_message_name + +Koha::Patron::Message::Preferences->search_with_message_name({ + borrowernumber => 123, + message_name => 'Hold_Filled', +}); + +Converts C into C and continues search. Use +Koha::Patron::Message::Preferences->search with a proper join for more complicated +searches. + +=cut + +sub search_with_message_name { + my ($self, $params, $attributes) = @_; + + if (ref($params) eq "HASH" && $params->{'message_name'}) { + my $attr = Koha::Patron::Message::Attributes->find({ + message_name => $params->{'message_name'}, + }); + $params->{'message_attribute_id'} = ($attr) ? + $attr->message_attribute_id : undef; + delete $params->{'message_name'}; + } + + return $self->SUPER::search($params, $attributes); +} + +=head3 type + +=cut + +sub _type { + return 'BorrowerMessagePreference'; +} + +sub object_class { + return 'Koha::Patron::Message::Preference'; +} + +=head1 AUTHOR + +Lari Taskula + +=cut + +1; diff --git a/Koha/Patron/Message/Transport.pm b/Koha/Patron/Message/Transport.pm new file mode 100644 index 0000000000..ca0906e600 --- /dev/null +++ b/Koha/Patron/Message/Transport.pm @@ -0,0 +1,50 @@ +package Koha::Patron::Message::Transport; + +# Copyright Koha-Suomi Oy 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version.a +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::Patron::Message::Transport - Koha Patron Message Transport object class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'MessageTransport'; +} + +=head1 AUTHOR + +Lari Taskula + +=cut + +1; diff --git a/Koha/Patron/Message/Transport/Preference.pm b/Koha/Patron/Message/Transport/Preference.pm new file mode 100644 index 0000000000..fe0ddeb08f --- /dev/null +++ b/Koha/Patron/Message/Transport/Preference.pm @@ -0,0 +1,51 @@ +package Koha::Patron::Message::Transport::Preference; + +# Copyright Koha-Suomi Oy 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version.a +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::Patron::Message::Transport::Preference - Koha Patron Message Transport +Preference object class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'BorrowerMessageTransportPreference'; +} + +=head1 AUTHOR + +Lari Taskula + +=cut + +1; diff --git a/Koha/Patron/Message/Transport/Preferences.pm b/Koha/Patron/Message/Transport/Preferences.pm new file mode 100644 index 0000000000..aabd8517a9 --- /dev/null +++ b/Koha/Patron/Message/Transport/Preferences.pm @@ -0,0 +1,56 @@ +package Koha::Patron::Message::Transport::Preferences; + +# Copyright Koha-Suomi Oy 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; +use Koha::Patron::Message::Transport::Preference; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::Patron::Message::Transport::Preferences - Koha Patron Message Transport +Preferences object class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'BorrowerMessageTransportPreference'; +} + +sub object_class { + return 'Koha::Patron::Message::Transport::Preference'; +} + +=head1 AUTHOR + +Lari Taskula + +=cut + +1; diff --git a/Koha/Patron/Message/Transport/Type.pm b/Koha/Patron/Message/Transport/Type.pm new file mode 100644 index 0000000000..4a52a10e3f --- /dev/null +++ b/Koha/Patron/Message/Transport/Type.pm @@ -0,0 +1,51 @@ +package Koha::Patron::Message::Transport::Type; + +# Copyright Koha-Suomi Oy 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version.a +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::Patron::Message::Transport::Type - Koha Patron Message Transport Type +object class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'MessageTransportType'; +} + +=head1 AUTHOR + +Lari Taskula + +=cut + +1; diff --git a/Koha/Patron/Message/Transport/Types.pm b/Koha/Patron/Message/Transport/Types.pm new file mode 100644 index 0000000000..2633ea3e73 --- /dev/null +++ b/Koha/Patron/Message/Transport/Types.pm @@ -0,0 +1,56 @@ +package Koha::Patron::Message::Transport::Types; + +# Copyright Koha-Suomi Oy 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; +use Koha::Patron::Message::Transport::Type; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::Patron::Message::Transport::Types - Koha Patron Message Transport Types +object class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'MessageTransportType'; +} + +sub object_class { + return 'Koha::Patron::Message::Transport::Type'; +} + +=head1 AUTHOR + +Lari Taskula + +=cut + +1; diff --git a/Koha/Patron/Message/Transports.pm b/Koha/Patron/Message/Transports.pm new file mode 100644 index 0000000000..b6aee329b5 --- /dev/null +++ b/Koha/Patron/Message/Transports.pm @@ -0,0 +1,55 @@ +package Koha::Patron::Message::Transports; + +# Copyright Koha-Suomi Oy 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; +use Koha::Patron::Message::Transport; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::Patron::Message::Transports - Koha Patron Message Transports object class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'MessageTransport'; +} + +sub object_class { + return 'Koha::Patron::Message::Transport'; +} + +=head1 AUTHOR + +Lari Taskula + +=cut + +1; diff --git a/installer/data/mysql/atomicupdate/Bug_14620-Contact-information-validation.perl b/installer/data/mysql/atomicupdate/Bug_14620-Contact-information-validation.perl new file mode 100644 index 0000000000..d816b0ca80 --- /dev/null +++ b/installer/data/mysql/atomicupdate/Bug_14620-Contact-information-validation.perl @@ -0,0 +1,7 @@ +$DBversion = 'XXX'; # will be replaced by the RM +if( CheckVersion( $DBversion ) ) { + $dbh->do("INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES ('ValidatePhoneNumber','','','Regex for validation of patron phone numbers.','Textarea')"); + + SetVersion( $DBversion ); + print "Upgrade to $DBversion done (Bug 14620 - description)\n"; +} diff --git a/t/db_dependent/Koha/Patron/Message/Attributes.t b/t/db_dependent/Koha/Patron/Message/Attributes.t new file mode 100644 index 0000000000..836b4f0cd5 --- /dev/null +++ b/t/db_dependent/Koha/Patron/Message/Attributes.t @@ -0,0 +1,74 @@ +#!/usr/bin/perl + +# Copyright 2017 Koha-Suomi Oy +# +# This file is part of Koha +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Test::More tests => 2; + +use Koha::Database; + +my $schema = Koha::Database->new->schema; + +subtest 'Test class imports' => sub { + plan tests => 2; + + use_ok('Koha::Patron::Message::Attribute'); + use_ok('Koha::Patron::Message::Attributes'); +}; + +subtest 'Test Koha::Patron::Message::Attributes' => sub { + plan tests => 6; + + $schema->storage->txn_begin; + + Koha::Patron::Message::Attribute->new({ + message_name => 'Test_Attribute' + })->store; + Koha::Patron::Message::Attribute->new({ + message_name => 'Test_Attribute2', + takes_days => 1 + })->store; + + my $attribute = Koha::Patron::Message::Attributes->find({ + message_name => 'Test_Attribute' }); + my $attribute2 = Koha::Patron::Message::Attributes->find({ + message_name => 'Test_Attribute2' }); + + is($attribute->message_name, 'Test_Attribute', + 'Added a new messaging attribute.'); + is($attribute->takes_days, 0, + 'For that messaging attribute, takes_days is disabled by default.'); + is($attribute2->message_name, 'Test_Attribute2', + 'Added another messaging attribute.'); + is($attribute2->takes_days, 1, + 'takes_days is enabled for that message attribute (as expected).'); + + $attribute->delete; + $attribute2->delete; + is(Koha::Patron::Message::Attributes->find({ + message_name => 'Test_Attribute' }), undef, + 'Deleted the first message attribute.'); + is(Koha::Patron::Message::Attributes->find({ + message_name => 'Test_Attribute2' }), undef, + 'Deleted the second message attribute.'); + + $schema->storage->txn_rollback; +}; + +1; diff --git a/t/db_dependent/Koha/Patron/Message/Preferences.t b/t/db_dependent/Koha/Patron/Message/Preferences.t new file mode 100644 index 0000000000..bd88c6308c --- /dev/null +++ b/t/db_dependent/Koha/Patron/Message/Preferences.t @@ -0,0 +1,719 @@ +#!/usr/bin/perl + +# Copyright 2017 Koha-Suomi Oy +# +# This file is part of Koha +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Test::More tests => 7; + +use t::lib::Mocks; +use t::lib::TestBuilder; + +use C4::Context; + +use Koha::Notice::Templates; +use Koha::Patron::Categories; +use Koha::Patron::Message::Attributes; +use Koha::Patron::Message::Transport::Types; +use Koha::Patron::Message::Transports; +use Koha::Patrons; + +use File::Temp qw/tempfile/; +use Log::Log4perl; + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; + +subtest 'Test class imports' => sub { + plan tests => 2; + + use_ok('Koha::Patron::Message::Preference'); + use_ok('Koha::Patron::Message::Preferences'); +}; + +subtest 'Test Koha::Patron::Message::Preferences' => sub { + plan tests => 2; + + $schema->storage->txn_begin; + + my $attribute = build_a_test_attribute(); + my $letter = build_a_test_letter(); + my $mtt = build_a_test_transport_type(); + Koha::Patron::Message::Transport->new({ + message_attribute_id => $attribute->message_attribute_id, + message_transport_type => $mtt->message_transport_type, + is_digest => 0, + letter_module => $letter->module, + letter_code => $letter->code, + })->store; + + subtest 'Test for a patron' => sub { + plan tests => 3; + + my $patron = build_a_test_patron(); + Koha::Patron::Message::Preference->new({ + borrowernumber => $patron->borrowernumber, + message_attribute_id => $attribute->message_attribute_id, + wants_digest => 0, + days_in_advance => undef, + })->store; + + my $preference = Koha::Patron::Message::Preferences->find({ + borrowernumber => $patron->borrowernumber, + message_attribute_id => $attribute->message_attribute_id + }); + ok($preference->borrower_message_preference_id > 0, + 'Added a new messaging preference for patron.'); + + subtest 'Test set not throwing an exception on duplicate object' => sub { + plan tests => 1; + + Koha::Patron::Message::Attributes->find({ + message_attribute_id => $attribute->message_attribute_id + })->set({ takes_days => 1 })->store; + $preference->set({ days_in_advance => 1 })->store; + is(ref($preference), 'Koha::Patron::Message::Preference', + 'Updating the preference does not cause duplicate object exception'); + }; + + $preference->delete; + is(Koha::Patron::Message::Preferences->search({ + borrowernumber => $patron->borrowernumber, + message_attribute_id => $attribute->message_attribute_id + })->count, 0, 'Deleted the messaging preference.'); + }; + + subtest 'Test for a category' => sub { + my $category = build_a_test_category(); + Koha::Patron::Message::Preference->new({ + categorycode => $category->categorycode, + message_attribute_id => $attribute->message_attribute_id, + wants_digest => 0, + days_in_advance => undef, + })->store; + + my $preference = Koha::Patron::Message::Preferences->find({ + categorycode => $category->categorycode, + message_attribute_id => $attribute->message_attribute_id + }); + ok($preference->borrower_message_preference_id > 0, + 'Added a new messaging preference for category.'); + + $preference->delete; + is(Koha::Patron::Message::Preferences->search({ + categorycode => $category->categorycode, + message_attribute_id => $attribute->message_attribute_id + })->count, 0, 'Deleted the messaging preference.'); + }; + + $schema->storage->txn_rollback; +}; + +subtest 'Test Koha::Patron::Message::Preferences->get_options' => sub { + plan tests => 2; + + subtest 'Test method availability and return value' => sub { + plan tests => 3; + + ok(Koha::Patron::Message::Preferences->can('get_options'), + 'Method get_options is available.'); + ok(my $options = Koha::Patron::Message::Preferences->get_options, + 'Called get_options successfully.'); + is(ref($options), 'ARRAY', 'get_options returns a ARRAYref'); + }; + + subtest 'Make sure options are correct' => sub { + $schema->storage->txn_begin; + my $options = Koha::Patron::Message::Preferences->get_options; + + foreach my $option (@$options) { + my $n = $option->{'message_name'}; + my $attr = Koha::Patron::Message::Attributes->find($option->{'message_attribute_id'}); + is($option->{'message_attribute_id'}, $attr->message_attribute_id, + '$n: message_attribute_id is set'); + is($option->{'message_name'}, $attr->message_name, '$n: message_name is set'); + is($option->{'takes_days'}, $attr->takes_days, '$n: takes_days is set'); + my $transports = Koha::Patron::Message::Transports->search({ + message_attribute_id => $option->{'message_attribute_id'}, + is_digest => $option->{'has_digest'} || 0, + }); + while (my $trnzport = $transports->next) { + is($option->{'has_digest'} || 0, $trnzport->is_digest, '$n: has_digest is set for '.$trnzport->message_transport_type); + is($option->{'transport_'.$trnzport->message_transport_type}, ' ', '$n: transport_'.$trnzport->message_transport_type.' is set'); + } + } + + $schema->storage->txn_rollback; + }; +}; + +subtest 'Add preferences from defaults' => sub { + plan tests => 3; + + $schema->storage->txn_begin; + + my $patron = build_a_test_patron(); + my ($default, $mtt1, $mtt2) = build_a_test_category_preference({ + patron => $patron, + }); + ok(Koha::Patron::Message::Preference->new_from_default({ + borrowernumber => $patron->borrowernumber, + categorycode => $patron->categorycode, + message_attribute_id => $default->message_attribute_id, + })->store, 'Added a default preference to patron.'); + ok(my $pref = Koha::Patron::Message::Preferences->find({ + borrowernumber => $patron->borrowernumber, + message_attribute_id => $default->message_attribute_id, + }), 'Found the default preference from patron.'); + is(Koha::Patron::Message::Transport::Preferences->search({ + borrower_message_preference_id => $pref->borrower_message_preference_id + })->count, 2, 'Found the two transport types that we set earlier'); + + $schema->storage->txn_rollback; +}; + +subtest 'Test Koha::Patron::Message::Preference->message_transport_types' => sub { + plan tests => 4; + + ok(Koha::Patron::Message::Preference->can('message_transport_types'), + 'Method message_transport_types available'); + + subtest 'get message_transport_types' => sub { + plan tests => 5; + + $schema->storage->txn_begin; + + my $patron = build_a_test_patron(); + my ($preference, $mtt1, $mtt2) = build_a_test_complete_preference({ + patron => $patron + }); + Koha::Patron::Message::Transport::Preferences->search({ + borrower_message_preference_id => $preference->borrower_message_preference_id, + })->delete; + Koha::Patron::Message::Transport::Preference->new({ + borrower_message_preference_id => $preference->borrower_message_preference_id, + message_transport_type => $mtt1->message_transport_type, + })->store; + Koha::Patron::Message::Transport::Preference->new({ + borrower_message_preference_id => $preference->borrower_message_preference_id, + message_transport_type => $mtt2->message_transport_type, + })->store; + my $stored_transports = Koha::Patron::Message::Transport::Preferences->search({ + borrower_message_preference_id => $preference->borrower_message_preference_id, + }); + my $transport1 = Koha::Patron::Message::Transports->find({ + message_attribute_id => $preference->message_attribute_id, + message_transport_type => $mtt1->message_transport_type, + }); + my $transport2 = Koha::Patron::Message::Transports->find({ + message_attribute_id => $preference->message_attribute_id, + message_transport_type => $mtt2->message_transport_type, + }); + my $transports = $preference->message_transport_types; + is(keys %{$transports}, $stored_transports->count, + '->message_transport_types gets correct amount of transport types.'); + is($transports->{$stored_transports->next->message_transport_type}, + $transport1->letter_code, 'Found correct message transport type and letter code.'); + is($transports->{$stored_transports->next->message_transport_type}, + $transport2->letter_code, 'Found correct message transport type and letter code.'); + ok(!$preference->message_transport_types->{'nonexistent'}, + 'Didn\'t find nonexistent transport type.'); + + subtest 'test logging of warnings by invalid message transport type' => sub { + plan tests => 2; + + my $log = mytempfile(); + my $conf = mytempfile( <<"HERE" +log4perl.logger.opac = WARN, OPAC +log4perl.appender.OPAC=Log::Log4perl::Appender::TestBuffer +log4perl.appender.OPAC.filename=$log +log4perl.appender.OPAC.mode=append +log4perl.appender.OPAC.layout=SimpleLayout +log4perl.logger.intranet = WARN, INTRANET +log4perl.appender.INTRANET=Log::Log4perl::Appender::TestBuffer +log4perl.appender.INTRANET.filename=$log +log4perl.appender.INTRANET.mode=append +log4perl.appender.INTRANET.layout=SimpleLayout +HERE + ); + t::lib::Mocks::mock_config('log4perl_conf', $conf); + my $appenders = Log::Log4perl->appenders; + my $appender = Log::Log4perl->appenders->{OPAC}; + + my $pref = Koha::Patron::Message::Preferences->find( + $preference->borrower_message_preference_id + ); + my $transports = $pref->message_transport_types; + is($appender, undef, 'Nothing in buffer yet'); + + my $mtt_new = build_a_test_transport_type(); + Koha::Patron::Message::Transport::Preference->new({ + borrower_message_preference_id => + $pref->borrower_message_preference_id, + message_transport_type => $mtt_new->message_transport_type, + })->store; + $pref = Koha::Patron::Message::Preferences->find( + $pref->borrower_message_preference_id + ); + $transports = $pref->message_transport_types; + $appender = Log::Log4perl->appenders->{OPAC}; + my $name = $pref->message_name; + my $tt = $mtt_new->message_transport_type; + like($appender->buffer, qr/WARN - $name has no transport with $tt/, + 'Logged invalid message transport type'); + }; + + $schema->storage->txn_rollback; + }; + + subtest 'set message_transport_types' => sub { + plan tests => 6; + + $schema->storage->txn_begin; + + my $patron = build_a_test_patron(); + my ($preference, $mtt1, $mtt2) = build_a_test_complete_preference({ + patron => $patron + }); + + my $mtt1_str = $mtt1->message_transport_type; + my $mtt2_str = $mtt2->message_transport_type; + # 1/3, use message_transport_types(list) + Koha::Patron::Message::Transport::Preferences->search({ + borrower_message_preference_id => $preference->borrower_message_preference_id, + })->delete; + ok($preference->message_transport_types($mtt1_str, $mtt2_str)->store, + '1/3 Set returned true.'); + my $stored_transports = Koha::Patron::Message::Transport::Preferences->search({ + borrower_message_preference_id => $preference->borrower_message_preference_id, + '-or' => [ + message_transport_type => $mtt1_str, + message_transport_type => $mtt2_str + ] + }); + is($stored_transports->count, 2, 'Two transports selected'); + + # 2/3, use message_transport_types(ARRAYREF) + Koha::Patron::Message::Transport::Preferences->search({ + borrower_message_preference_id => $preference->borrower_message_preference_id, + })->delete; + ok($preference->message_transport_types([$mtt1_str, $mtt2_str])->store, + '2/3 Set returned true.'); + $stored_transports = Koha::Patron::Message::Transport::Preferences->search({ + borrower_message_preference_id => $preference->borrower_message_preference_id, + '-or' => [ + message_transport_type => $mtt1_str, + message_transport_type => $mtt2_str + ] + }); + is($stored_transports->count, 2, 'Two transports selected'); + + # 3/3, use set({ message_transport_types => ARRAYREF }) + Koha::Patron::Message::Transport::Preferences->search({ + borrower_message_preference_id => $preference->borrower_message_preference_id, + })->delete; + ok($preference->set({ + message_transport_types => [$mtt1_str, $mtt2_str]})->store, + '3/3 Set returned true.'); + $stored_transports = Koha::Patron::Message::Transport::Preferences->search({ + borrower_message_preference_id => $preference->borrower_message_preference_id, + '-or' => [ + message_transport_type => $mtt1_str, + message_transport_type => $mtt2_str + ] + }); + is($stored_transports->count, 2, 'Two transports selected'); + + $schema->storage->txn_rollback; + }; + + subtest 'new message_transport_types' => sub { + plan tests => 3; + + $schema->storage->txn_begin; + + my $patron = build_a_test_patron(); + my $letter = build_a_test_letter(); + my $attribute = build_a_test_attribute(); + my $mtt = build_a_test_transport_type(); + Koha::Patron::Message::Transport->new({ + message_attribute_id => $attribute->message_attribute_id, + message_transport_type => $mtt->message_transport_type, + is_digest => 0, + letter_module => $letter->module, + letter_code => $letter->code, + })->store; + ok(my $preference = Koha::Patron::Message::Preference->new({ + borrowernumber => $patron->borrowernumber, + message_attribute_id => $attribute->message_attribute_id, + wants_digest => 0, + days_in_advance => undef, + message_transport_types => $mtt->message_transport_type, + })->store, 'Added a new messaging preference and transport types to patron.'); + ok($preference->message_transport_types->{$mtt->message_transport_type}, + 'The transport type is stored in the object.'); + my $stored_transports = Koha::Patron::Message::Transport::Preferences->search({ + borrower_message_preference_id => $preference->borrower_message_preference_id, + }); + is($stored_transports->next->message_transport_type, $mtt->message_transport_type, + 'The transport type is stored in the database.'); + + $schema->storage->txn_rollback; + }; +}; + +subtest 'Test Koha::Patron::Message::Preference->message_name' => sub { + plan tests => 1; + + $schema->storage->txn_begin; + + my $patron = build_a_test_patron(); + my $attribute = build_a_test_attribute(); + my ($preference, $mtt1, $mtt2) = build_a_test_complete_preference({ + patron => $patron, + attr => $attribute, + }); + my $message_name_pref = Koha::Patron::Message::Preferences->search_with_message_name({ + borrowernumber => $patron->{'borrowernumber'}, + message_name => $attribute->message_name, + })->next; + is($message_name_pref->message_name, $attribute->message_name, "Found preference with message_name"); + + $schema->storage->txn_rollback; +}; + +subtest 'Test adding a new preference with invalid parameters' => sub { + plan tests => 4; + + subtest 'Missing parameters' => sub { + plan tests => 1; + + eval { Koha::Patron::Message::Preference->new->store }; + is(ref $@, 'Koha::Exceptions::MissingParameter', + 'Adding a message preference without parameters' + .' => Koha::Exceptions::MissingParameter'); + }; + + subtest 'Too many parameters' => sub { + plan tests => 1; + + $schema->storage->txn_begin; + + my $patron = build_a_test_patron(); + eval { Koha::Patron::Message::Preference->new({ + borrowernumber => $patron->borrowernumber, + categorycode => $patron->categorycode, + })->store }; + is(ref $@, 'Koha::Exceptions::TooManyParameters', + 'Adding a message preference for both borrowernumber and categorycode' + .' => Koha::Exceptions::TooManyParameters'); + + $schema->storage->txn_rollback; + }; + + subtest 'Bad parameter' => sub { + plan tests => 22; + + $schema->storage->txn_begin; + + eval { Koha::Patron::Message::Preference->new({ + borrowernumber => -999, + })->store }; + is(ref $@, 'Koha::Exceptions::BadParameter', + 'Adding a message preference with invalid borrowernumber' + .' => Koha::Exceptions::BadParameter'); + is ($@->parameter, 'borrowernumber', 'The previous exception tells us it' + .' was the borrowernumber.'); + + eval { Koha::Patron::Message::Preference->new({ + categorycode => 'nonexistent', + })->store }; + is(ref $@, 'Koha::Exceptions::BadParameter', + 'Adding a message preference with invalid categorycode' + .' => Koha::Exceptions::BadParameter'); + is($@->parameter, 'categorycode', 'The previous exception tells us it' + .' was the categorycode.'); + + my $attribute = build_a_test_attribute({ takes_days => 0 }); + my $patron = build_a_test_patron(); + eval { Koha::Patron::Message::Preference->new({ + borrowernumber => $patron->borrowernumber, + message_attribute_id => $attribute->message_attribute_id, + days_in_advance => 10, + })->store }; + is(ref $@, 'Koha::Exceptions::BadParameter', + 'Adding a message preference with days in advance option when not' + .' available => Koha::Exceptions::BadParameter'); + is($@->parameter, 'days_in_advance', 'The previous exception tells us it' + .' was the days_in_advance.'); + + $attribute->set({ takes_days => 1 })->store; + eval { Koha::Patron::Message::Preference->new({ + borrowernumber => $patron->borrowernumber, + message_attribute_id => $attribute->message_attribute_id, + days_in_advance => 31, + })->store }; + is(ref $@, 'Koha::Exceptions::BadParameter', + 'Adding a message preference with days in advance option too large' + .' => Koha::Exceptions::BadParameter'); + is($@->parameter, 'days_in_advance', 'The previous exception tells us it' + .' was the days_in_advance.'); + + eval { Koha::Patron::Message::Preference->new({ + borrowernumber => $patron->borrowernumber, + message_transport_types => ['nonexistent'] + })->store }; + is (ref $@, 'Koha::Exceptions::BadParameter', + 'Adding a message preference with invalid message_transport_type' + .' => Koha::Exceptions::BadParameter'); + is ($@->parameter, 'message_transport_types', 'The previous exception ' + .'tells us it was the message_transport_types.'); + + my $mtt_new = build_a_test_transport_type(); + eval { + Koha::Patron::Message::Preference->new({ + borrowernumber => $patron->borrowernumber, + message_attribute_id => $attribute->message_attribute_id, + message_transport_types => [$mtt_new->message_transport_type], + wants_digest => 1, + })->store }; + is (ref $@, 'Koha::Exceptions::BadParameter', + 'Adding a message preference with invalid message_transport_type' + .' => Koha::Exceptions::BadParameter'); + is ($@->parameter, 'message_transport_types', 'The previous exception ' + .'tells us it was the message_transport_types.'); + like ($@->error, qr/^No transport configured/, 'Exception is because of ' + .'given message_transport_type is not a valid option.'); + + eval { + Koha::Patron::Message::Preference->new({ + borrowernumber => $patron->borrowernumber, + message_attribute_id => $attribute->message_attribute_id, + message_transport_types => [], + wants_digest => 1, + })->store }; + is (ref $@, 'Koha::Exceptions::BadParameter', + 'Adding a message preference with invalid message_transport_type' + .' => Koha::Exceptions::BadParameter'); + is ($@->parameter, 'wants_digest', 'The previous exception tells us it' + .' was the wants_digest'); + like ($@->error, qr/^Digest cannot be selected/, 'Exception s because of' + .' given digest is not available for this transport.'); + + eval { + Koha::Patron::Message::Preference->new({ + borrowernumber => $patron->borrowernumber, + message_attribute_id => $attribute->message_attribute_id, + message_transport_types => [], + wants_digest => 0, + })->store }; + is (ref $@, 'Koha::Exceptions::BadParameter', + 'Adding a message preference with invalid message_transport_type' + .' => Koha::Exceptions::BadParameter'); + is ($@->parameter, 'wants_digest', 'The previous exception tells us it' + .' was the wants_digest'); + like ($@->error, qr/^Digest must be selected/, 'Exception s because of' + .' digest has to be on for this transport.'); + + eval { + Koha::Patron::Message::Preference->new({ + borrowernumber => $patron->borrowernumber, + message_attribute_id => -1, + message_transport_types => [], + })->store }; + is (ref $@, 'Koha::Exceptions::BadParameter', + 'Adding a message preference with invalid message_transport_type' + .' => Koha::Exceptions::BadParameter'); + is ($@->parameter, 'message_attribute_id', 'The previous exception tells' + .' us it was the message_attribute_id'); + like ($@->error, qr/^Message attribute with id -1 not found/, 'Exception ' + .' is because of given message attribute id is not found.'); + + $schema->storage->txn_rollback; + }; + + subtest 'Duplicate object' => sub { + plan tests => 2; + + $schema->storage->txn_begin; + + my $attribute = build_a_test_attribute(); + my $letter = build_a_test_letter(); + my $mtt = build_a_test_transport_type(); + Koha::Patron::Message::Transport->new({ + message_attribute_id => $attribute->message_attribute_id, + message_transport_type => $mtt->message_transport_type, + is_digest => 0, + letter_module => $letter->module, + letter_code => $letter->code, + })->store; + my $patron = build_a_test_patron(); + my $preference = Koha::Patron::Message::Preference->new({ + borrowernumber => $patron->borrowernumber, + message_attribute_id => $attribute->message_attribute_id, + wants_digest => 0, + days_in_advance => undef, + })->store; + ok($preference->borrower_message_preference_id, + 'Added a new messaging preference for patron.'); + eval { Koha::Patron::Message::Preference->new({ + borrowernumber => $patron->borrowernumber, + message_attribute_id => $attribute->message_attribute_id, + wants_digest => 0, + days_in_advance => undef, + })->store }; + is(ref $@, 'Koha::Exceptions::DuplicateObject', + 'Adding a duplicate preference' + .' => Koha::Exceptions::DuplicateObject'); + + $schema->storage->txn_rollback; + }; +}; + +sub build_a_test_attribute { + my ($params) = @_; + + $params->{takes_days} = $params->{takes_days} && $params->{takes_days} > 0 + ? 1 : 0; + + my $attribute = $builder->build({ + source => 'MessageAttribute', + value => $params, + }); + + return Koha::Patron::Message::Attributes->find( + $attribute->{message_attribute_id} + ); +} + +sub build_a_test_category { + my $categorycode = $builder->build({ + source => 'Category' })->{categorycode}; + + return Koha::Patron::Categories->find($categorycode); +} + +sub build_a_test_letter { + my ($params) = @_; + + my $mtt = $params->{mtt} ? $params->{mtt} : 'email'; + my $branchcode = $builder->build({ + source => 'Branch' })->{branchcode}; + my $letter = $builder->build({ + source => 'Letter', + value => { + branchcode => '', + is_html => 0, + message_transport_type => $mtt + } + }); + + return Koha::Notice::Templates->find({ + module => $letter->{module}, + code => $letter->{code}, + branchcode => $letter->{branchcode}, + }); +} + +sub build_a_test_patron { + my $categorycode = $builder->build({ + source => 'Category' })->{categorycode}; + my $branchcode = $builder->build({ + source => 'Branch' })->{branchcode}; + my $borrowernumber = $builder->build({ + source => 'Borrower' })->{borrowernumber}; + + return Koha::Patrons->find($borrowernumber); +} + +sub build_a_test_transport_type { + my $mtt = $builder->build({ + source => 'MessageTransportType' }); + + return Koha::Patron::Message::Transport::Types->find( + $mtt->{message_transport_type} + ); +} + +sub build_a_test_category_preference { + my ($params) = @_; + + my $patron = $params->{patron}; + my $attr = $params->{attr} + ? $params->{attr} + : build_a_test_attribute($params->{days_in_advance}); + + my $letter = $params->{letter} ? $params->{letter} : build_a_test_letter(); + my $mtt1 = $params->{mtt1} ? $params->{mtt1} : build_a_test_transport_type(); + my $mtt2 = $params->{mtt2} ? $params->{mtt2} : build_a_test_transport_type(); + + Koha::Patron::Message::Transport->new({ + message_attribute_id => $attr->message_attribute_id, + message_transport_type => $mtt1->message_transport_type, + is_digest => $params->{digest} ? 1 : 0, + letter_module => $letter->module, + letter_code => $letter->code, + })->store; + + Koha::Patron::Message::Transport->new({ + message_attribute_id => $attr->message_attribute_id, + message_transport_type => $mtt2->message_transport_type, + is_digest => $params->{digest} ? 1 : 0, + letter_module => $letter->module, + letter_code => $letter->code, + })->store; + + my $default = Koha::Patron::Message::Preference->new({ + categorycode => $patron->categorycode, + message_attribute_id => $attr->message_attribute_id, + wants_digest => $params->{digest} ? 1 : 0, + days_in_advance => $params->{days_in_advance} + ? $params->{days_in_advance} : undef, + })->store; + + Koha::Patron::Message::Transport::Preference->new({ + borrower_message_preference_id => $default->borrower_message_preference_id, + message_transport_type => $mtt1->message_transport_type, + })->store; + Koha::Patron::Message::Transport::Preference->new({ + borrower_message_preference_id => $default->borrower_message_preference_id, + message_transport_type => $mtt2->message_transport_type, + })->store; + + return ($default, $mtt1, $mtt2); +} + +sub build_a_test_complete_preference { + my ($params) = @_; + + my ($default, $mtt1, $mtt2) = build_a_test_category_preference($params); + my $patron = $params->{patron}; + $patron->set_default_messaging_preferences; + return (Koha::Patron::Message::Preferences->search({ + borrowernumber => $patron->borrowernumber + })->next, $mtt1, $mtt2); +} + +sub mytempfile { + my ( $fh, $fn ) = tempfile( SUFFIX => '.logger.test', UNLINK => 1 ); + print $fh $_[0]//''; + close $fh; + return $fn; +} + +1; diff --git a/t/db_dependent/Koha/Patron/Message/Transport/Preferences.t b/t/db_dependent/Koha/Patron/Message/Transport/Preferences.t new file mode 100644 index 0000000000..0cdf8095a4 --- /dev/null +++ b/t/db_dependent/Koha/Patron/Message/Transport/Preferences.t @@ -0,0 +1,179 @@ +#!/usr/bin/perl + +# Copyright 2017 Koha-Suomi Oy +# +# This file is part of Koha +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Test::More tests => 2; + +use t::lib::Mocks; +use t::lib::TestBuilder; + +use Koha::Notice::Templates; +use Koha::Patron::Categories; +use Koha::Patron::Message::Attributes; +use Koha::Patron::Message::Preferences; +use Koha::Patron::Message::Transport::Types; +use Koha::Patron::Message::Transports; +use Koha::Patrons; + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; + +subtest 'Test class imports' => sub { + plan tests => 2; + + use_ok('Koha::Patron::Message::Transport::Preference'); + use_ok('Koha::Patron::Message::Transport::Preferences'); +}; + +subtest 'Test Koha::Patron::Message::Transport::Preferences' => sub { + plan tests => 2; + + $schema->storage->txn_begin; + + my $attribute = build_a_test_attribute(); + my $mtt = build_a_test_transport_type(); + my $letter = build_a_test_letter({ + mtt => $mtt->message_transport_type + }); + Koha::Patron::Message::Transport->new({ + message_attribute_id => $attribute->message_attribute_id, + message_transport_type => $mtt->message_transport_type, + is_digest => 0, + letter_module => $letter->module, + letter_code => $letter->code, + })->store; + + subtest 'For a patron' => sub { + my $patron = build_a_test_patron(); + my $preference = Koha::Patron::Message::Preference->new({ + borrowernumber => $patron->borrowernumber, + message_attribute_id => $attribute->message_attribute_id, + wants_digest => 0, + days_in_advance => undef, + })->store; + + my $pref_id = $preference->borrower_message_preference_id; + my $transport_pref = Koha::Patron::Message::Transport::Preference->new({ + borrower_message_preference_id => $pref_id, + message_transport_type => $mtt->message_transport_type, + })->store; + is(ref($transport_pref), 'Koha::Patron::Message::Transport::Preference', + 'Added a new messaging transport preference for patron.'); + + $transport_pref->delete; + is(Koha::Patron::Message::Transport::Preferences->search({ + borrower_message_preference_id => $pref_id, + message_transport_type => $mtt->message_transport_type, + })->count, 0, 'Deleted the messaging transport preference.'); + }; + + subtest 'For a category' => sub { + my $category = build_a_test_category(); + my $preference = Koha::Patron::Message::Preference->new({ + categorycode => $category->categorycode, + message_attribute_id => $attribute->message_attribute_id, + wants_digest => 0, + days_in_advance => undef, + })->store; + + my $pref_id = $preference->borrower_message_preference_id; + my $transport_pref = Koha::Patron::Message::Transport::Preference->new({ + borrower_message_preference_id => $pref_id, + message_transport_type => $mtt->message_transport_type, + })->store; + is(ref($transport_pref), 'Koha::Patron::Message::Transport::Preference', + 'Added a new messaging transport preference for category.'); + + $transport_pref->delete; + is(Koha::Patron::Message::Transport::Preferences->search({ + borrower_message_preference_id => $pref_id, + message_transport_type => $mtt->message_transport_type, + })->count, 0, 'Deleted the messaging transport preference.'); + }; + + $schema->storage->txn_rollback; +}; + +sub build_a_test_attribute { + my ($params) = @_; + + $params->{takes_days} = $params->{takes_days} && $params->{takes_days} > 0 + ? 1 : 0; + + my $attribute = $builder->build({ + source => 'MessageAttribute', + value => $params, + }); + + return Koha::Patron::Message::Attributes->find( + $attribute->{message_attribute_id} + ); +} + +sub build_a_test_category { + my $categorycode = $builder->build({ + source => 'Category' })->{categorycode}; + + return Koha::Patron::Categories->find($categorycode); +} + +sub build_a_test_letter { + my ($params) = @_; + + my $mtt = $params->{mtt} ? $params->{mtt} : 'email'; + my $branchcode = $builder->build({ + source => 'Branch' })->{branchcode}; + my $letter = $builder->build({ + source => 'Letter', + value => { + branchcode => '', + is_html => 0, + message_transport_type => $mtt + } + }); + + return Koha::Notice::Templates->find({ + module => $letter->{module}, + code => $letter->{code}, + branchcode => $letter->{branchcode}, + }); +} + +sub build_a_test_patron { + my $categorycode = $builder->build({ + source => 'Category' })->{categorycode}; + my $branchcode = $builder->build({ + source => 'Branch' })->{branchcode}; + my $borrowernumber = $builder->build({ + source => 'Borrower' })->{borrowernumber}; + + return Koha::Patrons->find($borrowernumber); +} + +sub build_a_test_transport_type { + my $mtt = $builder->build({ + source => 'MessageTransportType' }); + + return Koha::Patron::Message::Transport::Types->find( + $mtt->{message_transport_type} + ); +} + +1; diff --git a/t/db_dependent/Koha/Patron/Message/Transport/Types.t b/t/db_dependent/Koha/Patron/Message/Transport/Types.t new file mode 100644 index 0000000000..cbba32b228 --- /dev/null +++ b/t/db_dependent/Koha/Patron/Message/Transport/Types.t @@ -0,0 +1,54 @@ +#!/usr/bin/perl + +# Copyright 2017 Koha-Suomi Oy +# +# This file is part of Koha +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Test::More tests => 2; + +use Koha::Database; + +my $schema = Koha::Database->new->schema; + +subtest 'Test class imports' => sub { + plan tests => 2; + + use_ok('Koha::Patron::Message::Transport::Type'); + use_ok('Koha::Patron::Message::Transport::Types'); +}; + +subtest 'Test Koha::Patron::Message::Transport::Types' => sub { + plan tests => 2; + + $schema->storage->txn_begin; + + my $transport_type = Koha::Patron::Message::Transport::Type->new({ + message_transport_type => 'test' + })->store; + + is($transport_type->message_transport_type, 'test', + 'Added a new message transport type.'); + + $transport_type->delete; + is(Koha::Patron::Message::Transport::Types->find('test'), undef, + 'Deleted the message transport type.'); + + $schema->storage->txn_rollback; +}; + +1; diff --git a/t/db_dependent/Koha/Patron/Message/Transports.t b/t/db_dependent/Koha/Patron/Message/Transports.t new file mode 100644 index 0000000000..b9296fd3c1 --- /dev/null +++ b/t/db_dependent/Koha/Patron/Message/Transports.t @@ -0,0 +1,119 @@ +#!/usr/bin/perl + +# Copyright 2017 Koha-Suomi Oy +# +# This file is part of Koha +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Test::More tests => 2; + +use t::lib::TestBuilder; + +use Koha::Notice::Templates; +use Koha::Patron::Message::Attributes; +use Koha::Patron::Message::Transport::Types; + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; + +subtest 'Test class imports' => sub { + plan tests => 2; + + use_ok('Koha::Patron::Message::Transport'); + use_ok('Koha::Patron::Message::Transports'); +}; + +subtest 'Test Koha::Patron::Message::Transports' => sub { + plan tests => 2; + + $schema->storage->txn_begin; + + my $attribute = build_a_test_attribute(); + my $mtt = build_a_test_transport_type(); + my $letter = build_a_test_letter({ + mtt => $mtt->message_transport_type + }); + + my $transport = Koha::Patron::Message::Transport->new({ + message_attribute_id => $attribute->message_attribute_id, + message_transport_type => $mtt->message_transport_type, + is_digest => 0, + letter_module => $letter->module, + letter_code => $letter->code, + })->store; + + is($transport->message_attribute_id, $attribute->message_attribute_id, + 'Added a new messaging transport.'); + + $transport->delete; + is(Koha::Patron::Message::Transports->search({ + message_attribute_id => $attribute->message_attribute_id, + message_transport_type => $mtt->message_transport_type, + is_digest => 0 + })->count, 0, 'Deleted the messaging transport.'); + + $schema->storage->txn_rollback; +}; + +sub build_a_test_attribute { + my ($params) = @_; + + $params->{takes_days} = $params->{takes_days} && $params->{takes_days} > 0 + ? 1 : 0; + + my $attribute = $builder->build({ + source => 'MessageAttribute', + value => $params, + }); + + return Koha::Patron::Message::Attributes->find( + $attribute->{message_attribute_id} + ); +} + +sub build_a_test_letter { + my ($params) = @_; + + my $mtt = $params->{mtt} ? $params->{mtt} : 'email'; + my $branchcode = $builder->build({ + source => 'Branch' })->{branchcode}; + my $letter = $builder->build({ + source => 'Letter', + value => { + branchcode => '', + is_html => 0, + message_transport_type => $mtt + } + }); + + return Koha::Notice::Templates->find({ + module => $letter->{module}, + code => $letter->{code}, + branchcode => $letter->{branchcode}, + }); +} + +sub build_a_test_transport_type { + my $mtt = $builder->build({ + source => 'MessageTransportType' }); + + return Koha::Patron::Message::Transport::Types->find( + $mtt->{message_transport_type} + ); +} + +1; -- 2.17.1