- Restriction UI warning

- create folder restriction
- fixed UI bugs
This commit is contained in:
Čarodej
2022-01-05 12:48:07 +01:00
parent c7c11fe5b9
commit b4887cea0e
21 changed files with 306 additions and 71 deletions

View File

@@ -63,14 +63,14 @@
"/chunks/plan-settings.js": "/chunks/plan-settings.js?id=8a959e196d628d0efc4b",
"/chunks/plan-subscribers.js": "/chunks/plan-subscribers.js?id=7eff560fea52770a642f",
"/chunks/plans.js": "/chunks/plans.js?id=854c232c29d88c5b541a",
"/chunks/platform.js": "/chunks/platform.js?id=d6b426d84871fc636e9e",
"/chunks/platform.js": "/chunks/platform.js?id=c3427a1bceb2bbf9f738",
"/chunks/platform~chunks/shared.js": "/chunks/platform~chunks/shared.js?id=440568dcf151d51d2486",
"/chunks/platform~chunks/shared~chunks/shared-with-me~chunks/team-folders.js": "/chunks/platform~chunks/shared~chunks/shared-with-me~chunks/team-folders.js?id=7d983dfdc91de607d737",
"/chunks/profile.js": "/chunks/profile.js?id=8688d9c7ff850e6989e6",
"/chunks/profile~chunks/settings-password.js": "/chunks/profile~chunks/settings-password.js?id=dfa4128d68360d5e1b3b",
"/chunks/purchase-code.js": "/chunks/purchase-code.js?id=9e948882ae2315eb6132",
"/chunks/recent-uploads.js": "/chunks/recent-uploads.js?id=8577d4c771602671b38a",
"/chunks/settings.js": "/chunks/settings.js?id=548f24fc6d666c9db1a8",
"/chunks/settings.js": "/chunks/settings.js?id=4466d97a0211f77d9317",
"/chunks/settings-password.js": "/chunks/settings-password.js?id=b6eb94764cc7b47f835e",
"/chunks/settings-storage.js": "/chunks/settings-storage.js?id=76b45c336e8e12b23e81",
"/chunks/settings~chunks/settings-password.js": "/chunks/settings~chunks/settings-password.js?id=aafc9cd6aa47b01bc25a",
@@ -113,5 +113,90 @@
"/chunks/settings.35f000715b5a03522346.hot-update.js": "/chunks/settings.35f000715b5a03522346.hot-update.js",
"/chunks/settings.51d3c0571252e4f23ff1.hot-update.js": "/chunks/settings.51d3c0571252e4f23ff1.hot-update.js",
"/chunks/settings.255054593b1cd7f654d3.hot-update.js": "/chunks/settings.255054593b1cd7f654d3.hot-update.js",
"/chunks/settings.2438d1c93de4d0c45c67.hot-update.js": "/chunks/settings.2438d1c93de4d0c45c67.hot-update.js"
"/chunks/settings.2438d1c93de4d0c45c67.hot-update.js": "/chunks/settings.2438d1c93de4d0c45c67.hot-update.js",
"/chunks/platform.5811795aa26f29d23f5b.hot-update.js": "/chunks/platform.5811795aa26f29d23f5b.hot-update.js",
"/chunks/platform.8c481bcdc638d27a4a84.hot-update.js": "/chunks/platform.8c481bcdc638d27a4a84.hot-update.js",
"/chunks/platform.2c801c878d2302c04b04.hot-update.js": "/chunks/platform.2c801c878d2302c04b04.hot-update.js",
"/chunks/platform.6ae437c53d3355af934e.hot-update.js": "/chunks/platform.6ae437c53d3355af934e.hot-update.js",
"/chunks/platform.8a1132d7879b623a0ee4.hot-update.js": "/chunks/platform.8a1132d7879b623a0ee4.hot-update.js",
"/js/main.34827559ca00fbb7f164.hot-update.js": "/js/main.34827559ca00fbb7f164.hot-update.js",
"/js/main.11ddf2d8a48a946eb9b9.hot-update.js": "/js/main.11ddf2d8a48a946eb9b9.hot-update.js",
"/js/main.c81f24a0fd629af6c208.hot-update.js": "/js/main.c81f24a0fd629af6c208.hot-update.js",
"/js/main.07d32454f0bd3299c3bb.hot-update.js": "/js/main.07d32454f0bd3299c3bb.hot-update.js",
"/js/main.deef2a5be87c2f0386e1.hot-update.js": "/js/main.deef2a5be87c2f0386e1.hot-update.js",
"/js/main.7e7cfb75cc4b9255a594.hot-update.js": "/js/main.7e7cfb75cc4b9255a594.hot-update.js",
"/js/main.e31064a188136858221e.hot-update.js": "/js/main.e31064a188136858221e.hot-update.js",
"/js/main.5295702a8639b61805ac.hot-update.js": "/js/main.5295702a8639b61805ac.hot-update.js",
"/js/main.1663362fc2afa6e6c7fd.hot-update.js": "/js/main.1663362fc2afa6e6c7fd.hot-update.js",
"/js/main.b7f439a45efadc0d09c9.hot-update.js": "/js/main.b7f439a45efadc0d09c9.hot-update.js",
"/js/main.ab2d94da6e88e19834fc.hot-update.js": "/js/main.ab2d94da6e88e19834fc.hot-update.js",
"/js/main.d1bac7303de2752f8f2a.hot-update.js": "/js/main.d1bac7303de2752f8f2a.hot-update.js",
"/js/main.fa4020861f2256c1a814.hot-update.js": "/js/main.fa4020861f2256c1a814.hot-update.js",
"/js/main.49e61ab55a7999ac2d7c.hot-update.js": "/js/main.49e61ab55a7999ac2d7c.hot-update.js",
"/js/main.9a3d34d1573f5a360549.hot-update.js": "/js/main.9a3d34d1573f5a360549.hot-update.js",
"/js/main.a09414329bcddae0193d.hot-update.js": "/js/main.a09414329bcddae0193d.hot-update.js",
"/js/main.9af992eb88a9c439a7ab.hot-update.js": "/js/main.9af992eb88a9c439a7ab.hot-update.js",
"/js/main.583d206005a97f6eaede.hot-update.js": "/js/main.583d206005a97f6eaede.hot-update.js",
"/js/main.1a94a099a196d5dd94a7.hot-update.js": "/js/main.1a94a099a196d5dd94a7.hot-update.js",
"/vendors~chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~29ecd2dd.js": "/vendors~chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~29ecd2dd.js?id=6a9136010589fefae8c1",
"/js/main.4280084333a6f807e55e.hot-update.js": "/js/main.4280084333a6f807e55e.hot-update.js",
"/chunks/admin~chunks/app-language~chunks/dashboard~chunks/files~chunks/invoices~chunks/my-shared-item~3b21240c.4280084333a6f807e55e.hot-update.js": "/chunks/admin~chunks/app-language~chunks/dashboard~chunks/files~chunks/invoices~chunks/my-shared-item~3b21240c.4280084333a6f807e55e.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.4280084333a6f807e55e.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.4280084333a6f807e55e.hot-update.js",
"/chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chunks/app-others~chunks~217928f6.4280084333a6f807e55e.hot-update.js": "/chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chunks/app-others~chunks~217928f6.4280084333a6f807e55e.hot-update.js",
"/chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chunks/app-others~chunks~5acee76d.4280084333a6f807e55e.hot-update.js": "/chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chunks/app-others~chunks~5acee76d.4280084333a6f807e55e.hot-update.js",
"/chunks/app-language.4280084333a6f807e55e.hot-update.js": "/chunks/app-language.4280084333a6f807e55e.hot-update.js",
"/chunks/billing.4280084333a6f807e55e.hot-update.js": "/chunks/billing.4280084333a6f807e55e.hot-update.js",
"/chunks/dashboard~chunks/invoices~chunks/pages~chunks/plans~chunks/subscriptions.4280084333a6f807e55e.hot-update.js": "/chunks/dashboard~chunks/invoices~chunks/pages~chunks/plans~chunks/subscriptions.4280084333a6f807e55e.hot-update.js",
"/chunks/homepage.4280084333a6f807e55e.hot-update.js": "/chunks/homepage.4280084333a6f807e55e.hot-update.js",
"/chunks/installation-disclaimer.4280084333a6f807e55e.hot-update.js": "/chunks/installation-disclaimer.4280084333a6f807e55e.hot-update.js",
"/chunks/invitation.4280084333a6f807e55e.hot-update.js": "/chunks/invitation.4280084333a6f807e55e.hot-update.js",
"/chunks/page-edit.4280084333a6f807e55e.hot-update.js": "/chunks/page-edit.4280084333a6f807e55e.hot-update.js",
"/chunks/plan.4280084333a6f807e55e.hot-update.js": "/chunks/plan.4280084333a6f807e55e.hot-update.js",
"/chunks/plan-create/fixed.4280084333a6f807e55e.hot-update.js": "/chunks/plan-create/fixed.4280084333a6f807e55e.hot-update.js",
"/chunks/plan-create/metered.4280084333a6f807e55e.hot-update.js": "/chunks/plan-create/metered.4280084333a6f807e55e.hot-update.js",
"/chunks/plan-delete.4280084333a6f807e55e.hot-update.js": "/chunks/plan-delete.4280084333a6f807e55e.hot-update.js",
"/chunks/profile~chunks/settings-password.4280084333a6f807e55e.hot-update.js": "/chunks/profile~chunks/settings-password.4280084333a6f807e55e.hot-update.js",
"/chunks/settings-storage.4280084333a6f807e55e.hot-update.js": "/chunks/settings-storage.4280084333a6f807e55e.hot-update.js",
"/chunks/shared.4280084333a6f807e55e.hot-update.js": "/chunks/shared.4280084333a6f807e55e.hot-update.js",
"/chunks/shared-with-me~chunks/team-folders.4280084333a6f807e55e.hot-update.js": "/chunks/shared-with-me~chunks/team-folders.4280084333a6f807e55e.hot-update.js",
"/chunks/shared/single-file.4280084333a6f807e55e.hot-update.js": "/chunks/shared/single-file.4280084333a6f807e55e.hot-update.js",
"/chunks/sign-in.4280084333a6f807e55e.hot-update.js": "/chunks/sign-in.4280084333a6f807e55e.hot-update.js",
"/chunks/subscription-plans.4280084333a6f807e55e.hot-update.js": "/chunks/subscription-plans.4280084333a6f807e55e.hot-update.js",
"/chunks/subscriptions.4280084333a6f807e55e.hot-update.js": "/chunks/subscriptions.4280084333a6f807e55e.hot-update.js",
"/chunks/upgrade-billing~chunks/upgrade-plan.4280084333a6f807e55e.hot-update.js": "/chunks/upgrade-billing~chunks/upgrade-plan.4280084333a6f807e55e.hot-update.js",
"/chunks/user.4280084333a6f807e55e.hot-update.js": "/chunks/user.4280084333a6f807e55e.hot-update.js",
"/chunks/user-create.4280084333a6f807e55e.hot-update.js": "/chunks/user-create.4280084333a6f807e55e.hot-update.js",
"/chunks/user-subscription.4280084333a6f807e55e.hot-update.js": "/chunks/user-subscription.4280084333a6f807e55e.hot-update.js",
"/chunks/users.4280084333a6f807e55e.hot-update.js": "/chunks/users.4280084333a6f807e55e.hot-update.js",
"/js/main.759fcc4e53d2dc10eef7.hot-update.js": "/js/main.759fcc4e53d2dc10eef7.hot-update.js",
"/js/main.8c791a358db3536d409d.hot-update.js": "/js/main.8c791a358db3536d409d.hot-update.js",
"/js/main.56620b989bbce3ae0875.hot-update.js": "/js/main.56620b989bbce3ae0875.hot-update.js",
"/chunks/platform.68f9a7490063bdd5f3ab.hot-update.js": "/chunks/platform.68f9a7490063bdd5f3ab.hot-update.js",
"/chunks/platform.9fc7bcf362c1d4bbfc81.hot-update.js": "/chunks/platform.9fc7bcf362c1d4bbfc81.hot-update.js",
"/chunks/platform.ee93be9965a1cfa152fc.hot-update.js": "/chunks/platform.ee93be9965a1cfa152fc.hot-update.js",
"/chunks/platform.133e1026a756d3035944.hot-update.js": "/chunks/platform.133e1026a756d3035944.hot-update.js",
"/chunks/platform.6fcf086c7a4c1331a53c.hot-update.js": "/chunks/platform.6fcf086c7a4c1331a53c.hot-update.js",
"/js/main.f16a33ff7d5847b98266.hot-update.js": "/js/main.f16a33ff7d5847b98266.hot-update.js",
"/js/main.5f3afd688212022fb58a.hot-update.js": "/js/main.5f3afd688212022fb58a.hot-update.js",
"/js/main.007eb43910450b32c805.hot-update.js": "/js/main.007eb43910450b32c805.hot-update.js",
"/js/main.76d40e551720ac111fd9.hot-update.js": "/js/main.76d40e551720ac111fd9.hot-update.js",
"/js/main.b7babb7b19f9b09ca98d.hot-update.js": "/js/main.b7babb7b19f9b09ca98d.hot-update.js",
"/js/main.08e4f30c97bcc3a942e8.hot-update.js": "/js/main.08e4f30c97bcc3a942e8.hot-update.js",
"/js/main.fea58478d3dfe9206fed.hot-update.js": "/js/main.fea58478d3dfe9206fed.hot-update.js",
"/js/main.8881265f32669ed95bfb.hot-update.js": "/js/main.8881265f32669ed95bfb.hot-update.js",
"/chunks/settings.1eda8247e148c5d51d4d.hot-update.js": "/chunks/settings.1eda8247e148c5d51d4d.hot-update.js",
"/chunks/settings.d9d981a7197ff398ee22.hot-update.js": "/chunks/settings.d9d981a7197ff398ee22.hot-update.js",
"/chunks/platform.a7c645c2c8ceda4ae3f7.hot-update.js": "/chunks/platform.a7c645c2c8ceda4ae3f7.hot-update.js",
"/js/main.9fbff94db8eb20332da7.hot-update.js": "/js/main.9fbff94db8eb20332da7.hot-update.js",
"/js/main.959620b85c3df6282a5f.hot-update.js": "/js/main.959620b85c3df6282a5f.hot-update.js",
"/js/main.b8fe9507703cfb75e859.hot-update.js": "/js/main.b8fe9507703cfb75e859.hot-update.js",
"/js/main.a48539de27bb23dd5904.hot-update.js": "/js/main.a48539de27bb23dd5904.hot-update.js",
"/js/main.c2d0f57bdad53abf3859.hot-update.js": "/js/main.c2d0f57bdad53abf3859.hot-update.js",
"/js/main.9eb9d2d7d97cc33f46f7.hot-update.js": "/js/main.9eb9d2d7d97cc33f46f7.hot-update.js",
"/js/main.272640c4f5959835aa61.hot-update.js": "/js/main.272640c4f5959835aa61.hot-update.js",
"/js/main.287b5ae535954f8ed89c.hot-update.js": "/js/main.287b5ae535954f8ed89c.hot-update.js",
"/js/main.51906e2db8a6c36f5304.hot-update.js": "/js/main.51906e2db8a6c36f5304.hot-update.js",
"/js/main.c09b0f39fe6d0b43515b.hot-update.js": "/js/main.c09b0f39fe6d0b43515b.hot-update.js",
"/js/main.de28ca938da3825e62b3.hot-update.js": "/js/main.de28ca938da3825e62b3.hot-update.js",
"/js/main.be91e0ed3d68ecb1af06.hot-update.js": "/js/main.be91e0ed3d68ecb1af06.hot-update.js"
}

