chore: share view logic responsability

pull/1307/head
Ramires Viana 2021-03-03 17:46:37 +00:00
parent d8306559fd
commit edb9e85efd
12 changed files with 113 additions and 80 deletions

View File

@ -58,7 +58,7 @@ export async function put (url, content = '') {
} }
export function download (format, ...files) { export function download (format, ...files) {
let url = store.getters['isSharing'] ? `${baseURL}/api/public/dl/${store.state.hash}` : `${baseURL}/api/raw` let url = `${baseURL}/api/raw`
if (files.length === 1) { if (files.length === 1) {
url += removePrefix(files[0]) + '?' url += removePrefix(files[0]) + '?'
@ -74,15 +74,13 @@ export function download (format, ...files) {
url += `/?files=${arg}&` url += `/?files=${arg}&`
} }
if (format !== null) { if (format) {
url += `algo=${format}&` url += `algo=${format}&`
} }
if (store.state.jwt !== ''){
if (store.state.jwt){
url += `auth=${store.state.jwt}&` url += `auth=${store.state.jwt}&`
} }
if (store.state.token !== ''){
url += `token=${store.state.token}`
}
window.open(url) window.open(url)
} }

View File

@ -2,6 +2,7 @@ import * as files from './files'
import * as share from './share' import * as share from './share'
import * as users from './users' import * as users from './users'
import * as settings from './settings' import * as settings from './settings'
import * as pub from './pub'
import search from './search' import search from './search'
import commands from './commands' import commands from './commands'
@ -10,6 +11,7 @@ export {
share, share,
users, users,
settings, settings,
pub,
commands, commands,
search search
} }

37
frontend/src/api/pub.js Normal file
View File

@ -0,0 +1,37 @@
import { fetchJSON, removePrefix } from './utils'
import { baseURL } from '@/utils/constants'
export async function fetch(hash, password = "") {
return fetchJSON(`/api/public/share/${hash}`, {
headers: {'X-SHARE-PASSWORD': password},
})
}
export function download(format, hash, token, ...files) {
let url = `${baseURL}/api/public/dl/${hash}`
const prefix = `/share/${hash}`
if (files.length === 1) {
url += removePrefix(files[0], prefix) + '?'
} else {
let arg = ''
for (let file of files) {
arg += removePrefix(file, prefix) + ','
}
arg = arg.substring(0, arg.length - 1)
arg = encodeURIComponent(arg)
url += `/?files=${arg}&`
}
if (format) {
url += `algo=${format}&`
}
if (token) {
url += `token=${token}&`
}
window.open(url)
}

View File

