Files
Phraseanet/lib/Alchemy/Phrasea/Collection/CollectionService.php
Aina Sitraka 507219f715 PHRAS-3235 Admin - Collection - Emptying a collection by deleteRecord worker (#4113)
* emptying collection by deleteRecord worker

* fix test

* hide empty database
2022-09-02 15:42:27 +02:00

377 lines
12 KiB
PHP

<?php
/**
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Collection;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Authentication\ACLProvider;
use Alchemy\Phrasea\Collection\Reference\CollectionReference;
use Alchemy\Phrasea\Databox\DataboxConnectionProvider;
use Alchemy\Phrasea\Exception\RuntimeException;
use Alchemy\Phrasea\Model\Entities\User;
use Alchemy\Phrasea\Model\Repositories\UserRepository;
use Doctrine\DBAL\Connection;
class CollectionService
{
/**
* @var Application
*/
private $app;
/**
* @var Connection
*/
private $connection;
/**
* @var DataboxConnectionProvider
*/
private $connectionProvider;
/**
* @var callable
*/
private $userQueryFactory;
public function __construct(
Application $application,
Connection $connection,
DataboxConnectionProvider $connectionProvider,
callable $userQueryFactory
) {
$this->app = $application;
$this->connection = $connection;
$this->connectionProvider = $connectionProvider;
$this->userQueryFactory = $userQueryFactory;
}
/**
* @param Collection $collection
* @return int|null
* @throws \Doctrine\DBAL\DBALException
*/
public function getRecordCount(Collection $collection)
{
$connection = $this->connectionProvider->getConnection($collection->getDataboxId());
$sql = "SELECT COALESCE(COUNT(record_id), 0) AS recordCount FROM record WHERE coll_id = :coll_id";
$stmt = $connection->prepare($sql);
$stmt->execute([':coll_id' => $collection->getCollectionId()]);
$rowbas = $stmt->fetch(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
$amount = $rowbas ? (int) $rowbas["recordCount"] : null;
return $amount;
}
/**
* @param Collection $collection
* @return array
*/
public function getRecordDetails(Collection $collection)
{
$sql = "SELECT record.coll_id,name,COALESCE(asciiname, CONCAT('_',record.coll_id)) AS asciiname,
SUM(1) AS n, SUM(size) AS size
FROM record NATURAL JOIN subdef
INNER JOIN coll ON record.coll_id=coll.coll_id AND coll.coll_id = :coll_id
GROUP BY record.coll_id, subdef.name";
$connection = $this->connectionProvider->getConnection($collection->getDataboxId());
$stmt = $connection->prepare($sql);
$stmt->execute([':coll_id' => $collection->getCollectionId()]);
$rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
$ret = [];
foreach ($rs as $row) {
$ret[] = [
"coll_id" => (int) $row["coll_id"],
"name" => $row["name"],
"amount" => (int) $row["n"],
"size" => (int) $row["size"]];
}
return $ret;
}
/**
* @param Collection $collection
* @return $this
* @throws \Doctrine\DBAL\DBALException
*/
public function resetWatermark(Collection $collection)
{
$sql = 'SELECT path, file FROM record r INNER JOIN subdef s USING(record_id)
WHERE r.coll_id = :coll_id AND r.type="image" AND s.name="preview"';
$connection = $this->connectionProvider->getConnection($collection->getDataboxId());
$stmt = $connection->prepare($sql);
$stmt->execute([':coll_id' => $collection->getCollectionId()]);
while ($row2 = $stmt->fetch(\PDO::FETCH_ASSOC)) {
@unlink(\p4string::addEndSlash($row2['path']) . 'watermark_' . $row2['file']);
}
$stmt->closeCursor();
return $this;
}
/**
* @param Collection $collection
* @param int|null $record_id
* @return $this
* @throws \Doctrine\DBAL\DBALException
*/
public function resetStamp(Collection $collection, $record_id = null)
{
$sql = "SELECT path, file FROM record r INNER JOIN subdef s USING(record_id)\n"
. "WHERE r.coll_id = :coll_id\n"
. "AND r.type='image' AND s.name IN ('preview', 'document')";
$params = [':coll_id' => $collection->getCollectionId()];
if ($record_id) {
$sql .= " AND record_id = :record_id";
$params[':record_id'] = $record_id;
}
$connection = $this->connectionProvider->getConnection($collection->getDataboxId());
$stmt = $connection->prepare($sql);
$stmt->execute($params);
while ($row2 = $stmt->fetch(\PDO::FETCH_ASSOC)) {
@unlink(\p4string::addEndSlash($row2['path']) . 'stamp_' . $row2['file']);
}
$stmt->closeCursor();
return $this;
}
/**
* @param \databox $databox
* @param Collection $collection
* @param CollectionReference $reference
* @throws \Doctrine\DBAL\DBALException
*/
public function delete(\databox $databox, Collection $collection, CollectionReference $reference)
{
while ($this->getRecordCount($collection) > 0) {
$this->emptyCollection($databox, $collection);
}
$connection = $this->connectionProvider->getConnection($collection->getDataboxId());
$sql = "DELETE FROM coll WHERE coll_id = :coll_id";
$stmt = $connection->prepare($sql);
$stmt->execute([':coll_id' => $collection->getCollectionId()]);
$stmt->closeCursor();
$sql = "DELETE FROM bas WHERE base_id = :base_id";
$stmt = $this->connection->prepare($sql);
$stmt->execute([':base_id' => $reference->getBaseId()]);
$stmt->closeCursor();
$sql = "DELETE FROM basusr WHERE base_id = :base_id";
$stmt = $this->connection->prepare($sql);
$stmt->execute([':base_id' => $reference->getBaseId()]);
$stmt->closeCursor();
return;
}
/**
* @param \databox $databox
* @param Collection $collection
* @param int $pass_quantity
* @return $this
* @throws \Doctrine\DBAL\DBALException
*/
public function emptyCollection(\databox $databox, Collection $collection, $pass_quantity = 100)
{
$pass_quantity = (int) $pass_quantity > 200 ? 200 : (int) $pass_quantity;
$pass_quantity = (int) $pass_quantity < 10 ? 10 : (int) $pass_quantity;
$sql = "SELECT record_id FROM record WHERE coll_id = :coll_id
ORDER BY record_id DESC LIMIT 0, " . $pass_quantity;
$connection = $this->connectionProvider->getConnection($collection->getDataboxId());
$stmt = $connection->prepare($sql);
$stmt->execute([':coll_id' => $collection->getCollectionId()]);
$rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
foreach ($rs as $row) {
$record = $databox->get_record($row['record_id']);
$record->delete();
unset($record);
}
return $this;
}
/**
* Get list of the record_id
*
* @param Collection $collection
*
* @return array
*/
public function getCollectionRecordIdList(Collection $collection)
{
$sql = "SELECT record_id FROM record WHERE coll_id = :coll_id
ORDER BY record_id DESC";
$connection = $this->connectionProvider->getConnection($collection->getDataboxId());
$stmt = $connection->prepare($sql);
$stmt->execute([':coll_id' => $collection->getCollectionId()]);
$recordIdsList = $stmt->fetchAll(\PDO::FETCH_COLUMN);
$stmt->closeCursor();
return $recordIdsList;
}
/**
* @param CollectionReference $reference
* @return $this
* @throws \Doctrine\DBAL\DBALException
*/
public function unmountCollection(CollectionReference $reference)
{
$params = [':base_id' => $reference->getBaseId()];
$query = $this->app['phraseanet.user-query'];
$total = $query->on_base_ids([$reference->getBaseId()])
->include_phantoms(false)
->include_special_users(true)
->include_invite(true)
->include_templates(true)->get_total();
$n = 0;
while ($n < $total) {
$results = $query->limit($n, 50)->execute()->get_results();
foreach ($results as $user) {
$this->app->getAclForUser($user)->delete_data_from_cache(\ACL::CACHE_RIGHTS_SBAS);
$this->app->getAclForUser($user)->delete_data_from_cache(\ACL::CACHE_RIGHTS_BAS);
}
$n+=50;
}
$sql = "DELETE FROM basusr WHERE base_id = :base_id";
$stmt = $this->connection->prepare($sql);
$stmt->execute($params);
$stmt->closeCursor();
$sql = "DELETE FROM bas WHERE base_id = :base_id";
$stmt = $this->connection->prepare($sql);
$stmt->execute($params);
$stmt->closeCursor();
}
/**
* @param CollectionReference $reference
* @param User $user
*/
public function grantAdminRights(CollectionReference $reference, User $user)
{
$this->app->getAclForUser($user)->update_rights_to_base(
$reference->getBaseId(),
[
"basusr_infousr" => "", // todo : wtf
\ACL::CANPUTINALBUM => true,
\ACL::CANDWNLDHD => true,
\ACL::NOWATERMARK => true,
\ACL::CANDWNLDPREVIEW => true,
\ACL::CANCMD => true,
\ACL::CANADMIN => true,
\ACL::ACTIF => true,
\ACL::CANREPORT => true,
\ACL::CANPUSH => true,
\ACL::CANADDRECORD => true,
\ACL::CANMODIFRECORD => true,
\ACL::CANDELETERECORD => true,
\ACL::CHGSTATUS => true,
\ACL::IMGTOOLS => true,
\ACL::COLL_MANAGE => true,
\ACL::COLL_MODIFY_STRUCT => true
]
);
}
public function setOrderMasters(CollectionReference $reference, array $userIds)
{
/** @var UserRepository $userRepository */
$userRepository = $this->app['repo.users'];
$users = $userRepository->findBy(['id' => $userIds]);
$missingAdmins = array_diff($userIds, array_map(function (User $user) {
return $user->getId();
}, $users));
if (! empty($missingAdmins)) {
throw new RuntimeException(sprintf('Invalid usrIds provided [%s].', implode(',', $missingAdmins)));
}
$admins = $users;
/** @var Connection $conn */
$conn = $this->app->getApplicationBox()->get_connection();
$conn->beginTransaction();
try {
$factory = $this->userQueryFactory;
/** @var \User_Query $userQuery */
$userQuery = $factory();
$result = $userQuery->on_base_ids([ $reference->getBaseId()] )
->who_have_right([\ACL::ORDER_MASTER])
->include_templates(true)
->execute()
->get_results();
/** @var ACLProvider $acl */
$acl = $this->app['acl'];
foreach ($result as $user) {
$acl->get($user)->update_rights_to_base(
$reference->getBaseId(),
[
\ACL::ORDER_MASTER => false
]
);
}
foreach ($admins as $admin) {
$acl->get($admin)->update_rights_to_base(
$reference->getBaseId(),
[
\ACL::ORDER_MASTER => true
]
);
}
$conn->commit();
} catch (\Exception $e) {
$conn->rollBack();
throw $e;
}
}
}