From 47e2d9197fba76a6048a062941c4ed8091c0ff83 Mon Sep 17 00:00:00 2001 From: Varun Patil Date: Sat, 18 Mar 2023 19:03:17 -0700 Subject: [PATCH] recognize: fix compat with 3.6 (fix #500) Signed-off-by: Varun Patil --- lib/Controller/PeopleController.php | 27 ++++++++++--------- lib/Db/TimelineQueryPeopleRecognize.php | 35 +++++++++++++++++-------- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/lib/Controller/PeopleController.php b/lib/Controller/PeopleController.php index 7e729177..50e400f5 100644 --- a/lib/Controller/PeopleController.php +++ b/lib/Controller/PeopleController.php @@ -39,8 +39,9 @@ class PeopleController extends ApiBase */ public function recognizePeople(): JSONResponse { - $user = $this->userSession->getUser(); - if (null === $user) { + try { + $uid = $this->getUID(); + } catch (\Exception $e) { return Errors::NotLoggedIn(); } @@ -57,7 +58,7 @@ class PeopleController extends ApiBase // Run actual query $list = $this->timelineQuery->getPeopleRecognize( - $root, + $root, $uid ); return new JSONResponse($list, Http::STATUS_OK); @@ -74,8 +75,9 @@ class PeopleController extends ApiBase */ public function recognizePeoplePreview(int $id): Http\Response { - $user = $this->userSession->getUser(); - if (null === $user) { + try { + $uid = $this->getUID(); + } catch (\Exception $e) { return Errors::NotLoggedIn(); } @@ -91,13 +93,13 @@ class PeopleController extends ApiBase } // Run actual query - $detections = $this->timelineQuery->getPeopleRecognizePreview($root, $id); + $detections = $this->timelineQuery->getPeopleRecognizePreview($root, $id, $uid); - if (null === $detections || 0 === \count($detections)) { + if (0 === \count($detections)) { return Errors::NotFound('detections'); } - return $this->getPreviewResponse($detections, $user, 1.5); + return $this->getPreviewResponse($detections, 1.5); } /** @@ -183,7 +185,7 @@ class PeopleController extends ApiBase return Errors::NotFound('detections'); } - return $this->getPreviewResponse($detections, $user, 1.8); + return $this->getPreviewResponse($detections, 1.8); } /** @@ -195,16 +197,17 @@ class PeopleController extends ApiBase */ private function getPreviewResponse( array $detections, - \OCP\IUser $user, float $padding ): Http\Response { // Get preview manager $previewManager = \OC::$server->get(\OCP\IPreview::class); - // Find the first detection that has a preview /** @var \Imagick */ $image = null; - $userFolder = $this->rootFolder->getUserFolder($user->getUID()); + + // Find the first detection that has a preview + $userFolder = $this->rootFolder->getUserFolder($this->getUID()); + foreach ($detections as &$detection) { // Get the file (also checks permissions) $files = $userFolder->getById($detection['file_id']); diff --git a/lib/Db/TimelineQueryPeopleRecognize.php b/lib/Db/TimelineQueryPeopleRecognize.php index d6b9b9ea..8cceb855 100644 --- a/lib/Db/TimelineQueryPeopleRecognize.php +++ b/lib/Db/TimelineQueryPeopleRecognize.php @@ -11,14 +11,19 @@ trait TimelineQueryPeopleRecognize { protected IDBConnection $connection; - public function transformPeopleRecognitionFilter(IQueryBuilder &$query, string $userId, string $faceStr, bool $isAggregate) + public function transformPeopleRecognitionFilter(IQueryBuilder $query, string $userId, string $faceStr, bool $isAggregate) { // Get name and uid of face user $faceNames = explode('/', $faceStr); if (2 !== \count($faceNames)) { throw new \Exception('Invalid face query'); } - $faceUid = $faceNames[0]; + + // Starting with Recognize v3.6, the detections are duplicated for each user + // So we don't need to use the user ID provided by the user, but retain + // this here for backwards compatibility + API consistency with Face Recognition + // $faceUid = $faceNames[0]; + $faceName = $faceNames[1]; if (!$isAggregate) { @@ -28,15 +33,15 @@ trait TimelineQueryPeopleRecognize // Join with cluster $clusterQuery = null; - if ('NULL' !== $faceName) { + if ('NULL' === $faceName) { + $clusterQuery = $query->expr()->isNull('rfd.cluster_id'); + } else { $nameField = is_numeric($faceName) ? 'rfc.id' : 'rfc.title'; $query->innerJoin('m', 'recognize_face_clusters', 'rfc', $query->expr()->andX( - $query->expr()->eq('rfc.user_id', $query->createNamedParameter($faceUid)), + $query->expr()->eq('rfc.user_id', $query->createNamedParameter($userId)), $query->expr()->eq($nameField, $query->createNamedParameter($faceName)), )); $clusterQuery = $query->expr()->eq('rfd.cluster_id', 'rfc.id'); - } else { - $clusterQuery = $query->expr()->isNull('rfd.cluster_id'); } // Join with detections @@ -57,7 +62,7 @@ trait TimelineQueryPeopleRecognize ); } - public function getPeopleRecognize(TimelineRoot &$root) + public function getPeopleRecognize(TimelineRoot &$root, string $uid) { $query = $this->connection->getQueryBuilder(); @@ -74,6 +79,9 @@ trait TimelineQueryPeopleRecognize // WHERE these photos are in the user's requested folder recursively $query = $this->joinFilecache($query, $root, true, false); + // WHERE this cluster belongs to the user + $query->where($query->expr()->eq('rfc.user_id', $query->createNamedParameter($uid))); + // GROUP by ID of face cluster $query->groupBy('rfc.id'); @@ -89,15 +97,15 @@ trait TimelineQueryPeopleRecognize // Post process foreach ($faces as &$row) { $row['id'] = (int) $row['id']; + $row['count'] = (int) $row['count']; $row['name'] = $row['title']; unset($row['title']); - $row['count'] = (int) $row['count']; } return $faces; } - public function getPeopleRecognizePreview(TimelineRoot &$root, int $id) + public function getPeopleRecognizePreview(TimelineRoot &$root, int $id, string $uid): array { $query = $this->connection->getQueryBuilder(); @@ -113,7 +121,12 @@ trait TimelineQueryPeopleRecognize 'm.fileid', 'm.datetaken', // Just in case, for postgres )->from('recognize_face_detections', 'rfd'); - $query->where($query->expr()->eq('rfd.cluster_id', $query->createNamedParameter($id))); + + // WHERE detection belongs to this cluster AND user + $query->where($query->expr()->andX( + $query->expr()->eq('rfd.cluster_id', $query->createNamedParameter($id)), + $query->expr()->eq('rfd.user_id', $query->createNamedParameter($uid)), + )); // WHERE these photos are memories indexed $query->innerJoin('rfd', 'memories', 'm', $query->expr()->eq('m.fileid', 'rfd.file_id')); @@ -132,7 +145,7 @@ trait TimelineQueryPeopleRecognize $cursor = $this->executeQueryWithCTEs($query); $previews = $cursor->fetchAll(); if (empty($previews)) { - return null; + return []; } // Score the face detections