recognize: fix compat with 3.6 (fix #500)

Signed-off-by: Varun Patil <varunpatil@ucla.edu>
pull/504/head
Varun Patil 2023-03-18 19:03:17 -07:00
parent 1e424d7e46
commit 47e2d9197f
2 changed files with 39 additions and 23 deletions

View File

@ -39,8 +39,9 @@ class PeopleController extends ApiBase
*/ */
public function recognizePeople(): JSONResponse public function recognizePeople(): JSONResponse
{ {
$user = $this->userSession->getUser(); try {
if (null === $user) { $uid = $this->getUID();
} catch (\Exception $e) {
return Errors::NotLoggedIn(); return Errors::NotLoggedIn();
} }
@ -57,7 +58,7 @@ class PeopleController extends ApiBase
// Run actual query // Run actual query
$list = $this->timelineQuery->getPeopleRecognize( $list = $this->timelineQuery->getPeopleRecognize(
$root, $root, $uid
); );
return new JSONResponse($list, Http::STATUS_OK); return new JSONResponse($list, Http::STATUS_OK);
@ -74,8 +75,9 @@ class PeopleController extends ApiBase
*/ */
public function recognizePeoplePreview(int $id): Http\Response public function recognizePeoplePreview(int $id): Http\Response
{ {
$user = $this->userSession->getUser(); try {
if (null === $user) { $uid = $this->getUID();
} catch (\Exception $e) {
return Errors::NotLoggedIn(); return Errors::NotLoggedIn();
} }
@ -91,13 +93,13 @@ class PeopleController extends ApiBase
} }
// Run actual query // 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 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 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( private function getPreviewResponse(
array $detections, array $detections,
\OCP\IUser $user,
float $padding float $padding
): Http\Response { ): Http\Response {
// Get preview manager // Get preview manager
$previewManager = \OC::$server->get(\OCP\IPreview::class); $previewManager = \OC::$server->get(\OCP\IPreview::class);
// Find the first detection that has a preview
/** @var \Imagick */ /** @var \Imagick */
$image = null; $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) { foreach ($detections as &$detection) {
// Get the file (also checks permissions) // Get the file (also checks permissions)
$files = $userFolder->getById($detection['file_id']); $files = $userFolder->getById($detection['file_id']);

View File

@ -11,14 +11,19 @@ trait TimelineQueryPeopleRecognize
{ {
protected IDBConnection $connection; 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 // Get name and uid of face user
$faceNames = explode('/', $faceStr); $faceNames = explode('/', $faceStr);
if (2 !== \count($faceNames)) { if (2 !== \count($faceNames)) {
throw new \Exception('Invalid face query'); 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]; $faceName = $faceNames[1];
if (!$isAggregate) { if (!$isAggregate) {
@ -28,15 +33,15 @@ trait TimelineQueryPeopleRecognize
// Join with cluster // Join with cluster
$clusterQuery = null; $clusterQuery = null;
if ('NULL' !== $faceName) { if ('NULL' === $faceName) {
$clusterQuery = $query->expr()->isNull('rfd.cluster_id');
} else {
$nameField = is_numeric($faceName) ? 'rfc.id' : 'rfc.title'; $nameField = is_numeric($faceName) ? 'rfc.id' : 'rfc.title';
$query->innerJoin('m', 'recognize_face_clusters', 'rfc', $query->expr()->andX( $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)), $query->expr()->eq($nameField, $query->createNamedParameter($faceName)),
)); ));
$clusterQuery = $query->expr()->eq('rfd.cluster_id', 'rfc.id'); $clusterQuery = $query->expr()->eq('rfd.cluster_id', 'rfc.id');
} else {
$clusterQuery = $query->expr()->isNull('rfd.cluster_id');
} }
// Join with detections // 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(); $query = $this->connection->getQueryBuilder();
@ -74,6 +79,9 @@ trait TimelineQueryPeopleRecognize
// WHERE these photos are in the user's requested folder recursively // WHERE these photos are in the user's requested folder recursively
$query = $this->joinFilecache($query, $root, true, false); $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 // GROUP by ID of face cluster
$query->groupBy('rfc.id'); $query->groupBy('rfc.id');
@ -89,15 +97,15 @@ trait TimelineQueryPeopleRecognize
// Post process // Post process
foreach ($faces as &$row) { foreach ($faces as &$row) {
$row['id'] = (int) $row['id']; $row['id'] = (int) $row['id'];
$row['count'] = (int) $row['count'];
$row['name'] = $row['title']; $row['name'] = $row['title'];
unset($row['title']); unset($row['title']);
$row['count'] = (int) $row['count'];
} }
return $faces; return $faces;
} }
public function getPeopleRecognizePreview(TimelineRoot &$root, int $id) public function getPeopleRecognizePreview(TimelineRoot &$root, int $id, string $uid): array
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
@ -113,7 +121,12 @@ trait TimelineQueryPeopleRecognize
'm.fileid', 'm.fileid',
'm.datetaken', // Just in case, for postgres 'm.datetaken', // Just in case, for postgres
)->from('recognize_face_detections', 'rfd'); )->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 // WHERE these photos are memories indexed
$query->innerJoin('rfd', 'memories', 'm', $query->expr()->eq('m.fileid', 'rfd.file_id')); $query->innerJoin('rfd', 'memories', 'm', $query->expr()->eq('m.fileid', 'rfd.file_id'));
@ -132,7 +145,7 @@ trait TimelineQueryPeopleRecognize
$cursor = $this->executeQueryWithCTEs($query); $cursor = $this->executeQueryWithCTEs($query);
$previews = $cursor->fetchAll(); $previews = $cursor->fetchAll();
if (empty($previews)) { if (empty($previews)) {
return null; return [];
} }
// Score the face detections // Score the face detections