Skip to content

Commit 0849b55

Browse files
author
Julien Veyssier
authored
Merge pull request #2378 from nextcloud/enh/2339/non-image-media-attachments
Non-image media attachments
2 parents 3af1eb8 + 5f0f18a commit 0849b55

41 files changed

Lines changed: 978 additions & 520 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

appinfo/routes.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@
2727

2828
return [
2929
'routes' => [
30-
['name' => 'Image#insertImageFile', 'url' => '/image/filepath', 'verb' => 'POST'],
31-
['name' => 'Image#uploadImage', 'url' => '/image/upload', 'verb' => 'POST'],
32-
['name' => 'Image#getImage', 'url' => '/image', 'verb' => 'GET'],
30+
['name' => 'Attachment#insertAttachmentFile', 'url' => '/attachment/filepath', 'verb' => 'POST'],
31+
['name' => 'Attachment#uploadAttachment', 'url' => '/attachment/upload', 'verb' => 'POST'],
32+
['name' => 'Attachment#getImageFile', 'url' => '/image', 'verb' => 'GET'],
33+
['name' => 'Attachment#getMediaFile', 'url' => '/media', 'verb' => 'GET'],
34+
['name' => 'Attachment#getMediaFilePreview', 'url' => '/mediaPreview', 'verb' => 'GET'],
35+
['name' => 'Attachment#getMediaFileMetadata', 'url' => '/mediaMetadata', 'verb' => 'GET'],
3336

3437
['name' => 'Session#create', 'url' => '/session/create', 'verb' => 'PUT'],
3538
['name' => 'Session#fetch', 'url' => '/session/fetch', 'verb' => 'POST'],
Lines changed: 69 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,19 @@ const randUser2 = randHash()
2828
let currentUser = randUser
2929
const attachmentFileNameToId = {}
3030

31-
const ACTION_UPLOAD_LOCAL_FILE = 'insert-image-upload'
32-
const ACTION_INSERT_FROM_FILES = 'insert-image-insert'
33-
// const ACTION_INSERT_FROM_LINK = 3
31+
const ACTION_UPLOAD_LOCAL_FILE = 'insert-attachment-upload'
32+
const ACTION_INSERT_FROM_FILES = 'insert-attachment-insert'
3433

3534
/**
3635
* @param {string} name name of file
3736
* @param {string|null} requestAlias alias name
3837
*/
3938
function attachFile(name, requestAlias = null) {
4039
if (requestAlias) {
41-
cy.intercept({ method: 'POST', url: '**/upload' }).as(requestAlias)
40+
cy.intercept({ method: 'POST', url: '**/text/attachment/upload?**' }).as(requestAlias)
4241
}
4342
return cy.getEditor()
44-
.find('input[type="file"][data-text-el="image-file-input"]')
43+
.find('input[type="file"][data-text-el="attachment-file-input"]')
4544
.attachFile(name)
4645
}
4746

@@ -56,12 +55,12 @@ function fixedEncodeURIComponent(str) {
5655
}
5756

5857
/**
59-
* Open the image action menu and click one action
58+
* Open the attachment action menu and click one action
6059
*
6160
* @param {string} actionName position of the action to be clicked
6261
*/
63-
const clickOnImageAction = (actionName) => {
64-
cy.getActionEntry('insert-image')
62+
const clickOnAttachmentAction = (actionName) => {
63+
cy.getActionEntry('insert-attachment')
6564
.click()
6665

6766
return cy.get('.v-popper__wrapper .open')
@@ -70,69 +69,79 @@ const clickOnImageAction = (actionName) => {
7069
}
7170

7271
/**
73-
* Check if an image is visible in the document
72+
* Check if an attachment is visible in the document
7473
*
7574
* @param {number} documentId file ID of the current document
76-
* @param {string} imageName file name to be checked
77-
* @param {number} imageId file id
78-
* @param {number|undefined} index index of image in the document
75+
* @param {string} fileName attachment file name to be checked
76+
* @param {number} fileId attachment file id
77+
* @param {number|undefined} index index of the attachment in the document
78+
* @param {boolean} isImage is the attachment an image or a media file?
7979
*/
80-
const checkImage = (documentId, imageName, imageId, index) => {
81-
const encodedName = fixedEncodeURIComponent(imageName)
80+
const checkAttachment = (documentId, fileName, fileId, index, isImage = true) => {
81+
const encodedName = fixedEncodeURIComponent(fileName)
8282
const src = `.attachments.${documentId}/${encodedName}`
8383

84-
cy.log('Check the image is visible and well formed', documentId, imageName, imageId, index, encodedName)
84+
cy.log('Check the attachment is visible and well formed', documentId, fileName, fileId, index, encodedName)
8585
return new Cypress.Promise((resolve, reject) => {
8686
cy.get(`#editor [data-component="image-view"][data-src="${src}"]`)
8787
.find('.image__view') // wait for load finish
8888
.within(($el) => {
89-
// keep track that we have created this image in the attachment dir
89+
// keep track that we have created this attachment in the attachment dir
9090
if (!attachmentFileNameToId[documentId]) {
9191
attachmentFileNameToId[documentId] = {}
9292
}
9393

94-
attachmentFileNameToId[documentId][imageName] = imageId
94+
attachmentFileNameToId[documentId][fileName] = fileId
9595

9696
if (index > 0) {
97-
expect(imageName).include(`(${index + 1})`)
97+
expect(fileName).include(`(${index + 1})`)
9898
}
9999

100+
const srcPathEnd = isImage ? 'image' : 'mediaPreview'
101+
const srcFileNameParam = isImage ? 'imageFileName' : 'mediaFileName'
102+
100103
cy.wrap($el)
101104
.should('be.visible')
102105
.find('img')
103106
.should('have.attr', 'src')
104-
.should('contain', 'apps/text/image?documentId=' + documentId)
105-
.should('contain', 'imageFileName=' + encodeURIComponent(imageName))
106-
107-
return cy.wrap($el)
108-
.find('.image__caption input')
109-
.should('be.visible')
110-
.should('have.value', imageName)
107+
.should('contain', 'apps/text/' + srcPathEnd + '?documentId=' + documentId)
108+
.should('contain', srcFileNameParam + '=' + encodeURIComponent(fileName))
109+
110+
return isImage
111+
? cy.wrap($el)
112+
.find('.image__caption input')
113+
.should('be.visible')
114+
.should('have.value', fileName)
115+
: cy.wrap($el)
116+
.find('.metadata .name')
117+
.should('be.visible')
118+
.should('have.text', fileName)
111119

112120
})
113121
.then(resolve, reject)
114122
})
115123
}
116124

117125
/**
118-
* Wait for the image insertion request to finish and check if the image is visible
126+
* Wait for the attachment insertion request to finish and check if the attachment is visible
119127
*
120128
* @param {string} requestAlias Alias of the request we are waiting for
121-
* @param {number|undefined} index of image
129+
* @param {number|undefined} index of the attachment
130+
* @param {boolean} isImage is the attachment an image or a media file?
122131
*/
123-
const waitForRequestAndCheckImage = (requestAlias, index) => {
132+
const waitForRequestAndCheckAttachment = (requestAlias, index, isImage = true) => {
124133
return cy.wait('@' + requestAlias)
125134
.then((req) => {
126135
// the name of the created file on NC side is returned in the response
127136
const fileId = req.response.body.id
128137
const fileName = req.response.body.name
129138
const documentId = req.response.body.documentId
130139

131-
return checkImage(documentId, fileName, fileId, index)
140+
return checkAttachment(documentId, fileName, fileId, index, isImage)
132141
})
133142
}
134143

135-
describe('Test all image insertion methods', () => {
144+
describe('Test all attachment insertion methods', () => {
136145
before(() => {
137146
initUserAndFiles(randUser, 'test.md', 'empty.md')
138147

@@ -154,10 +163,10 @@ describe('Test all image insertion methods', () => {
154163
cy.showHiddenFiles()
155164
})
156165

157-
it('Insert an image from files', () => {
166+
it('Insert an image file from Files', () => {
158167
cy.openFile('test.md')
159168

160-
clickOnImageAction(ACTION_INSERT_FROM_FILES)
169+
clickOnAttachmentAction(ACTION_INSERT_FROM_FILES)
161170
.then(() => {
162171
const requestAlias = 'insertPathRequest'
163172
cy.intercept({ method: 'POST', url: '**/filepath' }).as(requestAlias)
@@ -167,27 +176,43 @@ describe('Test all image insertion methods', () => {
167176
cy.log('Click OK in the filepicker')
168177
cy.get('.oc-dialog > .oc-dialog-buttonrow button').click()
169178

170-
return waitForRequestAndCheckImage(requestAlias)
179+
return waitForRequestAndCheckAttachment(requestAlias)
171180
})
172181
})
173182

174-
it('Upload a local image', () => {
183+
it('Upload a local image file', () => {
175184
cy.openFile('test.md')
176185
// in this case we almost could just attach the file to the input
177186
// BUT we still need to click on the action because otherwise the command
178187
// is not handled correctly when the upload has been done in <MenuBar>
179-
clickOnImageAction(ACTION_UPLOAD_LOCAL_FILE)
188+
clickOnAttachmentAction(ACTION_UPLOAD_LOCAL_FILE)
180189
.then(() => {
181190
const requestAlias = 'uploadRequest'
182191
cy.log('Upload the file through the input')
183192

184193
attachFile('table.png', requestAlias)
185194

186-
return waitForRequestAndCheckImage(requestAlias)
195+
return waitForRequestAndCheckAttachment(requestAlias)
196+
})
197+
})
198+
199+
it('Upload a local media file', () => {
200+
cy.openFile('test.md')
201+
// in this case we almost could just attach the file to the input
202+
// BUT we still need to click on the action because otherwise the command
203+
// is not handled correctly when the upload has been done in <MenuBar>
204+
clickOnAttachmentAction(ACTION_UPLOAD_LOCAL_FILE)
205+
.then(() => {
206+
const requestAlias = 'uploadMediaRequest'
207+
cy.log('Upload the file through the input')
208+
209+
attachFile('file.txt.gz', requestAlias)
210+
211+
return waitForRequestAndCheckAttachment(requestAlias, undefined, false)
187212
})
188213
})
189214

190-
it('Upload images with the same name', () => {
215+
it('Upload image files with the same name', () => {
191216
// make sure we start from an emtpy file even on retries
192217
const filename = randHash() + '.md'
193218

@@ -196,14 +221,14 @@ describe('Test all image insertion methods', () => {
196221
cy.openFile(filename)
197222

198223
const assertImage = index => {
199-
return clickOnImageAction(ACTION_UPLOAD_LOCAL_FILE)
224+
return clickOnAttachmentAction(ACTION_UPLOAD_LOCAL_FILE)
200225
.then(() => {
201226
const requestAlias = `uploadRequest${index}`
202227
cy.log('Upload the file through the input', { index })
203228

204229
attachFile('github.png', requestAlias)
205230

206-
return waitForRequestAndCheckImage(requestAlias, index)
231+
return waitForRequestAndCheckAttachment(requestAlias, index)
207232
})
208233
}
209234

@@ -219,15 +244,15 @@ describe('Test all image insertion methods', () => {
219244
})
220245
})
221246

222-
it('test if image files are in the attachment folder', () => {
223-
// check we stored the image names/ids
247+
it('test if attachment files are in the attachment folder', () => {
248+
// check we stored the attachment names/ids
224249

225250
cy.get('.files-fileList tr[data-file="test.md"]', { timeout: 10000 })
226251
.should('have.attr', 'data-id')
227252
.then((documentId) => {
228253
const files = attachmentFileNameToId[documentId]
229254

230-
cy.expect(Object.keys(files)).to.have.lengthOf(2)
255+
cy.expect(Object.keys(files)).to.have.lengthOf(3)
231256
cy.openFolder('.attachments.' + documentId)
232257
cy.screenshot()
233258
for (const name in files) {
@@ -277,7 +302,7 @@ describe('Test all image insertion methods', () => {
277302
.should('exist')
278303
.should('have.attr', 'data-id')
279304
// these are new copied attachment files
280-
// so they should not have the same IDs than the ones created when uploading the images
305+
// so they should not have the same IDs than the ones created when uploading the files
281306
.should('not.eq', String(files[name]))
282307
}
283308
})
@@ -339,7 +364,7 @@ describe('Test all image insertion methods', () => {
339364
.should('exist')
340365
.should('have.attr', 'data-id')
341366
// these are new copied attachment files
342-
// so they should not have the same IDs than the ones created when uploading the images
367+
// so they should not have the same IDs than the ones created when uploading the files
343368
.should('not.eq', String(files[name]))
344369
}
345370
})

cypress/fixtures/file.txt.gz

38 Bytes
Binary file not shown.

index.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
OC = { webroot: '/OC_WEBROOT' }
1414
</script>
1515
<script type="module">
16-
import { RichTextReader, ImageResolver, IMAGE_RESOLVER } from './src/package.js'
16+
import { RichTextReader, AttachmentResolver, ATTACHMENT_RESOLVER } from './src/package.js'
1717
import Vue from 'vue'
1818
import content from './src/tests/fixtures/basic.md?raw'
1919
const app = new Vue({
@@ -25,7 +25,7 @@
2525
provide() {
2626
const val = {}
2727
Object.defineProperties(val, {
28-
[IMAGE_RESOLVER]: { get: () => this.$imageResolver },
28+
[ATTACHMENT_RESOLVER]: { get: () => this.$attachmentResolver },
2929
})
3030
return val
3131
},
@@ -47,7 +47,7 @@
4747
}),
4848
]),
4949
created() {
50-
this.$imageResolver = new ImageResolver({
50+
this.$attachmentResolver = new AttachmentResolver({
5151
currentDirectory: '/dir/',
5252
shareToken: 'SHARE_TOKEN',
5353
user: { uid: 'USER_UID' },

js/editor-rich.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/editor-rich.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/editor.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/editor.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/files-modal.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)