View File

@@ -9,6 +9,13 @@
<!--Show spinner before translations is loaded-->
<Spinner v-if="! isLoaded"/>
<!--Show warning bar when user functionality is restricted-->
<div v-if="isLimitedUser" class="bg-red-500 text-center py-1">
<router-link :to="{name: 'Billing'}" class="text-white font-bold text-xs">
{{ $t('Your functionality is restricted. Please review your billing settings.') }}
</router-link>
</div>
<!--App view-->
<router-view v-if="isLoaded" />
@@ -41,7 +48,9 @@ export default {
},
computed: {
...mapGetters([
'isDarkMode'
'isLimitedUser',
'isDarkMode',
'user',
]),
},
watch: {

View File

@@ -143,9 +143,6 @@ export default {
if ('two-factor-recovery-codes' === name)
this.getRecoveryCodes()
})
},
destroyed() {
events.$off('popup:open')
}
}
</script>

View File

@@ -1,6 +1,6 @@
import {debounce, isArray, orderBy} from "lodash"
import i18n from '/resources/js/i18n/index'
import store from '../store/index'
import {debounce, isArray, orderBy} from "lodash";
import {events} from '../bus'
import axios from 'axios'

View File

@@ -1,16 +1,18 @@
import {events} from "../bus";
import i18n from '/resources/js/i18n/index'
import store from '../store/index'
import {events} from '../bus'
const itemHelpers = {
install(Vue) {
Vue.prototype.$emptyTrash = function () {
this.$store.dispatch('emptyTrash')
store.dispatch('emptyTrash')
}
Vue.prototype.$emptyTrashQuietly = function () {
this.$store.dispatch('emptyTrashQuietly')
store.dispatch('emptyTrashQuietly')
}
Vue.prototype.$shareCancel = function () {
this.$store.dispatch('shareCancel')
store.dispatch('shareCancel')
}
Vue.prototype.$renameFileOrFolder = function (entry) {
@@ -22,16 +24,16 @@ const itemHelpers = {
}
Vue.prototype.$createFolder = function () {
this.$store.dispatch('createFolder', {
name: this.$t('popup_create_folder.folder_default_name')
store.dispatch('createFolder', {
name: i18n.t('popup_create_folder.folder_default_name')
})
}
Vue.prototype.$downloadSelection = function (item) {
let clipboard = this.$store.getters.clipboard
let clipboard = store.getters.clipboard
if (clipboard.length > 1 || (clipboard.length === 1 && clipboard[0].data.type === 'folder'))
this.$store.dispatch('downloadZip')
store.dispatch('downloadZip')
else {
Vue.prototype.$downloadFile(item.data.attributes.file_url, item.data.attributes.name + '.' + item.data.attributes.mimetype)
}
@@ -39,8 +41,8 @@ const itemHelpers = {
Vue.prototype.$dissolveTeamFolder = function (folder) {
events.$emit('confirm:open', {
title: this.$t('Are you sure you want to dissolve this team?'),
message: this.$t('All team members will lose access to your files and existing folder will be moved into your "Files" section.'),
title: i18n.t('Are you sure you want to dissolve this team?'),
message: i18n.t('All team members will lose access to your files and existing folder will be moved into your "Files" section.'),
action: {
id: folder.data.id,
operation: 'dissolve-team-folder',
@@ -50,8 +52,8 @@ const itemHelpers = {
Vue.prototype.$detachMeFromTeamFolder = function (folder) {
events.$emit('confirm:open', {
title: this.$t('Are you sure you want to leave this team?'),
message: this.$t("You will don't have access to the files and all your previously uploaded content will be part of this Team Folder you are leaving."),
title: i18n.t('Are you sure you want to leave this team?'),
message: i18n.t("You will don't have access to the files and all your previously uploaded content will be part of this Team Folder you are leaving."),
action: {
id: folder.data.id,
operation: 'leave-team-folder',
@@ -72,25 +74,25 @@ const itemHelpers = {
}
Vue.prototype.$removeFavourite = function (folder) {
this.$store.dispatch('removeFromFavourites', folder)
store.dispatch('removeFromFavourites', folder)
}
Vue.prototype.$deleteFileOrFolder = function (entry) {
if (!this.$store.getters.clipboard.includes(entry)) {
this.$store.dispatch('deleteItem', entry)
if (!store.getters.clipboard.includes(entry)) {
store.dispatch('deleteItem', entry)
}
if (this.$store.getters.clipboard.includes(entry)) {
this.$store.dispatch('deleteItem')
if (store.getters.clipboard.includes(entry)) {
store.dispatch('deleteItem')
}
}
Vue.prototype.$restoreFileOrFolder = function (entry) {
if (!this.$store.getters.clipboard.includes(entry))
this.$store.dispatch('restoreItem', entry)
if (!store.getters.clipboard.includes(entry))
store.dispatch('restoreItem', entry)
if (this.$store.getters.clipboard.includes(entry))
this.$store.dispatch('restoreItem', null)
if (store.getters.clipboard.includes(entry))
store.dispatch('restoreItem', null)
}
Vue.prototype.$shareFileOrFolder = function (entry) {

View File

@@ -117,7 +117,12 @@ const actions = {
dispatch('getAppData')
})
.catch(() => Vue.prototype.$isSomethingWrong())
.catch(error => {
events.$emit('alert:open', {
title: error.response.data.message,
message: i18n.t('popup_error.message')
})
})
},
renameItem: ({commit, getters, dispatch}, data) => {
@@ -222,13 +227,16 @@ const actions = {
'413': {
title: i18n.t('popup_paylod_error.title'),
message: i18n.t('popup_paylod_error.message')
}
},
'401': {
title: error.response.data.message,
},
}
events.$emit('alert:open', {
emoji: '😬😬😬',
title: messages[error.response.status]['title'],
message: messages[error.response.status]['message']
message: messages[error.response.status]['message'] || null
})
commit('PROCESSING_FILE', false)

View File

@@ -143,6 +143,7 @@ const mutations = {
}
const getters = {
isLimitedUser: state => state.user && state.user.data.relationships.failedPayments && state.user.data.relationships.failedPayments.data.length === 3,
permission: state => state.permission,
user: state => state.user,
}

View File

@@ -110,7 +110,8 @@
},
computed: {
...mapGetters([
'isVisibleSidebar'
'isVisibleSidebar',
'isLimitedUser',
])
},
data() {

View File

@@ -15,8 +15,7 @@ class FixedBillingLimitationEngine implements LimitationEngine
);
// Check if storage usage exceed predefined capacity
return ! ($usedPercentage >= 100)
;
return ! ($usedPercentage >= 100);
}
public function canDownload(User $user): bool

View File

@@ -9,21 +9,18 @@ class MeteredBillingLimitationEngine implements LimitationEngine
public function canUpload(User $user, int $fileSize = 0): bool
{
// Disable upload when user has more than 3 failed payments
return ! ($user->failedPayments()->count() >= 3)
;
return ! ($user->failedPayments()->count() >= 3);
}
public function canDownload(User $user): bool
{
// Disable upload when user has more than 3 failed payments
return ! ($user->failedPayments()->count() >= 3)
;
// Disable download when user has more than 3 failed payments
return ! ($user->failedPayments()->count() >= 3);
}
public function canCreateFolder(User $user): bool
{
// Disable upload when user has more than 3 failed payments
return ! ($user->failedPayments()->count() >= 3)
;
// Disable create folder when user has more than 3 failed payments
return ! ($user->failedPayments()->count() >= 3);
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace App\Users\Exceptions;
use Exception;
class InvalidUserActionException extends Exception
{
// TODO: translate
protected $message = 'This user action is not allowed.';
}

View File

@@ -88,17 +88,6 @@ class User extends Authenticatable implements MustVerifyEmail
return UserFactory::new();
}
public function __call($method, $parameters)
{
if (str_starts_with($method, 'can')) {
return resolve(LimitationManager::class)
->driver()
->$method($this, ...$parameters);
}
return parent::__call($method, $parameters);
}
/**
* Get user used storage details
*/
@@ -211,6 +200,17 @@ class User extends Authenticatable implements MustVerifyEmail
$this->notify(new ResetPassword($token));
}
public function __call($method, $parameters)
{
if (str_starts_with($method, 'can')) {
return resolve(LimitationManager::class)
->driver()
->$method($this, ...$parameters);
}
return parent::__call($method, $parameters);
}
protected static function boot()
{
parent::boot();

View File

@@ -1,6 +1,7 @@
<?php
namespace Domain\Files\Actions;
use App\Users\Exceptions\InvalidUserActionException;
use Illuminate\Support\Str;
use Domain\Sharing\Models\Share;
use Illuminate\Support\Facades\Auth;
@@ -21,6 +22,8 @@ class UploadFileAction
/**
* Upload new file
*
* @throws InvalidUserActionException
*/
public function __invoke(
UploadRequest $request,
@@ -68,7 +71,7 @@ class UploadFileAction
if (! $user->canUpload($fileSize)) {
Storage::disk('local')->delete("chunks/$chunkName");
abort(423, 'You exceed your storage limit!');
throw new InvalidUserActionException();
}
// Move finished file from chunk to file-manager directory

View File

@@ -1,6 +1,7 @@
<?php
namespace Domain\Files\Controllers;
use App\Users\Exceptions\InvalidUserActionException;
use Domain\Files\Models\File;
use Illuminate\Http\Response;
use App\Http\Controllers\Controller;
@@ -27,8 +28,15 @@ class UploadFileController extends Controller
return ($this->fakeUploadFile)($request);
}
$file = ($this->uploadFiles)($request);
try {
$file = ($this->uploadFiles)($request);
return response(new FileResource($file), 201);
return response(new FileResource($file), 201);
} catch (InvalidUserActionException $e) {
return response([
'type' => 'error',
'message' => $e->getMessage(),
], 401);
}
}
}

View File

@@ -5,24 +5,35 @@ use Domain\Sharing\Models\Share;
use Domain\Folders\Models\Folder;
use Illuminate\Support\Facades\Auth;
use Domain\Folders\Requests\CreateFolderRequest;
use App\Users\Exceptions\InvalidUserActionException;
class CreateFolderAction
{
/**
* Create new folder
*
* @throws InvalidUserActionException
*/
public function __invoke(
CreateFolderRequest $request,
?Share $shared = null,
): Folder|array {
// Get user model
$user = $shared
? $shared->user
: Auth::user();
// Check if user can create folder
if (! $user->canCreateFolder()) {
throw new InvalidUserActionException();
}
/*
* check if exist parent team folder, if yes,
* then get folder to detect whether it is team_folder
* Check if exist parent team folder, if yes,
* then get the latest parent folder to detect whether it is team_folder
*/
if ($request->has('parent_id')) {
$isTeamFolder = Folder::find(
$request->input('parent_id')
)
$isTeamFolder = Folder::find($request->input('parent_id'))
->getLatestParent()
->team_folder;
}
@@ -34,7 +45,7 @@ class CreateFolderAction
'color' => $request->input('color') ?? null,
'emoji' => $request->input('emoji') ?? null,
'author' => $shared ? 'visitor' : 'user',
'user_id' => $shared ? $shared->user_id : Auth::id(),
'user_id' => $user->id,
'team_folder' => $isTeamFolder ?? false,
]);
}

View File

@@ -7,6 +7,7 @@ use Domain\Folders\Resources\FolderResource;
use Domain\Folders\Actions\CreateFolderAction;
use Domain\Folders\Requests\CreateFolderRequest;
use Support\Demo\Actions\FakeCreateFolderAction;
use App\Users\Exceptions\InvalidUserActionException;
class CreateFolderController extends Controller
{
@@ -28,8 +29,17 @@ class CreateFolderController extends Controller
return response(new FolderResource($fakeFolder), 201);
}
$folder = ($this->createFolder)($request);
try {
// Create new folder
$folder = ($this->createFolder)($request);
return response(new FolderResource($folder), 201);
// Return new folder
return response(new FolderResource($folder), 201);
} catch (InvalidUserActionException $e) {
return response([
'type' => 'error',
'message' => $e->getMessage(),
], 401);
}
}
}

View File

@@ -4,9 +4,11 @@ namespace Domain\Folders\Controllers;
use Illuminate\Http\Response;
use Domain\Sharing\Models\Share;
use App\Http\Controllers\Controller;
use Domain\Folders\Resources\FolderResource;
use Domain\Folders\Actions\CreateFolderAction;
use Domain\Folders\Requests\CreateFolderRequest;
use Support\Demo\Actions\FakeCreateFolderAction;
use App\Users\Exceptions\InvalidUserActionException;
use Domain\Sharing\Actions\ProtectShareRecordAction;
use Domain\Sharing\Actions\VerifyAccessToItemAction;
@@ -19,7 +21,7 @@ class VisitorCreateFolderController extends Controller
private CreateFolderAction $createFolder,
private ProtectShareRecordAction $protectShareRecord,
private VerifyAccessToItemAction $verifyAccessToItem,
private FakeCreateFolderAction $fakeCreateFolderAction,
private FakeCreateFolderAction $fakeCreateFolder,
) {
}
@@ -28,7 +30,9 @@ class VisitorCreateFolderController extends Controller
Share $shared,
): Response | array {
if (is_demo_account()) {
return ($this->fakeCreateFolderAction)($request);
$fakeFolder = ($this->fakeCreateFolder)($request);
return response(new FolderResource($fakeFolder), 201);
}
// Check ability to access protected share record
@@ -42,9 +46,18 @@ class VisitorCreateFolderController extends Controller
// Check access to requested directory
($this->verifyAccessToItem)($request->parent_id, $shared);
// Create folder
$folder = ($this->createFolder)($request, $shared);
try {
// Create new folder
$folder = ($this->createFolder)($request, $shared);
return response($folder, 201);
// Return new folder
return response(new FolderResource($folder), 201);
} catch (InvalidUserActionException $e) {
// Return error response
return response([
'type' => 'error',
'message' => $e->getMessage(),
], 401);
}
}
}

View File

@@ -85,4 +85,24 @@ class DefaultLimitationTest extends TestCase
$this->assertEquals(1, $user->limitations->max_storage_amount);
$this->assertEquals(false, $user->canUpload(999999999));
}
/**
* @test
*/
public function it_can_create_new_folder()
{
$user = User::factory()
->create();
$this
->actingAs($user)
->postJson('/api/create-folder', [
'name' => 'New Folder',
])
->assertStatus(201);
$this->assertDatabaseHas('folders', [
'name' => 'New Folder',
]);
}
}

View File

@@ -46,4 +46,24 @@ class FixedBillingLimitationTest extends TestCase
$this->assertEquals(false, $user->canUpload(999999999));
}
/**
* @test
*/
public function it_can_create_new_folder()
{
$user = User::factory()
->create();
$this
->actingAs($user)
->postJson('/api/create-folder', [
'name' => 'New Folder',
])
->assertStatus(201);
$this->assertDatabaseHas('folders', [
'name' => 'New Folder',
]);
}
}

View File

@@ -40,4 +40,45 @@ class MeteredBillingLimitationTest extends TestCase
$this->assertEquals(false, $user->canUpload());
}
/**
* @test
*/
public function it_can_create_new_folder()
{
$user = User::factory()
->create();
$this
->actingAs($user)
->postJson('/api/create-folder', [
'name' => 'New Folder',
])
->assertStatus(201);
$this->assertDatabaseHas('folders', [
'name' => 'New Folder',
]);
}
/**
* @test
*/
public function it_cant_create_new_folder_because_user_has_3_failed_payments()
{
$user = User::factory()
->hasFailedpayments(3)
->create();
$this
->actingAs($user)
->postJson('/api/create-folder', [
'name' => 'New Folder',
])
->assertStatus(401);
$this->assertDatabaseMissing('folders', [
'name' => 'New Folder',
]);
}
}

View File

@@ -126,7 +126,7 @@ class FileTest extends TestCase
'file' => $file,
'parent_id' => null,
'is_last' => 'true',
])->assertStatus(423);
])->assertStatus(401);
Storage::disk('local')->assertMissing(
"files/$user->id/fake-file.jpeg"