<?php
declare(strict_types = 1);

/**
 * Gestion des requêtes Ajax pour la galerie.
 *
 * @license https://www.gnu.org/licenses/gpl-3.0.html
 * @link https://www.igalerie.org/
 */
class AjaxGallery extends Ajax
{
	/**
	 * Vérification du mot de passe de catégorie.
	 *
	 * @return void
	 */
	public static function checkCatPassword(): void
	{
		require_once(__DIR__ . '/GalleryCategory.class.php');

		$password = $_POST['password'] ?? '';
		$password = (string) (is_array($password) ? '' : $password);

		$cat_id = $_POST['cat_id'] ?? 0;
		$cat_id = (int) (is_array($cat_id) ? 0 : $cat_id);

		$r = GalleryCategory::checkPassword('category',
			$cat_id, $password, !empty($_POST['remember']));

		if ($r == 'db_error')
		{
			self::_error();
		}
		if ($r == 'not_found')
		{
			self::_forbidden();
		}
		if ($r == 'brute_force')
		{
			self::_printResponse(
			[
				'status' => 'error',
				'message' => __('Attaque par force brute détectée.')
			]);
		}
		if (substr($r, 0, 9) == 'redirect:')
		{
			self::_printResponse(
			[
				'status' => 'success',
				'url' => App::getURL(substr($r, 9))
			]);
		}

		self::_printResponse(
		[
			'status' => 'error',
			'message' => __('Mot de passe incorrect.')
		]);
	}

	/**
	 * Enregistrements de données dans le cookie des préférences.
	 *
	 * @return void
	 */
	public static function cookiePrefsWrite(): void
	{
		if (!Utility::checkPost('param', '`^[-a-z0-9_]{1,40}$`')
		 || !Utility::checkPost('value', '`^[-a-z0-9_,\.]{1,160}$`i'))
		{
			self::_forbidden();
		}

		Auth::$prefs->add($_POST['param'], $_POST['value']);
	}

	/**
	 * Supprime un commentaire.
	 *
	 * @return void
	 */
	public static function deleteComment(): void
	{
		// Permissions d'accès au commentaire.
		$com_id = self::_commentPermission();

		// Suppression du commentaire.
		$r = Comment::delete([$com_id]);

		// Message de rapport.
		if ($r == -1)
		{
			self::_error();
		}
		else if ($r > 0)
		{
			// Log d'activité.
			App::logActivity('comment_delete', '', ['com_id' => $com_id]);

			self::_printResponse(
			[
				'status' => 'success',
				'message' => __('Le commentaire a été supprimé.')
			]);
		}
	}

	/**
	 * Supprime un fichier.
	 *
	 * @return void
	 */
	public static function deleteItem(): void
	{
		// Identifiant.
		if (!Utility::checkPost('item_id', '`^\d{1,12}$`'))
		{
			self::_forbidden();
		}
		$id = (int) $_POST['item_id'];

		// Permissions d'accès au fichier.
		$item_infos = self::_itemPermission($id);

		// Permissions de suppression du fichier.
		if ((Auth::$isAdmin || (Config::$params['users']
		&& $item_infos['user_id'] == Auth::$id)) === FALSE)
		{
			self::_forbidden();
		}

		$r = Item::delete([$id]);

		// Message de rapport.
		if ($r == -1)
		{
			self::_error();
		}
		else if ($r > 0)
		{
			// Log d'activité.
			App::logActivity('item_delete', '', ['item_id' => $_POST['item_id']]);

			self::_printResponse(
			[
				'status' => 'success',
				'message' => __('Le fichier a été supprimé.'),
				'redirect' => CONF_GALLERY_PATH . '/'
			]);
		}
	}

