Koha/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt
Jonathan Druart 1b32e66380 Bug 27933: Fix patron search result ordering
On bug 27715 we restrict the order by dt params for security reasons.
However in some cases the param passed is "columnname" instead of
"table.columnname".
We should make sure the table is part of the sort fieldname.

Test plan:
Do a "normal" patron search (from the patrons home page) and another
patron search (guarantor for instance).
Sort by cardnumber, date of birth, expiration date, asc, desc and
confirm it works as expected.

Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
2021-03-18 15:03:26 +01:00

529 lines
23 KiB
Text

[% USE raw %]
[% USE Asset %]
[% USE Koha %]
[% USE TablesSettings %]
[% USE Branches %]
[% USE Categories %]
[% SET footerjs = 1 %]
[% PROCESS 'patronfields.inc' %]
[% INCLUDE 'doc-head-open.inc' %]
<title>Koha &rsaquo; Patrons [% IF ( searching ) %]&rsaquo; Search results[% END %]</title>
[% INCLUDE 'doc-head-close.inc' %]
</head>
<body id="pat_member" class="pat">
[% INCLUDE 'header.inc' %]
[% INCLUDE 'patron-search.inc' %]
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; [% IF ( searching ) %]<a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> &rsaquo; Search results[% ELSE %]Patrons[% END %]</div>
<div class="main container-fluid">
<div class="row">
<div class="col-sm-10 col-sm-push-2">
<main>
[% IF CAN_user_tools_manage_patron_lists %]
<div id="patron_list_dialog" class="dialog alert">
Added <span class="patrons-length"></span> patrons to <a></a>.
</div>
[% END %]
[% INCLUDE 'patron-toolbar.inc' %]
[% INCLUDE 'noadd-warnings.inc' %]
<div class="browse">
Browse by last name:
[% FOREACH letter IN alphabet.split(' ') %]
<a href="#" class="filterByLetter">[% letter | html %]</a>
[% END %]
</div>
[% IF CAN_user_borrowers_edit_borrowers && pending_borrower_modifications %]
<div class="pending-info" id="patron_updates_pending">
<a href="/cgi-bin/koha/members/members-update.pl">Patrons requesting modifications</a>:
<span class="number_box"><a href="/cgi-bin/koha/members/members-update.pl">[% pending_borrower_modifications | html %]</a></span>
</div>
[% END %]
<div id="searchresults">
<h3>Patrons found for: <span id="searchpattern">[% IF searchmember %] for '[% searchmember | html %]'[% END %]</span></h3>
[% IF CAN_user_tools_manage_patron_lists || CAN_user_borrowers_edit_borrowers %]
<div class="searchheader fh-fixedHeader" id="searchheader">
<div>
<a href="#" id="select_all"><i class="fa fa-check"></i> Select all</a>
|
<a href="#" id="clear_all"><i class="fa fa-remove"></i> Clear all</a>
[% IF CAN_user_tools_manage_patron_lists %]
|
<span>
<label for="add_to_patron_list">Add selected patrons to:</label>
<select id="add_to_patron_list" name="add_to_patron_list">
<option value=""></option>
[% IF patron_lists %]
<optgroup label="Patron lists:">
[% FOREACH pl IN patron_lists %]
<option value="[% pl.patron_list_id | html %]">[% pl.name | html %]</option>
[% END %]
</optgroup>
[% END %]
<option value="new">[ New list ]</option>
</select>
<input type="text" id="new_patron_list" name="new_patron_list" id="new_patron_list" />
<input id="add_to_patron_list_submit" type="submit" class="submit" value="Save">
</span>
[% END %]
[% IF CAN_user_tools_manage_patron_lists && CAN_user_borrowers_edit_borrowers %]
|
[% END %]
[% IF CAN_user_borrowers_edit_borrowers %]
<button id="merge-patrons" type="submit">Merge selected patrons</button>
[% END %]
</div>
</div>
[% END %]
<table id="memberresultst">
<thead>
<tr>
[% IF CAN_user_borrowers_edit_borrowers || CAN_user_tools_manage_patron_lists %]
<th>&nbsp;</th>
[% END %]
<th>Card</th>
<th>Name</th>
<th>Date of birth</th>
<th>Category</th>
<th>Library</th>
<th>Expires on</th>
<th>OD/Checkouts</th>
<th>Fines</th>
<th>Circ note</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</main>
</div> <!-- /.col-sm-10.col-sm-push-2 -->
<div class="col-sm-2 col-sm-pull-10">
<aside>
<form method="get" id="searchform">
<input type="hidden" id="firstletter_filter" value="" />
<fieldset class="brief">
<h3>Search patrons</h3>
<ol>
<li>
<label for="searchmember_filter">Search for:</label>
<input type="text" id="searchmember_filter" value="[% searchmember | html %]"/>
</li>
<li>
<label for="searchfieldstype_filter">Search field:</label>
<select name="searchfieldstype" id="searchfieldstype_filter">
[% pref_fields = Koha.Preference('DefaultPatronSearchFields').split(',') %]
[% default_fields = [ 'standard', 'surname', 'cardnumber', 'email', 'borrowernumber', 'userid', 'phone', 'address', 'dateofbirth', 'sort1', 'sort2' ] %]
[% search_options = default_fields.merge(pref_fields).unique %]
[% FOREACH s_o IN search_options %]
[% display_name = PROCESS patron_fields name=s_o %]
[% NEXT IF !display_name %]
[% IF searchfieldstype == s_o %]
<option selected="selected" value=[% s_o | html %]>[% display_name | $raw %]</option>
[% ELSE %]
<option value=[% s_o | html %]>[% display_name | $raw %]</option>
[% END %]
[% END %]
</select>
</li>
<li>
<label for="searchtype_filter">Search type:</label>
<select name="searchtype" id="searchtype_filter">
[% IF searchtype == "start_with" %]
<option value='start_with' selected="selected">Starts with</option>
<option value="contain">Contains</option>
[% ELSE %]
<option value='start_with'>Starts with</option>
<option value="contain" selected="selected">Contains</option>
[% END %]
</select>
</li>
<li>
<label for="categorycode_filter">Patron category:</label>
[% SET categories = Categories.all() %]
<select id="categorycode_filter">
<option value="">Any</option>
[% FOREACH cat IN categories %]
[% IF cat.categorycode == categorycode_filter %]
<option selected="selected" value="[% cat.categorycode | html %]">[% cat.description | html %]</option>
[% ELSE %]
<option value="[% cat.categorycode | html %]">[% cat.description | html %]</option>
[% END %]
[% END %]
</select>
</li>
<li>
<label for="branchcode_filter">Library:</label>
[% SET branches = Branches.all( selected => branchcode_filter, only_from_group => 1 ) %]
<select id="branchcode_filter">
[% IF branches.size != 1 %]
<option value="">Any</option>
[% END %]
[% PROCESS options_for_libraries libraries => branches %]
</select>
</li>
</ol>
<fieldset class="action">
<input type="submit" value="Search" />
<input type="button" value="Clear" id="clear_search" />
</fieldset>
</fieldset>
</form>
</aside>
</div> <!-- /.col-sm-2.col-sm-pull-10 -->
</div> <!-- /.row -->
[% MACRO jsinclude BLOCK %]
[% INCLUDE 'datatables.inc' %]
[% INCLUDE 'columns_settings.inc' %]
[% INCLUDE 'str/members-menu.inc' %]
[% Asset.js("lib/hc-sticky.js") | $raw %]
[% Asset.js("js/members-menu.js") | $raw %]
<script>
$(document).ready(function() {
$('#merge-patrons').prop('disabled', true);
$('#memberresultst').on('change', 'input.selection', function() {
if ( $('.selection:checked').length > 1 ) {
$('#merge-patrons').prop('disabled', false);
} else {
$('#merge-patrons').prop('disabled', true);
}
});
$('#merge-patrons').on('click', function() {
var merge_patrons_url = 'merge-patrons.pl?' + $('.selection:checked')
.map(function() {
return "id=" + $(this).val()
}).get().join('&');
window.location.href = merge_patrons_url;
});
$('#add_to_patron_list_submit').prop('disabled', true);
$('#new_patron_list').hide();
$('#add_to_patron_list').change(function() {
var value = $('#add_to_patron_list').val();
if ( value == 'new' ) {
$('#new_patron_list').val('')
$('#new_patron_list').show();
$('#new_patron_list').focus();
} else if ( value ) {
$('#new_patron_list').hide();
$('#add_to_patron_list_submit').prop('disabled', false);
} else {
$('#new_patron_list').hide();
$('#add_to_patron_list_submit').prop('disabled', true);
}
});
$('#new_patron_list').on('input', function() {
if ( $('#new_patron_list').val() ) {
$('#add_to_patron_list_submit').prop('disabled', false);
} else {
$('#add_to_patron_list_submit').prop('disabled', true);
}
});
$("#add_to_patron_list_submit").on('click', function(e){
if ( $('#add_to_patron_list').val() == 'new' ) {
if ( $('#new_patron_list').val() ) {
$("#add_to_patron_list option").each(function() {
if ( $(this).text() == $('#new_patron_list').val() ) {
alert( _("You already have a list with that name!") );
return false;
}
});
} else {
alert( _("You must give your new patron list a name!") );
return false;
}
}
if ( $("#memberresultst input:checkbox:checked").length == 0 ) {
alert( _("You have not selected any patrons to add to a list!") );
return false;
}
var borrowernumbers = [];
$("#memberresultst").find("input:checkbox:checked").each(function(){
borrowernumbers.push($(this).val());
});
var data = {
add_to_patron_list: $("#add_to_patron_list").val(),
new_patron_list: $("#new_patron_list").val(),
borrowernumbers: borrowernumbers
};
$.ajax({
data: data,
type: 'POST',
url: '/cgi-bin/koha/svc/members/add_to_list',
success: function(data) {
$("#patron_list_dialog").show();
$("#patron_list_dialog > span.patrons-length").html(data.patrons_added_to_list);
$("#patron_list_dialog > a").attr("href", "/cgi-bin/koha/patron_lists/list.pl?patron_list_id=" + data.patron_list.patron_list_id);
$("#patron_list_dialog > a").html(data.patron_list.name);
if ( $('#add_to_patron_list').val() == 'new' ) {
var new_patron_list_added = $("<option>", {
value: data.patron_list.patron_list_id,
text: data.patron_list.name
});
$("#add_to_patron_list optgroup").append(new_patron_list_added);
$("#add_to_patron_list").val(data.patron_list.patron_list_id);
$("#new_patron_list").val('');
$('#add_to_patron_list').change();
}
},
error: function() {
alert("an error occurred");
}
});
return true;
});
$(".filterByLetter").on("click",function(e){
e.preventDefault();
filterByFirstLetterSurname($(this).text());
});
$("#select_all").on("click",function(e){
e.preventDefault();
$(".selection").prop("checked", true).change();
});
$("#clear_all").on("click",function(e){
e.preventDefault();
$(".selection").prop("checked", false).change();
});
$("#clear_search").on("click",function(e){
e.preventDefault();
clearFilters(true);
});
$("#searchform").on("submit", filter);
});
var dtMemberResults;
var search = 1;
$(document).ready(function() {
[% IF searchmember %]
$("#searchmember_filter").val("[% searchmember | html %]");
[% END %]
[% IF searchfieldstype %]
$("searchfieldstype_filter").val("[% searchfieldstype | html %]");
[% END %]
[% IF searchtype %]
$("#searchtype_filter").val("[% searchtype | html %]");
[% END %]
[% IF categorycode %]
$("#categorycode_filter").val("[% categorycode_filter | html %]");
[% END %]
[% IF branchcode %]
$("#branchcode_filter").val("[% branchcode_filter | html %]");
[% END %]
[% IF view != "show_results" %]
search = 0;
[% ELSE %]
$("#searchresults").show();
[% END %]
// Build the aLengthMenu
var aLengthMenu = [
[% PatronsPerPage | html %], 10, 20, 50, 100, -1
];
jQuery.unique(aLengthMenu);
aLengthMenu.sort(function( a, b ){
// Put "All" at the end
if ( a == -1 ) {
return 1;
} else if ( b == -1 ) {
return -1;
}
return parseInt(a) < parseInt(b) ? -1 : 1;}
);
var aLengthMenuLabel = [];
$(aLengthMenu).each(function(){
if ( this == -1 ) {
// Label for -1 is "All"
aLengthMenuLabel.push(_("All"));
} else {
aLengthMenuLabel.push(this);
}
});
// Apply DataTables on the results table
var columns_settings = [% TablesSettings.GetColumns( 'members', 'member', 'memberresultst', 'json' ) | $raw %];
[% UNLESS CAN_user_borrowers_edit_borrowers OR CAN_user_tools_manage_patron_lists %]
[%# Remove the first column if we do not display the checkbox %]
columns_settings.splice(0, 1);
[% END %]
dtMemberResults = KohaTable("memberresultst", {
'bServerSide': true,
'sAjaxSource': "/cgi-bin/koha/svc/members/search",
'fnServerData': function(sSource, aoData, fnCallback) {
if ( ! search ) {
return;
}
aoData.push({
'name': 'searchmember',
'value': $("#searchmember_filter").val()
},{
'name': 'firstletter',
'value': $("#firstletter_filter").val()
},{
'name': 'searchfieldstype',
'value': $("#searchfieldstype_filter").val()
},{
'name': 'searchtype',
'value': $("#searchtype_filter").val()
},{
'name': 'categorycode',
'value': $("#categorycode_filter").val()
},{
'name': 'branchcode',
'value': $("#branchcode_filter").val()
},{
'name': 'name_sorton',
'value': 'borrowers.surname borrowers.firstname'
},{
'name': 'cardnumber_sorton',
'value': 'borrowers.cardnumber',
},{
'name': 'dateofbirth_sorton',
'value': 'borrowers.dateofbirth',
},{
'name': 'dateexpiry_sorton',
'value': 'borrowers.dateexpiry',
},{
'name': 'category_sorton',
'value': 'categories.description',
},{
'name': 'branch_sorton',
'value': 'branches.branchname'
},{
'name': 'template_path',
'value': 'members/tables/members_results.tt',
});
$.ajax({
'dataType': 'json',
'type': 'POST',
'url': sSource,
'data': aoData,
'success': function(json){
// redirect if there is only 1 result.
if ( json.aaData.length == 1 ) {
var borrowernumber = json.aaData[0].borrowernumber;
document.location.href="/cgi-bin/koha/members/moremember.pl?borrowernumber="+borrowernumber;
return false;
}
fnCallback(json);
}
});
},
'aoColumns':[
[% IF CAN_user_borrowers_edit_borrowers || CAN_user_tools_manage_patron_lists %]
{ 'mDataProp': 'dt_borrowernumber', 'bSortable': false },
[% END %]
{ 'mDataProp': 'dt_cardnumber' },
{ 'mDataProp': 'dt_name' },
{ 'mDataProp': 'dt_dateofbirth' },
{ 'mDataProp': 'dt_category' },
{ 'mDataProp': 'dt_branch' },
{ 'mDataProp': 'dt_dateexpiry' },
{ 'mDataProp': 'dt_od_checkouts', 'bSortable': false },
{ 'mDataProp': 'dt_fines', 'bSortable': false },
{ 'mDataProp': 'dt_borrowernotes' },
{ 'mDataProp': 'dt_action', 'bSortable': false, 'sClass': 'actions' }
],
'bFilter': false,
'bAutoWidth': false,
[% IF CAN_user_borrowers_edit_borrowers || CAN_user_tools_manage_patron_lists %]
'aaSorting': [[2, 'asc']],
[% ELSE %]
'aaSorting': [[1, 'asc']],
[% END %]
"aLengthMenu": [aLengthMenu, aLengthMenuLabel],
'sPaginationType': 'full_numbers',
"iDisplayLength": [% PatronsPerPage | html %],
"bProcessing": true,
"initComplete": function(settings, json) {
Sticky = $("#searchheader");
Sticky.hcSticky({
stickTo: "#searchresults",
stickyClass: "floating"
});
}
}, columns_settings);
update_searched();
});
// Update the string "Results found ..."
function update_searched(){
var searched = $("#searchfieldstype_filter").find("option:selected").text();
if ( $("#searchmember_filter").val() ) {
if ( $("#searchtype_filter").val() == 'start_with' ) {
searched += _(" starting with ");
} else {
searched += _(" containing ");
}
searched += "'" + $("#searchmember_filter").val() + "'";
}
if ( $("#firstletter_filter").val() ) {
searched += _(" begins with ") + "'" + $("#firstletter_filter").val() +"'";
}
if ( $("#categorycode_filter").val() ) {
searched += _(" with category ") + "'" + $("#categorycode_filter").find("option:selected").text() + "'";
}
if ( $("#branchcode_filter").val() ) {
searched += _(" in library ") + $("#branchcode_filter").find("option:selected").text();
}
$("#searchpattern").text(searched);
}
// Redraw the table
function filter() {
$("#firstletter_filter").val('');
update_searched();
search = 1;
$("#searchresults").show();
dtMemberResults.fnDraw();
return false;
}
// User has clicked on the Clear button
function clearFilters(redraw) {
$("#searchform select").val('');
$("#firstletter_filter").val('');
$("#searchmember_filter").val('');
if(redraw) {
search = 1;
$("#searchresults").show();
dtMemberResults.fnDraw();
}
}
// User has clicked on a letter
function filterByFirstLetterSurname(letter) {
clearFilters(false);
$("#firstletter_filter").val(letter);
update_searched();
search = 1;
$("#searchresults").show();
dtMemberResults.fnDraw();
}
</script>
[% END %]
[% INCLUDE 'intranet-bottom.inc' %]