Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ function w($base, $param)
['name' => 'Image#setExif', 'url' => '/api/image/set-exif/{id}', 'verb' => 'PATCH'],
['name' => 'Image#decodable', 'url' => '/api/image/decodable/{id}', 'verb' => 'GET'],
['name' => 'Image#editImage', 'url' => '/api/image/edit/{id}', 'verb' => 'PUT'],
['name' => 'Image#deleteFile', 'url' => '/api/image/delete/{id}', 'verb' => 'DELETE'],

['name' => 'Video#transcode', 'url' => '/api/video/transcode/{client}/{fileid}/{profile}', 'verb' => 'GET'],
['name' => 'Video#livephoto', 'url' => '/api/video/livephoto/{fileid}', 'verb' => 'GET'],
Expand Down
41 changes: 39 additions & 2 deletions lib/Controller/ImageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,9 @@ public function info(
$info['ownername'] = $owner->getDisplayName();
}

// Allow these ony for logged in users
// Get the path of the file relative to root
// For public shares, get path relative to share root
// For logged in users, get path relative to user folder
if ($user = $this->userSession->getUser()) {
// Get the path of the file relative to current user
// "/admin/files/Photos/Camera/20230821_135017.jpg" => "/Photos/..."
Expand Down Expand Up @@ -246,16 +248,27 @@ public function info(
}
$info['clusters'] = $clist;
}
} else {
// For public shares, get path relative to share root
$shareNode = $this->fs->getShareNode();
if ($shareNode) {
$sharePath = $shareNode->getPath();
$filePath = $file->getPath();
if (str_starts_with($filePath, $sharePath)) {
$info['filename'] = substr($filePath, \strlen($sharePath));
}
}
}

return new JSONResponse($info, Http::STATUS_OK);
});
}

