folder-share: add node share fake API

pull/474/head
Varun Patil 2023-03-10 09:30:56 -08:00
parent 53ebf7d18f
commit 4e6a2a1329
8 changed files with 98 additions and 11 deletions

View File

@ -103,6 +103,10 @@ class ApiBase extends Controller
// Public shared folder
if ($share = $this->getShareNode()) { // can throw
if (!$share instanceof Folder) {
throw new \Exception('Share is not a folder');
}
$root->addFolder($share);
return $root;
@ -229,8 +233,15 @@ class ApiBase extends Controller
if ($share = $this->getShareNode()) {
// Public shares may allow editing
// Just use the same permissions as the share
if ($share instanceof File) {
return $share;
}
if ($share instanceof Folder) {
return $this->getOneFileFromFolder($share, $id, $share->getPermissions());
}
return null;
}
} catch (\Exception $e) {
}
@ -301,7 +312,7 @@ class ApiBase extends Controller
// Get node from share
$node = $share->getNode(); // throws exception if not found
if (!$node instanceof Folder || !$node->isReadable() || !$node->isShareable()) {
if (!$node->isReadable() || !$node->isShareable()) {
throw new \Exception('Share not found or invalid');
}

View File

@ -3,6 +3,7 @@
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;
@ -12,6 +13,7 @@ use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IRequest;
use OCP\ISession;
use OCP\IURLGenerator;
@ -31,6 +33,7 @@ class PublicController extends AuthPublicShareController
protected IShareManager $shareManager;
protected IUserManager $userManager;
protected IAppManager $appManager;
protected IDBConnection $db;
protected IConfig $config;
protected IShare $share;
@ -47,6 +50,7 @@ class PublicController extends AuthPublicShareController
IShareManager $shareManager,
IUserManager $userManager,
IAppManager $appManager,
IDBConnection $db,
IConfig $config
) {
parent::__construct($AppName, $request, $session, $urlGenerator);
@ -57,6 +61,7 @@ class PublicController extends AuthPublicShareController
$this->shareManager = $shareManager;
$this->userManager = $userManager;
$this->appManager = $appManager;
$this->db = $db;
$this->config = $config;
}
@ -106,11 +111,6 @@ class PublicController extends AuthPublicShareController
throw new NotFoundException();
}
if (!($share->getNode() instanceof \OCP\Files\Folder)) {
// TODO: single file share
throw new NotFoundException();
}
// Redirect to main app if user owns this share
$this->redirectIfOwned($share);
@ -124,8 +124,14 @@ class PublicController extends AuthPublicShareController
// Share info
$this->initialState->provideInitialState('no_download', $share->getHideDownload());
// Share file id only if not a folder
$node = $share->getNode();
if ($node instanceof \OCP\Files\File) {
$this->initialState->provideInitialState('single_item', $this->getSingleItemInitialState($node));
}
$response = new PublicTemplateResponse($this->appName, 'main');
$response->setHeaderTitle($share->getNode()->getName());
$response->setHeaderTitle($node->getName());
$response->setFooterVisible(false); // wth is that anyway?
$response->setContentSecurityPolicy(PageController::getCSP());
$response->cacheFor(0);
@ -241,4 +247,13 @@ class PublicController extends AuthPublicShareController
exit;
}
/** Get initial state of single item */
private function getSingleItemInitialState(\OCP\Files\File $file): string
{
$timelineQuery = new TimelineQuery($this->db);
$photo = $timelineQuery->getSingleItem($file->getId());
return json_encode($photo);
}
}

View File

@ -18,8 +18,14 @@ class TimelineQuery
use TimelineQueryPeopleFaceRecognition;
use TimelineQueryPeopleRecognize;
use TimelineQueryPlaces;
use TimelineQuerySingleItem;
use TimelineQueryTags;
public const TIMELINE_SELECT = [
'm.isvideo', 'm.video_duration', 'm.datetaken', 'm.dayid', 'm.w', 'm.h', 'm.liveid',
'f.etag', 'f.path', 'f.name AS basename', 'mimetypes.mimetype',
];
protected IDBConnection $connection;
public function __construct(IDBConnection $connection)

View File

@ -153,13 +153,12 @@ trait TimelineQueryDays
// We don't actually use m.datetaken here, but postgres
// needs that all fields in ORDER BY are also in SELECT
// when using DISTINCT on selected fields
$query->select($fileid, 'm.isvideo', 'm.video_duration', 'm.datetaken', 'm.dayid', 'm.w', 'm.h', 'm.liveid')
$query->select($fileid, ...TimelineQuery::TIMELINE_SELECT)
->from('memories', 'm')
;
// JOIN with filecache for existing files
$query = $this->joinFilecache($query, $root, $recursive, $archive);
$query->addSelect('f.etag', 'f.path', 'f.name AS basename');
// SELECT rootid if not a single folder
if ($recursive && !$root->isEmpty()) {
@ -168,7 +167,6 @@ trait TimelineQueryDays
// JOIN with mimetypes to get the mimetype
$query->join('f', 'mimetypes', 'mimetypes', $query->expr()->eq('f.mimetype', 'mimetypes.id'));
$query->addSelect('mimetypes.mimetype');
// Filter by dayid unless wildcard
if (null !== $day_ids) {

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace OCA\Memories\Db;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
trait TimelineQuerySingleItem
{
protected IDBConnection $connection;
public function getSingleItem(int $fileId)
{
$query = $this->connection->getQueryBuilder();
$query->select('m.fileid', ...TimelineQuery::TIMELINE_SELECT)
->from('memories', 'm')
->where($query->expr()->eq('m.fileid', $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)))
;
// JOIN filecache for etag
$query->innerJoin('m', 'filecache', 'f', $query->expr()->eq('f.fileid', 'm.fileid'));
// JOIN with mimetypes to get the mimetype
$query->join('f', 'mimetypes', 'mimetypes', $query->expr()->eq('f.mimetype', 'mimetypes.id'));
unset($row['datetaken'], $row['path']);
return $query->executeQuery()->fetch();
}
}

View File

@ -766,6 +766,8 @@ export default defineComponent({
data = await dav.getPlacesData();
} else if (this.$route.name === "tags" && !this.$route.params.name) {
data = await dav.getTagsData();
} else if (dav.isSingleItem()) {
data = await dav.getSingleItemData();
} else {
// Try the cache
try {

View File

@ -9,3 +9,4 @@ export * from "./dav/onthisday";
export * from "./dav/tags";
export * from "./dav/other";
export * from "./dav/places";
export * from "./dav/single-item";

View File

@ -0,0 +1,22 @@
import { IDay } from "../../types";
import { loadState } from "@nextcloud/initial-state";
const singleItem = JSON.parse(loadState("memories", "single_item", "{}"));
export function isSingleItem(): boolean {
return Boolean(singleItem?.fileid);
}
export async function getSingleItemData(): Promise<IDay[]> {
if (!singleItem?.fileid) {
return [];
}
return [
{
dayid: singleItem.dayid,
count: 1,
detail: [singleItem],
},
] as any[];
}