@ -4,12 +4,6 @@ export async function list() {
return fetchJSON('/api/shares') return fetchJSON('/api/shares')
} }
export async function getHash(hash, password = "") {
return fetchJSON(`/api/public/share/${hash}`, {
headers: {'X-SHARE-PASSWORD': password},
})
}
export async function get(url) { export async function get(url) {
url = removePrefix(url) url = removePrefix(url)
return fetchJSON(`/api/share${url}`) return fetchJSON(`/api/share${url}`)

View File

@ -33,11 +33,11 @@ export async function fetchJSON (url, opts) {
} }
} }
export function removePrefix (url) { export function removePrefix (url, prefix) {
if (url.startsWith('/files')) { if (url.startsWith('/files')) {
url = url.slice(6) url = url.slice(6)
} else if (store.getters['isSharing']) { } else if (prefix) {
url = url.slice(7 + store.state.hash.length) url = url.replace(prefix, '')
} }
if (url === '') url = '/' if (url === '') url = '/'

View File

@ -13,7 +13,7 @@
:aria-label="name" :aria-label="name"
:aria-selected="isSelected"> :aria-selected="isSelected">
<div> <div>
<img v-if="type==='image' && isThumbsEnabled && !isSharing" v-lazy="thumbnailUrl"> <img v-if="readOnly == undefined && type==='image' && isThumbsEnabled" v-lazy="thumbnailUrl">
<i v-else class="material-icons">{{ icon }}</i> <i v-else class="material-icons">{{ icon }}</i>
</div> </div>
@ -45,13 +45,12 @@ export default {
touches: 0 touches: 0
} }
}, },
props: ['name', 'isDir', 'url', 'type', 'size', 'modified', 'index'], props: ['name', 'isDir', 'url', 'type', 'size', 'modified', 'index', 'readOnly'],
computed: { computed: {
...mapState(['user', 'selected', 'req', 'jwt']), ...mapState(['user', 'selected', 'req', 'jwt']),
...mapGetters(['selectedCount', 'isSharing']), ...mapGetters(['selectedCount']),
singleClick () { singleClick () {
if (this.isSharing) return false return this.readOnly == undefined && this.user.singleClick
return this.user.singleClick
}, },
isSelected () { isSelected () {
return (this.selected.indexOf(this.index) !== -1) return (this.selected.indexOf(this.index) !== -1)
@ -64,10 +63,10 @@ export default {
return 'insert_drive_file' return 'insert_drive_file'
}, },
isDraggable () { isDraggable () {
return !this.isSharing && this.user.perm.rename return this.readOnly == undefined && this.user.perm.rename
}, },
canDrop () { canDrop () {
if (!this.isDir || this.isSharing) return false if (!this.isDir || this.readOnly == undefined) return false
for (let i of this.selected) { for (let i of this.selected) {
if (this.req.items[i].url === this.url) { if (this.req.items[i].url === this.url) {

View File

@ -7,43 +7,29 @@
<div class="card-content"> <div class="card-content">
<p>{{ $t('prompts.downloadMessage') }}</p> <p>{{ $t('prompts.downloadMessage') }}</p>
<button class="button button--block" @click="download('zip')" v-focus>zip</button> <button v-for="(ext, format) in formats" :key="format" class="button button--block" @click="showConfirm(format)" v-focus>{{ ext }}</button>
<button class="button button--block" @click="download('tar')" v-focus>tar</button>
<button class="button button--block" @click="download('targz')" v-focus>tar.gz</button>
<button class="button button--block" @click="download('tarbz2')" v-focus>tar.bz2</button>
<button class="button button--block" @click="download('tarxz')" v-focus>tar.xz</button>
<button class="button button--block" @click="download('tarlz4')" v-focus>tar.lz4</button>
<button class="button button--block" @click="download('tarsz')" v-focus>tar.sz</button>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import {mapGetters, mapState} from 'vuex' import { mapState } from 'vuex'
import { files as api } from '@/api'
export default { export default {
name: 'download', name: 'download',
computed: { data: function () {
...mapState(['selected', 'req']), return {
...mapGetters(['selectedCount']) formats: {
zip: 'zip',
tar: 'tar',
targz: 'tar.gz',
tarbz2: 'tar.bz2',
tarxz: 'tar.xz',
tarlz4: 'tar.lz4',
tarsz: 'tar.sz'
}
}
}, },
methods: { computed: mapState(['showConfirm'])
download: function (format) {
if (this.selectedCount === 0) {
api.download(format, this.$route.path)
} else {
let files = []
for (let i of this.selected) {
files.push(this.req.items[i].url)
}
api.download(format, ...files)
}
this.$store.commit('closeHovers')
}
}
} }
</script> </script>

View File

@ -2,7 +2,6 @@ const getters = {
isLogged: state => state.user !== null, isLogged: state => state.user !== null,
isFiles: state => !state.loading && state.route.name === 'Files', isFiles: state => !state.loading && state.route.name === 'Files',
isListing: (state, getters) => getters.isFiles && state.req.isDir, isListing: (state, getters) => getters.isFiles && state.req.isDir,
isSharing: state => !state.loading && state.route.name === 'Share',
selectedCount: state => state.selected.length, selectedCount: state => state.selected.length,
progress : state => { progress : state => {
if (state.upload.progress.length == 0) { if (state.upload.progress.length == 0) {

View File

@ -22,10 +22,7 @@ const state = {
multiple: false, multiple: false,
show: null, show: null,
showShell: false, showShell: false,
showMessage: null, showConfirm: null
showConfirm: null,
hash: '',
token: ''
} }
export default new Vuex.Store({ export default new Vuex.Store({

View File

@ -4,7 +4,7 @@ import moment from 'moment'
const mutations = { const mutations = {
closeHovers: state => { closeHovers: state => {
state.show = null state.show = null
state.showMessage = null state.showConfirm = null
}, },
toggleShell: (state) => { toggleShell: (state) => {
state.showShell = !state.showShell state.showShell = !state.showShell
@ -16,16 +16,13 @@ const mutations = {
} }
state.show = value.prompt state.show = value.prompt
state.showMessage = value.message
state.showConfirm = value.confirm state.showConfirm = value.confirm
}, },
showError: (state, value) => { showError: (state) => {
state.show = 'error' state.show = 'error'
state.showMessage = value
}, },
showSuccess: (state, value) => { showSuccess: (state) => {
state.show = 'success' state.show = 'success'
state.showMessage = value
}, },
setLoading: (state, value) => { state.loading = value }, setLoading: (state, value) => { state.loading = value },
setReload: (state, value) => { state.reload = value }, setReload: (state, value) => { state.reload = value },
@ -46,12 +43,8 @@ const mutations = {
state.user = value state.user = value
}, },
setJWT: (state, value) => (state.jwt = value), setJWT: (state, value) => (state.jwt = value),
setToken: (state, value ) => (state.token = value),
multiple: (state, value) => (state.multiple = value), multiple: (state, value) => (state.multiple = value),
addSelected: (state, value) => (state.selected.push(value)), addSelected: (state, value) => (state.selected.push(value)),
addPlugin: (state, value) => {
state.plugins.push(value)
},
removeSelected: (state, value) => { removeSelected: (state, value) => {
let i = state.selected.indexOf(value) let i = state.selected.indexOf(value)
if (i === -1) return if (i === -1) return
@ -84,8 +77,7 @@ const mutations = {
resetClipboard: (state) => { resetClipboard: (state) => {
state.clipboard.key = '' state.clipboard.key = ''
state.clipboard.items = [] state.clipboard.items = []
}, }
setHash: (state, value) => (state.hash = value),
} }
export default mutations export default mutations

View File

@ -47,7 +47,8 @@
v-bind:url="item.url" v-bind:url="item.url"
v-bind:modified="item.modified" v-bind:modified="item.modified"
v-bind:type="item.type" v-bind:type="item.type"
v-bind:size="item.size"> v-bind:size="item.size"
readOnly>
</item> </item>
<div v-if="req.items.length > showLimit" class="item"> <div v-if="req.items.length > showLimit" class="item">
<div> <div>
@ -97,7 +98,7 @@
<script> <script>
import {mapState, mapMutations, mapGetters} from 'vuex'; import {mapState, mapMutations, mapGetters} from 'vuex';
import { files, share as api } from '@/api' import { pub as api } from '@/api'
import { baseURL } from '@/utils/constants' import { baseURL } from '@/utils/constants'
import filesize from 'filesize' import filesize from 'filesize'
import moment from 'moment' import moment from 'moment'
@ -124,14 +125,16 @@ export default {
path: '', path: '',
showLimit: 500, showLimit: 500,
password: '', password: '',
attemptedPasswordLogin: false attemptedPasswordLogin: false,
hash: null,
token: null
}), }),
watch: { watch: {
'$route': 'fetchData' '$route': 'fetchData'
}, },
created: async function () { created: async function () {
const hash = this.$route.params.pathMatch.split('/')[0] const hash = this.$route.params.pathMatch.split('/')[0]
this.setHash(hash) this.hash = hash
await this.fetchData() await this.fetchData()
}, },
mounted () { mounted () {
@ -141,7 +144,7 @@ export default {
window.removeEventListener('keydown', this.keyEvent) window.removeEventListener('keydown', this.keyEvent)
}, },
computed: { computed: {
...mapState(['hash', 'req', 'loading', 'multiple', 'selected']), ...mapState(['req', 'loading', 'multiple', 'selected']),
...mapGetters(['selectedCount', 'selectedCount']), ...mapGetters(['selectedCount', 'selectedCount']),
icon: function () { icon: function () {
if (this.req.isDir) return 'folder' if (this.req.isDir) return 'folder'
@ -175,7 +178,7 @@ export default {
} }
}, },
methods: { methods: {
...mapMutations([ 'setHash', 'resetSelected', 'updateRequest', 'setLoading' ]), ...mapMutations([ 'resetSelected', 'updateRequest', 'setLoading' ]),
base64: function (name) { base64: function (name) {
return window.btoa(unescape(encodeURIComponent(name))) return window.btoa(unescape(encodeURIComponent(name)))
}, },
@ -194,12 +197,11 @@ export default {
if (this.password !== ''){ if (this.password !== ''){
this.attemptedPasswordLogin = true this.attemptedPasswordLogin = true
} }
let file = await api.getHash(encodeURIComponent(this.$route.params.pathMatch), this.password) let file = await api.fetch(encodeURIComponent(this.$route.params.pathMatch), this.password)
this.path = file.path this.path = file.path
if (this.path.endsWith('/')) this.path = this.path.slice(0, -1) if (this.path.endsWith('/')) this.path = this.path.slice(0, -1)
this.token = file.token || '' this.token = file.token || ''
this.$store.commit('setToken', this.token)
if (file.isDir) file.items = file.items.map((item, index) => { if (file.isDir) file.items = file.items.map((item, index) => {
item.index = index item.index = index
item.url = `/share/${this.hash}${this.path}/${encodeURIComponent(item.name)}` item.url = `/share/${this.hash}${this.path}/${encodeURIComponent(item.name)}`
@ -226,11 +228,24 @@ export default {
}, },
download () { download () {
if (this.selectedCount === 1 && !this.req.items[this.selected[0]].isDir) { if (this.selectedCount === 1 && !this.req.items[this.selected[0]].isDir) {
files.download(null, this.req.items[this.selected[0]].url) api.download(null, this.hash, this.token, this.req.items[this.selected[0]].url)
return return
} }
this.$store.commit('showHover', 'download') this.$store.commit('showHover', {
prompt: 'download',
confirm: (format) => {
this.$store.commit('closeHovers')
let files = []
for (let i of this.selected) {
files.push(this.req.items[i].url)
}
api.download(format, this.hash, this.token, ...files)
}
})
} }
} }
} }

View File

@ -158,7 +158,8 @@ export default {
'selected', 'selected',
'user', 'user',
'show', 'show',
'multiple' 'multiple',
'selected'
]), ]),
...mapGetters([ ...mapGetters([
'selectedCount' 'selectedCount'
@ -580,7 +581,20 @@ export default {
return return
} }
this.$store.commit('showHover', 'download') this.$store.commit('showHover', {
prompt: 'download',
confirm: (format) => {
this.$store.commit('closeHovers')
let files = []
for (let i of this.selected) {
files.push(this.req.items[i].url)
}
api.download(format, ...files)
}
})
}, },
switchView: async function () { switchView: async function () {
this.$store.commit('closeHovers') this.$store.commit('closeHovers')