From b051ac303f667bf83139a9820e0d6bd749f9a7f8 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Wed, 27 Nov 2019 18:14:24 +0100 Subject: [PATCH] Bug 24151: Sync patron's attributes Sponsored-by: Association KohaLa - https://koha-fr.org/ --- Koha/Anonymized/Patron.pm | 42 +++++++++++ Koha/Patron.pm | 22 +++++- t/db_dependent/Koha/Pseudonymization.t | 125 ++++++++++++++++++++++++++++++++- 3 files changed, 186 insertions(+), 3 deletions(-) diff --git a/Koha/Anonymized/Patron.pm b/Koha/Anonymized/Patron.pm index 0d2fc38c19..52902830e9 100644 --- a/Koha/Anonymized/Patron.pm +++ b/Koha/Anonymized/Patron.pm @@ -21,6 +21,7 @@ use Carp; use Koha::Database; use Koha::Anonymized; +use Koha::Anonymized::Patron::Attributes; use base qw(Koha::Object); @@ -63,6 +64,47 @@ sub update_from_patron { return $self; } +sub add_extended_attribute { + my ( $self, $attribute ) = @_; + delete $attribute->{borrowernumber}; + + return unless Koha::Patron::Attribute::Types->find( + $attribute->{code} )->keep_for_anonymized; + + $self->_result->create_related('anonymized_borrower_attributes', $attribute); +} + + +sub extended_attributes { + my ( $self, $attributes ) = @_; + if ($attributes) { # setter + my $schema = $self->_result->result_source->schema; + $schema->txn_do( + sub { + # Remove the existing one + # FIXME We could use the filtering method, but do not want to copy/paste Koha::Patron::Attributes->filter_by_branch_limitations. + # Will do when Koha::Patron::Attributes will use Koha::Objects::Limit::Library + $self->extended_attributes->delete; + + # Insert the new ones + for my $attribute (@$attributes) { + delete $attribute->{borrowernumber}; + next unless Koha::Patron::Attribute::Types->find( + $attribute->{code} )->keep_for_anonymized; + + $self->_result->create_related('anonymized_borrower_attributes', $attribute); + } + } + ); + } + else { + # Behavior differs from Koha::Patron->extended_attributes + # No need to return them, so moving in else + my $rs = $self->_result->anonymized_borrower_attributes; + return Koha::Anonymized::Patron::Attributes->_new_from_dbic($rs)->search; + } +} + =head2 Internal methods =head3 _type diff --git a/Koha/Patron.pm b/Koha/Patron.pm index 834b6e120d..4ab70552a8 100644 --- a/Koha/Patron.pm +++ b/Koha/Patron.pm @@ -1451,7 +1451,18 @@ sub generate_userid { sub add_extended_attribute { my ($self, $attribute) = @_; $attribute->{borrowernumber} = $self->borrowernumber; - return Koha::Patron::Attribute->new($attribute)->store; + + my $stored = Koha::Patron::Attribute->new($attribute)->store; + + if ( C4::Context->preference('Pseudonymization') ) { + my $anonymized = + Koha::Anonymized::Patrons->find_from_borrowernumber( + $self->borrowernumber ); + $anonymized->add_extended_attribute($attribute); + } + + return $stored; + } =head3 extended_attributes @@ -1475,10 +1486,17 @@ sub extended_attributes { for my $attribute (@$attributes) { $self->_result->create_related('borrower_attributes', $attribute); } + + if ( C4::Context->preference('Pseudonymization') ) { + my $anonymized = + Koha::Anonymized::Patrons->find_from_borrowernumber( + $self->borrowernumber ); + $anonymized->extended_attributes( + $self->extended_attributes->unblessed ); + } } ); } - my $rs = $self->_result->borrower_attributes; # We call search to use the filters in Koha::Patron::Attributes->search return Koha::Patron::Attributes->_new_from_dbic($rs)->search; diff --git a/t/db_dependent/Koha/Pseudonymization.t b/t/db_dependent/Koha/Pseudonymization.t index 37e6de8f2d..8e56e7880a 100644 --- a/t/db_dependent/Koha/Pseudonymization.t +++ b/t/db_dependent/Koha/Pseudonymization.t @@ -19,7 +19,7 @@ use Modern::Perl; -use Test::More tests => 3; +use Test::More tests => 4; use Try::Tiny; use C4::Circulation; @@ -169,3 +169,126 @@ subtest 'Koha::Anonymized::Transactions tests' => sub { $schema->storage->txn_rollback; }; + +subtest 'Koha::Anonymized::Patrons tests' => sub { + + plan tests => 6; + + $schema->storage->txn_begin; + + t::lib::Mocks::mock_config( 'key', '$2a$08$9lmorEKnwQloheaCLFIfje' ); + t::lib::Mocks::mock_preference( 'Pseudonymization', 1 ); + t::lib::Mocks::mock_preference( 'PseudonymizationPatronFields', + 'branchcode,categorycode,sort1' ); + + my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); + my $patron_info = $patron->unblessed; + delete $patron_info->{borrowernumber}; + $patron->delete; + + my $attribute_type1 = Koha::Patron::Attribute::Type->new( + { + code => 'my code1', + description => 'my description1', + repeatable => 1, + keep_for_anonymized => 1, + } + )->store; + my $attribute_type2 = Koha::Patron::Attribute::Type->new( + { + code => 'my code2', + description => 'my description2', + keep_for_anonymized => 0, + } + )->store; + my $attribute_type3 = Koha::Patron::Attribute::Type->new( + { + code => 'my code3', + description => 'my description3', + keep_for_anonymized => 1, + } + )->store; + my $attribute_type4 = Koha::Patron::Attribute::Type->new( + { + code => 'my code4', + description => 'my description4', + keep_for_anonymized => 0, + } + )->store; + my $attribute_type5 = Koha::Patron::Attribute::Type->new( + { + code => 'my code5', + description => 'my description5', + keep_for_anonymized => 1, + } + )->store; + + $patron = Koha::Patron->new($patron_info)->store->get_from_storage; + my $attribute_values = [ + { + attribute => 'attribute for code1', + code => $attribute_type1->code, + }, + { + attribute => 'attribute for code2', + code => $attribute_type2->code + }, + { + attribute => 'attribute for code3', + code => $attribute_type3->code + }, + ]; + + $patron->extended_attributes($attribute_values); + my $anonymized = Koha::Anonymized::Patrons->find_from_borrowernumber( + $patron->borrowernumber ); + my $attributes = $anonymized->extended_attributes; + is( $attributes->count, 2, + 'Only the 2 attributes that have a type with keep_for_anonymized set should be kept' + ); + my $attribute_1 = $attributes->next; + is_deeply( + { attribute => $attribute_1->attribute, code => $attribute_1->code }, + $attribute_values->[0], + 'Attribute 1 should be retrieved correctly' + ); + my $attribute_2 = $attributes->next; + is_deeply( + { attribute => $attribute_2->attribute, code => $attribute_2->code }, + $attribute_values->[2], + 'Attribute 2 should be retrieved correctly' + ); + + # Adding another attribute for code 1, that is repeatable + $patron->add_extended_attribute( + { + attribute => 'attribute 2 for code 1', + code => $attribute_type1->code + } + ); + $attributes = $anonymized->extended_attributes; + is( $attributes->count, 3, + 'New repeatable attribute should have been added' ); + + # Adding an attribute for code 4, that should not be kept + $patron->add_extended_attribute( + { + attribute => 'attribute 1 for code 4', + code => $attribute_type4->code + } + ); + $attributes = $anonymized->extended_attributes; + is( $attributes->count, 3, 'No new attribute kept' ); + + # Adding a new attribute for code 5, no repeatable but kept + $patron->add_extended_attribute( + { + attribute => 'attribute 1 for code 5', + code => $attribute_type5->code + } + ); + $attributes = $anonymized->extended_attributes; + is( $attributes->count, 4, 'New attribute kept' ); + + $schema->storage->txn_rollback; +}; -- 2.11.0