	/**
	 * Édition des informations d'une catégorie : titre et description.
	 *
	 * @return void
	 */
	public static function editCategory(): void
	{
		// Identifiant.
		if (!Utility::checkPost('cat_id', '`^\d{1,12}$`'))
		{
			self::_forbidden();
		}
		$id = (int) $_POST['cat_id'];

		// Titre et description de la galerie.
		if ($id == 1)
		{
			if (!Auth::$isAdmin
			 || mb_strlen($_POST['title'] ?? '') > 255
			 || mb_strlen($_POST['description'] ?? '') > 65535)
			{
				self::_forbidden();
			}

			$db_params =
			[
				'gallery_title' => (string) ($_POST['title']
					?? Config::$params['gallery_title']),
				'gallery_description' => (string) ($_POST['description']
					?? Config::$params['gallery_description'])
			];
			$r = Config::changeDBParams($db_params);

			if ($r == -1)
			{
				self::_error();
			}

			$params = [];
			$params['title'] = $db_params['gallery_title'];
			$params['description_formated'] = $params['description'] = NULL;
			if (!Utility::isEmpty($db_params['gallery_description']))
			{
				$params['description'] = $db_params['gallery_description'];

				$desc = HTML::specialchars($db_params['gallery_description']);
				$params['description_formated'] = Template::formatText($desc);
			}

			if ($r > 0)
			{
				$params['status'] = 'success';
				$params['message'] = Report::getSuccessDefaultMessage();
			}
			else
			{
				$params['status'] = 'info';
				$params['message'] = Report::getNoChangeDefaultMessage();
			}

			self::_printResponse($params);
		}

		// Permissions d'accès à la catégorie.
		$cat_infos = self::_catPermission($id);

		// Permissions de modification de la catégorie.
		if ($cat_infos['cat_id'] > 1 && (Auth::$isAdmin || (Config::$params['users']
		&& Auth::$id != 2 && $cat_infos['user_id'] == Auth::$id)) === FALSE)
		{
			self::_forbidden();
		}

		// Préparation des données.
		$data = [];
		if (isset($_POST['title']))
		{
			$data['cat_name'] = $data['cat_url'] = $_POST['title'];
		}
		if (isset($_POST['description']))
		{
			$data['cat_desc'] = $_POST['description'];
		}
		if (!$data)
		{
			self::_forbidden();
		}

		// Mise à jour de la base de données.
		$data = [$id => $data];
		$r = Category::edit($data);

		// Erreur.
		if ($r == -1)
		{
			self::_error();
		}

		// Récupération des informations en base de données.
		if (!DB::execute('SELECT * FROM {categories} WHERE cat_id = ?', $id))
		{
			self::_error();
		}
		$i = DB::fetchRow();

		// Formatage des données.
		$params = [];
		if (isset($_POST['title']))
		{
			$params['title'] = $i['cat_name'];
			$params['page_title'] = $params['title'] . ' - ' . Config::$params['gallery_title'];
			$params['urlname'] = $i['cat_url'];
		}
		if (isset($_POST['description']))
		{
			$params['description'] = $i['cat_desc'];

			$params['description_formated'] = NULL;
			if (Config::$params['categories_description_model'])
			{
				$params['description_formated'] = Description::model('cat', $i);
			}
			else if ($i['cat_desc'] !== NULL)
			{
				HTML::specialchars($i['cat_desc']);
				$params['description_formated'] = Template::formatText($i['cat_desc']);
			}
		}

		// Modification réussie.
		if ($r > 0)
		{
			// Log d'activité.
			App::logActivity('cat_edit', '', ['cat_id' => $_POST['cat_id']]);

			$params['status'] = 'success';
			$params['message'] = Report::getSuccessDefaultMessage();
		}

		// Aucun changement.
		else
		{
			$params['status'] = 'info';
			$params['message'] = Report::getNoChangeDefaultMessage();
		}

		self::_printResponse($params);
	}

