Skip to content

Commit

Permalink
Merge pull request #5653 from nextcloud/chore/refactor-attachment-glo…
Browse files Browse the repository at this point in the history
…bal-store

chore: move some attachment logic to global state
  • Loading branch information
ChristophWurst authored Jan 2, 2024
2 parents 5850583 + 07c15f7 commit 1b88d05
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 25 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
"clover"
],
"transformIgnorePatterns": [
"/node_modules/(?!(@fullcalendar|uuid)).+\\.js$"
"/node_modules/(?!(@fullcalendar|uuid|webdav)).+\\.js$"
],
"setupFilesAfterEnv": [
"./tests/javascript/jest.setup.js",
Expand Down
20 changes: 4 additions & 16 deletions src/components/Editor/Attachments/AttachmentsList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,6 @@ import {
NcActionButton,
} from '@nextcloud/vue'
import {
mapState,
} from 'vuex'
import Upload from 'vue-material-design-icons/Upload.vue'
import Close from 'vue-material-design-icons/Close.vue'
import Folder from 'vue-material-design-icons/Folder.vue'
Expand All @@ -81,7 +77,6 @@ import logger from '../../../utils/logger.js'
import {
uploadLocalAttachment,
getFileInfo,
createFolder,
} from '../../../services/attachmentService.js'
import { parseXML } from 'webdav'
Expand Down Expand Up @@ -110,7 +105,6 @@ export default {
data() {
return {
uploading: false,
folderCreated: false,
}
},
computed: {
Expand All @@ -120,9 +114,6 @@ export default {
attachments() {
return this.calendarObjectInstance.attachments
},
...mapState({
attachmentsFolder: state => state.settings.attachmentsFolder,
}),
},
methods: {
addAttachmentWithProperty(calendarObjectInstance, sharedData) {
Expand All @@ -143,7 +134,7 @@ export default {
const filename = await picker.pick(t('calendar', 'Choose a file to share as a link'))
if (!this.isDuplicateAttachment(filename)) {
// TODO do not share Move this to PHP
const data = await getFileInfo(filename, this.currentUser.dav)
const data = await getFileInfo(filename, this.currentUser.dav.userId)
const davRes = await parseXML(data)
const davRespObj = davRes?.multistatus?.response[0]?.propstat?.prop
davRespObj.fileName = filename
Expand All @@ -169,15 +160,12 @@ export default {
this.$refs.localAttachments.click()
},
async onLocalAttachmentSelected(e) {
if (!this.folderCreated) {
await createFolder(this.attachmentsFolder, this.currentUser.userId)
this.folderCreated = true
}
try {
const attachments = await uploadLocalAttachment(this.attachmentsFolder, Array.from(e.target.files), this.currentUser.dav, this.attachments)
const attachmentsFolder = await this.$store.dispatch('createAttachmentsFolder')
const attachments = await uploadLocalAttachment(attachmentsFolder, Array.from(e.target.files), this.currentUser.dav, this.attachments)
// TODO do not share file, move to PHP
attachments.map(async attachment => {
const data = await getFileInfo(`${this.attachmentsFolder}/${attachment.path}`, this.currentUser.dav)
const data = await getFileInfo(`${attachmentsFolder}/${attachment.path}`, this.currentUser.dav.userId)
const davRes = await parseXML(data)
const davRespObj = davRes?.multistatus?.response[0]?.propstat?.prop
davRespObj.fileName = attachment.path
Expand Down
47 changes: 39 additions & 8 deletions src/services/attachmentService.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* @copyright 2022 Mikhail Sazanov <[email protected]>
*
* @author 2022 Mikhail Sazanov <[email protected]>
* @author Richard Steinmetz <[email protected]>
*
* @license AGPL-3.0-or-later
*
Expand All @@ -24,6 +25,7 @@ import axios from '@nextcloud/axios'
import { generateOcsUrl, generateRemoteUrl } from '@nextcloud/router'
import { showError, showSuccess } from '@nextcloud/dialogs'
import { translate as t } from '@nextcloud/l10n'
import { parseXML } from 'webdav'

/**
* Makes a share link for a given file or directory.
Expand Down Expand Up @@ -85,16 +87,44 @@ const shareFileWith = async function(path, sharedWith, permissions = 17) {

const createFolder = async function(folderName, userId) {
const url = generateRemoteUrl(`dav/files/${userId}/${folderName}`)
await axios({
method: 'MKCOL',
url,
}).catch(e => {
if (e.response.status !== 405) {
try {
await axios({
method: 'MKCOL',
url,
})
} catch (e) {
if (e?.response?.status !== 405) {
showError(t('calendar', 'Error creating a folder {folder}', {
folder: folderName,
}))
// Maybe the actual upload succeeds -> keep going
return folderName
}
})

// Folder already exists
if (folderName !== '/') {
folderName = await findFirstOwnedFolder(folderName, userId)
}
}

return folderName
}

const findFirstOwnedFolder = async function(path, userId) {
const infoXml = await getFileInfo(path, userId)
const info = await parseXML(infoXml)
const mountType = info?.multistatus?.response[0]?.propstat?.prop?.['mount-type']
if (mountType !== 'shared') {
return path
}

const hierarchy = path.split('/')
hierarchy.pop()
if (hierarchy.length === 1) {
return '/'
}

return findFirstOwnedFolder(hierarchy.join('/'), userId)
}

const uploadLocalAttachment = async function(folder, files, dav, componentAttachments) {
Expand Down Expand Up @@ -139,8 +169,8 @@ const uploadLocalAttachment = async function(folder, files, dav, componentAttach
}

// TODO is shared or not @share-types@
const getFileInfo = async function(path, dav) {
const url = generateRemoteUrl(`dav/files/${dav.userId}/${path}`)
const getFileInfo = async function(path, userId) {
const url = generateRemoteUrl(`dav/files/${userId}/${path}`)
const res = await axios({
method: 'PROPFIND',
url,
Expand All @@ -155,6 +185,7 @@ const getFileInfo = async function(path, dav) {
<oc:fileid />
<oc:share-types />
<nc:has-preview />
<nc:mount-type />
</d:prop>
</d:propfind>`,
}).catch(() => {
Expand Down
39 changes: 39 additions & 0 deletions src/store/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* @copyright Copyright (c) 2022 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/
*
* @author Georg Ehrke <[email protected]>
* @author Richard Steinmetz <[email protected]>
*
* @license AGPL-3.0-or-later
*
Expand All @@ -27,6 +28,7 @@ import { setConfig as setCalendarJsConfig } from '@nextcloud/calendar-js'
import { setConfig } from '../services/settings.js'
import { logInfo } from '../utils/logger.js'
import getTimezoneManager from '../services/timezoneDataProviderService.js'
import * as AttachmentService from '../services/attachmentService.js'

const state = {
// env
Expand All @@ -52,6 +54,7 @@ const state = {
// user-defined Nextcloud settings
momentLocale: 'en',
attachmentsFolder: '/Calendar',
attachmentsFolderCreated: false,
}

const mutations = {
Expand Down Expand Up @@ -143,6 +146,18 @@ const mutations = {
*/
setAttachmentsFolder(state, { attachmentsFolder }) {
state.attachmentsFolder = attachmentsFolder
state.attachmentsFolderCreated = false
},

/**
* Update wheter the user's attachments folder has been created
*
* @param {object} state The Vuex state
* @param {object} data The destructuring object
* @param {boolean} data.attachmentsFolderCreated True if the folder has been created
*/
setAttachmentsFolderCreated(state, { attachmentsFolderCreated }) {
state.attachmentsFolderCreated = attachmentsFolderCreated
},

/**
Expand Down Expand Up @@ -454,6 +469,30 @@ const actions = {
commit('setAttachmentsFolder', { attachmentsFolder })
},

/**
* Create the user's attachment folder if it doesn't exist and return its path
*
* @param {object} vuex The Vuex destructuring object
* @param {object} vuex.state The Vuex state
* @param {Function} vuex.commit The Vuex commit Function
* @param {Function} vuex.dispatch The Vuex commit function
* @param {object} vuex.getters The Vuex getters object
* @return {Promise<string>} The path of the user's attachments folder
*/
async createAttachmentsFolder({ state, commit, dispatch, getters }) {
if (state.attachmentsFolderCreated) {
return state.attachmentsFolder
}

const userId = getters.getCurrentUserPrincipal.dav.userId
const path = await AttachmentService.createFolder(state.attachmentsFolder, userId)
if (path !== state.attachmentsFolder) {
await dispatch('setAttachmentsFolder', { attachmentsFolder: path })
}
commit('setAttachmentsFolderCreated', { attachmentsFolderCreated: true })
return path
},

/**
* Initializes the calendar-js configuration
*
Expand Down
3 changes: 3 additions & 0 deletions tests/javascript/jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ import 'core-js/stable';
import 'regenerator-runtime/runtime';

document.title = 'Standard Nextcloud title'

// The webdav client requires a public fetch function
window.fetch = () => {}
1 change: 1 addition & 0 deletions tests/javascript/unit/store/settings.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ describe('store/settings test suite', () => {
disableAppointments: false,
canSubscribeLink: true,
attachmentsFolder: '/Calendar',
attachmentsFolderCreated: false,
showResources: true,
publicCalendars: null,
})
Expand Down

0 comments on commit 1b88d05

Please sign in to comment.