/**
* Set the exif data for a file.
* Set the exif data for a file (supports public shares).
*/
#[NoAdminRequired]
#[PublicPage]
public function setExif(int $id, array $raw): Http\Response
{
return Util::guardEx(function () use ($id, $raw) {
Expand Down Expand Up @@ -326,6 +339,7 @@ public function decodable(string $id): Http\Response
}

#[NoAdminRequired]
#[PublicPage]
public function editImage(
int $id,
string $name,
Expand Down Expand Up @@ -400,6 +414,29 @@ public function editImage(
});
}

/**
* Delete a file (supports public shares).
*/
#[NoAdminRequired]
#[PublicPage]
public function deleteFile(int $id): Http\Response
{
return Util::guardEx(function () use ($id) {
// Get the file
$file = $this->fs->getUserFile($id);

// Check if user has delete permissions
if (!$file->isDeletable()) {
throw Exceptions::Forbidden('No delete permission for this file');
}

// Delete the file
$file->delete();

return new JSONResponse(['deleted' => true], Http::STATUS_OK);
});
}

/**
* Given a blob of image data, return a JPEG blob.
*
Expand Down
3 changes: 3 additions & 0 deletions lib/Controller/PublicController.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ public function showShare(): TemplateResponse
// Share info
$this->initialState->provideInitialState('no_download', $share->getHideDownload());
$this->initialState->provideInitialState('share_title', $node->getName());
$this->initialState->provideInitialState('allow_upload', ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) === \OCP\Constants::PERMISSION_CREATE);
$this->initialState->provideInitialState('allow_delete', ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) === \OCP\Constants::PERMISSION_DELETE);


if ($node instanceof \OCP\Files\File) {
$this->initialState->provideInitialState('single_item', $this->getSingleItemInitialState($node));
Expand Down
5 changes: 3 additions & 2 deletions src/components/SelectionManager.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
{{ n('memories', '{n} selected', '{n} selected', size, { n: size }) }}
</div>

<NcActions :inline="1">
<NcActions :inline="3">
<NcActionButton
v-for="action of getActions()"
:key="action.name"
Expand Down Expand Up @@ -200,7 +200,8 @@ export default defineComponent({
name: t('memories', 'Delete'),
icon: DeleteIcon,
callback: this.deleteSelection.bind(this),
if: () => !this.routeIsAlbums,
allowPublic: true,
if: () => !this.routeIsAlbums && (!this.routeIsPublic || this.initstate.allow_delete),
},
{
name: t('memories', 'Remove from album'),
Expand Down
56 changes: 45 additions & 11 deletions src/components/top-matter/FolderTopMatter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</NcBreadcrumbs>

<div class="right-actions">
<NcActions :inline="1">
<NcActions :inline="3">
<NcActionButton
v-if="!routeIsPublic"
:aria-label="t('memories', 'Share folder')"
Expand All @@ -32,6 +32,17 @@
<template #icon> <UploadIcon :size="20" /> </template>
</NcActionButton>

<!-- Public upload button -->
<NcActionButton
v-if="routeIsPublic && allowUpload"
:aria-label="t('memories', 'Upload files')"
:disabled="isUploading"
@click="triggerFileUpload"
>
{{ isUploading ? t('memories', 'Uploading...') : t('memories', 'Upload files') }}
<template #icon> <UploadIcon :size="20" /> </template>
</NcActionButton>

<NcActionButton @click="toggleRecursive" close-after-click>
{{ recursive ? t('memories', 'Folder view') : t('memories', 'Timeline view') }}
<template #icon>
Expand All @@ -40,6 +51,9 @@
</template>
</NcActionButton>
</NcActions>

<!-- Progress bar for PublicUploadHandler -->
<PublicUploadHandler ref="uploadHandler" v-if="routeIsPublic && allowUpload" />
</div>
</div>
</template>
Expand All @@ -53,6 +67,7 @@ const NcBreadcrumbs = () => import('@nextcloud/vue/dist/Components/NcBreadcrumbs
const NcBreadcrumb = () => import('@nextcloud/vue/dist/Components/NcBreadcrumb.js');
import NcActions from '@nextcloud/vue/dist/Components/NcActions.js';
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js';
import PublicUploadHandler from '@components/upload/PublicUploadHandler.vue';

import * as utils from '@services/utils';
import * as nativex from '@native';
Expand All @@ -71,6 +86,7 @@ export default defineComponent({
NcBreadcrumb,
NcActions,
NcActionButton,
PublicUploadHandler,
HomeIcon,
ShareIcon,
TimelineIcon,
Expand Down Expand Up @@ -110,18 +126,28 @@ export default defineComponent({
isNative(): boolean {
return nativex.has();
},

allowUpload(): boolean {
return this.initstate.allow_upload === true;
},

// Check if PublicUploadHandler is currently uploading
isUploading(): boolean {
const handler = this.$refs.uploadHandler as any;
return handler?.processing || false;
},
},

methods: {
share() {
share(): void {
_m.modals.shareNodeLink(utils.getFolderRoutePath(this.config.folders_path));
},

upload() {
upload(): void {
_m.modals.upload();
},

toggleRecursive() {
toggleRecursive(): void {
this.$router.replace({
query: {
...this.$router.currentRoute.query,
Expand All @@ -130,25 +156,33 @@ export default defineComponent({
});
},

getRoute(path: string[]) {
getRoute(path: string[]): object {
return {
...this.$route,
params: { path },
hash: undefined,
};
},

// Trigger upload via PublicUploadHandler
triggerFileUpload(): void {
const handler = this.$refs.uploadHandler as any;
if (handler && typeof handler.startUpload === 'function') {
handler.startUpload();
} else {
console.error('PublicUploadHandler not properly initialized');
}
},
},
});
</script>

<style lang="scss" scoped>
.top-matter {
.breadcrumb {
min-width: 0;
height: unset;
.share-name {
margin-left: 0.75em;
}
.right-actions {
display: flex;
align-items: center;
gap: 10px; // Add spacing between actions and progress bar
}
}
</style>
Loading