	/**
	 * Édition d'un commentaire.
	 *
	 * @return void
	 */
	public static function editComment(): void
	{
		if (!isset($_POST['com_message']))
		{
			self::_forbidden();
		}

		// Permissions d'accès au commentaire.
		$com_id = self::_commentPermission();

		// Vérification du message : format.
		if (($r = Comment::checkMessage($_POST['com_message'], FALSE)) !== NULL)
		{
			self::_printResponse(
			[
				'status' => 'error',
				'message' => $r['message']
			]);
		}

		// Vérification du message : listes noires.
		if (is_array($r = App::blacklists('', '', '', $_POST['com_message'])))
		{
			self::_printResponse(
			[
				'status' => 'error',
				'message' => $r['text']
			]);
		}

		// Vérification du message : suppression des émojis ?
		if (Config::$params['comments_emoji_delete'])
		{
			$_POST['com_message'] = preg_replace(
				'`' . Emoji::REGEXP . '`u', '', $_POST['com_message']
			);
		}

		// Vérification du message : message vide ?
		if (Utility::isEmpty($_POST['com_message']))
		{
			self::_printResponse(
			[
				'status' => 'info',
				'message' => __('Le message que vous avez envoyé est vide.')
			]);
		}

		// Champs éditables.
		$fields = ['com_author', 'com_email', 'com_message', 'com_website'];

		// Préparation des données.
		$data = [];
		foreach ($fields as $f)
		{
			if (isset($_POST[$f]))
			{
				$data[substr($f, 4)] = $_POST[$f];
			}
		}
		if (!$data)
		{
			self::_forbidden();
		}

		// Mise à jour de la base de données.
		$data = [$com_id => $data];
		$r = Comment::edit($data);

		// Erreur.
		if ($r == -1)
		{
			self::_error();
		}

		// Récupération des informations en base de données.
		if (!DB::execute('SELECT * FROM {comments} WHERE com_id = ?', $com_id))
		{
			self::_error();
		}
		$i = DB::fetchRow();

		// Formatage des données.
		$params = [];
		foreach ($fields as $f)
		{
			if (isset($_POST[$f]))
			{
				$params[$f] = $i[$f];
				if ($f == 'com_message')
				{
					HTML::specialchars($i[$f]);
					$params['com_message_formated'] = Template::formatComment($i[$f]);
				}
			}
		}

		// Modification réussie.
		if ($r > 0)
		{
			// Log d'activité.
			App::logActivity('comment_edit', '', ['com_id' => $com_id]);

			$params['status'] = 'success';
			$params['message'] = Report::getSuccessDefaultMessage();
		}

		// Aucun changement.
		else
		{
			$params['status'] = 'info';
			$params['message'] = Report::getNoChangeDefaultMessage();
		}

		self::_printResponse($params);
	}

	/**
	 * Édition des informations d'un fichier : titre, nom de fichier, description et tags.
	 *
	 * @return void
	 */
	public static function editItem(): void
	{
		// Identifiant.
		if (!Utility::checkPost('item_id', '`^\d{1,12}$`'))
		{
			self::_forbidden();
		}
		$id = (int) $_POST['item_id'];

		// Permissions d'accès au fichier.
		$item_infos = self::_itemPermission($id);

		// Permissions de modification du fichier.
		if ((Auth::$isAdmin || (Config::$params['users']
		&& Auth::$id != 2 && $item_infos['user_id'] == Auth::$id)) === FALSE)
		{
			self::_forbidden();
		}

		// Préparation des données.
		$data = [];
		if (isset($_POST['title']))
		{
			$data['item_name'] = $data['item_url'] = $_POST['title'];
		}
		if (isset($_POST['filename']))
		{
			$data['item_path'] = $_POST['filename'];
		}
		if (isset($_POST['description']))
		{
			$data['item_desc'] = $_POST['description'];
		}
		if (Config::$params['tags'] && isset($_POST['tags']))
		{
			$data['tags'] = $_POST['tags'];
		}
		if (!$data)
		{
			self::_forbidden();
		}

		// Mise à jour de la base de données.
		$data = [$id => $data];
		$r = Item::edit($data);

		// Erreur.
		if ($r == -1)
		{
			self::_error();
		}

		// Récupération des informations en base de données.
		if (!DB::execute('SELECT * FROM {items} WHERE item_id = ?', $id))
		{
			self::_error();
		}
		$i = DB::fetchRow();

		// Formatage des données.
		$params = [];
		if (isset($_POST['title']))
		{
			$params['title'] = $i['item_name'];
			$params['page_title'] = $i['item_name'] . ' - ' . Config::$params['gallery_title'];
			$params['urlname'] = $i['item_url'];
		}
		if (isset($_POST['filename']))
		{
			$params['download'] = App::getFileSource($i['item_path'], TRUE);
			$params['filename'] = basename($i['item_path']);
			$params['is_video'] = Item::isVideo($i['item_type']);
			$params['source'] = App::getImageResize($i);
		}
		if (Config::$params['tags'] && isset($_POST['tags']))
		{
			require_once(__DIR__ . '/GalleryItems.class.php');
			$tags = GalleryItems::getTags((int) $i['item_id']);
			$tags_list = [];
			foreach ($tags as &$tag)
			{
				$tags_list[] = $tag['name'];
			}
			$params['tags_list'] = $tags_list;
			$params['tags'] = $tags;
		}
		if (isset($_POST['description']))
		{
			$params['description'] = $i['item_desc'];
			$params['description_formated'] = NULL;
			if (Config::$params['items_description_model'])
			{
				$params['description_formated'] = Description::model('item', $i);
			}
			else if ($i['item_desc'] !== NULL)
			{
				HTML::specialchars($i['item_desc']);
				$params['description_formated'] = Template::formatText($i['item_desc']);
			}
		}

		// Modification réussie.
		if ($r > 0)
		{
			// Log d'activité.
			App::logActivity('item_edit', '', ['item_id' => $_POST['item_id']]);

			$params['status'] = 'success';
			$params['message'] = Report::getSuccessDefaultMessage();
		}

		// Aucun changement.
		else
		{
			$params['status'] = 'info';
			$params['message'] = Report::getNoChangeDefaultMessage();
		}

		self::_printResponse($params);
	}

