Skip to content

Commit

Permalink
Merge pull request #2891 from nextcloud/feature/1129/file-upload
Browse files Browse the repository at this point in the history
File upload
  • Loading branch information
marcoambrosini authored Feb 21, 2020
2 parents 4d9ee24 + ec105b8 commit e9ce0ef
Show file tree
Hide file tree
Showing 5 changed files with 254 additions and 41 deletions.
73 changes: 73 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"hark": "^1.2.3",
"mockconsole": "0.0.1",
"nextcloud-vue-collections": "^0.7.2",
"url-parse": "^1.4.7",
"util": "^0.12.1",
"vue": "^2.6.11",
"vue-at": "^2.5.0-beta.2",
Expand All @@ -42,6 +43,7 @@
"vue-router": "^3.1.5",
"vue-shortkey": "^3.1.7",
"vuex": "^3.1.2",
"webdav": "^3.2.0",
"webrtc-adapter": "^7.4.0",
"webrtcsupport": "^2.2.0",
"wildemitter": "^1.2.1"
Expand Down
138 changes: 97 additions & 41 deletions src/components/NewMessageForm/NewMessageForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,37 @@
<template>
<div
class="wrapper">
<!--native file picker, hidden -->
<input id="file-upload"
ref="file-upload-input"
multiple
type="file"
class="hidden-visually"
@input="processFiles">
<div
class="new-message">
<form
class="new-message-form">
<div
class="new-message-form__button">
<button
v-if="!currentUserIsGuest"
class="new-message-form__button icon-clip-add-file"
@click.prevent="handleFileShare" />
<Actions
default-icon="icon-clip-add-file"
class="new-message-form__button">
<ActionButton
v-if="!currentUserIsGuest"
:close-after-click="true"
icon="icon-upload"
@click.prevent="clickImportInput">
{{ t('spreed', 'Upload new files') }}
</ActionButton>
<ActionButton
v-if="!currentUserIsGuest"
:close-after-click="true"
icon="icon-folder"
@click.prevent="handleFileShare">
{{ t('spreed', 'Share from Files') }}
</ActionButton>
</Actions>
</div>
<div class="new-message-form__input">
<Quote
Expand All @@ -54,12 +75,14 @@
</template>

<script>
import axios from '@nextcloud/axios'
import AdvancedInput from './AdvancedInput/AdvancedInput'
import { getFilePickerBuilder } from '@nextcloud/dialogs'
import { generateOcsUrl } from '@nextcloud/router'
import { getFilePickerBuilder, showError } from '@nextcloud/dialogs'
import { postNewMessage } from '../../services/messagesService'
import Quote from '../Quote'
import Actions from '@nextcloud/vue/dist/Components/Actions'
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
import client from '../../services/DavClient'
import { shareFileToRoom } from '../../services/filesSharingServices'

const picker = getFilePickerBuilder(t('spreed', 'File to share'))
.setMultiSelect(false)
Expand All @@ -73,6 +96,8 @@ export default {
components: {
AdvancedInput,
Quote,
Actions,
ActionButton,
},
data: function() {
return {
Expand Down Expand Up @@ -188,40 +213,6 @@ export default {
return 'temp-' + date.getTime()
},

async handleFileShare() {
picker.pick()
.then(async(path) => {
console.debug(`path ${path} selected for sharing`)
if (!path.startsWith('/')) {
throw new Error(t('files', 'Invalid path selected'))
}

try {
// FIXME move to service
await axios.post(
generateOcsUrl('apps/files_sharing/api/v1', 2) + 'shares',
{
shareType: 10, // OC.Share.SHARE_TYPE_ROOM,
path: path,
shareWith: this.token,
}
)
} catch (error) {
if (error.response
&& error.response.data
&& error.response.data.ocs
&& error.response.data.ocs.meta
&& error.response.data.ocs.meta.message) {
console.error(`Error while sharing file: ${error.response.data.ocs.meta.message || 'Unknown error'}`)
OCP.Toast.error(error.response.data.ocs.meta.message)
} else {
console.error(`Error while sharing file: Unknown error`)
OCP.Toast.error(t('files', 'Error while sharing file'))
}
}
})
},

/**
* Sends the new message
*/
Expand Down Expand Up @@ -251,6 +242,71 @@ export default {

}
},

/**
* Appends a file as a message to the messagelist.
* @param {string} path The file path from the user's root directory
* e.g. `/myfile.txt`
*/
async sendFile(path) {
try {
await shareFileToRoom(path, this.token)
} catch (error) {
if (error.response
&& error.response.data
&& error.response.data.ocs
&& error.response.data.ocs.meta
&& error.response.data.ocs.meta.message) {
console.error(`Error while sharing file: ${error.response.data.ocs.meta.message || 'Unknown error'}`)
OCP.Toast.error(error.response.data.ocs.meta.message)
} else {
console.error(`Error while sharing file: Unknown error`)
OCP.Toast.error(t('files', 'Error while sharing file'))
}
}
},

async handleFileShare() {
picker.pick()
.then(async(path) => {
console.debug(`path ${path} selected for sharing`)
if (!path.startsWith('/')) {
throw new Error(t('files', 'Invalid path selected'))
}
this.sendFile(path)
})
},

/**
* Clicks the hidden file input when clicking the correspondent ActionButton,
* thus opening the file-picker
*/
clickImportInput() {
this.$refs['file-upload-input'].click()
},

/**
* Uploads the files to the root files directory
* @param {object} event the file input event object
*/
async processFiles(event) {
// The selected files array
const files = Object.values(event.target.files)
// process each file in the array
for (let i = 0; i < files.length; i++) {
const userId = this.$store.getters.getUserId()
const path = `/files/${userId}/` + files[i].name
try {
// Upload the file
await client.putFileContents(path, files[i])
// Share the file to the talk room
this.sendFile('/' + files[i].name)
} catch (exception) {
console.debug('Error while uploading file:' + exception)
showError(t('spreed', 'Error while uploading file'))
}
}
},
},
}
</script>
Expand Down
37 changes: 37 additions & 0 deletions src/services/DavClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* @copyright Copyright (c) 2020 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

import webdav from 'webdav'
import axios from '@nextcloud/axios'
import parseUrl from 'url-parse'
import { generateRemoteUrl } from '@nextcloud/router'

// force our axios
const patcher = webdav.getPatcher()
patcher.patch('request', axios)

// init webdav client on default dav endpoint
const remote = generateRemoteUrl(`dav`)
const client = webdav.createClient(remote)

export const remotePath = parseUrl(remote).pathname
export default client
Loading

0 comments on commit e9ce0ef

Please sign in to comment.