diff options
-rw-r--r-- | apps/dav/lib/Connector/Sabre/CommentPropertiesPlugin.php | 31 | ||||
-rw-r--r-- | lib/private/Comments/Manager.php | 212 | ||||
-rw-r--r-- | lib/private/DB/QueryBuilder/QuoteHelper.php | 2 | ||||
-rw-r--r-- | lib/private/Repair/CleanTags.php | 2 | ||||
-rw-r--r-- | lib/public/Comments/ICommentsManager.php | 12 | ||||
-rw-r--r-- | tests/lib/Comments/FakeManager.php | 3 | ||||
-rw-r--r-- | tests/lib/Comments/ManagerTest.php | 215 | ||||
-rw-r--r-- | tests/lib/DB/QueryBuilder/QueryBuilderTest.php | 2 | ||||
-rw-r--r-- | tests/lib/DB/QueryBuilder/QuoteHelperTest.php | 2 |
9 files changed, 312 insertions, 169 deletions
diff --git a/apps/dav/lib/Connector/Sabre/CommentPropertiesPlugin.php b/apps/dav/lib/Connector/Sabre/CommentPropertiesPlugin.php index e48105f6d7a..66d6b335f40 100644 --- a/apps/dav/lib/Connector/Sabre/CommentPropertiesPlugin.php +++ b/apps/dav/lib/Connector/Sabre/CommentPropertiesPlugin.php @@ -42,6 +42,10 @@ class CommentPropertiesPlugin extends ServerPlugin { /** @var IUserSession */ private $userSession; + private $cachedUnreadCount = []; + + private $cachedFolders = []; + public function __construct(ICommentsManager $commentsManager, IUserSession $userSession) { $this->commentsManager = $commentsManager; $this->userSession = $userSession; @@ -79,6 +83,18 @@ class CommentPropertiesPlugin extends ServerPlugin { return; } + // need prefetch ? + if ($node instanceof \OCA\DAV\Connector\Sabre\Directory + && $propFind->getDepth() !== 0 + && !is_null($propFind->getStatus(self::PROPERTY_NAME_UNREAD)) + ) { + $unreadCounts = $this->commentsManager->getNumberOfUnreadCommentsForFolder($node->getId(), $this->userSession->getUser()); + $this->cachedFolders[] = $node->getPath(); + foreach ($unreadCounts as $id => $count) { + $this->cachedUnreadCount[$id] = $count; + } + } + $propFind->handle(self::PROPERTY_NAME_COUNT, function() use ($node) { return $this->commentsManager->getNumberOfCommentsForObject('files', strval($node->getId())); }); @@ -88,7 +104,20 @@ class CommentPropertiesPlugin extends ServerPlugin { }); $propFind->handle(self::PROPERTY_NAME_UNREAD, function() use ($node) { - return $this->getUnreadCount($node); + if (isset($this->cachedUnreadCount[$node->getId()])) { + return $this->cachedUnreadCount[$node->getId()]; + } else { + list($parentPath,) = \Sabre\Uri\split($node->getPath()); + if ($parentPath === '') { + $parentPath = '/'; + } + // if we already cached the folder this file is in we know there are no shares for this file + if (array_search($parentPath, $this->cachedFolders) === false) { + return $this->getUnreadCount($node); + } else { + return 0; + } + } }); } diff --git a/lib/private/Comments/Manager.php b/lib/private/Comments/Manager.php index 1467fef727b..695d209b68f 100644 --- a/lib/private/Comments/Manager.php +++ b/lib/private/Comments/Manager.php @@ -21,9 +21,11 @@ * along with this program. If not, see <http://www.gnu.org/licenses/> * */ + namespace OC\Comments; use Doctrine\DBAL\Exception\DriverException; +use Doctrine\DBAL\Platforms\MySqlPlatform; use OCP\Comments\CommentsEvent; use OCP\Comments\IComment; use OCP\Comments\ICommentsEventHandler; @@ -46,7 +48,7 @@ class Manager implements ICommentsManager { /** @var IConfig */ protected $config; - /** @var IComment[] */ + /** @var IComment[] */ protected $commentsCache = []; /** @var \Closure[] */ @@ -104,7 +106,7 @@ class Manager implements ICommentsManager { * @throws \UnexpectedValueException */ protected function prepareCommentForDatabaseWrite(IComment $comment) { - if( !$comment->getActorType() + if (!$comment->getActorType() || !$comment->getActorId() || !$comment->getObjectType() || !$comment->getObjectId() @@ -113,17 +115,17 @@ class Manager implements ICommentsManager { throw new \UnexpectedValueException('Actor, Object and Verb information must be provided for saving'); } - if($comment->getId() === '') { + if ($comment->getId() === '') { $comment->setChildrenCount(0); $comment->setLatestChildDateTime(new \DateTime('0000-00-00 00:00:00', new \DateTimeZone('UTC'))); $comment->setLatestChildDateTime(null); } - if(is_null($comment->getCreationDateTime())) { + if (is_null($comment->getCreationDateTime())) { $comment->setCreationDateTime(new \DateTime()); } - if($comment->getParentId() !== '0') { + if ($comment->getParentId() !== '0') { $comment->setTopmostParentId($this->determineTopmostParentId($comment->getParentId())); } else { $comment->setTopmostParentId('0'); @@ -143,7 +145,7 @@ class Manager implements ICommentsManager { */ protected function determineTopmostParentId($id) { $comment = $this->get($id); - if($comment->getParentId() === '0') { + if ($comment->getParentId() === '0') { return $comment->getId(); } else { return $this->determineTopmostParentId($comment->getId()); @@ -153,16 +155,16 @@ class Manager implements ICommentsManager { /** * updates child information of a comment * - * @param string $id - * @param \DateTime $cDateTime the date time of the most recent child + * @param string $id + * @param \DateTime $cDateTime the date time of the most recent child * @throws NotFoundException */ protected function updateChildrenInformation($id, \DateTime $cDateTime) { $qb = $this->dbConn->getQueryBuilder(); $query = $qb->select($qb->createFunction('COUNT(`id`)')) - ->from('comments') - ->where($qb->expr()->eq('parent_id', $qb->createParameter('id'))) - ->setParameter('id', $id); + ->from('comments') + ->where($qb->expr()->eq('parent_id', $qb->createParameter('id'))) + ->setParameter('id', $id); $resultStatement = $query->execute(); $data = $resultStatement->fetch(\PDO::FETCH_NUM); @@ -185,8 +187,8 @@ class Manager implements ICommentsManager { * @throws \InvalidArgumentException */ protected function checkRoleParameters($role, $type, $id) { - if( - !is_string($type) || empty($type) + if ( + !is_string($type) || empty($type) || !is_string($id) || empty($id) ) { throw new \InvalidArgumentException($role . ' parameters must be string and not empty'); @@ -200,7 +202,7 @@ class Manager implements ICommentsManager { */ protected function cache(IComment $comment) { $id = $comment->getId(); - if(empty($id)) { + if (empty($id)) { return; } $this->commentsCache[strval($id)] = $comment; @@ -228,11 +230,11 @@ class Manager implements ICommentsManager { * @since 9.0.0 */ public function get($id) { - if(intval($id) === 0) { + if (intval($id) === 0) { throw new \InvalidArgumentException('IDs must be translatable to a number in this implementation.'); } - if(isset($this->commentsCache[$id])) { + if (isset($this->commentsCache[$id])) { return $this->commentsCache[$id]; } @@ -245,7 +247,7 @@ class Manager implements ICommentsManager { $data = $resultStatement->fetch(); $resultStatement->closeCursor(); - if(!$data) { + if (!$data) { throw new NotFoundException(); } @@ -290,20 +292,20 @@ class Manager implements ICommentsManager { $qb = $this->dbConn->getQueryBuilder(); $query = $qb->select('*') - ->from('comments') - ->where($qb->expr()->eq('topmost_parent_id', $qb->createParameter('id'))) - ->orderBy('creation_timestamp', 'DESC') - ->setParameter('id', $id); + ->from('comments') + ->where($qb->expr()->eq('topmost_parent_id', $qb->createParameter('id'))) + ->orderBy('creation_timestamp', 'DESC') + ->setParameter('id', $id); - if($limit > 0) { + if ($limit > 0) { $query->setMaxResults($limit); } - if($offset > 0) { + if ($offset > 0) { $query->setFirstResult($offset); } $resultStatement = $query->execute(); - while($data = $resultStatement->fetch()) { + while ($data = $resultStatement->fetch()) { $comment = new Comment($this->normalizeDatabaseData($data)); $this->cache($comment); $tree['replies'][] = [ @@ -332,37 +334,37 @@ class Manager implements ICommentsManager { * @since 9.0.0 */ public function getForObject( - $objectType, - $objectId, - $limit = 0, - $offset = 0, - \DateTime $notOlderThan = null + $objectType, + $objectId, + $limit = 0, + $offset = 0, + \DateTime $notOlderThan = null ) { $comments = []; $qb = $this->dbConn->getQueryBuilder(); $query = $qb->select('*') - ->from('comments') - ->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) - ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) - ->orderBy('creation_timestamp', 'DESC') - ->setParameter('type', $objectType) - ->setParameter('id', $objectId); - - if($limit > 0) { + ->from('comments') + ->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) + ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) + ->orderBy('creation_timestamp', 'DESC') + ->setParameter('type', $objectType) + ->setParameter('id', $objectId); + + if ($limit > 0) { $query->setMaxResults($limit); } - if($offset > 0) { + if ($offset > 0) { $query->setFirstResult($offset); } - if(!is_null($notOlderThan)) { + if (!is_null($notOlderThan)) { $query ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan'))) ->setParameter('notOlderThan', $notOlderThan, 'datetime'); } $resultStatement = $query->execute(); - while($data = $resultStatement->fetch()) { + while ($data = $resultStatement->fetch()) { $comment = new Comment($this->normalizeDatabaseData($data)); $this->cache($comment); $comments[] = $comment; @@ -383,13 +385,13 @@ class Manager implements ICommentsManager { public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null) { $qb = $this->dbConn->getQueryBuilder(); $query = $qb->select($qb->createFunction('COUNT(`id`)')) - ->from('comments') - ->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) - ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) - ->setParameter('type', $objectType) - ->setParameter('id', $objectId); + ->from('comments') + ->where($qb->expr()->eq('object_type', $qb->createParameter('type'))) + ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id'))) + ->setParameter('type', $objectType) + ->setParameter('id', $objectId); - if(!is_null($notOlderThan)) { + if (!is_null($notOlderThan)) { $query ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan'))) ->setParameter('notOlderThan', $notOlderThan, 'datetime'); @@ -402,6 +404,40 @@ class Manager implements ICommentsManager { } /** + * Get the number of unread comments for all files in a folder + * + * @param int $folderId + * @param IUser $user + * @return array [$fileId => $unreadCount] + */ + public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user) { + $qb = $this->dbConn->getQueryBuilder(); + $query = $qb->select('fileid', $qb->createFunction( + 'COUNT(' . $qb->getColumnName('c.id') . ')') + )->from('comments', 'c') + ->innerJoin('c', 'filecache', 'f', $qb->expr()->andX( + $qb->expr()->eq('c.object_type', $qb->createNamedParameter('files')), + $qb->expr()->eq('f.fileid', $qb->expr()->castColumn('c.object_id', IQueryBuilder::PARAM_INT)) + )) + ->leftJoin('c', 'comments_read_markers', 'm', $qb->expr()->andX( + $qb->expr()->eq('m.object_type', $qb->createNamedParameter('files')), + $qb->expr()->eq('m.object_id', 'c.object_id'), + $qb->expr()->eq('m.user_id', $qb->createNamedParameter($user->getUID())) + )) + ->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($folderId))) + ->andWhere($qb->expr()->orX( + $qb->expr()->gt('c.creation_timestamp', 'marker_datetime'), + $qb->expr()->isNull('marker_datetime') + )) + ->groupBy('f.fileid'); + + $resultStatement = $query->execute(); + return array_map(function ($count) { + return (int)$count; + }, $resultStatement->fetchAll(\PDO::FETCH_KEY_PAIR)); + } + + /** * creates a new comment and returns it. At this point of time, it is not * saved in the used data storage. Use save() after setting other fields * of the comment (e.g. message or verb). @@ -433,7 +469,7 @@ class Manager implements ICommentsManager { * @since 9.0.0 */ public function delete($id) { - if(!is_string($id)) { + if (!is_string($id)) { throw new \InvalidArgumentException('Parameter must be string'); } @@ -481,16 +517,16 @@ class Manager implements ICommentsManager { * @since 9.0.0 */ public function save(IComment $comment) { - if($this->prepareCommentForDatabaseWrite($comment)->getId() === '') { + if ($this->prepareCommentForDatabaseWrite($comment)->getId() === '') { $result = $this->insert($comment); } else { $result = $this->update($comment); } - if($result && !!$comment->getParentId()) { + if ($result && !!$comment->getParentId()) { $this->updateChildrenInformation( - $comment->getParentId(), - $comment->getCreationDateTime() + $comment->getParentId(), + $comment->getCreationDateTime() ); $this->cache($comment); } @@ -509,17 +545,17 @@ class Manager implements ICommentsManager { $affectedRows = $qb ->insert('comments') ->values([ - 'parent_id' => $qb->createNamedParameter($comment->getParentId()), - 'topmost_parent_id' => $qb->createNamedParameter($comment->getTopmostParentId()), - 'children_count' => $qb->createNamedParameter($comment->getChildrenCount()), - 'actor_type' => $qb->createNamedParameter($comment->getActorType()), - 'actor_id' => $qb->createNamedParameter($comment->getActorId()), - 'message' => $qb->createNamedParameter($comment->getMessage()), - 'verb' => $qb->createNamedParameter($comment->getVerb()), - 'creation_timestamp' => $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'), - 'latest_child_timestamp' => $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'), - 'object_type' => $qb->createNamedParameter($comment->getObjectType()), - 'object_id' => $qb->createNamedParameter($comment->getObjectId()), + 'parent_id' => $qb->createNamedParameter($comment->getParentId()), + 'topmost_parent_id' => $qb->createNamedParameter($comment->getTopmostParentId()), + 'children_count' => $qb->createNamedParameter($comment->getChildrenCount()), + 'actor_type' => $qb->createNamedParameter($comment->getActorType()), + 'actor_id' => $qb->createNamedParameter($comment->getActorId()), + 'message' => $qb->createNamedParameter($comment->getMessage()), + 'verb' => $qb->createNamedParameter($comment->getVerb()), + 'creation_timestamp' => $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'), + 'latest_child_timestamp' => $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'), + 'object_type' => $qb->createNamedParameter($comment->getObjectType()), + 'object_id' => $qb->createNamedParameter($comment->getObjectId()), ]) ->execute(); @@ -548,22 +584,22 @@ class Manager implements ICommentsManager { $qb = $this->dbConn->getQueryBuilder(); $affectedRows = $qb ->update('comments') - ->set('parent_id', $qb->createNamedParameter($comment->getParentId())) - ->set('topmost_parent_id', $qb->createNamedParameter($comment->getTopmostParentId())) - ->set('children_count', $qb->createNamedParameter($comment->getChildrenCount())) - ->set('actor_type', $qb->createNamedParameter($comment->getActorType())) - ->set('actor_id', $qb->createNamedParameter($comment->getActorId())) - ->set('message', $qb->createNamedParameter($comment->getMessage())) - ->set('verb', $qb->createNamedParameter($comment->getVerb())) - ->set('creation_timestamp', $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime')) - ->set('latest_child_timestamp', $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime')) - ->set('object_type', $qb->createNamedParameter($comment->getObjectType())) - ->set('object_id', $qb->createNamedParameter($comment->getObjectId())) + ->set('parent_id', $qb->createNamedParameter($comment->getParentId())) + ->set('topmost_parent_id', $qb->createNamedParameter($comment->getTopmostParentId())) + ->set('children_count', $qb->createNamedParameter($comment->getChildrenCount())) + ->set('actor_type', $qb->createNamedParameter($comment->getActorType())) + ->set('actor_id', $qb->createNamedParameter($comment->getActorId())) + ->set('message', $qb->createNamedParameter($comment->getMessage())) + ->set('verb', $qb->createNamedParameter($comment->getVerb())) + ->set('creation_timestamp', $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime')) + ->set('latest_child_timestamp', $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime')) + ->set('object_type', $qb->createNamedParameter($comment->getObjectType())) + ->set('object_id', $qb->createNamedParameter($comment->getObjectId())) ->where($qb->expr()->eq('id', $qb->createParameter('id'))) ->setParameter('id', $comment->getId()) ->execute(); - if($affectedRows === 0) { + if ($affectedRows === 0) { throw new NotFoundException('Comment to update does ceased to exist'); } @@ -587,8 +623,8 @@ class Manager implements ICommentsManager { $qb = $this->dbConn->getQueryBuilder(); $affectedRows = $qb ->update('comments') - ->set('actor_type', $qb->createNamedParameter(ICommentsManager::DELETED_USER)) - ->set('actor_id', $qb->createNamedParameter(ICommentsManager::DELETED_USER)) + ->set('actor_type', $qb->createNamedParameter(ICommentsManager::DELETED_USER)) + ->set('actor_id', $qb->createNamedParameter(ICommentsManager::DELETED_USER)) ->where($qb->expr()->eq('actor_type', $qb->createParameter('type'))) ->andWhere($qb->expr()->eq('actor_id', $qb->createParameter('id'))) ->setParameter('type', $actorType) @@ -662,19 +698,19 @@ class Manager implements ICommentsManager { $qb = $this->dbConn->getQueryBuilder(); $values = [ - 'user_id' => $qb->createNamedParameter($user->getUID()), + 'user_id' => $qb->createNamedParameter($user->getUID()), 'marker_datetime' => $qb->createNamedParameter($dateTime, 'datetime'), - 'object_type' => $qb->createNamedParameter($objectType), - 'object_id' => $qb->createNamedParameter($objectId), + 'object_type' => $qb->createNamedParameter($objectType), + 'object_id' => $qb->createNamedParameter($objectId), ]; // Strategy: try to update, if this does not return affected rows, do an insert. $affectedRows = $qb ->update('comments_read_markers') - ->set('user_id', $values['user_id']) + ->set('user_id', $values['user_id']) ->set('marker_datetime', $values['marker_datetime']) - ->set('object_type', $values['object_type']) - ->set('object_id', $values['object_id']) + ->set('object_type', $values['object_type']) + ->set('object_id', $values['object_id']) ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id'))) ->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type'))) ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id'))) @@ -717,7 +753,7 @@ class Manager implements ICommentsManager { $data = $resultStatement->fetch(); $resultStatement->closeCursor(); - if(!$data || is_null($data['marker_datetime'])) { + if (!$data || is_null($data['marker_datetime'])) { return null; } @@ -774,10 +810,10 @@ class Manager implements ICommentsManager { * \OutOfBoundsException has to thrown. */ public function registerDisplayNameResolver($type, \Closure $closure) { - if(!is_string($type)) { + if (!is_string($type)) { throw new \InvalidArgumentException('String expected.'); } - if(isset($this->displayNameResolvers[$type])) { + if (isset($this->displayNameResolvers[$type])) { throw new \OutOfBoundsException('Displayname resolver for this type already registered'); } $this->displayNameResolvers[$type] = $closure; @@ -797,10 +833,10 @@ class Manager implements ICommentsManager { * provided ID is unknown. It must be ensured that a string is returned. */ public function resolveDisplayName($type, $id) { - if(!is_string($type)) { + if (!is_string($type)) { throw new \InvalidArgumentException('String expected.'); } - if(!isset($this->displayNameResolvers[$type])) { + if (!isset($this->displayNameResolvers[$type])) { throw new \OutOfBoundsException('No Displayname resolver for this type registered'); } return (string)$this->displayNameResolvers[$type]($id); @@ -812,7 +848,7 @@ class Manager implements ICommentsManager { * @return \OCP\Comments\ICommentsEventHandler[] */ private function getEventHandlers() { - if(!empty($this->eventHandlers)) { + if (!empty($this->eventHandlers)) { return $this->eventHandlers; } diff --git a/lib/private/DB/QueryBuilder/QuoteHelper.php b/lib/private/DB/QueryBuilder/QuoteHelper.php index 041718bce5a..705c3a89712 100644 --- a/lib/private/DB/QueryBuilder/QuoteHelper.php +++ b/lib/private/DB/QueryBuilder/QuoteHelper.php @@ -73,7 +73,7 @@ class QuoteHelper { return $string; } - return $alias . '.`' . $columnName . '`'; + return '`' . $alias . '`.`' . $columnName . '`'; } return '`' . $string . '`'; diff --git a/lib/private/Repair/CleanTags.php b/lib/private/Repair/CleanTags.php index 8b62395a501..9b44fb1e671 100644 --- a/lib/private/Repair/CleanTags.php +++ b/lib/private/Repair/CleanTags.php @@ -173,7 +173,7 @@ class CleanTags implements IRepairStep { $qb->select('d.' . $deleteId) ->from($deleteTable, 'd') - ->leftJoin('d', $sourceTable, 's', $qb->expr()->eq('d.' . $deleteId, ' s.' . $sourceId)) + ->leftJoin('d', $sourceTable, 's', $qb->expr()->eq('d.' . $deleteId, 's.' . $sourceId)) ->where( $qb->expr()->eq('d.type', $qb->expr()->literal('files')) ) diff --git a/lib/public/Comments/ICommentsManager.php b/lib/public/Comments/ICommentsManager.php index b43d5e8800b..f088ad9f70d 100644 --- a/lib/public/Comments/ICommentsManager.php +++ b/lib/public/Comments/ICommentsManager.php @@ -23,6 +23,8 @@ */ namespace OCP\Comments; +use OCP\IUser; + /** * Interface ICommentsManager * @@ -126,6 +128,16 @@ interface ICommentsManager { public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null); /** + * Get the number of unread comments for all files in a folder + * + * @param int $folderId + * @param IUser $user + * @return array [$fileId => $unreadCount] + * @since 12.0.0 + */ + public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user); + + /** * creates a new comment and returns it. At this point of time, it is not * saved in the used data storage. Use save() after setting other fields * of the comment (e.g. message or verb). diff --git a/tests/lib/Comments/FakeManager.php b/tests/lib/Comments/FakeManager.php index dfb8f21b64b..840961fb901 100644 --- a/tests/lib/Comments/FakeManager.php +++ b/tests/lib/Comments/FakeManager.php @@ -1,6 +1,7 @@ <?php namespace Test\Comments; +use OCP\IUser; /** * Class FakeManager @@ -44,4 +45,6 @@ class FakeManager implements \OCP\Comments\ICommentsManager { public function registerDisplayNameResolver($type, \Closure $closure) {} public function resolveDisplayName($type, $id) {} + + public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user) {} } diff --git a/tests/lib/Comments/ManagerTest.php b/tests/lib/Comments/ManagerTest.php index a320366f29e..24c634be137 100644 --- a/tests/lib/Comments/ManagerTest.php +++ b/tests/lib/Comments/ManagerTest.php @@ -6,7 +6,9 @@ use OC\Comments\Comment; use OCP\Comments\CommentsEvent; use OCP\Comments\ICommentsEventHandler; use OCP\Comments\ICommentsManager; +use OCP\IDBConnection; use OCP\IUser; +use Test\Files\Storage\DummyUser; use Test\TestCase; /** @@ -15,37 +17,44 @@ use Test\TestCase; * @group DB */ class ManagerTest extends TestCase { + /** @var IDBConnection */ + private $connection; public function setUp() { parent::setUp(); - $sql = \OC::$server->getDatabaseConnection()->getDatabasePlatform()->getTruncateTableSQL('`*PREFIX*comments`'); - \OC::$server->getDatabaseConnection()->prepare($sql)->execute(); + $this->connection = \OC::$server->getDatabaseConnection(); + + $sql = $this->connection->getDatabasePlatform()->getTruncateTableSQL('`*PREFIX*comments`'); + $this->connection->prepare($sql)->execute(); } - protected function addDatabaseEntry($parentId, $topmostParentId, $creationDT = null, $latestChildDT = null) { - if(is_null($creationDT)) { + protected function addDatabaseEntry($parentId, $topmostParentId, $creationDT = null, $latestChildDT = null, $objectId = null) { + if (is_null($creationDT)) { $creationDT = new \DateTime(); } - if(is_null($latestChildDT)) { + if (is_null($latestChildDT)) { $latestChildDT = new \DateTime('yesterday'); } + if (is_null($objectId)) { + $objectId = 'file64'; + } - $qb = \OC::$server->getDatabaseConnection()->getQueryBuilder(); + $qb = $this->connection->getQueryBuilder(); $qb ->insert('comments') ->values([ - 'parent_id' => $qb->createNamedParameter($parentId), - 'topmost_parent_id' => $qb->createNamedParameter($topmostParentId), - 'children_count' => $qb->createNamedParameter(2), - 'actor_type' => $qb->createNamedParameter('users'), - 'actor_id' => $qb->createNamedParameter('alice'), - 'message' => $qb->createNamedParameter('nice one'), - 'verb' => $qb->createNamedParameter('comment'), - 'creation_timestamp' => $qb->createNamedParameter($creationDT, 'datetime'), - 'latest_child_timestamp' => $qb->createNamedParameter($latestChildDT, 'datetime'), - 'object_type' => $qb->createNamedParameter('files'), - 'object_id' => $qb->createNamedParameter('file64'), + 'parent_id' => $qb->createNamedParameter($parentId), + 'topmost_parent_id' => $qb->createNamedParameter($topmostParentId), + 'children_count' => $qb->createNamedParameter(2), + 'actor_type' => $qb->createNamedParameter('users'), + 'actor_id' => $qb->createNamedParameter('alice'), + 'message' => $qb->createNamedParameter('nice one'), + 'verb' => $qb->createNamedParameter('comment'), + 'creation_timestamp' => $qb->createNamedParameter($creationDT, 'datetime'), + 'latest_child_timestamp' => $qb->createNamedParameter($latestChildDT, 'datetime'), + 'object_type' => $qb->createNamedParameter('files'), + 'object_id' => $qb->createNamedParameter($objectId), ]) ->execute(); @@ -83,17 +92,17 @@ class ManagerTest extends TestCase { $qb ->insert('comments') ->values([ - 'parent_id' => $qb->createNamedParameter('2'), - 'topmost_parent_id' => $qb->createNamedParameter('1'), - 'children_count' => $qb->createNamedParameter(2), - 'actor_type' => $qb->createNamedParameter('users'), - 'actor_id' => $qb->createNamedParameter('alice'), - 'message' => $qb->createNamedParameter('nice one'), - 'verb' => $qb->createNamedParameter('comment'), - 'creation_timestamp' => $qb->createNamedParameter($creationDT, 'datetime'), - 'latest_child_timestamp' => $qb->createNamedParameter($latestChildDT, 'datetime'), - 'object_type' => $qb->createNamedParameter('files'), - 'object_id' => $qb->createNamedParameter('file64'), + 'parent_id' => $qb->createNamedParameter('2'), + 'topmost_parent_id' => $qb->createNamedParameter('1'), + 'children_count' => $qb->createNamedParameter(2), + 'actor_type' => $qb->createNamedParameter('users'), + 'actor_id' => $qb->createNamedParameter('alice'), + 'message' => $qb->createNamedParameter('nice one'), + 'verb' => $qb->createNamedParameter('comment'), + 'creation_timestamp' => $qb->createNamedParameter($creationDT, 'datetime'), + 'latest_child_timestamp' => $qb->createNamedParameter($latestChildDT, 'datetime'), + 'object_type' => $qb->createNamedParameter('files'), + 'object_id' => $qb->createNamedParameter('file64'), ]) ->execute(); @@ -149,7 +158,7 @@ class ManagerTest extends TestCase { $this->assertSame(count($tree['replies']), 3); // one level deep - foreach($tree['replies'] as $reply) { + foreach ($tree['replies'] as $reply) { $this->assertTrue($reply['comment'] instanceof \OCP\Comments\IComment); $this->assertSame($reply['comment']->getId(), strval($id)); $this->assertSame(count($reply['replies']), 0); @@ -171,7 +180,7 @@ class ManagerTest extends TestCase { $this->assertSame(count($tree['replies']), 0); // one level deep - foreach($tree['replies'] as $reply) { + foreach ($tree['replies'] as $reply) { throw new \Exception('This ain`t happen'); } } @@ -233,14 +242,14 @@ class ManagerTest extends TestCase { $comments = $manager->getForObject('files', 'file64', 3, $offset); $this->assertTrue(is_array($comments)); - foreach($comments as $comment) { + foreach ($comments as $comment) { $this->assertTrue($comment instanceof \OCP\Comments\IComment); $this->assertSame($comment->getMessage(), 'nice one'); $this->assertSame($comment->getId(), strval($idToVerify)); $idToVerify--; } $offset += 3; - } while(count($comments) > 0); + } while (count($comments) > 0); } public function testGetForObjectWithDateTimeConstraint() { @@ -272,7 +281,7 @@ class ManagerTest extends TestCase { $comments = $manager->getForObject('files', 'file64', 3, $offset, new \DateTime('-4 hours')); $this->assertTrue(is_array($comments)); - foreach($comments as $comment) { + foreach ($comments as $comment) { $this->assertTrue($comment instanceof \OCP\Comments\IComment); $this->assertSame($comment->getMessage(), 'nice one'); $this->assertSame($comment->getId(), strval($idToVerify)); @@ -280,11 +289,11 @@ class ManagerTest extends TestCase { $idToVerify--; } $offset += 3; - } while(count($comments) > 0); + } while (count($comments) > 0); } public function testGetNumberOfCommentsForObject() { - for($i = 1; $i < 5; $i++) { + for ($i = 1; $i < 5; $i++) { $this->addDatabaseEntry(0, 0); } @@ -297,6 +306,52 @@ class ManagerTest extends TestCase { $this->assertSame($amount, 4); } + public function testGetNumberOfUnreadCommentsForFolder() { + // 2 comment for 1111 with 1 before read marker + // 2 comments for 1112 with no read marker + // 1 comment for 1113 before read marker + // 1 comment for 1114 with no read marker + $this->addDatabaseEntry(0, 0, null, null, '1112'); + for ($i = 1; $i < 5; $i++) { + $this->addDatabaseEntry(0, 0, null, null, '111' . $i); + } + $this->addDatabaseEntry(0, 0, (new \DateTime())->modify('-2 days'), null, '1111'); + $user = $this->createMock(IUser::class); + $user->expects($this->any()) + ->method('getUID') + ->will($this->returnValue('comment_test')); + + $manager = $this->getManager(); + + $manager->setReadMark('files', '1111', (new \DateTime())->modify('-1 days'), $user); + $manager->setReadMark('files', '1113', (new \DateTime()), $user); + + $query = $this->connection->getQueryBuilder(); + $query->insert('filecache') + ->values([ + 'fileid' => $query->createParameter('fileid'), + 'parent' => $query->createNamedParameter(1000), + 'size' => $query->createNamedParameter(10), + 'mtime' => $query->createNamedParameter(10), + 'storage_mtime' => $query->createNamedParameter(10), + 'path' => $query->createParameter('path'), + 'path_hash' => $query->createParameter('path'), + ]); + + for ($i = 1111; $i < 1115; $i++) { + $query->setParameter('path', 'path_' . $i); + $query->setParameter('fileid', $i); + $query->execute(); + } + + $amount = $manager->getNumberOfUnreadCommentsForFolder(1000, $user); + $this->assertEquals([ + '1111' => 1, + '1112' => 2, + '1114' => 1, + ], $amount); + } + public function invalidCreateArgsProvider() { return [ ['', 'aId-1', 'oType-1', 'oId-1'], @@ -380,10 +435,10 @@ class ManagerTest extends TestCase { $manager = $this->getManager(); $comment = new Comment(); $comment - ->setActor('users', 'alice') - ->setObject('files', 'file64') - ->setMessage('very beautiful, I am impressed!') - ->setVerb('comment'); + ->setActor('users', 'alice') + ->setObject('files', 'file64') + ->setMessage('very beautiful, I am impressed!') + ->setVerb('comment'); $manager->save($comment); @@ -401,10 +456,10 @@ class ManagerTest extends TestCase { $manager = $this->getManager(); $comment = new Comment(); $comment - ->setActor('users', 'alice') - ->setObject('files', 'file64') - ->setMessage('very beautiful, I am impressed!') - ->setVerb('comment'); + ->setActor('users', 'alice') + ->setObject('files', 'file64') + ->setMessage('very beautiful, I am impressed!') + ->setVerb('comment'); $manager->save($comment); @@ -428,16 +483,16 @@ class ManagerTest extends TestCase { $manager = $this->getManager(); - for($i = 0; $i < 3; $i++) { + for ($i = 0; $i < 3; $i++) { $comment = new Comment(); $comment - ->setActor('users', 'alice') - ->setObject('files', 'file64') - ->setParentId(strval($id)) - ->setMessage('full ack') - ->setVerb('comment') - // setting the creation time avoids using sleep() while making sure to test with different timestamps - ->setCreationDateTime(new \DateTime('+' . $i . ' minutes')); + ->setActor('users', 'alice') + ->setObject('files', 'file64') + ->setParentId(strval($id)) + ->setMessage('full ack') + ->setVerb('comment') + // setting the creation time avoids using sleep() while making sure to test with different timestamps + ->setCreationDateTime(new \DateTime('+' . $i . ' minutes')); $manager->save($comment); @@ -450,11 +505,11 @@ class ManagerTest extends TestCase { public function invalidActorArgsProvider() { return - [ - ['', ''], - [1, 'alice'], - ['users', 1], - ]; + [ + ['', ''], + [1, 'alice'], + ['users', 1], + ]; } /** @@ -482,7 +537,7 @@ class ManagerTest extends TestCase { $wasSuccessful = $manager->deleteReferencesOfActor('users', 'alice'); $this->assertTrue($wasSuccessful); - foreach($ids as $id) { + foreach ($ids as $id) { $comment = $manager->get(strval($id)); $this->assertSame($comment->getActorType(), ICommentsManager::DELETED_USER); $this->assertSame($comment->getActorId(), ICommentsManager::DELETED_USER); @@ -516,11 +571,11 @@ class ManagerTest extends TestCase { public function invalidObjectArgsProvider() { return - [ - ['', ''], - [1, 'file64'], - ['files', 1], - ]; + [ + ['', ''], + [1, 'file64'], + ['files', 1], + ]; } /** @@ -549,7 +604,7 @@ class ManagerTest extends TestCase { $this->assertTrue($wasSuccessful); $verified = 0; - foreach($ids as $id) { + foreach ($ids as $id) { try { $manager->get(strval($id)); } catch (\OCP\Comments\NotFoundException $e) { @@ -575,7 +630,7 @@ class ManagerTest extends TestCase { $manager = $this->getManager(); $manager->setReadMark('robot', '36', $dateTimeSet, $user); - $dateTimeGet = $manager->getReadMark('robot', '36', $user); + $dateTimeGet = $manager->getReadMark('robot', '36', $user); $this->assertEquals($dateTimeGet->getTimestamp(), $dateTimeSet->getTimestamp()); } @@ -594,7 +649,7 @@ class ManagerTest extends TestCase { $dateTimeSet = new \DateTime('today'); $manager->setReadMark('robot', '36', $dateTimeSet, $user); - $dateTimeGet = $manager->getReadMark('robot', '36', $user); + $dateTimeGet = $manager->getReadMark('robot', '36', $user); $this->assertEquals($dateTimeGet, $dateTimeSet); } @@ -611,7 +666,7 @@ class ManagerTest extends TestCase { $manager->setReadMark('robot', '36', $dateTimeSet, $user); $manager->deleteReadMarksFromUser($user); - $dateTimeGet = $manager->getReadMark('robot', '36', $user); + $dateTimeGet = $manager->getReadMark('robot', '36', $user); $this->assertNull($dateTimeGet); } @@ -628,7 +683,7 @@ class ManagerTest extends TestCase { $manager->setReadMark('robot', '36', $dateTimeSet, $user); $manager->deleteReadMarksOnObject('robot', '36'); - $dateTimeGet = $manager->getReadMark('robot', '36', $user); + $dateTimeGet = $manager->getReadMark('robot', '36', $user); $this->assertNull($dateTimeGet); } @@ -643,8 +698,12 @@ class ManagerTest extends TestCase { ->method('handle'); $manager = $this->getManager(); - $manager->registerEventHandler(function () use ($handler1) {return $handler1; }); - $manager->registerEventHandler(function () use ($handler2) {return $handler2; }); + $manager->registerEventHandler(function () use ($handler1) { + return $handler1; + }); + $manager->registerEventHandler(function () use ($handler2) { + return $handler2; + }); $comment = new Comment(); $comment @@ -667,11 +726,11 @@ class ManagerTest extends TestCase { public function testResolveDisplayName() { $manager = $this->getManager(); - $planetClosure = function($name) { + $planetClosure = function ($name) { return ucfirst($name); }; - $galaxyClosure = function($name) { + $galaxyClosure = function ($name) { return strtoupper($name); }; @@ -688,7 +747,7 @@ class ManagerTest extends TestCase { public function testRegisterResolverDuplicate() { $manager = $this->getManager(); - $planetClosure = function($name) { + $planetClosure = function ($name) { return ucfirst($name); }; $manager->registerDisplayNameResolver('planet', $planetClosure); @@ -701,7 +760,7 @@ class ManagerTest extends TestCase { public function testRegisterResolverInvalidType() { $manager = $this->getManager(); - $planetClosure = function($name) { + $planetClosure = function ($name) { return ucfirst($name); }; $manager->registerDisplayNameResolver(1337, $planetClosure); @@ -713,7 +772,7 @@ class ManagerTest extends TestCase { public function testResolveDisplayNameUnregisteredType() { $manager = $this->getManager(); - $planetClosure = function($name) { + $planetClosure = function ($name) { return ucfirst($name); }; @@ -724,7 +783,9 @@ class ManagerTest extends TestCase { public function testResolveDisplayNameDirtyResolver() { $manager = $this->getManager(); - $planetClosure = function() { return null; }; + $planetClosure = function () { + return null; + }; $manager->registerDisplayNameResolver('planet', $planetClosure); $this->assertTrue(is_string($manager->resolveDisplayName('planet', 'neptune'))); @@ -736,7 +797,9 @@ class ManagerTest extends TestCase { public function testResolveDisplayNameInvalidType() { $manager = $this->getManager(); - $planetClosure = function() { return null; }; + $planetClosure = function () { + return null; + }; $manager->registerDisplayNameResolver('planet', $planetClosure); $this->assertTrue(is_string($manager->resolveDisplayName(1337, 'neptune'))); diff --git a/tests/lib/DB/QueryBuilder/QueryBuilderTest.php b/tests/lib/DB/QueryBuilder/QueryBuilderTest.php index 22808f586ef..150c772b26c 100644 --- a/tests/lib/DB/QueryBuilder/QueryBuilderTest.php +++ b/tests/lib/DB/QueryBuilder/QueryBuilderTest.php @@ -1200,7 +1200,7 @@ class QueryBuilderTest extends \Test\TestCase { public function dataGetColumnName() { return [ ['column', '', '`column`'], - ['column', 'a', 'a.`column`'], + ['column', 'a', '`a`.`column`'], ]; } diff --git a/tests/lib/DB/QueryBuilder/QuoteHelperTest.php b/tests/lib/DB/QueryBuilder/QuoteHelperTest.php index b83d9eed2df..3c1abd72f66 100644 --- a/tests/lib/DB/QueryBuilder/QuoteHelperTest.php +++ b/tests/lib/DB/QueryBuilder/QuoteHelperTest.php @@ -65,7 +65,7 @@ class QuoteHelperTest extends \Test\TestCase { public function dataQuoteColumnNames() { return [ // Single case - ['d.column', 'd.`column`'], + ['d.column', '`d`.`column`'], ['column', '`column`'], [new Literal('literal'), 'literal'], [new Literal(1), '1'], |