mirror of https://github.com/nextcloud/server
Cleanup tags and Share component
- Port to LoggerInterface - Use IDBConnection and IQueryBuilder instead of raw SQL and OC_DB - Use IEventListener instead of hooks - Remove the now unused OC_DB and OC_DB_StatementWrapper legacy utils Signed-off-by: Carl Schwan <carl@carlschwan.eu>
This commit is contained in:
parent
b4708fb9f0
commit
92a5a8f075
|
@ -49,6 +49,7 @@ use OC\DB\MissingIndexInformation;
|
|||
use OC\DB\MissingPrimaryKeyInformation;
|
||||
use OC\DB\SchemaWrapper;
|
||||
use OC\Metadata\FileEventListener;
|
||||
use OC\TagManager;
|
||||
use OCP\AppFramework\App;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\Files\Events\Node\NodeDeletedEvent;
|
||||
|
@ -78,7 +79,7 @@ class Application extends App {
|
|||
|
||||
$server = $container->getServer();
|
||||
/** @var IEventDispatcher $eventDispatcher */
|
||||
$eventDispatcher = $server->query(IEventDispatcher::class);
|
||||
$eventDispatcher = $server->get(IEventDispatcher::class);
|
||||
|
||||
$notificationManager = $server->getNotificationManager();
|
||||
$notificationManager->registerNotifierService(CoreNotifier::class);
|
||||
|
@ -325,10 +326,15 @@ class Application extends App {
|
|||
/** @var IConfig $config */
|
||||
$config = $container->get(IConfig::class);
|
||||
if ($config->getSystemValueBool('enable_file_metadata', true)) {
|
||||
$eventDispatcher = \OC::$server->get(IEventDispatcher::class);
|
||||
/** @psalm-suppress InvalidArgument */
|
||||
$eventDispatcher->addServiceListener(NodeDeletedEvent::class, FileEventListener::class);
|
||||
/** @psalm-suppress InvalidArgument */
|
||||
$eventDispatcher->addServiceListener(NodeRemovedFromCache::class, FileEventListener::class);
|
||||
/** @psalm-suppress InvalidArgument */
|
||||
$eventDispatcher->addServiceListener(NodeWrittenEvent::class, FileEventListener::class);
|
||||
}
|
||||
|
||||
// Tags
|
||||
$eventDispatcher->addServiceListener(UserDeletedEvent::class, TagManager::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1595,8 +1595,6 @@ return array(
|
|||
'OC\\User\\User' => $baseDir . '/lib/private/User/User.php',
|
||||
'OC_API' => $baseDir . '/lib/private/legacy/OC_API.php',
|
||||
'OC_App' => $baseDir . '/lib/private/legacy/OC_App.php',
|
||||
'OC_DB' => $baseDir . '/lib/private/legacy/OC_DB.php',
|
||||
'OC_DB_StatementWrapper' => $baseDir . '/lib/private/legacy/OC_DB_StatementWrapper.php',
|
||||
'OC_Defaults' => $baseDir . '/lib/private/legacy/OC_Defaults.php',
|
||||
'OC_EventSource' => $baseDir . '/lib/private/legacy/OC_EventSource.php',
|
||||
'OC_FileChunking' => $baseDir . '/lib/private/legacy/OC_FileChunking.php',
|
||||
|
|
|
@ -1628,8 +1628,6 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
|
|||
'OC\\User\\User' => __DIR__ . '/../../..' . '/lib/private/User/User.php',
|
||||
'OC_API' => __DIR__ . '/../../..' . '/lib/private/legacy/OC_API.php',
|
||||
'OC_App' => __DIR__ . '/../../..' . '/lib/private/legacy/OC_App.php',
|
||||
'OC_DB' => __DIR__ . '/../../..' . '/lib/private/legacy/OC_DB.php',
|
||||
'OC_DB_StatementWrapper' => __DIR__ . '/../../..' . '/lib/private/legacy/OC_DB_StatementWrapper.php',
|
||||
'OC_Defaults' => __DIR__ . '/../../..' . '/lib/private/legacy/OC_Defaults.php',
|
||||
'OC_EventSource' => __DIR__ . '/../../..' . '/lib/private/legacy/OC_EventSource.php',
|
||||
'OC_FileChunking' => __DIR__ . '/../../..' . '/lib/private/legacy/OC_FileChunking.php',
|
||||
|
|
|
@ -32,6 +32,9 @@ use OCP\IUser;
|
|||
use OCP\User\Events\UserChangedEvent;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @template-implements IEventListener<UserChangedEvent>
|
||||
*/
|
||||
class Hooks implements IEventListener {
|
||||
|
||||
/** @var IAccountManager */
|
||||
|
|
|
@ -50,6 +50,8 @@ use Icewind\Streams\CallbackWrapper;
|
|||
use OC\Files\Mount\MoveableMount;
|
||||
use OC\Files\Storage\Storage;
|
||||
use OC\User\LazyUser;
|
||||
use OC\Share\Share;
|
||||
use OC\User\User;
|
||||
use OCA\Files_Sharing\SharedMount;
|
||||
use OCP\Constants;
|
||||
use OCP\Files\Cache\ICacheEntry;
|
||||
|
@ -1800,10 +1802,10 @@ class View {
|
|||
}
|
||||
|
||||
// check if any of the parents were shared by the current owner (include collections)
|
||||
$shares = \OCP\Share::getItemShared(
|
||||
$shares = Share::getItemShared(
|
||||
'folder',
|
||||
$fileId,
|
||||
\OCP\Share::FORMAT_NONE,
|
||||
\OC\Share\Constants::FORMAT_NONE,
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
|
|
@ -33,6 +33,11 @@ use OCP\Files\NotFoundException;
|
|||
use OCP\Files\FileInfo;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @template-implements IEventListener<NodeRemovedFromCache>
|
||||
* @template-implements IEventListener<NodeDeletedEvent>
|
||||
* @template-implements IEventListener<NodeWrittenEvent>
|
||||
*/
|
||||
class FileEventListener implements IEventListener {
|
||||
private IMetadataManager $manager;
|
||||
private LoggerInterface $logger;
|
||||
|
|
|
@ -32,9 +32,13 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OC\Share;
|
||||
|
||||
use OCA\Files_Sharing\ShareBackend\File;
|
||||
use OCP\DB\Exception;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Share\IShare;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
|
@ -59,11 +63,13 @@ class Share extends Constants {
|
|||
*
|
||||
* Apps are required to handle permissions on their own, this class only
|
||||
* stores and manages the permissions of shares
|
||||
*
|
||||
* @see lib/public/constants.php
|
||||
*/
|
||||
|
||||
/**
|
||||
* Register a sharing backend class that implements OCP\Share_Backend for an item type
|
||||
*
|
||||
* @param string $itemType Item type
|
||||
* @param string $class Backend class
|
||||
* @param string $collectionOf (optional) Depends on item type
|
||||
|
@ -83,13 +89,14 @@ class Share extends Constants {
|
|||
\OC::$server->get(LoggerInterface::class)->warning(
|
||||
'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class']
|
||||
.' is already registered for '.$itemType,
|
||||
['app' => 'OCP\Share']);
|
||||
['app' => 'files_sharing']);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the items of item type shared with the current user
|
||||
*
|
||||
* @param string $itemType
|
||||
* @param int $format (optional) Format type must be defined by the backend
|
||||
* @param mixed $parameters (optional)
|
||||
|
@ -106,6 +113,7 @@ class Share extends Constants {
|
|||
|
||||
/**
|
||||
* Get the items of item type shared with a user
|
||||
*
|
||||
* @param string $itemType
|
||||
* @param string $user id for which user we want the shares
|
||||
* @param int $format (optional) Format type must be defined by the backend
|
||||
|
@ -123,53 +131,46 @@ class Share extends Constants {
|
|||
|
||||
/**
|
||||
* Get the item of item type shared with a given user by source
|
||||
*
|
||||
* @param string $itemType
|
||||
* @param string $itemSource
|
||||
* @param string $user User to whom the item was shared
|
||||
* @param string $owner Owner of the share
|
||||
* @param int $shareType only look for a specific share type
|
||||
* @param ?string $user User to whom the item was shared
|
||||
* @param ?string $owner Owner of the share
|
||||
* @param ?int $shareType only look for a specific share type
|
||||
* @return array Return list of items with file_target, permissions and expiration
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getItemSharedWithUser($itemType, $itemSource, $user, $owner = null, $shareType = null) {
|
||||
public static function getItemSharedWithUser(string $itemType, string $itemSource, ?string $user = null, ?string $owner = null, ?int $shareType = null) {
|
||||
$shares = [];
|
||||
$fileDependent = false;
|
||||
|
||||
$where = 'WHERE';
|
||||
$fileDependentWhere = '';
|
||||
if ($itemType === 'file' || $itemType === 'folder') {
|
||||
$fileDependent = true;
|
||||
$fileDependent = $itemType === 'file' || $itemType === 'folder';
|
||||
$qb = self::getSelectStatement(self::FORMAT_NONE, $fileDependent);
|
||||
$qb->from('share', 's');
|
||||
if ($fileDependent) {
|
||||
$qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('file_source', 'f.fileid'));
|
||||
$qb->innerJoin('s', 'storages', 'st', $qb->expr()->eq('numeric_id', 'f.storage'));
|
||||
$column = 'file_source';
|
||||
$fileDependentWhere = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
|
||||
$fileDependentWhere .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
|
||||
} else {
|
||||
$column = 'item_source';
|
||||
}
|
||||
|
||||
$select = self::createSelectStatement(self::FORMAT_NONE, $fileDependent);
|
||||
$qb->where($qb->expr()->eq($column, $qb->createNamedParameter($itemSource)))
|
||||
->andWhere($qb->expr()->eq('item_type', $qb->createNamedParameter($itemType)));
|
||||
|
||||
$where .= ' `' . $column . '` = ? AND `item_type` = ? ';
|
||||
$arguments = [$itemSource, $itemType];
|
||||
// for link shares $user === null
|
||||
if ($user !== null) {
|
||||
$where .= ' AND `share_with` = ? ';
|
||||
$arguments[] = $user;
|
||||
$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($user)));
|
||||
}
|
||||
|
||||
if ($shareType !== null) {
|
||||
$where .= ' AND `share_type` = ? ';
|
||||
$arguments[] = $shareType;
|
||||
$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType, IQueryBuilder::PARAM_INT)));
|
||||
}
|
||||
|
||||
if ($owner !== null) {
|
||||
$where .= ' AND `uid_owner` = ? ';
|
||||
$arguments[] = $owner;
|
||||
$qb->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($owner)));
|
||||
}
|
||||
|
||||
$query = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` '. $fileDependentWhere . $where);
|
||||
|
||||
$result = \OC_DB::executeAudited($query, $arguments);
|
||||
|
||||
while ($row = $result->fetchRow()) {
|
||||
$result = $qb->executeQuery();
|
||||
while ($row = $result->fetch()) {
|
||||
if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
|
||||
continue;
|
||||
}
|
||||
|
@ -183,7 +184,7 @@ class Share extends Constants {
|
|||
$path = substr($path, strlen($owner) + 1); //normalize path to 'files/foo.txt`
|
||||
$row['path'] = $path;
|
||||
} else {
|
||||
\OC::$server->getLogger()->warning(
|
||||
\OC::$server->get(LoggerInterface::class)->warning(
|
||||
'Could not resolve mount point for ' . $row['storage_id'],
|
||||
['app' => 'OCP\Share']
|
||||
);
|
||||
|
@ -193,7 +194,7 @@ class Share extends Constants {
|
|||
}
|
||||
$result->closeCursor();
|
||||
|
||||
//if didn't found a result than let's look for a group share.
|
||||
// if we didn't found a result then let's look for a group share.
|
||||
if (empty($shares) && $user !== null) {
|
||||
$userObject = \OC::$server->getUserManager()->get($user);
|
||||
$groups = [];
|
||||
|
@ -202,28 +203,27 @@ class Share extends Constants {
|
|||
}
|
||||
|
||||
if (!empty($groups)) {
|
||||
$where = $fileDependentWhere . ' WHERE `' . $column . '` = ? AND `item_type` = ? AND `share_with` in (?)';
|
||||
$arguments = [$itemSource, $itemType, $groups];
|
||||
$types = [null, null, IQueryBuilder::PARAM_STR_ARRAY];
|
||||
$qb = self::getSelectStatement(self::FORMAT_NONE, $fileDependent);
|
||||
$qb->from('share', 's');
|
||||
|
||||
if ($owner !== null) {
|
||||
$where .= ' AND `uid_owner` = ?';
|
||||
$arguments[] = $owner;
|
||||
$types[] = null;
|
||||
if ($fileDependent) {
|
||||
$qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('file_source', 'f.fileid'))
|
||||
->innerJoin('s', 'storages', 'st', $qb->expr()->eq('numeric_id', 'f.storage'));
|
||||
}
|
||||
|
||||
// TODO: inject connection, hopefully one day in the future when this
|
||||
// class isn't static anymore...
|
||||
$conn = \OC::$server->getDatabaseConnection();
|
||||
$result = $conn->executeQuery(
|
||||
'SELECT ' . $select . ' FROM `*PREFIX*share` ' . $where,
|
||||
$arguments,
|
||||
$types
|
||||
);
|
||||
$qb->where($qb->expr()->eq($column, $qb->createNamedParameter($itemSource)))
|
||||
->andWhere($qb->expr()->eq('item_type', $qb->createNamedParameter($itemType, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($qb->expr()->in('share_with', $qb->createNamedParameter($groups, IQueryBuilder::PARAM_STR_ARRAY)));
|
||||
|
||||
if ($owner !== null) {
|
||||
$qb->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($owner)));
|
||||
}
|
||||
$result = $qb->executeQuery();
|
||||
|
||||
while ($row = $result->fetch()) {
|
||||
$shares[] = $row;
|
||||
}
|
||||
$result->closeCursor();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,6 +232,7 @@ class Share extends Constants {
|
|||
|
||||
/**
|
||||
* Get the shared item of item type owned by the current user
|
||||
*
|
||||
* @param string $itemType
|
||||
* @param string $itemSource
|
||||
* @param int $format (optional) Format type must be defined by the backend
|
||||
|
@ -250,9 +251,10 @@ class Share extends Constants {
|
|||
|
||||
/**
|
||||
* Get the backend class for the specified item type
|
||||
*
|
||||
* @param string $itemType
|
||||
* @throws \Exception
|
||||
* @return \OCP\Share_Backend
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getBackend($itemType) {
|
||||
$l = \OC::$server->getL10N('lib');
|
||||
|
@ -285,6 +287,7 @@ class Share extends Constants {
|
|||
|
||||
/**
|
||||
* Check if resharing is allowed
|
||||
*
|
||||
* @return boolean true if allowed or false
|
||||
*
|
||||
* Resharing is allowed by default if not configured
|
||||
|
@ -302,10 +305,11 @@ class Share extends Constants {
|
|||
|
||||
/**
|
||||
* Get a list of collection item types for the specified item type
|
||||
*
|
||||
* @param string $itemType
|
||||
* @return array
|
||||
* @return array|false
|
||||
*/
|
||||
private static function getCollectionItemTypes($itemType) {
|
||||
private static function getCollectionItemTypes(string $itemType) {
|
||||
$collectionTypes = [$itemType];
|
||||
foreach (self::$backendTypes as $type => $backend) {
|
||||
if (in_array($backend['collectionOf'], $collectionTypes)) {
|
||||
|
@ -326,6 +330,7 @@ class Share extends Constants {
|
|||
|
||||
/**
|
||||
* Get shared items from the database
|
||||
*
|
||||
* @param string $itemType
|
||||
* @param string $item Item source or target (optional)
|
||||
* @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
|
||||
|
@ -344,31 +349,36 @@ class Share extends Constants {
|
|||
* Refactoring notes:
|
||||
* * defacto $limit, $itemsShareWithBySource, $checkExpireDate, $parameters and $format is always the default and therefore is removed in the subsequent call
|
||||
*/
|
||||
public static function getItems($itemType, $item = null, $shareType = null, $shareWith = null,
|
||||
public static function getItems($itemType, ?string $item = null, ?int $shareType = null, $shareWith = null,
|
||||
$uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1,
|
||||
$includeCollections = false, $itemShareWithBySource = false, $checkExpireDate = true) {
|
||||
if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') != 'yes') {
|
||||
return [];
|
||||
}
|
||||
$fileDependent = $itemType == 'file' || $itemType == 'folder';
|
||||
$qb = self::getSelectStatement(self::FORMAT_NONE, $fileDependent, $uidOwner);
|
||||
$qb->from('share', 's');
|
||||
|
||||
$backend = self::getBackend($itemType);
|
||||
$collectionTypes = false;
|
||||
// Get filesystem root to add it to the file target and remove from the
|
||||
// file source, match file_source with the file cache
|
||||
if ($itemType == 'file' || $itemType == 'folder') {
|
||||
if ($fileDependent) {
|
||||
if (!is_null($uidOwner)) {
|
||||
$root = \OC\Files\Filesystem::getRoot();
|
||||
} else {
|
||||
$root = '';
|
||||
}
|
||||
$where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
|
||||
if (!isset($item)) {
|
||||
$where .= ' AND `file_target` IS NOT NULL ';
|
||||
if (isset($item)) {
|
||||
$qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('file_source', 'f.fileid'));
|
||||
} else {
|
||||
$qb->innerJoin('s', 'filecache', 'f', $qb->expr()->andX(
|
||||
$qb->expr()->eq('file_source', 'f.fileid'),
|
||||
$qb->expr()->isNotNull('file_target')
|
||||
));
|
||||
}
|
||||
$where .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
|
||||
$fileDependent = true;
|
||||
$queryArgs = [];
|
||||
$qb->innerJoin('s', 'storages', 'st', $qb->expr()->eq('numeric_id', 'f.storage'));
|
||||
} else {
|
||||
$fileDependent = false;
|
||||
$root = '';
|
||||
$collectionTypes = self::getCollectionItemTypes($itemType);
|
||||
if ($includeCollections && !isset($item) && $collectionTypes) {
|
||||
|
@ -378,25 +388,21 @@ class Share extends Constants {
|
|||
} else {
|
||||
$itemTypes = $collectionTypes;
|
||||
}
|
||||
$placeholders = implode(',', array_fill(0, count($itemTypes), '?'));
|
||||
$where = ' WHERE `item_type` IN ('.$placeholders.'))';
|
||||
$queryArgs = $itemTypes;
|
||||
$qb->where($qb->expr()->in('item_type', $qb->createNamedParameter($itemTypes, IQueryBuilder::PARAM_STR_ARRAY)));
|
||||
} else {
|
||||
$where = ' WHERE `item_type` = ?';
|
||||
$queryArgs = [$itemType];
|
||||
$qb->where($qb->expr()->eq('item_type', $qb->createNamedParameter($itemType)));
|
||||
}
|
||||
}
|
||||
if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
|
||||
$where .= ' AND `share_type` != ?';
|
||||
$queryArgs[] = IShare::TYPE_LINK;
|
||||
$qb->andWhere($qb->expr()->neq('share_type', $qb->createNamedParameter(IShare::TYPE_LINK, IQueryBuilder::PARAM_INT)));
|
||||
}
|
||||
if (isset($shareType)) {
|
||||
// Include all user and group items
|
||||
if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) {
|
||||
$where .= ' AND ((`share_type` in (?, ?) AND `share_with` = ?) ';
|
||||
$queryArgs[] = IShare::TYPE_USER;
|
||||
$queryArgs[] = self::$shareTypeGroupUserUnique;
|
||||
$queryArgs[] = $shareWith;
|
||||
if ($shareType === self::$shareTypeUserAndGroups && isset($shareWith)) {
|
||||
$qb->andWhere($qb->expr()->andX(
|
||||
$qb->expr()->in('share_type', $qb->createNamedParameter([IShare::TYPE_USER, self::$shareTypeGroupUserUnique], IQueryBuilder::PARAM_INT_ARRAY)),
|
||||
$qb->expr()->eq('share_with', $qb->createNamedParameter($shareWith))
|
||||
));
|
||||
|
||||
$user = \OC::$server->getUserManager()->get($shareWith);
|
||||
$groups = [];
|
||||
|
@ -404,31 +410,26 @@ class Share extends Constants {
|
|||
$groups = \OC::$server->getGroupManager()->getUserGroupIds($user);
|
||||
}
|
||||
if (!empty($groups)) {
|
||||
$placeholders = implode(',', array_fill(0, count($groups), '?'));
|
||||
$where .= ' OR (`share_type` = ? AND `share_with` IN ('.$placeholders.')) ';
|
||||
$queryArgs[] = IShare::TYPE_GROUP;
|
||||
$queryArgs = array_merge($queryArgs, $groups);
|
||||
$qb->orWhere($qb->expr()->andX(
|
||||
$qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_GROUP, IQueryBuilder::PARAM_INT)),
|
||||
$qb->expr()->in('share_with', $qb->createNamedParameter($groups, IQueryBuilder::PARAM_STR_ARRAY))
|
||||
));
|
||||
}
|
||||
$where .= ')';
|
||||
|
||||
// Don't include own group shares
|
||||
$where .= ' AND `uid_owner` != ?';
|
||||
$queryArgs[] = $shareWith;
|
||||
$qb->andWhere($qb->expr()->neq('uid_owner', $qb->createNamedParameter($shareWith)));
|
||||
} else {
|
||||
$where .= ' AND `share_type` = ?';
|
||||
$queryArgs[] = $shareType;
|
||||
$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType, IQueryBuilder::PARAM_INT)));
|
||||
if (isset($shareWith)) {
|
||||
$where .= ' AND `share_with` = ?';
|
||||
$queryArgs[] = $shareWith;
|
||||
$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($shareWith, IQueryBuilder::PARAM_STR)));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($uidOwner)) {
|
||||
$where .= ' AND `uid_owner` = ?';
|
||||
$queryArgs[] = $uidOwner;
|
||||
$qb->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uidOwner)));
|
||||
if (!isset($shareType)) {
|
||||
// Prevent unique user targets for group shares from being selected
|
||||
$where .= ' AND `share_type` != ?';
|
||||
$queryArgs[] = self::$shareTypeGroupUserUnique;
|
||||
$qb->andWhere($qb->expr()->neq('share_type', $qb->createNamedParameter(self::$shareTypeGroupUserUnique, IQueryBuilder::PARAM_INT)));
|
||||
}
|
||||
if ($fileDependent) {
|
||||
$column = 'file_source';
|
||||
|
@ -444,54 +445,53 @@ class Share extends Constants {
|
|||
}
|
||||
if (isset($item)) {
|
||||
$collectionTypes = self::getCollectionItemTypes($itemType);
|
||||
if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
|
||||
$where .= ' AND (';
|
||||
} else {
|
||||
$where .= ' AND';
|
||||
}
|
||||
// If looking for own shared items, check item_source else check item_target
|
||||
if (isset($uidOwner)) {
|
||||
// If item type is a file, file source needs to be checked in case the item was converted
|
||||
if ($fileDependent) {
|
||||
$where .= ' `file_source` = ?';
|
||||
$expr = $qb->expr()->eq('file_source', $qb->createNamedParameter($item));
|
||||
$column = 'file_source';
|
||||
} else {
|
||||
$where .= ' `item_source` = ?';
|
||||
$expr = $qb->expr()->eq('item_source', $qb->createNamedParameter($item));
|
||||
$column = 'item_source';
|
||||
}
|
||||
} else {
|
||||
if ($fileDependent) {
|
||||
$where .= ' `file_target` = ?';
|
||||
$item = \OC\Files\Filesystem::normalizePath($item);
|
||||
$expr = $qb->expr()->eq('file_target', $qb->createNamedParameter($item));
|
||||
} else {
|
||||
$where .= ' `item_target` = ?';
|
||||
$expr = $qb->expr()->eq('item_target', $qb->createNamedParameter($item));
|
||||
}
|
||||
}
|
||||
$queryArgs[] = $item;
|
||||
if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
|
||||
$placeholders = implode(',', array_fill(0, count($collectionTypes), '?'));
|
||||
$where .= ' OR `item_type` IN ('.$placeholders.'))';
|
||||
$queryArgs = array_merge($queryArgs, $collectionTypes);
|
||||
$qb->andWhere($qb->expr()->orX(
|
||||
$expr,
|
||||
$qb->expr()->in('item_type', $qb->createNamedParameter($collectionTypes, IQueryBuilder::PARAM_STR_ARRAY))
|
||||
));
|
||||
} else {
|
||||
$qb->andWhere($expr);
|
||||
}
|
||||
}
|
||||
|
||||
$where .= ' ORDER BY `*PREFIX*share`.`id` ASC';
|
||||
|
||||
$queryLimit = null;
|
||||
$select = self::createSelectStatement(self::FORMAT_NONE, $fileDependent, $uidOwner);
|
||||
$root = strlen($root);
|
||||
$query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
|
||||
$result = $query->execute($queryArgs);
|
||||
if ($result === false) {
|
||||
\OC::$server->get(LoggerInterface::class)->error(
|
||||
\OC_DB::getErrorMessage() . ', select=' . $select . ' where=',
|
||||
['app' => 'OCP\Share']);
|
||||
$qb->orderBy('s.id', 'ASC');
|
||||
try {
|
||||
$result = $qb->executeQuery();
|
||||
} catch (\Exception $e) {
|
||||
\OCP\Server::get(LoggerInterface::class)->error(
|
||||
'Error while selecting shares: ' . $qb->getSQL(),
|
||||
[
|
||||
'app' => 'files_sharing',
|
||||
'exception' => $e
|
||||
]);
|
||||
throw new \RuntimeException('Wrong SQL query', 500, $e);
|
||||
}
|
||||
|
||||
$root = strlen($root);
|
||||
$items = [];
|
||||
$targets = [];
|
||||
$switchedItems = [];
|
||||
$mounts = [];
|
||||
while ($row = $result->fetchRow()) {
|
||||
while ($row = $result->fetch()) {
|
||||
//var_dump($row);
|
||||
self::transformDBResults($row);
|
||||
// Filter out duplicate group shares for users with unique targets
|
||||
if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
|
||||
|
@ -548,16 +548,12 @@ class Share extends Constants {
|
|||
->from('share')
|
||||
->where($query->expr()->eq('id', $query->createNamedParameter($row['parent'])));
|
||||
|
||||
$parentResult = $query->execute();
|
||||
$parentRow = $parentResult->fetch();
|
||||
$parentResult->closeCursor();
|
||||
$parentRow = false;
|
||||
try {
|
||||
$parentResult = $query->executeQuery();
|
||||
$parentRow = $parentResult->fetchOne();
|
||||
$parentResult->closeCursor();
|
||||
|
||||
if ($parentRow === false) {
|
||||
\OC::$server->get(LoggerInterface::class)->error(
|
||||
'Can\'t select parent: ' .
|
||||
\OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
|
||||
['app' => 'OCP\Share']);
|
||||
} else {
|
||||
$tmpPath = $parentRow['file_target'];
|
||||
// find the right position where the row path continues from the target path
|
||||
$pos = strrpos($row['path'], $parentRow['file_target']);
|
||||
|
@ -567,6 +563,12 @@ class Share extends Constants {
|
|||
$tmpPath = $tmpPath . '/' . $pathPart;
|
||||
}
|
||||
$row['path'] = $tmpPath;
|
||||
} catch (Exception $e) {
|
||||
\OCP\Server::get(LoggerInterface::class)
|
||||
->error('Can\'t select parent :' . $e->getMessage() . ' query=' . $query->getSQL(), [
|
||||
'exception' => $e,
|
||||
'app' => 'core'
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
if (!isset($mounts[$row['storage']])) {
|
||||
|
@ -576,7 +578,7 @@ class Share extends Constants {
|
|||
}
|
||||
}
|
||||
if (!empty($mounts[$row['storage']])) {
|
||||
$path = $mounts[$row['storage']]->getMountPoint().$row['path'];
|
||||
$path = $mounts[$row['storage']]->getMountPoint() . $row['path'];
|
||||
$relPath = substr($path, $root); // path relative to data/user
|
||||
$row['path'] = rtrim($relPath, '/');
|
||||
}
|
||||
|
@ -618,6 +620,7 @@ class Share extends Constants {
|
|||
$items[$row['id']] = $row;
|
||||
}
|
||||
}
|
||||
$result->closeCursor();
|
||||
|
||||
// group items if we are looking for items shared with the current user
|
||||
if (isset($shareWith) && $shareWith === \OC_User::getUser()) {
|
||||
|
@ -641,7 +644,7 @@ class Share extends Constants {
|
|||
$collection['path'] = basename($row['path']);
|
||||
}
|
||||
$row['collection'] = $collection;
|
||||
// Fetch all of the children sources
|
||||
// Fetch all the children sources
|
||||
$children = $collectionBackend->getChildren($row[$column]);
|
||||
foreach ($children as $child) {
|
||||
$childItem = $row;
|
||||
|
@ -739,7 +742,7 @@ class Share extends Constants {
|
|||
if (!isset($result[$key]['grouped'])) {
|
||||
$result[$key]['grouped'][] = $result[$key];
|
||||
}
|
||||
$result[$key]['permissions'] = (int) $item['permissions'] | (int) $r['permissions'];
|
||||
$result[$key]['permissions'] = (int)$item['permissions'] | (int)$r['permissions'];
|
||||
$result[$key]['grouped'][] = $item;
|
||||
$grouped = true;
|
||||
break;
|
||||
|
@ -755,83 +758,142 @@ class Share extends Constants {
|
|||
}
|
||||
|
||||
/**
|
||||
* construct select statement
|
||||
* @param int $format
|
||||
* @param boolean $fileDependent ist it a file/folder share or a general share
|
||||
* @param string $uidOwner
|
||||
* @return string select statement
|
||||
* Construct select statement
|
||||
*
|
||||
* @param bool $fileDependent ist it a file/folder share or a general share
|
||||
*/
|
||||
private static function createSelectStatement($format, $fileDependent, $uidOwner = null) {
|
||||
$select = '*';
|
||||
private static function getSelectStatement(int $format, bool $fileDependent, ?string $uidOwner = null): IQueryBuilder {
|
||||
/** @var IDBConnection $connection */
|
||||
$connection = \OC::$server->get(IDBConnection::class);
|
||||
$qb = $connection->getQueryBuilder();
|
||||
if ($format == self::FORMAT_STATUSES) {
|
||||
if ($fileDependent) {
|
||||
$select = '`*PREFIX*share`.`id`, `*PREFIX*share`.`parent`, `share_type`, `path`, `storage`, '
|
||||
. '`share_with`, `uid_owner` , `file_source`, `stime`, `*PREFIX*share`.`permissions`, '
|
||||
. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`, '
|
||||
. '`uid_initiator`';
|
||||
} else {
|
||||
$select = '`id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_source`, `stime`, `*PREFIX*share`.`permissions`';
|
||||
}
|
||||
} else {
|
||||
if (isset($uidOwner)) {
|
||||
if ($fileDependent) {
|
||||
$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,'
|
||||
. ' `share_type`, `share_with`, `file_source`, `file_target`, `path`, `*PREFIX*share`.`permissions`, `stime`,'
|
||||
. ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`, '
|
||||
. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
|
||||
} else {
|
||||
$select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,'
|
||||
. ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`';
|
||||
}
|
||||
} else {
|
||||
if ($fileDependent) {
|
||||
if ($format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_GET_FOLDER_CONTENTS || $format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_FILE_APP_ROOT) {
|
||||
$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, '
|
||||
. '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, '
|
||||
. '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
|
||||
. '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`';
|
||||
} else {
|
||||
$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,'
|
||||
. '`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,'
|
||||
. '`file_source`, `path`, `file_target`, `*PREFIX*share`.`permissions`,'
|
||||
. '`stime`, `expiration`, `token`, `storage`, `mail_send`,'
|
||||
. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
|
||||
}
|
||||
}
|
||||
return $qb->select(
|
||||
's.id',
|
||||
's.parent',
|
||||
'share_type',
|
||||
'path',
|
||||
'storage',
|
||||
'share_with',
|
||||
'uid_owner',
|
||||
'file_source',
|
||||
'stime',
|
||||
's.permissions',
|
||||
'uid_initiator'
|
||||
)->selectAlias('st.id', 'storage_id')
|
||||
->selectAlias('f.parent', 'file_parent');
|
||||
}
|
||||
return $qb->select('id', 'parent', 'share_type', 'share_with', 'uid_owner', 'item_source', 'stime', 's.permissions');
|
||||
}
|
||||
return $select;
|
||||
|
||||
if (isset($uidOwner)) {
|
||||
if ($fileDependent) {
|
||||
return $qb->select(
|
||||
's.id',
|
||||
'item_type',
|
||||
'item_source',
|
||||
's.parent',
|
||||
'share_type',
|
||||
'share_with',
|
||||
'file_source',
|
||||
'file_target',
|
||||
'path',
|
||||
's.permissions',
|
||||
'stime',
|
||||
'expiration',
|
||||
'token',
|
||||
'storage',
|
||||
'mail_send',
|
||||
'uid_owner',
|
||||
'uid_initiator'
|
||||
)->selectAlias('st.id', 'storage_id')
|
||||
->selectAlias('f.parent', 'file_parent');
|
||||
}
|
||||
return $qb->select('id', 'item_type', 'item_source', 'parent', 'share_type',
|
||||
'share_with', 'uid_owner', 'file_source', 'stime', 's.permissions',
|
||||
'expiration', 'token', 'mail_send');
|
||||
}
|
||||
|
||||
if ($fileDependent) {
|
||||
if ($format == File::FORMAT_GET_FOLDER_CONTENTS || $format == File::FORMAT_FILE_APP_ROOT) {
|
||||
return $qb->select(
|
||||
's.id',
|
||||
'item_type',
|
||||
'item_source',
|
||||
's.parent',
|
||||
'uid_owner',
|
||||
'share_type',
|
||||
'share_with',
|
||||
'file_source',
|
||||
'path',
|
||||
'file_target',
|
||||
's.permissions',
|
||||
'stime',
|
||||
'expiration',
|
||||
'storage',
|
||||
'name',
|
||||
'mtime',
|
||||
'mimepart',
|
||||
'size',
|
||||
'encrypted',
|
||||
'etag',
|
||||
'mail_send'
|
||||
)->selectAlias('f.parent', 'file_parent');
|
||||
}
|
||||
return $qb->select(
|
||||
's.id',
|
||||
'item_type',
|
||||
'item_source',
|
||||
'item_target',
|
||||
's.parent',
|
||||
'share_type',
|
||||
'share_with',
|
||||
'uid_owner',
|
||||
'file_source',
|
||||
'path',
|
||||
'file_target',
|
||||
's.permissions',
|
||||
'stime',
|
||||
'expiration',
|
||||
'token',
|
||||
'storage',
|
||||
'mail_send',
|
||||
)->selectAlias('f.parent', 'file_parent')
|
||||
->selectAlias('st.id', 'storage_id');
|
||||
}
|
||||
return $qb->select('*');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* transform db results
|
||||
*
|
||||
* @param array $row result
|
||||
*/
|
||||
private static function transformDBResults(&$row) {
|
||||
if (isset($row['id'])) {
|
||||
$row['id'] = (int) $row['id'];
|
||||
$row['id'] = (int)$row['id'];
|
||||
}
|
||||
if (isset($row['share_type'])) {
|
||||
$row['share_type'] = (int) $row['share_type'];
|
||||
$row['share_type'] = (int)$row['share_type'];
|
||||
}
|
||||
if (isset($row['parent'])) {
|
||||
$row['parent'] = (int) $row['parent'];
|
||||
$row['parent'] = (int)$row['parent'];
|
||||
}
|
||||
if (isset($row['file_parent'])) {
|
||||
$row['file_parent'] = (int) $row['file_parent'];
|
||||
$row['file_parent'] = (int)$row['file_parent'];
|
||||
}
|
||||
if (isset($row['file_source'])) {
|
||||
$row['file_source'] = (int) $row['file_source'];
|
||||
$row['file_source'] = (int)$row['file_source'];
|
||||
}
|
||||
if (isset($row['permissions'])) {
|
||||
$row['permissions'] = (int) $row['permissions'];
|
||||
$row['permissions'] = (int)$row['permissions'];
|
||||
}
|
||||
if (isset($row['storage'])) {
|
||||
$row['storage'] = (int) $row['storage'];
|
||||
$row['storage'] = (int)$row['storage'];
|
||||
}
|
||||
if (isset($row['stime'])) {
|
||||
$row['stime'] = (int) $row['stime'];
|
||||
$row['stime'] = (int)$row['stime'];
|
||||
}
|
||||
if (isset($row['expiration']) && $row['share_type'] !== IShare::TYPE_LINK) {
|
||||
// discard expiration date for non-link shares, which might have been
|
||||
|
@ -842,6 +904,7 @@ class Share extends Constants {
|
|||
|
||||
/**
|
||||
* format result
|
||||
*
|
||||
* @param array $items result
|
||||
* @param string $column is it a file share or a general share ('file_target' or 'item_target')
|
||||
* @param \OCP\Share_Backend $backend sharing backend
|
||||
|
|
|
@ -30,6 +30,9 @@ use OCP\EventDispatcher\IEventListener;
|
|||
use OCP\Group\Events\UserRemovedEvent;
|
||||
use OCP\Share\IManager;
|
||||
|
||||
/**
|
||||
* @template-implements IEventListener<UserRemovedEvent>
|
||||
*/
|
||||
class UserRemovedListener implements IEventListener {
|
||||
|
||||
/** @var IManager */
|
||||
|
|
|
@ -28,26 +28,30 @@ namespace OC;
|
|||
|
||||
use OC\Tagging\TagMapper;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\EventDispatcher\Event;
|
||||
use OCP\EventDispatcher\IEventListener;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\ITagManager;
|
||||
use OCP\ITags;
|
||||
use OCP\IUserSession;
|
||||
use OCP\User\Events\UserDeletedEvent;
|
||||
use OCP\Db\Exception as DBException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class TagManager implements ITagManager {
|
||||
/**
|
||||
* @template-implements IEventListener<UserDeletedEvent>
|
||||
*/
|
||||
class TagManager implements ITagManager, IEventListener {
|
||||
private TagMapper $mapper;
|
||||
private IUserSession $userSession;
|
||||
private IDBConnection $connection;
|
||||
private LoggerInterface $logger;
|
||||
|
||||
/** @var TagMapper */
|
||||
private $mapper;
|
||||
|
||||
/** @var IUserSession */
|
||||
private $userSession;
|
||||
|
||||
/** @var IDBConnection */
|
||||
private $connection;
|
||||
|
||||
public function __construct(TagMapper $mapper, IUserSession $userSession, IDBConnection $connection) {
|
||||
public function __construct(TagMapper $mapper, IUserSession $userSession, IDBConnection $connection, LoggerInterface $logger) {
|
||||
$this->mapper = $mapper;
|
||||
$this->userSession = $userSession;
|
||||
$this->connection = $connection;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,7 +76,7 @@ class TagManager implements ITagManager {
|
|||
}
|
||||
$userId = $this->userSession->getUser()->getUId();
|
||||
}
|
||||
return new Tags($this->mapper, $userId, $type, $defaultTags);
|
||||
return new Tags($this->mapper, $userId, $type, $this->logger, $this->connection, $defaultTags);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,4 +101,57 @@ class TagManager implements ITagManager {
|
|||
|
||||
return $users;
|
||||
}
|
||||
|
||||
public function handle(Event $event): void {
|
||||
if (!($event instanceof UserDeletedEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find all objectid/tagId pairs.
|
||||
$user = $event->getUser();
|
||||
$qb = $this->connection->getQueryBuilder();
|
||||
$qb->select('id')
|
||||
->from('vcategory')
|
||||
->where($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())));
|
||||
try {
|
||||
$result = $qb->executeQuery();
|
||||
} catch (DBException $e) {
|
||||
$this->logger->error($e->getMessage(), [
|
||||
'app' => 'core',
|
||||
'exception' => $e,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$tagsIds = array_map(fn (array $row) => (int)$row['id'], $result->fetchAll());
|
||||
$result->closeCursor();
|
||||
|
||||
if (count($tagsIds) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean vcategory_to_object table
|
||||
$qb = $this->connection->getQueryBuilder();
|
||||
$qb = $qb->delete('vcategory_to_object')
|
||||
->where($qb->expr()->in('categoryid', $qb->createParameter('chunk')));
|
||||
|
||||
// Clean vcategory
|
||||
$qb1 = $this->connection->getQueryBuilder();
|
||||
$qb1 = $qb1->delete('vcategory')
|
||||
->where($qb1->expr()->in('uid', $qb1->createParameter('chunk')));
|
||||
|
||||
foreach (array_chunk($tagsIds, 1000) as $tagChunk) {
|
||||
$qb->setParameter('chunk', $tagChunk, IQueryBuilder::PARAM_INT_ARRAY);
|
||||
$qb1->setParameter('chunk', $tagChunk, IQueryBuilder::PARAM_INT_ARRAY);
|
||||
try {
|
||||
$qb->executeStatement();
|
||||
$qb1->executeStatement();
|
||||
} catch (DBException $e) {
|
||||
$this->logger->error($e->getMessage(), [
|
||||
'app' => 'core',
|
||||
'exception' => $e,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,72 +32,49 @@ namespace OC;
|
|||
|
||||
use OC\Tagging\Tag;
|
||||
use OC\Tagging\TagMapper;
|
||||
use OCP\DB\Exception;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\ILogger;
|
||||
use OCP\ITags;
|
||||
use OCP\Share_Backend;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Tags implements ITags {
|
||||
|
||||
/**
|
||||
* Tags
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $tags = [];
|
||||
|
||||
/**
|
||||
* Used for storing objectid/categoryname pairs while rescanning.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $relations = [];
|
||||
|
||||
/**
|
||||
* Type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $type;
|
||||
|
||||
/**
|
||||
* User
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $user;
|
||||
private static array $relations = [];
|
||||
private string $type;
|
||||
private string $user;
|
||||
private IDBConnection $db;
|
||||
private LoggerInterface $logger;
|
||||
private array $tags = [];
|
||||
|
||||
/**
|
||||
* Are we including tags for shared items?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $includeShared = false;
|
||||
private bool $includeShared = false;
|
||||
|
||||
/**
|
||||
* The current user, plus any owners of the items shared with the current
|
||||
* user, if $this->includeShared === true.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $owners = [];
|
||||
private array $owners = [];
|
||||
|
||||
/**
|
||||
* The Mapper we're using to communicate our Tag objects to the database.
|
||||
*
|
||||
* @var TagMapper
|
||||
* The Mapper we are using to communicate our Tag objects to the database.
|
||||
*/
|
||||
private $mapper;
|
||||
private TagMapper $mapper;
|
||||
|
||||
/**
|
||||
* The sharing backend for objects of $this->type. Required if
|
||||
* $this->includeShared === true to determine ownership of items.
|
||||
*
|
||||
* @var \OCP\Share_Backend
|
||||
*/
|
||||
private $backend;
|
||||
private ?Share_Backend $backend = null;
|
||||
|
||||
public const TAG_TABLE = '*PREFIX*vcategory';
|
||||
public const RELATION_TABLE = '*PREFIX*vcategory_to_object';
|
||||
public const TAG_TABLE = 'vcategory';
|
||||
public const RELATION_TABLE = 'vcategory_to_object';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
|
@ -109,12 +86,14 @@ class Tags implements ITags {
|
|||
*
|
||||
* since 20.0.0 $includeShared isn't used anymore
|
||||
*/
|
||||
public function __construct(TagMapper $mapper, $user, $type, $defaultTags = []) {
|
||||
public function __construct(TagMapper $mapper, string $user, string $type, LoggerInterface $logger, IDBConnection $connection, array $defaultTags = []) {
|
||||
$this->mapper = $mapper;
|
||||
$this->user = $user;
|
||||
$this->type = $type;
|
||||
$this->owners = [$this->user];
|
||||
$this->tags = $this->mapper->loadTags($this->owners, $this->type);
|
||||
$this->db = $connection;
|
||||
$this->logger = $logger;
|
||||
|
||||
if (count($defaultTags) > 0 && count($this->tags) === 0) {
|
||||
$this->addMultiple($defaultTags, true);
|
||||
|
@ -126,7 +105,7 @@ class Tags implements ITags {
|
|||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isEmpty() {
|
||||
public function isEmpty(): bool {
|
||||
return count($this->tags) === 0;
|
||||
}
|
||||
|
||||
|
@ -137,7 +116,7 @@ class Tags implements ITags {
|
|||
* @param string $id The ID of the tag that is going to be mapped
|
||||
* @return array|false
|
||||
*/
|
||||
public function getTag($id) {
|
||||
public function getTag(string $id) {
|
||||
$key = $this->getTagById($id);
|
||||
if ($key !== false) {
|
||||
return $this->tagMap($this->tags[$key]);
|
||||
|
@ -154,9 +133,9 @@ class Tags implements ITags {
|
|||
* ['id' => 1, 'name' = 'Shared tag', 'owner' = 'Other user', 'type' => 'tagtype'],
|
||||
* ]
|
||||
*
|
||||
* @return array
|
||||
* @return array<array-key, array{id: int, name: string}>
|
||||
*/
|
||||
public function getTags() {
|
||||
public function getTags(): array {
|
||||
if (!count($this->tags)) {
|
||||
return [];
|
||||
}
|
||||
|
@ -181,7 +160,7 @@ class Tags implements ITags {
|
|||
* @param string $user The user whose tags are to be checked.
|
||||
* @return array An array of Tag objects.
|
||||
*/
|
||||
public function getTagsForUser($user) {
|
||||
public function getTagsForUser(string $user): array {
|
||||
return array_filter($this->tags,
|
||||
function ($tag) use ($user) {
|
||||
return $tag->getOwner() === $user;
|
||||
|
@ -193,23 +172,26 @@ class Tags implements ITags {
|
|||
* Get the list of tags for the given ids.
|
||||
*
|
||||
* @param array $objIds array of object ids
|
||||
* @return array|boolean of tags id as key to array of tag names
|
||||
* @return array|false of tags id as key to array of tag names
|
||||
* or false if an error occurred
|
||||
*/
|
||||
public function getTagsForObjects(array $objIds) {
|
||||
$entries = [];
|
||||
|
||||
try {
|
||||
$conn = \OC::$server->getDatabaseConnection();
|
||||
$chunks = array_chunk($objIds, 900, false);
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->select('category', 'categoryid', 'objid')
|
||||
->from(self::RELATION_TABLE, 'r')
|
||||
->join('r', self::TAG_TABLE, 't', $qb->expr()->eq('r.categoryid', 't.id'))
|
||||
->where($qb->expr()->eq('uid', $qb->createParameter('uid')))
|
||||
->andWhere($qb->expr()->eq('r.type', $qb->createParameter('type')))
|
||||
->andWhere($qb->expr()->in('objid', $qb->createParameter('chunk')));
|
||||
foreach ($chunks as $chunk) {
|
||||
$result = $conn->executeQuery(
|
||||
'SELECT `category`, `categoryid`, `objid` ' .
|
||||
'FROM `' . self::RELATION_TABLE . '` r, `' . self::TAG_TABLE . '` ' .
|
||||
'WHERE `categoryid` = `id` AND `uid` = ? AND r.`type` = ? AND `objid` IN (?)',
|
||||
[$this->user, $this->type, $chunk],
|
||||
[null, null, IQueryBuilder::PARAM_INT_ARRAY]
|
||||
);
|
||||
$qb->setParameter('uid', $this->user, IQueryBuilder::PARAM_STR);
|
||||
$qb->setParameter('type', $this->type, IQueryBuilder::PARAM_STR);
|
||||
$qb->setParameter('chunk', $chunk, IQueryBuilder::PARAM_INT_ARRAY);
|
||||
$result = $qb->executeQuery();
|
||||
while ($row = $result->fetch()) {
|
||||
$objId = (int)$row['objid'];
|
||||
if (!isset($entries[$objId])) {
|
||||
|
@ -217,11 +199,11 @@ class Tags implements ITags {
|
|||
}
|
||||
$entries[$objId][] = $row['category'];
|
||||
}
|
||||
$result->closeCursor();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\OC::$server->getLogger()->logException($e, [
|
||||
'message' => __METHOD__,
|
||||
'level' => ILogger::ERROR,
|
||||
$this->logger->error($e->getMessage(), [
|
||||
'exception' => $e,
|
||||
'app' => 'core',
|
||||
]);
|
||||
return false;
|
||||
|
@ -236,18 +218,17 @@ class Tags implements ITags {
|
|||
* Throws an exception if the tag could not be found.
|
||||
*
|
||||
* @param string $tag Tag id or name.
|
||||
* @return array|false An array of object ids or false on error.
|
||||
* @return int[]|false An array of object ids or false on error.
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getIdsForTag($tag) {
|
||||
$result = null;
|
||||
$tagId = false;
|
||||
if (is_numeric($tag)) {
|
||||
$tagId = $tag;
|
||||
} elseif (is_string($tag)) {
|
||||
$tag = trim($tag);
|
||||
if ($tag === '') {
|
||||
\OCP\Util::writeLog('core', __METHOD__.', Cannot use empty tag names', ILogger::DEBUG);
|
||||
$this->logger->debug(__METHOD__ . ' Cannot use empty tag names', ['app' => 'core']);
|
||||
return false;
|
||||
}
|
||||
$tagId = $this->getTagId($tag);
|
||||
|
@ -261,32 +242,24 @@ class Tags implements ITags {
|
|||
}
|
||||
|
||||
$ids = [];
|
||||
$sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE
|
||||
. '` WHERE `categoryid` = ?';
|
||||
|
||||
try {
|
||||
$stmt = \OC_DB::prepare($sql);
|
||||
$result = $stmt->execute([$tagId]);
|
||||
if ($result === null) {
|
||||
$stmt->closeCursor();
|
||||
\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
|
||||
return false;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\OC::$server->getLogger()->logException($e, [
|
||||
'message' => __METHOD__,
|
||||
'level' => ILogger::ERROR,
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->select('objid')
|
||||
->from(self::RELATION_TABLE)
|
||||
->where($qb->expr()->eq('categoryid', $qb->createNamedParameter($tagId, IQueryBuilder::PARAM_STR)));
|
||||
$result = $qb->executeQuery();
|
||||
} catch (Exception $e) {
|
||||
$this->logger->error($e->getMessage(), [
|
||||
'app' => 'core',
|
||||
'exception' => $e,
|
||||
]);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_null($result)) {
|
||||
while ($row = $result->fetchRow()) {
|
||||
$ids[] = (int)$row['objid'];
|
||||
}
|
||||
$result->closeCursor();
|
||||
while ($row = $result->fetch()) {
|
||||
$ids[] = (int)$row['objid'];
|
||||
}
|
||||
$result->closeCursor();
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
@ -297,9 +270,8 @@ class Tags implements ITags {
|
|||
*
|
||||
* @param string $name The tag name to check for.
|
||||
* @param string $user The user whose tags are to be checked.
|
||||
* @return bool
|
||||
*/
|
||||
public function userHasTag($name, $user) {
|
||||
public function userHasTag(string $name, string $user): bool {
|
||||
$key = $this->array_searchi($name, $this->getTagsForUser($user));
|
||||
return ($key !== false) ? $this->tags[$key]->getId() : false;
|
||||
}
|
||||
|
@ -308,9 +280,8 @@ class Tags implements ITags {
|
|||
* Checks whether a tag is saved for or shared with the current user.
|
||||
*
|
||||
* @param string $name The tag name to check for.
|
||||
* @return bool
|
||||
*/
|
||||
public function hasTag($name) {
|
||||
public function hasTag(string $name): bool {
|
||||
return $this->getTagId($name) !== false;
|
||||
}
|
||||
|
||||
|
@ -320,15 +291,16 @@ class Tags implements ITags {
|
|||
* @param string $name A string with a name of the tag
|
||||
* @return false|int the id of the added tag or false on error.
|
||||
*/
|
||||
public function add($name) {
|
||||
public function add(string $name) {
|
||||
$name = trim($name);
|
||||
|
||||
if ($name === '') {
|
||||
\OCP\Util::writeLog('core', __METHOD__.', Cannot add an empty tag', ILogger::DEBUG);
|
||||
$this->logger->debug(__METHOD__ . ' Cannot add an empty tag', ['app' => 'core']);
|
||||
return false;
|
||||
}
|
||||
if ($this->userHasTag($name, $this->user)) {
|
||||
\OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', ILogger::DEBUG);
|
||||
// TODO use unique db properties instead of an additional check
|
||||
$this->logger->debug(__METHOD__ . ' Tag with name already exists', ['app' => 'core']);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
|
@ -336,14 +308,13 @@ class Tags implements ITags {
|
|||
$tag = $this->mapper->insert($tag);
|
||||
$this->tags[] = $tag;
|
||||
} catch (\Exception $e) {
|
||||
\OC::$server->getLogger()->logException($e, [
|
||||
'message' => __METHOD__,
|
||||
'level' => ILogger::ERROR,
|
||||
$this->logger->error($e->getMessage(), [
|
||||
'exception' => $e,
|
||||
'app' => 'core',
|
||||
]);
|
||||
return false;
|
||||
}
|
||||
\OCP\Util::writeLog('core', __METHOD__.', id: ' . $tag->getId(), ILogger::DEBUG);
|
||||
$this->logger->debug(__METHOD__ . ' Added an tag with ' . $tag->getId(), ['app' => 'core']);
|
||||
return $tag->getId();
|
||||
}
|
||||
|
||||
|
@ -354,12 +325,12 @@ class Tags implements ITags {
|
|||
* @param string $to The new name of the tag.
|
||||
* @return bool
|
||||
*/
|
||||
public function rename($from, $to) {
|
||||
public function rename($from, string $to): bool {
|
||||
$from = trim($from);
|
||||
$to = trim($to);
|
||||
|
||||
if ($to === '' || $from === '') {
|
||||
\OCP\Util::writeLog('core', __METHOD__.', Cannot use empty tag names', ILogger::DEBUG);
|
||||
$this->logger->debug(__METHOD__ . 'Cannot use an empty tag names', ['app' => 'core']);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -369,13 +340,13 @@ class Tags implements ITags {
|
|||
$key = $this->getTagByName($from);
|
||||
}
|
||||
if ($key === false) {
|
||||
\OCP\Util::writeLog('core', __METHOD__.', tag: ' . $from. ' does not exist', ILogger::DEBUG);
|
||||
$this->logger->debug(__METHOD__ . 'Tag ' . $from . 'does not exist', ['app' => 'core']);
|
||||
return false;
|
||||
}
|
||||
$tag = $this->tags[$key];
|
||||
|
||||
if ($this->userHasTag($to, $tag->getOwner())) {
|
||||
\OCP\Util::writeLog('core', __METHOD__.', A tag named ' . $to. ' already exists for user ' . $tag->getOwner() . '.', ILogger::DEBUG);
|
||||
$this->logger->debug(__METHOD__ . 'A tag named' . $to . 'already exists for user' . $tag->getOwner(), ['app' => 'core']);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -383,9 +354,8 @@ class Tags implements ITags {
|
|||
$tag->setName($to);
|
||||
$this->tags[$key] = $this->mapper->update($tag);
|
||||
} catch (\Exception $e) {
|
||||
\OC::$server->getLogger()->logException($e, [
|
||||
'message' => __METHOD__,
|
||||
'level' => ILogger::ERROR,
|
||||
$this->logger->error($e->getMessage(), [
|
||||
'exception' => $e,
|
||||
'app' => 'core',
|
||||
]);
|
||||
return false;
|
||||
|
@ -396,13 +366,13 @@ class Tags implements ITags {
|
|||
/**
|
||||
* Add a list of new tags.
|
||||
*
|
||||
* @param string[] $names A string with a name or an array of strings containing
|
||||
* @param string|string[] $names A string with a name or an array of strings containing
|
||||
* the name(s) of the tag(s) to add.
|
||||
* @param bool $sync When true, save the tags
|
||||
* @param int|null $id int Optional object id to add to this|these tag(s)
|
||||
* @return bool Returns false on error.
|
||||
*/
|
||||
public function addMultiple($names, $sync = false, $id = null) {
|
||||
public function addMultiple($names, bool $sync = false, ?int $id = null): bool {
|
||||
if (!is_array($names)) {
|
||||
$names = [$names];
|
||||
}
|
||||
|
@ -430,122 +400,50 @@ class Tags implements ITags {
|
|||
/**
|
||||
* Save the list of tags and their object relations
|
||||
*/
|
||||
protected function save() {
|
||||
if (is_array($this->tags)) {
|
||||
foreach ($this->tags as $tag) {
|
||||
try {
|
||||
if (!$this->mapper->tagExists($tag)) {
|
||||
$this->mapper->insert($tag);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\OC::$server->getLogger()->logException($e, [
|
||||
'message' => __METHOD__,
|
||||
'level' => ILogger::ERROR,
|
||||
'app' => 'core',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// reload tags to get the proper ids.
|
||||
$this->tags = $this->mapper->loadTags($this->owners, $this->type);
|
||||
\OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true),
|
||||
ILogger::DEBUG);
|
||||
// Loop through temporarily cached objectid/tagname pairs
|
||||
// and save relations.
|
||||
$tags = $this->tags;
|
||||
// For some reason this is needed or array_search(i) will return 0..?
|
||||
ksort($tags);
|
||||
$dbConnection = \OC::$server->getDatabaseConnection();
|
||||
foreach (self::$relations as $relation) {
|
||||
$tagId = $this->getTagId($relation['tag']);
|
||||
\OCP\Util::writeLog('core', __METHOD__ . 'catid, ' . $relation['tag'] . ' ' . $tagId, ILogger::DEBUG);
|
||||
if ($tagId) {
|
||||
try {
|
||||
$dbConnection->insertIfNotExist(self::RELATION_TABLE,
|
||||
[
|
||||
'objid' => $relation['objid'],
|
||||
'categoryid' => $tagId,
|
||||
'type' => $this->type,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
\OC::$server->getLogger()->logException($e, [
|
||||
'message' => __METHOD__,
|
||||
'level' => ILogger::ERROR,
|
||||
'app' => 'core',
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
self::$relations = []; // reset
|
||||
} else {
|
||||
\OCP\Util::writeLog('core', __METHOD__.', $this->tags is not an array! '
|
||||
. print_r($this->tags, true), ILogger::ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete tags and tag/object relations for a user.
|
||||
*
|
||||
* For hooking up on post_deleteUser
|
||||
*
|
||||
* @param array $arguments
|
||||
*/
|
||||
public static function post_deleteUser($arguments) {
|
||||
// Find all objectid/tagId pairs.
|
||||
$result = null;
|
||||
try {
|
||||
$stmt = \OC_DB::prepare('SELECT `id` FROM `' . self::TAG_TABLE . '` '
|
||||
. 'WHERE `uid` = ?');
|
||||
$result = $stmt->execute([$arguments['uid']]);
|
||||
if ($result === null) {
|
||||
\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\OC::$server->getLogger()->logException($e, [
|
||||
'message' => __METHOD__,
|
||||
'level' => ILogger::ERROR,
|
||||
'app' => 'core',
|
||||
]);
|
||||
}
|
||||
|
||||
if (!is_null($result)) {
|
||||
protected function save(): void {
|
||||
foreach ($this->tags as $tag) {
|
||||
try {
|
||||
$stmt = \OC_DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` '
|
||||
. 'WHERE `categoryid` = ?');
|
||||
while ($row = $result->fetchRow()) {
|
||||
try {
|
||||
$stmt->execute([$row['id']]);
|
||||
} catch (\Exception $e) {
|
||||
\OC::$server->getLogger()->logException($e, [
|
||||
'message' => __METHOD__,
|
||||
'level' => ILogger::ERROR,
|
||||
'app' => 'core',
|
||||
]);
|
||||
}
|
||||
if (!$this->mapper->tagExists($tag)) {
|
||||
$this->mapper->insert($tag);
|
||||
}
|
||||
$result->closeCursor();
|
||||
} catch (\Exception $e) {
|
||||
\OC::$server->getLogger()->logException($e, [
|
||||
'message' => __METHOD__,
|
||||
'level' => ILogger::ERROR,
|
||||
$this->logger->error($e->getMessage(), [
|
||||
'exception' => $e,
|
||||
'app' => 'core',
|
||||
]);
|
||||
}
|
||||
}
|
||||
try {
|
||||
$stmt = \OC_DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` '
|
||||
. 'WHERE `uid` = ?');
|
||||
$result = $stmt->execute([$arguments['uid']]);
|
||||
if ($result === null) {
|
||||
\OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
|
||||
|
||||
// reload tags to get the proper ids.
|
||||
$this->tags = $this->mapper->loadTags($this->owners, $this->type);
|
||||
$this->logger->debug(__METHOD__ . 'tags' . print_r($this->tags, true), ['app' => 'core']);
|
||||
// Loop through temporarily cached objectid/tagname pairs
|
||||
// and save relations.
|
||||
$tags = $this->tags;
|
||||
// For some reason this is needed or array_search(i) will return 0..?
|
||||
ksort($tags);
|
||||
foreach (self::$relations as $relation) {
|
||||
$tagId = $this->getTagId($relation['tag']);
|
||||
$this->logger->debug(__METHOD__ . 'catid ' . $relation['tag'] . ' ' . $tagId, ['app' => 'core']);
|
||||
if ($tagId) {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->insert(self::RELATION_TABLE)
|
||||
->values([
|
||||
'objid' => $qb->createNamedParameter($relation['objid'], IQueryBuilder::PARAM_INT),
|
||||
'categoryid' => $qb->createNamedParameter($tagId, IQueryBuilder::PARAM_INT),
|
||||
'type' => $qb->createNamedParameter($this->type),
|
||||
]);
|
||||
try {
|
||||
$qb->executeStatement();
|
||||
} catch (Exception $e) {
|
||||
$this->logger->error($e->getMessage(), [
|
||||
'exception' => $e,
|
||||
'app' => 'core',
|
||||
]);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\OC::$server->getLogger()->logException($e, [
|
||||
'message' => __METHOD__,
|
||||
'level' => ILogger::ERROR,
|
||||
'app' => 'core',
|
||||
]);
|
||||
}
|
||||
self::$relations = []; // reset
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -554,28 +452,21 @@ class Tags implements ITags {
|
|||
* @param array $ids The ids of the objects
|
||||
* @return boolean Returns false on error.
|
||||
*/
|
||||
public function purgeObjects(array $ids) {
|
||||
public function purgeObjects(array $ids): bool {
|
||||
if (count($ids) === 0) {
|
||||
// job done ;)
|
||||
return true;
|
||||
}
|
||||
$updates = $ids;
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->delete(self::RELATION_TABLE)
|
||||
->where($qb->expr()->in('objid', $qb->createNamedParameter($ids)));
|
||||
try {
|
||||
$query = 'DELETE FROM `' . self::RELATION_TABLE . '` ';
|
||||
$query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids) - 1) . '?) ';
|
||||
$query .= 'AND `type`= ?';
|
||||
$updates[] = $this->type;
|
||||
$stmt = \OC_DB::prepare($query);
|
||||
$result = $stmt->execute($updates);
|
||||
if ($result === null) {
|
||||
\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
|
||||
return false;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\OC::$server->getLogger()->logException($e, [
|
||||
'message' => __METHOD__,
|
||||
'level' => ILogger::ERROR,
|
||||
$qb->executeStatement();
|
||||
} catch (Exception $e) {
|
||||
$this->logger->error($e->getMessage(), [
|
||||
'app' => 'core',
|
||||
'exception' => $e,
|
||||
]);
|
||||
return false;
|
||||
}
|
||||
|
@ -648,18 +539,19 @@ class Tags implements ITags {
|
|||
} else {
|
||||
$tagId = $tag;
|
||||
}
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->insert(self::RELATION_TABLE)
|
||||
->values([
|
||||
'objid' => $qb->createNamedParameter($objid, IQueryBuilder::PARAM_INT),
|
||||
'categoryid' => $qb->createNamedParameter($tagId, IQueryBuilder::PARAM_INT),
|
||||
'type' => $qb->createNamedParameter($this->type, IQueryBuilder::PARAM_STR),
|
||||
]);
|
||||
try {
|
||||
\OC::$server->getDatabaseConnection()->insertIfNotExist(self::RELATION_TABLE,
|
||||
[
|
||||
'objid' => $objid,
|
||||
'categoryid' => $tagId,
|
||||
'type' => $this->type,
|
||||
]);
|
||||
$qb->executeStatement();
|
||||
} catch (\Exception $e) {
|
||||
\OC::$server->getLogger()->logException($e, [
|
||||
'message' => __METHOD__,
|
||||
'level' => ILogger::ERROR,
|
||||
\OC::$server->getLogger()->error($e->getMessage(), [
|
||||
'app' => 'core',
|
||||
'exception' => $e,
|
||||
]);
|
||||
return false;
|
||||
}
|
||||
|
@ -686,15 +578,17 @@ class Tags implements ITags {
|
|||
}
|
||||
|
||||
try {
|
||||
$sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
|
||||
. 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?';
|
||||
$stmt = \OC_DB::prepare($sql);
|
||||
$stmt->execute([$objid, $tagId, $this->type]);
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->delete(self::RELATION_TABLE)
|
||||
->where($qb->expr()->andX(
|
||||
$qb->expr()->eq('objid', $qb->createNamedParameter($objid)),
|
||||
$qb->expr()->eq('categoryid', $qb->createNamedParameter($tagId)),
|
||||
$qb->expr()->eq('type', $qb->createNamedParameter($this->type)),
|
||||
))->executeStatement();
|
||||
} catch (\Exception $e) {
|
||||
\OC::$server->getLogger()->logException($e, [
|
||||
'message' => __METHOD__,
|
||||
'level' => ILogger::ERROR,
|
||||
$this->logger->error($e->getMessage(), [
|
||||
'app' => 'core',
|
||||
'exception' => $e,
|
||||
]);
|
||||
return false;
|
||||
}
|
||||
|
@ -736,21 +630,14 @@ class Tags implements ITags {
|
|||
}
|
||||
if (!is_null($id) && $id !== false) {
|
||||
try {
|
||||
$sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
|
||||
. 'WHERE `categoryid` = ?';
|
||||
$stmt = \OC_DB::prepare($sql);
|
||||
$result = $stmt->execute([$id]);
|
||||
if ($result === null) {
|
||||
\OCP\Util::writeLog('core',
|
||||
__METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(),
|
||||
ILogger::ERROR);
|
||||
return false;
|
||||
}
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->delete(self::RELATION_TABLE)
|
||||
->where($qb->expr()->eq('categoryid', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)))
|
||||
->executeStatement();
|
||||
} catch (\Exception $e) {
|
||||
\OC::$server->getLogger()->logException($e, [
|
||||
'message' => __METHOD__,
|
||||
'level' => ILogger::ERROR,
|
||||
$this->logger->error($e->getMessage(), [
|
||||
'app' => 'core',
|
||||
'exception' => $e,
|
||||
]);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,184 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
||||
*
|
||||
* @author Andreas Fischer <bantu@owncloud.com>
|
||||
* @author Bart Visscher <bartv@thisnet.nl>
|
||||
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
* @author Joas Schilling <coding@schilljs.com>
|
||||
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
|
||||
* @author Lukas Reschke <lukas@statuscode.ch>
|
||||
* @author Morris Jobke <hey@morrisjobke.de>
|
||||
* @author Robin Appelman <robin@icewind.nl>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
* @author Vincent Petry <vincent@nextcloud.com>
|
||||
*
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
class OC_DB {
|
||||
|
||||
/**
|
||||
* Prepare a SQL query
|
||||
* @param string $query Query string
|
||||
* @param int|null $limit
|
||||
* @param int|null $offset
|
||||
* @param bool|null $isManipulation
|
||||
* @throws \OC\DatabaseException
|
||||
* @return OC_DB_StatementWrapper prepared SQL query
|
||||
* @deprecated 21.0.0 Please use \OCP\IDBConnection::getQueryBuilder() instead
|
||||
*
|
||||
* SQL query via Doctrine prepare(), needs to be execute()'d!
|
||||
*/
|
||||
public static function prepare($query, $limit = null, $offset = null, $isManipulation = null) {
|
||||
$connection = \OC::$server->getDatabaseConnection();
|
||||
|
||||
if ($isManipulation === null) {
|
||||
//try to guess, so we return the number of rows on manipulations
|
||||
$isManipulation = self::isManipulation($query);
|
||||
}
|
||||
|
||||
// return the result
|
||||
try {
|
||||
$result = $connection->prepare($query, $limit, $offset);
|
||||
} catch (\Doctrine\DBAL\Exception $e) {
|
||||
throw new \OC\DatabaseException($e->getMessage());
|
||||
}
|
||||
// differentiate between query and manipulation
|
||||
return new OC_DB_StatementWrapper($result, $isManipulation);
|
||||
}
|
||||
|
||||
/**
|
||||
* tries to guess the type of statement based on the first 10 characters
|
||||
* the current check allows some whitespace but does not work with IF EXISTS or other more complex statements
|
||||
*
|
||||
* @param string $sql
|
||||
* @return bool
|
||||
*/
|
||||
public static function isManipulation($sql) {
|
||||
$sql = trim($sql);
|
||||
$selectOccurrence = stripos($sql, 'SELECT');
|
||||
if ($selectOccurrence === 0) {
|
||||
return false;
|
||||
}
|
||||
$insertOccurrence = stripos($sql, 'INSERT');
|
||||
if ($insertOccurrence === 0) {
|
||||
return true;
|
||||
}
|
||||
$updateOccurrence = stripos($sql, 'UPDATE');
|
||||
if ($updateOccurrence === 0) {
|
||||
return true;
|
||||
}
|
||||
$deleteOccurrence = stripos($sql, 'DELETE');
|
||||
if ($deleteOccurrence === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is triggered with "SHOW VERSION" and some more, so until we made a list, we keep this out.
|
||||
// \OC::$server->getLogger()->logException(new \Exception('Can not detect if query is manipulating: ' . $sql));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* execute a prepared statement, on error write log and throw exception
|
||||
* @param mixed $stmt OC_DB_StatementWrapper,
|
||||
* an array with 'sql' and optionally 'limit' and 'offset' keys
|
||||
* .. or a simple sql query string
|
||||
* @param array $parameters
|
||||
* @return OC_DB_StatementWrapper
|
||||
* @throws \OC\DatabaseException
|
||||
* @deprecated 21.0.0 Please use \OCP\IDBConnection::getQueryBuilder() instead
|
||||
*/
|
||||
public static function executeAudited($stmt, array $parameters = []) {
|
||||
if (is_string($stmt)) {
|
||||
// convert to an array with 'sql'
|
||||
if (stripos($stmt, 'LIMIT') !== false) { //OFFSET requires LIMIT, so we only need to check for LIMIT
|
||||
// TODO try to convert LIMIT OFFSET notation to parameters
|
||||
$message = 'LIMIT and OFFSET are forbidden for portability reasons,'
|
||||
. ' pass an array with \'limit\' and \'offset\' instead';
|
||||
throw new \OC\DatabaseException($message);
|
||||
}
|
||||
$stmt = ['sql' => $stmt, 'limit' => null, 'offset' => null];
|
||||
}
|
||||
if (is_array($stmt)) {
|
||||
// convert to prepared statement
|
||||
if (! array_key_exists('sql', $stmt)) {
|
||||
$message = 'statement array must at least contain key \'sql\'';
|
||||
throw new \OC\DatabaseException($message);
|
||||
}
|
||||
if (! array_key_exists('limit', $stmt)) {
|
||||
$stmt['limit'] = null;
|
||||
}
|
||||
if (! array_key_exists('limit', $stmt)) {
|
||||
$stmt['offset'] = null;
|
||||
}
|
||||
$stmt = self::prepare($stmt['sql'], $stmt['limit'], $stmt['offset']);
|
||||
}
|
||||
self::raiseExceptionOnError($stmt, 'Could not prepare statement');
|
||||
if ($stmt instanceof OC_DB_StatementWrapper) {
|
||||
$result = $stmt->execute($parameters);
|
||||
self::raiseExceptionOnError($result, 'Could not execute statement');
|
||||
} else {
|
||||
if (is_object($stmt)) {
|
||||
$message = 'Expected a prepared statement or array got ' . get_class($stmt);
|
||||
} else {
|
||||
$message = 'Expected a prepared statement or array got ' . gettype($stmt);
|
||||
}
|
||||
throw new \OC\DatabaseException($message);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if a result is an error and throws an exception, works with \Doctrine\DBAL\Exception
|
||||
* @param mixed $result
|
||||
* @param string $message
|
||||
* @return void
|
||||
* @throws \OC\DatabaseException
|
||||
*/
|
||||
public static function raiseExceptionOnError($result, $message = null) {
|
||||
if ($result === false) {
|
||||
if ($message === null) {
|
||||
$message = self::getErrorMessage();
|
||||
} else {
|
||||
$message .= ', Root cause:' . self::getErrorMessage();
|
||||
}
|
||||
throw new \OC\DatabaseException($message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the error code and message as a string for logging
|
||||
* works with DoctrineException
|
||||
* @return string
|
||||
*/
|
||||
public static function getErrorMessage() {
|
||||
$connection = \OC::$server->getDatabaseConnection();
|
||||
return $connection->getError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a table exists in the database - the database prefix will be prepended
|
||||
*
|
||||
* @param string $table
|
||||
* @return bool
|
||||
* @throws \OC\DatabaseException
|
||||
*/
|
||||
public static function tableExists($table) {
|
||||
$connection = \OC::$server->getDatabaseConnection();
|
||||
return $connection->tableExists($table);
|
||||
}
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
||||
*
|
||||
* @author Bart Visscher <bartv@thisnet.nl>
|
||||
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
* @author Joas Schilling <coding@schilljs.com>
|
||||
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
|
||||
* @author Lukas Reschke <lukas@statuscode.ch>
|
||||
* @author Morris Jobke <hey@morrisjobke.de>
|
||||
* @author Robin Appelman <robin@icewind.nl>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
*
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
use OCP\DB\IPreparedStatement;
|
||||
|
||||
/**
|
||||
* small wrapper around \Doctrine\DBAL\Driver\Statement to make it behave, more like an MDB2 Statement
|
||||
*
|
||||
* @method boolean bindValue(mixed $param, mixed $value, integer $type = null);
|
||||
* @method string errorCode();
|
||||
* @method array errorInfo();
|
||||
* @method integer rowCount();
|
||||
* @method array fetchAll(integer $fetchMode = null);
|
||||
*/
|
||||
class OC_DB_StatementWrapper {
|
||||
/** @var IPreparedStatement */
|
||||
private $statement = null;
|
||||
|
||||
/** @var bool */
|
||||
private $isManipulation = false;
|
||||
|
||||
/** @var array */
|
||||
private $lastArguments = [];
|
||||
|
||||
/**
|
||||
* @param IPreparedStatement $statement
|
||||
* @param boolean $isManipulation
|
||||
*/
|
||||
public function __construct(IPreparedStatement $statement, $isManipulation) {
|
||||
$this->statement = $statement;
|
||||
$this->isManipulation = $isManipulation;
|
||||
}
|
||||
|
||||
/**
|
||||
* pass all other function directly to the \Doctrine\DBAL\Driver\Statement
|
||||
*/
|
||||
public function __call($name, $arguments) {
|
||||
return call_user_func_array([$this->statement,$name], $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* make execute return the result instead of a bool
|
||||
*
|
||||
* @param mixed[] $input
|
||||
* @return \OC_DB_StatementWrapper|int|bool
|
||||
* @deprecated
|
||||
*/
|
||||
public function execute($input = []) {
|
||||
$this->lastArguments = $input;
|
||||
try {
|
||||
if (count($input) > 0) {
|
||||
$result = $this->statement->execute($input);
|
||||
} else {
|
||||
$result = $this->statement->execute();
|
||||
}
|
||||
} catch (\Doctrine\DBAL\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->isManipulation) {
|
||||
return $this->statement->rowCount();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* provide an alias for fetch
|
||||
*
|
||||
* @return mixed
|
||||
* @deprecated
|
||||
*/
|
||||
public function fetchRow() {
|
||||
return $this->statement->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a simple fetchOne.
|
||||
*
|
||||
* fetch single column from the next row
|
||||
* @return string
|
||||
* @deprecated
|
||||
*/
|
||||
public function fetchOne() {
|
||||
return $this->statement->fetchOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the cursor, enabling the statement to be executed again.
|
||||
*
|
||||
* @deprecated Use Result::free() instead.
|
||||
*/
|
||||
public function closeCursor(): void {
|
||||
$this->statement->closeCursor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a PHP variable to a corresponding named or question mark placeholder in the
|
||||
* SQL statement that was use to prepare the statement.
|
||||
*
|
||||
* @param mixed $column Either the placeholder name or the 1-indexed placeholder index
|
||||
* @param mixed $variable The variable to bind
|
||||
* @param integer|null $type one of the PDO::PARAM_* constants
|
||||
* @param integer|null $length max length when using an OUT bind
|
||||
* @return boolean
|
||||
*/
|
||||
public function bindParam($column, &$variable, $type = null, $length = null) {
|
||||
return $this->statement->bindParam($column, $variable, $type, $length);
|
||||
}
|
||||
}
|
|
@ -69,6 +69,7 @@ use OC\AppFramework\Http\Request;
|
|||
use OC\Files\SetupManager;
|
||||
use OCP\Files\Template\ITemplateManager;
|
||||
use OCP\IConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUser;
|
||||
|
@ -749,9 +750,13 @@ class OC_Util {
|
|||
$dbType = \OC::$server->getSystemConfig()->getValue('dbtype', 'sqlite');
|
||||
if ($dbType === 'pgsql') {
|
||||
// check PostgreSQL version
|
||||
// TODO latest postgresql 8 released was 8 years ago, maybe remove the
|
||||
// check completely?
|
||||
try {
|
||||
$result = \OC_DB::executeAudited('SHOW SERVER_VERSION');
|
||||
$data = $result->fetchRow();
|
||||
/** @var IDBConnection $connection */
|
||||
$connection = \OC::$server->get(IDBConnection::class);
|
||||
$result = $connection->executeQuery('SHOW SERVER_VERSION');
|
||||
$data = $result->fetch();
|
||||
$result->closeCursor();
|
||||
if (isset($data['server_version'])) {
|
||||
$version = $data['server_version'];
|
||||
|
|
|
@ -32,9 +32,6 @@ namespace OCP;
|
|||
|
||||
use OC\Tags;
|
||||
|
||||
// FIXME: Where should I put this? Or should it be implemented as a Listener?
|
||||
\OC_Hook::connect('OC_User', 'post_deleteUser', Tags::class, 'post_deleteUser');
|
||||
|
||||
/**
|
||||
* Class for easily tagging objects by their id
|
||||
*
|
||||
|
@ -55,11 +52,9 @@ interface ITags {
|
|||
|
||||
/**
|
||||
* Check if any tags are saved for this type and user.
|
||||
*
|
||||
* @return boolean
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public function isEmpty();
|
||||
public function isEmpty(): bool;
|
||||
|
||||
/**
|
||||
* Returns an array mapping a given tag's properties to its values:
|
||||
|
@ -69,34 +64,40 @@ interface ITags {
|
|||
* @return array|false
|
||||
* @since 8.0.0
|
||||
*/
|
||||
public function getTag($id);
|
||||
public function getTag(string $id);
|
||||
|
||||
/**
|
||||
* Get the tags for a specific user.
|
||||
*
|
||||
* This returns an array with id/name maps:
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* ['id' => 0, 'name' = 'First tag'],
|
||||
* ['id' => 1, 'name' = 'Second tag'],
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* @return array
|
||||
* @return array<array-key, array{id: int, name: string}>
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public function getTags();
|
||||
public function getTags(): array;
|
||||
|
||||
/**
|
||||
* Get a list of tags for the given item ids.
|
||||
*
|
||||
* This returns an array with object id / tag names:
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* 1 => array('First tag', 'Second tag'),
|
||||
* 2 => array('Second tag'),
|
||||
* 3 => array('Second tag', 'Third tag'),
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* @param array $objIds item ids
|
||||
* @return array|boolean with object id as key and an array
|
||||
* @return array|false with object id as key and an array
|
||||
* of tag names as value or false if an error occurred
|
||||
* @since 8.0.0
|
||||
*/
|
||||
|
@ -117,10 +118,9 @@ interface ITags {
|
|||
* Checks whether a tag is already saved.
|
||||
*
|
||||
* @param string $name The name to check for.
|
||||
* @return bool
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public function hasTag($name);
|
||||
public function hasTag(string $name): bool;
|
||||
|
||||
/**
|
||||
* Checks whether a tag is saved for the given user,
|
||||
|
@ -131,7 +131,7 @@ interface ITags {
|
|||
* @return bool
|
||||
* @since 8.0.0
|
||||
*/
|
||||
public function userHasTag($name, $user);
|
||||
public function userHasTag(string $name, string $user): bool;
|
||||
|
||||
/**
|
||||
* Add a new tag.
|
||||
|
@ -140,7 +140,7 @@ interface ITags {
|
|||
* @return int|false the id of the added tag or false if it already exists.
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public function add($name);
|
||||
public function add(string $name);
|
||||
|
||||
/**
|
||||
* Rename tag.
|
||||
|
@ -150,19 +150,19 @@ interface ITags {
|
|||
* @return bool
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public function rename($from, $to);
|
||||
public function rename($from, string $to): bool;
|
||||
|
||||
/**
|
||||
* Add a list of new tags.
|
||||
*
|
||||
* @param string[] $names A string with a name or an array of strings containing
|
||||
* @param string|string[] $names A string with a name or an array of strings containing
|
||||
* the name(s) of the to add.
|
||||
* @param bool $sync When true, save the tags
|
||||
* @param int|null $id int Optional object id to add to this|these tag(s)
|
||||
* @return bool Returns false on error.
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public function addMultiple($names, $sync = false, $id = null);
|
||||
public function addMultiple($names, bool $sync = false, ?int $id = null): bool;
|
||||
|
||||
/**
|
||||
* Delete tag/object relations from the db
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
|
||||
namespace Test\Share;
|
||||
|
||||
use OC\Share\Share;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IGroup;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUser;
|
||||
|
@ -35,36 +38,25 @@ use OCP\Share\IShare;
|
|||
class ShareTest extends \Test\TestCase {
|
||||
protected $itemType;
|
||||
|
||||
/** @var IUser */
|
||||
protected $user1;
|
||||
/** @var IUser */
|
||||
protected $user2;
|
||||
/** @var IUser */
|
||||
protected $user3;
|
||||
/** @var IUser */
|
||||
protected $user4;
|
||||
/** @var IUser */
|
||||
protected $user5;
|
||||
/** @var IUser */
|
||||
protected $user6;
|
||||
/** @var IUser */
|
||||
protected $groupAndUser_user;
|
||||
protected IUser $user1;
|
||||
protected IUser $user2;
|
||||
protected IUser $user3;
|
||||
protected IUser $user4;
|
||||
protected IUser $user5;
|
||||
protected IUser $user6;
|
||||
protected IUser $groupAndUser_user;
|
||||
|
||||
/** @var IGroup */
|
||||
protected $group1;
|
||||
/** @var IGroup */
|
||||
protected $group2;
|
||||
/** @var IGroup */
|
||||
protected $groupAndUser_group;
|
||||
protected IGroup $group1;
|
||||
protected IGroup $group2;
|
||||
protected IGroup $groupAndUser_group;
|
||||
|
||||
protected $resharing;
|
||||
protected $dateInFuture;
|
||||
protected $dateInPast;
|
||||
protected string $resharing;
|
||||
protected string $dateInFuture;
|
||||
protected string $dateInPast;
|
||||
|
||||
/** @var IGroupManager */
|
||||
protected $groupManager;
|
||||
/** @var IUserManager */
|
||||
protected $userManager;
|
||||
protected IGroupManager $groupManager;
|
||||
protected IUserManager $userManager;
|
||||
private IDBConnection $connection;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
@ -90,6 +82,7 @@ class ShareTest extends \Test\TestCase {
|
|||
$this->group1 = $this->groupManager->createGroup($this->getUniqueID('group1_'));
|
||||
$this->group2 = $this->groupManager->createGroup($this->getUniqueID('group2_'));
|
||||
$this->groupAndUser_group = $this->groupManager->createGroup($groupAndUserId);
|
||||
$this->connection = \OC::$server->get(IDBConnection::class);
|
||||
|
||||
$this->group1->addUser($this->user1);
|
||||
$this->group1->addUser($this->user2);
|
||||
|
@ -99,7 +92,7 @@ class ShareTest extends \Test\TestCase {
|
|||
$this->groupAndUser_group->addUser($this->user2);
|
||||
$this->groupAndUser_group->addUser($this->user3);
|
||||
|
||||
\OC\Share\Share::registerBackend('test', 'Test\Share\Backend');
|
||||
Share::registerBackend('test', 'Test\Share\Backend');
|
||||
\OC_Hook::clear('OCP\\Share');
|
||||
\OC::registerShareHooks(\OC::$server->getSystemConfig());
|
||||
$this->resharing = \OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_resharing', 'yes');
|
||||
|
@ -113,8 +106,9 @@ class ShareTest extends \Test\TestCase {
|
|||
}
|
||||
|
||||
protected function tearDown(): void {
|
||||
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `item_type` = ?');
|
||||
$query->execute(['test']);
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->delete('share')->andWhere($query->expr()->eq('item_type', $query->createNamedParameter('test')));
|
||||
$query->executeStatement();
|
||||
\OC::$server->getConfig()->setAppValue('core', 'shareapi_allow_resharing', $this->resharing);
|
||||
|
||||
$this->user1->delete();
|
||||
|
@ -136,39 +130,51 @@ class ShareTest extends \Test\TestCase {
|
|||
public function testGetItemSharedWithUser() {
|
||||
\OC_User::setUserId($this->user1->getUID());
|
||||
|
||||
//add dummy values to the share table
|
||||
$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` ('
|
||||
.' `item_type`, `item_source`, `item_target`, `share_type`,'
|
||||
.' `share_with`, `uid_owner`) VALUES (?,?,?,?,?,?)');
|
||||
$args = ['test', 99, 'target1', IShare::TYPE_USER, $this->user2->getUID(), $this->user1->getUID()];
|
||||
$query->execute($args);
|
||||
$args = ['test', 99, 'target2', IShare::TYPE_USER, $this->user4->getUID(), $this->user1->getUID()];
|
||||
$query->execute($args);
|
||||
$args = ['test', 99, 'target3', IShare::TYPE_USER, $this->user3->getUID(), $this->user2->getUID()];
|
||||
$query->execute($args);
|
||||
$args = ['test', 99, 'target4', IShare::TYPE_USER, $this->user3->getUID(), $this->user4->getUID()];
|
||||
$query->execute($args);
|
||||
$args = ['test', 99, 'target4', IShare::TYPE_USER, $this->user6->getUID(), $this->user4->getUID()];
|
||||
$query->execute($args);
|
||||
// add dummy values to the share table
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->insert('share')
|
||||
->values([
|
||||
'item_type' => $query->createParameter('itemType'),
|
||||
'item_source' => $query->createParameter('itemSource'),
|
||||
'item_target' => $query->createParameter('itemTarget'),
|
||||
'share_type' => $query->createParameter('shareType'),
|
||||
'share_with' => $query->createParameter('shareWith'),
|
||||
'uid_owner' => $query->createParameter('uidOwner')
|
||||
]);
|
||||
$args = [
|
||||
['test', 99, 'target1', IShare::TYPE_USER, $this->user2->getUID(), $this->user1->getUID()],
|
||||
['test', 99, 'target2', IShare::TYPE_USER, $this->user4->getUID(), $this->user1->getUID()],
|
||||
['test', 99, 'target3', IShare::TYPE_USER, $this->user3->getUID(), $this->user2->getUID()],
|
||||
['test', 99, 'target4', IShare::TYPE_USER, $this->user3->getUID(), $this->user4->getUID()],
|
||||
['test', 99, 'target4', IShare::TYPE_USER, $this->user6->getUID(), $this->user4->getUID()],
|
||||
];
|
||||
foreach ($args as $row) {
|
||||
$query->setParameter('itemType', $row[0]);
|
||||
$query->setParameter('itemSource', $row[1], IQueryBuilder::PARAM_INT);
|
||||
$query->setParameter('itemTarget', $row[2]);
|
||||
$query->setParameter('shareType', $row[3], IQueryBuilder::PARAM_INT);
|
||||
$query->setParameter('shareWith', $row[4]);
|
||||
$query->setParameter('uidOwner', $row[5]);
|
||||
$query->executeStatement();
|
||||
}
|
||||
|
||||
|
||||
$result1 = \OCP\Share::getItemSharedWithUser('test', 99, $this->user2->getUID(), $this->user1->getUID());
|
||||
$result1 = Share::getItemSharedWithUser('test', 99, $this->user2->getUID(), $this->user1->getUID());
|
||||
$this->assertSame(1, count($result1));
|
||||
$this->verifyResult($result1, ['target1']);
|
||||
|
||||
$result2 = \OCP\Share::getItemSharedWithUser('test', 99, null, $this->user1->getUID());
|
||||
$result2 = Share::getItemSharedWithUser('test', 99, null, $this->user1->getUID());
|
||||
$this->assertSame(2, count($result2));
|
||||
$this->verifyResult($result2, ['target1', 'target2']);
|
||||
|
||||
$result3 = \OCP\Share::getItemSharedWithUser('test', 99, $this->user3->getUID());
|
||||
$result3 = Share::getItemSharedWithUser('test', 99, $this->user3->getUID());
|
||||
$this->assertSame(2, count($result3));
|
||||
$this->verifyResult($result3, ['target3', 'target4']);
|
||||
|
||||
$result4 = \OCP\Share::getItemSharedWithUser('test', 99, null, null);
|
||||
$result4 = Share::getItemSharedWithUser('test', 99, null, null);
|
||||
$this->assertSame(5, count($result4)); // 5 because target4 appears twice
|
||||
$this->verifyResult($result4, ['target1', 'target2', 'target3', 'target4']);
|
||||
|
||||
$result6 = \OCP\Share::getItemSharedWithUser('test', 99, $this->user6->getUID(), null);
|
||||
$result6 = Share::getItemSharedWithUser('test', 99, $this->user6->getUID(), null);
|
||||
$this->assertSame(1, count($result6));
|
||||
$this->verifyResult($result6, ['target4']);
|
||||
}
|
||||
|
@ -176,38 +182,52 @@ class ShareTest extends \Test\TestCase {
|
|||
public function testGetItemSharedWithUserFromGroupShare() {
|
||||
\OC_User::setUserId($this->user1->getUID());
|
||||
|
||||
//add dummy values to the share table
|
||||
$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` ('
|
||||
.' `item_type`, `item_source`, `item_target`, `share_type`,'
|
||||
.' `share_with`, `uid_owner`) VALUES (?,?,?,?,?,?)');
|
||||
$args = ['test', 99, 'target1', IShare::TYPE_GROUP, $this->group1->getGID(), $this->user1->getUID()];
|
||||
$query->execute($args);
|
||||
$args = ['test', 99, 'target2', IShare::TYPE_GROUP, $this->group2->getGID(), $this->user1->getUID()];
|
||||
$query->execute($args);
|
||||
$args = ['test', 99, 'target3', IShare::TYPE_GROUP, $this->group1->getGID(), $this->user2->getUID()];
|
||||
$query->execute($args);
|
||||
$args = ['test', 99, 'target4', IShare::TYPE_GROUP, $this->group1->getGID(), $this->user4->getUID()];
|
||||
$query->execute($args);
|
||||
// add dummy values to the share table
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->insert('share')
|
||||
->values([
|
||||
'item_type' => $query->createParameter('itemType'),
|
||||
'item_source' => $query->createParameter('itemSource'),
|
||||
'item_target' => $query->createParameter('itemTarget'),
|
||||
'share_type' => $query->createParameter('shareType'),
|
||||
'share_with' => $query->createParameter('shareWith'),
|
||||
'uid_owner' => $query->createParameter('uidOwner')
|
||||
]);
|
||||
$args = [
|
||||
['test', 99, 'target1', IShare::TYPE_GROUP, $this->group1->getGID(), $this->user1->getUID()],
|
||||
['test', 99, 'target2', IShare::TYPE_GROUP, $this->group2->getGID(), $this->user1->getUID()],
|
||||
['test', 99, 'target3', IShare::TYPE_GROUP, $this->group1->getGID(), $this->user2->getUID()],
|
||||
['test', 99, 'target4', IShare::TYPE_GROUP, $this->group1->getGID(), $this->user4->getUID()],
|
||||
];
|
||||
foreach ($args as $row) {
|
||||
$query->setParameter('itemType', $row[0]);
|
||||
$query->setParameter('itemSource', $row[1], IQueryBuilder::PARAM_INT);
|
||||
$query->setParameter('itemTarget', $row[2]);
|
||||
$query->setParameter('shareType', $row[3], IQueryBuilder::PARAM_INT);
|
||||
$query->setParameter('shareWith', $row[4]);
|
||||
$query->setParameter('uidOwner', $row[5]);
|
||||
$query->executeStatement();
|
||||
}
|
||||
|
||||
// user2 is in group1 and group2
|
||||
$result1 = \OCP\Share::getItemSharedWithUser('test', 99, $this->user2->getUID(), $this->user1->getUID());
|
||||
$result1 = Share::getItemSharedWithUser('test', 99, $this->user2->getUID(), $this->user1->getUID());
|
||||
$this->assertSame(2, count($result1));
|
||||
$this->verifyResult($result1, ['target1', 'target2']);
|
||||
|
||||
$result2 = \OCP\Share::getItemSharedWithUser('test', 99, null, $this->user1->getUID());
|
||||
$result2 = Share::getItemSharedWithUser('test', 99, null, $this->user1->getUID());
|
||||
$this->assertSame(2, count($result2));
|
||||
$this->verifyResult($result2, ['target1', 'target2']);
|
||||
|
||||
// user3 is in group1 and group2
|
||||
$result3 = \OCP\Share::getItemSharedWithUser('test', 99, $this->user3->getUID());
|
||||
$result3 = Share::getItemSharedWithUser('test', 99, $this->user3->getUID());
|
||||
$this->assertSame(3, count($result3));
|
||||
$this->verifyResult($result3, ['target1', 'target3', 'target4']);
|
||||
|
||||
$result4 = \OCP\Share::getItemSharedWithUser('test', 99, null, null);
|
||||
$result4 = Share::getItemSharedWithUser('test', 99, null, null);
|
||||
$this->assertSame(4, count($result4));
|
||||
$this->verifyResult($result4, ['target1', 'target2', 'target3', 'target4']);
|
||||
|
||||
$result6 = \OCP\Share::getItemSharedWithUser('test', 99, $this->user6->getUID(), null);
|
||||
$result6 = Share::getItemSharedWithUser('test', 99, $this->user6->getUID(), null);
|
||||
$this->assertSame(0, count($result6));
|
||||
}
|
||||
|
||||
|
@ -227,7 +247,7 @@ class ShareTest extends \Test\TestCase {
|
|||
* @param string $expectedResult
|
||||
*/
|
||||
public function testRemoveProtocolFromUrl($url, $expectedResult) {
|
||||
$share = new \OC\Share\Share();
|
||||
$share = new Share();
|
||||
$result = self::invokePrivate($share, 'removeProtocolFromUrl', [$url]);
|
||||
$this->assertSame($expectedResult, $result);
|
||||
}
|
||||
|
@ -316,7 +336,7 @@ class ShareTest extends \Test\TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
class DummyShareClass extends \OC\Share\Share {
|
||||
class DummyShareClass extends Share {
|
||||
public static function groupItemsTest($items) {
|
||||
return parent::groupItems($items, 'test');
|
||||
}
|
||||
|
|
|
@ -22,8 +22,10 @@
|
|||
|
||||
namespace Test;
|
||||
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserSession;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Class TagsTest
|
||||
|
@ -60,8 +62,8 @@ class TagsTest extends \Test\TestCase {
|
|||
->willReturn($this->user);
|
||||
|
||||
$this->objectType = $this->getUniqueID('type_');
|
||||
$this->tagMapper = new \OC\Tagging\TagMapper(\OC::$server->getDatabaseConnection());
|
||||
$this->tagMgr = new \OC\TagManager($this->tagMapper, $this->userSession, \OC::$server->getDatabaseConnection());
|
||||
$this->tagMapper = new \OC\Tagging\TagMapper(\OC::$server->get(IDBConnection::class));
|
||||
$this->tagMgr = new \OC\TagManager($this->tagMapper, $this->userSession, \OC::$server->get(IDBConnection::class), \OC::$server->get(LoggerInterface::class));
|
||||
}
|
||||
|
||||
protected function tearDown(): void {
|
||||
|
@ -78,7 +80,7 @@ class TagsTest extends \Test\TestCase {
|
|||
->expects($this->any())
|
||||
->method('getUser')
|
||||
->willReturn(null);
|
||||
$this->tagMgr = new \OC\TagManager($this->tagMapper, $this->userSession, \OC::$server->getDatabaseConnection());
|
||||
$this->tagMgr = new \OC\TagManager($this->tagMapper, $this->userSession, \OC::$server->getDatabaseConnection(), \OC::$server->get(LoggerInterface::class));
|
||||
$this->assertNull($this->tagMgr->load($this->objectType));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue