diff --git a/app/Http/Helpers/helpers.php b/app/Http/Helpers/helpers.php index f64ffa0b..09067f80 100644 --- a/app/Http/Helpers/helpers.php +++ b/app/Http/Helpers/helpers.php @@ -355,6 +355,25 @@ function format_gigabytes($gigabytes) } } +/** + * Format string to formated megabytes string + * + * @param $megabytes + * @return string + */ +function format_megabytes($megabytes) +{ + if ($megabytes >= 1000) { + return $megabytes / 1000 . 'GB'; + } + + if ($megabytes >= 1000000) { + return $megabytes / 1000000 . 'TB'; + } + + return $megabytes . 'MB'; +} + /** * Convert megabytes to bytes * @@ -495,6 +514,7 @@ function get_file_type($file_mimetype) } } + /** * Get file type from mimetype * @@ -529,187 +549,9 @@ function get_pretty_name($basename, $name, $mimetype) return $name . '.' . $mimetype; } -/** - * Get exif data from jpeg image - * - * @param $file - * @return array - */ function get_image_meta_data($file) { - if (get_file_type_from_mimetype($file->getMimeType()) === 'jpeg') { - return exif_read_data($file); + if(get_file_type_from_mimetype($file->getMimeType()) === 'jpeg') { + return exif_read_data($file); } } - -/** - * Check if app is in dev mode - * - * @return bool - */ -function is_dev() -{ - return env('APP_ENV') === 'local' ? true : false; -} - -/** - * @param $str - * @return bool - */ -function seems_utf8($str) -{ - $length = strlen($str); - for ($i=0; $i < $length; $i++) { - $c = ord($str[$i]); - if ($c < 0x80) $n = 0; # 0bbbbbbb - elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb - elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb - elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb - elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb - elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b - else return false; # Does not match any model - for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ? - if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80)) - return false; - } - } - return true; -} - -/** - * Converts all accent characters to ASCII characters. - * - * If there are no accent characters, then the string given is just returned. - * - * @param string $string Text that might have accent characters - * @return string Filtered string with replaced "nice" characters. - */ -function remove_accents($string) { - if ( !preg_match('/[\x80-\xff]/', $string) ) - return $string; - - if (seems_utf8($string)) { - $chars = array( - // Decompositions for Latin-1 Supplement - chr(195).chr(128) => 'A', chr(195).chr(129) => 'A', - chr(195).chr(130) => 'A', chr(195).chr(131) => 'A', - chr(195).chr(132) => 'A', chr(195).chr(133) => 'A', - chr(195).chr(135) => 'C', chr(195).chr(136) => 'E', - chr(195).chr(137) => 'E', chr(195).chr(138) => 'E', - chr(195).chr(139) => 'E', chr(195).chr(140) => 'I', - chr(195).chr(141) => 'I', chr(195).chr(142) => 'I', - chr(195).chr(143) => 'I', chr(195).chr(145) => 'N', - chr(195).chr(146) => 'O', chr(195).chr(147) => 'O', - chr(195).chr(148) => 'O', chr(195).chr(149) => 'O', - chr(195).chr(150) => 'O', chr(195).chr(153) => 'U', - chr(195).chr(154) => 'U', chr(195).chr(155) => 'U', - chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y', - chr(195).chr(159) => 's', chr(195).chr(160) => 'a', - chr(195).chr(161) => 'a', chr(195).chr(162) => 'a', - chr(195).chr(163) => 'a', chr(195).chr(164) => 'a', - chr(195).chr(165) => 'a', chr(195).chr(167) => 'c', - chr(195).chr(168) => 'e', chr(195).chr(169) => 'e', - chr(195).chr(170) => 'e', chr(195).chr(171) => 'e', - chr(195).chr(172) => 'i', chr(195).chr(173) => 'i', - chr(195).chr(174) => 'i', chr(195).chr(175) => 'i', - chr(195).chr(177) => 'n', chr(195).chr(178) => 'o', - chr(195).chr(179) => 'o', chr(195).chr(180) => 'o', - chr(195).chr(181) => 'o', chr(195).chr(182) => 'o', - chr(195).chr(182) => 'o', chr(195).chr(185) => 'u', - chr(195).chr(186) => 'u', chr(195).chr(187) => 'u', - chr(195).chr(188) => 'u', chr(195).chr(189) => 'y', - chr(195).chr(191) => 'y', - // Decompositions for Latin Extended-A - chr(196).chr(128) => 'A', chr(196).chr(129) => 'a', - chr(196).chr(130) => 'A', chr(196).chr(131) => 'a', - chr(196).chr(132) => 'A', chr(196).chr(133) => 'a', - chr(196).chr(134) => 'C', chr(196).chr(135) => 'c', - chr(196).chr(136) => 'C', chr(196).chr(137) => 'c', - chr(196).chr(138) => 'C', chr(196).chr(139) => 'c', - chr(196).chr(140) => 'C', chr(196).chr(141) => 'c', - chr(196).chr(142) => 'D', chr(196).chr(143) => 'd', - chr(196).chr(144) => 'D', chr(196).chr(145) => 'd', - chr(196).chr(146) => 'E', chr(196).chr(147) => 'e', - chr(196).chr(148) => 'E', chr(196).chr(149) => 'e', - chr(196).chr(150) => 'E', chr(196).chr(151) => 'e', - chr(196).chr(152) => 'E', chr(196).chr(153) => 'e', - chr(196).chr(154) => 'E', chr(196).chr(155) => 'e', - chr(196).chr(156) => 'G', chr(196).chr(157) => 'g', - chr(196).chr(158) => 'G', chr(196).chr(159) => 'g', - chr(196).chr(160) => 'G', chr(196).chr(161) => 'g', - chr(196).chr(162) => 'G', chr(196).chr(163) => 'g', - chr(196).chr(164) => 'H', chr(196).chr(165) => 'h', - chr(196).chr(166) => 'H', chr(196).chr(167) => 'h', - chr(196).chr(168) => 'I', chr(196).chr(169) => 'i', - chr(196).chr(170) => 'I', chr(196).chr(171) => 'i', - chr(196).chr(172) => 'I', chr(196).chr(173) => 'i', - chr(196).chr(174) => 'I', chr(196).chr(175) => 'i', - chr(196).chr(176) => 'I', chr(196).chr(177) => 'i', - chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij', - chr(196).chr(180) => 'J', chr(196).chr(181) => 'j', - chr(196).chr(182) => 'K', chr(196).chr(183) => 'k', - chr(196).chr(184) => 'k', chr(196).chr(185) => 'L', - chr(196).chr(186) => 'l', chr(196).chr(187) => 'L', - chr(196).chr(188) => 'l', chr(196).chr(189) => 'L', - chr(196).chr(190) => 'l', chr(196).chr(191) => 'L', - chr(197).chr(128) => 'l', chr(197).chr(129) => 'L', - chr(197).chr(130) => 'l', chr(197).chr(131) => 'N', - chr(197).chr(132) => 'n', chr(197).chr(133) => 'N', - chr(197).chr(134) => 'n', chr(197).chr(135) => 'N', - chr(197).chr(136) => 'n', chr(197).chr(137) => 'N', - chr(197).chr(138) => 'n', chr(197).chr(139) => 'N', - chr(197).chr(140) => 'O', chr(197).chr(141) => 'o', - chr(197).chr(142) => 'O', chr(197).chr(143) => 'o', - chr(197).chr(144) => 'O', chr(197).chr(145) => 'o', - chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe', - chr(197).chr(148) => 'R',chr(197).chr(149) => 'r', - chr(197).chr(150) => 'R',chr(197).chr(151) => 'r', - chr(197).chr(152) => 'R',chr(197).chr(153) => 'r', - chr(197).chr(154) => 'S',chr(197).chr(155) => 's', - chr(197).chr(156) => 'S',chr(197).chr(157) => 's', - chr(197).chr(158) => 'S',chr(197).chr(159) => 's', - chr(197).chr(160) => 'S', chr(197).chr(161) => 's', - chr(197).chr(162) => 'T', chr(197).chr(163) => 't', - chr(197).chr(164) => 'T', chr(197).chr(165) => 't', - chr(197).chr(166) => 'T', chr(197).chr(167) => 't', - chr(197).chr(168) => 'U', chr(197).chr(169) => 'u', - chr(197).chr(170) => 'U', chr(197).chr(171) => 'u', - chr(197).chr(172) => 'U', chr(197).chr(173) => 'u', - chr(197).chr(174) => 'U', chr(197).chr(175) => 'u', - chr(197).chr(176) => 'U', chr(197).chr(177) => 'u', - chr(197).chr(178) => 'U', chr(197).chr(179) => 'u', - chr(197).chr(180) => 'W', chr(197).chr(181) => 'w', - chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y', - chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z', - chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z', - chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z', - chr(197).chr(190) => 'z', chr(197).chr(191) => 's', - // Euro Sign - chr(226).chr(130).chr(172) => 'E', - // GBP (Pound) Sign - chr(194).chr(163) => ''); - - $string = strtr($string, $chars); - } else { - // Assume ISO-8859-1 if not UTF-8 - $chars['in'] = chr(128).chr(131).chr(138).chr(142).chr(154).chr(158) - .chr(159).chr(162).chr(165).chr(181).chr(192).chr(193).chr(194) - .chr(195).chr(196).chr(197).chr(199).chr(200).chr(201).chr(202) - .chr(203).chr(204).chr(205).chr(206).chr(207).chr(209).chr(210) - .chr(211).chr(212).chr(213).chr(214).chr(216).chr(217).chr(218) - .chr(219).chr(220).chr(221).chr(224).chr(225).chr(226).chr(227) - .chr(228).chr(229).chr(231).chr(232).chr(233).chr(234).chr(235) - .chr(236).chr(237).chr(238).chr(239).chr(241).chr(242).chr(243) - .chr(244).chr(245).chr(246).chr(248).chr(249).chr(250).chr(251) - .chr(252).chr(253).chr(255); - - $chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy"; - - $string = strtr($string, $chars['in'], $chars['out']); - $double_chars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254)); - $double_chars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th'); - $string = str_replace($double_chars['in'], $double_chars['out'], $string); - } - - return $string; -} diff --git a/app/Http/Tools/Editor.php b/app/Http/Tools/Editor.php index 5c513cab..28508b34 100644 --- a/app/Http/Tools/Editor.php +++ b/app/Http/Tools/Editor.php @@ -328,9 +328,21 @@ class Editor $disk_file_name = basename('chunks/' . $file->getClientOriginalName(), '.part'); $temp_filename = $file->getClientOriginalName(); - // Generate file - File::append(config('filesystems.disks.local.root') . '/chunks/' . $temp_filename, $file->get()); + // File Path + $file_path = config('filesystems.disks.local.root') . '/chunks/' . $temp_filename;\ + // Generate file + File::append($file_path, $file->get()); + + // Size of file + $file_size = File::size($file_path); + + // Size of limit + $limit = get_setting('upload_limit'); + + // File size handling + if( $limit && $file_size > format_bytes($limit)) abort(413); + // If last then process file if ($request->boolean('is_last')) { diff --git a/resources/js/components/FilesView/FileItemGrid.vue b/resources/js/components/FilesView/FileItemGrid.vue index 19368ad8..94a9b5db 100644 --- a/resources/js/components/FilesView/FileItemGrid.vue +++ b/resources/js/components/FilesView/FileItemGrid.vue @@ -15,15 +15,15 @@ - + {{ data.mimetype }} - + - + diff --git a/resources/js/components/FilesView/FileItemList.vue b/resources/js/components/FilesView/FileItemList.vue index 95ca10fd..65585a03 100644 --- a/resources/js/components/FilesView/FileItemList.vue +++ b/resources/js/components/FilesView/FileItemList.vue @@ -1,283 +1,222 @@ @@ -285,322 +224,231 @@ export default { @import '@assets/vue-file-manager/_variables'; @import '@assets/vue-file-manager/_mixins'; -.slide-from-left-move { - transition: transform 300s ease; -} - -.slide-from-left-enter-active, -.slide-from-right-enter-active, -.slide-from-left-leave-active, -.slide-from-right-leave-active { - transition: all 300ms; -} - -.slide-from-left-enter, -.slide-from-left-leave-to { - opacity: 0; - transform: translateX(-100%); -} - -.slide-from-right-enter, -.slide-from-right-leave-to { - opacity: 0; - transform: translateX(100%); -} - - -.check-select { - margin-right: 15px; - margin-left: 6px; - - .select-box { - width: 20px; - height: 20px; - background-color: darken($light_background, 5%); - display: flex; - justify-content: center; - align-items: center; - border-radius: 5px; - } - - .select-box-active { - background-color: #f4f5f6; - - .icon { - stroke: $text; - } - } -} - .file-wrapper { - user-select: none; - position: relative; + user-select: none; + position: relative; - &:hover { - border-color: transparent; - } + &:hover { + border-color: transparent; + } - .actions { - text-align: right; - width: 50px; + .actions { + text-align: right; + width: 50px; - .show-actions { - cursor: pointer; - padding: 12px 6px 12px; + .show-actions { + cursor: pointer; + padding: 12px 6px 12px; - .icon-action { - @include font-size(14); + .icon-action { + @include font-size(14); - path { - fill: $theme; - } - } - } - } + path { + fill: $theme; + } + } + } + } - .item-name { - display: block; - width: 100%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + .item-name { + display: block; + width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; - .item-info { - display: block; - line-height: 1; - } + .item-info { + display: block; + line-height: 1; + } - .item-shared { - display: inline-block; + .item-shared { + display: inline-block; - .label { - @include font-size(12); - font-weight: 400; - color: $theme; - } + .label { + @include font-size(12); + font-weight: 400; + color: $theme; + } - .shared-icon { - vertical-align: middle; + .shared-icon { + vertical-align: middle; - path, - circle, - line { - stroke: $theme; - } - } - } + path, + circle, + line { + stroke: $theme; + } + } + } - .item-size, - .item-length { - @include font-size(11); - font-weight: 400; - color: rgba($text, 0.7); - } + .item-size, + .item-length { + @include font-size(11); + font-weight: 400; + color: rgba($text, 0.7); + } - .name { - white-space: nowrap; + .name { + white-space: nowrap; - &[contenteditable] { - -webkit-user-select: text; - user-select: text; - } + &[contenteditable] { + -webkit-user-select: text; + user-select: text; + } - &[contenteditable='true']:hover { - text-decoration: underline; - } - } + &[contenteditable='true']:hover { + text-decoration: underline; + } + } - .name { - color: $text; - @include font-size(14); - font-weight: 700; - max-height: 40px; - overflow: hidden; - text-overflow: ellipsis; + .name { + color: $text; + @include font-size(14); + font-weight: 700; + max-height: 40px; + overflow: hidden; + text-overflow: ellipsis; - &.actived { - max-height: initial; - } - } - } + &.actived { + max-height: initial; + } + } + } - &.selected { - .file-item { - background: $light_background; - } - } + &.selected { + .file-item { + background: $light_background; + } + } - .icon-item { - text-align: center; - position: relative; - flex: 0 0 50px; - line-height: 0; - margin-right: 20px; + .icon-item { + text-align: center; + position: relative; + flex: 0 0 50px; + line-height: 0; + margin-right: 20px; - .folder-icon { - @include font-size(52); + .folder-icon { + @include font-size(52); - path { - fill: $theme; - } + path { + fill: $theme; + } - &.is-deleted { - path { - fill: $dark_background; - } - } - } + &.is-deleted { + path { + fill: $dark_background; + } + } + } - .file-icon { - @include font-size(45); + .file-icon { + @include font-size(45); - path { - fill: #fafafc; - stroke: #dfe0e8; - stroke-width: 1; - } - } + path { + fill: #fafafc; + stroke: #dfe0e8; + stroke-width: 1; + } + } - .file-icon-text { - line-height: 1; - top: 40%; - @include font-size(11); - margin: 0 auto; - position: absolute; - text-align: center; - left: 0; - right: 0; - color: $theme; - font-weight: 600; - user-select: none; - max-width: 50px; - max-height: 20px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } + .file-icon-text { + line-height: 1; + top: 40%; + @include font-size(11); + margin: 0 auto; + position: absolute; + text-align: center; + left: 0; + right: 0; + color: $theme; + font-weight: 600; + user-select: none; + max-width: 50px; + max-height: 20px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } - .image { - object-fit: cover; - user-select: none; - max-width: 100%; - border-radius: 5px; - width: 50px; - height: 50px; - pointer-events: none; - } - } + .image { + object-fit: cover; + user-select: none; + max-width: 100%; + border-radius: 5px; + width: 50px; + height: 50px; + pointer-events: none; + } + } - .file-item { - border: 2px dashed transparent; - width: 100%; - display: flex; - align-items: center; - padding: 7px; + .file-item { + border: 2px dashed transparent; + width: 100%; + display: flex; + align-items: center; + padding: 7px; - &.is-dragenter { - border: 2px dashed $theme; - border-radius: 8px; - } + &.is-dragenter { + border: 2px dashed $theme; + border-radius: 8px; + } - &.no-clicked { - background: white !important; + &:hover, + &.is-clicked { + border-radius: 8px; + background: $light_background; - .item-name { - .name { - color: $text !important; - } - } - } - - &:hover, - &.is-clicked { - border-radius: 8px; - background: $light_background; - } - } + .item-name .name { + color: $theme; + } + } + } } @media (prefers-color-scheme: dark) { - .check-select { + .file-wrapper { + .icon-item { + .file-icon { + path { + fill: $dark_mode_foreground; + stroke: #2f3c54; + } + } - .select-box { - background-color: lighten($dark_mode_foreground, 10%); - } + .folder-icon { + &.is-deleted { + path { + fill: lighten($dark_mode_foreground, 5%); + } + } + } + } - .select-box-active { - background-color: lighten($dark_mode_foreground, 10%); + .file-item { + &:hover, + &.is-clicked { + background: $dark_mode_foreground; - .icon { - stroke: $theme; - } - } - } + .file-icon { + path { + fill: $dark_mode_background; + } + } + } + } - .file-wrapper { - .icon-item { - .file-icon { - path { - fill: $dark_mode_foreground; - stroke: #2f3c54; - } - } + .item-name { + .name { + color: $dark_mode_text_primary; + } - .folder-icon { - &.is-deleted { - path { - fill: lighten($dark_mode_foreground, 5%); - } - } - } - } - - .file-item { - &.no-clicked { - background: $dark_mode_background !important; - - .file-icon { - - path { - fill: $dark_mode_foreground !important; - stroke: #2F3C54; - } - } - - .item-name { - - .name { - color: $dark_mode_text_primary !important; - } - } - } - - &:hover, - &.is-clicked { - background: $dark_mode_foreground; - - .item-name .name { - color: $theme; - } - - .file-icon { - path { - fill: $dark_mode_background; - } - } - } - } - - .item-name { - .name { - color: $dark_mode_text_primary; - } - - .item-size, - .item-length { - color: $dark_mode_text_secondary; - } - } - } + .item-size, + .item-length { + color: $dark_mode_text_secondary; + } + } + } } \ No newline at end of file diff --git a/resources/js/components/FilesView/FilePreview.vue b/resources/js/components/FilesView/FilePreview.vue index deba87bd..76b792e6 100644 --- a/resources/js/components/FilesView/FilePreview.vue +++ b/resources/js/components/FilesView/FilePreview.vue @@ -1,9 +1,9 @@ @@ -17,9 +17,9 @@ computed: { ...mapGetters(['fileInfoDetail']), canBePreview() { - return this.fileInfoDetail[0] && ! includes([ + return this.fileInfoDetail && ! includes([ 'folder', 'file' - ], this.fileInfoDetail[0].type) + ], this.fileInfoDetail.type) } }, } diff --git a/resources/js/helpers.js b/resources/js/helpers.js index 7ec1adbc..df7ab047 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -1,335 +1,328 @@ import i18n from '@/i18n/index' import store from './store/index' -import { debounce, includes } from 'lodash' -import { events } from './bus' +import {debounce, includes} from "lodash"; +import {events} from './bus' import axios from 'axios' import router from '@/router' const Helpers = { - install(Vue) { + install(Vue) { - Vue.prototype.$updateText = debounce(function(route, name, value) { + Vue.prototype.$updateText = debounce(function (route, name, value) { + + let enableEmptyInput = ['mimetypes_blacklist' , 'google_analytics' , 'upload_limit'] + + if (value === '' && !enableEmptyInput.includes(name)) return + + axios.post(this.$store.getters.api + route, {name, value, _method: 'patch'}) + .catch(error => { + events.$emit('alert:open', { + title: this.$t('popup_error.title'), + message: this.$t('popup_error.message'), + }) + }) + }, 150) + + Vue.prototype.$updateImage = function (route, name, image) { + + // Create form + let formData = new FormData() + + // Add image to form + formData.append('name', name) + formData.append(name, image) + formData.append('_method', 'PATCH') + + axios.post(this.$store.getters.api + route, formData, { + headers: { + 'Content-Type': 'multipart/form-data', + } + }) + .catch(error => { + events.$emit('alert:open', { + title: this.$t('popup_error.title'), + message: this.$t('popup_error.message'), + }) + }) + } + + Vue.prototype.$scrollTop = function () { + var container = document.getElementById('vue-file-manager') + + if (container) { + container.scrollTop = 0 + } + } + + Vue.prototype.$getImage = function (source) { + return source ? this.$store.getters.config.host + '/' + source : '' + } + + Vue.prototype.$getCreditCardBrand = function (brand) { + return `/assets/icons/${brand}.svg` + } + + Vue.prototype.$getInvoiceLink = function (customer, id) { + return '/invoice/' + customer + '/' + id + } + + Vue.prototype.$openImageOnNewTab = function (source) { + let win = window.open(source, '_blank') + + win.focus() + } + + Vue.prototype.$createFolder = function (folderName) { + this.$store.dispatch('createFolder', folderName) + } + + Vue.prototype.$handleUploading = async function (files, parent_id) { + + let fileBuffer = [] + + // Append the file list to fileBuffer array + Array.prototype.push.apply(fileBuffer, files); + + let fileSucceed = 0 + + // Update files count in progressbar + store.commit('UPDATE_FILE_COUNT_PROGRESS', { + current: fileSucceed, + total: files.length + }) + + // Reset upload progress to 0 + store.commit('UPLOADING_FILE_PROGRESS', 0) + + // Get parent id + let parentFolder = this.$store.getters.currentFolder ? this.$store.getters.currentFolder.unique_id : 0 + let rootFolder = parent_id ? parent_id : parentFolder - let enableEmptyInput = ['mimetypes_blacklist', 'google_analytics'] + // Upload files + do { + let file = fileBuffer.shift(), + chunks = [] - if (value === '' && !enableEmptyInput.includes(name)) return - - axios.post(this.$store.getters.api + route, { name, value, _method: 'patch' }) - .catch(error => { - events.$emit('alert:open', { - title: this.$t('popup_error.title'), - message: this.$t('popup_error.message') - }) - }) - }, 150) - - Vue.prototype.$updateImage = function(route, name, image) { - - // Create form - let formData = new FormData() - - // Add image to form - formData.append('name', name) - formData.append(name, image) - formData.append('_method', 'PATCH') - - axios.post(this.$store.getters.api + route, formData, { - headers: { - 'Content-Type': 'multipart/form-data' - } - }) - .catch(error => { - events.$emit('alert:open', { - title: this.$t('popup_error.title'), - message: this.$t('popup_error.message') - }) - }) - } - - Vue.prototype.$scrollTop = function() { - var container = document.getElementById('vue-file-manager') - - if (container) { - container.scrollTop = 0 - } - } - - Vue.prototype.$getImage = function(source) { - return source ? this.$store.getters.config.host + '/' + source : '' - } - - Vue.prototype.$getCreditCardBrand = function(brand) { - return `/assets/icons/${brand}.svg` - } - - Vue.prototype.$getInvoiceLink = function(customer, id) { - return '/invoice/' + customer + '/' + id - } - - Vue.prototype.$openImageOnNewTab = function(source) { - let win = window.open(source, '_blank') - - win.focus() - } - - Vue.prototype.$handleUploading = async function(files, parent_id) { - - let fileBuffer = [] + // Calculate ceils + let size = this.$store.getters.config.chunkSize, + chunksCeil = Math.ceil(file.size / size); - // Append the file list to fileBuffer array - Array.prototype.push.apply(fileBuffer, files) + // Create chunks + for (let i = 0; i < chunksCeil; i++) { + chunks.push(file.slice( + i * size, Math.min(i * size + size, file.size), file.type + )); + } - let fileSucceed = 0 + // Set Data + let formData = new FormData(), + uploadedSize = 0, + isNotGeneralError = true, + striped_name = file.name.replace(/[^A-Za-z 0-9 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*/g, ''), + filename = Array(16).fill(0).map(x => Math.random().toString(36).charAt(2)).join('') + '-' + striped_name + '.part' - // Update files count in progressbar - store.commit('UPDATE_FILE_COUNT_PROGRESS', { - current: fileSucceed, - total: files.length - }) + do { + let isLast = chunks.length === 1, + chunk = chunks.shift(), + attempts = 0 - // Reset upload progress to 0 - store.commit('UPLOADING_FILE_PROGRESS', 0) + // Set form data + formData.set('file', chunk, filename); + formData.set('parent_id', rootFolder) + formData.set('is_last', isLast); - // Get parent id - let parentFolder = this.$store.getters.currentFolder ? this.$store.getters.currentFolder.unique_id : 0 - let rootFolder = parent_id ? parent_id : parentFolder + // Upload chunks + do { + await store.dispatch('uploadFiles', { + form: formData, + fileSize: file.size, + totalUploadedSize: uploadedSize + }).then(() => { + uploadedSize = uploadedSize + chunk.size + }).catch((error) => { - // Upload files - do { - let file = fileBuffer.shift(), - chunks = [] + // Count attempts + attempts++ - // Calculate ceils - let size = this.$store.getters.config.chunkSize, - chunksCeil = Math.ceil(file.size / size) + // Break uploading proccess + if (error.response.status === 500) + isNotGeneralError = false - // Create chunks - for (let i = 0; i < chunksCeil; i++) { - chunks.push(file.slice( - i * size, Math.min(i * size + size, file.size), file.type - )) - } + //Break if mimetype of file is in blacklist or file size exceed upload limit + if(error.response.status === 415 || 413) + isNotGeneralError = false - // Set Data - let formData = new FormData(), - uploadedSize = 0, - isNotGeneralError = true, - striped_name = file.name.replace(/[^A-Za-z 0-9 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*/g, ''), - filename = Array(16).fill(0).map(x => Math.random().toString(36).charAt(2)).join('') + '-' + striped_name + '.part' + // Show Error + if (attempts === 3) + this.$isSomethingWrong() + }) + } while (isNotGeneralError && attempts !== 0 && attempts !== 3) - do { - let isLast = chunks.length === 1, - chunk = chunks.shift(), - attempts = 0 + } while (isNotGeneralError && chunks.length !== 0) - // Set form data - formData.set('file', chunk, filename) - formData.set('parent_id', rootFolder) - formData.set('is_last', isLast) + fileSucceed++ - // Upload chunks - do { - await store.dispatch('uploadFiles', { - form: formData, - fileSize: file.size, - totalUploadedSize: uploadedSize - }).then(() => { - uploadedSize = uploadedSize + chunk.size - }).catch((error) => { + // Progress file log + store.commit('UPDATE_FILE_COUNT_PROGRESS', { + current: fileSucceed, + total: files.length + }) - // Count attempts - attempts++ + } while (fileBuffer.length !== 0) - // Break uploading proccess - if (error.response.status === 500) - isNotGeneralError = false + store.commit('UPDATE_FILE_COUNT_PROGRESS', undefined) + } - //Break if mimetype of file is in blacklist - if (error.response.status === 415) - isNotGeneralError = false + Vue.prototype.$uploadFiles = async function (files) { - // Show Error - if (attempts === 3) - this.$isSomethingWrong() - }) - } while (isNotGeneralError && attempts !== 0 && attempts !== 3) + if (files.length == 0) return - } while (isNotGeneralError && chunks.length !== 0) + if (!this.$checkFileMimetype(files) || !this.$checkUploadLimit(files)) return + + this.$handleUploading(files, undefined) + } - fileSucceed++ + Vue.prototype.$uploadExternalFiles = async function (event, parent_id) { - // Progress file log - store.commit('UPDATE_FILE_COUNT_PROGRESS', { - current: fileSucceed, - total: files.length - }) + // Prevent submit empty files + if (event.dataTransfer.items.length == 0) return - } while (fileBuffer.length !== 0) + // Get files + let files = [...event.dataTransfer.items].map(item => item.getAsFile()); - store.commit('UPDATE_FILE_COUNT_PROGRESS', undefined) - } + this.$handleUploading(files, parent_id) + } - Vue.prototype.$uploadFiles = async function(files) { + Vue.prototype.$downloadFile = function (url, filename) { + var anchor = document.createElement('a') - if (files.length == 0) return + anchor.href = url - if (!this.$checkFileMimetype(files)) return + anchor.download = filename - this.$handleUploading(files, undefined) - } + document.body.appendChild(anchor) - Vue.prototype.$uploadExternalFiles = async function(event, parent_id) { + anchor.click() + } + + Vue.prototype.$closePopup = function () { + events.$emit('popup:close') + } + + Vue.prototype.$isThisRoute = function (route, locations) { + + return includes(locations, route.name) + } + + Vue.prototype.$isThisLocation = function (location) { + + // Get current location + let currentLocation = store.getters.currentFolder && store.getters.currentFolder.location ? store.getters.currentFolder.location : undefined + + // Check if type is object + if (typeof location === 'Object' || location instanceof Object) { + return includes(location, currentLocation) + + } else { + return currentLocation === location + } + } + + Vue.prototype.$checkPermission = function (type) { + + let currentPermission = store.getters.permission + + // Check if type is object + if (typeof type === 'Object' || type instanceof Object) { + return includes(type, currentPermission) + + } else { + return currentPermission === type + } + } - // Prevent submit empty files - if (event.dataTransfer.items.length == 0) return + Vue.prototype.$isMobile = function () { + const toMatch = [ + /Android/i, + /webOS/i, + /iPhone/i, + /iPad/i, + /iPod/i, + /BlackBerry/i, + /Windows Phone/i + ] + + return toMatch.some(toMatchItem => { + return navigator.userAgent.match(toMatchItem) + }) + } - // Get files - let files = [...event.dataTransfer.items].map(item => item.getAsFile()) - - this.$handleUploading(files, parent_id) - } - - Vue.prototype.$downloadFile = function(url, filename) { - var anchor = document.createElement('a') - - anchor.href = url - - anchor.download = filename - - document.body.appendChild(anchor) - - anchor.click() - } - - Vue.prototype.$closePopup = function() { - events.$emit('popup:close') - } - - Vue.prototype.$isThisRoute = function(route, locations) { - - return includes(locations, route.name) - } - - Vue.prototype.$isThisLocation = function(location) { - - // Get current location - let currentLocation = store.getters.currentFolder && store.getters.currentFolder.location ? store.getters.currentFolder.location : undefined - - // Check if type is object - if (typeof location === 'Object' || location instanceof Object) { - return includes(location, currentLocation) - - } else { - return currentLocation === location - } - } - - Vue.prototype.$checkPermission = function(type) { - - let currentPermission = store.getters.permission - - // Check if type is object - if (typeof type === 'Object' || type instanceof Object) { - return includes(type, currentPermission) - - } else { - return currentPermission === type - } - } - - Vue.prototype.$isMobile = function() { - const toMatch = [ - /Android/i, - /webOS/i, - /iPhone/i, - /iPad/i, - /iPod/i, - /BlackBerry/i, - /Windows Phone/i - ] - - return toMatch.some(toMatchItem => { - return navigator.userAgent.match(toMatchItem) - }) - } - - Vue.prototype.$isMinimalScale = function() { - let sizeType = store.getters.filesViewWidth - - return sizeType === 'minimal-scale' - } - - Vue.prototype.$isCompactScale = function() { - let sizeType = store.getters.filesViewWidth - - return sizeType === 'compact-scale' - } - - Vue.prototype.$isFullScale = function() { - let sizeType = store.getters.filesViewWidth - - return sizeType === 'full-scale' - } - - Vue.prototype.$isSomethingWrong = function() { - events.$emit('alert:open', { - title: i18n.t('popup_error.title'), - message: i18n.t('popup_error.message') - }) - } - Vue.prototype.$checkFileMimetype = function(files) { - let validated = true - let mimetypesBlacklist = store.getters.config.mimetypesBlacklist - - for (let i = 0; i < files.length; i++) { - let fileType = files[i].type.split('/') - - if (!fileType[0]) { - fileType[1] = _.last(files[i].name.split('.')) - } - - if (mimetypesBlacklist.includes(fileType[1])) { - validated = false - - events.$emit('alert:open', { - emoji: '😬😬😬', - title: i18n.t('popup_mimetypes_blacklist.title'), - message: i18n.t('popup_mimetypes_blacklist.message', { mimetype: fileType[1] }) - }) - } - } - return validated - } - Vue.prototype.$getDataByLocation = function() { - - let folder = store.getters.currentFolder - - let actions = { - 'base': ['getFolder', [{ folder: folder, back: true, init: false, sorting: true }]], - 'public': ['browseShared', [{ folder: folder, back: true, init: false, sorting: true }]], - 'trash': ['getFolder', [{ folder: folder, back: true, init: false, sorting: true }]], - 'participant_uploads': ['getParticipantUploads'], - 'trash-root': ['getTrash'], - 'latest': ['getLatest'], - 'shared': ['getShared'] - } - - this.$store.dispatch(...actions[folder.location]) - - // Get dara of user with favourites tree - this.$store.dispatch('getAppData') - - // Get data of Navigator tree - this.$store.dispatch('getFolderTree') - } - Vue.prototype.$checkOS = function() { - // Handle styled scrollbar for Windows - if (navigator.userAgent.indexOf('Windows') != -1) { - let body = document.body - body.classList.add('windows') - } - } - } + Vue.prototype.$isMinimalScale = function () { + let sizeType = store.getters.filesViewWidth + + return sizeType === 'minimal-scale' + } + + Vue.prototype.$isCompactScale = function () { + let sizeType = store.getters.filesViewWidth + + return sizeType === 'compact-scale' + } + + Vue.prototype.$isFullScale = function () { + let sizeType = store.getters.filesViewWidth + + return sizeType === 'full-scale' + } + + Vue.prototype.$isSomethingWrong = function () { + + events.$emit('alert:open', { + title: this.$t('popup_error.title'), + message: this.$t('popup_error.message'), + }) + } + Vue.prototype.$checkFileMimetype = function(files) { + let validated = true + let mimetypesBlacklist = store.getters.config.mimetypesBlacklist + + for (let i = 0 ; i uploadLimit) { + validate = false + events.$emit('alert:open', { + emoji: '😟😟😟', + title: i18n.t('popup_upload_limit.title'), + message: i18n.t('popup_upload_limit.message', {uploadLimit: store.getters.config.uploadLimitFormatted}), + }) + break + } + } + return validate + } + } } -export default Helpers \ No newline at end of file +export default Helpers diff --git a/resources/js/i18n/lang/cn.json b/resources/js/i18n/lang/cn.json index 082ade87..0930f97d 100644 --- a/resources/js/i18n/lang/cn.json +++ b/resources/js/i18n/lang/cn.json @@ -211,6 +211,9 @@ "username_plac": "输入您的邮件用户名" }, "others": { + "upload_limit": "Upload Limit", + "upload_limit_plac": "Type your upload limit in MB", + "upload_limit_help": "If you want to set max file size limit on single upload, add size of your limit in MB. E.g. 100 means 100 MB and 2 000 means 2 000 MB limit.", "mimetypes_blacklist": "Mimetypes Blacklist", "mimetypes_blacklist_plac":"Add mimetypes to Blacklist" , "mimetypes_blacklist_help" :"If you want to prevent upload some type of files, just add them to blacklist like this: x-php,mp3,jpeg
Use a comma between each mimetype. Don't use a dot before mimetypes." , @@ -518,8 +521,12 @@ }, "title": "选择付款方式" }, + "popup_upload_limit": { + "title": "You exceed upload limit on single file", + "message": "Size of your uploaded file exceed the upload limit ({uploadLimit})." + }, "popup_mimetypes_blacklist": { - "title": "Oh no", + "title": "You are trying to upload unsupported file type", "message": "File of this type ({mimetype}) is not allowed to upload." }, "popup_zipping": { diff --git a/resources/js/i18n/lang/en.json b/resources/js/i18n/lang/en.json index cb74a53e..83c8e385 100644 --- a/resources/js/i18n/lang/en.json +++ b/resources/js/i18n/lang/en.json @@ -213,6 +213,9 @@ "username_plac": "Type your mail username" }, "others": { + "upload_limit": "Upload Limit", + "upload_limit_plac": "Type your upload limit in MB", + "upload_limit_help": "If you want to set max file size limit on single upload, add size of your limit in MB. E.g. 100 means 100 MB and 2 000 means 2 000 MB limit.", "mimetypes_blacklist": "Mimetypes Blacklist", "mimetypes_blacklist_plac":"Add mimetypes to Blacklist" , "mimetypes_blacklist_help" :"If you want to prevent upload some type of files, just add them to blacklist like this: x-php,mp3,jpeg
Use a comma between each mimetype. Don't use a dot before mimetypes." , @@ -520,8 +523,12 @@ }, "title": "Choose Payment Method" }, + "popup_upload_limit": { + "title": "You exceed upload limit on single file", + "message": "Size of your uploaded file exceed the upload limit ({uploadLimit})." + }, "popup_mimetypes_blacklist": { - "title": "Oh No", + "title": "You are trying to upload unsupported file type", "message": "File of this type ({mimetype}) is not allowed to upload." }, "popup_delete_card": { diff --git a/resources/js/i18n/lang/sk.json b/resources/js/i18n/lang/sk.json index 4360a027..08db223a 100644 --- a/resources/js/i18n/lang/sk.json +++ b/resources/js/i18n/lang/sk.json @@ -213,6 +213,9 @@ "username_plac": "Zadajte svoje používateľské meno pre poštu" }, "others": { + "upload_limit": "Limit nahrávania", + "upload_limit_plac": "Pridajte veľkosť limitu v MB", + "upload_limit_help": "Ak chcete nastaviť limit pre nahrávane jedneho súboru, pridajte veľkosť vášho limitu v MB.", "mimetypes_blacklist": "Čierna listina mimetypov", "mimetypes_blacklist_plac":"Pridajte mimetypy do Čiernej listiny", "mimetypes_blacklist_help" :"Ak chcete zakázať nahrávanie niektorých typov súborov, jednoducho ich pridajte na čiernu listinu, príklad: x-php, mp3, jpeg
Medzi mimetypmi použite čiarku. Nevkladajte bodku pred mimetyp." , @@ -520,8 +523,12 @@ }, "title": "Vyberte si metódu platby" }, + "popup_upload_limit": { + "title": "Je nám to ľúto", + "message": "Veľkosť nahravaného súboru prekročila limit pre nahraávane súbory ({uploadLimit})" + }, "popup_mimetypes_blacklist": { - "title": "Ospravelnujume sa", + "title": "Ospravedlňujeme sa", "message": "Nieje povolené nahrávať tento typ súboru ({mimetype})." }, "popup_zipping": { diff --git a/resources/js/store/modules/fileFunctions.js b/resources/js/store/modules/fileFunctions.js index 90ffce84..d777915a 100644 --- a/resources/js/store/modules/fileFunctions.js +++ b/resources/js/store/modules/fileFunctions.js @@ -1,357 +1,258 @@ import i18n from '@/i18n/index' import router from '@/router' -import { events } from '@/bus' -import { last } from 'lodash' +import {events} from '@/bus' +import {last} from 'lodash' import axios from 'axios' -import Vue from 'vue' - -const defaultState = { - isZippingFiles: false, -} const actions = { - downloadFiles: ({ commit, getters }) => { - let files = [] + moveItem: ({commit, getters, dispatch}, [item_from, to_item]) => { - // get unique_ids of selected files - getters.fileInfoDetail.forEach(file => files.push(file.unique_id)) + // Get route + let route = getters.sharedDetail && ! getters.sharedDetail.protected + ? '/api/move/' + item_from.unique_id + '/public/' + router.currentRoute.params.token + : '/api/move/' + item_from.unique_id - // Get route - let route = getters.sharedDetail && !getters.sharedDetail.protected - ? '/api/zip/public/' + router.currentRoute.params.token - : '/api/zip' + axios + .post(route, { + from_type: item_from.type, + to_unique_id: to_item.unique_id, + _method: 'patch' + }) + .then(() => { + commit('REMOVE_ITEM', item_from.unique_id) + commit('INCREASE_FOLDER_ITEM', to_item.unique_id) - commit('ZIPPING_FILE_STATUS', true) + if (item_from.type === 'folder' && getters.currentFolder.location !== 'public') + dispatch('getAppData') - axios.post(route, { - files: files - }) - .then(response => { - Vue.prototype.$downloadFile(response.data.url, response.data.name) - }) - .catch(() => { - Vue.prototype.$isSomethingWrong() - }) - .finally(() => { - commit('ZIPPING_FILE_STATUS', false) - }) - }, - moveItem: ({ commit, getters, dispatch }, { to_item, noSelectedItem }) => { + }) + .catch(() => isSomethingWrong()) + }, + createFolder: ({commit, getters, dispatch}, folderName) => { - let itemsToMove = [] - let items = [noSelectedItem] + // Get route + let route = getters.sharedDetail && ! getters.sharedDetail.protected + ? '/api/create-folder/public/' + router.currentRoute.params.token + : '/api/create-folder' - // If coming no selected item dont get items to move from fileInfoDetail - if (!noSelectedItem) - items = getters.fileInfoDetail + axios + .post(route, { + parent_id: getters.currentFolder.unique_id, + name: folderName + }) + .then(response => { + commit('ADD_NEW_FOLDER', response.data) - items.forEach(data => itemsToMove.push({ - 'force_delete': data.deleted_at ? true : false, - 'unique_id': data.unique_id, - 'type': data.type - })) + events.$emit('scrollTop') - // Remove file preview - if (!noSelectedItem) - commit('CLEAR_FILEINFO_DETAIL') + if ( getters.currentFolder.location !== 'public' ) { + dispatch('getAppData') + } + }) + .catch(() => isSomethingWrong()) + }, + renameItem: ({commit, getters, dispatch}, data) => { - // Get route - let route = getters.sharedDetail && !getters.sharedDetail.protected - ? '/api/move/public/' + router.currentRoute.params.token - : '/api/move' + // Updated name in favourites panel + if (getters.permission === 'master' && data.type === 'folder') + commit('UPDATE_NAME_IN_FAVOURITES', data) - axios - .post(route, { - _method: 'post', - to_unique_id: to_item.unique_id, - items: itemsToMove - }) - .then(() => { - itemsToMove.forEach(item => { - commit('REMOVE_ITEM', item.unique_id) - commit('INCREASE_FOLDER_ITEM', to_item.unique_id) + // Get route + let route = getters.sharedDetail && ! getters.sharedDetail.protected + ? '/api/rename-item/' + data.unique_id + '/public/' + router.currentRoute.params.token + : '/api/rename-item/' + data.unique_id - if (item.type === 'folder') - dispatch('getAppData') - if (getters.currentFolder.location === 'public') - dispatch('getFolderTree') - }) - }) - .catch(() => Vue.prototype.$isSomethingWrong()) - }, - createFolder: ({ commit, getters, dispatch }, folderName) => { + axios + .post(route, { + name: data.name, + type: data.type, + _method: 'patch' + }) + .then(response => { + commit('CHANGE_ITEM_NAME', response.data) - // Get route - let route = getters.sharedDetail && !getters.sharedDetail.protected - ? '/api/create-folder/public/' + router.currentRoute.params.token - : '/api/create-folder' + if (data.type === 'folder' && getters.currentFolder.location !== 'public') + dispatch('getAppData') + }) + .catch(() => isSomethingWrong()) + }, + uploadFiles: ({commit, getters}, {form, fileSize, totalUploadedSize}) => { + return new Promise((resolve, reject) => { - axios - .post(route, { - parent_id: getters.currentFolder.unique_id, - name: folderName - }) - .then(response => { - commit('ADD_NEW_FOLDER', response.data) + // Get route + let route = getters.sharedDetail && ! getters.sharedDetail.protected + ? '/api/upload/public/' + router.currentRoute.params.token + : '/api/upload' - events.$emit('scrollTop') + axios + .post(route, form, { + headers: { + 'Content-Type': 'application/octet-stream' + }, + onUploadProgress: event => { - if (getters.currentFolder.location !== 'public') - dispatch('getAppData') - if (getters.currentFolder.location === 'public') - dispatch('getFolderTree') + var percentCompleted = Math.floor(((totalUploadedSize + event.loaded) / fileSize) * 100) - }) - .catch(() => Vue.prototype.$isSomethingWrong()) - }, - renameItem: ({ commit, getters, dispatch }, data) => { + commit('UPLOADING_FILE_PROGRESS', percentCompleted >= 100 ? 100 : percentCompleted) - // Updated name in favourites panel - if (getters.permission === 'master' && data.type === 'folder') - commit('UPDATE_NAME_IN_FAVOURITES', data) + if (percentCompleted >= 100) { + commit('PROCESSING_FILE', true) + } + } + }) + .then(response => { + commit('PROCESSING_FILE', false) - // Get route - let route = getters.sharedDetail && !getters.sharedDetail.protected - ? '/api/rename-item/' + data.unique_id + '/public/' + router.currentRoute.params.token - : '/api/rename-item/' + data.unique_id + // Check if user is in uploading folder, if yes, than show new file + if (response.data.folder_id == getters.currentFolder.unique_id) + commit('ADD_NEW_ITEMS', response.data) - axios - .post(route, { - name: data.name, - type: data.type, - _method: 'patch' - }) - .then(response => { - commit('CHANGE_ITEM_NAME', response.data) + resolve(response) + }) + .catch(error => { + commit('PROCESSING_FILE', false) - if (data.type === 'folder' && getters.currentFolder.location !== 'public') - dispatch('getAppData') - if (data.type === 'folder' && getters.currentFolder.location === 'public') - dispatch('getFolderTree') - }) - .catch(() => Vue.prototype.$isSomethingWrong()) - }, - uploadFiles: ({ commit, getters }, { form, fileSize, totalUploadedSize }) => { - return new Promise((resolve, reject) => { + reject(error) - // Get route - let route = getters.sharedDetail && !getters.sharedDetail.protected - ? '/api/upload/public/' + router.currentRoute.params.token - : '/api/upload' + switch (error.response.status) { + case 423: + events.$emit('alert:open', { + emoji: '😬😬😬', + title: i18n.t('popup_exceed_limit.title'), + message: i18n.t('popup_exceed_limit.message') + }) + break; + case 415: + events.$emit('alert:open', { + emoji: '😬😬😬', + title: i18n.t('popup_mimetypes_blacklist.title'), + message: i18n.t('popup_mimetypes_blacklist.message') + }) + break; + case 413: + events.$emit('alert:open', { + emoji: '😟😟😟', + title: i18n.t('popup_upload_limit.title'), + message: i18n.t('popup_upload_limit.message', {uploadLimit: getters.config.uploadLimitFormatted}) + }) + break; + default: + events.$emit('alert:open', { + title: i18n.t('popup_error.title'), + message: i18n.t('popup_error.message'), + }) + break; + } - // Create cancel token for axios cancelation - const CancelToken = axios.CancelToken - const source = CancelToken.source() + // Reset uploader + commit('UPDATE_FILE_COUNT_PROGRESS', undefined) + }) + }) + }, + restoreItem: ({commit, getters}, item) => { - axios - .post(route, form, { - cancelToken: source.token, - headers: { - 'Content-Type': 'application/octet-stream' - }, - onUploadProgress: event => { + let restoreToHome = false - var percentCompleted = Math.floor(((totalUploadedSize + event.loaded) / fileSize) * 100) + // Check if file can be restored to home directory + if (getters.currentFolder.location === 'trash') + restoreToHome = true - commit('UPLOADING_FILE_PROGRESS', percentCompleted >= 100 ? 100 : percentCompleted) + // Remove file + commit('REMOVE_ITEM', item.unique_id) - if (percentCompleted >= 100) { - commit('PROCESSING_FILE', true) - } - } - }) - .then(response => { - commit('PROCESSING_FILE', false) + // Remove file preview + commit('CLEAR_FILEINFO_DETAIL') - // Check if user is in uploading folder, if yes, than show new file - if (response.data.folder_id == getters.currentFolder.unique_id) - commit('ADD_NEW_ITEMS', response.data) + axios + .post(getters.api + '/restore-item/' + item.unique_id, { + type: item.type, + to_home: restoreToHome, + _method: 'patch' + }) + .catch(() => isSomethingWrong()) + }, + deleteItem: ({commit, getters, dispatch}, data) => { - resolve(response) - }) - .catch(error => { - commit('PROCESSING_FILE', false) + // Remove file + commit('REMOVE_ITEM', data.unique_id) - reject(error) + // Remove item from sidebar + if (getters.permission === 'master') { - switch (error.response.status) { - case 423: - events.$emit('alert:open', { - emoji: '😬😬😬', - title: i18n.t('popup_exceed_limit.title'), - message: i18n.t('popup_exceed_limit.message') - }) - break - case 415: - events.$emit('alert:open', { - emoji: '😬😬😬', - title: i18n.t('popup_mimetypes_blacklist.title'), - message: i18n.t('popup_mimetypes_blacklist.message') - }) - break - case 413: - events.$emit('alert:open', { - emoji: '😟😟😟', - title: i18n.t('popup_paylod_error.title'), - message: i18n.t('popup_paylod_error.message') - }) - break - default: - events.$emit('alert:open', { - title: i18n.t('popup_error.title'), - message: i18n.t('popup_error.message') - }) - break - } + if (data.type === 'folder') + commit('REMOVE_ITEM_FROM_FAVOURITES', data) + } - // Reset uploader - commit('UPDATE_FILE_COUNT_PROGRESS', undefined) - }) + // Remove file preview + commit('CLEAR_FILEINFO_DETAIL') - // Cancel the upload request - events.$on('cancel-upload', () => { - source.cancel() + // Get route + let route = getters.sharedDetail && ! getters.sharedDetail.protected + ? '/api/remove-item/' + data.unique_id + '/public/' + router.currentRoute.params.token + : '/api/remove-item/' + data.unique_id - // Hide upload progress bar - commit('PROCESSING_FILE', false) - commit('UPDATE_FILE_COUNT_PROGRESS', undefined) - }) - }) - }, - restoreItem: ({ commit, getters }, item) => { + axios + .post(route, { + _method: 'delete', + data: { + type: data.type, + force_delete: data.deleted_at ? true : false, + }, + }) + .then(() => { - let restoreToHome = false + // If is folder, update app data + if (data.type === 'folder') { - // Check if file can be restored to home directory - if (getters.currentFolder.location === 'trash') - restoreToHome = true + if (data.unique_id === getters.currentFolder.unique_id) { - // Remove file - commit('REMOVE_ITEM', item.unique_id) + if ( getters.currentFolder.location === 'public' ) { + dispatch('browseShared', [{folder: last(getters.browseHistory), back: true, init: false}]) + } else { + dispatch('getFolder', [{folder: last(getters.browseHistory), back: true, init: false}]) + } + } - // Remove file preview - commit('CLEAR_FILEINFO_DETAIL') + if ( getters.currentFolder.location !== 'public' ) + dispatch('getAppData') + } + }) + .catch(() => isSomethingWrong()) + }, + emptyTrash: ({commit, getters}) => { - axios - .post(getters.api + '/restore-item/' + item.unique_id, { - type: item.type, - to_home: restoreToHome, - _method: 'patch' - }) - .catch(() => Vue.prototype.$isSomethingWrong()) - }, - deleteItem: ({ commit, getters, dispatch }, noSelectedItem) => { + // Clear file browser + commit('LOADING_STATE', {loading: true, data: []}) - let itemsToDelete = [] - let items = [noSelectedItem] + axios + .post(getters.api + '/empty-trash', { + _method: 'delete' + }) + .then(() => { + commit('LOADING_STATE', {loading: false, data: []}) + events.$emit('scrollTop') - // If coming no selected item dont get items to move from fileInfoDetail - if (!noSelectedItem) - items = getters.fileInfoDetail + // Remove file preview + commit('CLEAR_FILEINFO_DETAIL') - items.forEach(data => { - itemsToDelete.push({ - 'force_delete': data.deleted_at ? true : false, - 'type': data.type, - 'unique_id': data.unique_id - }) - - // Remove file - commit('REMOVE_ITEM', data.unique_id) - - // Remove item from sidebar - if (getters.permission === 'master') { - - if (data.type === 'folder') - commit('REMOVE_ITEM_FROM_FAVOURITES', data) - } - - // Remove file - commit('REMOVE_ITEM', data.unique_id) - - // Remove item from sidebar - if (getters.permission === 'master') { - - if (data.type === 'folder') - commit('REMOVE_ITEM_FROM_FAVOURITES', data) - } - }) - - // Remove file preview - if (!noSelectedItem) { - commit('CLEAR_FILEINFO_DETAIL') - } - - // Get route - let route = getters.sharedDetail && !getters.sharedDetail.protected - ? '/api/remove-item/public/' + router.currentRoute.params.token - : '/api/remove-item' - - axios - .post(route, { - _method: 'post', - data: itemsToDelete - }) - .then(() => { - - itemsToDelete.forEach(data => { - - // If is folder, update app data - if (data.type === 'folder') { - - if (data.unique_id === getters.currentFolder.unique_id) { - - if (getters.currentFolder.location === 'public') { - dispatch('browseShared', [{ folder: last(getters.browseHistory), back: true, init: false }]) - } else { - dispatch('getFolder', [{ folder: last(getters.browseHistory), back: true, init: false }]) - } - } - } - }) - - if (getters.currentFolder.location !== 'public') - dispatch('getAppData') - - if (getters.currentFolder.location === 'public') - dispatch('getFolderTree') - - }) - .catch(() => Vue.prototype.$isSomethingWrong()) - }, - emptyTrash: ({ commit, getters }) => { - - // Clear file browser - commit('LOADING_STATE', { loading: true, data: [] }) - - axios - .post(getters.api + '/empty-trash', { - _method: 'delete' - }) - .then(() => { - commit('LOADING_STATE', { loading: false, data: [] }) - events.$emit('scrollTop') - - // Remove file preview - commit('CLEAR_FILEINFO_DETAIL') - }) - .catch(() => Vue.prototype.$isSomethingWrong()) - } + // Show success message + events.$emit('success:open', { + title: i18n.t('popup_trashed.title'), + message: i18n.t('popup_trashed.message'), + }) + }) + .catch(() => isSomethingWrong()) + }, } -const mutations = { - ZIPPING_FILE_STATUS(state, status) { - state.isZippingFiles = status - } -} - -const getters = { - isZippingFiles: state => state.isZippingFiles +// Show error message +function isSomethingWrong() { + events.$emit('alert:open', { + title: i18n.t('popup_error.title'), + message: i18n.t('popup_error.message'), + }) } export default { - state: defaultState, - mutations, - actions, - getters + actions, } diff --git a/resources/js/views/Admin/AppSettings/AppSettingsTabs/Others.vue b/resources/js/views/Admin/AppSettings/AppSettingsTabs/Others.vue index 75e1f4ad..e24c2f70 100644 --- a/resources/js/views/Admin/AppSettings/AppSettingsTabs/Others.vue +++ b/resources/js/views/Admin/AppSettings/AppSettingsTabs/Others.vue @@ -89,6 +89,15 @@ +
+ + + + {{ errors[0] }} + + +
+ {{ $t('admin_settings.others.section_cache') }} @@ -163,7 +172,7 @@ mounted() { axios.get('/api/settings', { params: { - column: 'contact_email|google_analytics|storage_default|registration|storage_limitation|mimetypes_blacklist' + column: 'contact_email|google_analytics|storage_default|registration|storage_limitation|mimetypes_blacklist|upload_limit' } }) .then(response => { @@ -175,7 +184,8 @@ defaultStorage: response.data.storage_default, userRegistration: parseInt(response.data.registration), storageLimitation: parseInt(response.data.storage_limitation), - mimetypesBlacklist : response.data.mimetypes_blacklist + mimetypesBlacklist : response.data.mimetypes_blacklist, + uploadLimit: response.data.upload_limit } }) } diff --git a/resources/views/index.blade.php b/resources/views/index.blade.php index e57a5221..ce6ee48f 100644 --- a/resources/views/index.blade.php +++ b/resources/views/index.blade.php @@ -56,6 +56,8 @@ storageDefaultSpace: {{ isset($settings->storage_default) ? $settings->storage_default : 5 }}, storageDefaultSpaceFormatted: '{{ isset($settings->storage_default) ? format_gigabytes($settings->storage_default) : format_gigabytes(5) }}', mimetypesBlacklist: '{{ isset($settings->mimetypes_blacklist) ? $settings->mimetypes_blacklist: null}}', + uploadLimit: {{ isset($settings->upload_limit) ? format_bytes($settings->upload_limit) : 'undefined' }}, + uploadLimitFormatted: '{{ isset($settings->upload_limit) ? format_megabytes($settings->upload_limit) : null }}', hasAuthCookie: {{ Cookie::has('token') ? 1 : 0 }}, isSaaS: {{ isset($settings->license) && $settings->license === 'Extended' ? 1 : 0 }},