Skip to content

Commit d7426f6

Browse files
committed
fix(encryption): Correctly set encrypted to 0 when copying
If encryption got disabled, copying should set encrypted to 0 for the new unencrypted copy. For instance when using encryption:decrypt-all Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com> Signed-off-by: Louis Chemineau <louis@chmn.me> [skip ci]
1 parent ceb65eb commit d7426f6

File tree

4 files changed

+94
-47
lines changed

4 files changed

+94
-47
lines changed

apps/files/src/newMenu/newFromTemplate.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type { TemplateFile } from '../types.ts'
99

1010
import { Folder, Node, Permission, addNewFileMenuEntry } from '@nextcloud/files'
1111
import { loadState } from '@nextcloud/initial-state'
12+
import { isPublicShare } from '@nextcloud/sharing/public'
1213
import { newNodeName } from '../utils/newNodeDialog'
1314
import { translate as t } from '@nextcloud/l10n'
1415
import Vue, { defineAsyncComponent } from 'vue'
@@ -46,7 +47,12 @@ const getTemplatePicker = async (context: Folder) => {
4647
* Register all new-file-menu entries for all template providers
4748
*/
4849
export function registerTemplateEntries() {
49-
const templates = loadState<TemplateFile[]>('files', 'templates', [])
50+
let templates: TemplateFile[]
51+
if (isPublicShare()) {
52+
templates = loadState<TemplateFile[]>('files_sharing', 'templates', [])
53+
} else {
54+
templates = loadState<TemplateFile[]>('files', 'templates', [])
55+
}
5056

5157
// Init template files menu
5258
templates.forEach((provider, index) => {

apps/files/src/views/TemplatePicker.vue

Lines changed: 78 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ import type { TemplateFile } from '../types.ts'
5252
import { getCurrentUser } from '@nextcloud/auth'
5353
import { showError, spawnDialog } from '@nextcloud/dialogs'
5454
import { emit } from '@nextcloud/event-bus'
55-
import { File } from '@nextcloud/files'
55+
import { File, Node } from '@nextcloud/files'
56+
import { getClient, getRootPath, resultToNode, getDefaultPropfind } from '@nextcloud/files/dav'
5657
import { translate as t } from '@nextcloud/l10n'
5758
import { generateRemoteUrl } from '@nextcloud/router'
5859
import { normalize, extname, join } from 'path'
@@ -64,6 +65,7 @@ import NcModal from '@nextcloud/vue/dist/Components/NcModal.js'
6465
import TemplatePreview from '../components/TemplatePreview.vue'
6566
import TemplateFiller from '../components/TemplateFiller.vue'
6667
import logger from '../logger.ts'
68+
import type { FileStat, ResponseDataDetailed } from 'webdav'
6769
6870
const border = 2
6971
const margin = 8
@@ -167,6 +169,12 @@ export default defineComponent({
167169
this.name = name
168170
this.provider = provider
169171
172+
// Skip templates logic for external users.
173+
if (getCurrentUser() === null) {
174+
this.onSubmit()
175+
return
176+
}
177+
170178
const templates = await getTemplates()
171179
const fetchedProvider = templates.find((fetchedProvider) => fetchedProvider.app === provider.app && fetchedProvider.label === provider.label)
172180
if (fetchedProvider === null) {
@@ -224,56 +232,80 @@ export default defineComponent({
224232
this.name = `${this.name}${this.provider?.extension ?? ''}`
225233
}
226234
227-
try {
228-
const fileInfo = await createFromTemplate(
229-
normalize(`${currentDirectory}/${this.name}`),
230-
this.selectedTemplate?.filename as string ?? '',
231-
this.selectedTemplate?.templateType as string ?? '',
232-
templateFields,
233-
)
234-
logger.debug('Created new file', fileInfo)
235-
236-
const owner = getCurrentUser()?.uid || null
237-
const node = new File({
238-
id: fileInfo.fileid,
239-
source: generateRemoteUrl(join(`dav/files/${owner}`, fileInfo.filename)),
240-
root: `/files/${owner}`,
241-
mime: fileInfo.mime,
242-
mtime: new Date(fileInfo.lastmod * 1000),
243-
owner,
244-
size: fileInfo.size,
245-
permissions: fileInfo.permissions,
246-
attributes: {
247-
// Inherit some attributes from parent folder like the mount type and real owner
248-
'mount-type': this.parent?.attributes?.['mount-type'],
249-
'owner-id': this.parent?.attributes?.['owner-id'],
250-
'owner-display-name': this.parent?.attributes?.['owner-display-name'],
251-
...fileInfo,
252-
'has-preview': fileInfo.hasPreview,
253-
},
254-
})
235+
// Create a blank file for external users as we can't use the templates.
236+
if (getCurrentUser() === null) {
237+
const client = getClient()
238+
const filename = join(getRootPath(), currentDirectory, this.name ?? '')
239+
240+
await client.putFileContents(filename, '')
241+
const response = await client.stat(filename, { data: getDefaultPropfind(), details: true }) as ResponseDataDetailed<FileStat>
242+
logger.debug('Created new file', { fileInfo: response.data })
243+
244+
const node = resultToNode(response.data)
255245
256-
// Update files list
257-
emit('files:node:created', node)
258-
259-
// Open the new file
260-
window.OCP.Files.Router.goToRoute(
261-
null, // use default route
262-
{ view: 'files', fileid: node.fileid },
263-
{ dir: node.dirname, openfile: 'true' },
264-
)
265-
266-
// Close the picker
267-
this.close()
268-
} catch (error) {
269-
logger.error('Error while creating the new file from template', { error })
270-
showError(t('files', 'Unable to create new file from template'))
271-
} finally {
272-
this.loading = false
246+
this.handleFileCreation(node)
247+
} else {
248+
try {
249+
const fileInfo = await createFromTemplate(
250+
normalize(`${currentDirectory}/${this.name}`),
251+
this.selectedTemplate?.filename as string ?? '',
252+
this.selectedTemplate?.templateType as string ?? '',
253+
templateFields,
254+
)
255+
logger.debug('Created new file', { fileInfo })
256+
257+
const owner = getCurrentUser()?.uid || null
258+
const node = new File({
259+
id: fileInfo.fileid,
260+
source: generateRemoteUrl(join(`dav/files/${owner}`, fileInfo.filename)),
261+
root: `/files/${owner}`,
262+
mime: fileInfo.mime,
263+
mtime: new Date(fileInfo.lastmod * 1000),
264+
owner,
265+
size: fileInfo.size,
266+
permissions: fileInfo.permissions,
267+
attributes: {
268+
// Inherit some attributes from parent folder like the mount type and real owner
269+
'mount-type': this.parent?.attributes?.['mount-type'],
270+
'owner-id': this.parent?.attributes?.['owner-id'],
271+
'owner-display-name': this.parent?.attributes?.['owner-display-name'],
272+
...fileInfo,
273+
'has-preview': fileInfo.hasPreview,
274+
},
275+
})
276+
277+
this.handleFileCreation(node)
278+
279+
// Close the picker
280+
this.close()
281+
} catch (error) {
282+
logger.error('Error while creating the new file from template', { error })
283+
showError(t('files', 'Unable to create new file from template'))
284+
} finally {
285+
this.loading = false
286+
}
273287
}
274288
},
275289
290+
handleFileCreation(node: Node) {
291+
// Update files list
292+
emit('files:node:created', node)
293+
294+
// Open the new file
295+
window.OCP.Files.Router.goToRoute(
296+
null, // use default route
297+
{ view: 'files', fileid: node.fileid },
298+
{ dir: node.dirname, openfile: 'true' },
299+
)
300+
},
301+
276302
async onSubmit() {
303+
// Skip templates logic for external users.
304+
if (getCurrentUser() === null) {
305+
this.loading = true
306+
return this.createFile()
307+
}
308+
277309
const fileId = this.selectedTemplate?.fileid
278310
279311
// Only request field extraction if there is a valid template

apps/files_sharing/lib/DefaultPublicShareTemplateProvider.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use OCP\Defaults;
2525
use OCP\EventDispatcher\IEventDispatcher;
2626
use OCP\Files\File;
27+
use OCP\Files\Template\ITemplateManager;
2728
use OCP\IAppConfig;
2829
use OCP\IConfig;
2930
use OCP\IL10N;
@@ -49,6 +50,7 @@ public function __construct(
4950
private Defaults $defaults,
5051
private IConfig $config,
5152
private IRequest $request,
53+
private ITemplateManager $templateManager,
5254
private IInitialState $initialState,
5355
private IAppConfig $appConfig,
5456
) {
@@ -120,6 +122,8 @@ public function renderPage(IShare $share, string $token, string $path): Template
120122
$this->eventDispatcher->dispatchTyped(new LoadViewer());
121123
}
122124

125+
$this->initialState->provideInitialState('templates', $this->templateManager->listCreators());
126+
123127
// Allow external apps to register their scripts
124128
$this->eventDispatcher->dispatchTyped(new BeforeTemplateRenderedEvent($share));
125129

apps/files_sharing/tests/Controller/ShareControllerTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
use OCP\Files\File;
3131
use OCP\Files\IRootFolder;
3232
use OCP\Files\NotFoundException;
33+
use OCP\Files\Template\ITemplateManager;
3334
use OCP\IAppConfig;
3435
use OCP\IConfig;
3536
use OCP\IL10N;
@@ -67,6 +68,7 @@ class ShareControllerTest extends \Test\TestCase {
6768
private Manager&MockObject $shareManager;
6869
private IPreview&MockObject $previewManager;
6970
private IUserManager&MockObject $userManager;
71+
private ITemplateManager&MockObject $templateManager;
7072
private IInitialState&MockObject $initialState;
7173
private IURLGenerator&MockObject $urlGenerator;
7274
private ISecureRandom&MockObject $secureRandom;
@@ -86,6 +88,7 @@ protected function setUp(): void {
8688
$this->config = $this->createMock(IConfig::class);
8789
$this->appConfig = $this->createMock(IAppConfig::class);
8890
$this->userManager = $this->createMock(IUserManager::class);
91+
$this->templateManager = $this->createMock(ITemplateManager::class);
8992
$this->initialState = $this->createMock(IInitialState::class);
9093
$this->federatedShareProvider = $this->createMock(FederatedShareProvider::class);
9194
$this->federatedShareProvider->expects($this->any())
@@ -113,6 +116,7 @@ protected function setUp(): void {
113116
$this->defaults,
114117
$this->config,
115118
$this->createMock(IRequest::class),
119+
$this->templateManager,
116120
$this->initialState,
117121
$this->appConfig,
118122
)
@@ -482,6 +486,7 @@ public function testShowFileDropShare(): void {
482486
'ownerDisplayName' => 'ownerDisplay',
483487
'note' => 'The note',
484488
'label' => 'A label',
489+
'templates' => [],
485490
];
486491

487492
$response = $this->shareController->showShare();

0 commit comments

Comments
 (0)