	/**
	 * Ajoute ou retire un fichier des favoris d'un utilisateur.
	 *
	 * @param string $action
	 *   Action à effectuer : 'add' ou 'remove'.
	 *
	 * @return void
	 */
	public static function favorites(string $action): void
	{
		// Quelques vérifications.
		if (!Config::$params['users'] || !Config::$params['favorites']
		|| !Utility::checkPost('item_id', '`^\d{1,12}$`'))
		{
			self::_forbidden();
		}

		// Permissions d'accès au fichier.
		self::_itemPermission((int) $_POST['item_id']);

		// On modifie les favoris.
		$r = Item::favorites([$_POST['item_id']], $action, Auth::$id);
		if ($r == 0)
		{
			self::_forbidden();
		}
		if ($r == -1)
		{
			self::_error();
		}

		// Log d'activité.
		App::logActivity('favorites_' . $action, '', ['item_id' => $_POST['item_id']]);

		// Récupération du nombre de favoris du fichier.
		$item_favorites = 0;
		$sql = 'SELECT item_id, item_url, item_favorites FROM {items} WHERE item_id = ?';
		if (DB::execute($sql, $_POST['item_id']) && $i = DB::fetchRow())
		{
			$item_favorites = (int) $i['item_favorites'];
		}

		self::_printResponse([
			'favorites' => $item_favorites,
			'favorites_short' => L10N::formatShortNumber($item_favorites),
			'status' => 'success'
		]);
	}

