diff options
author | plegall <plg@piwigo.org> | 2013-10-28 16:25:46 +0000 |
---|---|---|
committer | plegall <plg@piwigo.org> | 2013-10-28 16:25:46 +0000 |
commit | 2fdcfdddfecb66c7d654004cd1d44ceb6a1233c7 (patch) | |
tree | 19ec3a89f6857f8e82f05ddad7a1ed07d4aebabf | |
parent | 7367858be89bef8163d77ac9b1aed18c8c17555f (diff) |
feature 1668, in progress: redesign user manager (jQuery datatables, AJAX calls)
git-svn-id: http://piwigo.org/svn/trunk@25194 68402e56-0260-453c-a942-63ccdbb3a9ee
-rw-r--r-- | admin/themes/default/js/common.js | 50 | ||||
-rw-r--r-- | admin/themes/default/template/user_list.tpl | 583 | ||||
-rw-r--r-- | admin/user_list.php | 700 | ||||
-rw-r--r-- | admin/user_list_backend.php | 158 |
4 files changed, 591 insertions, 900 deletions
diff --git a/admin/themes/default/js/common.js b/admin/themes/default/js/common.js new file mode 100644 index 000000000..d0e460bd8 --- /dev/null +++ b/admin/themes/default/js/common.js @@ -0,0 +1,50 @@ +function array_delete(arr, item) { + var i = arr.indexOf(item); + if (i != -1) arr.splice(i, 1); +} + +function sprintf() { + var i = 0, a, f = arguments[i++], o = [], m, p, c, x, s = ''; + while (f) { + if (m = /^[^\x25]+/.exec(f)) { + o.push(m[0]); + } + else if (m = /^\x25{2}/.exec(f)) { + o.push('%'); + } + else if (m = /^\x25(?:(\d+)\$)?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(f)) { + if (((a = arguments[m[1] || i++]) == null) || (a == undefined)) { + throw('Too few arguments.'); + } + if (/[^s]/.test(m[7]) && (typeof(a) != 'number')) { + throw('Expecting number but found ' + typeof(a)); + } + + switch (m[7]) { + case 'b': a = a.toString(2); break; + case 'c': a = String.fromCharCode(a); break; + case 'd': a = parseInt(a); break; + case 'e': a = m[6] ? a.toExponential(m[6]) : a.toExponential(); break; + case 'f': a = m[6] ? parseFloat(a).toFixed(m[6]) : parseFloat(a); break; + case 'o': a = a.toString(8); break; + case 's': a = ((a = String(a)) && m[6] ? a.substring(0, m[6]) : a); break; + case 'u': a = Math.abs(a); break; + case 'x': a = a.toString(16); break; + case 'X': a = a.toString(16).toUpperCase(); break; + } + + a = (/[def]/.test(m[7]) && m[2] && a >= 0 ? '+'+ a : a); + c = m[3] ? m[3] == '0' ? '0' : m[3].charAt(1) : ' '; + x = m[5] - String(a).length - s.length; + p = m[5] ? str_repeat(c, x) : ''; + o.push(s + (m[4] ? a + p : p + a)); + } + else { + throw('Huh ?!'); + } + + f = f.substring(m[0].length); + } + + return o.join(''); +}
\ No newline at end of file diff --git a/admin/themes/default/template/user_list.tpl b/admin/themes/default/template/user_list.tpl index 5bb3f18ed..911bfc978 100644 --- a/admin/themes/default/template/user_list.tpl +++ b/admin/themes/default/template/user_list.tpl @@ -1,8 +1,246 @@ +{combine_script id='common' load='footer' path='admin/themes/default/js/common.js'} + +{combine_script id='jquery.dataTables' load='footer' path='themes/default/js/plugins/jquery.dataTables.js'} +{combine_css path="themes/default/js/plugins/datatables/css/jquery.dataTables.css"} + +{footer_script} +var selectedMessage_pattern = "{'%d of %d photos selected'|@translate}"; +var selectedMessage_none = "{'No photo selected, %d photos in current set'|@translate}"; +var selectedMessage_all = "{'All %d photos are selected'|@translate}"; +var applyOnDetails_pattern = "{'on the %d selected users'|@translate}"; +var missingConfirm = "{'You need to confirm deletion'|translate}"; + +var allUsers = [{$all_users}]; +var selection = [{$selection}]; +{/footer_script} + +{footer_script}{literal} +jQuery(document).ready(function() { + /* first column must be prefixed with the open/close icon */ + var aoColumns = [ + { + 'bVisible':false + }, + { + "mRender": function(data, type, full) { + return '<label><input type="checkbox" data-user_id="'+full[0]+'"> '+data+'</label>'; + } + } + ]; + + for (i=2; i<jQuery("#userList thead tr th").length; i++) { + aoColumns.push(null); + } + + var oTable = jQuery('#userList').dataTable({ + "iDisplayLength": 10, + "bDeferRender": true, + "bProcessing": true, + "bServerSide": true, + "sAjaxSource": "admin/user_list_backend.php", + "fnDrawCallback": function( oSettings ) { + jQuery("#userList input[type=checkbox]").each(function() { + var user_id = jQuery(this).data("user_id"); + jQuery(this).prop('checked', (selection.indexOf(user_id) != -1)); + }); + }, + "aoColumns": aoColumns + }); + + /** + * Selection management + */ + function checkSelection() { + if (selection.length > 0) { + jQuery("#forbidAction").hide(); + jQuery("#permitAction").show(); + + jQuery("#applyOnDetails").text( + sprintf( + applyOnDetails_pattern, + selection.length + ) + ); + + if (selection.length == allUsers.length) { + jQuery("#selectedMessage").text( + sprintf( + selectedMessage_all, + allUsers.length + ) + ); + } + else { + jQuery("#selectedMessage").text( + sprintf( + selectedMessage_pattern, + selection.length, + allUsers.length + ) + ); + } + } + else { + jQuery("#forbidAction").show(); + jQuery("#permitAction").hide(); + + jQuery("#selectedMessage").text( + sprintf( + selectedMessage_none, + allUsers.length + ) + ); + } + + jQuery("#applyActionBlock .infos").hide(); + } + + jQuery(document).on('change', '#userList input[type=checkbox]', function() { + var user_id = jQuery(this).data("user_id"); + + array_delete(selection, user_id); + + if (jQuery(this).is(":checked")) { + selection.push(user_id); + } + + checkSelection(); + }); + + jQuery("#selectAll").click(function () { + selection = allUsers; + jQuery("#userList input[type=checkbox]").prop('checked', true); + checkSelection(); + return false; + }); + + jQuery("#selectNone").click(function () { + selection = []; + jQuery("#userList input[type=checkbox]").prop('checked', false); + checkSelection(); + return false; + }); + + jQuery("#selectInvert").click(function () { + var newSelection = []; + for(var i in allUsers) + { + if (selection.indexOf(allUsers[i]) == -1) { + newSelection.push(allUsers[i]); + } + } + selection = newSelection; + + jQuery("#userList input[type=checkbox]").each(function() { + var user_id = jQuery(this).data("user_id"); + jQuery(this).prop('checked', (selection.indexOf(user_id) != -1)); + }); + + checkSelection(); + return false; + }); + + /** + * Action management + */ + jQuery("[id^=action_]").hide(); + + jQuery("select[name=selectAction]").change(function () { + jQuery("#applyActionBlock .infos").hide(); + + jQuery("[id^=action_]").hide(); + + jQuery("#action_"+$(this).prop("value")).show(); + + if (jQuery(this).val() != -1) { + jQuery("#applyActionBlock").show(); + } + else { + jQuery("#applyActionBlock").hide(); + } + }); + + jQuery("#permitAction input, #permitAction select").click(function() { + jQuery("#applyActionBlock .infos").hide(); + }); + + jQuery("#applyAction").click(function() { + var action = jQuery("select[name=selectAction]").prop("value"); + var method = null; + var data = { + user_id: selection + }; + + switch (action) { + case 'delete': + if (!jQuery("input[name=confirm_deletion]").is(':checked')) { + alert(missingConfirm); + return false; + } + method = 'pwg.users.delete'; + break; + case 'group_associate': + method = 'pwg.groups.addUser'; + data.group_id = jQuery("select[name=associate]").prop("value"); + break; + case 'group_dissociate': + method = 'pwg.groups.deleteUser'; + data.group_id = jQuery("select[name=dissociate]").prop("value"); + break; + } + + jQuery.ajax({ + url: "ws.php?format=json&method="+method, + type:"POST", + data: data, + beforeSend: function() { + jQuery("#applyActionLoading").show(); + }, + success:function(data) { + oTable.fnDraw(); + jQuery("#applyActionLoading").hide(); + jQuery("#applyActionBlock .infos").show(); + + if (action == 'delete') { + var allUsers_new = []; + for(var i in allUsers) + { + if (selection.indexOf(allUsers[i]) == -1) { + allUsers_new.push(allUsers[i]); + } + } + allUsers = allUsers_new; + console.log('allUsers_new.length = '+allUsers_new.length); + selection = []; + checkSelection(); + } + }, + error:function(XMLHttpRequest, textStatus, errorThrows) { + jQuery("#applyActionLoading").hide(); + } + }); + + return false; + }); + +}); +{/literal}{/footer_script} + +{literal} +<style> +.dataTables_wrapper, .dataTables_info {clear:none;} +table.dataTable {clear:right;padding-top:10px;} +.bulkAction {margin-top:10px;} +.actionButtons {margin-left:0;} +#applyActionBlock .infos {background-image:none; padding:2px 5px; margin:0;border-radius:5px;} +</style> +{/literal} + <div class="titrePage"> <h2>{'User list'|@translate}</h2> </div> -<form class="filter" method="post" name="add_user" action="{$F_ADD_ACTION}"> +<form style="display:none" class="filter" method="post" name="add_user" action="{$F_ADD_ACTION}"> <fieldset> <legend>{'Add a user'|@translate}</legend> <label>{'Username'|@translate} <input type="text" name="login" maxlength="50" size="20"></label> @@ -18,273 +256,140 @@ </fieldset> </form> -<form class="filter" method="get" name="filter" action="{$F_FILTER_ACTION}"> -<fieldset> - <legend>{'Filter'|@translate}</legend> - <input type="hidden" name="page" value="user_list"> - - <label>{'Username'|@translate} <input type="text" name="username" value="{$F_USERNAME}"></label> - - <label> - {'status'|@translate} - {html_options name=status options=$status_options selected=$status_selected} - </label> - - <label> - {'Group'|@translate} - {html_options name=group options=$group_options selected=$group_selected} - </label> - - <label> - {'Sort by'|@translate} - {html_options name=order_by options=$order_options selected=$order_selected} - </label> - - <label> - {'Sort order'|@translate} - {html_options name=direction options=$direction_options selected=$direction_selected} - </label> - - <label> - - <input class="submit" type="submit" value="{'Submit'|@translate}"> - </label> - -</fieldset> - -</form> - <form method="post" name="preferences" action=""> -{if !empty($navbar) }{include file='navigation_bar.tpl'|@get_extent:'navbar'}{/if} - -<table class="table2" width="97%"> +<table id="userList"> <thead> - <tr class="throw"> - <td> </td> - <td>{'Username'|@translate}</td> - <td>{'User status'|@translate}</td> - <td>{'Email address'|@translate}</td> - <td>{'Groups'|@translate}</td> - <td>{'Properties'|@translate}</td> - {if not empty($plugin_user_list_column_titles)} - {foreach from=$plugin_user_list_column_titles item=title} - <td>{$title}</td> - {/foreach} - {/if} - <td>{'Actions'|@translate}</td> + <tr> + <th>id</th> + <th>{'Username'|@translate}</th> + <th>{'Status'|@translate}</th> + <th>{'Email address'|@translate}</th> </tr> </thead> - - {foreach from=$users item=user name=users_loop} - <tr class="{if $smarty.foreach.users_loop.index is odd}row1{else}row2{/if}"> - <td><input type="checkbox" name="selection[]" value="{$user.ID}" {$user.CHECKED} id="selection-{$user.ID}"></td> - <td><label for="selection-{$user.ID}">{$user.USERNAME}</label></td> - <td>{$user.STATUS}</td> - <td>{$user.EMAIL}</td> - <td>{$user.GROUPS}</td> - <td>{$user.PROPERTIES}</td> - {foreach from=$user.plugin_columns item=data} - <td>{$data}</td> - {/foreach} - <td style="text-align:center;"> - <a href="{$user.U_PERM}"><img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/permissions.png" style="border:none" alt="{'Permissions'|@translate}" title="{'Permissions'|@translate}"></a> - <a href="{$user.U_PROFILE}"><img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/edit_s.png" style="border:none" alt="{'Profile'|@translate}" title="{'Profile'|@translate}"></a> - {foreach from=$user.plugin_actions item=data} - {$data} - {/foreach} - </td> - </tr> - {/foreach} </table> -{if !empty($navbar) }{include file='navigation_bar.tpl'|@get_extent:'navbar'}{/if} - -{* delete the selected users ? *} -<fieldset> - <legend>{'Deletions'|@translate}</legend> - <label><input type="checkbox" name="confirm_deletion" value="1"> {'confirm'|@translate}</label> - <input class="submit" type="submit" value="{'Delete selected users'|@translate}" name="delete"> -</fieldset> +<div style="clear:right"></div> -<fieldset> - <legend>{'Status'|@translate}</legend> +<p class="checkActions"> + {'Select:'|@translate} + <a href="#" id="selectAll">{'All'|@translate}</a>, + <a href="#" id="selectNone">{'None'|@translate}</a>, + <a href="#" id="selectInvert">{'Invert'|@translate}</a> - <table> - <tr> - <td>{'Status'|@translate}</td> - <td> - <label><input type="radio" name="status_action" value="leave" checked="checked"> {'leave'|@translate}</label> - <label><input type="radio" name="status_action" value="set" id="status_action_set"> {'set to'|@translate}</label> - <select onchange="document.getElementById('status_action_set').checked = true;" name="status" size="1"> - {html_options options=$pref_status_options selected=$pref_status_selected} - </select> - </td> - </tr> - </table> -</fieldset> - -{* form to set properties for many users at once *} -<fieldset> - <legend>{'Groups'|@translate}</legend> + <span id="selectedMessage"></span> +</p> -<table> +<fieldset id="action"> + <legend>{'Action'|@translate}</legend> + + <div id="forbidAction"{if count($selection) != 0} style="display:none"{/if}>{'No user selected, no action possible.'|@translate}</div> + <div id="permitAction"{if count($selection) == 0} style="display:none"{/if}> + + <select name="selectAction"> + <option value="-1">{'Choose an action'|@translate}</option> + <option disabled="disabled">------------------</option> + <option value="delete" class="icon-trash">{'Delete selected users'|@translate}</option> + <option value="status">{'Status'|@translate}</option> + <option value="group_associate">{'associate to group'|translate}</option> + <option value="group_dissociate">{'dissociate from group'|@translate}</option> + <option value="enabled_high">{'High definition enabled'|@translate}</option> + <option value="level">{'Privacy level'|@translate}</option> + <option value="nb_image_page">{'Number of photos per page'|@translate}</option> + <option value="theme">{'Interface theme'|@translate}</option> + <option value="language">{'Language'|@translate}</option> + <option value="recent_period">{'Recent period'|@translate}</option> + <option value="expand">{'Expand all albums'|@translate}</option> +{if $ACTIVATE_COMMENTS} + <option value="show_nb_comments">{'Show number of comments'|@translate}</option> +{/if} + <option value="show_nb_hits">{'Show number of hits'|@translate}</option> + </select> + + {* delete *} + <div id="action_delete" class="bulkAction"> + <p><label><input type="checkbox" name="confirm_deletion" value="1"> {'Are you sure?'|@translate}</label></p> + </div> + + {* status *} + <div id="action_status" class="bulkAction"> + <select name="status"> + {html_options options=$pref_status_options selected=$pref_status_selected} + </select> + </div> - <tr> - <td>{'associate to group'|@translate}</td> - <td> + {* group_associate *} + <div id="action_group_associate" class="bulkAction"> {html_options name=associate options=$association_options selected=$associate_selected} - </td> - </tr> + </div> - <tr> - <td>{'dissociate from group'|@translate}</td> - <td> + {* group_dissociate *} + <div id="action_group_dissociate" class="bulkAction"> {html_options name=dissociate options=$association_options selected=$dissociate_selected} - </td> - </tr> - -</table> - -</fieldset> - -{* Properties *} -<fieldset> - <legend>{'Properties'|@translate}</legend> - - <table> - - <tr> - <td>{'High definition enabled'|@translate}</td> - <td> - <label><input type="radio" name="enabled_high" value="leave" checked="checked"> {'leave'|@translate}</label> - / {'set to'|@translate} - <label><input type="radio" name="enabled_high" value="true">{'Yes'|@translate}</label> - <label><input type="radio" name="enabled_high" value="false">{'No'|@translate}</label> - </td> - </tr> - - <tr> - <td>{'Privacy level'|@translate}</td> - <td> - <label><input type="radio" name="level_action" value="leave" checked="checked">{'leave'|@translate}</label> - <label><input type="radio" name="level_action" value="set" id="level_action_set">{'set to'|@translate}</label> - <select onchange="document.getElementById('level_action_set').checked = true;" name="level" size="1"> - {html_options options=$level_options selected=$level_selected} - </select> - </td> - </tr> - </table> + </div> + + {* enabled_high *} + <div id="action_enabled_high" class="bulkAction"> + <label><input type="radio" name="enabled_high" value="true">{'Yes'|@translate}</label> + <label><input type="radio" name="enabled_high" value="false">{'No'|@translate}</label> + </div> + + {* level *} + <div id="action_level" class="bulkAction"> + <select name="level" size="1"> + {html_options options=$level_options selected=$level_selected} + </select> + </div> -</fieldset> + {* nb_image_page *} + <div id="action_nb_image_page" class="bulkAction"> + <input size="4" maxlength="3" type="text" name="nb_image_page" value="{$NB_IMAGE_PAGE}"> + </div> -{* preference *} -<fieldset> - <legend>{'Preferences'|@translate}</legend> - -<table> - <tr> - <td>{'Number of photos per page'|@translate}</td> - <td> - <label><input type="radio" name="nb_image_page_action" value="leave" checked="checked"> {'leave'|@translate}</label> - <label><input type="radio" name="nb_image_page_action" value="set" id="nb_image_page_action_set"> {'set to'|@translate}</label> - <input onmousedown="document.getElementById('nb_image_page_action_set').checked = true;" - size="4" maxlength="3" type="text" name="nb_image_page" value="{$NB_IMAGE_PAGE}"> - </td> - </tr> - - <tr> - <td>{'Interface theme'|@translate}</td> - <td> - <label><input type="radio" name="theme_action" value="leave" checked="checked"> {'leave'|@translate}</label> - <label><input type="radio" name="theme_action" value="set" id="theme_action_set"> {'set to'|@translate}</label> - <select onchange="document.getElementById('theme_action_set').checked = true;" name="theme" size="1"> + {* theme *} + <div id="action_theme" class="bulkAction"> + <select name="theme" size="1"> {html_options options=$theme_options selected=$theme_selected} </select> - </td> - </tr> - - <tr> - <td>{'Language'|@translate}</td> - <td> - <label><input type="radio" name="language_action" value="leave" checked="checked"> {'leave'|@translate}</label> - <label><input type="radio" name="language_action" value="set" id="language_action_set"> {'set to'|@translate}</label> - <select onchange="document.getElementById('language_action_set').checked = true;" name="language" size="1"> + </div> + + {* language *} + <div id="action_language" class="bulkAction"> + <select name="language" size="1"> {html_options options=$language_options selected=$language_selected} </select> - </td> - </tr> - - <tr> - <td>{'Recent period'|@translate}</td> - <td> - <label><input type="radio" name="recent_period_action" value="leave" checked="checked"> {'leave'|@translate}</label> - <label><input type="radio" name="recent_period_action" value="set" id="recent_period_action_set"> {'set to'|@translate}</label> - <input onmousedown="document.getElementById('recent_period_action_set').checked = true;" - type="text" size="3" maxlength="2" name="recent_period" value="{$RECENT_PERIOD}"> - </td> - </tr> - - <tr> - <td>{'Expand all albums'|@translate}</td> - <td> - <label><input type="radio" name="expand" value="leave" checked="checked"> {'leave'|@translate}</label> - / {'set to'|@translate} + </div> + + {* recent_period *} + <div id="action_recent_period" class="bulkAction"> + <input type="text" size="3" maxlength="2" name="recent_period" value="{$RECENT_PERIOD}"> + </div> + + {* expand *} + <div id="action_expand" class="bulkAction"> <label><input type="radio" name="expand" value="true">{'Yes'|@translate}</label> <label><input type="radio" name="expand" value="false">{'No'|@translate}</label> - </td> - </tr> + </div> -{if $ACTIVATE_COMMENTS} - <tr> - <td>{'Show number of comments'|@translate}</td> - <td> - <label><input type="radio" name="show_nb_comments" value="leave" checked="checked"> {'leave'|@translate}</label> - / {'set to'|@translate} + {* show_nb_comments *} + <div id="action_show_nb_comments" class="bulkAction"> <label><input type="radio" name="show_nb_comments" value="true">{'Yes'|@translate}</label> <label><input type="radio" name="show_nb_comments" value="false">{'No'|@translate}</label> - </td> - </tr> -{/if} + </div> - <tr> - <td>{'Show number of hits'|@translate}</td> - <td> - <label><input type="radio" name="show_nb_hits" value="leave" checked="checked"> {'leave'|@translate}</label> - / {'set to'|@translate} + {* show_nb_hits *} + <div id="action_show_nb_hits" class="bulkAction"> <label><input type="radio" name="show_nb_hits" value="true">{'Yes'|@translate}</label> <label><input type="radio" name="show_nb_hits" value="false">{'No'|@translate}</label> - </td> - </tr> + </div> -</table> + <p id="applyActionBlock" style="display:none" class="actionButtons"> + <input id="applyAction" class="submit" type="submit" value="{'Apply action'|@translate}" name="submit"> <span id="applyOnDetails"></span> + <span id="applyActionLoading" style="display:none"><img src="themes/default/images/ajax-loader-small.gif"></span> + <span class="infos" style="display:none">✔ Users modified</span> + </p> + </div> {* #permitAction *} </fieldset> -<p> - {'target'|@translate} - <label><input type="radio" name="target" value="all"> {'all'|@translate}</label> - <label><input type="radio" name="target" value="selection" checked="checked"> {'selection'|@translate}</label> -</p> - -<p> - <input class="submit" type="submit" value="{'Submit'|@translate}" name="pref_submit"> - <input class="submit" type="reset" value="{'Reset'|@translate}" name="pref_reset"> -</p> - -</form> - -<script type="text/javascript">// <![CDATA[{literal} -jQuery("form:last").submit( function() { - if ( jQuery("input[name=target][value=selection]:checked", this).length > 0 ) - if ( jQuery("input[name='selection[]']:checked", this).length == 0) - { - alert( {/literal}"{'Select at least one user'|@translate|escape:javascript}"{literal} ); - return false; - } - return true; -} -);{/literal} -// ]]> -</script> - +</form> diff --git a/admin/user_list.php b/admin/user_list.php index 57387f6b1..a9744a0d2 100644 --- a/admin/user_list.php +++ b/admin/user_list.php @@ -26,492 +26,10 @@ */ // +-----------------------------------------------------------------------+ -// | functions | -// +-----------------------------------------------------------------------+ - -/** - * returns a list of users depending on page filters (in $_GET) - * - * Each user comes with his related informations : id, username, mail - * address, list of groups. - * - * @return array - */ -function get_filtered_user_list() -{ - global $conf, $page; - - $users = array(); - - // filter - $filter = array(); - - if (isset($_GET['username']) and !empty($_GET['username'])) - { - $username = str_replace('*', '%', $_GET['username']); - $filter['username'] = pwg_db_real_escape_string($username); - } - - if (isset($_GET['group']) - and -1 != $_GET['group'] - and is_numeric($_GET['group'])) - { - $filter['group'] = $_GET['group']; - } - - if (isset($_GET['status']) - and in_array($_GET['status'], get_enums(USER_INFOS_TABLE, 'status'))) - { - $filter['status'] = $_GET['status']; - } - - // how to order the list? - $order_by = 'id'; - if (isset($_GET['order_by']) - and in_array($_GET['order_by'], array_keys($page['order_by_items']))) - { - $order_by = $_GET['order_by']; - } - - $direction = 'ASC'; - if (isset($_GET['direction']) - and in_array($_GET['direction'], array_keys($page['direction_items']))) - { - $direction = strtoupper($_GET['direction']); - } - - // search users depending on filters and order - $query = ' -SELECT DISTINCT u.'.$conf['user_fields']['id'].' AS id, - u.'.$conf['user_fields']['username'].' AS username, - u.'.$conf['user_fields']['email'].' AS email, - ui.status, - ui.enabled_high, - ui.level - FROM '.USERS_TABLE.' AS u - INNER JOIN '.USER_INFOS_TABLE.' AS ui - ON u.'.$conf['user_fields']['id'].' = ui.user_id - LEFT JOIN '.USER_GROUP_TABLE.' AS ug - ON u.'.$conf['user_fields']['id'].' = ug.user_id - WHERE u.'.$conf['user_fields']['id'].' > 0'; - if (isset($filter['username'])) - { - $query.= ' - AND u.'.$conf['user_fields']['username'].' LIKE \''.$filter['username'].'\''; - } - if (isset($filter['group'])) - { - $query.= ' - AND ug.group_id = '.$filter['group']; - } - if (isset($filter['status'])) - { - $query.= ' - AND ui.status = \''.$filter['status']."'"; - } - $query.= ' - ORDER BY '.$order_by.' '.$direction.' -;'; - - $result = pwg_query($query); - while ($row = pwg_db_fetch_assoc($result)) - { - $user = $row; - $user['groups'] = array(); - - $users[] = $user; - } - - // add group lists - $user_ids = array(); - foreach ($users as $i => $user) - { - $user_ids[$i] = $user['id']; - } - $user_nums = array_flip($user_ids); - - if (count($user_ids) > 0) - { - $query = ' -SELECT user_id, group_id - FROM '.USER_GROUP_TABLE.' - WHERE user_id IN ('.implode(',', $user_ids).') -;'; - $result = pwg_query($query); - while ($row = pwg_db_fetch_assoc($result)) - { - $users[ $user_nums[ $row['user_id'] ] ]['groups'][] = $row['group_id']; - } - } - - return $users; -} - -// +-----------------------------------------------------------------------+ -// | initialization | -// +-----------------------------------------------------------------------+ - -if (!defined('PHPWG_ROOT_PATH')) -{ - die('Hacking attempt!'); -} - -include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); - -// +-----------------------------------------------------------------------+ -// | Check Access and exit when user status is not ok | -// +-----------------------------------------------------------------------+ -check_status(ACCESS_ADMINISTRATOR); - -$page['order_by_items'] = array( - 'id' => l10n('registration date'), - 'username' => l10n('Username'), - 'level' => l10n('Privacy level'), - 'Language' => l10n('Language'), - 'email' => l10n('Email address'), - ); - -$page['direction_items'] = array( - 'asc' => l10n('ascending'), - 'desc' => l10n('descending') - ); - -// +-----------------------------------------------------------------------+ -// | add a user | -// +-----------------------------------------------------------------------+ - -// Check for config_default var - If True : Using double password type else single password type -// This feature is discussed on Piwigo's english forum -if ($conf['double_password_type_in_admin'] == true) -{ - if (isset($_POST['submit_add'])) - { - if(empty($_POST['password'])) - { - $page['errors'][] = l10n('Password is missing. Please enter the password.'); - } - else if(empty($_POST['password_conf'])) - { - $page['errors'][] = l10n('Password confirmation is missing. Please confirm the chosen password.'); - } - else if ($_POST['password'] != $_POST['password_conf']) - { - $page['errors'][] = l10n('The passwords do not match'); - } - else - { - register_user($_POST['login'], - $_POST['password'], - $_POST['email'], - false, - $page['errors']); - - if (count($page['errors']) == 0) - { - $page['infos'][] = l10n('user "%s" added', $_POST['login']); - } - } - } -} -else if ($conf['double_password_type_in_admin'] == false) -{ - if (isset($_POST['submit_add'])) - { - register_user($_POST['login'], - $_POST['password'], - $_POST['email'], - false, - $page['errors']); - - if (count($page['errors']) == 0) - { - $page['infos'][] = l10n('user "%s" added', stripslashes($_POST['login'])); - } - } -} - -// email notification -if ( - isset($_POST['submit_add']) - and count($page['errors']) == 0 - and !empty($_POST['email']) - and isset($_POST['send_password_by_mail']) - ) -{ - include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php'); - - $keyargs_content = array( - get_l10n_args('Hello %s,', $_POST['login']), - get_l10n_args('Thank you for registering at %s!', $conf['gallery_title']), - get_l10n_args('', ''), - get_l10n_args('Here are your connection settings', ''), - get_l10n_args('Username: %s', $_POST['login']), - get_l10n_args('Password: %s', $_POST['password']), - get_l10n_args('Email: %s', $_POST['email']), - get_l10n_args('', ''), - get_l10n_args('If you think you\'ve received this email in error, please contact us at %s', get_webmaster_mail_address()), - ); - - pwg_mail( - $_POST['email'], - array( - 'subject' => '['.$conf['gallery_title'].'] '.l10n('Registration'), - 'content' => l10n_args($keyargs_content), - 'content_format' => 'text/plain', - ) - ); -} - -// +-----------------------------------------------------------------------+ -// | user list | -// +-----------------------------------------------------------------------+ - -$page['filtered_users'] = get_filtered_user_list(); - -// +-----------------------------------------------------------------------+ -// | selected users | -// +-----------------------------------------------------------------------+ - -if (isset($_POST['delete']) or isset($_POST['pref_submit'])) -{ - $collection = array(); - - switch ($_POST['target']) - { - case 'all' : - { - foreach($page['filtered_users'] as $local_user) - { - $collection[] = $local_user['id']; - } - break; - } - case 'selection' : - { - if (isset($_POST['selection'])) - { - $collection = $_POST['selection']; - } - break; - } - } - - if (count($collection) == 0) - { - $page['errors'][] = l10n('Select at least one user'); - } -} - -// +-----------------------------------------------------------------------+ -// | delete users | -// +-----------------------------------------------------------------------+ -if (isset($_POST['delete']) and count($collection) > 0) -{ - if (in_array($conf['guest_id'], $collection)) - { - $page['errors'][] = l10n('Guest cannot be deleted'); - } - if (($conf['guest_id'] != $conf['default_user_id']) and - in_array($conf['default_user_id'], $collection)) - { - $page['errors'][] = l10n('Default user cannot be deleted'); - } - if (in_array($conf['webmaster_id'], $collection)) - { - $page['errors'][] = l10n('Webmaster cannot be deleted'); - } - if (in_array($user['id'], $collection)) - { - $page['errors'][] = l10n('You cannot delete your account'); - } - - if (count($page['errors']) == 0) - { - if (isset($_POST['confirm_deletion']) and 1 == $_POST['confirm_deletion']) - { - foreach ($collection as $user_id) - { - delete_user($user_id); - } - - $page['infos'][] = l10n_dec( - '%d user deleted', '%d users deleted', - count($collection) - ); - - foreach ($page['filtered_users'] as $filter_key => $filter_user) - { - if (in_array($filter_user['id'], $collection)) - { - unset($page['filtered_users'][$filter_key]); - } - } - } - else - { - $page['errors'][] = l10n('You need to confirm deletion'); - } - } -} - -// +-----------------------------------------------------------------------+ -// | preferences form submission | -// +-----------------------------------------------------------------------+ - -if (isset($_POST['pref_submit']) and count($collection) > 0) -{ - if (-1 != $_POST['associate']) - { - $datas = array(); - - $query = ' -SELECT user_id - FROM '.USER_GROUP_TABLE.' - WHERE group_id = '.$_POST['associate'].' -;'; - $associated = array_from_query($query, 'user_id'); - - $associable = array_diff($collection, $associated); - - if (count($associable) > 0) - { - foreach ($associable as $item) - { - $datas[] = array( - 'group_id' => $_POST['associate'], - 'user_id' => $item - ); - } - - mass_inserts(USER_GROUP_TABLE, - array('group_id', 'user_id'), - $datas); - } - } - - if (-1 != $_POST['dissociate']) - { - $query = ' -DELETE FROM '.USER_GROUP_TABLE.' - WHERE group_id = '.$_POST['dissociate'].' - AND user_id IN ('.implode(',', $collection).') -'; - pwg_query($query); - } - - // properties to set for the collection (a user list) - $datas = array(); - $dbfields = array('primary' => array('user_id'), 'update' => array()); - - $formfields = array( - 'nb_image_page', 'theme', 'language', - 'recent_period', 'expand', 'show_nb_hits', - 'status', 'enabled_high', 'level' - ); - - $true_false_fields = array('expand', 'show_nb_hits', 'enabled_high'); - - if ($conf['activate_comments']) - { - $formfields[] = 'show_nb_comments'; - $true_false_fields[] = 'show_nb_comments'; - } - - foreach ($formfields as $formfield) - { - // special for true/false fields - if (in_array($formfield, $true_false_fields)) - { - $test = $formfield; - } - else - { - $test = $formfield.'_action'; - } - - if ($_POST[$test] != 'leave') - { - $dbfields['update'][] = $formfield; - } - } - - // updating elements is useful only if needed... - if (count($dbfields['update']) > 0) - { - $datas = array(); - - foreach ($collection as $user_id) - { - $data = array(); - $data['user_id'] = $user_id; - - // TODO : verify if submited values are semanticaly correct - foreach ($dbfields['update'] as $dbfield) - { - // if the action is 'unset', the key won't be in row and - // mass_updates function will set this field to NULL - if (in_array($dbfield, $true_false_fields) - or 'set' == $_POST[$dbfield.'_action']) - { - $data[$dbfield] = $_POST[$dbfield]; - } - } - - // if the status is getting greater or equal to "admin", then level - // automatically switches to "admin" (8), unless the level is also - // defined in the same batch action. - if (isset($data['status']) and in_array($data['status'], array('webmaster', 'admin'))) - { - if (!isset($data['level'])) - { - $data['level'] = 8; - if (!in_array('level', $dbfields['update'])) - { - $dbfields['update'][] = 'level'; - } - } - } - - // special users checks - if - ( - ($conf['webmaster_id'] == $user_id) or - ($conf['guest_id'] == $user_id) or - ($conf['default_user_id'] == $user_id) - ) - { - // status must not be changed - if (isset($data['status'])) - { - if ($conf['webmaster_id'] == $user_id) - { - $data['status'] = 'webmaster'; - } - else - { - $data['status'] = 'guest'; - } - } - } - - $datas[] = $data; - } - - mass_updates(USER_INFOS_TABLE, $dbfields, $datas); - } - - redirect( - get_root_url(). - 'admin.php'. - get_query_string_diff(array(), false) - ); -} - -// +-----------------------------------------------------------------------+ // | groups list | // +-----------------------------------------------------------------------+ -$groups[-1] = '------------'; +$groups = array(); $query = ' SELECT id, name @@ -526,89 +44,53 @@ while ($row = pwg_db_fetch_assoc($result)) } // +-----------------------------------------------------------------------+ -// | template init | +// | template | // +-----------------------------------------------------------------------+ $template->set_filenames(array('user_list'=>'user_list.tpl')); -$base_url = PHPWG_ROOT_PATH.'admin.php?page=user_list'; +$query = ' +SELECT + DISTINCT u.'.$conf['user_fields']['id'].' AS id, + u.'.$conf['user_fields']['username'].' AS username, + u.'.$conf['user_fields']['email'].' AS email, + ui.status, + ui.enabled_high, + ui.level + FROM '.USERS_TABLE.' AS u + INNER JOIN '.USER_INFOS_TABLE.' AS ui ON u.'.$conf['user_fields']['id'].' = ui.user_id + WHERE u.'.$conf['user_fields']['id'].' > 0 +;'; -if (isset($_GET['start']) and is_numeric($_GET['start'])) -{ - $start = $_GET['start']; -} -else +$result = pwg_query($query); +while ($row = pwg_db_fetch_assoc($result)) { - $start = 0; + $users[] = $row; + $user_ids[] = $row['id']; } $template->assign( array( - 'U_HELP' => get_root_url().'admin/popuphelp.php?page=user_list', - - 'F_ADD_ACTION' => $base_url, - 'F_USERNAME' => @htmlentities($_GET['username'], ENT_COMPAT, 'UTF-8'), - 'F_FILTER_ACTION' => get_root_url().'admin.php', - - 'ACTIVATE_COMMENTS' => $conf['activate_comments'], - )); - -// Display or Hide double password type -$template->assign('Double_Password', $conf['double_password_type_in_admin'] ); - -// Filter status options -$status_options[-1] = '------------'; -foreach (get_enums(USER_INFOS_TABLE, 'status') as $status) -{ - $status_options[$status] = l10n('user_status_'.$status); -} -$template->assign('status_options', $status_options); -$template->assign('status_selected', - isset($_GET['status']) ? $_GET['status'] : ''); - -// Filter group options -$template->assign('group_options', $groups); -$template->assign('group_selected', - isset($_GET['group']) ? $_GET['group'] : ''); - -// Filter order options -$template->assign('order_options', $page['order_by_items']); -$template->assign('order_selected', - isset($_GET['order_by']) ? $_GET['order_by'] : ''); - -// Filter direction options -$template->assign('direction_options', $page['direction_items']); -$template->assign('direction_selected', - isset($_GET['direction']) ? $_GET['direction'] : ''); + 'users' => $users, + 'all_users' => join(',', $user_ids), + ) + ); +// echo '<pre>'; print_r($users); echo '</pre>'; -if (isset($_POST['pref_submit'])) -{ - $template->assign( - array( - 'NB_IMAGE_PAGE' => $_POST['nb_image_page'], - 'RECENT_PERIOD' => $_POST['recent_period'], - )); -} -else -{ - $default_user = get_default_user_info(true); - $template->assign( - array( - 'NB_IMAGE_PAGE' => $default_user['nb_image_page'], - 'RECENT_PERIOD' => $default_user['recent_period'], - )); -} +$default_user = get_default_user_info(true); -// Template Options -$template->assign('theme_options', get_pwg_themes()); -$template->assign('theme_selected', - isset($_POST['pref_submit']) ? $_POST['theme'] : get_default_theme()); - -// Language options -$template->assign('language_options', get_languages()); -$template->assign('language_selected', - isset($_POST['pref_submit']) ? $_POST['language'] : get_default_language()); +$template->assign( + array( + 'NB_IMAGE_PAGE' => $default_user['nb_image_page'], + 'RECENT_PERIOD' => $default_user['recent_period'], + 'theme_options' => get_pwg_themes(), + 'theme_selected' => get_default_theme(), + 'language_options' => get_languages(), + 'language_selected' => get_default_language(), + 'association_options' => $groups, + ) + ); // Status options foreach (get_enums(USER_INFOS_TABLE, 'status') as $status) @@ -620,16 +102,7 @@ foreach (get_enums(USER_INFOS_TABLE, 'status') as $status) } } $template->assign('pref_status_options', $pref_status_options); -$template->assign('pref_status_selected', - isset($_POST['pref_submit']) ? $_POST['status'] : 'normal'); - -// associate and dissociate options -$template->assign('association_options', $groups); -$template->assign('associate_selected', - isset($_POST['pref_submit']) ? $_POST['associate'] : ''); -$template->assign('dissociate_selected', - isset($_POST['pref_submit']) ? $_POST['dissociate'] : ''); - +$template->assign('pref_status_selected', 'normal'); // user level options foreach ($conf['available_permission_levels'] as $level) @@ -637,107 +110,12 @@ foreach ($conf['available_permission_levels'] as $level) $level_options[$level] = l10n(sprintf('Level %d', $level)); } $template->assign('level_options', $level_options); -$template->assign('level_selected', - isset($_POST['pref_submit']) ? $_POST['level'] : $default_user['level']); - -// +-----------------------------------------------------------------------+ -// | navigation bar | -// +-----------------------------------------------------------------------+ - -$url = PHPWG_ROOT_PATH.'admin.php'.get_query_string_diff(array('start')); - -$navbar = create_navigation_bar( - $url, - count($page['filtered_users']), - $start, - $conf['users_page'] - ); +$template->assign('level_selected', $default_user['level']); -$template->assign('navbar', $navbar); - -// +-----------------------------------------------------------------------+ -// | user list | -// +-----------------------------------------------------------------------+ - -$profile_url = get_root_url().'admin.php?page=profile&user_id='; -$perm_url = get_root_url().'admin.php?page=user_perm&user_id='; - -$visible_user_list = array(); -foreach ($page['filtered_users'] as $num => $local_user) -{ - // simulate LIMIT $start, $conf['users_page'] - if ($num < $start) - { - continue; - } - if ($num >= $start + $conf['users_page']) - { - break; - } - - $visible_user_list[] = $local_user; -} - -// allow plugins to fill template var plugin_user_list_column_titles and -// plugin_columns/plugin_actions for each user in the list -$visible_user_list = trigger_event('loc_visible_user_list', $visible_user_list); - -foreach ($visible_user_list as $local_user) -{ - $groups_string = preg_replace( - '/(\d+)/e', - "\$groups['$1']", - implode( - ', ', - $local_user['groups'] - ) - ); - - if (isset($_POST['pref_submit']) - and isset($_POST['selection']) - and in_array($local_user['id'], $_POST['selection'])) - { - $checked = 'checked="checked"'; - } - else - { - $checked = ''; - } - - $properties = array(); - if ( $local_user['level'] != 0 ) - { - $properties[] = l10n( sprintf('Level %d', $local_user['level']) ); - } - $properties[] = - (isset($local_user['enabled_high']) and ($local_user['enabled_high'] == 'true')) - ? l10n('High definition') : l10n(''); - - $template->append( - 'users', - array( - 'ID' => $local_user['id'], - 'CHECKED' => $checked, - 'U_PROFILE' => $profile_url.$local_user['id'], - 'U_PERM' => $perm_url.$local_user['id'], - 'USERNAME' => stripslashes($local_user['username']) - .($local_user['id'] == $conf['guest_id'] - ? '<br>['.l10n('guest').']' : '') - .($local_user['id'] == $conf['default_user_id'] - ? '<br>['.l10n('default values').']' : ''), - 'STATUS' => l10n('user_status_'.$local_user['status']), - 'EMAIL' => get_email_address_as_display_text($local_user['email']), - 'GROUPS' => $groups_string, - 'PROPERTIES' => implode( ', ', $properties), - 'plugin_columns' => isset($local_user['plugin_columns']) ? $local_user['plugin_columns'] : array(), - 'plugin_actions' => isset($local_user['plugin_actions']) ? $local_user['plugin_actions'] : array(), - ) - ); -} // +-----------------------------------------------------------------------+ -// | html code display | +// | html code display | // +-----------------------------------------------------------------------+ $template->assign_var_from_handle('ADMIN_CONTENT', 'user_list'); -?> +?>
\ No newline at end of file diff --git a/admin/user_list_backend.php b/admin/user_list_backend.php new file mode 100644 index 000000000..8b9734b07 --- /dev/null +++ b/admin/user_list_backend.php @@ -0,0 +1,158 @@ +<?php +define('PHPWG_ROOT_PATH','../'); +define('IN_ADMIN', true); + +include_once(PHPWG_ROOT_PATH.'include/common.inc.php'); + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Easy set variables + */ + +/* Array of database columns which should be read and sent back to DataTables. Use a space where + * you want to insert a non-database field (for example a counter or static image) + */ +$aColumns = array('id', 'username', 'status', 'mail_address'); + +/* Indexed column (used for fast and accurate table cardinality) */ +$sIndexColumn = "id"; + +/* DB table to use */ +$sTable = USERS_TABLE.' INNER JOIN '.USER_INFOS_TABLE.' AS ui ON id = ui.user_id'; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * If you just want to use the basic configuration for DataTables with PHP server-side, there is + * no need to edit below this line + */ + +/* + * Paging + */ +$sLimit = ""; +if ( isset( $_GET['iDisplayStart'] ) && $_GET['iDisplayLength'] != '-1' ) +{ + $sLimit = "LIMIT ".pwg_db_real_escape_string( $_GET['iDisplayStart'] ).", ". + pwg_db_real_escape_string( $_GET['iDisplayLength'] ); +} + + +/* + * Ordering + */ +if ( isset( $_GET['iSortCol_0'] ) ) +{ + $sOrder = "ORDER BY "; + for ( $i=0 ; $i<intval( $_GET['iSortingCols'] ) ; $i++ ) + { + if ( $_GET[ 'bSortable_'.intval($_GET['iSortCol_'.$i]) ] == "true" ) + { + $sOrder .= $aColumns[ intval( $_GET['iSortCol_'.$i] ) ]." + ".pwg_db_real_escape_string( $_GET['sSortDir_'.$i] ) .", "; + } + } + + $sOrder = substr_replace( $sOrder, "", -2 ); + if ( $sOrder == "ORDER BY" ) + { + $sOrder = ""; + } +} + + +/* + * Filtering + * NOTE this does not match the built-in DataTables filtering which does it + * word by word on any field. It's possible to do here, but concerned about efficiency + * on very large tables, and MySQL's regex functionality is very limited + */ +$sWhere = ""; +if ( $_GET['sSearch'] != "" ) +{ + $sWhere = "WHERE ("; + for ( $i=0 ; $i<count($aColumns) ; $i++ ) + { + $sWhere .= $aColumns[$i]." LIKE '%".pwg_db_real_escape_string( $_GET['sSearch'] )."%' OR "; + } + $sWhere = substr_replace( $sWhere, "", -3 ); + $sWhere .= ')'; +} + +/* Individual column filtering */ +for ( $i=0 ; $i<count($aColumns) ; $i++ ) +{ + if ( $_GET['bSearchable_'.$i] == "true" && $_GET['sSearch_'.$i] != '' ) + { + if ( $sWhere == "" ) + { + $sWhere = "WHERE "; + } + else + { + $sWhere .= " AND "; + } + $sWhere .= $aColumns[$i]." LIKE '%".pwg_db_real_escape_string($_GET['sSearch_'.$i])."%' "; + } +} + + +/* + * SQL queries + * Get data to display + */ +$sQuery = " + SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))." + FROM $sTable + $sWhere + $sOrder + $sLimit + "; +$rResult = pwg_query($sQuery); + +/* Data set length after filtering */ +$sQuery = " + SELECT FOUND_ROWS() + "; +$rResultFilterTotal = pwg_query($sQuery); +$aResultFilterTotal = pwg_db_fetch_array($rResultFilterTotal); +$iFilteredTotal = $aResultFilterTotal[0]; + +/* Total data set length */ +$sQuery = " + SELECT COUNT(".$sIndexColumn.") + FROM $sTable + "; +$rResultTotal = pwg_query($sQuery); +$aResultTotal = pwg_db_fetch_array($rResultTotal); +$iTotal = $aResultTotal[0]; + + +/* + * Output + */ +$output = array( + "sEcho" => intval($_GET['sEcho']), + "iTotalRecords" => $iTotal, + "iTotalDisplayRecords" => $iFilteredTotal, + "aaData" => array() + ); + +while ( $aRow = pwg_db_fetch_array( $rResult ) ) +{ + $row = array(); + for ( $i=0 ; $i<count($aColumns) ; $i++ ) + { + if ( $aColumns[$i] == "version" ) + { + /* Special output formatting for 'version' column */ + $row[] = ($aRow[ $aColumns[$i] ]=="0") ? '-' : $aRow[ $aColumns[$i] ]; + } + else if ( $aColumns[$i] != ' ' ) + { + /* General output */ + $row[] = $aRow[ $aColumns[$i] ]; + } + } + $output['aaData'][] = $row; +} + +echo json_encode( $output ); +?>
\ No newline at end of file |