Add basic folder share stuff
parent
c8727c4f28
commit
9209b8f55d
|
@ -24,6 +24,9 @@ return [
|
||||||
'defaults' => [ 'name' => '' ]
|
'defaults' => [ 'name' => '' ]
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// Public pages
|
||||||
|
['name' => 'page#sharedFolder', 'url' => '/s/{token}', 'verb' => 'GET'],
|
||||||
|
|
||||||
// API
|
// API
|
||||||
['name' => 'api#days', 'url' => '/api/days', 'verb' => 'GET'],
|
['name' => 'api#days', 'url' => '/api/days', 'verb' => 'GET'],
|
||||||
['name' => 'api#dayPost', 'url' => '/api/days', 'verb' => 'POST'],
|
['name' => 'api#dayPost', 'url' => '/api/days', 'verb' => 'POST'],
|
||||||
|
|
|
@ -43,6 +43,7 @@ use OCP\IDBConnection;
|
||||||
use OCP\IPreview;
|
use OCP\IPreview;
|
||||||
use OCP\IRequest;
|
use OCP\IRequest;
|
||||||
use OCP\IUserSession;
|
use OCP\IUserSession;
|
||||||
|
use OCP\Share\IManager as IShareManager;
|
||||||
|
|
||||||
class ApiController extends Controller
|
class ApiController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -53,6 +54,7 @@ class ApiController extends Controller
|
||||||
private IAppManager $appManager;
|
private IAppManager $appManager;
|
||||||
private TimelineQuery $timelineQuery;
|
private TimelineQuery $timelineQuery;
|
||||||
private TimelineWrite $timelineWrite;
|
private TimelineWrite $timelineWrite;
|
||||||
|
private IShareManager $shareManager;
|
||||||
private IPreview $preview;
|
private IPreview $preview;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
@ -62,6 +64,7 @@ class ApiController extends Controller
|
||||||
IDBConnection $connection,
|
IDBConnection $connection,
|
||||||
IRootFolder $rootFolder,
|
IRootFolder $rootFolder,
|
||||||
IAppManager $appManager,
|
IAppManager $appManager,
|
||||||
|
IShareManager $shareManager,
|
||||||
IPreview $preview
|
IPreview $preview
|
||||||
) {
|
) {
|
||||||
parent::__construct(Application::APPNAME, $request);
|
parent::__construct(Application::APPNAME, $request);
|
||||||
|
@ -71,6 +74,7 @@ class ApiController extends Controller
|
||||||
$this->connection = $connection;
|
$this->connection = $connection;
|
||||||
$this->rootFolder = $rootFolder;
|
$this->rootFolder = $rootFolder;
|
||||||
$this->appManager = $appManager;
|
$this->appManager = $appManager;
|
||||||
|
$this->shareManager = $shareManager;
|
||||||
$this->previewManager = $preview;
|
$this->previewManager = $preview;
|
||||||
$this->timelineQuery = new TimelineQuery($this->connection);
|
$this->timelineQuery = new TimelineQuery($this->connection);
|
||||||
$this->timelineWrite = new TimelineWrite($connection, $preview);
|
$this->timelineWrite = new TimelineWrite($connection, $preview);
|
||||||
|
@ -78,22 +82,28 @@ class ApiController extends Controller
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
|
*
|
||||||
|
* @PublicPage
|
||||||
*/
|
*/
|
||||||
public function days(): JSONResponse
|
public function days(): JSONResponse
|
||||||
{
|
{
|
||||||
$user = $this->userSession->getUser();
|
$user = $this->userSession->getUser();
|
||||||
if (null === $user) {
|
if (null === $user && !$this->getShareToken()) {
|
||||||
return new JSONResponse([], Http::STATUS_PRECONDITION_FAILED);
|
return new JSONResponse([], Http::STATUS_PRECONDITION_FAILED);
|
||||||
}
|
}
|
||||||
$uid = $user->getUID();
|
$uid = $user ? $user->getUID() : '';
|
||||||
|
|
||||||
// Get the folder to show
|
// Get the folder to show
|
||||||
$folder = $this->getRequestFolder();
|
$folder = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$folder = $this->getRequestFolder();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
$recursive = null === $this->request->getParam('folder');
|
$recursive = null === $this->request->getParam('folder');
|
||||||
$archive = null !== $this->request->getParam('archive');
|
$archive = null !== $this->request->getParam('archive');
|
||||||
if (null === $folder) {
|
|
||||||
return new JSONResponse(['message' => 'Folder not found'], Http::STATUS_NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove folder if album
|
// Remove folder if album
|
||||||
// Permissions will be checked during the transform
|
// Permissions will be checked during the transform
|
||||||
|
@ -127,6 +137,8 @@ class ApiController extends Controller
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
|
*
|
||||||
|
* @PublicPage
|
||||||
*/
|
*/
|
||||||
public function dayPost(): JSONResponse
|
public function dayPost(): JSONResponse
|
||||||
{
|
{
|
||||||
|
@ -140,14 +152,16 @@ class ApiController extends Controller
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
|
*
|
||||||
|
* @PublicPage
|
||||||
*/
|
*/
|
||||||
public function day(string $id): JSONResponse
|
public function day(string $id): JSONResponse
|
||||||
{
|
{
|
||||||
$user = $this->userSession->getUser();
|
$user = $this->userSession->getUser();
|
||||||
if (null === $user) {
|
if (null === $user && !$this->getShareToken()) {
|
||||||
return new JSONResponse([], Http::STATUS_PRECONDITION_FAILED);
|
return new JSONResponse([], Http::STATUS_PRECONDITION_FAILED);
|
||||||
}
|
}
|
||||||
$uid = $user->getUID();
|
$uid = $user ? $user->getUID() : '';
|
||||||
|
|
||||||
// Check for wildcard
|
// Check for wildcard
|
||||||
$day_ids = [];
|
$day_ids = [];
|
||||||
|
@ -664,6 +678,8 @@ class ApiController extends Controller
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
*
|
*
|
||||||
|
* @PublicPage
|
||||||
|
*
|
||||||
* @NoCSRFRequired
|
* @NoCSRFRequired
|
||||||
*/
|
*/
|
||||||
public function serviceWorker(): StreamResponse
|
public function serviceWorker(): StreamResponse
|
||||||
|
@ -697,6 +713,11 @@ class ApiController extends Controller
|
||||||
$transforms[] = [$this->timelineQuery, 'transformExtraFields', $fields];
|
$transforms[] = [$this->timelineQuery, 'transformExtraFields', $fields];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Other transforms not allowed for public shares
|
||||||
|
if (null === $this->userSession->getUser()) {
|
||||||
|
return $transforms;
|
||||||
|
}
|
||||||
|
|
||||||
// Filter only favorites
|
// Filter only favorites
|
||||||
if ($this->request->getParam('fav')) {
|
if ($this->request->getParam('fav')) {
|
||||||
$transforms[] = [$this->timelineQuery, 'transformFavoriteFilter'];
|
$transforms[] = [$this->timelineQuery, 'transformFavoriteFilter'];
|
||||||
|
@ -753,7 +774,9 @@ class ApiController extends Controller
|
||||||
*/
|
*/
|
||||||
private function preloadDays(array &$days, &$folder, bool $recursive, bool $archive)
|
private function preloadDays(array &$days, &$folder, bool $recursive, bool $archive)
|
||||||
{
|
{
|
||||||
$uid = $this->userSession->getUser()->getUID();
|
$user = $this->userSession->getUser();
|
||||||
|
$uid = $user ? $user->getUID() : '';
|
||||||
|
|
||||||
$transforms = $this->getTransformations(false);
|
$transforms = $this->getTransformations(false);
|
||||||
$preloaded = 0;
|
$preloaded = 0;
|
||||||
$preloadDayIds = [];
|
$preloadDayIds = [];
|
||||||
|
@ -799,33 +822,49 @@ class ApiController extends Controller
|
||||||
/** Get the Folder object relevant to the request */
|
/** Get the Folder object relevant to the request */
|
||||||
private function getRequestFolder()
|
private function getRequestFolder()
|
||||||
{
|
{
|
||||||
$uid = $this->userSession->getUser()->getUID();
|
$user = $this->userSession->getUser();
|
||||||
|
if (null === $user) {
|
||||||
|
// Public shares only
|
||||||
|
if ($token = $this->getShareToken()) {
|
||||||
|
$share = $this->shareManager->getShareByToken($token)->getNode(); // throws exception if not found
|
||||||
|
if (!$share instanceof Folder) {
|
||||||
|
throw new \Exception('Share not found or invalid');
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
return $share;
|
||||||
$folder = null;
|
|
||||||
$folderPath = $this->request->getParam('folder');
|
|
||||||
$forcedTimelinePath = $this->request->getParam('timelinePath');
|
|
||||||
$userFolder = $this->rootFolder->getUserFolder($uid);
|
|
||||||
|
|
||||||
if (null !== $folderPath) {
|
|
||||||
$folder = $userFolder->get($folderPath);
|
|
||||||
} elseif (null !== $forcedTimelinePath) {
|
|
||||||
$folder = $userFolder->get($forcedTimelinePath);
|
|
||||||
} else {
|
|
||||||
$configPath = Exif::removeExtraSlash(Exif::getPhotosPath($this->config, $uid));
|
|
||||||
$folder = $userFolder->get($configPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$folder instanceof Folder) {
|
|
||||||
throw new \Exception('Folder not found');
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$uid = $user->getUID();
|
||||||
|
|
||||||
|
$folder = null;
|
||||||
|
$folderPath = $this->request->getParam('folder');
|
||||||
|
$forcedTimelinePath = $this->request->getParam('timelinePath');
|
||||||
|
$userFolder = $this->rootFolder->getUserFolder($uid);
|
||||||
|
|
||||||
|
if (null !== $folderPath) {
|
||||||
|
$folder = $userFolder->get($folderPath);
|
||||||
|
} elseif (null !== $forcedTimelinePath) {
|
||||||
|
$folder = $userFolder->get($forcedTimelinePath);
|
||||||
|
} else {
|
||||||
|
$configPath = Exif::removeExtraSlash(Exif::getPhotosPath($this->config, $uid));
|
||||||
|
$folder = $userFolder->get($configPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$folder instanceof Folder) {
|
||||||
|
throw new \Exception('Folder not found');
|
||||||
|
}
|
||||||
|
|
||||||
return $folder;
|
return $folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getShareToken()
|
||||||
|
{
|
||||||
|
return $this->request->getParam('folder_share');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if albums are enabled for this user.
|
* Check if albums are enabled for this user.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -8,6 +8,7 @@ use OCA\Viewer\Event\LoadViewer;
|
||||||
use OCP\App\IAppManager;
|
use OCP\App\IAppManager;
|
||||||
use OCP\AppFramework\Controller;
|
use OCP\AppFramework\Controller;
|
||||||
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
||||||
|
use OCP\AppFramework\Http\Template\PublicTemplateResponse;
|
||||||
use OCP\AppFramework\Http\TemplateResponse;
|
use OCP\AppFramework\Http\TemplateResponse;
|
||||||
use OCP\AppFramework\Services\IInitialState;
|
use OCP\AppFramework\Services\IInitialState;
|
||||||
use OCP\EventDispatcher\IEventDispatcher;
|
use OCP\EventDispatcher\IEventDispatcher;
|
||||||
|
@ -103,6 +104,31 @@ class PageController extends Controller
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @PublicPage
|
||||||
|
*
|
||||||
|
* @NoCSRFRequired
|
||||||
|
*/
|
||||||
|
public function sharedFolder(string $token)
|
||||||
|
{
|
||||||
|
// Scripts
|
||||||
|
Util::addScript($this->appName, 'memories-main');
|
||||||
|
$this->eventDispatcher->dispatchTyped(new LoadSidebar());
|
||||||
|
$this->eventDispatcher->dispatchTyped(new LoadViewer());
|
||||||
|
|
||||||
|
// App version
|
||||||
|
$this->initialState->provideInitialState('version', $this->appManager->getAppInfo('memories')['version']);
|
||||||
|
|
||||||
|
$policy = new ContentSecurityPolicy();
|
||||||
|
$policy->addAllowedWorkerSrcDomain("'self'");
|
||||||
|
$policy->addAllowedScriptDomain("'self'");
|
||||||
|
|
||||||
|
$response = new PublicTemplateResponse($this->appName, 'main');
|
||||||
|
$response->setContentSecurityPolicy($policy);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
*
|
*
|
||||||
|
|
|
@ -102,7 +102,7 @@ trait TimelineQueryDays
|
||||||
// We don't actually use m.datetaken here, but postgres
|
// We don't actually use m.datetaken here, but postgres
|
||||||
// needs that all fields in ORDER BY are also in SELECT
|
// needs that all fields in ORDER BY are also in SELECT
|
||||||
// when using DISTINCT on selected fields
|
// when using DISTINCT on selected fields
|
||||||
$query->select($fileid, 'f.etag', 'm.isvideo', 'vco.categoryid', 'm.datetaken', 'm.dayid', 'm.w', 'm.h')
|
$query->select($fileid, 'f.etag', 'f.path', 'm.isvideo', 'vco.categoryid', 'm.datetaken', 'm.dayid', 'm.w', 'm.h')
|
||||||
->from('memories', 'm')
|
->from('memories', 'm')
|
||||||
;
|
;
|
||||||
$query = $this->joinFilecache($query, $folder, $recursive, $archive);
|
$query = $this->joinFilecache($query, $folder, $recursive, $archive);
|
||||||
|
@ -129,7 +129,7 @@ trait TimelineQueryDays
|
||||||
$rows = $cursor->fetchAll();
|
$rows = $cursor->fetchAll();
|
||||||
$cursor->closeCursor();
|
$cursor->closeCursor();
|
||||||
|
|
||||||
return $this->processDay($rows);
|
return $this->processDay($rows, $folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,10 +150,13 @@ trait TimelineQueryDays
|
||||||
/**
|
/**
|
||||||
* Process the single day response.
|
* Process the single day response.
|
||||||
*
|
*
|
||||||
* @param array $day
|
* @param array $day
|
||||||
|
* @param null|Folder $folder
|
||||||
*/
|
*/
|
||||||
private function processDay(&$day)
|
private function processDay(&$day, $folder)
|
||||||
{
|
{
|
||||||
|
$basePath = null !== $folder ? $folder->getInternalPath() : '#__#__#';
|
||||||
|
|
||||||
foreach ($day as &$row) {
|
foreach ($day as &$row) {
|
||||||
// We don't need date taken (see query builder)
|
// We don't need date taken (see query builder)
|
||||||
unset($row['datetaken']);
|
unset($row['datetaken']);
|
||||||
|
@ -172,6 +175,14 @@ trait TimelineQueryDays
|
||||||
}
|
}
|
||||||
unset($row['categoryid']);
|
unset($row['categoryid']);
|
||||||
|
|
||||||
|
// Check if path exists and starts with basePath and remove
|
||||||
|
if (isset($row['path']) && !empty($row['path'])) {
|
||||||
|
if (0 === strpos($row['path'], $basePath)) {
|
||||||
|
$row['filename'] = substr($row['path'], \strlen($basePath));
|
||||||
|
}
|
||||||
|
unset($row['path']);
|
||||||
|
}
|
||||||
|
|
||||||
// All transform processing
|
// All transform processing
|
||||||
$this->processFace($row);
|
$this->processFace($row);
|
||||||
}
|
}
|
||||||
|
|
|
@ -532,6 +532,11 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
|
||||||
query.set("fields", "basename,mimetype");
|
query.set("fields", "basename,mimetype");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Favorites
|
||||||
|
if (this.$route.name === "folder-share") {
|
||||||
|
query.set("folder_share", this.$route.params.token);
|
||||||
|
}
|
||||||
|
|
||||||
// Create query string and append to URL
|
// Create query string and append to URL
|
||||||
const queryStr = query.toString();
|
const queryStr = query.toString();
|
||||||
if (queryStr) {
|
if (queryStr) {
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
class="fill-block"
|
class="fill-block"
|
||||||
:class="{ error: info.flag & c.FLAG_LOAD_FAIL }"
|
:class="{ error: info.flag & c.FLAG_LOAD_FAIL }"
|
||||||
:key="'fpreview-' + info.fileid"
|
:key="'fpreview-' + info.fileid"
|
||||||
:src="getPreviewUrl(info.fileid, info.etag, true, 256)"
|
:src="getPreviewUrl(info, true, 256)"
|
||||||
@error="info.flag |= c.FLAG_LOAD_FAIL"
|
@error="info.flag |= c.FLAG_LOAD_FAIL"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -40,16 +40,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Prop, Emit, Mixins, Watch } from "vue-property-decorator";
|
import Check from "vue-material-design-icons/Check.vue";
|
||||||
import { IDay, IPhoto } from "../../types";
|
import Star from "vue-material-design-icons/Star.vue";
|
||||||
|
import Video from "vue-material-design-icons/Video.vue";
|
||||||
import { getPhotosPreviewUrl, getPreviewUrl } from "../../services/FileUtils";
|
import { Component, Emit, Mixins, Prop, Watch } from "vue-property-decorator";
|
||||||
import errorsvg from "../../assets/error.svg";
|
import errorsvg from "../../assets/error.svg";
|
||||||
import GlobalMixin from "../../mixins/GlobalMixin";
|
import GlobalMixin from "../../mixins/GlobalMixin";
|
||||||
|
import { getPreviewUrl } from "../../services/FileUtils";
|
||||||
import Check from "vue-material-design-icons/Check.vue";
|
import { IDay, IPhoto } from "../../types";
|
||||||
import Video from "vue-material-design-icons/Video.vue";
|
|
||||||
import Star from "vue-material-design-icons/Star.vue";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
|
@ -122,9 +120,7 @@ export default class Photo extends Mixins(GlobalMixin) {
|
||||||
) - 1;
|
) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fun =
|
return getPreviewUrl(this.data, false, size);
|
||||||
this.$route.name === "albums" ? getPhotosPreviewUrl : getPreviewUrl;
|
|
||||||
return fun(this.data.fileid, this.data.etag, false, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set src with overlay face rect */
|
/** Set src with overlay face rect */
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
class="fill-block"
|
class="fill-block"
|
||||||
:class="{ error: info.flag & c.FLAG_LOAD_FAIL }"
|
:class="{ error: info.flag & c.FLAG_LOAD_FAIL }"
|
||||||
:key="'fpreview-' + info.fileid"
|
:key="'fpreview-' + info.fileid"
|
||||||
:src="getPreviewUrl(info.fileid, info.etag)"
|
:src="getPreviewUrl(info)"
|
||||||
@error="info.flag |= c.FLAG_LOAD_FAIL"
|
@error="info.flag |= c.FLAG_LOAD_FAIL"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -80,7 +80,7 @@ export default class Tag extends Mixins(GlobalMixin) {
|
||||||
this.refreshPreviews();
|
this.refreshPreviews();
|
||||||
}
|
}
|
||||||
|
|
||||||
getPreviewUrl(fileid: number, etag: string) {
|
getPreviewUrl(photo: IPhoto) {
|
||||||
if (this.isFace) {
|
if (this.isFace) {
|
||||||
return generateUrl(
|
return generateUrl(
|
||||||
"/apps/memories/api/faces/preview/" + this.data.fileid
|
"/apps/memories/api/faces/preview/" + this.data.fileid
|
||||||
|
@ -88,10 +88,10 @@ export default class Tag extends Mixins(GlobalMixin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isAlbum) {
|
if (this.isAlbum) {
|
||||||
return getPhotosPreviewUrl(fileid, etag, true, 256);
|
return getPhotosPreviewUrl(photo, true, 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getPreviewUrl(fileid, etag, true, 256);
|
return getPreviewUrl(photo, true, 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
get isFace() {
|
get isFace() {
|
||||||
|
|
|
@ -89,7 +89,7 @@ import ImageMultiple from "vue-material-design-icons/ImageMultiple.vue";
|
||||||
import { NcButton, NcListItem, NcLoadingIcon } from "@nextcloud/vue";
|
import { NcButton, NcListItem, NcLoadingIcon } from "@nextcloud/vue";
|
||||||
import { generateUrl } from "@nextcloud/router";
|
import { generateUrl } from "@nextcloud/router";
|
||||||
import { getPhotosPreviewUrl } from "../../services/FileUtils";
|
import { getPhotosPreviewUrl } from "../../services/FileUtils";
|
||||||
import { IAlbum } from "../../types";
|
import { IAlbum, IPhoto } from "../../types";
|
||||||
import axios from "@nextcloud/axios";
|
import axios from "@nextcloud/axios";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -103,7 +103,13 @@ import axios from "@nextcloud/axios";
|
||||||
},
|
},
|
||||||
filters: {
|
filters: {
|
||||||
toCoverUrl(fileId: string) {
|
toCoverUrl(fileId: string) {
|
||||||
return getPhotosPreviewUrl(Number(fileId), "unknown", true, 256);
|
return getPhotosPreviewUrl(
|
||||||
|
{
|
||||||
|
fileid: Number(fileId),
|
||||||
|
} as IPhoto,
|
||||||
|
true,
|
||||||
|
256
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -157,12 +157,7 @@ export default class OnThisDay extends Mixins(GlobalMixin) {
|
||||||
|
|
||||||
// Get random photo
|
// Get random photo
|
||||||
year.preview ||= utils.randomChoice(year.photos);
|
year.preview ||= utils.randomChoice(year.photos);
|
||||||
year.url = getPreviewUrl(
|
year.url = getPreviewUrl(year.preview, false, 512);
|
||||||
year.preview.fileid,
|
|
||||||
year.preview.etag,
|
|
||||||
false,
|
|
||||||
512
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.$nextTick();
|
await this.$nextTick();
|
||||||
|
|
|
@ -135,5 +135,14 @@ export default new Router({
|
||||||
window.open(generateUrl("/apps/maps"), "_blank");
|
window.open(generateUrl("/apps/maps"), "_blank");
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: "/s/:token",
|
||||||
|
component: Timeline,
|
||||||
|
name: "folder-share",
|
||||||
|
props: (route) => ({
|
||||||
|
rootTitle: t("memories", "Shared Folder"),
|
||||||
|
}),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,9 +19,10 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
import camelcase from "camelcase";
|
|
||||||
import { isNumber } from "./NumberUtils";
|
|
||||||
import { generateUrl } from "@nextcloud/router";
|
import { generateUrl } from "@nextcloud/router";
|
||||||
|
import camelcase from "camelcase";
|
||||||
|
import { IExtendedPhoto, IFileInfo, IPhoto } from "../types";
|
||||||
|
import { isNumber } from "./NumberUtils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an url encoded path
|
* Get an url encoded path
|
||||||
|
@ -133,29 +134,41 @@ const genFileInfo = function (obj) {
|
||||||
return fileInfo;
|
return fileInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Get preview URL from Nextcloud core */
|
/** Get preview URL from photo object */
|
||||||
const getPreviewUrl = function (
|
const getPreviewUrl = function (
|
||||||
fileid: number,
|
photo: IPhoto | IFileInfo,
|
||||||
etag: string,
|
|
||||||
square: boolean,
|
square: boolean,
|
||||||
size: number
|
size: number
|
||||||
): string {
|
) {
|
||||||
const a = square ? "0" : "1";
|
const a = square ? "0" : "1";
|
||||||
|
|
||||||
|
// Public preview
|
||||||
|
if (vuerouter.currentRoute.name === "folder-share") {
|
||||||
|
const token = vuerouter.currentRoute.params.token;
|
||||||
|
return generateUrl(
|
||||||
|
`/apps/files_sharing/publicpreview/${token}?file=${photo.filename}&fileId=${photo.fileid}&x=${size}&y=${size}&a=${a}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Albums from Photos
|
||||||
|
if (vuerouter.currentRoute.name === "albums") {
|
||||||
|
return getPhotosPreviewUrl(photo, square, size);
|
||||||
|
}
|
||||||
|
|
||||||
return generateUrl(
|
return generateUrl(
|
||||||
`/core/preview?fileId=${fileid}&c=${etag}&x=${size}&y=${size}&forceIcon=0&a=${a}`
|
`/core/preview?fileId=${photo.fileid}&c=${photo.etag}&x=${size}&y=${size}&forceIcon=0&a=${a}`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Get the preview URL from the photos app */
|
/** Get the preview URL from the photos app */
|
||||||
const getPhotosPreviewUrl = function (
|
const getPhotosPreviewUrl = function (
|
||||||
fileid: number,
|
photo: IPhoto | IFileInfo,
|
||||||
etag: string,
|
|
||||||
square: boolean,
|
square: boolean,
|
||||||
size: number
|
size: number
|
||||||
): string {
|
): string {
|
||||||
const a = square ? "0" : "1";
|
const a = square ? "0" : "1";
|
||||||
return generateUrl(
|
return generateUrl(
|
||||||
`/apps/photos/api/v1/preview/${fileid}?c=${etag}&x=${size}&y=${size}&forceIcon=0&a=${a}`
|
`/apps/photos/api/v1/preview/${photo.fileid}?c=${photo.etag}&x=${size}&y=${size}&forceIcon=0&a=${a}`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,8 @@ export type IPhoto = {
|
||||||
fileid: number;
|
fileid: number;
|
||||||
/** Etag from server */
|
/** Etag from server */
|
||||||
etag?: string;
|
etag?: string;
|
||||||
|
/** Path to file */
|
||||||
|
filename?: string;
|
||||||
/** Bit flags */
|
/** Bit flags */
|
||||||
flag: number;
|
flag: number;
|
||||||
/** DayID from server */
|
/** DayID from server */
|
||||||
|
|
Loading…
Reference in New Issue