Skip to content

Commit

Permalink
Change quota handling (#7522)
Browse files Browse the repository at this point in the history
 Change quota handling
  • Loading branch information
AlexAndBear committed Aug 26, 2022
1 parent 73c7f40 commit de8db52
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 79 deletions.
@@ -0,0 +1,10 @@
Bugfix: Allow uploads outside of user's home despite quota being exceeded

We've fixed a bug where a user was not able to upload a file in a share or space
when the personal home quota was exceeded.
We also show a message in the upload details if an upload to a share fails because the share owner's
quota is exceeded.

https://github.com/owncloud/web/pull/7522
https://github.com/owncloud/web/issues/6318
https://github.com/owncloud/web/issues/5817
26 changes: 8 additions & 18 deletions packages/web-app-files/src/components/AppBar/CreateAndUpload.vue
Expand Up @@ -247,9 +247,6 @@ export default defineComponent({
if (!this.canUpload) {
return this.$gettext('You have no permission to create new files!')
}
if (!this.hasFreeSpace) {
return this.$gettext('You have not enough space left to create new files!')
}
return null
},
newButtonAriaLabel() {
Expand All @@ -266,9 +263,6 @@ export default defineComponent({
if (!this.canUpload) {
return this.$gettext('You have no permission to upload!')
}
if (!this.hasFreeSpace) {
return this.$gettext('You have not enough space left to upload!')
}
return null
},
uploadButtonAriaLabel() {
Expand All @@ -280,25 +274,14 @@ export default defineComponent({
},
uploadOrFileCreationBlocked() {
return !this.canUpload || !this.hasFreeSpace
return !this.canUpload
},
canUpload() {
if (!this.currentFolder) {
return false
}
return this.currentFolder.canUpload({ user: this.user })
},
hasFreeSpace() {
return (
!this.quota ||
this.quota.free > 0 ||
(this.currentFolder &&
this.currentFolder.permissions &&
this.currentFolder.permissions.indexOf('M') >= 0) ||
this.isPublicLocation
)
}
},
methods: {
Expand Down Expand Up @@ -734,6 +717,13 @@ export default defineComponent({
const uploadSizeSpaceMapping = uppyResources.reduce((acc, uppyResource) => {
let targetUploadSpace
if (
uppyResource.meta.routeName === 'files-spaces-share' ||
uppyResource.meta.routeName === 'files-public-files'
) {
return acc
}
if (uppyResource.meta.routeName === 'files-spaces-personal') {
targetUploadSpace = this.spaces.find((space) => space.driveType === 'personal')
} else {
Expand Down
123 changes: 77 additions & 46 deletions packages/web-runtime/src/components/UploadInfo.vue
Expand Up @@ -32,8 +32,8 @@
v-else
class="upload-info-label"
:class="{
'upload-info-danger': errors.length && !uploadsCancelled,
'upload-info-success': !errors.length && !uploadsCancelled
'upload-info-danger': Object.keys(errors).length && !uploadsCancelled,
'upload-info-success': !Object.keys(errors).length && !uploadsCancelled
}"
>
{{ uploadingLabel }}
Expand All @@ -46,7 +46,7 @@
v-text="infoExpanded ? $gettext('Hide details') : $gettext('Show details')"
></oc-button>
<oc-button
v-if="!runningUploads && errors.length"
v-if="!runningUploads && Object.keys(errors).length"
v-oc-tooltip="$gettext('Retry all failed uploads')"
class="oc-ml-s"
appearance="raw"
Expand Down Expand Up @@ -90,43 +90,50 @@
<li
v-for="(item, idx) in uploads"
:key="idx"
class="oc-flex oc-flex-middle"
:class="{
'oc-mb-s': idx !== Object.keys(uploads).length - 1
}"
>
<oc-icon v-if="item.status === 'error'" name="close" variation="danger" size="small" />
<oc-icon
v-else-if="item.status === 'success'"
name="check"
variation="success"
size="small"
/>
<oc-icon v-else-if="item.status === 'cancelled'" name="close" size="small" />
<oc-icon v-else-if="uploadsPaused" name="pause" size="small" />
<div v-else class="oc-flex"><oc-spinner size="small" /></div>
<oc-resource
v-if="displayFileAsResource(item)"
:key="item.path"
class="oc-ml-s"
:resource="item"
:is-path-displayed="true"
:is-thumbnail-displayed="displayThumbnails"
:is-resource-clickable="isResourceClickable(item)"
:parent-folder-name-default="defaultParentFolderName(item)"
:folder-link="folderLink(item)"
:parent-folder-link="parentFolderLink(item)"
/>
<span v-else class="oc-flex oc-flex-middle oc-text-truncate">
<oc-resource-icon :resource="item" size="large" class="file_info__icon oc-mx-s" />
<oc-resource-name
:name="item.name"
:extension="item.extension"
:type="item.type"
full-path=""
:is-path-displayed="false"
<span class="oc-flex oc-flex-middle">
<oc-icon v-if="item.status === 'error'" name="close" variation="danger" size="small" />
<oc-icon
v-else-if="item.status === 'success'"
name="check"
variation="success"
size="small"
/>
<oc-icon v-else-if="item.status === 'cancelled'" name="close" size="small" />
<oc-icon v-else-if="uploadsPaused" name="pause" size="small" />
<div v-else class="oc-flex"><oc-spinner size="small" /></div>
<oc-resource
v-if="displayFileAsResource(item)"
:key="item.path"
class="oc-ml-s"
:resource="item"
:is-path-displayed="true"
:is-thumbnail-displayed="displayThumbnails"
:is-resource-clickable="isResourceClickable(item)"
:parent-folder-name-default="defaultParentFolderName(item)"
:folder-link="folderLink(item)"
:parent-folder-link="parentFolderLink(item)"
/>
<span v-else class="oc-flex oc-flex-middle oc-text-truncate">
<oc-resource-icon :resource="item" size="large" class="file_info__icon oc-mx-s" />
<oc-resource-name
:name="item.name"
:extension="item.extension"
:type="item.type"
full-path=""
:is-path-displayed="false"
/>
</span>
</span>
<span
v-if="getUploadItemMessage(item)"
class="upload-info-message oc-ml-xs oc-text-small"
:class="getUploadItemClass(item)"
v-text="getUploadItemMessage(item)"
></span>
</li>
</ul>
</div>
Expand All @@ -148,7 +155,7 @@ export default {
showInfo: false, // show the overlay?
infoExpanded: false, // show the info including all uploads?
uploads: {}, // uploads that are being displayed via "infoExpanded"
errors: [], // all failed files
errors: {}, // all failed files
successful: [], // all successful files
filesInProgressCount: 0, // files (not folders!) that are being processed currently
totalProgress: 0, // current uploads progress (0-100)
Expand Down Expand Up @@ -179,7 +186,7 @@ export default {
if (this.uploadsCancelled) {
return this.$gettext('Upload cancelled')
}
if (this.errors.length) {
if (Object.keys(this.errors).length) {
return this.$gettext('Upload failed')
}
if (!this.runningUploads) {
Expand All @@ -188,15 +195,15 @@ export default {
return this.$gettext('Preparing upload...')
},
uploadingLabel() {
if (this.errors.length) {
const count = this.successful.length + this.errors.length
if (Object.keys(this.errors).length) {
const count = this.successful.length + Object.keys(this.errors).length
return this.$gettextInterpolate(
this.$ngettext(
'%{ errors } of %{ uploads } item failed',
'%{ errors } of %{ uploads } items failed',
count
),
{ uploads: count, errors: this.errors.length }
{ uploads: count, errors: Object.keys(this.errors).length }
)
}
return this.$gettextInterpolate(
Expand Down Expand Up @@ -290,8 +297,8 @@ export default {
this.remainingTime = this.getRemainingTime(remainingMilliseconds)
})
this.$uppyService.subscribe('uploadError', (file) => {
if (this.errors.includes(file.meta.uploadId)) {
this.$uppyService.subscribe('uploadError', ({ file, error }) => {
if (this.errors[file.meta.uploadId]) {
return
}
Expand All @@ -308,7 +315,7 @@ export default {
this.uploads[file.meta.uploadId].targetRoute = file.meta.route
this.uploads[file.meta.uploadId].status = 'error'
this.errors.push(file.meta.uploadId)
this.errors[file.meta.uploadId] = error
this.filesInProgressCount -= 1
if (file.meta.topLevelFolderId) {
Expand Down Expand Up @@ -412,7 +419,7 @@ export default {
cleanOverlay() {
this.uploadsCancelled = false
this.uploads = {}
this.errors = []
this.errors = {}
this.successful = []
this.filesInProgressCount = 0
this.runningUploads = 0
Expand Down Expand Up @@ -504,9 +511,9 @@ export default {
this.infoExpanded = !this.infoExpanded
},
retryUploads() {
this.filesInProgressCount += this.errors.length
this.filesInProgressCount += Object.keys(this.errors).length
this.runningUploads += 1
for (const fileID of this.errors) {
for (const fileID of Object.keys(this.errors)) {
this.uploads[fileID].status = undefined
const topLevelFolderId = this.uploads[fileID].meta.topLevelFolderId
Expand All @@ -515,7 +522,7 @@ export default {
this.uploads[topLevelFolderId].errorCount = 0
}
}
this.errors = []
this.errors = {}
this.$uppyService.retryAllUploads()
},
togglePauseUploads() {
Expand All @@ -541,6 +548,30 @@ export default {
for (const item of runningUploads) {
this.uploads[item.meta.uploadId].status = 'cancelled'
}
},
getUploadItemMessage(item) {
const error = this.errors[item.meta.uploadId]
if (error) {
// TODO: Remove code as soon as https://github.com/tus/tus-js-client/issues/448 is solved
let errorMessage = this.$gettext('Unknown error')
if (error.message.includes('response code: 507')) {
errorMessage = this.$gettext('Quota exceeded')
}
return errorMessage
/**
* TODO: Enable code as soon as https://github.com/tus/tus-js-client/issues/448 is solved
switch (error?.originalResponse?.getStatus()) {
case 507:
return this.$gettext('Quota exceeded')
default:
return this.$gettext('Unknown error')
}**/
}
},
getUploadItemClass(item) {
return this.errors[item.meta.uploadId] ? 'upload-info-danger' : 'upload-info-success'
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/web-runtime/src/services/uppyService.ts
Expand Up @@ -171,8 +171,8 @@ export class UppyService {
this.uppy.on('upload-success', (file) => {
this.publish('uploadSuccess', file)
})
this.uppy.on('upload-error', (file) => {
this.publish('uploadError', file)
this.uppy.on('upload-error', (file, error) => {
this.publish('uploadError', { file, error })
})
this.uppy.on('file-removed', () => {
this.publish('uploadRemoved')
Expand Down

0 comments on commit de8db52

Please sign in to comment.