refactor: fs manager

Signed-off-by: Varun Patil <varunpatil@ucla.edu>
pull/563/head
Varun Patil 2023-03-23 14:45:56 -07:00
parent 5c9f1c4915
commit 78d063eed6
23 changed files with 160 additions and 170 deletions

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace OCA\Memories\ClustersBackend; namespace OCA\Memories\ClustersBackend;
use OCA\Memories\Db\TimelineQuery; use OCA\Memories\Db\TimelineQuery;
use OCA\Memories\Db\TimelineRoot;
use OCA\Memories\Util; use OCA\Memories\Util;
use OCP\IConfig; use OCP\IConfig;
@ -32,7 +31,6 @@ class FaceRecognitionBackend extends Backend
{ {
use PeopleBackendUtils; use PeopleBackendUtils;
public TimelineRoot $root;
protected TimelineQuery $timelineQuery; protected TimelineQuery $timelineQuery;
protected IConfig $config; protected IConfig $config;
@ -58,14 +56,14 @@ class FaceRecognitionBackend extends Backend
public function getClusters(): array public function getClusters(): array
{ {
return array_merge( return array_merge(
$this->timelineQuery->getFaceRecognitionPersons($this->root, $this->model()), $this->timelineQuery->getFaceRecognitionPersons($this->model()),
$this->timelineQuery->getFaceRecognitionClusters($this->root, $this->model()) $this->timelineQuery->getFaceRecognitionClusters($this->model())
); );
} }
public function getPhotos(string $name, ?int $limit = null): array public function getPhotos(string $name, ?int $limit = null): array
{ {
return $this->timelineQuery->getFaceRecognitionPhotos($name, $this->model(), $this->root, $limit) ?? []; return $this->timelineQuery->getFaceRecognitionPhotos($name, $this->model(), $limit) ?? [];
} }
public function sortPhotosForPreview(array &$photos) public function sortPhotosForPreview(array &$photos)

View File

@ -24,12 +24,10 @@ declare(strict_types=1);
namespace OCA\Memories\ClustersBackend; namespace OCA\Memories\ClustersBackend;
use OCA\Memories\Db\TimelineQuery; use OCA\Memories\Db\TimelineQuery;
use OCA\Memories\Db\TimelineRoot;
use OCA\Memories\Util; use OCA\Memories\Util;
class PlacesBackend extends Backend class PlacesBackend extends Backend
{ {
public TimelineRoot $root;
protected TimelineQuery $timelineQuery; protected TimelineQuery $timelineQuery;
public function __construct( public function __construct(
@ -50,11 +48,11 @@ class PlacesBackend extends Backend
public function getClusters(): array public function getClusters(): array
{ {
return $this->timelineQuery->getPlaces($this->root); return $this->timelineQuery->getPlaces();
} }
public function getPhotos(string $name, ?int $limit = null): array public function getPhotos(string $name, ?int $limit = null): array
{ {
return $this->timelineQuery->getPlacePhotos((int) $name, $this->root, $limit) ?? []; return $this->timelineQuery->getPlacePhotos((int) $name, $limit) ?? [];
} }
} }

View File

@ -24,14 +24,12 @@ declare(strict_types=1);
namespace OCA\Memories\ClustersBackend; namespace OCA\Memories\ClustersBackend;
use OCA\Memories\Db\TimelineQuery; use OCA\Memories\Db\TimelineQuery;
use OCA\Memories\Db\TimelineRoot;
use OCA\Memories\Util; use OCA\Memories\Util;
class RecognizeBackend extends Backend class RecognizeBackend extends Backend
{ {
use PeopleBackendUtils; use PeopleBackendUtils;
public TimelineRoot $root;
protected TimelineQuery $timelineQuery; protected TimelineQuery $timelineQuery;
public function __construct( public function __construct(
@ -52,12 +50,12 @@ class RecognizeBackend extends Backend
public function getClusters(): array public function getClusters(): array
{ {
return $this->timelineQuery->getPeopleRecognize($this->root, Util::getUID()); return $this->timelineQuery->getPeopleRecognize(Util::getUID());
} }
public function getPhotos(string $name, ?int $limit = null): array public function getPhotos(string $name, ?int $limit = null): array
{ {
return $this->timelineQuery->getPeopleRecognizePhotos((int) $name, $this->root, $limit) ?? []; return $this->timelineQuery->getPeopleRecognizePhotos((int) $name, $limit) ?? [];
} }
public function sortPhotosForPreview(array &$photos) public function sortPhotosForPreview(array &$photos)

View File

@ -24,12 +24,10 @@ declare(strict_types=1);
namespace OCA\Memories\ClustersBackend; namespace OCA\Memories\ClustersBackend;
use OCA\Memories\Db\TimelineQuery; use OCA\Memories\Db\TimelineQuery;
use OCA\Memories\Db\TimelineRoot;
use OCA\Memories\Util; use OCA\Memories\Util;
class TagsBackend extends Backend class TagsBackend extends Backend
{ {
public TimelineRoot $root;
protected TimelineQuery $timelineQuery; protected TimelineQuery $timelineQuery;
public function __construct( public function __construct(
@ -50,11 +48,11 @@ class TagsBackend extends Backend
public function getClusters(): array public function getClusters(): array
{ {
return $this->timelineQuery->getTags($this->root); return $this->timelineQuery->getTags();
} }
public function getPhotos(string $name, ?int $limit = null): array public function getPhotos(string $name, ?int $limit = null): array
{ {
return $this->timelineQuery->getTagPhotos($name, $this->root, $limit) ?? []; return $this->timelineQuery->getTagPhotos($name, $limit) ?? [];
} }
} }

View File

@ -123,13 +123,6 @@ class ClustersController extends GenericApiController
if (!$this->backend->isEnabled()) { if (!$this->backend->isEnabled()) {
throw Exceptions::NotEnabled($this->backend->appName()); throw Exceptions::NotEnabled($this->backend->appName());
} }
if (property_exists($this->backend, 'root')) {
$this->backend->root = $this->getRequestRoot();
if ($this->backend->root->isEmpty()) {
throw Exceptions::NoRequestRoot();
}
}
} }
/** /**

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace OCA\Memories\Controller; namespace OCA\Memories\Controller;
use OCA\Memories\Db\TimelineRoot;
use OCA\Memories\Exceptions; use OCA\Memories\Exceptions;
use OCA\Memories\Util; use OCA\Memories\Util;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
@ -42,10 +41,8 @@ class DaysController extends GenericApiController
{ {
return Util::guardEx(function () { return Util::guardEx(function () {
$uid = $this->getShareToken() ? '' : Util::getUID(); $uid = $this->getShareToken() ? '' : Util::getUID();
$root = $this->getRequestRoot();
$list = $this->timelineQuery->getDays( $list = $this->timelineQuery->getDays(
$root,
$uid, $uid,
$this->isRecursive(), $this->isRecursive(),
$this->isArchive(), $this->isArchive(),
@ -57,7 +54,7 @@ class DaysController extends GenericApiController
$list = $this->timelineQuery->daysToMonths($list); $list = $this->timelineQuery->daysToMonths($list);
} else { } else {
// Preload some day responses // Preload some day responses
$this->preloadDays($list, $uid, $root); $this->preloadDays($list, $uid);
} }
// Reverse response if requested. Folders still stay at top. // Reverse response if requested. Folders still stay at top.
@ -67,6 +64,7 @@ class DaysController extends GenericApiController
// Add subfolder info if querying non-recursively // Add subfolder info if querying non-recursively
if (!$this->isRecursive()) { if (!$this->isRecursive()) {
$root = $this->timelineQuery->root();
array_unshift($list, $this->getSubfoldersEntry($root->getFolder($root->getOneId()))); array_unshift($list, $this->getSubfoldersEntry($root->getFolder($root->getOneId())));
} }
@ -98,9 +96,6 @@ class DaysController extends GenericApiController
return new JSONResponse([], Http::STATUS_OK); return new JSONResponse([], Http::STATUS_OK);
} }
// Get the folder to show
$root = $this->getRequestRoot();
// Convert to actual dayIds if month view // Convert to actual dayIds if month view
if ($this->isMonthView()) { if ($this->isMonthView()) {
$dayIds = $this->timelineQuery->monthIdToDayIds((int) $dayIds[0]); $dayIds = $this->timelineQuery->monthIdToDayIds((int) $dayIds[0]);
@ -108,7 +103,6 @@ class DaysController extends GenericApiController
// Run actual query // Run actual query
$list = $this->timelineQuery->getDay( $list = $this->timelineQuery->getDay(
$root,
$uid, $uid,
$dayIds, $dayIds,
$this->isRecursive(), $this->isRecursive(),
@ -158,17 +152,9 @@ class DaysController extends GenericApiController
{ {
$transforms = []; $transforms = [];
// Add extra information, basename and mimetype
if (!$aggregateOnly && ($fields = $this->request->getParam('fields'))) {
$fields = explode(',', $fields);
$transforms[] = [$this->timelineQuery, 'transformExtraFields', $fields];
}
// Filter for one album // Filter for one album
if (Util::albumsIsEnabled()) { if (($albumId = $this->request->getParam('album')) && Util::albumsIsEnabled()) {
if ($albumId = $this->request->getParam('album')) { $transforms[] = [$this->timelineQuery, 'transformAlbumFilter', $albumId];
$transforms[] = [$this->timelineQuery, 'transformAlbumFilter', $albumId];
}
} }
// Other transforms not allowed for public shares // Other transforms not allowed for public shares
@ -235,11 +221,10 @@ class DaysController extends GenericApiController
/** /**
* Preload a few "day" at the start of "days" response. * Preload a few "day" at the start of "days" response.
* *
* @param array $days the days array * @param array $days the days array
* @param string $uid User ID or blank for public shares * @param string $uid User ID or blank for public shares
* @param TimelineRoot $root the root folder
*/ */
private function preloadDays(array &$days, string $uid, TimelineRoot &$root) private function preloadDays(array &$days, string $uid)
{ {
$transforms = $this->getTransformations(false); $transforms = $this->getTransformations(false);
$preloaded = 0; $preloaded = 0;
@ -261,7 +246,6 @@ class DaysController extends GenericApiController
if (\count($preloadDayIds) > 0) { if (\count($preloadDayIds) > 0) {
$allDetails = $this->timelineQuery->getDay( $allDetails = $this->timelineQuery->getDay(
$root,
$uid, $uid,
$preloadDayIds, $preloadDayIds,
$this->isRecursive(), $this->isRecursive(),

View File

@ -128,7 +128,7 @@ class DownloadController extends GenericApiController
public function one(int $fileid): Http\Response public function one(int $fileid): Http\Response
{ {
return Util::guardEx(function () use ($fileid) { return Util::guardEx(function () use ($fileid) {
$file = $this->getUserFile($fileid); $file = $this->fs->getUserFile($fileid);
if (null === $file) { if (null === $file) {
return Exceptions::NotFoundFile($fileid); return Exceptions::NotFoundFile($fileid);
} }
@ -215,7 +215,7 @@ class DownloadController extends GenericApiController
try { try {
// This checks permissions // This checks permissions
$file = $this->getUserFile($fileId); $file = $this->fs->getUserFile($fileId);
if (null === $file) { if (null === $file) {
throw new \Exception('File not found'); throw new \Exception('File not found');
} }

View File

@ -25,6 +25,7 @@ namespace OCA\Memories\Controller;
use OCA\Memories\AppInfo\Application; use OCA\Memories\AppInfo\Application;
use OCA\Memories\Db\TimelineQuery; use OCA\Memories\Db\TimelineQuery;
use OCA\Memories\Manager\FsManager;
use OCP\App\IAppManager; use OCP\App\IAppManager;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\Files\IRootFolder; use OCP\Files\IRootFolder;
@ -36,16 +37,16 @@ use Psr\Log\LoggerInterface;
abstract class GenericApiController extends Controller abstract class GenericApiController extends Controller
{ {
use GenericApiControllerFs;
use GenericApiControllerParams; use GenericApiControllerParams;
protected IConfig $config; protected IConfig $config;
protected IUserSession $userSession; protected IUserSession $userSession;
protected IRootFolder $rootFolder; protected IRootFolder $rootFolder;
protected IAppManager $appManager; protected IAppManager $appManager;
protected TimelineQuery $timelineQuery;
protected IDBConnection $connection; protected IDBConnection $connection;
protected LoggerInterface $logger; protected LoggerInterface $logger;
protected TimelineQuery $timelineQuery;
protected FsManager $fs;
public function __construct( public function __construct(
IRequest $request, IRequest $request,
@ -55,7 +56,8 @@ abstract class GenericApiController extends Controller
IRootFolder $rootFolder, IRootFolder $rootFolder,
IAppManager $appManager, IAppManager $appManager,
LoggerInterface $logger, LoggerInterface $logger,
TimelineQuery $timelineQuery TimelineQuery $timelineQuery,
FsManager $fs
) { ) {
parent::__construct(Application::APPNAME, $request); parent::__construct(Application::APPNAME, $request);
@ -66,5 +68,6 @@ abstract class GenericApiController extends Controller
$this->appManager = $appManager; $this->appManager = $appManager;
$this->logger = $logger; $this->logger = $logger;
$this->timelineQuery = $timelineQuery; $this->timelineQuery = $timelineQuery;
$this->fs = $fs;
} }
} }

View File

@ -55,7 +55,7 @@ class ImageController extends GenericApiController
throw Exceptions::MissingParameter('id, x, y'); throw Exceptions::MissingParameter('id, x, y');
} }
$file = $this->getUserFile($id); $file = $this->fs->getUserFile($id);
if (!$file) { if (!$file) {
throw Exceptions::NotFoundFile($id); throw Exceptions::NotFoundFile($id);
} }
@ -113,7 +113,7 @@ class ImageController extends GenericApiController
continue; continue;
} }
$file = $this->getUserFile($fileid); $file = $this->fs->getUserFile($fileid);
if (!$file) { if (!$file) {
continue; continue;
} }
@ -178,7 +178,7 @@ class ImageController extends GenericApiController
bool $tags = false bool $tags = false
): Http\Response { ): Http\Response {
return Util::guardEx(function () use ($id, $basic, $current, $tags) { return Util::guardEx(function () use ($id, $basic, $current, $tags) {
$file = $this->getUserFile((int) $id); $file = $this->fs->getUserFile((int) $id);
if (!$file) { if (!$file) {
throw Exceptions::NotFoundFile($id); throw Exceptions::NotFoundFile($id);
} }
@ -222,7 +222,7 @@ class ImageController extends GenericApiController
public function setExif(string $id, array $raw): Http\Response public function setExif(string $id, array $raw): Http\Response
{ {
return Util::guardEx(function () use ($id, $raw) { return Util::guardEx(function () use ($id, $raw) {
$file = $this->getUserFile((int) $id); $file = $this->fs->getUserFile((int) $id);
if (!$file) { if (!$file) {
throw Exceptions::NotFoundFile($id); throw Exceptions::NotFoundFile($id);
} }
@ -261,7 +261,7 @@ class ImageController extends GenericApiController
public function decodable(string $id): Http\Response public function decodable(string $id): Http\Response
{ {
return Util::guardEx(function () use ($id) { return Util::guardEx(function () use ($id) {
$file = $this->getUserFile((int) $id); $file = $this->fs->getUserFile((int) $id);
if (!$file) { if (!$file) {
throw Exceptions::NotFoundFile($id); throw Exceptions::NotFoundFile($id);
} }

View File

@ -36,9 +36,6 @@ class MapController extends GenericApiController
public function clusters(): Http\Response public function clusters(): Http\Response
{ {
return Util::guardEx(function () { return Util::guardEx(function () {
// Get the folder to show
$root = $this->getRequestRoot();
// Make sure we have bounds and zoom level // Make sure we have bounds and zoom level
// Zoom level is used to determine the grid length // Zoom level is used to determine the grid length
$bounds = $this->request->getParam('bounds'); $bounds = $this->request->getParam('bounds');
@ -52,11 +49,11 @@ class MapController extends GenericApiController
$clusterDensity = 1; $clusterDensity = 1;
$gridLen = 180.0 / (2 ** $zoomLevel * $clusterDensity); $gridLen = 180.0 / (2 ** $zoomLevel * $clusterDensity);
$clusters = $this->timelineQuery->getMapClusters($gridLen, $bounds, $root); $clusters = $this->timelineQuery->getMapClusters($gridLen, $bounds);
// Get previews for each cluster // Get previews for each cluster
$clusterIds = array_map(fn ($cluster) => (int) $cluster['id'], $clusters); $clusterIds = array_map(fn ($cluster) => (int) $cluster['id'], $clusters);
$previews = $this->timelineQuery->getMapClusterPreviews($clusterIds, $root); $previews = $this->timelineQuery->getMapClusterPreviews($clusterIds);
// Merge the responses // Merge the responses
$fileMap = []; $fileMap = [];

View File

@ -4,7 +4,6 @@ namespace OCA\Memories\Controller;
use OCA\Memories\AppInfo\Application; use OCA\Memories\AppInfo\Application;
use OCA\Memories\Db\TimelineQuery; use OCA\Memories\Db\TimelineQuery;
use OCP\App\IAppManager;
use OCP\AppFramework\AuthPublicShareController; use OCP\AppFramework\AuthPublicShareController;
use OCP\AppFramework\Http\Template\PublicTemplateResponse; use OCP\AppFramework\Http\Template\PublicTemplateResponse;
use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\TemplateResponse;
@ -16,7 +15,6 @@ use OCP\IConfig;
use OCP\IRequest; use OCP\IRequest;
use OCP\ISession; use OCP\ISession;
use OCP\IURLGenerator; use OCP\IURLGenerator;
use OCP\IUserManager;
use OCP\IUserSession; use OCP\IUserSession;
use OCP\Share\IManager as IShareManager; use OCP\Share\IManager as IShareManager;
use OCP\Share\IShare; use OCP\Share\IShare;
@ -30,8 +28,6 @@ class PublicController extends AuthPublicShareController
protected IUserSession $userSession; protected IUserSession $userSession;
protected IRootFolder $rootFolder; protected IRootFolder $rootFolder;
protected IShareManager $shareManager; protected IShareManager $shareManager;
protected IUserManager $userManager;
protected IAppManager $appManager;
protected IConfig $config; protected IConfig $config;
protected TimelineQuery $timelineQuery; protected TimelineQuery $timelineQuery;
@ -47,8 +43,6 @@ class PublicController extends AuthPublicShareController
IUserSession $userSession, IUserSession $userSession,
IRootFolder $rootFolder, IRootFolder $rootFolder,
IShareManager $shareManager, IShareManager $shareManager,
IUserManager $userManager,
IAppManager $appManager,
IConfig $config, IConfig $config,
TimelineQuery $timelineQuery TimelineQuery $timelineQuery
) { ) {
@ -58,8 +52,6 @@ class PublicController extends AuthPublicShareController
$this->userSession = $userSession; $this->userSession = $userSession;
$this->rootFolder = $rootFolder; $this->rootFolder = $rootFolder;
$this->shareManager = $shareManager; $this->shareManager = $shareManager;
$this->userManager = $userManager;
$this->appManager = $appManager;
$this->config = $config; $this->config = $config;
$this->timelineQuery = $timelineQuery; $this->timelineQuery = $timelineQuery;
} }
@ -106,7 +98,7 @@ class PublicController extends AuthPublicShareController
throw new NotFoundException(); throw new NotFoundException();
} }
if (!self::validateShare($share)) { if (!\OCA\Memories\Manager\FsManager::validateShare($share)) {
throw new NotFoundException(); throw new NotFoundException();
} }
@ -144,38 +136,6 @@ class PublicController extends AuthPublicShareController
return $response; return $response;
} }
/**
* Validate the permissions of the share.
*/
public static function validateShare(?IShare $share): bool
{
if (null === $share) {
return false;
}
// Get user manager
$userManager = \OC::$server->get(IUserManager::class);
// Check if share read is allowed
if (!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) {
return false;
}
// If the owner is disabled no access to the linke is granted
$owner = $userManager->get($share->getShareOwner());
if (null === $owner || !$owner->isEnabled()) {
return false;
}
// If the initiator of the share is disabled no access is granted
$initiator = $userManager->get($share->getSharedBy());
if (null === $initiator || !$initiator->isEnabled()) {
return false;
}
return $share->getNode()->isReadable() && $share->getNode()->isShareable();
}
protected function showAuthFailed(): TemplateResponse protected function showAuthFailed(): TemplateResponse
{ {
$templateParameters = ['share' => $this->share, 'wrongpw' => true]; $templateParameters = ['share' => $this->share, 'wrongpw' => true];

View File

@ -118,7 +118,7 @@ class ShareController extends GenericApiController
try { try {
$file = null; $file = null;
if ($id) { if ($id) {
$file = $this->getUserFile($id); $file = $this->fs->getUserFile($id);
} elseif ($path) { } elseif ($path) {
$file = Util::getUserFolder($uid)->get($path); $file = Util::getUserFolder($uid)->get($path);
} }

View File

@ -44,7 +44,7 @@ class TagsController extends GenericApiController
} }
// Check the user is allowed to edit the file // Check the user is allowed to edit the file
$file = $this->getUserFile($id); $file = $this->fs->getUserFile($id);
if (null === $file) { if (null === $file) {
throw Exceptions::NotFoundFile($id); throw Exceptions::NotFoundFile($id);
} }

View File

@ -56,7 +56,7 @@ class VideoController extends GenericApiController
} }
// Get file // Get file
$file = $this->getUserFile($fileid); $file = $this->fs->getUserFile($fileid);
if (!$file || !$file->isReadable()) { if (!$file || !$file->isReadable()) {
throw Exceptions::NotFoundFile($fileid); throw Exceptions::NotFoundFile($fileid);
} }
@ -116,7 +116,7 @@ class VideoController extends GenericApiController
string $transcode = '' string $transcode = ''
) { ) {
return Util::guardEx(function () use ($fileid, $liveid, $format, $transcode) { return Util::guardEx(function () use ($fileid, $liveid, $format, $transcode) {
$file = $this->getUserFile($fileid); $file = $this->fs->getUserFile($fileid);
if (null === $file) { if (null === $file) {
throw Exceptions::NotFoundFile($fileid); throw Exceptions::NotFoundFile($fileid);
} }

View File

@ -27,12 +27,24 @@ class TimelineQuery
]; ];
protected IDBConnection $connection; protected IDBConnection $connection;
private ?TimelineRoot $_root = null;
public function __construct(IDBConnection $connection) public function __construct(IDBConnection $connection)
{ {
$this->connection = $connection; $this->connection = $connection;
} }
public function root(): TimelineRoot
{
if (null === $this->_root) {
$this->_root = new TimelineRoot();
$fsManager = \OC::$server->get(\OCA\Memories\Manager\FsManager::class);
$fsManager->populateRoot($this->_root);
}
return $this->_root;
}
public static function debugQuery(IQueryBuilder &$query, string $sql = '') public static function debugQuery(IQueryBuilder &$query, string $sql = '')
{ {
// Print the query and exit // Print the query and exit
@ -63,10 +75,6 @@ class TimelineQuery
return $sql; return $sql;
} }
public function transformExtraFields(IQueryBuilder &$query, string $uid, array &$fields)
{
}
public function getInfoById(int $id, bool $basic): array public function getInfoById(int $id, bool $basic): array
{ {
$qb = $this->connection->getQueryBuilder(); $qb = $this->connection->getQueryBuilder();

View File

@ -78,15 +78,13 @@ trait TimelineQueryDays
/** /**
* Get the days response from the database for the timeline. * Get the days response from the database for the timeline.
* *
* @param TimelineRoot $root The root to get the days from * @param bool $recursive Whether to get the days recursively
* @param bool $recursive Whether to get the days recursively * @param bool $archive Whether to get the days only from the archive folder
* @param bool $archive Whether to get the days only from the archive folder * @param array $queryTransforms An array of query transforms to apply to the query
* @param array $queryTransforms An array of query transforms to apply to the query
* *
* @return array The days response * @return array The days response
*/ */
public function getDays( public function getDays(
TimelineRoot &$root,
string $uid, string $uid,
bool $recursive, bool $recursive,
bool $archive, bool $archive,
@ -99,7 +97,7 @@ trait TimelineQueryDays
$query->select('m.dayid', $count) $query->select('m.dayid', $count)
->from('memories', 'm') ->from('memories', 'm')
; ;
$query = $this->joinFilecache($query, $root, $recursive, $archive); $query = $this->joinFilecache($query, null, $recursive, $archive);
// Group and sort by dayid // Group and sort by dayid
$query->groupBy('m.dayid') $query->groupBy('m.dayid')
@ -119,18 +117,16 @@ trait TimelineQueryDays
/** /**
* Get the day response from the database for the timeline. * Get the day response from the database for the timeline.
* *
* @param TimelineRoot $root The root to get the day from * @param string $uid The user id
* @param string $uid The user id * @param int[] $day_ids The day ids to fetch
* @param int[] $day_ids The day ids to fetch * @param bool $recursive If the query should be recursive
* @param bool $recursive If the query should be recursive * @param bool $archive If the query should include only the archive folder
* @param bool $archive If the query should include only the archive folder * @param array $queryTransforms The query transformations to apply
* @param array $queryTransforms The query transformations to apply * @param mixed $day_ids
* @param mixed $day_ids
* *
* @return array An array of day responses * @return array An array of day responses
*/ */
public function getDay( public function getDay(
TimelineRoot &$root,
string $uid, string $uid,
?array $day_ids, ?array $day_ids,
bool $recursive, bool $recursive,
@ -150,7 +146,7 @@ trait TimelineQueryDays
; ;
// JOIN with filecache for existing files // JOIN with filecache for existing files
$query = $this->joinFilecache($query, $root, $recursive, $archive); $query = $this->joinFilecache($query, null, $recursive, $archive);
// JOIN with mimetypes to get the mimetype // JOIN with mimetypes to get the mimetype
$query->join('f', 'mimetypes', 'mimetypes', $query->expr()->eq('f.mimetype', 'mimetypes.id')); $query->join('f', 'mimetypes', 'mimetypes', $query->expr()->eq('f.mimetype', 'mimetypes.id'));
@ -271,11 +267,15 @@ trait TimelineQueryDays
* @param bool $archive Whether to get the days only from the archive folder * @param bool $archive Whether to get the days only from the archive folder
*/ */
private function joinFilecache( private function joinFilecache(
IQueryBuilder &$query, IQueryBuilder $query,
TimelineRoot &$root, ?TimelineRoot $root = null,
bool $recursive, bool $recursive = true,
bool $archive bool $archive = false
) { ) {
if (null === $root) {
$root = $this->root();
}
// Join with memories // Join with memories
$baseOp = $query->expr()->eq('f.fileid', 'm.fileid'); $baseOp = $query->expr()->eq('f.fileid', 'm.fileid');
if ($root->isEmpty()) { if ($root->isEmpty()) {

View File

@ -33,8 +33,7 @@ trait TimelineQueryMap
public function getMapClusters( public function getMapClusters(
float $gridLen, float $gridLen,
string $bounds, string $bounds
TimelineRoot &$root
): array { ): array {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
@ -57,7 +56,7 @@ trait TimelineQueryMap
$query->innerJoin('c', 'memories', 'm', $query->expr()->eq('c.id', 'm.mapcluster')); $query->innerJoin('c', 'memories', 'm', $query->expr()->eq('c.id', 'm.mapcluster'));
// JOIN with filecache for existing files // JOIN with filecache for existing files
$query = $this->joinFilecache($query, $root, true, false); $query = $this->joinFilecache($query);
// Bound the query to the map bounds // Bound the query to the map bounds
$this->transformMapBoundsFilter($query, '', $bounds, 'c'); $this->transformMapBoundsFilter($query, '', $bounds, 'c');
@ -86,7 +85,7 @@ trait TimelineQueryMap
return $clusters; return $clusters;
} }
public function getMapClusterPreviews(array $clusterIds, TimelineRoot &$root) public function getMapClusterPreviews(array $clusterIds)
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
@ -97,7 +96,7 @@ trait TimelineQueryMap
); );
// 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);
// GROUP BY the cluster // GROUP BY the cluster
$query->groupBy('m.mapcluster'); $query->groupBy('m.mapcluster');

View File

@ -58,7 +58,7 @@ trait TimelineQueryPeopleFaceRecognition
); );
} }
public function getFaceRecognitionPhotos(string $id, int $currentModel, TimelineRoot &$root, ?int $limit) public function getFaceRecognitionPhotos(string $id, int $currentModel, ?int $limit)
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
@ -95,7 +95,7 @@ trait TimelineQueryPeopleFaceRecognition
} }
// 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);
// LIMIT results // LIMIT results
if (null !== $limit) { if (null !== $limit) {
@ -110,7 +110,7 @@ trait TimelineQueryPeopleFaceRecognition
return $this->executeQueryWithCTEs($query)->fetchAll(); return $this->executeQueryWithCTEs($query)->fetchAll();
} }
public function getFaceRecognitionClusters(TimelineRoot &$root, int $currentModel, bool $show_singles = false, bool $show_hidden = false) public function getFaceRecognitionClusters(int $currentModel, bool $show_singles = false, bool $show_hidden = false)
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
@ -133,7 +133,7 @@ trait TimelineQueryPeopleFaceRecognition
)); ));
// 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);
// GROUP by ID of face cluster // GROUP by ID of face cluster
$query->groupBy('frp.id'); $query->groupBy('frp.id');
@ -170,7 +170,7 @@ trait TimelineQueryPeopleFaceRecognition
return $faces; return $faces;
} }
public function getFaceRecognitionPersons(TimelineRoot &$root, int $currentModel) public function getFaceRecognitionPersons(int $currentModel)
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
@ -193,7 +193,7 @@ trait TimelineQueryPeopleFaceRecognition
)); ));
// 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);
// GROUP by name of face clusters // GROUP by name of face clusters
$query->where($query->expr()->isNotNull('frp.name')); $query->where($query->expr()->isNotNull('frp.name'));

View File

@ -62,7 +62,7 @@ trait TimelineQueryPeopleRecognize
); );
} }
public function getPeopleRecognize(TimelineRoot &$root, string $uid) public function getPeopleRecognize(string $uid)
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
@ -77,7 +77,7 @@ trait TimelineQueryPeopleRecognize
$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'));
// 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);
// WHERE this cluster belongs to the user // WHERE this cluster belongs to the user
$query->where($query->expr()->eq('rfc.user_id', $query->createNamedParameter($uid))); $query->where($query->expr()->eq('rfc.user_id', $query->createNamedParameter($uid)));
@ -105,7 +105,7 @@ trait TimelineQueryPeopleRecognize
return $faces; return $faces;
} }
public function getPeopleRecognizePhotos(int $id, TimelineRoot $root, ?int $limit): array public function getPeopleRecognizePhotos(int $id, ?int $limit): array
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
@ -129,7 +129,7 @@ trait TimelineQueryPeopleRecognize
$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'));
// 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);
// LIMIT results // LIMIT results
if (null !== $limit) { if (null !== $limit) {

View File

@ -19,7 +19,7 @@ trait TimelineQueryPlaces
)); ));
} }
public function getPlaces(TimelineRoot &$root) public function getPlaces()
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
@ -34,7 +34,7 @@ trait TimelineQueryPlaces
$query->innerJoin('mp', 'memories', 'm', $query->expr()->eq('m.fileid', 'mp.fileid')); $query->innerJoin('mp', 'memories', 'm', $query->expr()->eq('m.fileid', 'mp.fileid'));
// 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);
// GROUP and ORDER by tag name // GROUP and ORDER by tag name
$query->groupBy('e.osm_id', 'e.name'); $query->groupBy('e.osm_id', 'e.name');
@ -54,7 +54,7 @@ trait TimelineQueryPlaces
return $places; return $places;
} }
public function getPlacePhotos(int $id, TimelineRoot $root, ?int $limit): array public function getPlacePhotos(int $id, ?int $limit): array
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
@ -67,7 +67,7 @@ trait TimelineQueryPlaces
$query->innerJoin('mp', 'memories', 'm', $query->expr()->eq('m.fileid', 'mp.fileid')); $query->innerJoin('mp', 'memories', 'm', $query->expr()->eq('m.fileid', 'mp.fileid'));
// 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);
// MAX number of photos // MAX number of photos
if (null !== $limit) { if (null !== $limit) {

View File

@ -37,7 +37,7 @@ trait TimelineQueryTags
)); ));
} }
public function getTags(TimelineRoot &$root) public function getTags()
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
@ -57,7 +57,7 @@ trait TimelineQueryTags
$query->innerJoin('stom', 'memories', 'm', $query->expr()->eq('m.objectid', 'stom.objectid')); $query->innerJoin('stom', 'memories', 'm', $query->expr()->eq('m.objectid', 'stom.objectid'));
// 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);
// GROUP and ORDER by tag name // GROUP and ORDER by tag name
$query->groupBy('st.id'); $query->groupBy('st.id');
@ -77,7 +77,7 @@ trait TimelineQueryTags
return $tags; return $tags;
} }
public function getTagPhotos(string $tagName, TimelineRoot $root, ?int $limit) public function getTagPhotos(string $tagName, ?int $limit)
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
$tagId = $this->getSystemTagId($query, $tagName); $tagId = $this->getSystemTagId($query, $tagName);
@ -98,7 +98,7 @@ trait TimelineQueryTags
$query->innerJoin('stom', 'memories', 'm', $query->expr()->eq('m.objectid', 'stom.objectid')); $query->innerJoin('stom', 'memories', 'm', $query->expr()->eq('m.objectid', 'stom.objectid'));
// 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);
// MAX number of files // MAX number of files
if (null !== $limit) { if (null !== $limit) {

View File

@ -68,7 +68,7 @@ class Exif
/** /**
* Get the path to the user's configured photos directory. * Get the path to the user's configured photos directory.
*/ */
public static function getPhotosPath(IConfig &$config, string &$userId) public static function getPhotosPath(IConfig $config, string &$userId)
{ {
$p = $config->getUserValue($userId, Application::APPNAME, 'timelinePath', ''); $p = $config->getUserValue($userId, Application::APPNAME, 'timelinePath', '');
if (empty($p)) { if (empty($p)) {

View File

@ -21,7 +21,7 @@ declare(strict_types=1);
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace OCA\Memories\Controller; namespace OCA\Memories\Manager;
use OCA\Memories\Db\TimelineQuery; use OCA\Memories\Db\TimelineQuery;
use OCA\Memories\Db\TimelineRoot; use OCA\Memories\Db\TimelineRoot;
@ -31,22 +31,37 @@ use OCP\Files\File;
use OCP\Files\Folder; use OCP\Files\Folder;
use OCP\Files\IRootFolder; use OCP\Files\IRootFolder;
use OCP\IConfig; use OCP\IConfig;
use OCP\IRequest;
use OCP\IUserManager;
use OCP\IUserSession; use OCP\IUserSession;
use OCP\Share\IShare;
trait GenericApiControllerFs class FsManager
{ {
use GenericApiControllerParams;
protected IConfig $config; protected IConfig $config;
protected IUserSession $userSession; protected IUserSession $userSession;
protected IRootFolder $rootFolder; protected IRootFolder $rootFolder;
protected TimelineQuery $timelineQuery; protected TimelineQuery $timelineQuery;
protected IRequest $request;
public function __construct(
IConfig $config,
IUserSession $userSession,
IRootFolder $rootFolder,
TimelineQuery $timelineQuery,
IRequest $request
) {
$this->config = $config;
$this->userSession = $userSession;
$this->rootFolder = $rootFolder;
$this->timelineQuery = $timelineQuery;
$this->request = $request;
}
/** Get the TimelineRoot object relevant to the request */ /** Get the TimelineRoot object relevant to the request */
protected function getRequestRoot() public function populateRoot(TimelineRoot &$root)
{ {
$user = $this->userSession->getUser(); $user = $this->userSession->getUser();
$root = new TimelineRoot();
// Albums have no folder // Albums have no folder
if ($this->request->getParam('album') && Util::albumsIsEnabled()) { if ($this->request->getParam('album') && Util::albumsIsEnabled()) {
@ -71,7 +86,7 @@ trait GenericApiControllerFs
// Anything else needs a user // Anything else needs a user
if (null === $user) { if (null === $user) {
throw new \Exception('User not logged in'); throw new \Exception('User not logged in: no timeline root');
} }
$uid = $user->getUID(); $uid = $user->getUID();
@ -107,7 +122,7 @@ trait GenericApiControllerFs
/** /**
* Get a file with ID for the current user. * Get a file with ID for the current user.
*/ */
protected function getUserFile(int $fileId): ?File public function getUserFile(int $fileId): ?File
{ {
// Don't check self for share token // Don't check self for share token
if ($this->getShareToken()) { if ($this->getShareToken()) {
@ -122,7 +137,7 @@ trait GenericApiControllerFs
/** /**
* Get a file with ID from user's folder. * Get a file with ID from user's folder.
*/ */
protected function getUserFolderFile(int $id): ?File public function getUserFolderFile(int $id): ?File
{ {
$user = $this->userSession->getUser(); $user = $this->userSession->getUser();
if (null === $user) { if (null === $user) {
@ -138,8 +153,10 @@ trait GenericApiControllerFs
/** /**
* Get a file with ID from an album. * Get a file with ID from an album.
*
* @param int $id FileID
*/ */
protected function getAlbumFile(int $id): ?File public function getAlbumFile(int $id): ?File
{ {
$user = $this->userSession->getUser(); $user = $this->userSession->getUser();
if (null === $user) { if (null === $user) {
@ -163,9 +180,9 @@ trait GenericApiControllerFs
/** /**
* Get a file with ID from a public share. * Get a file with ID from a public share.
* *
* @param int $fileId * @param int $id FileID
*/ */
protected function getShareFile(int $id): ?File public function getShareFile(int $id): ?File
{ {
try { try {
// Album share // Album share
@ -205,7 +222,7 @@ trait GenericApiControllerFs
return null; return null;
} }
protected function getShareObject() public function getShareObject()
{ {
// Get token from request // Get token from request
$token = $this->getShareToken(); $token = $this->getShareToken();
@ -215,7 +232,7 @@ trait GenericApiControllerFs
// Get share by token // Get share by token
$share = \OC::$server->get(\OCP\Share\IManager::class)->getShareByToken($token); $share = \OC::$server->get(\OCP\Share\IManager::class)->getShareByToken($token);
if (!PublicController::validateShare($share)) { if (!self::validateShare($share)) {
return null; return null;
} }
@ -235,14 +252,14 @@ trait GenericApiControllerFs
return $share; return $share;
} }
protected function getShareNode() public function getShareNode()
{ {
$share = $this->getShareObject(); $share = $this->getShareObject();
if (null === $share) { if (null === $share) {
return null; return null;
} }
// Get node from share // Get node from share
$node = $share->getNode(); // throws exception if not found $node = $share->getNode(); // throws exception if not found
if (!$node->isReadable() || !$node->isShareable()) { if (!$node->isReadable() || !$node->isShareable()) {
throw new \Exception('Share not found or invalid'); throw new \Exception('Share not found or invalid');
@ -254,6 +271,38 @@ trait GenericApiControllerFs
return $node; return $node;
} }
/**
* Validate the permissions of the share.
*/
public static function validateShare(?IShare $share): bool
{
if (null === $share) {
return false;
}
// Get user manager
$userManager = \OC::$server->get(IUserManager::class);
// Check if share read is allowed
if (!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) {
return false;
}
// If the owner is disabled no access to the linke is granted
$owner = $userManager->get($share->getShareOwner());
if (null === $owner || !$owner->isEnabled()) {
return false;
}
// If the initiator of the share is disabled no access is granted
$initiator = $userManager->get($share->getSharedBy());
if (null === $initiator || !$initiator->isEnabled()) {
return false;
}
return $share->getNode()->isReadable() && $share->getNode()->isShareable();
}
/** /**
* Helper to get one file or null from a fiolder. * Helper to get one file or null from a fiolder.
* *
@ -287,4 +336,9 @@ trait GenericApiControllerFs
return $file; return $file;
} }
private function getShareToken()
{
return $this->request->getParam('token');
}
} }