From 3d72b90e2d372e6eb9a290188478f64affbcfd0f Mon Sep 17 00:00:00 2001 From: plegall Date: Mon, 24 Mar 2014 20:19:22 +0000 Subject: bug 3057: avoid warnings and SQL crash when encountering inconsistent permissions + rewrite permissions consistancy check when setting albums to private status. git-svn-id: http://piwigo.org/svn/branches/2.6@27925 68402e56-0260-453c-a942-63ccdbb3a9ee --- admin/include/functions.php | 190 +++++++++++++++++++++++++++++-------- include/functions_category.inc.php | 9 ++ 2 files changed, 161 insertions(+), 38 deletions(-) diff --git a/admin/include/functions.php b/admin/include/functions.php index bdeab47e7..ac59d2d34 100644 --- a/admin/include/functions.php +++ b/admin/include/functions.php @@ -699,15 +699,166 @@ UPDATE '.CATEGORIES_TABLE.' ;'; pwg_query($query); } + // make a category private => all its child categories become private if ($value == 'private') { $subcats = get_subcat_ids($categories); + $query = ' UPDATE '.CATEGORIES_TABLE.' SET status = \'private\' WHERE id IN ('.implode(',', $subcats).')'; pwg_query($query); + + // We have to keep permissions consistant: a sub-album can't be + // permitted to a user or group if its parent album is not permitted to + // the same user or group. Let's remove all permissions on sub-albums if + // it is not consistant. Let's take the following example: + // + // A1 permitted to U1,G1 + // A1/A2 permitted to U1,U2,G1,G2 + // A1/A2/A3 permitted to U3,G1 + // A1/A2/A4 permitted to U2 + // A1/A5 permitted to U4 + // A6 permitted to U4 + // A6/A7 permitted to G1 + // + // (we consider that it can be possible to start with inconsistant + // permission, given that public albums can have hidden permissions, + // revealed once the album returns to private status) + // + // The admin selects A2,A3,A4,A5,A6,A7 to become private (all but A1, + // which is private, which can be true if we're moving A2 into A1). The + // result must be: + // + // A2 permission removed to U2,G2 + // A3 permission removed to U3 + // A4 permission removed to U2 + // A5 permission removed to U2 + // A6 permission removed to U4 + // A7 no permission removed + // + // 1) we must extract "top albums": A2, A5 and A6 + // 2) for each top album, decide which album is the reference for permissions + // 3) remove all inconsistant permissions from sub-albums of each top-album + + // step 1, search top albums + $all_categories = array(); + $top_categories = array(); + $parent_ids = array(); + + $query = ' +SELECT + id, + name, + id_uppercat, + uppercats, + global_rank + FROM '.CATEGORIES_TABLE.' + WHERE id IN ('.implode(',', $categories).') +;'; + $result = pwg_query($query); + while ($row = pwg_db_fetch_assoc($result)) + { + $all_categories[] = $row; + } + + usort($all_categories, 'global_rank_compare'); + + foreach ($all_categories as $cat) + { + $is_top = true; + + if (!empty($cat['id_uppercat'])) + { + foreach (explode(',', $cat['uppercats']) as $id_uppercat) + { + if (isset($top_categories[$id_uppercat])) + { + $is_top = false; + break; + } + } + } + + if ($is_top) + { + $top_categories[$cat['id']] = $cat; + + if (!empty($cat['id_uppercat'])) + { + $parent_ids[] = $cat['id_uppercat']; + } + } + } + + // step 2, search the reference album for permissions + // + // to find the reference of each top album, we will need the parent albums + $parent_cats = array(); + + if (count($parent_ids) > 0) + { + $query = ' +SELECT + id, + status + FROM '.CATEGORIES_TABLE.' + WHERE id IN ('.implode(',', $parent_ids).') +;'; + $result = pwg_query($query); + while ($row = pwg_db_fetch_assoc($result)) + { + $parent_cats[$row['id']] = $row; + } + } + + $tables = array( + USER_ACCESS_TABLE => 'user_id', + GROUP_ACCESS_TABLE => 'group_id' + ); + + foreach ($top_categories as $top_category) + { + // what is the "reference" for list of permissions? The parent album + // if it is private, else the album itself + $ref_cat_id = $top_category['id']; + + if (!empty($top_category['id_uppercat']) + and isset($parent_cats[ $top_category['id_uppercat'] ]) + and 'private' == $parent_cats[ $top_category['id_uppercat'] ]['status']) + { + $ref_cat_id = $top_category['id_uppercat']; + } + + $subcats = get_subcat_ids(array($top_category['id'])); + + foreach ($tables as $table => $field) + { + // what are the permissions user/group of the reference album + $query = ' +SELECT '.$field.' + FROM '.$table.' + WHERE cat_id = '.$ref_cat_id.' +;'; + $ref_access = array_from_query($query, $field); + + if (count($ref_access) == 0) + { + $ref_access[] = -1; + } + + // step 3, remove the inconsistant permissions from sub-albums + $query = ' +DELETE + FROM '.$table.' + WHERE '.$field.' NOT IN ('.implode(',', $ref_access).') + AND cat_id IN ('.implode(',', $subcats).') +;'; + pwg_query($query); + } + } } } @@ -1139,44 +1290,7 @@ SELECT status if ('private' == $parent_status) { - foreach ($categories as $cat_id => $category) - { - if ('public' == $category['status']) - { - set_cat_status(array($cat_id), 'private'); - } - - $subcats = get_subcat_ids(array($cat_id)); - - foreach ($tables as $table => $field) - { - $query = ' -SELECT '.$field.' - FROM '.$table.' - WHERE cat_id = '.$cat_id.' -;'; - $category_access = array_from_query($query, $field); - - $query = ' -SELECT '.$field.' - FROM '.$table.' - WHERE cat_id = '.$new_parent.' -;'; - $parent_access = array_from_query($query, $field); - - $to_delete = array_diff($category_access, $parent_access); - - if (count($to_delete) > 0) - { - $query = ' -DELETE FROM '.$table.' - WHERE '.$field.' IN ('.implode(',', $to_delete).') - AND cat_id IN ('.implode(',', $subcats).') -;'; - pwg_query($query); - } - } - } + set_cat_status(array_keys($categories), 'private'); } $page['infos'][] = l10n_dec( diff --git a/include/functions_category.inc.php b/include/functions_category.inc.php index 43289ca01..5a4416a18 100644 --- a/include/functions_category.inc.php +++ b/include/functions_category.inc.php @@ -538,6 +538,15 @@ FROM '.CATEGORIES_TABLE.' as c if ( !isset( $cat['id_uppercat'] ) ) continue; + // Piwigo before 2.5.3 may have generated inconsistent permissions, ie + // private album A1/A2 permitted to user U1 but private album A1 not + // permitted to U1. + // + // TODO 2.7: add an upgrade script to repair permissions and remove this + // test + if ( !isset($cats[ $cat['id_uppercat'] ])) + continue; + $parent = & $cats[ $cat['id_uppercat'] ]; $parent['nb_categories']++; -- cgit v1.2.3