	/**
	 * Retire plusieurs fichiers des favoris d'un utilisateur.
	 *
	 * @return void
	 */
	public static function favoritesRemoveAll(): void
	{
		// Quelques vérifications.
		if (!Config::$params['users'] || !Config::$params['favorites']
		|| !Utility::checkPost('cat_id', '`^\d{1,12}$`'))
		{
			self::_forbidden();
		}

		$cat_id = (int) $_POST['cat_id'];

		// Permissions d'accès à la catégorie.
		self::_catPermission($cat_id);

		// Récupération du chemin de la catégorie.
		$cat_path = '%';
		if ($cat_id > 1)
		{
			$sql = 'SELECT cat_path FROM {categories} WHERE cat_id = ?';
			if (!DB::execute($sql, $cat_id))
			{
				self::_error();
			}
			$cat_path = DB::likeEscape((string) DB::fetchVal()) . '/%';
		}

		// Récupération des fichiers de la catégorie
		// présent dans les favoris de l'utilsateur.
		$items_id = [];
		$sql = 'SELECT i.item_id
				  FROM {items} AS i,
					   {favorites} AS fav,
					   {categories} AS cat
				 WHERE cat_status = "1"
				   AND item_status = "1"
				   AND i.item_id = fav.item_id
				   AND i.cat_id = cat.cat_id
				   AND fav.user_id = :user_id
				   AND item_path LIKE :cat_path
				   AND ' . SQL::catPerms() . '
				   AND ' . SQL::catPassword();
		DB::params(['user_id' => Auth::$id, 'cat_path' => $cat_path]);
		if (!DB::execute($sql))
		{
			self::_error();
		}
		if (!$items_id = DB::fetchCol('item_id'))
		{
			self::_forbidden();
		}

		// On modifie les favoris.
		$r = Item::favorites($items_id, 'remove', Auth::$id);
		if ($r == 0)
		{
			self::_forbidden();
		}
		if ($r == -1)
		{
			self::_error();
		}

		// Log d'activité.
		App::logActivity('favorites_remove', '', ['cat_id' => $_POST['cat_id']]);

		self::_printResponse(
		[
			'status' => 'success',
			'message' => __('Vos favoris ont été supprimés.'),
			'redirect' => App::getURL()
		]);
	}

	/**
	 * Liste des albums.
	 *
	 * @return void
	 */
	public static function getAlbumsList()
	{
		if (!Config::$params['browse'] || !Config::$params['browse_ajax'] || !isset($_POST['q']))
		{
			self::_forbidden();
		}

		require_once(__DIR__ . '/Gallery.class.php');

		$_GET['q'] = $_POST['q'] ?? '';
		Gallery::request();
		App::filtersGET();
		if (Config::$params['search'] && isset($_GET['search']))
		{
			Gallery::$search = new Search();
			Gallery::$search->sql($_GET['search']);
		}

		$cat_id = in_array($_GET['section'], ['album', 'category']) ? $_GET['category_id'] : 0;
		if ($_GET['section'] == 'item')
		{
			if (DB::execute('SELECT cat_id FROM {items} WHERE item_id = ?', $_GET['item_id']))
			{
				$cat_id = DB::fetchVal();
			}
		}

		if (!$browse = Gallery::makeCategoriesList((int) $cat_id))
		{
			self::_forbidden();
		}

		self::_printResponse(['status' => 'success', 'browse' => $browse]);
	}

	/**
	 * Retourne les informations d'une vignette d'image ou de vidéo choisie au hasard.
	 *
	 * @return void
	 */
	public static function getRandomItem(): void
	{
		if (!Config::$params['random_item'] || !isset($_POST['item_size'])
		|| !preg_match('`^\d{2,3}(x\d{2,3})?$`', $_POST['item_size'])
		)
		{
			self::_forbidden();
		}

		require_once(__DIR__ . '/Gallery.class.php');

		if (!$r = Gallery::randomItem($i))
		{
			self::_error();
		}

		$stats = ['comments' => 0, 'favorites' => 0, 'views' => 0, 'votes' => 0];
		foreach ($stats as $stat => &$value)
		{
			$value = Config::$params['thumbs_item_info_' . $stat]
				? $r['stats'][$stat]['short'] ?? 0
				: 0;
		}

		self::_printResponse(
		[
			'status' => 'success',
			'item' =>
			[
				'duration_text' => $r['duration_text'],
				'id' => $r['id'],
				'is_recent' => $r['is_recent'],
				'in_selection' => $r['in_selection'],
				'is_video' => $r['is_video'],
				'link_item' => $r['link_item'],
				'stats' => $stats,
				'title' => $r['title'],
				'thumb_src' => App::getThumbSource('item', $i, $_POST['item_size'], '', FALSE)
			],
			'l10n' =>
			[
				'new' => __('Nouveau')
			]
		]);
	}

	/**
	 * Connexion utilisateur.
	 *
	 * @return void
	 */
	public static function login(): void
	{
		$cause = '';
		if (Auth::form((string) $_POST['login'], (string) $_POST['password'],
		!empty($_POST['remember']), $cause))
		{
			self::_printResponse(
			[
				'status' => 'success'
			]);
		}
		else
		{
			self::_printResponse(
			[
				'status' => 'error',
				'message' => L10N::getTextLoginRejected($cause)
			]);
		}
	}

