diff --git a/core/Application.php b/core/Application.php
index 34932cab18399..4e56502f1d1c0 100644
--- a/core/Application.php
+++ b/core/Application.php
@@ -49,7 +49,11 @@
use OC\DB\MissingPrimaryKeyInformation;
use OC\DB\SchemaWrapper;
use OC\Metadata\FileEventListener;
+use OC\TagManager;
use OCP\AppFramework\App;
+use OCP\AppFramework\Bootstrap\IBootContext;
+use OCP\AppFramework\Bootstrap\IBootstrap;
+use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Events\Node\NodeDeletedEvent;
use OCP\Files\Events\Node\NodeWrittenEvent;
@@ -307,14 +311,20 @@ function (GenericEvent $event) use ($container) {
$eventDispatcher->addServiceListener(UserDeletedEvent::class, UserDeletedFilesCleanupListener::class);
$eventDispatcher->addServiceListener(UserDeletedEvent::class, UserDeletedWebAuthnCleanupListener::class);
+ /** @var IEventDispatcher $eventDispatcher */
+ $newEventDispatcher = \OC::$server->get(IEventDispatcher::class);
+
// Metadata
/** @var IConfig $config */
$config = $container->get(IConfig::class);
if ($config->getSystemValueBool('enable_file_metadata', true)) {
- $eventDispatcher = \OC::$server->get(IEventDispatcher::class);
- $eventDispatcher->addServiceListener(NodeDeletedEvent::class, FileEventListener::class);
- $eventDispatcher->addServiceListener(NodeRemovedFromCache::class, FileEventListener::class);
- $eventDispatcher->addServiceListener(NodeWrittenEvent::class, FileEventListener::class);
+ $newEventDispatcher->addServiceListener(NodeDeletedEvent::class, FileEventListener::class);
+ $newEventDispatcher->addServiceListener(NodeRemovedFromCache::class, FileEventListener::class);
+ $newEventDispatcher->addServiceListener(NodeWrittenEvent::class, FileEventListener::class);
}
+
+ // Tags
+ $newEventDispatcher->addServiceListener(UserDeletedEvent::class, TagManager::class);
+
}
}
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 685fae9bef11c..7c3558a78d8e1 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -1547,8 +1547,6 @@
'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',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 7e778d73b8323..3a4355d28f1b0 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -1576,8 +1576,6 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'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',
diff --git a/lib/private/Setup/MySQL.php b/lib/private/Setup/MySQL.php
index 920baf3e4ee10..c54f9ee951755 100644
--- a/lib/private/Setup/MySQL.php
+++ b/lib/private/Setup/MySQL.php
@@ -78,7 +78,6 @@ private function createDatabase($connection) {
try {
$name = $this->dbName;
$user = $this->dbUser;
- //we can't use OC_DB functions here because we need to connect as the administrative user.
$characterSet = $this->config->getValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
$query = "CREATE DATABASE IF NOT EXISTS `$name` CHARACTER SET $characterSet COLLATE ${characterSet}_bin;";
$connection->executeUpdate($query);
diff --git a/lib/private/Share/Share.php b/lib/private/Share/Share.php
index 47b09982f3aff..090a4ed01f7dd 100644
--- a/lib/private/Share/Share.php
+++ b/lib/private/Share/Share.php
@@ -32,11 +32,16 @@
* along with this program. If not, see
*
*/
+
namespace OC\Share;
+use OCA\Files_Sharing\ShareBackend\File;
+use OCP\DB\Exception;
use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
use OCP\ILogger;
use OCP\Share\IShare;
+use Psr\Log\LoggerInterface;
/**
* This class provides the ability for apps to share their content between users.
@@ -59,11 +64,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
@@ -81,8 +88,8 @@ public static function registerBackend($itemType, $class, $collectionOf = null,
return true;
}
\OCP\Util::writeLog('OCP\Share',
- 'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class']
- .' is already registered for '.$itemType,
+ 'Sharing backend ' . $class . ' not registered, ' . self::$backendTypes[$itemType]['class']
+ . ' is already registered for ' . $itemType,
ILogger::WARN);
}
return false;
@@ -90,6 +97,7 @@ public static function registerBackend($itemType, $class, $collectionOf = null,
/**
* 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 +114,7 @@ public static function getItemsSharedWith() {
/**
* 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 +132,46 @@ public static function getItemsSharedWithUser($itemType, $user) {
/**
* 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', 'storage', 'f', $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)));
}
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 +185,7 @@ public static function getItemSharedWithUser($itemType, $itemSource, $user, $own
$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 +195,7 @@ public static function getItemSharedWithUser($itemType, $itemSource, $user, $own
}
$result->closeCursor();
- //if didn't found a result than let's look for a group share.
+ // if didn't found a result than let's look for a group share.
if (empty($shares) && $user !== null) {
$userObject = \OC::$server->getUserManager()->get($user);
$groups = [];
@@ -202,28 +204,26 @@ public static function getItemSharedWithUser($itemType, $itemSource, $user, $own
}
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];
+ // TODO: inject connection, hopefully one day in the future when this
+ // class isn't static anymore...
+ /** @var IDBConnection $conn */
+ $qb = self::getSelectStatement(self::FORMAT_NONE, $fileDependent);
+ $qb->from('share', 's')
+ ->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('file_source', 'f.fileid'))
+ ->innerJoin('s', 'storage', 'f', $qb->expr()->eq('numeric_id', 'f.storage'))
+ ->where($qb->expr()->eq($column, $qb->createNamedParameter($itemSource)))
+ ->andWhere($qb->expr()->eq('item_type', $qb->createNamedParameter($itemType)))
+ ->andWhere($qb->expr()->in('share_with', $qb->createNamedParameter($groups, IQueryBuilder::PARAM_STR_ARRAY)));
if ($owner !== null) {
- $where .= ' AND `uid_owner` = ?';
- $arguments[] = $owner;
- $types[] = null;
+ $qb->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($owner)));
}
-
- // 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
- );
+ $result = $qb->executeQuery();
while ($row = $result->fetch()) {
$shares[] = $row;
}
+ $result->closeCursor();
}
}
@@ -232,6 +232,7 @@ public static function getItemSharedWithUser($itemType, $itemSource, $user, $own
/**
* 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 @@ public static function getItemShared($itemType, $itemSource, $format = self::FOR
/**
* 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');
@@ -284,6 +286,7 @@ public static function getBackend($itemType) {
/**
* Check if resharing is allowed
+ *
* @return boolean true if allowed or false
*
* Resharing is allowed by default if not configured
@@ -301,10 +304,11 @@ public static function isResharingAllowed() {
/**
* 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)) {
@@ -325,6 +329,7 @@ private static function getCollectionItemTypes($itemType) {
/**
* 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
@@ -349,25 +354,29 @@ public static function getItems($itemType, $item = null, $shareType = null, $sha
if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') != 'yes') {
return [];
}
+ $fileDependent = $itemType == 'file' || $itemType == 'folder';
+ $qb = self::getSelectStatement(self::FORMAT_NONE, $fileDependent, $uidOwner);
+
$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', 'storage', 'f', $qb->expr()->eq('numeric_id', 'f.storage'));
} else {
- $fileDependent = false;
$root = '';
$collectionTypes = self::getCollectionItemTypes($itemType);
if ($includeCollections && !isset($item) && $collectionTypes) {
@@ -377,25 +386,21 @@ public static function getItems($itemType, $item = null, $shareType = null, $sha
} 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;
+ $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 = [];
@@ -403,31 +408,26 @@ public static function getItems($itemType, $item = null, $shareType = null, $sha
$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()->neq('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()->eq('share_type', $qb->createNamedParameter(self::$shareTypeGroupUserUnique, IQueryBuilder::PARAM_INT)));
}
if ($fileDependent) {
$column = 'file_source';
@@ -443,54 +443,43 @@ public static function getItems($itemType, $item = null, $shareType = null, $sha
}
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($placeholders, IQueryBuilder::PARAM_STR_ARRAY))
+ ));
+ } else {
+ $qb->andWhere($expr);
}
}
+ $qb->orderBy('s.id', 'ASC');
+ $result = $qb->executeQuery();
- $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) {
- \OCP\Util::writeLog('OCP\Share',
- \OC_DB::getErrorMessage() . ', select=' . $select . ' where=',
- ILogger::ERROR);
- }
$items = [];
$targets = [];
$switchedItems = [];
$mounts = [];
- while ($row = $result->fetchRow()) {
+ while ($row = $result->fetch()) {
self::transformDBResults($row);
// Filter out duplicate group shares for users with unique targets
if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
@@ -547,15 +536,19 @@ public static function getItems($itemType, $item = null, $shareType = null, $sha
->from('share')
->where($query->expr()->eq('id', $query->createNamedParameter($row['parent'])));
- $parentResult = $query->execute();
- $parentRow = $parentResult->fetch();
- $parentResult->closeCursor();
+ try {
+ $parentResult = $query->executeQuery();
+ $parentRow = $parentResult->fetchOne();
+ $parentResult->closeCursor();
+ } catch (Exception $e) {
+ \OC::$server->get(LoggerInterface::class)
+ ->error('Can\'t select parent :' . $e->getMessage() . ' query=' . $query->getSQL(), [
+ 'exception' => $e,
+ 'app' => 'core'
+ ]);
+ }
- if ($parentRow === false) {
- \OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .
- \OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
- ILogger::ERROR);
- } else {
+ if ($parentRow !== false) {
$tmpPath = $parentRow['file_target'];
// find the right position where the row path continues from the target path
$pos = strrpos($row['path'], $parentRow['file_target']);
@@ -574,7 +567,7 @@ public static function getItems($itemType, $item = null, $shareType = null, $sha
}
}
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, '/');
}
@@ -616,6 +609,7 @@ public static function getItems($itemType, $item = null, $shareType = null, $sha
$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()) {
@@ -639,7 +633,7 @@ public static function getItems($itemType, $item = null, $shareType = null, $sha
$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;
@@ -737,7 +731,7 @@ protected static function groupItems($items, $itemType) {
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;
@@ -753,83 +747,142 @@ protected static function groupItems($items, $itemType) {
}
/**
- * construct select statement
- * @param int $format
- * @param boolean $fileDependent ist it a file/folder share or a generla 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
@@ -840,6 +893,7 @@ private static function transformDBResults(&$row) {
/**
* 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
diff --git a/lib/private/TagManager.php b/lib/private/TagManager.php
index 8c9dca98c92eb..3c2bb5bb92ad0 100644
--- a/lib/private/TagManager.php
+++ b/lib/private/TagManager.php
@@ -28,26 +28,27 @@
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 {
+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 +73,7 @@ public function load($type, $defaultTags = [], $includeShared = false, $userId =
}
$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 +98,68 @@ public function getUsersFavoritingObject(string $objectType, int $objectId): arr
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,
+ ]);
+ }
+
+ $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,
+ ]);
+ }
+ }
+
+ foreach (array_chunk($tagsIds, 1000) as $tagChunk) {
+ $qb->setParameter('chunk', $tagChunk, IQueryBuilder::PARAM_INT_ARRAY);
+ try {
+ $qb->executeStatement();
+ } catch (DBException $e) {
+ $this->logger->error($e->getMessage(), [
+ 'app' => 'core',
+ 'exception' => $e,
+ ]);
+ }
+ }
+ }
}
diff --git a/lib/private/Tags.php b/lib/private/Tags.php
index c11d83e41cff3..965b8e2271b5f 100644
--- a/lib/private/Tags.php
+++ b/lib/private/Tags.php
@@ -32,72 +32,52 @@
use OC\Tagging\Tag;
use OC\Tagging\TagMapper;
+use OCP\DB\Exception;
use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\IDBConnection;
use OCP\ILogger;
use OCP\ITags;
+use OCP\Share_Backend;
+use OCP\User\Events\UserDeletedEvent;
+use Psr\Log\LoggerInterface;
-class Tags implements ITags {
-
- /**
- * Tags
- *
- * @var array
- */
- private $tags = [];
-
+class Tags implements ITags, IEventListener {
/**
* 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,7 +89,7 @@ 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;
@@ -119,6 +99,8 @@ public function __construct(TagMapper $mapper, $user, $type, $defaultTags = [])
if (count($defaultTags) > 0 && count($this->tags) === 0) {
$this->addMultiple($defaultTags, true);
}
+ $this->db = $connection;
+ $this->logger = $logger;
}
/**
@@ -126,7 +108,7 @@ public function __construct(TagMapper $mapper, $user, $type, $defaultTags = [])
*
* @return boolean
*/
- public function isEmpty() {
+ public function isEmpty(): bool {
return count($this->tags) === 0;
}
@@ -137,7 +119,7 @@ public function isEmpty() {
* @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 +136,9 @@ public function getTag($id) {
* ['id' => 1, 'name' = 'Shared tag', 'owner' = 'Other user', 'type' => 'tagtype'],
* ]
*
- * @return array
+ * @return array
*/
- public function getTags() {
+ public function getTags(): array {
if (!count($this->tags)) {
return [];
}
@@ -181,7 +163,7 @@ public function getTags() {
* @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 +175,26 @@ function ($tag) use ($user) {
* 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('t.categoryid', 'r.id'))
+ ->where($qb->expr()->eq('r.uid', $qb->createParameter('uid')))
+ ->andWhere($qb->expr()->eq('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])) {
@@ -219,9 +204,8 @@ public function getTagsForObjects(array $objIds) {
}
}
} 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 +220,17 @@ public function getTagsForObjects(array $objIds) {
* 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,28 +244,22 @@ public function getIdsForTag($tag) {
}
$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()) {
+ while ($row = $result->fetch()) {
$ids[] = (int)$row['objid'];
}
$result->closeCursor();
@@ -308,9 +285,8 @@ public function userHasTag($name, $user) {
* 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 +296,16 @@ public function hasTag($name) {
* @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 +313,13 @@ public function add($name) {
$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 +330,12 @@ public function add($name) {
* @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 +345,13 @@ public function rename($from, $to) {
$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 +359,8 @@ public function rename($from, $to) {
$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;
@@ -402,7 +377,7 @@ public function rename($from, $to) {
* @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(array $names, bool $sync = false, ?int $id = null): bool {
if (!is_array($names)) {
$names = [$names];
}
@@ -430,122 +405,50 @@ public function addMultiple($names, $sync = false, $id = null) {
/**
* 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 +457,21 @@ public static function post_deleteUser($arguments) {
* @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;
}
@@ -686,15 +582,17 @@ public function unTag($objid, $tag) {
}
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 +634,14 @@ public function delete($names) {
}
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;
}
@@ -822,4 +713,7 @@ private function tagMap(Tag $tag) {
'type' => $tag->getType()
];
}
+
+ public function handle(Event $event): void {
+ }
}
diff --git a/lib/private/legacy/OC_DB.php b/lib/private/legacy/OC_DB.php
deleted file mode 100644
index 39faf8e80aad8..0000000000000
--- a/lib/private/legacy/OC_DB.php
+++ /dev/null
@@ -1,184 +0,0 @@
-
- * @author Bart Visscher
- * @author Christoph Wurst
- * @author Joas Schilling
- * @author Jörn Friedrich Dreyer
- * @author Lukas Reschke
- * @author Morris Jobke
- * @author Robin Appelman
- * @author Thomas Müller
- * @author Vincent Petry
- *
- * @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
- *
- */
-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);
- }
-}
diff --git a/lib/private/legacy/OC_DB_StatementWrapper.php b/lib/private/legacy/OC_DB_StatementWrapper.php
deleted file mode 100644
index d6214a49a3335..0000000000000
--- a/lib/private/legacy/OC_DB_StatementWrapper.php
+++ /dev/null
@@ -1,135 +0,0 @@
-
- * @author Christoph Wurst
- * @author Joas Schilling
- * @author Jörn Friedrich Dreyer
- * @author Lukas Reschke
- * @author Morris Jobke
- * @author Robin Appelman
- * @author Thomas Müller
- *
- * @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
- *
- */
-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);
- }
-}
diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php
index edee23995f1a3..dfe6a6b459a76 100644
--- a/lib/private/legacy/OC_Util.php
+++ b/lib/private/legacy/OC_Util.php
@@ -69,6 +69,7 @@
use OC\Files\SetupManager;
use OCP\Files\Template\ITemplateManager;
use OCP\IConfig;
+use OCP\IDBConnection;
use OCP\IGroupManager;
use OCP\IURLGenerator;
use OCP\IUser;
@@ -755,9 +756,13 @@ public static function checkDatabaseVersion() {
$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'];
diff --git a/lib/public/ITags.php b/lib/public/ITags.php
index 03bcb845f4e5f..ac76e9dd79809 100644
--- a/lib/public/ITags.php
+++ b/lib/public/ITags.php
@@ -32,9 +32,6 @@
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 @@ public function isEmpty();
* @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
* @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 @@ public function getIdsForTag($tag);
* 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 @@ public function hasTag($name);
* @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 @@ public function userHasTag($name, $user);
* @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,7 +150,7 @@ public function add($name);
* @return bool
* @since 6.0.0
*/
- public function rename($from, $to);
+ public function rename($from, string $to): bool;
/**
* Add a list of new tags.
@@ -162,7 +162,7 @@ public function rename($from, $to);
* @return bool Returns false on error.
* @since 6.0.0
*/
- public function addMultiple($names, $sync = false, $id = null);
+ public function addMultiple(array $names, bool $sync = false, ?int $id = null): bool;
/**
* Delete tag/object relations from the db
diff --git a/tests/lib/Share/ShareTest.php b/tests/lib/Share/ShareTest.php
index c690ada99ca8b..995604140c018 100644
--- a/tests/lib/Share/ShareTest.php
+++ b/tests/lib/Share/ShareTest.php
@@ -21,6 +21,8 @@
namespace Test\Share;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
use OCP\IGroup;
use OCP\IGroupManager;
use OCP\IUser;
@@ -35,36 +37,25 @@
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;
-
- /** @var IGroup */
- protected $group1;
- /** @var IGroup */
- protected $group2;
- /** @var IGroup */
- protected $groupAndUser_group;
-
- protected $resharing;
- protected $dateInFuture;
- protected $dateInPast;
-
- /** @var IGroupManager */
- protected $groupManager;
- /** @var IUserManager */
- protected $userManager;
+ protected IUser $user1;
+ protected IUser $user2;
+ protected IUser $user3;
+ protected IUser $user4;
+ protected IUser $user5;
+ protected IUser $user6;
+ protected IUser $groupAndUser_user;
+
+ protected IGroup $group1;
+ protected IGroup $group2;
+ protected IGroup $groupAndUser_group;
+
+ protected string $resharing;
+ protected string $dateInFuture;
+ protected string $dateInPast;
+
+ protected IGroupManager $groupManager;
+ protected IUserManager $userManager;
+ private IDBConnection $connection;
protected function setUp(): void {
parent::setUp();
@@ -90,6 +81,7 @@ protected function setUp(): void {
$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);
@@ -113,8 +105,9 @@ protected function setUp(): void {
}
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,21 +129,33 @@ protected function tearDown(): void {
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->setValue('itemType', $row[0]);
+ $query->setValue('itemSource', $row[1], IQueryBuilder::PARAM_INT);
+ $query->setValue('itemTarget', $row[2]);
+ $query->setValue('shareType', $row[3], IQueryBuilder::PARAM_INT);
+ $query->setValue('shareWith', $row[4]);
+ $query->setValue('uidOwner', $row[5]);
+ $query->executeStatement();
+ }
$result1 = \OCP\Share::getItemSharedWithUser('test', 99, $this->user2->getUID(), $this->user1->getUID());
$this->assertSame(1, count($result1));
@@ -176,18 +181,32 @@ public function testGetItemSharedWithUser() {
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->setValue('itemType', $row[0]);
+ $query->setValue('itemSource', $row[1], IQueryBuilder::PARAM_INT);
+ $query->setValue('itemTarget', $row[2]);
+ $query->setValue('shareType', $row[3], IQueryBuilder::PARAM_INT);
+ $query->setValue('shareWith', $row[4]);
+ $query->setValue('uidOwner', $row[5]);
+ $query->executeStatement();
+ }
// user2 is in group1 and group2
$result1 = \OCP\Share::getItemSharedWithUser('test', 99, $this->user2->getUID(), $this->user1->getUID());