use Try::Tiny;
use C4::Context;
+use C4::Auth qw( checkpw_hash );
use C4::Log qw( logaction );
use Koha::Account;
use Koha::ArticleRequests;
-use C4::Letters;
+use C4::Letters qw( GetPreparedLetter EnqueueLetter SendQueuedMessages );
use Koha::AuthUtils;
use Koha::Checkouts;
use Koha::CirculationRules;
use Koha::Club::Enrollments;
use Koha::Database;
use Koha::DateUtils qw( dt_from_string );
+use Koha::Encryption;
use Koha::Exceptions::Password;
use Koha::Holds;
+use Koha::CurbsidePickups;
use Koha::Old::Checkouts;
use Koha::Patron::Attributes;
use Koha::Patron::Categories;
# Make a copy of the plain text password for later use
$self->plain_text_password( $self->password );
+ $self->password_expiration_date( $self->password
+ ? $self->category->get_password_expiry_date || undef
+ : undef );
# Create a disabled account if no password provided
$self->password( $self->password
? Koha::AuthUtils::hash_password( $self->password )
# Clean up guarantors on category change if required
$self->guarantor_relationships->delete
- if ( $self->category->category_type ne 'C'
- && $self->category->category_type ne 'P' );
+ unless ( $self->category->can_be_guarantee );
}
Delete patron's holds, lists and finally the patron.
-Lists owned by the borrower are deleted, but entries from the borrower to
-other lists are kept.
+Lists owned by the borrower are deleted or ownership is transferred depending on the
+ListOwnershipUponPatronDeletion pref, but entries from the borrower to other lists are kept.
=cut
$hold->cancel;
}
- # Delete all lists and all shares of this borrower
- # Consistent with the approach Koha uses on deleting individual lists
- # Note that entries in virtualshelfcontents added by this borrower to
- # lists of others will be handled by a table constraint: the borrower
- # is set to NULL in those entries.
- # NOTE:
- # We could handle the above deletes via a constraint too.
- # But a new BZ report 11889 has been opened to discuss another approach.
- # Instead of deleting we could also disown lists (based on a pref).
- # In that way we could save shared and public lists.
- # The current table constraints support that idea now.
- # This pref should then govern the results of other routines/methods such as
- # Koha::Virtualshelf->new->delete too.
- # FIXME Could be $patron->get_lists
- $_->delete for Koha::Virtualshelves->search( { owner => $self->borrowernumber } )->as_list;
+ # Handle lists (virtualshelves)
+ $self->virtualshelves->disown_or_delete;
# We cannot have a FK on borrower_modifications.borrowernumber, the table is also used
# for patron selfreg
return $self;
}
-
=head3 category
my $patron_category = $patron->category
return 0;
}
+=head3 password_expired
+
+my $password_expired = $patron->password_expired;
+
+Returns 1 if the patron's password is expired or 0;
+
+=cut
+
+sub password_expired {
+ my ($self) = @_;
+ return 0 unless $self->password_expiration_date;
+ return 1 if dt_from_string( $self->password_expiration_date ) <= dt_from_string->truncate( to => 'day' );
+ return 0;
+}
+
=head3 is_going_to_expire
my $is_going_to_expire = $patron->is_going_to_expire;
}
}
+ if ( C4::Context->preference('NotifyPasswordChange') ) {
+ my $self_from_storage = $self->get_from_storage;
+ if ( !C4::Auth::checkpw_hash( $password, $self_from_storage->password ) ) {
+ my $emailaddr = $self_from_storage->notice_email_address;
+
+ # if we manage to find a valid email address, send notice
+ if ($emailaddr) {
+ my $letter = C4::Letters::GetPreparedLetter(
+ module => 'members',
+ letter_code => 'PASSWORD_CHANGE',
+ branchcode => $self_from_storage->branchcode,
+ ,
+ lang => $self_from_storage->lang || 'default',
+ tables => {
+ 'branches' => $self_from_storage->branchcode,
+ 'borrowers' => $self_from_storage->borrowernumber,
+ },
+ want_librarian => 1,
+ ) or return;
+
+ my $message_id = C4::Letters::EnqueueLetter(
+ {
+ letter => $letter,
+ borrowernumber => $self_from_storage->id,
+ to_address => $emailaddr,
+ message_transport_type => 'email'
+ }
+ );
+ C4::Letters::SendQueuedMessages( { message_id => $message_id } );
+ }
+ }
+ }
+
my $digest = Koha::AuthUtils::hash_password($password);
+ $self->password_expiration_date( $self->category->get_password_expiry_date || undef );
+
# We do not want to call $self->store and retrieve password from DB
$self->password($digest);
$self->login_attempts(0);
return Koha::Old::Checkouts->_new_from_dbic( $old_checkouts );
}
-=head3 get_overdues
+=head3 overdues
-my $overdue_items = $patron->get_overdues
+my $overdue_items = $patron->overdues
Return the overdue items
=cut
-sub get_overdues {
+sub overdues {
my ($self) = @_;
my $dtf = Koha::Database->new->schema->storage->datetime_parser;
return $self->checkouts->search(
);
}
-sub overdues { my $self = shift; return $self->get_overdues(@_); }
-
=head3 get_routing_lists
my $routinglists = $patron->get_routing_lists
return Koha::Old::Holds->_new_from_dbic($old_holds_rs);
}
+=head3 curbside_pickups
+
+my $curbside_pickups = $patron->curbside_pickups;
+
+Return all the curbside pickups for this patron
+
+=cut
+
+sub curbside_pickups {
+ my ($self) = @_;
+ my $curbside_pickups_rs = $self->_result->curbside_pickups_borrowernumbers->search;
+ return Koha::CurbsidePickups->_new_from_dbic($curbside_pickups_rs);
+}
+
=head3 return_claims
my $return_claims = $patron->return_claims
Koha::Patron::Attribute::Types->search(
{
mandatory => 1,
+ category_code => [ undef, $self->categorycode ],
'borrower_attribute_types_branches.b_branchcode' =>
- undef
+ undef,
},
{ join => 'borrower_attribute_types_branches' }
)->get_column('code');
emailpro => 'secondary_email',
flags => undef, # permissions manipulation handled in /permissions
gonenoaddress => 'incorrect_address',
- guarantorid => 'guarantor_id',
lastseen => 'last_seen',
lost => 'patron_card_lost',
opacnote => 'opac_notes',
altcontactsurname => 'altcontact_surname',
altcontactstate => 'altcontact_state',
altcontactzipcode => 'altcontact_postal_code',
+ password_expiration_date => undef,
primary_contact_method => undef,
secret => undef,
auth_method => undef,
sub recalls {
my ( $self ) = @_;
- return Koha::Recalls->search({ borrowernumber => $self->borrowernumber });
+ return Koha::Recalls->search({ patron_id => $self->borrowernumber });
}
=head3 account_balance
return $self->account->balance;
}
+=head3 notify_library_of_registration
+
+$patron->notify_library_of_registration( $email_patron_registrations );
+
+Send patron registration email to library if EmailPatronRegistrations system preference is enabled.
+
+=cut
+
+sub notify_library_of_registration {
+ my ( $self, $email_patron_registrations ) = @_;
+
+ if (
+ my $letter = C4::Letters::GetPreparedLetter(
+ module => 'members',
+ letter_code => 'OPAC_REG',
+ branchcode => $self->branchcode,
+ lang => $self->lang || 'default',
+ tables => {
+ 'borrowers' => $self->borrowernumber
+ },
+ )
+ ) {
+ my $to_address;
+ if ( $email_patron_registrations eq "BranchEmailAddress" ) {
+ my $library = Koha::Libraries->find( $self->branchcode );
+ $to_address = $library->inbound_email_address;
+ }
+ elsif ( $email_patron_registrations eq "KohaAdminEmailAddress" ) {
+ $to_address = C4::Context->preference('ReplytoDefault')
+ || C4::Context->preference('KohaAdminEmailAddress');
+ }
+ else {
+ $to_address =
+ C4::Context->preference('EmailAddressForPatronRegistrations')
+ || C4::Context->preference('ReplytoDefault')
+ || C4::Context->preference('KohaAdminEmailAddress');
+ }
+
+ my $message_id = C4::Letters::EnqueueLetter(
+ {
+ letter => $letter,
+ borrowernumber => $self->borrowernumber,
+ to_address => $to_address,
+ message_transport_type => 'email'
+ }
+ ) or warn "can't enqueue letter $letter";
+ if ( $message_id ) {
+ return 1;
+ }
+ }
+}
=head3 has_messaging_preference
return 0;
}
+=head3 encode_secret
+
+ $patron->encode_secret($secret32);
+
+Secret (TwoFactorAuth expects it in base32 format) is encrypted.
+You still need to call ->store.
+
+=cut
+
+sub encode_secret {
+ my ( $self, $secret ) = @_;
+ if( $secret ) {
+ return $self->secret( Koha::Encryption->new->encrypt_hex($secret) );
+ }
+ return $self->secret($secret);
+}
+
+=head3 decoded_secret
+
+ my $secret32 = $patron->decoded_secret;
+
+Decode the patron secret. We expect to get back a base32 string, but this
+is not checked here. Caller of encode_secret is responsible for that.
+
+=cut
+
+sub decoded_secret {
+ my ( $self ) = @_;
+ if( $self->secret ) {
+ return Koha::Encryption->new->decrypt_hex( $self->secret );
+ }
+ return $self->secret;
+}
+
+=head3 virtualshelves
+
+ my $shelves = $patron->virtualshelves;
+
+=cut
+
+sub virtualshelves {
+ my $self = shift;
+ return Koha::Virtualshelves->_new_from_dbic( scalar $self->_result->virtualshelves );
+}
+
=head2 Internal methods
=head3 _type