summaryrefslogtreecommitdiffstats
path: root/lib/private/Comments/Manager.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/Comments/Manager.php')
-rw-r--r--lib/private/Comments/Manager.php238
1 files changed, 212 insertions, 26 deletions
diff --git a/lib/private/Comments/Manager.php b/lib/private/Comments/Manager.php
index a0a670817f4..1cc82b5c2ce 100644
--- a/lib/private/Comments/Manager.php
+++ b/lib/private/Comments/Manager.php
@@ -4,7 +4,7 @@
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
+ * @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -30,6 +30,8 @@ namespace OC\Comments;
use Doctrine\DBAL\Exception\DriverException;
use Doctrine\DBAL\Exception\InvalidFieldNameException;
+use OCA\Comments\AppInfo\Application;
+use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Comments\CommentsEvent;
use OCP\Comments\IComment;
use OCP\Comments\ICommentsEventHandler;
@@ -38,20 +40,28 @@ use OCP\Comments\NotFoundException;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IConfig;
use OCP\IDBConnection;
-use OCP\ILogger;
use OCP\IUser;
+use OCP\IInitialStateService;
+use OCP\Util;
+use Psr\Log\LoggerInterface;
class Manager implements ICommentsManager {
/** @var IDBConnection */
protected $dbConn;
- /** @var ILogger */
+ /** @var LoggerInterface */
protected $logger;
/** @var IConfig */
protected $config;
+ /** @var ITimeFactory */
+ protected $timeFactory;
+
+ /** @var IInitialStateService */
+ protected $initialStateService;
+
/** @var IComment[] */
protected $commentsCache = [];
@@ -64,21 +74,16 @@ class Manager implements ICommentsManager {
/** @var \Closure[] */
protected $displayNameResolvers = [];
- /**
- * Manager constructor.
- *
- * @param IDBConnection $dbConn
- * @param ILogger $logger
- * @param IConfig $config
- */
- public function __construct(
- IDBConnection $dbConn,
- ILogger $logger,
- IConfig $config
- ) {
+ public function __construct(IDBConnection $dbConn,
+ LoggerInterface $logger,
+ IConfig $config,
+ ITimeFactory $timeFactory,
+ IInitialStateService $initialStateService) {
$this->dbConn = $dbConn;
$this->logger = $logger;
$this->config = $config;
+ $this->timeFactory = $timeFactory;
+ $this->initialStateService = $initialStateService;
}
/**
@@ -396,6 +401,7 @@ class Manager implements ICommentsManager {
* @param string $sortDirection direction of the comments (`asc` or `desc`)
* @param int $limit optional, number of maximum comments to be returned. if
* set to 0, all comments are returned.
+ * @param bool $includeLastKnown
* @return IComment[]
* @return array
*/
@@ -404,7 +410,8 @@ class Manager implements ICommentsManager {
string $objectId,
int $lastKnownCommentId,
string $sortDirection = 'asc',
- int $limit = 30
+ int $limit = 30,
+ bool $includeLastKnown = false
): array {
$comments = [];
@@ -428,6 +435,11 @@ class Manager implements ICommentsManager {
if ($lastKnownComment instanceof IComment) {
$lastKnownCommentDateTime = $lastKnownComment->getCreationDateTime();
if ($sortDirection === 'desc') {
+ if ($includeLastKnown) {
+ $idComparison = $query->expr()->lte('id', $query->createNamedParameter($lastKnownCommentId));
+ } else {
+ $idComparison = $query->expr()->lt('id', $query->createNamedParameter($lastKnownCommentId));
+ }
$query->andWhere(
$query->expr()->orX(
$query->expr()->lt(
@@ -441,11 +453,16 @@ class Manager implements ICommentsManager {
$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
IQueryBuilder::PARAM_DATE
),
- $query->expr()->lt('id', $query->createNamedParameter($lastKnownCommentId))
+ $idComparison
)
)
);
} else {
+ if ($includeLastKnown) {
+ $idComparison = $query->expr()->gte('id', $query->createNamedParameter($lastKnownCommentId));
+ } else {
+ $idComparison = $query->expr()->gt('id', $query->createNamedParameter($lastKnownCommentId));
+ }
$query->andWhere(
$query->expr()->orX(
$query->expr()->gt(
@@ -459,7 +476,7 @@ class Manager implements ICommentsManager {
$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
IQueryBuilder::PARAM_DATE
),
- $query->expr()->gt('id', $query->createNamedParameter($lastKnownCommentId))
+ $idComparison
)
)
);
@@ -518,6 +535,25 @@ class Manager implements ICommentsManager {
* @return IComment[]
*/
public function search(string $search, string $objectType, string $objectId, string $verb, int $offset, int $limit = 50): array {
+ $objectIds = [];
+ if ($objectId) {
+ $objectIds[] = $objectIds;
+ }
+ return $this->searchForObjects($search, $objectType, $objectIds, $verb, $offset, $limit);
+ }
+
+ /**
+ * Search for comments on one or more objects with a given content
+ *
+ * @param string $search content to search for
+ * @param string $objectType Limit the search by object type
+ * @param array $objectIds Limit the search by object ids
+ * @param string $verb Limit the verb of the comment
+ * @param int $offset
+ * @param int $limit
+ * @return IComment[]
+ */
+ public function searchForObjects(string $search, string $objectType, array $objectIds, string $verb, int $offset, int $limit = 50): array {
$query = $this->dbConn->getQueryBuilder();
$query->select('*')
@@ -532,8 +568,8 @@ class Manager implements ICommentsManager {
if ($objectType !== '') {
$query->andWhere($query->expr()->eq('object_type', $query->createNamedParameter($objectType)));
}
- if ($objectId !== '') {
- $query->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)));
+ if (!empty($objectIds)) {
+ $query->andWhere($query->expr()->in('object_id', $query->createNamedParameter($objectIds, IQueryBuilder::PARAM_STR_ARRAY)));
}
if ($verb !== '') {
$query->andWhere($query->expr()->eq('verb', $query->createNamedParameter($verb)));
@@ -589,13 +625,145 @@ class Manager implements ICommentsManager {
}
/**
+ * @param string $objectType the object type, e.g. 'files'
+ * @param string[] $objectIds the id of the object
+ * @param IUser $user
+ * @param string $verb Limit the verb of the comment - Added in 14.0.0
+ * @return array Map with object id => # of unread comments
+ * @psalm-return array<string, int>
+ * @since 21.0.0
+ */
+ public function getNumberOfUnreadCommentsForObjects(string $objectType, array $objectIds, IUser $user, $verb = ''): array {
+ $query = $this->dbConn->getQueryBuilder();
+ $query->select('c.object_id', $query->func()->count('c.id', 'num_comments'))
+ ->from('comments', 'c')
+ ->leftJoin('c', 'comments_read_markers', 'm', $query->expr()->andX(
+ $query->expr()->eq('m.user_id', $query->createNamedParameter($user->getUID())),
+ $query->expr()->eq('c.object_type', 'm.object_type'),
+ $query->expr()->eq('c.object_id', 'm.object_id')
+ ))
+ ->where($query->expr()->eq('c.object_type', $query->createNamedParameter($objectType)))
+ ->andWhere($query->expr()->in('c.object_id', $query->createNamedParameter($objectIds, IQueryBuilder::PARAM_STR_ARRAY)))
+ ->andWhere($query->expr()->orX(
+ $query->expr()->gt('c.creation_timestamp', 'm.marker_datetime'),
+ $query->expr()->isNull('m.marker_datetime')
+ ))
+ ->groupBy('c.object_id');
+
+ if ($verb !== '') {
+ $query->andWhere($query->expr()->eq('c.verb', $query->createNamedParameter($verb)));
+ }
+
+ $result = $query->execute();
+ $unreadComments = array_fill_keys($objectIds, 0);
+ while ($row = $result->fetch()) {
+ $unreadComments[$row['object_id']] = (int) $row['num_comments'];
+ }
+ $result->closeCursor();
+
+ return $unreadComments;
+ }
+
+ /**
+ * @param string $objectType
+ * @param string $objectId
+ * @param int $lastRead
+ * @param string $verb
+ * @return int
+ * @since 21.0.0
+ */
+ public function getNumberOfCommentsForObjectSinceComment(string $objectType, string $objectId, int $lastRead, string $verb = ''): int {
+ $query = $this->dbConn->getQueryBuilder();
+ $query->select($query->func()->count('id', 'num_messages'))
+ ->from('comments')
+ ->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
+ ->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
+ ->andWhere($query->expr()->gt('id', $query->createNamedParameter($lastRead)));
+
+ if ($verb !== '') {
+ $query->andWhere($query->expr()->eq('verb', $query->createNamedParameter($verb)));
+ }
+
+ $result = $query->execute();
+ $data = $result->fetch();
+ $result->closeCursor();
+
+ return (int) ($data['num_messages'] ?? 0);
+ }
+
+ /**
+ * @param string $objectType
+ * @param string $objectId
+ * @param \DateTime $beforeDate
+ * @param string $verb
+ * @return int
+ * @since 21.0.0
+ */
+ public function getLastCommentBeforeDate(string $objectType, string $objectId, \DateTime $beforeDate, string $verb = ''): int {
+ $query = $this->dbConn->getQueryBuilder();
+ $query->select('id')
+ ->from('comments')
+ ->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
+ ->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
+ ->andWhere($query->expr()->lt('creation_timestamp', $query->createNamedParameter($beforeDate, IQueryBuilder::PARAM_DATE)))
+ ->orderBy('creation_timestamp', 'desc');
+
+ if ($verb !== '') {
+ $query->andWhere($query->expr()->eq('verb', $query->createNamedParameter($verb)));
+ }
+
+ $result = $query->execute();
+ $data = $result->fetch();
+ $result->closeCursor();
+
+ return (int) ($data['id'] ?? 0);
+ }
+
+ /**
+ * @param string $objectType
+ * @param string $objectId
+ * @param string $verb
+ * @param string $actorType
+ * @param string[] $actors
+ * @return \DateTime[] Map of "string actor" => "\DateTime most recent comment date"
+ * @psalm-return array<string, \DateTime>
+ * @since 21.0.0
+ */
+ public function getLastCommentDateByActor(
+ string $objectType,
+ string $objectId,
+ string $verb,
+ string $actorType,
+ array $actors
+ ): array {
+ $lastComments = [];
+
+ $query = $this->dbConn->getQueryBuilder();
+ $query->select('actor_id')
+ ->selectAlias($query->createFunction('MAX(' . $query->getColumnName('creation_timestamp') . ')'), 'last_comment')
+ ->from('comments')
+ ->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
+ ->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
+ ->andWhere($query->expr()->eq('verb', $query->createNamedParameter($verb)))
+ ->andWhere($query->expr()->eq('actor_type', $query->createNamedParameter($actorType)))
+ ->andWhere($query->expr()->in('actor_id', $query->createNamedParameter($actors, IQueryBuilder::PARAM_STR_ARRAY)))
+ ->groupBy('actor_id');
+
+ $result = $query->execute();
+ while ($row = $result->fetch()) {
+ $lastComments[$row['actor_id']] = $this->timeFactory->getDateTime($row['last_comment']);
+ }
+ $result->closeCursor();
+
+ return $lastComments;
+ }
+
+ /**
* Get the number of unread comments for all files in a folder
*
* @param int $folderId
* @param IUser $user
* @return array [$fileId => $unreadCount]
- *
- * @suppress SqlInjectionChecker
*/
public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user) {
$qb = $this->dbConn->getQueryBuilder();
@@ -695,7 +863,10 @@ class Manager implements ICommentsManager {
$affectedRows = $query->execute();
$this->uncache($id);
} catch (DriverException $e) {
- $this->logger->logException($e, ['app' => 'core_comments']);
+ $this->logger->error($e->getMessage(), [
+ 'exception' => $e,
+ 'app' => 'core_comments',
+ ]);
return false;
}
@@ -920,7 +1091,10 @@ class Manager implements ICommentsManager {
try {
$affectedRows = $query->execute();
} catch (DriverException $e) {
- $this->logger->logException($e, ['app' => 'core_comments']);
+ $this->logger->error($e->getMessage(), [
+ 'exception' => $e,
+ 'app' => 'core_comments',
+ ]);
return false;
}
return ($affectedRows > 0);
@@ -935,7 +1109,6 @@ class Manager implements ICommentsManager {
* @param \DateTime $dateTime
* @param IUser $user
* @since 9.0.0
- * @suppress SqlInjectionChecker
*/
public function setReadMark($objectType, $objectId, \DateTime $dateTime, IUser $user) {
$this->checkRoleParameters('Object', $objectType, $objectId);
@@ -1025,7 +1198,10 @@ class Manager implements ICommentsManager {
try {
$affectedRows = $query->execute();
} catch (DriverException $e) {
- $this->logger->logException($e, ['app' => 'core_comments']);
+ $this->logger->error($e->getMessage(), [
+ 'exception' => $e,
+ 'app' => 'core_comments',
+ ]);
return false;
}
return ($affectedRows > 0);
@@ -1121,4 +1297,14 @@ class Manager implements ICommentsManager {
$entity->handle($event);
}
}
+
+ /**
+ * Load the Comments app into the page
+ *
+ * @since 21.0.0
+ */
+ public function load(): void {
+ $this->initialStateService->provideInitialState(Application::APP_ID, 'max-message-length', IComment::MAX_MESSAGE_LENGTH);
+ Util::addScript(Application::APP_ID, 'comments-app');
+ }
}