Bugzilla – Attachment 42627 Details for
Bug 13757
Make patron attributes editable in the opac if set to 'editable in OPAC'
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 13757 - Make patron attributes editable in the OPAC (2/2)
Bug-13757---Make-patron-attributes-editable-in-the.patch (text/plain), 16.65 KB, created by
Jesse Weaver
on 2015-09-17 00:42:19 UTC
(
hide
)
Description:
Bug 13757 - Make patron attributes editable in the OPAC (2/2)
Filename:
MIME Type:
Creator:
Jesse Weaver
Created:
2015-09-17 00:42:19 UTC
Size:
16.65 KB
patch
obsolete
>From 8dbd77bb08885c59dbadd246ae4acd6886adf62a Mon Sep 17 00:00:00 2001 >From: Jesse Weaver <pianohacker@gmail.com> >Date: Wed, 2 Sep 2015 17:54:04 -0600 >Subject: [PATCH] Bug 13757 - Make patron attributes editable in the OPAC (2/2) > >This patch makes attributes marked as OPAC-editable editable from the >OPAC. > >NOTE: This needs to be extended to work with the modifications system, >and thus only works for new patrons. > >Test plan: > 1) Create attributes that cover the spectrum of possible attribute > types; repeatable, unique, dropdown, etc. > 2) Verify that all of these attributes are correctly validated and > saved. >--- > .../bootstrap/en/modules/opac-memberentry.tt | 108 +++++++++++++++--- > opac/opac-memberentry.pl | 125 +++++++++++++++++++-- > 2 files changed, 205 insertions(+), 28 deletions(-) > >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 ca35988..b68fe31 100644 >--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt >+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt >@@ -1,5 +1,7 @@ >+[% USE AuthorisedValues %] > [% USE Koha %] > [% USE KohaDates %] >+[% USE Math %] > [% SET userupdateview = 1 %] > > [% INCLUDE 'doc-head-open.inc' %] >@@ -70,6 +72,10 @@ > <div class="alert">You typed in the wrong characters in the box before submitting. Please try again.</div> > [% END %] > >+ [% IF ( extended_unique_id_failed_code ) %] >+ <div class="alert" id="extended_unique_id_failed"><a href="#patron-attr-start-[% extended_unique_id_failed_code %]">[% extended_unique_id_failed_description %]</a> value <i>[% extended_unique_id_failed_value %]</i> is already in use.</div> >+ [% END %] >+ > <form method="post" action="/cgi-bin/koha/opac-memberentry.pl" id="memberentry-form"> > > [% UNLESS hidden.defined('branchcode') %] >@@ -750,6 +756,72 @@ > </fieldset> > [% END %] > >+ [% IF ( Koha.Preference('ExtendedPatronAttributes') && patron_attribute_classes.size ) %] >+ [% FOREACH pa_class IN patron_attribute_classes %] >+ [% IF pa_class.class %] >+ <fieldset id="aai_[% pa_loo.class %]" class="rows patron-attributes"> >+ <legend>[% pa_loo.lib %]</legend> >+ [% ELSE %] >+ <fieldset class="rows patron-attributes"> >+ <legend>Additional information</legend> >+ [% END %] >+ <ol class="attributes_table"> >+ [% FOREACH pa IN pa_class.items %] >+ [% FOREACH pa_value IN pa.values %] >+ [% IF loop.first %]<a name="patron-attr-start-[% pa.type.code %]"></a>[% END %] >+ [% form_id = 'patron-attr-' _ Math.int( Math.rand(1000000) ) %] >+ <li data-category_code="[% pa.type.category_code %]"> >+ <label for="[% form_id %]">[% pa.type.description %]: </label> >+ [% IF pa.type.opac_editable %] >+ <input type="hidden" name="patron_attribute_code" value="[% pa.type.code |html %]" /> >+ [% IF ( pa.type.authorised_value_category ) %] >+ <select id="[% form_id %]" name="patron_attribute_value"> >+ <option value=""></option> >+ [% FOREACH auth_val IN AuthorisedValues.Get( pa.type.authorised_value_category, pa_value.value || '', 1 ) %] >+ [% IF ( auth_val.selected ) %] >+ <option value="[% auth_val.authorised_value %]" selected="selected"> >+ [%# Yes, lib; GetAuthorisedValues takes care of intelligently setting this from lib_opac %] >+ [% auth_val.lib %] >+ </option> >+ [% ELSE %] >+ <option value="[% auth_val.authorised_value %]" > >+ [% auth_val.lib %] >+ </option> >+ [% END %] >+ [% END %] >+ </select> >+ [% ELSE %] >+ <textarea rows="2" cols="30" id="[% form_id %]" name="patron_attribute_value">[% pa_value.value %]</textarea> >+ [% END %] >+ [% IF ( pa.type.password_allowed ) %] >+ (<label class="lradio" for="[% form_id %]_password">Password:</label> >+ <input type="password" maxlength="64" value="[% pa_value.password %]" id="[% form_id %]_password" name="patron_attribute_password" />) >+ [% ELSE %] >+ [%# To keep the form inputs lined up in the POST %] >+ <input type="hidden" name="patron_attribute_password" value="" /> >+ [% END %] >+ <a href="#" class="clear-attribute">Clear</a> >+ [% IF ( pa.type.repeatable ) %] >+ <a href="#" class="clone-attribute">New</a> >+ [% END %] >+ [% ELSE %] >+ [% IF ( pa.type.authorised_value_category ) %] >+ [% AuthorisedValues.GetByCode( pa.type.authorised_value, pa_value.value, 1 ) %] >+ [% ELSE %] >+ [% pa_value.value | html_line_break %] >+ [% END %] >+ [% IF ( pa_value.password ) %] >+ (Password: *******) >+ [% END %] >+ [% END %] >+ </li> >+ [% END %] >+ [% END %] >+ </ol> >+ </fieldset> >+ [% END %] >+ [% END %] >+ > [% UNLESS action == 'edit' %] > <fieldset class="rows" id="memberentry_captcha"> > <ol> >@@ -766,24 +838,6 @@ > </fieldset> > [% END %] > >- [% IF ( borrower.ExtendedPatronAttributes ) %] >- <fieldset class="rows"> >- <legend>Additional information</legend> >- <ol> >- [% FOREACH patron_attribute IN borrower.patron_attributes %] >- <li> >- <label>[% patron_attribute.description %]:</label> >- [% IF ( patron_attribute.value_description ) %] >- [% patron_attribute.value_description %] >- [% ELSE %] >- [% patron_attribute.value |html_line_break %] >- [% END %] >- </li> >- [% END %] >- </ol> >- </fieldset> >- [% END %] >- > [% IF action == 'edit' %] > [% IF OPACPatronDetails %] > <fieldset class="action"> >@@ -853,6 +907,24 @@ > error.css('width', 'auto'); > } > }); >+ >+ $(".patron-attributes").on( 'click', '.clear-attribute', function() { >+ $(this).parent() >+ .find('textarea').attr('value', '').end() >+ .find('select').attr('value', '').end(); >+ >+ return false; >+ } ); >+ >+ $(".patron-attributes").on( 'click', '.clone-attribute', function() { >+ var clone = $(this).parent().clone().insertAfter( $(this).parent() ); >+ >+ var newId = 50 + parseInt(Math.random() * 100000); >+ $('input[type!="hidden"],select,textarea', clone).attr('id', 'patron-attr-' + newId).attr('value', ''); >+ $("label", clone).attr('for', 'patron-attr-' + newId).attr('value', ''); >+ >+ return false; >+ } ); > }); > //]]> > </script> >diff --git a/opac/opac-memberentry.pl b/opac/opac-memberentry.pl >index f696208..40957cf 100755 >--- a/opac/opac-memberentry.pl >+++ b/opac/opac-memberentry.pl >@@ -19,9 +19,11 @@ use Modern::Perl; > > use CGI qw ( -utf8 ); > use Digest::MD5 qw( md5_base64 md5_hex ); >+use List::MoreUtils qw( each_array uniq ); > use String::Random qw( random_string ); > > use C4::Auth; >+use C4::Koha qw( GetAuthorisedValueByCode ); > use C4::Output; > use C4::Members; > use C4::Form::MessagingPreferences; >@@ -70,6 +72,21 @@ $template->param( > OPACPatronDetails => C4::Context->preference('OPACPatronDetails'), > ); > >+my $attributes = ParsePatronAttributes($cgi); >+my $conflicting_attribute = 0; >+ >+foreach my $attr (@$attributes) { >+ unless ( C4::Members::Attributes::CheckUniqueness($attr->{code}, $attr->{value}, $borrowernumber) ) { >+ my $attr_info = C4::Members::AttributeTypes->fetch($attr->{code}); >+ $template->param( >+ extended_unique_id_failed_code => $attr->{code}, >+ extended_unique_id_failed_value => $attr->{value}, >+ extended_unique_id_failed_description => $attr_info->description() >+ ); >+ $conflicting_attribute = 1; >+ } >+} >+ > if ( $action eq 'create' ) { > > my %borrower = ParseCgiForBorrower($cgi); >@@ -79,12 +96,13 @@ if ( $action eq 'create' ) { > my @empty_mandatory_fields = CheckMandatoryFields( \%borrower, $action ); > my $invalidformfields = CheckForInvalidFields(\%borrower); > >- if (@empty_mandatory_fields || @$invalidformfields) { >+ if (@empty_mandatory_fields || @$invalidformfields || $conflicting_attribute) { > $template->param( > empty_mandatory_fields => \@empty_mandatory_fields, > invalid_form_fields => $invalidformfields, > borrower => \%borrower > ); >+ $template->param( patron_attribute_classes => GeneratePatronAttributesForm( undef, $attributes ) ); > } > elsif ( > md5_base64( $cgi->param('captcha') ) ne $cgi->param('captcha_digest') ) >@@ -93,6 +111,7 @@ if ( $action eq 'create' ) { > failed_captcha => 1, > borrower => \%borrower > ); >+ $template->param( patron_attribute_classes => GeneratePatronAttributesForm( undef, $attributes ) ); > } > else { > if ( >@@ -150,6 +169,7 @@ if ( $action eq 'create' ) { > C4::Context->preference('OpacPasswordChange') ); > > my ( $borrowernumber, $password ) = AddMember_Opac(%borrower); >+ C4::Members::Attributes::SetBorrowerAttributes( $borrowernumber, $attributes ); > C4::Form::MessagingPreferences::handle_form_action($cgi, { borrowernumber => $borrowernumber }, $template, 1, C4::Context->preference('PatronSelfRegistrationDefaultCategory') ) if $borrowernumber && C4::Context->preference('EnhancedMessagingPreferences'); > > $template->param( password_cleartext => $password ); >@@ -172,12 +192,13 @@ elsif ( $action eq 'update' ) { > CheckMandatoryFields( \%borrower_changes, $action ); > my $invalidformfields = CheckForInvalidFields(\%borrower); > >- if (@empty_mandatory_fields || @$invalidformfields) { >+ if (@empty_mandatory_fields || @$invalidformfields || $conflicting_attribute) { > $template->param( > empty_mandatory_fields => \@empty_mandatory_fields, > invalid_form_fields => $invalidformfields, > borrower => \%borrower > ); >+ $template->param( patron_attribute_classes => GeneratePatronAttributesForm( undef, $attributes ) ); > > $template->param( action => 'edit' ); > } >@@ -215,14 +236,6 @@ elsif ( $action eq 'update' ) { > elsif ( $action eq 'edit' ) { #Display logged in borrower's data > my $borrower = GetMember( borrowernumber => $borrowernumber ); > >- if (C4::Context->preference('ExtendedPatronAttributes')) { >- my $attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber, 'opac'); >- if (scalar(@$attributes) > 0) { >- $borrower->{ExtendedPatronAttributes} = 1; >- $borrower->{patron_attributes} = $attributes; >- } >- } >- > $template->param( > borrower => $borrower, ); > >@@ -235,6 +248,9 @@ elsif ( $action eq 'edit' ) { #Display logged in borrower's data > } > } > >+ $template->param( patron_attribute_classes => GeneratePatronAttributesForm( $borrower ) ); >+} else { >+ $template->param( patron_attribute_classes => GeneratePatronAttributesForm() ); > } > > my $captcha = random_string("CCCCC"); >@@ -361,3 +377,92 @@ sub DelEmptyFields { > > return %borrower; > } >+ >+sub GeneratePatronAttributesForm { >+ my ( $borrower, $entered_attributes ) = @_; >+ >+ use Data::Dumper; warn Dumper( $entered_attributes ); >+ >+ # Get all attribute types and the values for this patron (if applicable) >+ my @types = C4::Members::AttributeTypes::GetAttributeTypes(); >+ >+ if (scalar(@types) == 0) { >+ return []; >+ } >+ >+ my %attr_values = (); >+ >+ if ( $borrower ) { >+ my $attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber); >+ >+ # Remap the patron's attributes into a hash of arrayrefs per attribute (depends on >+ # autovivification) >+ foreach my $attr (@$attributes) { >+ push @{ $attr_values{ $attr->{code} } }, $attr; >+ } >+ } >+ >+ if ( $entered_attributes ) { >+ foreach my $attr (@$entered_attributes) { >+ push @{ $attr_values{ $attr->{code} } }, $attr; >+ } >+ } >+ >+ # Find all existing classes >+ my @classes = uniq( map { $_->{class} } @types ); >+ @classes = sort @classes; >+ my %items_by_class; >+ >+ foreach my $attr_type_desc (@types) { >+ my $attr_type = C4::Members::AttributeTypes->fetch( $attr_type_desc->{code} ); >+ # Make sure this attribute should be displayed in the OPAC >+ next unless ( $attr_type->opac_display() ); >+ # Then, make sure it either has values or is editable >+ next unless ( $attr_values{ $attr_type->code() } || $attr_type->opac_editable() ); >+ >+ push @{ $items_by_class{ $attr_type->class() } }, { >+ type => $attr_type, >+ # If editable, make sure there's at least one empty entry, to make the template's job easier >+ values => $attr_values{ $attr_type->code() } || [{}] >+ }; >+ } >+ >+ use Data::Dumper; warn Dumper( \%items_by_class ); >+ >+ # Finally, build a list of containing classes >+ my @class_loop; >+ foreach my $class (@classes) { >+ next unless ( $items_by_class{$class} ); >+ >+ my $lib = GetAuthorisedValueByCode( 'PA_CLASS', $class, 1 ) || $class; >+ push @class_loop, { >+ class => $class, >+ items => $items_by_class{$class}, >+ lib => $lib, >+ }; >+ } >+ >+ return \@class_loop; >+} >+ >+sub ParsePatronAttributes { >+ my ( $cgi ) = @_; >+ >+ my @codes = $cgi->param('patron_attribute_code'); >+ my @values = $cgi->param('patron_attribute_value'); >+ my @passwords = $cgi->param('patron_attribute_password'); >+ >+ my $ea = each_array( @codes, @values, @passwords ); >+ my @attributes; >+ my %dups = (); >+ >+ while ( my ( $code, $value, $password ) = $ea->() ) { >+ next unless defined($value) and $value ne ''; >+ next if exists $dups{$code}->{$value}; >+ $dups{$code}->{$value} = 1; >+ >+ push @attributes, { code => $code, value => $value, password => $password }; >+ } >+ >+ return \@attributes; >+} >-- >2.5.0
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 13757
:
42254
|
42626
|
42627
|
47625
|
48040
|
48041
|
48042
|
48043
|
48379
|
48380
|
48381
|
48382
|
56924
|
56925
|
56926
|
56927
|
56928
|
56929
|
57041
|
57042
|
57043
|
57044
|
57045
|
57046
|
58252
|
58253
|
58254
|
58255
|
58351
|
58352
|
58353
|
58354
|
58355
|
58356
|
58357
|
58428
|
58429
|
58581
|
58703
|
58706
|
58707
|
58708
|
58709
|
58710
|
58711
|
58712
|
58713
|
58714
|
58715
|
59376
|
59737
|
59738
|
59739
|
59813
|
59896
|
59897
|
59898
|
60359
|
60360
|
61132
|
61133
|
61134
|
61135
|
61136
|
61137
|
61138
|
61139
|
61140
|
61141
|
61142
|
61143
|
61144
|
61145
|
61146
|
61147
|
61148
|
61149
|
61150
|
61492
|
61493
|
61555
|
61556
|
61557
|
61558
|
61559
|
61560
|
61561
|
61562
|
61563
|
61564
|
61565
|
61566
|
61567
|
61568
|
61569
|
61570
|
61571
|
61572
|
61573
|
61574
|
61575