	/**
	 * Suggestions de recherche.
	 *
	 * @return void
	 */
	public static function searchSuggestion(): void
	{
		if (!Config::$params['search'] || !Config::$params['search_suggestion'])
		{
			self::_forbidden();
		}

		self::_printResponse(
		[
			'status' => 'success',
			'suggestion' => array_keys(
				Search::suggestion((string) $_POST['search'] ?? '')
			)
		]);
	}

	/**
	 * Mode sélection.
	 *
	 * @return void
	 */
	public static function selection(): void
	{
		if (!Selection::isActivated())
		{
			self::_forbidden();
		}
		switch ($_POST['action'] ?? '')
		{
			// Gestion de la sélection.
			case 'selection-add' :
			case 'selection-remove' :
			case 'selection-delete' :
				$response = function($r)
				{
					if ($r < 0)
					{
						self::_error();
					}
					else
					{
						self::_printResponse(
						[
							'status' => 'success',
							'stats' => Selection::getStats()
						]);
					}
				};
				if ($_POST['action'] == 'selection-delete')
				{
					$response(Selection::delete());
					break;
				}
				$items_id = [];
				if (isset($_POST['id']) && is_array($_POST['id']) && count($_POST['id']) <= 1000)
				{
					$items_id = array_unique(array_map('intval', $_POST['id']));
				}
				if (!Auth::$connected)
				{
					$items_id = [$items_id[0]];
				}
				$response($_POST['action'] == 'selection-add'
					? Selection::add($items_id)
					: Selection::remove($items_id));
				break;

			// Suppression de fichiers.
			case 'delete' :
				if (!Auth::$isAdmin || !($items_id = Selection::getItems()))
				{
					break;
				}
				switch ($count = Item::delete($items_id))
				{
					case -1 :
						self::_error();
						break;

					case 0 :
						self::_printResponse(
						[
							'status' => 'info',
							'message' => __('Aucun fichier n\'a été supprimé.')
						]);
						break;

					default :
						self::_printResponse(
						[
							'status' => 'success',
							'message' => $count > 1
								? sprintf(__('%s fichiers ont été supprimés.'), $count)
								: __('1 fichier a été supprimé.'),
							'stats' => Selection::getStats()
						]);
						break;
				}
				break;

			// Téléchargement de la sélection.
			case 'download' :
				if ($items_id = Selection::getItems())
				{
					Item::download('selection.zip', $items_id);
				}
				break;

			// Favoris.
			case 'favorites-add' :
			case 'favorites-remove' :
				if (!Auth::$connected || (!$items_id = Selection::getItems()))
				{
					break;
				}
				$action = substr($_POST['action'], 10);
				$count = Item::favorites($items_id, $action, Auth::$id);
				if ($count > 0)
				{
					App::logActivity('favorites_' . $action, '', ['selection_count' => $count]);
				}
				switch ($count)
				{
					case -1 :
						self::_error();
						break;

					case 0 :
						self::_noChange();
						break;

					case 1 :
						$message = $action == 'add'
							? __('1 fichier a été ajouté à vos favoris')
							: __('1 fichier a été retiré de vos favoris');
						self::_printResponse(['status' => 'success', 'message' => $message]);
						break;

					default :
						$message = $action == 'add'
							? sprintf(__('%s fichiers ont été ajoutés à vos favoris'), $count)
							: sprintf(__('%s fichiers ont été retirés de vos favoris'), $count);
						self::_printResponse(['status' => 'success', 'message' => $message]);
				}
				break;

			// Déplacement de fichiers dans l'album courant.
			case 'move' :
				if (!Auth::$isAdmin || !Utility::checkPost('album_id', '`^\d{1,12}$`')
				|| !($items_id = Selection::getItems()))
				{
					break;
				}
				switch ($count = Item::move($items_id, (int) $_POST['album_id']))
				{
					case -1 :
						self::_error();
						break;

					case 0 :
						self::_printResponse(
						[
							'status' => 'info',
							'message' => __('Aucun fichier n\'a été déplacé.')
						]);
						break;

					default :
						self::_printResponse(
						[
							'status' => 'success',
							'message' => $count > 1
								? sprintf(__('%s fichiers ont été déplacés.'), $count)
								: __('1 fichier a été déplacé.')
						]);
						break;
				}
				break;

			// Ajout ou suppression de tags.
			case 'tags' :
				if (!Auth::$isAdmin || (!$items_id = Selection::getItems()))
				{
					break;
				}
				$count = 0;
				if (!empty($_POST['delete_all']))
				{
					if (($r = Tags::itemsDeleteAll($items_id)) < 0)
					{
						self::_error();
					}
					$count += $r;
				}
				foreach (['delete', 'add'] as $action)
				{
					if (!isset($_POST[$action]) && !is_string($_POST[$action]))
					{
						continue;
					}
					if (mb_strlen($tags_str = Tags::sanitize($_POST[$action])))
					{
						$tags = [];
						foreach (explode(',', $tags_str) as &$tag_name)
						{
							foreach ($items_id as &$item_id)
							{
								$tags[] = ['item_id' => $item_id, 'tag_name' => $tag_name];
							}
						}
						if (($r = Tags::{'items' . ucfirst($action)}($tags)) < 0)
						{
							self::_error();
						}
						$count += $r;
					}
				}
				if ($count)
				{
					self::_success();
				}
				else
				{
					self::_noChange();
				}
				break;
		}
	}

