Bugzilla – Attachment 79376 Details for
Bug 20028
Export all patron related personal data in one package
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 20028: Export all patron related personal data in one package
Bug-20028-Export-all-patron-related-personal-data-.patch (text/plain), 14.38 KB, created by
Jon Knight
on 2018-09-25 14:06:00 UTC
(
hide
)
Description:
Bug 20028: Export all patron related personal data in one package
Filename:
MIME Type:
Creator:
Jon Knight
Created:
2018-09-25 14:06:00 UTC
Size:
14.38 KB
patch
obsolete
>From c8750e242c5daeba50c51c2de36017d67a1639a6 Mon Sep 17 00:00:00 2001 >From: Jon Knight <J.P.Knight@lboro.ac.uk> >Date: Tue, 25 Sep 2018 14:00:04 +0000 >Subject: [PATCH] Bug 20028: Export all patron related personal data in one > package > >Add a system preference to determine whether patron data export is permitted, >and if it is an extra option in the staff UI to initiate the export. At this >stage the API for patron data isn't ready so as a placeholder it just goes >to the readingrec.pl script. > >Testing plan: > >* Apply patch. > >* Turn the AllowGDPRPatronExport in the administration sysprefs > >* Search for a patron (eg Mabel in the standard test data) and then > click on the "More" button on the right hand side of the button bar. > You should see "Export patron's GDPR data" option. Selecting that will > generate and download a JSON file containing the patron's data to > your client machine. > >* Turn off AllowGDPRPatronExport in the administration sysprefs > >* The "Export patron's GDPR data" option should no long be visible from > the "More" button in the patron page. >--- > installer/data/mysql/sysprefs.sql | 1 + > .../prog/en/includes/members-toolbar.inc | 3 + > .../prog/en/modules/admin/preferences/patrons.pref | 6 + > koha-tmpl/intranet-tmpl/prog/js/members-menu.js | 8 + > members/readingrec.pl | 252 ++++++++++++++++++++- > 5 files changed, 269 insertions(+), 1 deletion(-) > >diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql >index a08ff3e..d67e100 100644 >--- a/installer/data/mysql/sysprefs.sql >+++ b/installer/data/mysql/sysprefs.sql >@@ -17,6 +17,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` > ('AllFinesNeedOverride','1','0','If on, staff will be asked to override every fine, even if it is below noissuescharge.','YesNo'), > ('AllowAllMessageDeletion','0','','Allow any Library to delete any message','YesNo'), > ('AllowFineOverride','0','0','If on, staff will be able to issue books to patrons with fines greater than noissuescharge.','YesNo'), >+('AllowGDPRPatronExport','1','','If set all data for a patron can be exported from the staff interface.','YesNo'), > ('AllowHoldDateInFuture','0','','If set a date field is displayed on the Hold screen of the Staff Interface, allowing the hold date to be set in the future.','YesNo'), > ('AllowHoldItemTypeSelection','0','','If enabled, patrons and staff will be able to select the itemtype when placing a hold','YesNo'), > ('AllowHoldPolicyOverride','0',NULL,'Allow staff to override hold policies when placing holds','YesNo'), >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/members-toolbar.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/members-toolbar.inc >index 3f9a0ea..f7113bf 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/members-toolbar.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/members-toolbar.inc >@@ -89,6 +89,9 @@ > <li><a id="exportcheckins" href="#">Export today's checked in barcodes</a></li> > [% END %] > [% END %] >+ [% IF Koha.Preference('AllowGDPRPatronExport') %] >+ <li><a id="exportgdprdata" href="#">Export patron's GDPR data</a></li> >+ [% END %] > </ul> > </div> > </div> >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 8c8227d4..1075b5f 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 >@@ -1,6 +1,12 @@ > Patrons: > General: > - >+ - pref: AllowGDPRPatronExport >+ choices: >+ yes: "Allow export" >+ no: "Don't allow export" >+ - of patron data for GDPR compliance. >+ - > - pref: AutoEmailOpacUser > choices: > yes: Send >diff --git a/koha-tmpl/intranet-tmpl/prog/js/members-menu.js b/koha-tmpl/intranet-tmpl/prog/js/members-menu.js >index ecc22b1..dfff51b 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/members-menu.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/members-menu.js >@@ -55,6 +55,11 @@ $(document).ready(function(){ > $(".btn-group").removeClass("open"); > return false; > }); >+ $("#exportgdprdata").click(function(){ >+ export_gdpr_data(); >+ $(".btn-group").removeClass("open"); >+ return false; >+ }); > $("#printsummary").click(function(){ > printx_window("page"); > $(".btn-group").removeClass("open"); >@@ -108,6 +113,9 @@ function confirm_reregistration() { > function export_barcodes() { > window.open('/cgi-bin/koha/members/readingrec.pl?borrowernumber=' + borrowernumber + '&op=export_barcodes'); > } >+function export_gdpr_data() { >+ window.open('/cgi-bin/koha/members/readingrec.pl?borrowernumber=' + borrowernumber + '&op=export_gdprdata'); >+} > var slip_re = /slip/; > function printx_window(print_type) { > var handler = print_type.match(slip_re) ? "printslip" : "summary-print"; >diff --git a/members/readingrec.pl b/members/readingrec.pl >index 4ce115e..ee7e4a0 100755 >--- a/members/readingrec.pl >+++ b/members/readingrec.pl >@@ -30,9 +30,12 @@ use C4::Members; > use List::MoreUtils qw/any uniq/; > use Koha::DateUtils; > use C4::Members::Attributes qw(GetBorrowerAttributes); >+use JSON; >+use Data::Dumper; > > use Koha::Patrons; > use Koha::Patron::Categories; >+use Koha::Account::Lines; > > my $input = CGI->new; > >@@ -54,7 +57,6 @@ if ($input->param('borrowernumber')) { > my $borrowernumber = $input->param('borrowernumber'); > $patron = Koha::Patrons->find( $borrowernumber ); > } >- > my $logged_in_user = Koha::Patrons->find( $loggedinuser ) or die "Not logged in"; > output_and_exit_if_error( $input, $cookie, $template, { module => 'members', logged_in_user => $logged_in_user, current_patron => $patron } ); > >@@ -92,6 +94,254 @@ if ( $op eq 'export_barcodes' ) { > } > } > >+if($op eq 'export_gdprdata') { >+ my $exportedData = { >+ 'patron' => { >+ 'title' => $patron->title, >+ 'surname' => $patron->surname, >+ 'firstname' => $patron->firstname, >+ 'othernames' => $patron->othernames, >+ 'initials' => $patron->initials, >+ 'streetnumber' => $patron->streetnumber, >+ 'streettype' => $patron->streettype, >+ 'address' => $patron->address, >+ 'address2' => $patron->address2, >+ 'city' => $patron->city, >+ 'state' => $patron->state, >+ 'zipcode' => $patron->zipcode, >+ 'country' => $patron->country, >+ 'category_type' => $patron->category->category_type, >+ 'email' => $patron->email, >+ 'phone' => $patron->phone, >+ 'mobile' => $patron->mobile, >+ 'fax' => $patron->fax, >+ 'emailpro' => $patron->emailpro, >+ 'phonepro' => $patron->phonepro, >+ 'B_streetnumber' => $patron->B_streetnumber, >+ 'B_streettype' => $patron->B_streettype, >+ 'B_address' => $patron->B_address, >+ 'B_address2' => $patron->B_address2, >+ 'B_city' => $patron->B_city, >+ 'B_state' => $patron->B_state, >+ 'B_zipcode' => $patron->B_zipcode, >+ 'B_country' => $patron->B_country, >+ 'B_email' => $patron->B_email, >+ 'B_phone' => $patron->B_phone, >+ 'dateoffbirth' => $patron->dateofbirth, >+ 'categorycode' => $patron->categorycode, >+ 'dateenrolled' => $patron->dateenrolled, >+ 'dateexpiry' => $patron->dateexpiry, >+ 'date_renewed' => $patron->date_renewed, >+ 'gonenoaddress' => $patron->gonenoaddress, >+ 'lost' => $patron->lost, >+ 'debarred' => $patron->debarred, >+ 'debarredcomment' => $patron->debarredcomment, >+ 'contactname' => $patron->contactname, >+ 'contactfirstname' => $patron->contactfirstname, >+ 'contacttitle' => $patron->contacttitle, >+ 'borrowernotes' => $patron->borrowernotes, >+ 'sex' => $patron->sex, >+ 'userid' => $patron->userid, >+ 'opacnote' => $patron->opacnote, >+ 'contactnote' => $patron->contactnote, >+ 'altcontactfirstname' => $patron->altcontactfirstname, >+ 'altcontactsurname' => $patron->altcontactsurname, >+ 'altcontactaddress1' => $patron->altcontactaddress1, >+ 'altcontactaddress2' => $patron->altcontactaddress2, >+ 'altcontactaddress3' => $patron->altcontactaddress3, >+ 'altcontactstate' => $patron->altcontactstate, >+ 'altcontactzipcode' => $patron->altcontactzipcode, >+ 'altcontactcountry' => $patron->altcontactcountry, >+ 'altcontactphone' => $patron->altcontactphone, >+ 'smsalertnumber' => $patron->smsalertnumber, >+ 'updated_on' => $patron->updated_on, >+ 'lastseen' => $patron->lastseen, >+ 'lang' => $patron->lang, >+ 'login_attempts' => $patron->login_attempts, >+ 'account_locked' => $patron->account_locked, >+ 'age' => $patron->get_age, >+ 'has_overdues' => $patron->has_overdues, >+ 'borrowernumber' => $patron->borrowernumber, >+ 'cardnumber' => $patron->cardnumber, >+ 'branchcode' => $patron->branchcode, >+ }, >+ }; >+ >+ my $guarantor = $patron->guarantor(); >+ if($guarantor) { >+ $exportedData->{'patron'}->{'guarantor'} = >+ $guarantor->{'borrowernumber'}; >+ } >+ my @guarantees = $patron->guarantees(); >+ if(@guarantees) { >+ foreach my $bod (@guarantees) { >+ push @{$exportedData->{'patron'}->{'guarantees'}}, $bod->borrowernumber; >+ } >+ } >+ >+ my $image = $patron->image; >+ if($image) { >+ $exportedData->{'image'} = { >+ 'mimetype' => $image->mimetype, >+ 'imagefile' => $image->imagefile, >+ }; >+ } >+ >+ my $holds = $patron->holds; >+ if($holds) { >+ while(my $hold = $holds->next()) { >+ push @{$exportedData->{'holds'}}, { >+ 'reserve_id' => $hold->reserve_id, >+ 'reservedate' => $hold->reservedate, >+ 'biblionumber' => $hold->biblionumber, >+ 'branchcode' => $hold->branchcode, >+ 'nofificationdate' => $hold->notificationdate, >+ 'reminderdate' => $hold->reminderdate, >+ 'cancellationdate' => $hold->cancellationdate, >+ 'reservenotes' => $hold->reservenotes, >+ 'priority' => $hold->priority, >+ 'found' => $hold->found, >+ 'timestamp' => $hold->timestamp, >+ 'itemnumber' => $hold->itemnumber, >+ 'waitingdate' => $hold->waitingdate, >+ 'expirationdate' => $hold->expirationdate, >+ 'lowestPriority' => $hold->lowestPriority, >+ 'suspend' => $hold->suspend, >+ 'suspend_until' => $hold->suspend_until, >+ 'itemtype' => $hold->itemtype, >+ } >+ } >+ } >+ >+ my $oldHolds = $patron->old_holds; >+ if($oldHolds) { >+ while(my $hold = $oldHolds->next()) { >+ push @{$exportedData->{'holds'}}, { >+ 'reserve_id' => $hold->reserve_id, >+ 'reservedate' => $hold->reservedate, >+ 'biblionumber' => $hold->biblionumber, >+ 'branchcode' => $hold->branchcode, >+ 'nofificationdate' => $hold->notificationdate, >+ 'reminderdate' => $hold->reminderdate, >+ 'cancellationdate' => $hold->cancellationdate, >+ 'reservenotes' => $hold->reservenotes, >+ 'priority' => $hold->priority, >+ 'found' => $hold->found, >+ 'timestamp' => $hold->timestamp, >+ 'itemnumber' => $hold->itemnumber, >+ 'waitingdate' => $hold->waitingdate, >+ 'expirationdate' => $hold->expirationdate, >+ 'lowestPriority' => $hold->lowestPriority, >+ 'suspend' => $hold->suspend, >+ 'suspend_until' => $hold->suspend_until, >+ 'itemtype' => $hold->itemtype, >+ } >+ } >+ } >+ >+ my $checkouts = $patron->checkouts; >+ if($checkouts) { >+ while(my $checkout = $checkouts->next()) { >+ push @{$exportedData->{'checkouts'}}, { >+ 'issue_id' => $checkout->issue_id, >+ 'itemnumber' => $checkout->itemnumber, >+ 'date_due' => $checkout->date_due, >+ 'branchcode' => $checkout->branchcode, >+ 'returndate' => $checkout->returndate, >+ 'lastreneweddate' => $checkout->lastreneweddate, >+ 'renewals' =>$checkout->renewals, >+ 'auto_renew' => $checkout->auto_renew, >+ 'auto_renew_error' => $checkout->auto_renew_error, >+ 'timestamp' => $checkout->timestamp, >+ 'issuedate' => $checkout->issuedate, >+ 'onsite_checkout' => $checkout->onsite_checkout, >+ 'note' => $checkout->note, >+ 'notedate' => $checkout->notedate, >+ } >+ } >+ } >+ >+ my $oldCheckouts = $patron->old_checkouts; >+ if($oldCheckouts) { >+ while(my $checkout = $oldCheckouts->next()) { >+ push @{$exportedData->{'checkouts'}}, { >+ 'issue_id' => $checkout->issue_id, >+ 'itemnumber' => $checkout->itemnumber, >+ 'date_due' => $checkout->date_due, >+ 'branchcode' => $checkout->branchcode, >+ 'returndate' => $checkout->returndate, >+ 'lastreneweddate' => $checkout->lastreneweddate, >+ 'renewals' =>$checkout->renewals, >+ 'auto_renew' => $checkout->auto_renew, >+ 'auto_renew_error' => $checkout->auto_renew_error, >+ 'timestamp' => $checkout->timestamp, >+ 'issuedate' => $checkout->issuedate, >+ 'onsite_checkout' => $checkout->onsite_checkout, >+ 'note' => $checkout->note, >+ 'notedate' => $checkout->notedate, >+ } >+ } >+ } >+ >+ my $clubs = $patron->get_club_enrollments; >+ if($clubs) { >+ while(my $club = $clubs->next()) { >+ push @{$exportedData->{'clubs'}}, { >+ id => $club->id, >+ date_enrolled => $club->date_enrolled, >+ date_canceled => $club->date_canceled, >+ date_created => $club->date_created, >+ date_updated => $club->date_updated, >+ branchcode => $club->branchcode, >+ } >+ } >+ } >+ >+ my $account = $patron->account; >+ if($account) { >+ $exportedData->{'account'} = { >+ 'balance' => $account->balance, >+ 'non_issues_charges' => $account->non_issues_charges, >+ }; >+ my $acclines = Koha::Account::Lines->search( >+ { >+ borrowernumber => $patron->borrowernumber, >+ }, >+ { >+ order_by => 'accountno' >+ } >+ ); >+ while(my $thisLine = $acclines->next()) { >+ push @{$exportedData->{'account'}->{'accountLines'}}, { >+ 'accountlines_id' => $thisLine->accountlines_id, >+ 'payment_type' => $thisLine->payment_type, >+ 'amountoutstanding' => $thisLine->amountoutstanding, >+ 'accounttype' => $thisLine->accounttype, >+ 'timestamp' => $thisLine->timestamp, >+ 'issue_id' => $thisLine->issue_id, >+ 'description' => $thisLine->description, >+ 'lastincrement' => $thisLine->lastincrement, >+ 'date' => $thisLine->date, >+ 'amount' => $thisLine->amount, >+ 'manager_id' => $thisLine->manager_id, >+ 'note' => $thisLine->note, >+ } >+ } >+ } >+ >+ # Generate the JSON file and spit it out >+ my $today = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 }); >+ my $borrowercardnumber = $patron->cardnumber; >+ print $input->header( >+ -type => 'application/json', >+ -charset => 'utf-8', >+ -attachment => "$today-$borrowercardnumber-GDPR-Export.json" >+ ); >+ my $json = new JSON; >+ print $json->pretty->encode($exportedData); >+ exit; >+} >+ > if (! $limit){ > $limit = 'full'; > } >-- >2.1.4
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 20028
:
75622
|
78095
|
79376
|
79381
|
116344
|
116604
|
117106
|
117107
|
117108
|
117109
|
119968
|
119969
|
119970
|
119971
|
119972
|
119974
|
119975
|
119976
|
119977
|
120844
|
120845
|
120846
|
120847
|
124156
|
124157
|
124158
|
124159
|
124160
|
124161
|
124164
|
124165
|
124166
|
124167
|
124168