| 
      
            Lines 19-27
          use Modern::Perl;
      
      
        Link Here
      
     | 
  
        
          | 19 | 
           | 
          19 | 
           | 
        
        
          | 20 | 
          use CGI qw ( -utf8 );  | 
          20 | 
          use CGI qw ( -utf8 );  | 
        
        
          | 21 | 
          use Digest::MD5 qw( md5_base64 md5_hex );  | 
          21 | 
          use Digest::MD5 qw( md5_base64 md5_hex );  | 
        
            
               | 
               | 
              22 | 
              use List::MoreUtils qw( each_array uniq );  | 
            
        
          | 22 | 
          use String::Random qw( random_string );  | 
          23 | 
          use String::Random qw( random_string );  | 
        
        
          | 23 | 
           | 
          24 | 
           | 
        
        
          | 24 | 
          use C4::Auth;  | 
          25 | 
          use C4::Auth;  | 
        
            
               | 
               | 
              26 | 
              use C4::Koha qw( GetAuthorisedValueByCode );  | 
            
        
          | 25 | 
          use C4::Output;  | 
          27 | 
          use C4::Output;  | 
        
        
          | 26 | 
          use C4::Members;  | 
          28 | 
          use C4::Members;  | 
        
        
          | 27 | 
          use C4::Form::MessagingPreferences;  | 
          29 | 
          use C4::Form::MessagingPreferences;  | 
        
  
    | 
      
            Lines 70-75
          $template->param(
      
      
        Link Here
      
     | 
  
        
          | 70 | 
              OPACPatronDetails => C4::Context->preference('OPACPatronDetails'), | 
          72 | 
              OPACPatronDetails => C4::Context->preference('OPACPatronDetails'), | 
        
        
          | 71 | 
          );  | 
          73 | 
          );  | 
        
        
          | 72 | 
           | 
          74 | 
           | 
        
            
               | 
               | 
              75 | 
              my $attributes = ParsePatronAttributes($cgi);  | 
            
            
              | 76 | 
              my $conflicting_attribute = 0;  | 
            
            
              | 77 | 
               | 
            
            
              | 78 | 
              foreach my $attr (@$attributes) { | 
            
            
              | 79 | 
                  unless ( C4::Members::Attributes::CheckUniqueness($attr->{code}, $attr->{value}, $borrowernumber) ) { | 
            
            
              | 80 | 
                      my $attr_info = C4::Members::AttributeTypes->fetch($attr->{code}); | 
            
            
              | 81 | 
                      $template->param(  | 
            
            
              | 82 | 
                          extended_unique_id_failed_code => $attr->{code}, | 
            
            
              | 83 | 
                          extended_unique_id_failed_value => $attr->{value}, | 
            
            
              | 84 | 
                          extended_unique_id_failed_description => $attr_info->description()  | 
            
            
              | 85 | 
                      );  | 
            
            
              | 86 | 
                      $conflicting_attribute = 1;  | 
            
            
              | 87 | 
                  }  | 
            
            
              | 88 | 
              }  | 
            
            
              | 89 | 
               | 
            
        
          | 73 | 
          if ( $action eq 'create' ) { | 
          90 | 
          if ( $action eq 'create' ) { | 
        
        
          | 74 | 
           | 
          91 | 
           | 
        
        
          | 75 | 
              my %borrower = ParseCgiForBorrower($cgi);  | 
          92 | 
              my %borrower = ParseCgiForBorrower($cgi);  | 
        
  
    | 
      
            Lines 79-90
          if ( $action eq 'create' ) {
      
      
        Link Here
      
     | 
  
        
          | 79 | 
              my @empty_mandatory_fields = CheckMandatoryFields( \%borrower, $action );  | 
          96 | 
              my @empty_mandatory_fields = CheckMandatoryFields( \%borrower, $action );  | 
        
        
          | 80 | 
              my $invalidformfields = CheckForInvalidFields(\%borrower);  | 
          97 | 
              my $invalidformfields = CheckForInvalidFields(\%borrower);  | 
        
        
          | 81 | 
           | 
          98 | 
           | 
        
          
            
              | 82 | 
                  if (@empty_mandatory_fields || @$invalidformfields) { | 
              99 | 
                  if (@empty_mandatory_fields || @$invalidformfields || $conflicting_attribute) { | 
            
        
          | 83 | 
                  $template->param(  | 
          100 | 
                  $template->param(  | 
        
        
          | 84 | 
                      empty_mandatory_fields => \@empty_mandatory_fields,  | 
          101 | 
                      empty_mandatory_fields => \@empty_mandatory_fields,  | 
        
        
          | 85 | 
                      invalid_form_fields    => $invalidformfields,  | 
          102 | 
                      invalid_form_fields    => $invalidformfields,  | 
        
        
          | 86 | 
                      borrower               => \%borrower  | 
          103 | 
                      borrower               => \%borrower  | 
        
        
          | 87 | 
                  );  | 
          104 | 
                  );  | 
        
            
               | 
               | 
              105 | 
                      $template->param( patron_attribute_classes => GeneratePatronAttributesForm( undef, $attributes ) );  | 
            
        
          | 88 | 
              }  | 
          106 | 
              }  | 
        
        
          | 89 | 
              elsif (  | 
          107 | 
              elsif (  | 
        
        
          | 90 | 
                  md5_base64( $cgi->param('captcha') ) ne $cgi->param('captcha_digest') ) | 
          108 | 
                  md5_base64( $cgi->param('captcha') ) ne $cgi->param('captcha_digest') ) | 
        
  
    | 
      
            Lines 93-98
          if ( $action eq 'create' ) {
      
      
        Link Here
      
     | 
  
        
          | 93 | 
                      failed_captcha => 1,  | 
          111 | 
                      failed_captcha => 1,  | 
        
        
          | 94 | 
                      borrower       => \%borrower  | 
          112 | 
                      borrower       => \%borrower  | 
        
        
          | 95 | 
                  );  | 
          113 | 
                  );  | 
        
            
               | 
               | 
              114 | 
                      $template->param( patron_attribute_classes => GeneratePatronAttributesForm( undef, $attributes ) );  | 
            
        
          | 96 | 
              }  | 
          115 | 
              }  | 
        
        
          | 97 | 
              else { | 
          116 | 
              else { | 
        
        
          | 98 | 
                  if (  | 
          117 | 
                  if (  | 
        
  
    | 
      
            Lines 150-155
          if ( $action eq 'create' ) {
      
      
        Link Here
      
     | 
  
        
          | 150 | 
                            C4::Context->preference('OpacPasswordChange') ); | 
          169 | 
                            C4::Context->preference('OpacPasswordChange') ); | 
        
        
          | 151 | 
           | 
          170 | 
           | 
        
        
          | 152 | 
                      my ( $borrowernumber, $password ) = AddMember_Opac(%borrower);  | 
          171 | 
                      my ( $borrowernumber, $password ) = AddMember_Opac(%borrower);  | 
        
            
               | 
               | 
              172 | 
                          C4::Members::Attributes::SetBorrowerAttributes( $borrowernumber, $attributes );  | 
            
        
          | 153 | 
                      C4::Form::MessagingPreferences::handle_form_action($cgi, { borrowernumber => $borrowernumber }, $template, 1, C4::Context->preference('PatronSelfRegistrationDefaultCategory') ) if $borrowernumber && C4::Context->preference('EnhancedMessagingPreferences'); | 
          173 | 
                      C4::Form::MessagingPreferences::handle_form_action($cgi, { borrowernumber => $borrowernumber }, $template, 1, C4::Context->preference('PatronSelfRegistrationDefaultCategory') ) if $borrowernumber && C4::Context->preference('EnhancedMessagingPreferences'); | 
        
        
          | 154 | 
           | 
          174 | 
           | 
        
        
          | 155 | 
                      $template->param( password_cleartext => $password );  | 
          175 | 
                      $template->param( password_cleartext => $password );  | 
        
  
    | 
      
            Lines 172-183
          elsif ( $action eq 'update' ) {
      
      
        Link Here
      
     | 
  
        
          | 172 | 
                CheckMandatoryFields( \%borrower_changes, $action );  | 
          192 | 
                CheckMandatoryFields( \%borrower_changes, $action );  | 
        
        
          | 173 | 
              my $invalidformfields = CheckForInvalidFields(\%borrower);  | 
          193 | 
              my $invalidformfields = CheckForInvalidFields(\%borrower);  | 
        
        
          | 174 | 
           | 
          194 | 
           | 
        
          
            
              | 175 | 
                  if (@empty_mandatory_fields || @$invalidformfields) { | 
              195 | 
                  if (@empty_mandatory_fields || @$invalidformfields || $conflicting_attribute) { | 
            
        
          | 176 | 
                  $template->param(  | 
          196 | 
                  $template->param(  | 
        
        
          | 177 | 
                      empty_mandatory_fields => \@empty_mandatory_fields,  | 
          197 | 
                      empty_mandatory_fields => \@empty_mandatory_fields,  | 
        
        
          | 178 | 
                      invalid_form_fields    => $invalidformfields,  | 
          198 | 
                      invalid_form_fields    => $invalidformfields,  | 
        
        
          | 179 | 
                      borrower               => \%borrower  | 
          199 | 
                      borrower               => \%borrower  | 
        
        
          | 180 | 
                  );  | 
          200 | 
                  );  | 
        
            
               | 
               | 
              201 | 
                      $template->param( patron_attribute_classes => GeneratePatronAttributesForm( undef, $attributes ) );  | 
            
        
          | 181 | 
           | 
          202 | 
           | 
        
        
          | 182 | 
                  $template->param( action => 'edit' );  | 
          203 | 
                  $template->param( action => 'edit' );  | 
        
        
          | 183 | 
              }  | 
          204 | 
              }  | 
        
  
    | 
      
            Lines 215-228
          elsif ( $action eq 'update' ) {
      
      
        Link Here
      
     | 
  
        
          | 215 | 
          elsif ( $action eq 'edit' ) {    #Display logged in borrower's data | 
          236 | 
          elsif ( $action eq 'edit' ) {    #Display logged in borrower's data | 
        
        
          | 216 | 
              my $borrower = GetMember( borrowernumber => $borrowernumber );  | 
          237 | 
              my $borrower = GetMember( borrowernumber => $borrowernumber );  | 
        
        
          | 217 | 
           | 
          238 | 
           | 
        
            
              | 218 | 
                  if (C4::Context->preference('ExtendedPatronAttributes')) { | 
               | 
               | 
            
            
              | 219 | 
                      my $attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber, 'opac');  | 
            
            
              | 220 | 
                      if (scalar(@$attributes) > 0) { | 
            
            
              | 221 | 
                          $borrower->{ExtendedPatronAttributes} = 1; | 
            
            
              | 222 | 
                          $borrower->{patron_attributes} = $attributes; | 
            
            
              | 223 | 
                      }  | 
            
            
              | 224 | 
                  }  | 
            
            
              | 225 | 
               | 
            
        
          | 226 | 
              $template->param(  | 
          239 | 
              $template->param(  | 
        
        
          | 227 | 
                  borrower => $borrower, );  | 
          240 | 
                  borrower => $borrower, );  | 
        
        
          | 228 | 
           | 
          241 | 
           | 
        
  
    | 
      
            Lines 235-240
          elsif ( $action eq 'edit' ) {    #Display logged in borrower's data
      
      
        Link Here
      
     | 
  
        
          | 235 | 
                  }  | 
          248 | 
                  }  | 
        
        
          | 236 | 
              }  | 
          249 | 
              }  | 
        
        
          | 237 | 
           | 
          250 | 
           | 
        
            
               | 
               | 
              251 | 
                  $template->param( patron_attribute_classes => GeneratePatronAttributesForm( $borrower ) );  | 
            
            
              | 252 | 
              } else { | 
            
            
              | 253 | 
                  $template->param( patron_attribute_classes => GeneratePatronAttributesForm() );  | 
            
        
          | 238 | 
          }  | 
          254 | 
          }  | 
        
        
          | 239 | 
           | 
          255 | 
           | 
        
        
          | 240 | 
          my $captcha = random_string("CCCCC"); | 
          256 | 
          my $captcha = random_string("CCCCC"); | 
        
  
    | 
      
            Lines 361-363
          sub DelEmptyFields {
      
      
        Link Here
      
     | 
  
        
          | 361 | 
           | 
          377 | 
           | 
        
        
          | 362 | 
              return %borrower;  | 
          378 | 
              return %borrower;  | 
        
        
          | 363 | 
          }  | 
          379 | 
          }  | 
        
          
            
              | 364 | 
              -   | 
              380 | 
               | 
            
            
               | 
               | 
              381 | 
              sub GeneratePatronAttributesForm { | 
            
            
              | 382 | 
                  my ( $borrower, $entered_attributes ) = @_;  | 
            
            
              | 383 | 
               | 
            
            
              | 384 | 
                  use Data::Dumper; warn Dumper( $entered_attributes );  | 
            
            
              | 385 | 
               | 
            
            
              | 386 | 
                  # Get all attribute types and the values for this patron (if applicable)  | 
            
            
              | 387 | 
                  my @types = C4::Members::AttributeTypes::GetAttributeTypes();  | 
            
            
              | 388 | 
               | 
            
            
              | 389 | 
                  if (scalar(@types) == 0) { | 
            
            
              | 390 | 
                      return [];  | 
            
            
              | 391 | 
                  }  | 
            
            
              | 392 | 
               | 
            
            
              | 393 | 
                  my %attr_values = ();  | 
            
            
              | 394 | 
               | 
            
            
              | 395 | 
                  if ( $borrower ) { | 
            
            
              | 396 | 
                      my $attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);  | 
            
            
              | 397 | 
               | 
            
            
              | 398 | 
                      # Remap the patron's attributes into a hash of arrayrefs per attribute (depends on  | 
            
            
              | 399 | 
                      # autovivification)  | 
            
            
              | 400 | 
                      foreach my $attr (@$attributes) { | 
            
            
              | 401 | 
                          push @{ $attr_values{ $attr->{code} } }, $attr; | 
            
            
              | 402 | 
                      }  | 
            
            
              | 403 | 
                  }  | 
            
            
              | 404 | 
               | 
            
            
              | 405 | 
                  if ( $entered_attributes ) { | 
            
            
              | 406 | 
                      foreach my $attr (@$entered_attributes) { | 
            
            
              | 407 | 
                          push @{ $attr_values{ $attr->{code} } }, $attr; | 
            
            
              | 408 | 
                      }  | 
            
            
              | 409 | 
                  }  | 
            
            
              | 410 | 
               | 
            
            
              | 411 | 
                  # Find all existing classes  | 
            
            
              | 412 | 
                  my @classes = uniq( map { $_->{class} } @types ); | 
            
            
              | 413 | 
                  @classes = sort @classes;  | 
            
            
              | 414 | 
                  my %items_by_class;  | 
            
            
              | 415 | 
               | 
            
            
              | 416 | 
                  foreach my $attr_type_desc (@types) { | 
            
            
              | 417 | 
                      my $attr_type = C4::Members::AttributeTypes->fetch( $attr_type_desc->{code} ); | 
            
            
              | 418 | 
                      # Make sure this attribute should be displayed in the OPAC  | 
            
            
              | 419 | 
                      next unless ( $attr_type->opac_display() );  | 
            
            
              | 420 | 
                      # Then, make sure it either has values or is editable  | 
            
            
              | 421 | 
                      next unless ( $attr_values{ $attr_type->code() } || $attr_type->opac_editable() ); | 
            
            
              | 422 | 
               | 
            
            
              | 423 | 
                      push @{ $items_by_class{ $attr_type->class() } }, { | 
            
            
              | 424 | 
                          type => $attr_type,  | 
            
            
              | 425 | 
                          # If editable, make sure there's at least one empty entry, to make the template's job easier  | 
            
            
              | 426 | 
                          values => $attr_values{ $attr_type->code() } || [{}] | 
            
            
              | 427 | 
                      };  | 
            
            
              | 428 | 
                  }  | 
            
            
              | 429 | 
               | 
            
            
              | 430 | 
                  use Data::Dumper; warn Dumper( \%items_by_class );  | 
            
            
              | 431 | 
               | 
            
            
              | 432 | 
                  # Finally, build a list of containing classes  | 
            
            
              | 433 | 
                  my @class_loop;  | 
            
            
              | 434 | 
                  foreach my $class (@classes) { | 
            
            
              | 435 | 
                      next unless ( $items_by_class{$class} ); | 
            
            
              | 436 | 
               | 
            
            
              | 437 | 
                      my $lib = GetAuthorisedValueByCode( 'PA_CLASS', $class, 1 ) || $class;  | 
            
            
              | 438 | 
                      push @class_loop, { | 
            
            
              | 439 | 
                          class => $class,  | 
            
            
              | 440 | 
                          items => $items_by_class{$class}, | 
            
            
              | 441 | 
                          lib   => $lib,  | 
            
            
              | 442 | 
                      };  | 
            
            
              | 443 | 
                  }  | 
            
            
              | 444 | 
               | 
            
            
              | 445 | 
                  return \@class_loop;  | 
            
            
              | 446 | 
              }  | 
            
            
              | 447 | 
               | 
            
            
              | 448 | 
              sub ParsePatronAttributes { | 
            
            
              | 449 | 
                  my ( $cgi ) = @_;  | 
            
            
              | 450 | 
               | 
            
            
              | 451 | 
                  my @codes = $cgi->param('patron_attribute_code'); | 
            
            
              | 452 | 
                  my @values = $cgi->param('patron_attribute_value'); | 
            
            
              | 453 | 
                  my @passwords = $cgi->param('patron_attribute_password'); | 
            
            
              | 454 | 
               | 
            
            
              | 455 | 
                  my $ea = each_array( @codes, @values, @passwords );  | 
            
            
              | 456 | 
                  my @attributes;  | 
            
            
              | 457 | 
                  my %dups = ();  | 
            
            
              | 458 | 
               | 
            
            
              | 459 | 
                  while ( my ( $code, $value, $password ) = $ea->() ) { | 
            
            
              | 460 | 
                      next unless defined($value) and $value ne '';  | 
            
            
              | 461 | 
                      next if exists $dups{$code}->{$value}; | 
            
            
              | 462 | 
                      $dups{$code}->{$value} = 1; | 
            
            
              | 463 | 
               | 
            
            
              | 464 | 
                      push @attributes, { code => $code, value => $value, password => $password }; | 
            
            
              | 465 | 
                  }  | 
            
            
              | 466 | 
               | 
            
            
              | 467 | 
                  return \@attributes;  | 
            
            
              | 468 | 
              }  |