	/**
	 * Recharge une liste de fichiers pour le thème.
	 *
	 * @return void
	 */
	public static function themeFiles(): void
	{
		// Vérifications.
		if (!Auth::$isAdmin || !is_array($_POST['dir']) || empty($_POST['dir']))
		{
			self::_forbidden();
		}

		// Récupération des fichiers.
		$files = [];
		foreach ($_POST['dir'] as &$dir)
		{
			if (in_array($dir, ['background', 'banners']))
			{
				$files_dir = [];
				foreach (scandir(GALLERY_ROOT . '/images/' . $dir) as &$f)
				{
					if (preg_match('`^[a-z0-9_-]{1,250}\.(gif|jpe?g|png|webp)$`i', $f))
					{
						$files_dir[] = $f;
					}
				}
				$files[$dir] = $files_dir;
			}
		}

		self::_printResponse(
		[
			'status' => 'success',
			'files' => $files
		]);
	}

	/**
	 * Enregistrement des paramètres de thème.
	 *
	 * @return void
	 */
	public static function themeParams(): void
	{
		// Vérifications.
		if (!Auth::$isAdmin || !is_array($_POST['params'] ?? '')
		|| !Utility::checkPost('template', '`^[a-z0-9_]{1,50}$`i')
		|| $_POST['template'] != Config::$params['theme_template'])
		{
			self::_forbidden();
		}

		if (mb_strlen(Utility::jsonEncode($_POST['params'])) > 10000)
		{
			self::_printResponse(
			[
				'status' => 'error',
				'message' => 'Array too large.'
			]);
		}

		// Enregistrement.
		$params = is_array(Config::$params['theme_params'])
			? Config::$params['theme_params']
			: [];
		$params[$_POST['template']] = $_POST['params'];
		$r = Config::changeDBParams(['theme_params' => $params]);

		// Message de rapport.
		if ($r == -1)
		{
			self::_error();
		}
		else if ($r > 0)
		{
			self::_success();
		}
		else
		{
			self::_noChange();
		}
	}

