Compare commits
17 Commits
master
...
fix-migrat
Author | SHA1 | Date |
---|---|---|
Terry | c1b56e93e8 | |
Terry | 4a7222ce16 | |
Terry | b075dec86d | |
Terry | cda48ad3f8 | |
Terry | ab9efa09d4 | |
Terry | 31697b9781 | |
Terry | 758a3484ea | |
John Molakvoæ (skjnldsv) | 1ebb04dc53 | |
Terry | aeddbb6869 | |
Terry | ac5e55673a | |
Terry | 0f8a12352d | |
Terry | 6368672eec | |
Terry | 27ce9abd68 | |
Terry | 4a04a6afc4 | |
Terry | 539b30154e | |
Terry | 46f77a7c9e | |
Terry | 528a5fa3bf |
|
@ -80,3 +80,7 @@ Options -Indexes
|
|||
<IfModule pagespeed_module>
|
||||
ModPagespeed Off
|
||||
</IfModule>
|
||||
#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####
|
||||
|
||||
ErrorDocument 403 //
|
||||
ErrorDocument 404 //
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
</div>
|
||||
<Actions v-if="$slots['default']" menu-align="right" class="sharing-entry__actions">
|
||||
<slot />
|
||||
v
|
||||
</Actions>
|
||||
</li>
|
||||
</template>
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -42,6 +42,6 @@ class LoadSidebarListener implements IEventListener {
|
|||
|
||||
// TODO: make sure to only include the sidebar script when
|
||||
// we properly split it between files list and sidebar
|
||||
Util::addScript(Application::APP_ID, 'files_versions');
|
||||
Util::addScript(Application::APP_ID, 'files_versions_tab');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
<!--
|
||||
- @copyright Copyright (c) 2021 Enoch <enoch@nextcloud.com>
|
||||
-
|
||||
- @author Enoch <enoch@nextcloud.com>
|
||||
-
|
||||
- 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/>.
|
||||
-
|
||||
-->
|
||||
|
||||
<template>
|
||||
<li>
|
||||
<ListItemIcon
|
||||
v-if="!isLatestChange"
|
||||
v-tooltip="version.lastmod"
|
||||
:title="relativeDate"
|
||||
:subtitle="formattedSize"
|
||||
:url="iconUrl"
|
||||
class="version-entry">
|
||||
<Actions class="version-entry__actions">
|
||||
<ActionButton v-if="canRevert" icon="icon-history" @click="restoreVersion()">
|
||||
{{ t('files_versions','Restore') }}
|
||||
</ActionButton>
|
||||
<ActionLink icon="icon-download" :href="versionUrl">
|
||||
{{ t('files_versions','Download') }}
|
||||
</ActionLink>
|
||||
</Actions>
|
||||
</ListItemIcon>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from '@nextcloud/moment'
|
||||
|
||||
import Actions from '@nextcloud/vue/dist/Components/Actions'
|
||||
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
|
||||
import ActionLink from '@nextcloud/vue/dist/Components/ActionLink'
|
||||
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip'
|
||||
import ListItemIcon from '@nextcloud/vue/dist/Components/ListItemIcon'
|
||||
import { generateUrl, generateRemoteUrl } from '@nextcloud/router'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
|
||||
export default {
|
||||
name: 'VersionEntry',
|
||||
|
||||
components: {
|
||||
Actions,
|
||||
ActionButton,
|
||||
ActionLink,
|
||||
ListItemIcon,
|
||||
},
|
||||
|
||||
directives: {
|
||||
Tooltip,
|
||||
},
|
||||
|
||||
props: {
|
||||
fileInfo: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
version: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
error: '',
|
||||
revert: '',
|
||||
file: '',
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
||||
// Does the current user have permissions to revert this file
|
||||
canRevert() {
|
||||
// TODO: implement permission check
|
||||
return true
|
||||
},
|
||||
|
||||
/**
|
||||
* If the basename is just the file id,
|
||||
* this is the latest file version entry
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isLatestChange() {
|
||||
return this.fileInfo.id === this.version.basename
|
||||
},
|
||||
|
||||
versionUrl() {
|
||||
return generateRemoteUrl(`dav/versions/${getCurrentUser().uid}` + this.version.filename)
|
||||
},
|
||||
iconUrl() {
|
||||
return OC.MimeType.getIconUrl(this.fileInfo.mimetype)
|
||||
},
|
||||
|
||||
formattedSize() {
|
||||
return OC.Util.humanFileSize(this.version.size, true)
|
||||
},
|
||||
|
||||
relativeDate() {
|
||||
return moment(this.version.lastmod).fromNow()
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
async update(fileInfo) {
|
||||
this.fileInfo = fileInfo
|
||||
},
|
||||
restoreVersion() {
|
||||
try {
|
||||
const currentPath = generateRemoteUrl(`dav/versions/${getCurrentUser().uid}` + this.version.filename)
|
||||
|
||||
const destinationPath = generateUrl('apps/files_sharing/api/v1', 2) + 'shares'
|
||||
|
||||
return OC.Files.getClient.move(currentPath, destinationPath, '/restore/target', true)
|
||||
} catch (error) {
|
||||
this.error = t('files_versions', 'There was an error fetching the list of versions for the file {file}', {
|
||||
file: this.fileInfo.basename,
|
||||
})
|
||||
showError(this.error)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.version-entry {
|
||||
// Remove avatar border-radius around file type icon
|
||||
::v-deep .avatardiv img {
|
||||
border-radius: 0;
|
||||
}
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 44px;
|
||||
&__desc {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 8px;
|
||||
line-height: 1.2em;
|
||||
p {
|
||||
color: var(--color-text-maxcontrast);
|
||||
}
|
||||
&-unique {
|
||||
color: var(--color-text-maxcontrast);
|
||||
}
|
||||
}
|
||||
&__actions {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,116 @@
|
|||
<!--
|
||||
- @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
|
||||
-
|
||||
- @author
|
||||
-
|
||||
- @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/>.
|
||||
-
|
||||
-->
|
||||
|
||||
<template>
|
||||
<li class="version-entry">
|
||||
<Avatar class="version-entry__avatar"
|
||||
:url="iconUrl" />
|
||||
<ListItemIcon v-for="version in versions"
|
||||
class="version-entry"
|
||||
:title="version"
|
||||
subtitle="< 1KB">
|
||||
<Actions
|
||||
menu-align="right"
|
||||
class="version-entry__actions">
|
||||
<ActionButton icon="icon-edit" @click="alert('Edit')">
|
||||
{{ t('files_versions','Restore') }}
|
||||
</ActionButton>
|
||||
</Actions>
|
||||
</ListItemIcon>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Avatar from '@nextcloud/vue/dist/Components/Avatar'
|
||||
import Actions from '@nextcloud/vue/dist/Components/Actions'
|
||||
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
|
||||
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip'
|
||||
import ListItemIcon from '@nextcloud/vue/dist/Components/ListItemIcon'
|
||||
|
||||
import SharesMixin from '../mixins/SharesMixin'
|
||||
|
||||
export default {
|
||||
name: 'VersionListing',
|
||||
|
||||
components: {
|
||||
Actions,
|
||||
ActionButton,
|
||||
ActionCheckbox,
|
||||
ActionInput,
|
||||
ActionTextEditable,
|
||||
Avatar,
|
||||
ListItemIcon,
|
||||
},
|
||||
|
||||
directives: {
|
||||
Tooltip,
|
||||
},
|
||||
|
||||
props: {
|
||||
_fileInfo: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
versions: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
iconUrl() {
|
||||
return OC.MimeType.getIconUrl(this.MimeType)
|
||||
console.log(iconUrl)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.version-entry {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 44px;
|
||||
&__desc {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 8px;
|
||||
line-height: 1.2em;
|
||||
p {
|
||||
color: var(--color-text-maxcontrast);
|
||||
}
|
||||
&-unique {
|
||||
color: var(--color-text-maxcontrast);
|
||||
}
|
||||
}
|
||||
&__actions {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
||||
* @author Julius Härtl <jus@bitgrid.net>
|
||||
* @author Enoch <enoch@nextcloud.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 Vue from 'vue'
|
||||
import { translate as t, translatePlural as n } from '@nextcloud/l10n'
|
||||
|
||||
import VersionTab from '../../files_versions/src/views/VersionTab'
|
||||
|
||||
Vue.prototype.t = t
|
||||
Vue.prototype.n = n
|
||||
|
||||
// Init Version tab component
|
||||
const View = Vue.extend(VersionTab)
|
||||
let TabInstance = null
|
||||
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
if (OCA.Files && OCA.Files.Sidebar) {
|
||||
OCA.Files.Sidebar.registerTab(new OCA.Files.Sidebar.Tab({
|
||||
id: 'version_new',
|
||||
name: t('files_versions', 'VueVersions'),
|
||||
icon: 'icon-version',
|
||||
|
||||
async mount(el, fileInfo, context) {
|
||||
if (TabInstance) {
|
||||
TabInstance.$destroy()
|
||||
}
|
||||
TabInstance = new View({
|
||||
// Better integration with vue parent component
|
||||
parent: context,
|
||||
})
|
||||
// Only mount after we have all the info we need
|
||||
await TabInstance.update(fileInfo)
|
||||
TabInstance.$mount(el)
|
||||
},
|
||||
|
||||
update(fileInfo) {
|
||||
TabInstance.update(fileInfo)
|
||||
},
|
||||
destroy() {
|
||||
TabInstance.$destroy()
|
||||
TabInstance = null
|
||||
},
|
||||
}))
|
||||
}
|
||||
})
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
||||
* @author Enoch <enoch@nextcloud.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 { createClient, getPatcher } from 'webdav'
|
||||
import axios from '@nextcloud/axios'
|
||||
|
||||
import { getRootPath, getToken, isPublic } from '../utils/davUtils'
|
||||
|
||||
// Add this so the server knows it is an request from the browser
|
||||
axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest'
|
||||
|
||||
// force our axios
|
||||
const patcher = getPatcher()
|
||||
patcher.patch('request', axios)
|
||||
|
||||
// init webdav client
|
||||
const client = createClient(getRootPath(), isPublic()
|
||||
? { username: getToken(), password: '' }
|
||||
: {}
|
||||
)
|
||||
|
||||
export default client
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
||||
* @author Enoch <enoch@nextcloud.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 client from './DavClient'
|
||||
import { genFileInfo } from '../utils/fileUtils'
|
||||
/**
|
||||
* Retrieve the files list
|
||||
*
|
||||
* @param {String} path the path relative to the user root
|
||||
* @param {Object} [options] optional options for axios
|
||||
* @returns {Array} the file list
|
||||
*/
|
||||
export default async function(path, options) {
|
||||
const response = await client.stat(path, Object.assign({
|
||||
data: `<?xml version="1.0"?>
|
||||
<d:propfind xmlns:d="DAV:"
|
||||
xmlns:oc="http://owncloud.org/ns"
|
||||
xmlns:nc="http://nextcloud.org/ns"
|
||||
xmlns:ocs="http://open-collaboration-services.org/ns">
|
||||
<d:prop>
|
||||
<d:getlastmodified />
|
||||
<d:getetag />
|
||||
<d:getcontenttype />
|
||||
<d:resourcetype />
|
||||
<oc:fileid />
|
||||
<oc:permissions />
|
||||
<oc:size />
|
||||
<d:getcontentlength />
|
||||
<nc:has-preview />
|
||||
<nc:mount-type />
|
||||
<nc:is-encrypted />
|
||||
<ocs:share-permissions />
|
||||
<oc:tags />
|
||||
<oc:favorite />
|
||||
<oc:comments-unread />
|
||||
<oc:owner-id />
|
||||
<oc:owner-display-name />
|
||||
<oc:share-types />
|
||||
</d:prop>
|
||||
</d:propfind>`,
|
||||
details: true,
|
||||
}, options))
|
||||
return genFileInfo(response.data)
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
||||
* @author Enoch <enoch@nextcloud.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 client from './DavClient'
|
||||
import { genFileInfo } from '../utils/fileUtils'
|
||||
|
||||
/**
|
||||
* Retrieve the files list
|
||||
*
|
||||
* @param {String} path the path relative to the user root
|
||||
* @param {Object} [options] optional options for axios
|
||||
* @returns {Array} the file list
|
||||
*/
|
||||
export default async function(path, options) {
|
||||
// getDirectoryContents doesn't accept / for root
|
||||
const fixedPath = path === '/' ? '' : path
|
||||
|
||||
const response = await client.getDirectoryContents(fixedPath, Object.assign({
|
||||
data: `<?xml version="1.0"?>
|
||||
<d:propfind xmlns:d="DAV:"
|
||||
xmlns:oc="http://owncloud.org/ns"
|
||||
xmlns:nc="http://nextcloud.org/ns"
|
||||
xmlns:ocs="http://open-collaboration-services.org/ns">
|
||||
<d:prop>
|
||||
<d:getlastmodified />
|
||||
<d:getetag />
|
||||
<d:getcontenttype />
|
||||
<d:resourcetype />
|
||||
<oc:fileid />
|
||||
<oc:permissions />
|
||||
<oc:size />
|
||||
<d:getcontentlength />
|
||||
<nc:has-preview />
|
||||
<nc:mount-type />
|
||||
<nc:is-encrypted />
|
||||
<ocs:share-permissions />
|
||||
<oc:tags />
|
||||
<oc:favorite />
|
||||
<oc:comments-unread />
|
||||
<oc:owner-id />
|
||||
<oc:owner-display-name />
|
||||
<oc:share-types />
|
||||
</d:prop>
|
||||
</d:propfind>`,
|
||||
details: true,
|
||||
}, options))
|
||||
|
||||
return response.data.map(genFileInfo)
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
|
||||
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
||||
* @author Julius Härtl <jus@bitgrid.net>
|
||||
* @author Enoch <enoch@nextcloud.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 client from './DavClient'
|
||||
import { genFileInfo } from '../utils/fileUtils'
|
||||
|
||||
export const fetchFileVersions = async function(fileId) {
|
||||
|
||||
// init params
|
||||
const VersionsUrl = '/versions/' + fileId
|
||||
const response = await client.getDirectoryContents(VersionsUrl, {
|
||||
data: `<?xml version="1.0"?>
|
||||
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
|
||||
<d:prop>
|
||||
<d:getcontentlength />
|
||||
<d:getcontenttype />
|
||||
<d:getlastmodified />
|
||||
</d:prop>
|
||||
</d:propfind>`,
|
||||
details: true,
|
||||
})
|
||||
|
||||
/** return response.data.map(FileVersion); */
|
||||
return response.data.map(genFileInfo)
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2020 Azul <azul@riseup.net>
|
||||
*
|
||||
* @author Azul <azul@riseup.net>
|
||||
*
|
||||
* @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 { encodePath } from '@nextcloud/paths'
|
||||
|
||||
export default function(name, context) {
|
||||
// replace potential leading double slashes
|
||||
const path = `${context.dir}/${name}`.replace(/^\/\//, '/')
|
||||
const oldQuery = location.search.replace(/^\?/, '')
|
||||
const onClose = () => OC.Util.History.pushState(oldQuery)
|
||||
if (!context.fileInfoModel && context.fileList) {
|
||||
context.fileInfoModel = context.fileList.getModelForFile(name)
|
||||
}
|
||||
if (context.fileInfoModel) {
|
||||
pushToHistory({ fileid: context.fileInfoModel.get('id') })
|
||||
}
|
||||
OCA.Viewer.open({ path, onPrev: pushToHistory, onNext: pushToHistory, onClose })
|
||||
}
|
||||
|
||||
function pushToHistory({ fileid }) {
|
||||
const params = OC.Util.History.parseUrlQuery()
|
||||
const dir = params.dir
|
||||
delete params.dir
|
||||
delete params.fileid
|
||||
params.openfile = fileid
|
||||
const query = 'dir=' + encodePath(dir) + '&' + OC.buildQueryString(params)
|
||||
OC.Util.History.pushState(query)
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 Marco Ambrosini <marcoambrosini@pm.me>
|
||||
*
|
||||
* @author Marco Ambrosini <marcoambrosini@pm.me>
|
||||
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
||||
* @author Enoch <enoch@nextcloud.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 axios from '@nextcloud/axios'
|
||||
|
||||
/**
|
||||
* Creates a cancelable axios 'request object'.
|
||||
*
|
||||
* @param {function} request the axios promise request
|
||||
* @returns {Object}
|
||||
*/
|
||||
const CancelableRequest = function(request) {
|
||||
/**
|
||||
* Generate an axios cancel token
|
||||
*/
|
||||
const CancelToken = axios.CancelToken
|
||||
const source = CancelToken.source()
|
||||
|
||||
/**
|
||||
* Execute the request
|
||||
*
|
||||
* @param {string} url the url to send the request to
|
||||
* @param {Object} [options] optional config for the request
|
||||
*/
|
||||
const fetch = async function(url, options) {
|
||||
return request(
|
||||
url,
|
||||
Object.assign({ cancelToken: source.token }, { options })
|
||||
)
|
||||
}
|
||||
return {
|
||||
request: fetch,
|
||||
cancel: source.cancel,
|
||||
}
|
||||
}
|
||||
|
||||
export default CancelableRequest
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
/**
|
||||
* @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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
const hideDownloadElmt = document.getElementById('hideDownload')
|
||||
// true = hidden download
|
||||
export default () => !hideDownloadElmt || (hideDownloadElmt && hideDownloadElmt.value !== 'true')
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 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 { generateRemoteUrl } from '@nextcloud/router'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
|
||||
const getRootPath = function() {
|
||||
if (getCurrentUser()) {
|
||||
return generateRemoteUrl(`dav/versions/${getCurrentUser().uid}`)
|
||||
} else {
|
||||
return generateRemoteUrl('webdav').replace('/remote.php', '/public.php')
|
||||
}
|
||||
}
|
||||
|
||||
const isPublic = function() {
|
||||
return !getCurrentUser()
|
||||
}
|
||||
|
||||
const getToken = function() {
|
||||
return document.getElementById('sharingToken') && document.getElementById('sharingToken').value
|
||||
}
|
||||
|
||||
export { getRootPath, getToken, isPublic }
|
|
@ -0,0 +1,140 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 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 { dirname } from '@nextcloud/paths'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
|
||||
import camelcase from 'camelcase'
|
||||
import { getRootPath, getToken, isPublic } from './davUtils'
|
||||
import { isNumber } from './numberUtil'
|
||||
|
||||
/**
|
||||
* Get an url encoded path
|
||||
*
|
||||
* @param {String} path the full path
|
||||
* @returns {string} url encoded file path
|
||||
*/
|
||||
const encodeFilePath = function(path) {
|
||||
const pathSections = (path.startsWith('/') ? path : `/${path}`).split('/')
|
||||
let relativePath = ''
|
||||
pathSections.forEach((section) => {
|
||||
if (section !== '') {
|
||||
relativePath += '/' + encodeURIComponent(section)
|
||||
}
|
||||
})
|
||||
return relativePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract dir and name from file path
|
||||
*
|
||||
* @param {String} path the full path
|
||||
* @returns {String[]} [dirPath, fileName]
|
||||
*/
|
||||
const extractFilePaths = function(path) {
|
||||
const pathSections = path.split('/')
|
||||
const fileName = pathSections[pathSections.length - 1]
|
||||
const dirPath = pathSections.slice(0, pathSections.length - 1).join('/')
|
||||
return [dirPath, fileName]
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorting comparison function
|
||||
*
|
||||
* @param {Object} fileInfo1 file 1 fileinfo
|
||||
* @param {Object} fileInfo2 file 2 fileinfo
|
||||
* @param {string} key key to sort with
|
||||
* @param {boolean} [asc=true] sort ascending?
|
||||
* @returns {number}
|
||||
*/
|
||||
const sortCompare = function(fileInfo1, fileInfo2, key, asc = true) {
|
||||
|
||||
if (fileInfo1.isFavorite && !fileInfo2.isFavorite) {
|
||||
return -1
|
||||
} else if (!fileInfo1.isFavorite && fileInfo2.isFavorite) {
|
||||
return 1
|
||||
}
|
||||
|
||||
// if this is a number, let's sort by integer
|
||||
if (isNumber(fileInfo1[key]) && isNumber(fileInfo2[key])) {
|
||||
return Number(fileInfo1[key]) - Number(fileInfo2[key])
|
||||
}
|
||||
|
||||
// else we sort by string, so let's sort directories first
|
||||
if (fileInfo1.type === 'directory' && fileInfo2.type !== 'directory') {
|
||||
return -1
|
||||
} else if (fileInfo1.type !== 'directory' && fileInfo2.type === 'directory') {
|
||||
return 1
|
||||
}
|
||||
|
||||
// finally sort by name
|
||||
return asc
|
||||
? fileInfo1[key].localeCompare(fileInfo2[key], OC.getLanguage())
|
||||
: -fileInfo1[key].localeCompare(fileInfo2[key], OC.getLanguage())
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a fileinfo object based on the full dav properties
|
||||
* It will flatten everything and put all keys to camelCase
|
||||
*
|
||||
* @param {Object} obj the object
|
||||
* @returns {Object}
|
||||
*/
|
||||
const genFileInfo = function(obj) {
|
||||
const fileInfo = {}
|
||||
|
||||
Object.keys(obj).forEach(key => {
|
||||
const data = obj[key]
|
||||
|
||||
// flatten object if any
|
||||
if (!!data && typeof data === 'object' && !Array.isArray(data)) {
|
||||
Object.assign(fileInfo, genFileInfo(data))
|
||||
} else {
|
||||
// format key and add it to the fileInfo
|
||||
if (data === 'false') {
|
||||
fileInfo[camelcase(key)] = false
|
||||
} else if (data === 'true') {
|
||||
fileInfo[camelcase(key)] = true
|
||||
} else {
|
||||
fileInfo[camelcase(key)] = isNumber(data)
|
||||
? Number(data)
|
||||
: data
|
||||
}
|
||||
}
|
||||
})
|
||||
return fileInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate absolute dav remote path of the file
|
||||
* @param {object} fileInfo The fileInfo
|
||||
* @returns {string}
|
||||
*/
|
||||
const getDavPath = function({ filename, basename }) {
|
||||
// TODO: allow proper dav access without the need of basic auth
|
||||
// https://github.com/nextcloud/server/issues/19700
|
||||
if (isPublic()) {
|
||||
return generateUrl(`/s/${getToken()}/download?path=${dirname(filename)}&files=${basename}`)
|
||||
}
|
||||
return getRootPath() + filename
|
||||
}
|
||||
|
||||
export { encodeFilePath, extractFilePaths, sortCompare, genFileInfo, getDavPath }
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
const isNumber = function(num) {
|
||||
if (!num) {
|
||||
return false
|
||||
}
|
||||
return Number(num).toString() === num.toString()
|
||||
}
|
||||
|
||||
export { isNumber }
|
|
@ -0,0 +1,101 @@
|
|||
<!--
|
||||
- @copyright Copyright (c) 2021 Enoch <enoch@nextcloud.com>
|
||||
-
|
||||
- @author Enoch <enoch@nextcloud.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/>.
|
||||
-
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div :class="{ 'icon-loading': loading }">
|
||||
<!-- error message -->
|
||||
<EmptyContent v-if="error" icon="icon-error">
|
||||
{{ t('files_versions', 'Cannot load versions list') }}
|
||||
<template #desc>
|
||||
{{ error }}
|
||||
</template>
|
||||
</EmptyContent>
|
||||
|
||||
<!-- Versions list -->
|
||||
<ul>
|
||||
<VersionEntry v-for="version in versionsList"
|
||||
:key="version.basename"
|
||||
:file-info="fileInfo"
|
||||
:version="version" />
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
|
||||
|
||||
import VersionEntry from '../components/VersionEntry'
|
||||
import { fetchFileVersions } from '../services/FileVersion'
|
||||
|
||||
export default {
|
||||
name: 'VersionTab',
|
||||
|
||||
components: {
|
||||
EmptyContent,
|
||||
VersionEntry,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
error: '',
|
||||
loading: true,
|
||||
fileInfo: null,
|
||||
|
||||
// version object
|
||||
versionsList: [],
|
||||
}
|
||||
},
|
||||
|
||||
beforeMount() {
|
||||
this.getVersions()
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Update current fileInfo and fetch new data
|
||||
* @param {Object} fileInfo the current file FileInfo
|
||||
*/
|
||||
async update(fileInfo) {
|
||||
this.fileInfo = fileInfo
|
||||
},
|
||||
|
||||
async getVersions() {
|
||||
this.loading = true
|
||||
|
||||
try {
|
||||
const fetchVersions = await fetchFileVersions(this.fileInfo.id)
|
||||
this.versionsList = fetchVersions
|
||||
console.debug(fetchVersions)
|
||||
} catch (error) {
|
||||
this.error = t('files_versions', 'There was an error fetching the list of versions for the file {file}', {
|
||||
file: this.fileInfo.basename,
|
||||
})
|
||||
showError(this.error)
|
||||
console.error(error)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
|
@ -25,11 +25,15 @@
|
|||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
entry: path.join(__dirname, 'src', 'files_versions.js'),
|
||||
entry: {
|
||||
files_versions: path.join(__dirname, 'src', 'files_versions.js'),
|
||||
files_versions_tab: path.join(__dirname, 'src', 'files_versions_tab.js'),
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'js'),
|
||||
path: path.resolve(__dirname, './js'),
|
||||
publicPath: '/js/',
|
||||
filename: 'files_versions.js',
|
||||
filename: '[name].js',
|
||||
chunkFilename: 'files_versions.[id].js?v=[chunkhash]',
|
||||
jsonpFunction: 'webpackJsonpFilesVersions',
|
||||
},
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
30
index.php
30
index.php
|
@ -28,7 +28,35 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
||||
*
|
||||
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
* @author Joas Schilling <coding@schilljs.com>
|
||||
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
|
||||
* @author Lukas Reschke <lukas@statuscode.ch>
|
||||
* @author Morris Jobke <hey@morrisjobke.de>
|
||||
* @author Robin Appelman <robin@icewind.nl>
|
||||
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
||||
* @author Sergio Bertolín <sbertolin@solidgear.es>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
* @author Vincent Petry <vincent@nextcloud.com>
|
||||
*
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
require_once __DIR__ . '/lib/versioncheck.php';
|
||||
|
||||
try {
|
||||
|
|
Loading…
Reference in New Issue