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;
use OCA\Memories\Db\TimelineQuery;
use OCA\Memories\Db\TimelineRoot;
use OCA\Memories\Util;
use OCP\IConfig;
@ -32,7 +31,6 @@ class FaceRecognitionBackend extends Backend
{
use PeopleBackendUtils;
public TimelineRoot $root;
protected TimelineQuery $timelineQuery;
protected IConfig $config;
@ -58,14 +56,14 @@ class FaceRecognitionBackend extends Backend
public function getClusters(): array
{
return array_merge(
$this->timelineQuery->getFaceRecognitionPersons($this->root, $this->model()),
$this->timelineQuery->getFaceRecognitionClusters($this->root, $this->model())
$this->timelineQuery->getFaceRecognitionPersons($this->model()),
$this->timelineQuery->getFaceRecognitionClusters($this->model())
);
}
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)

View File

@ -24,12 +24,10 @@ declare(strict_types=1);
namespace OCA\Memories\ClustersBackend;
use OCA\Memories\Db\TimelineQuery;
use OCA\Memories\Db\TimelineRoot;
use OCA\Memories\Util;
class PlacesBackend extends Backend
{
public TimelineRoot $root;
protected TimelineQuery $timelineQuery;
public function __construct(
@ -50,11 +48,11 @@ class PlacesBackend extends Backend
public function getClusters(): array
{
return $this->timelineQuery->getPlaces($this->root);
return $this->timelineQuery->getPlaces();
}
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;
use OCA\Memories\Db\TimelineQuery;
use OCA\Memories\Db\TimelineRoot;
use OCA\Memories\Util;
class RecognizeBackend extends Backend
{
use PeopleBackendUtils;
public TimelineRoot $root;
protected TimelineQuery $timelineQuery;
public function __construct(
@ -52,12 +50,12 @@ class RecognizeBackend extends Backend
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
{
return $this->timelineQuery->getPeopleRecognizePhotos((int) $name, $this->root, $limit) ?? [];
return $this->timelineQuery->getPeopleRecognizePhotos((int) $name, $limit) ?? [];
}
public function sortPhotosForPreview(array &$photos)

View File

@ -24,12 +24,10 @@ declare(strict_types=1);
namespace OCA\Memories\ClustersBackend;
use OCA\Memories\Db\TimelineQuery;
use OCA\Memories\Db\TimelineRoot;
use OCA\Memories\Util;
class TagsBackend extends Backend
{
public TimelineRoot $root;
protected TimelineQuery $timelineQuery;
public function __construct(
@ -50,11 +48,11 @@ class TagsBackend extends Backend
public function getClusters(): array
{
return $this->timelineQuery->getTags($this->root);
return $this->timelineQuery->getTags();
}
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()) {
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;
use OCA\Memories\Db\TimelineRoot;
use OCA\Memories\Exceptions;
use OCA\Memories\Util;
use OCP\AppFramework\Http;
@ -42,10 +41,8 @@ class DaysController extends GenericApiController
{
return Util::guardEx(function () {
$uid = $this->getShareToken() ? '' : Util::getUID();
$root = $this->getRequestRoot();
$list = $this->timelineQuery->getDays(
$root,
$uid,
$this->isRecursive(),
$this->isArchive(),
@ -57,7 +54,7 @@ class DaysController extends GenericApiController
$list = $this->timelineQuery->daysToMonths($list);
} else {
// Preload some day responses
$this->preloadDays($list, $uid, $root);
$this->preloadDays($list, $uid);
}
// Reverse response if requested. Folders still stay at top.
@ -67,6 +64,7 @@ class DaysController extends GenericApiController
// Add subfolder info if querying non-recursively
if (!$this->isRecursive()) {
$root = $this->timelineQuery->root();
array_unshift($list, $this->getSubfoldersEntry($root->getFolder($root->getOneId())));
}
@ -98,9 +96,6 @@ class DaysController extends GenericApiController
return new JSONResponse([], Http::STATUS_OK);
}
// Get the folder to show
$root = $this->getRequestRoot();
// Convert to actual dayIds if month view
if ($this->isMonthView()) {
$dayIds = $this->timelineQuery->monthIdToDayIds((int) $dayIds[0]);
@ -108,7 +103,6 @@ class DaysController extends GenericApiController
// Run actual query
$list = $this->timelineQuery->getDay(
$root,
$uid,
$dayIds,
$this->isRecursive(),
@ -158,17 +152,9 @@ class DaysController extends GenericApiController
{
$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
if (Util::albumsIsEnabled()) {
if ($albumId = $this->request->getParam('album')) {
$transforms[] = [$this->timelineQuery, 'transformAlbumFilter', $albumId];
}
if (($albumId = $this->request->getParam('album')) && Util::albumsIsEnabled()) {
$transforms[] = [$this->timelineQuery, 'transformAlbumFilter', $albumId];
}
// 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.
*
* @param array $days the days array
* @param string $uid User ID or blank for public shares
* @param TimelineRoot $root the root folder
* @param array $days the days array
* @param string $uid User ID or blank for public shares
*/
private function preloadDays(array &$days, string $uid, TimelineRoot &$root)
private function preloadDays(array &$days, string $uid)
{
$transforms = $this->getTransformations(false);
$preloaded = 0;
@ -261,7 +246,6 @@ class DaysController extends GenericApiController
if (\count($preloadDayIds) > 0) {
$allDetails = $this->timelineQuery->getDay(
$root,
$uid,
$preloadDayIds,
$this->isRecursive(),

View File

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

View File

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

View File

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

View File

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

View File

@ -4,7 +4,6 @@ namespace OCA\Memories\Controller;
use OCA\Memories\AppInfo\Application;
use OCA\Memories\Db\TimelineQuery;
use OCP\App\IAppManager;
use OCP\AppFramework\AuthPublicShareController;
use OCP\AppFramework\Http\Template\PublicTemplateResponse;
use OCP\AppFramework\Http\TemplateResponse;
@ -16,7 +15,6 @@ use OCP\IConfig;
use OCP\IRequest;
use OCP\ISession;
use OCP\IURLGenerator;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Share\IManager as IShareManager;
use OCP\Share\IShare;
@ -30,8 +28,6 @@ class PublicController extends AuthPublicShareController
protected IUserSession $userSession;
protected IRootFolder $rootFolder;
protected IShareManager $shareManager;
protected IUserManager $userManager;
protected IAppManager $appManager;
protected IConfig $config;
protected TimelineQuery $timelineQuery;
@ -47,8 +43,6 @@ class PublicController extends AuthPublicShareController
IUserSession $userSession,
IRootFolder $rootFolder,
IShareManager $shareManager,
IUserManager $userManager,
IAppManager $appManager,
IConfig $config,
TimelineQuery $timelineQuery
) {
@ -58,8 +52,6 @@ class PublicController extends AuthPublicShareController
$this->userSession = $userSession;
$this->rootFolder = $rootFolder;
$this->shareManager = $shareManager;
$this->userManager = $userManager;
$this->appManager = $appManager;
$this->config = $config;
$this->timelineQuery = $timelineQuery;
}
@ -106,7 +98,7 @@ class PublicController extends AuthPublicShareController
throw new NotFoundException();
}
if (!self::validateShare($share)) {
if (!\OCA\Memories\Manager\FsManager::validateShare($share)) {
throw new NotFoundException();
}
@ -144,38 +136,6 @@ class PublicController extends AuthPublicShareController
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
{
$templateParameters = ['share' => $this->share, 'wrongpw' => true];

View File

@ -118,7 +118,7 @@ class ShareController extends GenericApiController
try {
$file = null;
if ($id) {
$file = $this->getUserFile($id);
$file = $this->fs->getUserFile($id);
} elseif ($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
$file = $this->getUserFile($id);
$file = $this->fs->getUserFile($id);
if (null === $file) {
throw Exceptions::NotFoundFile($id);
}

View File

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

View File

@ -27,12 +27,24 @@ class TimelineQuery
];
protected IDBConnection $connection;
private ?TimelineRoot $_root = null;
public function __construct(IDBConnection $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 = '')
{
// Print the query and exit
@ -63,10 +75,6 @@ class TimelineQuery
return $sql;
}
public function transformExtraFields(IQueryBuilder &$query, string $uid, array &$fields)
{
}
public function getInfoById(int $id, bool $basic): array
{
$qb = $this->connection->getQueryBuilder();

View File

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

View File

@ -33,8 +33,7 @@ trait TimelineQueryMap
public function getMapClusters(
float $gridLen,
string $bounds,
TimelineRoot &$root
string $bounds
): array {
$query = $this->connection->getQueryBuilder();
@ -57,7 +56,7 @@ trait TimelineQueryMap
$query->innerJoin('c', 'memories', 'm', $query->expr()->eq('c.id', 'm.mapcluster'));
// JOIN with filecache for existing files
$query = $this->joinFilecache($query, $root, true, false);
$query = $this->joinFilecache($query);
// Bound the query to the map bounds
$this->transformMapBoundsFilter($query, '', $bounds, 'c');
@ -86,7 +85,7 @@ trait TimelineQueryMap
return $clusters;
}
public function getMapClusterPreviews(array $clusterIds, TimelineRoot &$root)
public function getMapClusterPreviews(array $clusterIds)
{
$query = $this->connection->getQueryBuilder();
@ -97,7 +96,7 @@ trait TimelineQueryMap
);
// 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
$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();
@ -95,7 +95,7 @@ trait TimelineQueryPeopleFaceRecognition
}
// WHERE these photos are in the user's requested folder recursively
$query = $this->joinFilecache($query, $root, true, false);
$query = $this->joinFilecache($query);
// LIMIT results
if (null !== $limit) {
@ -110,7 +110,7 @@ trait TimelineQueryPeopleFaceRecognition
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();
@ -133,7 +133,7 @@ trait TimelineQueryPeopleFaceRecognition
));
// 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
$query->groupBy('frp.id');
@ -170,7 +170,7 @@ trait TimelineQueryPeopleFaceRecognition
return $faces;
}
public function getFaceRecognitionPersons(TimelineRoot &$root, int $currentModel)
public function getFaceRecognitionPersons(int $currentModel)
{
$query = $this->connection->getQueryBuilder();
@ -193,7 +193,7 @@ trait TimelineQueryPeopleFaceRecognition
));
// 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
$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();
@ -77,7 +77,7 @@ trait TimelineQueryPeopleRecognize
$query->innerJoin('rfd', 'memories', 'm', $query->expr()->eq('m.fileid', 'rfd.file_id'));
// 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
$query->where($query->expr()->eq('rfc.user_id', $query->createNamedParameter($uid)));
@ -105,7 +105,7 @@ trait TimelineQueryPeopleRecognize
return $faces;
}
public function getPeopleRecognizePhotos(int $id, TimelineRoot $root, ?int $limit): array
public function getPeopleRecognizePhotos(int $id, ?int $limit): array
{
$query = $this->connection->getQueryBuilder();
@ -129,7 +129,7 @@ trait TimelineQueryPeopleRecognize
$query->innerJoin('rfd', 'memories', 'm', $query->expr()->eq('m.fileid', 'rfd.file_id'));
// WHERE these photos are in the user's requested folder recursively
$query = $this->joinFilecache($query, $root, true, false);
$query = $this->joinFilecache($query);
// LIMIT results
if (null !== $limit) {

View File

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

View File

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

View File

@ -68,7 +68,7 @@ class Exif
/**
* 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', '');
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/>.
*/
namespace OCA\Memories\Controller;
namespace OCA\Memories\Manager;
use OCA\Memories\Db\TimelineQuery;
use OCA\Memories\Db\TimelineRoot;
@ -31,22 +31,37 @@ use OCP\Files\File;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\IConfig;
use OCP\IRequest;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Share\IShare;
trait GenericApiControllerFs
class FsManager
{
use GenericApiControllerParams;
protected IConfig $config;
protected IUserSession $userSession;
protected IRootFolder $rootFolder;
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 */
protected function getRequestRoot()
public function populateRoot(TimelineRoot &$root)
{
$user = $this->userSession->getUser();
$root = new TimelineRoot();
// Albums have no folder
if ($this->request->getParam('album') && Util::albumsIsEnabled()) {
@ -71,7 +86,7 @@ trait GenericApiControllerFs
// Anything else needs a user
if (null === $user) {
throw new \Exception('User not logged in');
throw new \Exception('User not logged in: no timeline root');
}
$uid = $user->getUID();
@ -107,7 +122,7 @@ trait GenericApiControllerFs
/**
* 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
if ($this->getShareToken()) {
@ -122,7 +137,7 @@ trait GenericApiControllerFs
/**
* 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();
if (null === $user) {
@ -138,8 +153,10 @@ trait GenericApiControllerFs
/**
* 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();
if (null === $user) {
@ -163,9 +180,9 @@ trait GenericApiControllerFs
/**
* 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 {
// Album share
@ -205,7 +222,7 @@ trait GenericApiControllerFs
return null;
}
protected function getShareObject()
public function getShareObject()
{
// Get token from request
$token = $this->getShareToken();
@ -215,7 +232,7 @@ trait GenericApiControllerFs
// Get share by token
$share = \OC::$server->get(\OCP\Share\IManager::class)->getShareByToken($token);
if (!PublicController::validateShare($share)) {
if (!self::validateShare($share)) {
return null;
}
@ -235,14 +252,14 @@ trait GenericApiControllerFs
return $share;
}
protected function getShareNode()
public function getShareNode()
{
$share = $this->getShareObject();
if (null === $share) {
return null;
}
// Get node from share
// Get node from share
$node = $share->getNode(); // throws exception if not found
if (!$node->isReadable() || !$node->isShareable()) {
throw new \Exception('Share not found or invalid');
@ -254,6 +271,38 @@ trait GenericApiControllerFs
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.
*
@ -287,4 +336,9 @@ trait GenericApiControllerFs
return $file;
}
private function getShareToken()
{
return $this->request->getParam('token');
}
}