Piwigo/include/ws_functions/pwg.categories.php
Linty 40ca83d382 fixes #2221 use backticks instead of quotes
...because that's what backticks are for.
2024-09-03 16:19:06 +02:00

1472 lines
38 KiB
PHP

<?php
// +-----------------------------------------------------------------------+
// | This file is part of Piwigo. |
// | |
// | For copyright and license information, please view the COPYING.txt |
// | file that was distributed with this source code. |
// +-----------------------------------------------------------------------+
/**
* API method
* Returns images per category
* @param mixed[] $params
* @option int[] cat_id (optional)
* @option bool recursive
* @option int per_page
* @option int page
* @option string order (optional)
*/
function ws_categories_getImages($params, &$service)
{
global $user, $conf;
$params['cat_id'] = array_unique($params['cat_id']);
if (count($params['cat_id']) > 0)
{
// do the categories really exist?
$query = '
SELECT id
FROM '.CATEGORIES_TABLE.'
WHERE id IN ('.implode(',', $params['cat_id']).')
;';
$db_cat_ids = query2array($query, null, 'id');
$missing_cat_ids = array_diff($params['cat_id'], $db_cat_ids);
if (count($missing_cat_ids) > 0)
{
return new PwgError(404, 'cat_id {'.implode(',', $missing_cat_ids).'} not found');
}
}
$images = array();
$image_ids = array();
$total_images = 0;
//------------------------------------------------- get the related categories
$where_clauses = array();
foreach ($params['cat_id'] as $cat_id)
{
if ($params['recursive'])
{
$where_clauses[] = 'uppercats '.DB_REGEX_OPERATOR.' \'(^|,)'.$cat_id.'(,|$)\'';
}
else
{
$where_clauses[] = 'id='.$cat_id;
}
}
if (!empty($where_clauses))
{
$where_clauses = array('('. implode("\n OR ", $where_clauses) . ')');
}
$where_clauses[] = get_sql_condition_FandF(
array('forbidden_categories' => 'id'),
null, true
);
$query = '
SELECT
id,
image_order
FROM '. CATEGORIES_TABLE .'
WHERE '. implode("\n AND ", $where_clauses) .'
;';
$result = pwg_query($query);
$cats = array();
while ($row = pwg_db_fetch_assoc($result))
{
$row['id'] = (int)$row['id'];
$cats[ $row['id'] ] = $row;
}
//-------------------------------------------------------- get the images
if (!empty($cats))
{
$where_clauses = ws_std_image_sql_filter($params, 'i.');
$where_clauses[] = 'category_id IN ('. implode(',', array_keys($cats)) .')';
$where_clauses[] = get_sql_condition_FandF(
array('visible_images' => 'i.id'),
null, true
);
$order_by = ws_std_image_sql_order($params, 'i.');
if ( empty($order_by)
and count($params['cat_id'])==1
and isset($cats[ $params['cat_id'][0] ]['image_order'])
)
{
$order_by = $cats[ $params['cat_id'][0] ]['image_order'];
}
$order_by = empty($order_by) ? $conf['order_by'] : 'ORDER BY '.$order_by;
$favorite_ids = get_user_favorites();
$query = '
SELECT SQL_CALC_FOUND_ROWS i.*
FROM '. IMAGES_TABLE .' i
INNER JOIN '. IMAGE_CATEGORY_TABLE .' ON i.id=image_id
WHERE '. implode("\n AND ", $where_clauses) .'
GROUP BY i.id
'. $order_by .'
LIMIT '. $params['per_page'] .'
OFFSET '. ($params['per_page']*$params['page']) .'
;';
$result = pwg_query($query);
while ($row = pwg_db_fetch_assoc($result))
{
$image_ids[] = $row['id'];
$image = array();
$image['is_favorite'] = isset($favorite_ids[ $row['id'] ]);
foreach (array('id', 'width', 'height', 'hit') as $k)
{
if (isset($row[$k]))
{
$image[$k] = (int)$row[$k];
}
}
foreach (array('file', 'name', 'comment', 'date_creation', 'date_available') as $k)
{
$image[$k] = $row[$k];
}
$image = array_merge($image, ws_std_get_urls($row));
$images[] = $image;
}
list($total_images) = pwg_db_fetch_row(pwg_query('SELECT FOUND_ROWS()'));
$total_images = (int)$total_images;
// let's take care of adding the related albums to each photo
if (count($image_ids) > 0)
{
$category_ids = array();
// find the complete list (given permissions) of albums linked to photos
$query = '
SELECT
image_id,
category_id
FROM '.IMAGE_CATEGORY_TABLE.'
WHERE image_id IN ('.implode(',', $image_ids).')
AND '.get_sql_condition_FandF(array('forbidden_categories' => 'category_id'), null, true).'
;';
$result = pwg_query($query);
while ($row = pwg_db_fetch_assoc($result))
{
$category_ids[] = $row['category_id'];
@$categories_of_image[ $row['image_id'] ][] = $row['category_id'];
}
if (count($category_ids) > 0)
{
// find details (for URL generation) about each album
$query = '
SELECT
id,
name,
permalink
FROM '. CATEGORIES_TABLE .'
WHERE id IN ('. implode(',', $category_ids) .')
;';
$details_for_category = query2array($query, 'id');
}
foreach ($images as $idx => $image)
{
$image_cats = array();
// it should not be possible at this point, but let's consider a photo can be in no album
if (!isset($categories_of_image[ $image['id'] ]))
{
continue;
}
foreach ($categories_of_image[ $image['id'] ] as $cat_id)
{
$url = make_index_url(array('category' => $details_for_category[$cat_id]));
$page_url = make_picture_url(
array(
'category' => $details_for_category[$cat_id],
'image_id' => $image['id'],
'image_file' => $image['file'],
)
);
$image_cats[] = array(
'id' => (int)$cat_id,
'url' => $url,
'page_url' => $page_url,
);
}
$images[$idx]['categories'] = new PwgNamedArray(
$image_cats,
'category',
array('id', 'url', 'page_url')
);
}
}
}
return array(
'paging' => new PwgNamedStruct(
array(
'page' => $params['page'],
'per_page' => $params['per_page'],
'count' => count($images),
'total_count' => $total_images
)
),
'images' => new PwgNamedArray(
$images, 'image',
ws_std_get_image_xml_attributes()
)
);
}
/**
* API method
* Returns a list of categories
* @param mixed[] $params
* @option int cat_id (optional)
* @option bool recursive
* @option bool public
* @option bool tree_output
* @option bool fullname
*/
function ws_categories_getList($params, &$service)
{
global $user, $conf;
if (!in_array($params['thumbnail_size'], array_keys(ImageStdParams::get_defined_type_map())))
{
return new PwgError(WS_ERR_INVALID_PARAM, "Invalid thumbnail_size");
}
if (!empty($params['limit']) and $params['recursive'])
{
return new PwgError(WS_ERR_INVALID_PARAM, 'Cannot use both recursive and limit parameters at the same time');
}
$output = [];
$where = array('1=1');
$join_type = 'INNER';
$join_user = $user['id'];
if (!$params['recursive'])
{
if ($params['cat_id']>0)
{
$where[] = '(
id_uppercat = '. (int)($params['cat_id']) .'
OR id='.(int)($params['cat_id']).'
)';
}
else
{
$where[] = 'id_uppercat IS NULL';
}
}
elseif ($params['cat_id']>0)
{
$where[] = 'uppercats '. DB_REGEX_OPERATOR .' \'(^|,)'.
(int)($params['cat_id']) .'(,|$)\'';
}
if ($params['public'])
{
$where[] = 'status = "public"';
$where[] = 'visible = "true"';
$join_user = $conf['guest_id'];
}
elseif (is_admin())
{
// in this very specific case, we don't want to hide empty
// categories. Function calculate_permissions will only return
// categories that are either locked or private and not permitted
//
// calculate_permissions does not consider empty categories as forbidden
$forbidden_categories = calculate_permissions($user['id'], $user['status']);
$where[]= 'id NOT IN ('.$forbidden_categories.')';
$join_type = 'LEFT';
}
$query = '
SELECT SQL_CALC_FOUND_ROWS
id, name, comment, permalink, status,
uppercats, global_rank, id_uppercat,
nb_images, count_images AS total_nb_images,
representative_picture_id, user_representative_picture_id, count_images, count_categories,
date_last, max_date_last, count_categories AS nb_categories,
image_order
FROM '. CATEGORIES_TABLE .'
'.$join_type.' JOIN '. USER_CACHE_CATEGORIES_TABLE .'
ON id=cat_id AND user_id='.$join_user.'
WHERE '. implode("\n AND ", $where);
if (isset($params['search']) and '' != $params['search'])
{
$query .= '
AND name LIKE \'%'.pwg_db_real_escape_string($params['search']).'%\'';
if (!isset($params['limit']))
{
$query .= ' LIMIT '.$conf["linked_album_search_limit"];
}
}
if (isset($params['limit']))
{
$query .= '
ORDER BY `rank` ASC
LIMIT '.($params['limit'] + ($params['cat_id'] > 0 ? 1 : 0));
}
$query.= '
;';
$result = pwg_query($query);
if (isset($params['limit']))
{
list($result_count) = pwg_db_fetch_row(pwg_query('SELECT FOUND_ROWS()'));
if ($params['cat_id'] > 0)
{
$result_count = $result_count - 1;
}
$output['limit'] = array(
'limited_to' => $params['limit'],
'total_cats' => intval($result_count),
'remaining_cats' => $result_count > $params['limit'] ? $result_count - $params['limit'] : 0,
);
}
// management of the album thumbnail -- starts here
$image_ids = array();
$categories = array();
$user_representative_updates_for = array();
// management of the album thumbnail -- stops here
$cats = array();
while ($row = pwg_db_fetch_assoc($result))
{
$row['url'] = make_index_url(
array(
'category' => $row
)
);
foreach (array('id','nb_images','total_nb_images','nb_categories') as $key)
{
$row[$key] = (int)$row[$key];
}
if ($params['fullname'])
{
$row['name'] = strip_tags(get_cat_display_name_cache($row['uppercats'], null));
}
else
{
$row['name'] = strip_tags(
trigger_change(
'render_category_name',
$row['name'],
'ws_categories_getList'
)
);
}
$row['comment'] = strip_tags(
(string) trigger_change(
'render_category_description',
$row['comment'],
'ws_categories_getList'
)
);
// management of the album thumbnail -- starts here
//
// on branch 2.3, the algorithm is duplicated from
// include/category_cats, but we should use a common code for Piwigo 2.4
//
// warning : if the API method is called with $params['public'], the
// album thumbnail may be not accurate. The thumbnail can be viewed by
// the connected user, but maybe not by the guest. Changing the
// filtering method would be too complicated for now. We will simply
// avoid to persist the user_representative_picture_id in the database
// if $params['public']
if (!empty($row['user_representative_picture_id']))
{
$image_id = $row['user_representative_picture_id'];
}
elseif (!empty($row['representative_picture_id']))
{ // if a representative picture is set, it has priority
$image_id = $row['representative_picture_id'];
}
elseif ($conf['allow_random_representative'])
{
// searching a random representant among elements in sub-categories
$image_id = get_random_image_in_category($row);
}
else
{ // searching a random representant among representant of sub-categories
if ($row['count_categories']>0 and $row['count_images']>0)
{
$query = '
SELECT representative_picture_id
FROM '. CATEGORIES_TABLE .'
INNER JOIN '. USER_CACHE_CATEGORIES_TABLE .'
ON id=cat_id AND user_id='.$user['id'].'
WHERE uppercats LIKE \''.$row['uppercats'].',%\'
AND representative_picture_id IS NOT NULL
'.get_sql_condition_FandF(
array('visible_categories' => 'id'),
"\n AND"
).'
ORDER BY '. DB_RANDOM_FUNCTION .'()
LIMIT 1
;';
$subresult = pwg_query($query);
if (pwg_db_num_rows($subresult) > 0)
{
list($image_id) = pwg_db_fetch_row($subresult);
}
}
}
if (isset($image_id))
{
if ($conf['representative_cache_on_subcats'] and $row['user_representative_picture_id'] != $image_id)
{
$user_representative_updates_for[ $row['id'] ] = $image_id;
}
$row['representative_picture_id'] = $image_id;
$image_ids[] = $image_id;
$categories[] = $row;
}
unset($image_id);
// management of the album thumbnail -- stops here
if (empty($row['image_order']))
{
$row['image_order'] = str_replace('ORDER BY ', '', $conf['order_by']);
}
$cats[] = $row;
}
usort($cats, 'global_rank_compare');
// management of the album thumbnail -- starts here
if (count($categories) > 0)
{
$thumbnail_src_of = array();
$new_image_ids = array();
$query = '
SELECT id, path, representative_ext, level
FROM '. IMAGES_TABLE .'
WHERE id IN ('. implode(',', $image_ids) .')
;';
$result = pwg_query($query);
while ($row = pwg_db_fetch_assoc($result))
{
if ($row['level'] <= $user['level'])
{
$thumbnail_src_of[$row['id']] = DerivativeImage::url($params['thumbnail_size'], $row);
}
else
{
// problem: we must not display the thumbnail of a photo which has a
// higher privacy level than user privacy level
//
// * what is the represented category?
// * find a random photo matching user permissions
// * register it at user_representative_picture_id
// * set it as the representative_picture_id for the category
foreach ($categories as &$category)
{
if ($row['id'] == $category['representative_picture_id'])
{
// searching a random representant among elements in sub-categories
$image_id = get_random_image_in_category($category);
if (isset($image_id) and !in_array($image_id, $image_ids))
{
$new_image_ids[] = $image_id;
}
if ($conf['representative_cache_on_level'])
{
$user_representative_updates_for[ $category['id'] ] = $image_id;
}
$category['representative_picture_id'] = $image_id;
}
}
unset($category);
}
}
if (count($new_image_ids) > 0)
{
$query = '
SELECT id, path, representative_ext
FROM '. IMAGES_TABLE .'
WHERE id IN ('. implode(',', $new_image_ids) .')
;';
$result = pwg_query($query);
while ($row = pwg_db_fetch_assoc($result))
{
$thumbnail_src_of[ $row['id'] ] = DerivativeImage::url($params['thumbnail_size'], $row);
}
}
}
// compared to code in include/category_cats, we only persist the new
// user_representative if we have used $user['id'] and not the guest id,
// or else the real guest may see thumbnail that he should not
if (!$params['public'] and count($user_representative_updates_for))
{
$updates = array();
foreach ($user_representative_updates_for as $cat_id => $image_id)
{
$updates[] = array(
'user_id' => $user['id'],
'cat_id' => $cat_id,
'user_representative_picture_id' => $image_id,
);
}
mass_updates(
USER_CACHE_CATEGORIES_TABLE,
array(
'primary' => array('user_id', 'cat_id'),
'update' => array('user_representative_picture_id')
),
$updates
);
}
foreach ($cats as &$cat)
{
foreach ($categories as $category)
{
if ($category['id'] == $cat['id'] and isset($category['representative_picture_id']))
{
$cat['tn_url'] = $thumbnail_src_of[$category['representative_picture_id']];
}
}
// we don't want them in the output
unset($cat['user_representative_picture_id'], $cat['count_images'], $cat['count_categories']);
}
unset($cat);
// management of the album thumbnail -- stops here
if ($params['tree_output'])
{
return categories_flatlist_to_tree($cats);
}
$output['categories'] = new PwgNamedArray(
$cats,
'category',
ws_std_get_category_xml_attributes()
);
return $output;
}
/**
* API method
* Returns the list of categories as you can see them in administration
* @param mixed[] $params
*
* Only admin can run this method and permissions are not taken into
* account.
*/
function ws_categories_getAdminList($params, &$service)
{
global $conf;
if (!isset($params['additional_output']))
{
$params['additional_output'] = "";
}
$params['additional_output'] = array_map('trim', explode(',', $params['additional_output']));
$query = '
SELECT category_id, COUNT(*) AS counter
FROM '. IMAGE_CATEGORY_TABLE .'
GROUP BY category_id
;';
$nb_images_of = query2array($query, 'category_id', 'counter');
// pwg_db_real_escape_string
$where = array('1=1');
if (!$params['recursive'])
{
if ($params['cat_id']>0)
{
$where[] = '(
id_uppercat = '. (int)($params['cat_id']) .'
OR id='.(int)($params['cat_id']).'
)';
}
else
{
$where[] = 'id_uppercat IS NULL';
}
}
elseif ($params['cat_id']>0)
{
$where[] = 'uppercats '. DB_REGEX_OPERATOR .' \'(^|,)'.
(int)($params['cat_id']) .'(,|$)\'';
}
$query = '
SELECT SQL_CALC_FOUND_ROWS id, name, comment, uppercats, global_rank, dir, status, image_order
FROM '. CATEGORIES_TABLE .'
WHERE '. implode("\n AND ", $where);
if (isset($params["search"]) and $params['search'] != "")
{
$query .= '
AND name LIKE \'%'.pwg_db_real_escape_string($params["search"]).'%\'
LIMIT '.$conf["linked_album_search_limit"];
}
$query .= '
;';
$result = pwg_query($query);
list($counter) = pwg_db_fetch_row(pwg_query('SELECT FOUND_ROWS()'));
$cats = array();
while ($row = pwg_db_fetch_assoc($result))
{
$id = $row['id'];
$row['nb_images'] = isset($nb_images_of[$id]) ? $nb_images_of[$id] : 0;
$cat_display_name = get_cat_display_name_cache(
$row['uppercats'],
'admin.php?page=album-'
);
$row['name'] = strip_tags(
trigger_change(
'render_category_name',
$row['name'],
'ws_categories_getAdminList'
)
);
$row['fullname'] = strip_tags($cat_display_name);
isset($row['comment']) ? false : $row['comment'] = "";
$row['comment'] = strip_tags(
trigger_change(
'render_category_description',
$row['comment'],
'ws_categories_getAdminList'
)
);
if (empty($row['image_order']))
{
$row['image_order'] = str_replace('ORDER BY ', '', $conf['order_by']);
}
if (in_array('full_name_with_admin_links', $params['additional_output']))
{
$row["full_name_with_admin_links"] = $cat_display_name;
}
$cats[] = $row;
}
if (!$params['recursive'])
{
$cats_ids = array_column($cats, 'id');
$nb_subcats_of = array();
if (!empty($cats_ids))
{
$query = '
SELECT
id_uppercat,
COUNT(*) AS nb_subcats
FROM '. CATEGORIES_TABLE .'
WHERE id_uppercat IN ('. implode(',', $cats_ids ) .')
GROUP BY id_uppercat
';
$nb_subcats_of = query2array($query, 'id_uppercat', 'nb_subcats');
}
foreach ($cats as $idx => $cat)
{
$cats[$idx]['nb_categories'] = intval($nb_subcats_of[ $cat['id'] ] ?? 0);
}
}
$limit_reached = false;
if ($counter > $conf["linked_album_search_limit"])
{
$limit_reached = true;
}
usort($cats, 'global_rank_compare');
return array(
'categories' => new PwgNamedArray(
$cats,
'category',
array('id', 'nb_images', 'name', 'uppercats', 'global_rank', 'status', 'test')
),
'limit' => $conf["linked_album_search_limit"],
'limit_reached' => $limit_reached,
);
}
/**
* API method
* Adds a category
* @param mixed[] $params
* @option string name
* @option int parent (optional)
* @option string comment (optional)
* @option bool visible
* @option string status (optional)
* @option bool commentable
*/
function ws_categories_add($params, &$service)
{
include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
global $conf;
if (isset($params['pwg_token']) and get_pwg_token() != $params['pwg_token'])
{
return new PwgError(403, 'Invalid security token');
}
if (!empty($params['position']) and in_array($params['position'], array('first','last')))
{
//TODO make persistent with user prefs
$conf['newcat_default_position'] = $params["position"];
}
$options = array();
if (!empty($params['status']) and in_array($params['status'], array('private','public')))
{
$options['status'] = $params['status'];
}
if (!empty($params['comment']))
{
$options['comment'] = (!$conf['allow_html_descriptions'] or !isset($params['pwg_token'])) ? strip_tags($params['comment']) : $params['comment'];
}
$creation_output = create_virtual_category(
(!$conf['allow_html_descriptions'] or !isset($params['pwg_token'])) ? strip_tags($params['name']) : $params['name'],
$params['parent'],
$options
);
if (isset($creation_output['error']))
{
return new PwgError(500, $creation_output['error']);
}
invalidate_user_cache();
return $creation_output;
}
/**
* API method
* Set the rank of a category
* @param mixed[] $params
* @option int cat_id
* @option int rank
*/
function ws_categories_setRank($params, &$service)
{
// does the category really exist?
$query = '
SELECT id, id_uppercat, `rank`
FROM '.CATEGORIES_TABLE.'
WHERE id IN ('.implode(',',$params['category_id']).')
;';
$categories = query2array($query);
if (count($categories) == 0)
{
return new PwgError(404, 'category_id not found');
}
$category = $categories[0];
//check the number of category given by the user
if(count($params['category_id']) > 1)
{
$order_new = $params['category_id'];
$order_new_by_id = $order_new;
sort($order_new_by_id, SORT_NUMERIC);
$query = '
SELECT id
FROM '.CATEGORIES_TABLE.'
WHERE id_uppercat '.(empty($category['id_uppercat']) ? "IS NULL" : "= ".$category['id_uppercat']).'
ORDER BY `id` ASC
;';
$cat_asc = query2array($query, null, 'id');
if(strcmp(implode(',',$cat_asc), implode(',',$order_new_by_id)) !==0)
{
return new PwgError(WS_ERR_INVALID_PARAM, 'you need to provide all sub-category ids for a given category');
}
}
else
{
$params['category_id'] = implode($params['category_id']);
$query = '
SELECT id
FROM '.CATEGORIES_TABLE.'
WHERE id_uppercat '.(empty($category['id_uppercat']) ? "IS NULL" : "= ".$category['id_uppercat']).'
AND id != '.$params['category_id'].'
ORDER BY `rank` ASC
;';
$order_old = query2array($query, null, 'id');
$order_new = array();
$was_inserted = false;
$i = 1;
foreach ($order_old as $category_id)
{
if($i == $params['rank'])
{
$order_new[] = $params['category_id'];
$was_inserted = true;
}
$order_new[] = $category_id;
++$i;
}
if (!$was_inserted)
{
$order_new[] = $params['category_id'];
}
}
// include function to set the global rank
include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
save_categories_order($order_new);
}
/**
* API method
* Sets details of a category
* @param mixed[] $params
* @option int cat_id
* @option string name (optional)
* @option string status (optional)
* @option bool visible (optional)
* @option string comment (optional)
* @option bool commentable (optional)
* @option bool apply_commentable_to_subalbums (optional)
*/
function ws_categories_setInfo($params, &$service)
{
global $conf;
if (isset($params['pwg_token']) and get_pwg_token() != $params['pwg_token'])
{
return new PwgError(403, 'Invalid security token');
}
// does the category really exist?
$query = '
SELECT *
FROM '.CATEGORIES_TABLE.'
WHERE id = '.$params['category_id'].'
;';
$categories = query2array($query);
if (count($categories) == 0)
{
return new PwgError(404, 'category_id not found');
}
$category = $categories[0];
if (!empty($params['status']))
{
if (!in_array($params['status'], array('private','public')))
{
return new PwgError(WS_ERR_INVALID_PARAM, "Invalid status, only public/private");
}
if ($params['status'] != $category['status'])
{
include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
set_cat_status(array($params['category_id']), $params['status']);
}
}
$update = array(
'id' => $params['category_id'],
);
foreach (array('visible', 'commentable') as $param_name)
{
if (isset($params[$param_name]) and !preg_match('/^(true|false)$/i', $params[$param_name]))
{
return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid param '.$param_name.' : '.$params[$param_name]);
}
}
if (!empty($params['visible']) and ($params['visible'] != $category['visible']))
{
include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
set_cat_visible(array($params['category_id']), $params['visible']);
}
$info_columns = array('name', 'comment','commentable');
$perform_update = false;
foreach ($info_columns as $key)
{
if (isset($params[$key]))
{
$perform_update = true;
$update[$key] = (!$conf['allow_html_descriptions'] or !isset($params['pwg_token'])) ? strip_tags($params[$key]) : $params[$key];
}
}
if (isset($params['commentable']) && isset($params['apply_commentable_to_subalbums']) && $params['apply_commentable_to_subalbums'])
{
$subcats = get_subcat_ids(array($params['category_id']));
if (count($subcats) > 0)
{
$query = '
UPDATE '.CATEGORIES_TABLE.'
SET commentable = \''.$params['commentable'].'\'
WHERE id IN ('.implode(',', $subcats).')
;';
pwg_query($query);
}
}
if ($perform_update)
{
single_update(
CATEGORIES_TABLE,
$update,
array('id' => $update['id'])
);
}
pwg_activity('album', $params['category_id'], 'edit', array('fields' => implode(',', array_keys($update))));
}
/**
* API method
* Sets representative image of a category
* @param mixed[] $params
* @option int category_id
* @option int image_id
*/
function ws_categories_setRepresentative($params, &$service)
{
// does the category really exist?
$query = '
SELECT COUNT(*)
FROM '. CATEGORIES_TABLE .'
WHERE id = '. $params['category_id'] .'
;';
list($count) = pwg_db_fetch_row(pwg_query($query));
if ($count == 0)
{
return new PwgError(404, 'category_id not found');
}
// does the image really exist?
$query = '
SELECT COUNT(*)
FROM '. IMAGES_TABLE .'
WHERE id = '. $params['image_id'] .'
;';
list($count) = pwg_db_fetch_row(pwg_query($query));
if ($count == 0)
{
return new PwgError(404, 'image_id not found');
}
// apply change
$query = '
UPDATE '. CATEGORIES_TABLE .'
SET representative_picture_id = '. $params['image_id'] .'
WHERE id = '. $params['category_id'] .'
;';
pwg_query($query);
$query = '
UPDATE '. USER_CACHE_CATEGORIES_TABLE .'
SET user_representative_picture_id = NULL
WHERE cat_id = '. $params['category_id'] .'
;';
pwg_query($query);
pwg_activity('album', $params['category_id'], 'edit', array('image_id'=>$params['image_id']));
}
/**
* API method
*
* Deletes the album thumbnail. Only possible if
* $conf['allow_random_representative'] or if the album has no direct photos.
*
* @param mixed[] $params
* @option int category_id
*/
function ws_categories_deleteRepresentative($params, &$service)
{
global $conf;
// does the category really exist?
$query = '
SELECT id
FROM '. CATEGORIES_TABLE .'
WHERE id = '. $params['category_id'] .'
;';
$result = pwg_query($query);
if (pwg_db_num_rows($result) == 0)
{
return new PwgError(404, 'category_id not found');
}
$query = '
SELECT COUNT(*)
FROM '.IMAGE_CATEGORY_TABLE.'
WHERE category_id = '.$params['category_id'].'
;';
list($nb_images) = pwg_db_fetch_row(pwg_query($query));
if (!$conf['allow_random_representative'] and $nb_images != 0)
{
return new PwgError(401, 'not permitted');
}
$query = '
UPDATE '.CATEGORIES_TABLE.'
SET representative_picture_id = NULL
WHERE id = '.$params['category_id'].'
;';
pwg_query($query);
pwg_activity('album', $params['category_id'], 'edit');
}
/**
* API method
*
* Find a new album thumbnail.
*
* @param mixed[] $params
* @option int category_id
*/
function ws_categories_refreshRepresentative($params, &$service)
{
global $conf;
// does the category really exist?
$query = '
SELECT id
FROM '. CATEGORIES_TABLE .'
WHERE id = '. $params['category_id'] .'
;';
$result = pwg_query($query);
if (pwg_db_num_rows($result) == 0)
{
return new PwgError(404, 'category_id not found');
}
$query = '
SELECT
DISTINCT category_id
FROM '.IMAGE_CATEGORY_TABLE.'
WHERE category_id = '.$params['category_id'].'
LIMIT 1
;';
$result = pwg_query($query);
$has_images = pwg_db_num_rows($result) > 0 ? true : false;
if (!$has_images)
{
return new PwgError(401, 'not permitted');
}
include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
set_random_representant(array($params['category_id']));
pwg_activity('album', $params['category_id'], 'edit');
// return url of the new representative
$query = '
SELECT *
FROM '.CATEGORIES_TABLE.'
WHERE id = '.$params['category_id'].'
;';
$category = pwg_db_fetch_assoc(pwg_query($query));
return get_category_representant_properties($category['representative_picture_id'], IMG_SMALL);
}
/**
* API method
* Deletes a category
* @param mixed[] $params
* @option string|int[] category_id
* @option string photo_deletion_mode
* @option string pwg_token
*/
function ws_categories_delete($params, &$service)
{
if (get_pwg_token() != $params['pwg_token'])
{
return new PwgError(403, 'Invalid security token');
}
$modes = array('no_delete', 'delete_orphans', 'force_delete');
if (!in_array($params['photo_deletion_mode'], $modes))
{
return new PwgError(500,
'[ws_categories_delete]'
.' invalid parameter photo_deletion_mode "'.$params['photo_deletion_mode'].'"'
.', possible values are {'.implode(', ', $modes).'}.'
);
}
if (!is_array($params['category_id']))
{
$params['category_id'] = preg_split(
'/[\s,;\|]/',
$params['category_id'],
-1,
PREG_SPLIT_NO_EMPTY
);
}
$params['category_id'] = array_map('intval', $params['category_id']);
$category_ids = array();
foreach ($params['category_id'] as $category_id)
{
if ($category_id > 0)
{
$category_ids[] = $category_id;
}
}
if (count($category_ids) == 0)
{
return;
}
$query = '
SELECT id
FROM '. CATEGORIES_TABLE .'
WHERE id IN ('. implode(',', $category_ids) .')
;';
$category_ids = array_from_query($query, 'id');
if (count($category_ids) == 0)
{
return;
}
include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
delete_categories($category_ids, $params['photo_deletion_mode']);
update_global_rank();
invalidate_user_cache();
}
/**
* API method
* Moves a category
* @param mixed[] $params
* @option string|int[] category_id
* @option int parent
* @option string pwg_token
*/
function ws_categories_move($params, &$service)
{
global $page;
if (get_pwg_token() != $params['pwg_token'])
{
return new PwgError(403, 'Invalid security token');
}
if (!is_array($params['category_id']))
{
$params['category_id'] = preg_split(
'/[\s,;\|]/',
$params['category_id'],
-1,
PREG_SPLIT_NO_EMPTY
);
}
$params['category_id'] = array_map('intval', $params['category_id']);
$category_ids = array();
foreach ($params['category_id'] as $category_id)
{
if ($category_id > 0)
{
$category_ids[] = $category_id;
}
}
if (count($category_ids) == 0)
{
return new PwgError(403, 'Invalid category_id input parameter, no category to move');
}
// we can't move physical categories
$categories_in_db = array();
$update_cat_ids = array();
$query = '
SELECT id, name, dir, uppercats
FROM '. CATEGORIES_TABLE .'
WHERE id IN ('. implode(',', $category_ids) .')
;';
$result = pwg_query($query);
while ($row = pwg_db_fetch_assoc($result))
{
$categories_in_db[ $row['id'] ] = $row;
$update_cat_ids = array_merge($update_cat_ids, array_slice(explode(',', $row['uppercats']), 0, -1));
// we break on error at first physical category detected
if (!empty($row['dir']))
{
$row['name'] = strip_tags(
trigger_change(
'render_category_name',
$row['name'],
'ws_categories_move'
)
);
return new PwgError(403,
sprintf(
'Category %s (%u) is not a virtual category, you cannot move it',
$row['name'],
$row['id']
)
);
}
}
if (count($categories_in_db) != count($category_ids))
{
$unknown_category_ids = array_diff($category_ids, array_keys($categories_in_db));
return new PwgError(403,
sprintf(
'Category %u does not exist',
$unknown_category_ids[0]
)
);
}
// does this parent exists? This check should be made in the
// move_categories function, not here
// 0 as parent means "move categories at gallery root"
if (0 != $params['parent'])
{
$subcat_ids = get_subcat_ids(array($params['parent']));
if (count($subcat_ids) == 0)
{
return new PwgError(403, 'Unknown parent category id');
}
}
$page['infos'] = array();
$page['errors'] = array();
include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
move_categories($category_ids, $params['parent']);
invalidate_user_cache();
if (count($page['errors']) != 0)
{
return new PwgError(403, implode('; ', $page['errors']));
}
$query = '
SELECT uppercats
FROM '. CATEGORIES_TABLE .'
WHERE id IN ('. implode(',', $category_ids) .')
;';
$result = pwg_query($query);
while ($row = pwg_db_fetch_assoc($result))
{
$cat_display_name = get_cat_display_name_cache(
$row['uppercats'],
'admin.php?page=album-'
);
$update_cat_ids = array_merge($update_cat_ids, array_slice(explode(',', $row['uppercats']), 0, -1));
}
$query = '
SELECT
category_id,
COUNT(*) AS nb_photos
FROM '.IMAGE_CATEGORY_TABLE.'
GROUP BY category_id
;';
$nb_photos_in = query2array($query, 'category_id', 'nb_photos');
$update_cats = [];
foreach (array_unique($update_cat_ids) as $update_cat)
{
$nb_sub_photos = 0;
$sub_cat_without_parent = array_diff(get_subcat_ids(array($update_cat)), array($update_cat));
foreach ($sub_cat_without_parent as $id_sub_cat)
{
$nb_sub_photos += isset($nb_photos_in[$id_sub_cat]) ? $nb_photos_in[$id_sub_cat] : 0;
}
$update_cats[] = array(
'cat_id' => $update_cat,
'nb_sub_photos' => $nb_sub_photos,
);
}
return array(
'new_ariane_string' => $cat_display_name,
'updated_cats' => $update_cats,
);
}
/**
* API method
* Return the number of orphan photos if an album is deleted
* @since 12
*/
function ws_categories_calculateOrphans($param, &$service)
{
global $conf;
$category_id = $param['category_id'][0];
$query = '
SELECT DISTINCT
category_id
FROM
'.IMAGE_CATEGORY_TABLE.'
WHERE
category_id = '.$category_id.'
LIMIT 1';
$result = pwg_query($query);
$category['has_images'] = pwg_db_num_rows($result)>0 ? true : false;
// number of sub-categories
$subcat_ids = get_subcat_ids(array($category_id));
$category['nb_subcats'] = count($subcat_ids) - 1;
// total number of images under this category (including sub-categories)
$query = '
SELECT DISTINCT
(image_id)
FROM
'.IMAGE_CATEGORY_TABLE.'
WHERE
category_id IN ('.implode(',', $subcat_ids).')
;';
$image_ids_recursive = query2array($query, null, 'image_id');
$category['nb_images_recursive'] = count($image_ids_recursive);
// number of images that would become orphan on album deletion
$category['nb_images_becoming_orphan'] = 0;
$category['nb_images_associated_outside'] = 0;
if ($category['nb_images_recursive'] > 0)
{
// if we don't have "too many" photos, it's faster to compute the orphans with MySQL
if ($category['nb_images_recursive'] < 1000)
{
$query = '
SELECT DISTINCT
(image_id)
FROM
'.IMAGE_CATEGORY_TABLE.'
WHERE
category_id
NOT IN
('.implode(',', $subcat_ids).')
AND
image_id
IN
('.implode(',', $image_ids_recursive).')
;';
$image_ids_associated_outside = query2array($query, null, 'image_id');
$category['nb_images_associated_outside'] = count($image_ids_associated_outside);
$image_ids_becoming_orphan = array_diff($image_ids_recursive, $image_ids_associated_outside);
$category['nb_images_becoming_orphan'] = count($image_ids_becoming_orphan);
}
// else it's better to avoid sending a huge SQL request, we compute the orphan list with PHP
else
{
$image_ids_recursive_keys = array_flip($image_ids_recursive);
$query = '
SELECT
image_id
FROM
'.IMAGE_CATEGORY_TABLE.'
WHERE
category_id
NOT IN
('.implode(',', $subcat_ids).')
;';
$image_ids_associated_outside = query2array($query, null, 'image_id');
$image_ids_not_orphan = array();
foreach ($image_ids_associated_outside as $image_id)
{
if (isset($image_ids_recursive_keys[$image_id]))
{
$image_ids_not_orphan[] = $image_id;
}
}
$category['nb_images_associated_outside'] = count(array_unique($image_ids_not_orphan));
$image_ids_becoming_orphan = array_diff($image_ids_recursive, $image_ids_not_orphan);
$category['nb_images_becoming_orphan'] = count($image_ids_becoming_orphan);
}
}
$output[] = array(
'nb_images_associated_outside' => $category['nb_images_associated_outside'],
'nb_images_becoming_orphan' => $category['nb_images_becoming_orphan'],
'nb_images_recursive' => $category['nb_images_recursive'],
);
return $output;
}
?>