diff options
author | Morris Jobke <hey@morrisjobke.de> | 2017-04-10 13:21:39 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-10 13:21:39 -0500 |
commit | a045f3c4d7ef606ea302712952ec474d5ea5637a (patch) | |
tree | 4edf7b74e8220a4ed06fc1f3e9b2b7064e21cd6a /lib | |
parent | a750436ebc3a71f4fe34596cc0bdb1f9b61ba912 (diff) | |
parent | 11c1e5dd8641e38c44e49d0f527444be7f92da1b (diff) | |
download | nextcloud-server-a045f3c4d7ef606ea302712952ec474d5ea5637a.tar.gz nextcloud-server-a045f3c4d7ef606ea302712952ec474d5ea5637a.zip |
Merge pull request #4146 from nextcloud/unread-comments-folder
Allow getting the unread comment count for an entire folder at once
Diffstat (limited to 'lib')
-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 |
4 files changed, 138 insertions, 90 deletions
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). |