	/**
	 * Récupération de l'URL de vignettes de catégories.
	 *
	 * @return void
	 */
	public static function thumbsCatSource(): void
	{
		// Vérifications.
		if (!Auth::$isAdmin || !is_array($_POST['cat_id'] ?? '')
		|| !Utility::checkPost('size', '`^\d{1,4}(x\d{1,4})?$`i'))
		{
			self::_forbidden();
		}

		$sql = 'SELECT cat.*,
					   i.item_id,
					   i.item_type,
					   i.item_path,
					   i.item_width,
					   i.item_height,
					   i.item_orientation,
					   i.item_adddt
				  FROM {categories} AS cat
			 LEFT JOIN {items} AS i
					ON cat.thumb_id = i.item_id
				 WHERE cat.cat_id IN (' . DB::inInt($_POST['cat_id']) . ')';
		if (!DB::execute($sql))
		{
			self::_error();
		}

		$thumbs_source = [];
		foreach (DB::fetchAll() as &$i)
		{
			$thumbs_source[$i['cat_id']] = App::getThumbSource('cat', $i, $_POST['size'], '');
		}

		self::_printResponse(
		[
			'status' => 'success',
			'thumbs_source' => $thumbs_source
		]);
	}

	/**
	 * Récupération de l'URL de vignettes de fichiers.
	 *
	 * @return void
	 */
	public static function thumbsItemsSource(): void
	{
		// Vérifications.
		if (!Auth::$isAdmin || !is_array($_POST['items_id'] ?? '')
		|| !Utility::checkPost('size', '`^\d{1,4}(x\d{1,4})?$`i'))
		{
			self::_forbidden();
		}

		$items_id = DB::inInt($_POST['items_id']);
		if (!DB::execute("SELECT * FROM {items} WHERE item_id IN ($items_id)"))
		{
			self::_error();
		}

		$thumbs_source = [];
		foreach (DB::fetchAll() as &$i)
		{
			$thumbs_source[$i['item_id']] = App::getThumbSource('item', $i, $_POST['size'], '');
		}

		self::_printResponse(
		[
			'status' => 'success',
			'thumbs_source' => $thumbs_source
		]);
	}



	/**
	 * Vérifie les permissions d'accès à une catégorie.
	 *
	 * @param int $cat_id
	 *
	 * @return array
	 */
	private static function _catPermission(int $cat_id): array
	{
		$sql = 'SELECT *
				  FROM {categories} AS cat
				 WHERE cat_id = :cat_id
				   AND cat_status = "1"
				   AND ' . SQL::catPerms() . '
				   AND ' . SQL::catPassword();
		DB::params(['cat_id' => $cat_id]);
		if (!DB::execute($sql))
		{
			self::_error();
		}
		if (!$infos = DB::fetchRow())
		{
			self::_forbidden();
		}

		return $infos;
	}

	/**
	 * Vérifie les permissions d'accès à un commentaire.
	 *
	 * @return int
	 */
	private static function _commentPermission(): int
	{
		// Identifiant.
		if (!Utility::checkPost('com_id', '`^\d{1,12}$`'))
		{
			self::_forbidden();
		}
		$com_id = (int) $_POST['com_id'];

		// Permission d'édition du commentaire.
		$sql = 'SELECT i.item_id,
					   com.user_id
				  FROM {comments} AS com
			 LEFT JOIN {items} AS i USING (item_id)
				 WHERE com_id = ?
				   AND com_status = "1"';
		if (!DB::execute($sql, $com_id))
		{
			self::_error();
		}
		if (!$com_infos = DB::fetchRow())
		{
			self::_forbidden();
		}
		if ((Auth::$isAdmin || (Config::$params['users']
		&& Auth::$id != 2 && $com_infos['user_id'] == Auth::$id)) === FALSE)
		{
			self::_forbidden();
		}

		// Permissions d'accès au fichier.
		self::_itemPermission((int) $com_infos['item_id']);

		return $com_id;
	}

	/**
	 * Vérifie les permissions d'accès à un fichier.
	 *
	 * @param int $item_id
	 *
	 * @return array
	 */
	private static function _itemPermission(int $item_id): array
	{
		$sql = 'SELECT i.*
				  FROM {items} AS i
			 LEFT JOIN {categories} AS cat USING (cat_id)
				 WHERE item_id = :item_id
				   AND item_status = "1"
				   AND ' . SQL::catPerms() . '
				   AND ' . SQL::catPassword();
		DB::params(['item_id' => $item_id]);
		if (!DB::execute($sql))
		{
			self::_error();
		}
		if (!$infos = DB::fetchRow())
		{
			self::_forbidden();
		}

		return $infos;
	}
}
?>