UI improvements part 2

This commit is contained in:
Čarodej
2022-01-27 13:14:57 +01:00
parent a2726ae2c5
commit d855739bf2
30 changed files with 268 additions and 93 deletions

View File

@@ -399,7 +399,7 @@ return [
'global.total' => 'Total',
'input_image.supported' => 'Supported formats are .png, .jpg, .jpeg.',
'input_image.title' => 'Upload Image',
'inputs.placeholder_search_files' => 'Search for anything...',
'inputs.placeholder_search_files' => 'Search anything...',
'item_thumbnail.deleted_at' => 'Deleted {time}',
'item_thumbnail.original_location' => 'Original Location',
'locations.home' => 'Files',

View File

@@ -2,7 +2,7 @@
"/js/main.js": "/js/main.js",
"/css/app.css": "/css/app.css",
"/css/tailwind.css": "/css/tailwind.css",
"/chunks/admin.js": "/chunks/admin.js?id=88821c570ece7a4835c8",
"/chunks/admin.js": "/chunks/admin.js?id=de73ccab1ced122c79f9",
"/chunks/admin-account.js": "/chunks/admin-account.js?id=6e28465565ea92af804f",
"/chunks/admin-account~chunks/app-appearance~chunks/app-email~chunks/app-index~chunks/app-setup~chunks~ba362dfc.js": "/chunks/admin-account~chunks/app-appearance~chunks/app-email~chunks/app-index~chunks/app-setup~chunks~ba362dfc.js?id=f1db11992a10d86198ae",
"/chunks/admin-account~chunks/app-setup~chunks/billings-detail~chunks/create-new-password~chunks/datab~a2d1c36e.js": "/chunks/admin-account~chunks/app-setup~chunks/billings-detail~chunks/create-new-password~chunks/datab~a2d1c36e.js?id=bbdda6115aa358c2209e",
@@ -12,7 +12,7 @@
"/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~673d1ac3.js": "/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~673d1ac3.js?id=34845d890e9e65d2adc0",
"/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~97130d1f.js": "/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~97130d1f.js?id=8da02dcc87f434aca532",
"/chunks/admin~chunks/platform~chunks/settings.js": "/chunks/admin~chunks/platform~chunks/settings.js?id=457420de4eafe9f1c5d3",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.js?id=c7550917d07310acecff",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.js?id=d70888d9345ad027bff8",
"/chunks/admin~chunks/platform~chunks/shared.js": "/chunks/admin~chunks/platform~chunks/shared.js?id=3e732ede912619794ed9",
"/chunks/app-appearance.js": "/chunks/app-appearance.js?id=f320fe6298f15a06d573",
"/chunks/app-appearance~chunks/app-email~chunks/app-index~chunks/payments/billings~chunks/payments/set~0dc0a1dd.js": "/chunks/app-appearance~chunks/app-email~chunks/app-index~chunks/payments/billings~chunks/payments/set~0dc0a1dd.js?id=85c3dcde9e03e25b549e",
@@ -39,7 +39,7 @@
"/chunks/dynamic-page.js": "/chunks/dynamic-page.js?id=6c86916c6c6f679fa86b",
"/chunks/email-verified.js": "/chunks/email-verified.js?id=fcba9acf60a855b730d5",
"/chunks/environment-setup.js": "/chunks/environment-setup.js?id=037716aec84bcf2dbd87",
"/chunks/files.js": "/chunks/files.js?id=692eff6c814b00ac7d97",
"/chunks/files.js": "/chunks/files.js?id=34950cf3b0c8f604bf38",
"/chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/shared~chunks/share~c7960950.js": "/chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/shared~chunks/share~c7960950.js?id=f41b30739fcbba3ae537",
"/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~34b5eb22.js": "/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~34b5eb22.js?id=94ead73a2f7abcbc3214",
"/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~bf3ddedc.js": "/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~bf3ddedc.js?id=6489d55d6d88986008c9",
@@ -49,7 +49,7 @@
"/chunks/installation-disclaimer.js": "/chunks/installation-disclaimer.js?id=a38af72f7ea45f34ffb9",
"/chunks/invitation.js": "/chunks/invitation.js?id=ce0aa06dd9c62f505b9b",
"/chunks/invoices.js": "/chunks/invoices.js?id=2a61a6196dc553fe193d",
"/chunks/my-shared-items.js": "/chunks/my-shared-items.js?id=ef0a2dbe808eaee42c1f",
"/chunks/my-shared-items.js": "/chunks/my-shared-items.js?id=782261b00546f4590849",
"/chunks/not-found.js": "/chunks/not-found.js?id=bd6cc309172531900b13",
"/chunks/page-edit.js": "/chunks/page-edit.js?id=5ff141bd6538ec84ecff",
"/chunks/pages.js": "/chunks/pages.js?id=1ce97ecc061c94d203c3",
@@ -69,16 +69,16 @@
"/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=66e964be4ab127b1f723",
"/chunks/profile.js": "/chunks/profile.js?id=f86f4783c664ca19e6ed",
"/chunks/purchase-code.js": "/chunks/purchase-code.js?id=d9af0efad2af2679954b",
"/chunks/recent-uploads.js": "/chunks/recent-uploads.js?id=8577d4c771602671b38a",
"/chunks/settings.js": "/chunks/settings.js?id=2bf24c09d7a7e4e311e3",
"/chunks/recent-uploads.js": "/chunks/recent-uploads.js?id=376eafcf7e98317b5092",
"/chunks/settings.js": "/chunks/settings.js?id=655804d5542f6c3907d5",
"/chunks/settings-password.js": "/chunks/settings-password.js?id=5663c0b40d30395b1800",
"/chunks/settings-storage.js": "/chunks/settings-storage.js?id=03dc91e6eca3401c7264",
"/chunks/setup-wizard.js": "/chunks/setup-wizard.js?id=651d5accf401908724c5",
"/chunks/shared.js": "/chunks/shared.js?id=a140c15b483547b020e9",
"/chunks/shared-with-me.js": "/chunks/shared-with-me.js?id=e38098eca4e38683a83b",
"/chunks/shared-with-me.js": "/chunks/shared-with-me.js?id=5ad15d8de528f9c45157",
"/chunks/shared-with-me~chunks/team-folders.js": "/chunks/shared-with-me~chunks/team-folders.js?id=abf65131397ea2b12355",
"/chunks/shared/authenticate.js": "/chunks/shared/authenticate.js?id=09f54f209289c79ccc33",
"/chunks/shared/files.js": "/chunks/shared/files.js?id=84377b3190940b5196f6",
"/chunks/shared/files.js": "/chunks/shared/files.js?id=d2b2314b1671457be48a",
"/chunks/shared/single-file.js": "/chunks/shared/single-file.js?id=1abb5dd58d0ed626cd6e",
"/chunks/sign-in.js": "/chunks/sign-in.js?id=e716349738364703249e",
"/chunks/sign-up.js": "/chunks/sign-up.js?id=fedc03943b75d930b982",
@@ -87,9 +87,9 @@
"/chunks/subscription-plans.js": "/chunks/subscription-plans.js?id=15d40df6f0b187cf1129",
"/chunks/subscription-service.js": "/chunks/subscription-service.js?id=3fffee3b8bab3e23ba18",
"/chunks/subscriptions.js": "/chunks/subscriptions.js?id=d36f7ea9fc48b0226565",
"/chunks/team-folders.js": "/chunks/team-folders.js?id=d0b1bb2f9e63fa36dd50",
"/chunks/team-folders.js": "/chunks/team-folders.js?id=7ffd359b25ff016da5de",
"/chunks/temporary-unavailable.js": "/chunks/temporary-unavailable.js?id=145f1b0766214eee1aad",
"/chunks/trash.js": "/chunks/trash.js?id=1f5f349fb9ec23ba2e93",
"/chunks/trash.js": "/chunks/trash.js?id=1a2baf87714da126f8f7",
"/chunks/user.js": "/chunks/user.js?id=45f0a820b34424ad3fe9",
"/chunks/user-create.js": "/chunks/user-create.js?id=ec5e0749e0fc93be4664",
"/chunks/user-delete.js": "/chunks/user-delete.js?id=91cd831e23203fd3157c",
@@ -347,5 +347,57 @@
"/chunks/app-language.504629177b6761c98736.hot-update.js": "/chunks/app-language.504629177b6761c98736.hot-update.js",
"/chunks/app-language.92a8a483adc8df63a01a.hot-update.js": "/chunks/app-language.92a8a483adc8df63a01a.hot-update.js",
"/chunks/app-language.3d120b13bef15acb9090.hot-update.js": "/chunks/app-language.3d120b13bef15acb9090.hot-update.js",
"/chunks/app-language.460ec4352b584c67a6d4.hot-update.js": "/chunks/app-language.460ec4352b584c67a6d4.hot-update.js"
"/chunks/app-language.460ec4352b584c67a6d4.hot-update.js": "/chunks/app-language.460ec4352b584c67a6d4.hot-update.js",
"/chunks/admin.aea3f37f694b0ed59df9.hot-update.js": "/chunks/admin.aea3f37f694b0ed59df9.hot-update.js",
"/chunks/admin.9eca60f21105b10f5ba1.hot-update.js": "/chunks/admin.9eca60f21105b10f5ba1.hot-update.js",
"/chunks/settings.2a86b6bb32721c26847c.hot-update.js": "/chunks/settings.2a86b6bb32721c26847c.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.64bc74803ac686236844.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.64bc74803ac686236844.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.8bf61f46a1f5c14faf93.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.8bf61f46a1f5c14faf93.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.1e15dbc93d093e24e1d7.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.1e15dbc93d093e24e1d7.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.0032e84bf50c332eb847.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.0032e84bf50c332eb847.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.78b3544dab4173fc8a42.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.78b3544dab4173fc8a42.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.e6b8c42db873cdfe2ccd.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.e6b8c42db873cdfe2ccd.hot-update.js",
"/chunks/files.94851e6c657d1b2f870c.hot-update.js": "/chunks/files.94851e6c657d1b2f870c.hot-update.js",
"/chunks/files.bcb4fdd736c68a303dce.hot-update.js": "/chunks/files.bcb4fdd736c68a303dce.hot-update.js",
"/chunks/files.58b89e95a2b88f8cb7d6.hot-update.js": "/chunks/files.58b89e95a2b88f8cb7d6.hot-update.js",
"/chunks/files.95859042c75e5ae784b1.hot-update.js": "/chunks/files.95859042c75e5ae784b1.hot-update.js",
"/chunks/files.0ba73302a3f70289643d.hot-update.js": "/chunks/files.0ba73302a3f70289643d.hot-update.js",
"/chunks/files.a5af19f6febc9566408d.hot-update.js": "/chunks/files.a5af19f6febc9566408d.hot-update.js",
"/js/main.062b8801a3a56279b3e7.hot-update.js": "/js/main.062b8801a3a56279b3e7.hot-update.js",
"/js/main.8b87da76ecc0a343f903.hot-update.js": "/js/main.8b87da76ecc0a343f903.hot-update.js",
"/js/main.61df756dc6cbc8f7f986.hot-update.js": "/js/main.61df756dc6cbc8f7f986.hot-update.js",
"/js/main.c72ce546879c4e65b027.hot-update.js": "/js/main.c72ce546879c4e65b027.hot-update.js",
"/js/main.b0160643fa00ebdfd1b0.hot-update.js": "/js/main.b0160643fa00ebdfd1b0.hot-update.js",
"/js/main.1fb5fe7522cbb5e2d7c9.hot-update.js": "/js/main.1fb5fe7522cbb5e2d7c9.hot-update.js",
"/js/main.230eb66a5d86dbc0ed27.hot-update.js": "/js/main.230eb66a5d86dbc0ed27.hot-update.js",
"/js/main.2a9d2199a4d1929950c8.hot-update.js": "/js/main.2a9d2199a4d1929950c8.hot-update.js",
"/js/main.7fd60acd3a251219469b.hot-update.js": "/js/main.7fd60acd3a251219469b.hot-update.js",
"/js/main.8d856d552f4be72be0e3.hot-update.js": "/js/main.8d856d552f4be72be0e3.hot-update.js",
"/js/main.2511dc93f991ae56e07b.hot-update.js": "/js/main.2511dc93f991ae56e07b.hot-update.js",
"/js/main.c5c372824b2d33da7e09.hot-update.js": "/js/main.c5c372824b2d33da7e09.hot-update.js",
"/js/main.ccf5a2288497238447c3.hot-update.js": "/js/main.ccf5a2288497238447c3.hot-update.js",
"/js/main.f90c4343d2960e75b4a8.hot-update.js": "/js/main.f90c4343d2960e75b4a8.hot-update.js",
"/chunks/files.813fa4d730b4dc32cf36.hot-update.js": "/chunks/files.813fa4d730b4dc32cf36.hot-update.js",
"/chunks/my-shared-items.db4e67466ef9527ef443.hot-update.js": "/chunks/my-shared-items.db4e67466ef9527ef443.hot-update.js",
"/chunks/recent-uploads.db4e67466ef9527ef443.hot-update.js": "/chunks/recent-uploads.db4e67466ef9527ef443.hot-update.js",
"/chunks/shared-with-me.db4e67466ef9527ef443.hot-update.js": "/chunks/shared-with-me.db4e67466ef9527ef443.hot-update.js",
"/chunks/shared/files.db4e67466ef9527ef443.hot-update.js": "/chunks/shared/files.db4e67466ef9527ef443.hot-update.js",
"/chunks/team-folders.db4e67466ef9527ef443.hot-update.js": "/chunks/team-folders.db4e67466ef9527ef443.hot-update.js",
"/chunks/trash.db4e67466ef9527ef443.hot-update.js": "/chunks/trash.db4e67466ef9527ef443.hot-update.js",
"/js/main.40e0f100d21dfca78290.hot-update.js": "/js/main.40e0f100d21dfca78290.hot-update.js",
"/js/main.5df103d6e3a7028d60f5.hot-update.js": "/js/main.5df103d6e3a7028d60f5.hot-update.js",
"/js/main.2edd1c2f16d9ad1ff905.hot-update.js": "/js/main.2edd1c2f16d9ad1ff905.hot-update.js",
"/js/main.a2b467f55f6d2a7f08c3.hot-update.js": "/js/main.a2b467f55f6d2a7f08c3.hot-update.js",
"/js/main.4fda0a2e7a0871a74a1c.hot-update.js": "/js/main.4fda0a2e7a0871a74a1c.hot-update.js",
"/js/main.58ebab9fd52ad6e4dd61.hot-update.js": "/js/main.58ebab9fd52ad6e4dd61.hot-update.js",
"/js/main.219e0bfac030c6eceaf3.hot-update.js": "/js/main.219e0bfac030c6eceaf3.hot-update.js",
"/js/main.631f4fd4e5ae2ec555c6.hot-update.js": "/js/main.631f4fd4e5ae2ec555c6.hot-update.js",
"/js/main.cee4ccc7d8c4e4c5e8a8.hot-update.js": "/js/main.cee4ccc7d8c4e4c5e8a8.hot-update.js",
"/js/main.e33e24f9ce88070ae233.hot-update.js": "/js/main.e33e24f9ce88070ae233.hot-update.js",
"/js/main.c61b27f8bdd2027891be.hot-update.js": "/js/main.c61b27f8bdd2027891be.hot-update.js",
"/js/main.19a5a11f2f40dcc50f6d.hot-update.js": "/js/main.19a5a11f2f40dcc50f6d.hot-update.js",
"/js/main.c0c79fc6ab3ea3113995.hot-update.js": "/js/main.c0c79fc6ab3ea3113995.hot-update.js",
"/js/main.866acfdd88418791a158.hot-update.js": "/js/main.866acfdd88418791a158.hot-update.js",
"/js/main.a6730a78442e26530fba.hot-update.js": "/js/main.a6730a78442e26530fba.hot-update.js",
"/js/main.f7c7fe63fce4501b3c61.hot-update.js": "/js/main.f7c7fe63fce4501b3c61.hot-update.js"
}

View File

@@ -76,7 +76,8 @@
<div v-if="actions.length !== 0" class="mb-2">
<div v-for="(result, i) in actions" :key="result.action.value" class="relative">
<div
class="flex items-center px-3.5 py-2.5"
@mousedown="openAction(result)"
class="flex items-center px-3.5 py-2.5 cursor-pointer"
:class="{'dark:bg-4x-dark-foreground bg-light-background rounded-xl': i === index}"
>
<settings-icon v-if="['AppOthers', 'Profile', 'Password'].includes(result.action.value)" size="18" class="vue-feather text-theme"/>

View File

@@ -36,7 +36,7 @@ const itemHelpers = {
})
}
Vue.prototype.$downloadSelection = function (item) {
Vue.prototype.$downloadSelection = function (item = undefined) {
// Show alert message when download is disabled
if (! store.getters.user.data.meta.restrictions.canDownload) {
Vue.prototype.$temporarilyDisabledDownload()
@@ -44,12 +44,25 @@ const itemHelpers = {
return
}
// Download folder zip
if (item && item.data.type === 'folder') {
store.dispatch('downloadZip', item)
return
}
// Download single item
if (item && item.data.type !== 'folder') {
Vue.prototype.$downloadFile(item.data.attributes.file_url, item.data.attributes.name + '.' + item.data.attributes.mimetype)
return
}
// Download selection
let clipboard = store.getters.clipboard
if (clipboard.length > 1 || (clipboard.length === 1 && clipboard[0].data.type === 'folder'))
if (clipboard.length > 1 || (clipboard.length === 1 && clipboard[0].data.type === 'folder')) {
store.dispatch('downloadZip')
else {
Vue.prototype.$downloadFile(item.data.attributes.file_url, item.data.attributes.name + '.' + item.data.attributes.mimetype)
}
}

View File

@@ -14,25 +14,31 @@ const defaultState = {
}
const actions = {
downloadZip: ({getters}) => {
downloadZip: ({getters}, item = undefined) => {
let files = []
// get ids of selected files
getters.clipboard.forEach(file => {
let type = file.data.type === 'folder'
? 'folder'
: 'file'
// Get if from retrieved item
if (item) {
files.push(item.data.id + '|folder')
}
files.push(file.data.id + '|' + type)
})
// Get ids of selected files
if (! item) {
getters.clipboard.forEach(file => {
let type = file.data.type === 'folder'
? 'folder'
: 'file'
let items = files.join(',')
files.push(file.data.id + '|' + type)
})
}
// Get route
let route = getters.sharedDetail
? `/api/zip/${router.currentRoute.params.token}?items=${items}`
: `/api/zip?items=${items}`
? `/api/zip/${router.currentRoute.params.token}?items=${files.join(',')}`
: `/api/zip?items=${files.join(',')}`
// Download zip
Vue.prototype.$downloadFile(route, 'files.zip')
},
moveItem: ({commit, getters, dispatch}, {to_item, noSelectedItem}) => {

View File

@@ -38,7 +38,7 @@
</ContentGroup>
</ContentSidebar>
<router-view class="md:px-6 px-2.5 w-full overflow-x-hidden relative lg:pt-6" />
<router-view class="lg:pt-6 md:px-6 px-2.5 lg:pb-0 pb-12 w-full overflow-x-hidden relative" />
</div>
</template>

View File

@@ -76,7 +76,7 @@
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
</OptionGroup>
<OptionGroup>
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
</OptionGroup>
</template>
</ContextMenu>

View File

@@ -27,7 +27,7 @@
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
</OptionGroup>
<OptionGroup>
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
</OptionGroup>
</template>
</ContextMenu>

View File

@@ -68,7 +68,7 @@
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
</OptionGroup>
<OptionGroup>
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
</OptionGroup>
</template>
</ContextMenu>

View File

@@ -22,7 +22,7 @@
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
</OptionGroup>
<OptionGroup>
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
</OptionGroup>
</template>
</ContextMenu>

View File

@@ -62,7 +62,7 @@
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
</OptionGroup>
<OptionGroup>
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
</OptionGroup>
</template>
</ContextMenu>

View File

@@ -84,7 +84,7 @@
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
</OptionGroup>
<OptionGroup>
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
</OptionGroup>
</template>
</ContextMenu>

View File

@@ -26,7 +26,7 @@
<Option @click.native="$emptyTrash" :title="$t('context_menu.empty_trash')" icon="empty-trash" />
</OptionGroup>
<OptionGroup>
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
</OptionGroup>
</template>
</ContextMenu>

View File

@@ -26,7 +26,7 @@
<MobileNavigationToolbar />
<div v-if="user" class="md:px-6 px-2.5 w-full overflow-x-hidden relative lg:pt-6 xl:max-w-screen-lg md:max-w-4xl mx-auto">
<div v-if="user" class="lg:pt-6 md:px-6 px-2.5 lg:pb-0 pb-12 w-full overflow-x-hidden relative xl:max-w-screen-lg md:max-w-4xl mx-auto">
<div v-if="! isLoading" id="page-content">
<div class="card shadow-card sticky top-0 z-10" style="padding-bottom: 0">

View File

@@ -11,15 +11,15 @@ use Domain\Admin\Controllers\Dashboard\GetNewbiesController;
use Domain\Admin\Controllers\Users\ChangeUserRoleController;
use Domain\Settings\Controllers\UpdateSettingValueController;
use Domain\Admin\Controllers\Users\ResetUserPasswordController;
use Domain\Transactions\Controllers\GetAllTransactionsController;
use Domain\Admin\Controllers\Dashboard\GetDashboardDataController;
use Domain\Transactions\Controllers\GetUserTransactionsController;
use Domain\Localization\Controllers\UpdateLanguageStringController;
use Domain\Admin\Controllers\Users\ShowUserStorageCapacityController;
use Domain\Admin\Controllers\Dashboard\GetLatestTransactionsController;
use Domain\Admin\Controllers\Users\ChangeUserStorageCapacityController;
use Domain\Settings\Controllers\StoreSocialServiceCredentialsController;
use Domain\Settings\Controllers\StorePaymentServiceCredentialsController;
use Domain\Transactions\Controllers\GetAllTransactionsController;
use Domain\Transactions\Controllers\GetUserTransactionsController;
// Dashboard
Route::group(['prefix' => 'dashboard'], function () {

View File

@@ -38,7 +38,7 @@ class AuthServiceProvider extends ServiceProvider
Gate::define($ability, function (?User $user, File | Folder $item, ?Share $share) use ($ability) {
// If share link exist, then check share access
if ($share) {
return $this->share_guard($share, $item);
return $this->shareGuard($share, $item);
}
// Check user owner status
@@ -47,7 +47,7 @@ class AuthServiceProvider extends ServiceProvider
}
// Check team member ability to access into requested item
return $this->team_member_guard($item, $user, $ability);
return $this->teamMemberGuard($item, $user, $ability);
});
});
@@ -58,9 +58,9 @@ class AuthServiceProvider extends ServiceProvider
});
}
private function share_guard(Share $share, Folder | File $item): bool
private function shareGuard(Share $share, Folder | File $item): bool
{
if (! $share->is_protected && $share->user_id === $item->user_id) {
if (! $share->is_protected) {
return true;
}
@@ -86,7 +86,7 @@ class AuthServiceProvider extends ServiceProvider
return $share->user_id === $item->user_id;
}
private function team_member_guard(Folder | File $item, ?User $user, $ability): bool
private function teamMemberGuard(Folder | File $item, ?User $user, $ability): bool
{
$teamFolder = $item->getLatestParent();

View File

@@ -4,8 +4,8 @@ namespace App\Users\Requests;
use App\Users\Rules\EmailProvider;
use App\Users\Rules\ReCaptchaRules;
use Illuminate\Foundation\Http\FormRequest;
use App\Users\Rules\PasswordValidationRules;
use Illuminate\Validation\Rules\RequiredIf;
use App\Users\Rules\PasswordValidationRules;
class RegisterUserRequest extends FormRequest
{
@@ -29,10 +29,10 @@ class RegisterUserRequest extends FormRequest
public function rules()
{
return [
'email' => ['required', 'string', 'email', 'max:255', 'unique:users,email', new EmailProvider],
'name' => 'required|string|max:255',
'password' => $this->passwordRules(),
'reCaptcha' => [new RequiredIf(get_settings('allowed_recaptcha') == 1), 'string', app(ReCaptchaRules::class)]
'email' => ['required', 'string', 'email', 'max:255', 'unique:users,email', new EmailProvider],
'name' => 'required|string|max:255',
'password' => $this->passwordRules(),
'reCaptcha' => [new RequiredIf(get_settings('allowed_recaptcha') == 1), 'string', app(ReCaptchaRules::class)],
];
}
}

View File

@@ -1,7 +1,6 @@
<?php
namespace App\Users\Rules;
use GuzzleHttp\Client;
use Illuminate\Contracts\Validation\Rule;
@@ -17,16 +16,17 @@ class ReCaptchaRules implements Rule
public function passes($attribute, $value)
{
$client = new Client();
$response = $client->post('https://www.google.com/recaptcha/api/siteverify',
$response = $client->post(
'https://www.google.com/recaptcha/api/siteverify',
[
'form_params' => [
'secret' => env('RECAPTCHA_CLIENT_SECRET', false),
'secret' => env('RECAPTCHA_CLIENT_SECRET', false),
'remoteip' => request()->getClientIp(),
'response' => $value
]
'response' => $value,
],
]
);
$body = json_decode((string)$response->getBody());
$body = json_decode((string) $response->getBody());
return $body->success;
}
@@ -35,4 +35,4 @@ class ReCaptchaRules implements Rule
{
return 'Are you a robot?';
}
}
}

View File

@@ -1,5 +1,4 @@
<?php
namespace Domain\Files\Actions;
use Domain\Folders\Models\Folder;

View File

@@ -25,9 +25,9 @@ class SendContactMessageRequest extends FormRequest
public function rules()
{
return [
'email' => 'required|email',
'message' => 'required|string',
'reCaptcha' => [new RequiredIf(get_settings('allowed_recaptcha') == 1), 'string', app(ReCaptchaRules::class)]
'email' => 'required|email',
'message' => 'required|string',
'reCaptcha' => [new RequiredIf(get_settings('allowed_recaptcha') == 1), 'string', app(ReCaptchaRules::class)],
];
}
}

View File

@@ -27,7 +27,7 @@ class StoreSocialServiceCredentialsController
if (! app()->runningUnitTests()) {
$credentials = [
'facebook' => [
'FACEBOOK_CLIENT_ID' => $request->input('client_id'),
'FACEBOOK_CLIENT_ID' => $request->input('client_id'),
'FACEBOOK_CLIENT_SECRET' => $request->input('client_secret'),
],
'google' => [
@@ -42,7 +42,6 @@ class StoreSocialServiceCredentialsController
'RECAPTCHA_CLIENT_ID' => $request->input('client_id'),
'RECAPTCHA_CLIENT_SECRET' => $request->input('client_secret'),
],
];
// Store credentials into the .env file

View File

@@ -1,8 +1,8 @@
<?php
namespace Domain\Transactions\Controllers;
use App\Http\Controllers\Controller;
use App\Users\Models\User;
use App\Http\Controllers\Controller;
use Domain\Transactions\Resources\TransactionCollection;
class GetUserTransactionsController extends Controller

View File

@@ -6,9 +6,8 @@ use Domain\Folders\Models\Folder;
class GetItemsListFromUrlParamAction
{
public function __invoke(
string $user_id
): array {
public function __invoke(): array
{
$list = explode(',', request()->get('items'));
$itemList = collect($list)
@@ -29,12 +28,10 @@ class GetItemsListFromUrlParamAction
->where('type', 'file')
->pluck('id');
$folders = Folder::whereUserId($user_id)
->whereIn('id', $folderIds)
$folders = Folder::whereIn('id', $folderIds)
->get();
$files = File::whereUserId($user_id)
->whereIn('id', $fileIds)
$files = File::whereIn('id', $fileIds)
->get();
return [$folders, $files];

View File

@@ -1,12 +1,12 @@
<?php
namespace Domain\Zip\Actions;
use Gate;
use ZipStream\ZipStream;
use Illuminate\Support\Str;
use Domain\Sharing\Models\Share;
use Domain\Folders\Models\Folder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use STS\ZipStream\ZipStreamFacade as Zip;
@@ -17,9 +17,6 @@ class ZipAction
Collection $files,
?Share $shared = null
): ZipStream {
// Get user id
$user_id = Auth::id() ?? $shared->user_id;
// Get zip name from single requested folder
if ($files->isEmpty() && $folders->count() === 1) {
$zipName = Str::slug($folders->first()->name) . '.zip';
@@ -29,7 +26,12 @@ class ZipAction
$zip = Zip::create($zipName ?? 'files.zip');
// Zip Files
$files->map(function ($file) use ($zip) {
$files->map(function ($file) use ($zip, $shared) {
// Check user privileges to the file
if (! Gate::any(['can-edit', 'can-view'], [$file, $shared])) {
abort(403, 'Access Denied');
}
// get file path
$filePath = "files/$file->user_id/$file->basename";
@@ -50,11 +52,15 @@ class ZipAction
});
// Zip Folders
$folders->map(function ($folder) use ($zip, $user_id) {
$folders->map(function ($folder) use ($zip, $shared) {
// Check user privileges to the folder
if (! Gate::any(['can-edit', 'can-view'], [$folder, $shared])) {
abort(403, 'Access Denied');
}
// Get folder
$requested_folder = Folder::with(['folders.files', 'files'])
->where('id', $folder->id)
->where('user_id', $user_id)
->with('folders')
->first();
@@ -62,7 +68,7 @@ class ZipAction
foreach ($folderFiles as $file) {
// get file path
$filePath = "files/$user_id/{$file['basename']}";
$filePath = "files/{$file['user_id']}/{$file['basename']}";
// Add file into zip
if (Storage::exists($filePath)) {

View File

@@ -27,10 +27,7 @@ class VisitorZipController extends Controller
Request $request,
Share $shared,
): ZipStream {
// Check ability to access protected share record
($this->protectShareRecord)($shared);
list($folders, $files) = ($this->getItemsListFromUrlParam)($shared->user_id);
list($folders, $files) = ($this->getItemsListFromUrlParam)();
// Check access to requested folders
if ($folders->isNotEmpty()) {

View File

@@ -21,7 +21,7 @@ class ZipController extends Controller
Request $request,
): ZipStream {
// Get list of folders and files from requested url parameter
list($folders, $files) = ($this->getItemsListFromUrlParam)(auth()->id());
list($folders, $files) = ($this->getItemsListFromUrlParam)();
// Zip items
$zip = ($this->zip)($folders, $files);

View File

@@ -913,13 +913,8 @@ if (! function_exists('remove_accents')) {
if (! function_exists('get_files_for_zip')) {
/**
* Get all files from folder and get their folder location in VueFileManager directories
*
* @param $folders
* @param null $files
* @param array $path
* @return array
*/
function get_files_for_zip($folders, $files, $path = [])
function get_files_for_zip($folders, $files, array $path = []): array
{
// Return file list
if (! isset($folders->folders)) {
@@ -933,6 +928,7 @@ if (! function_exists('get_files_for_zip')) {
$folders->files->each(function ($file) use ($files, $path) {
$files->push([
'name' => $file->name,
'user_id' => $file->user_id,
'basename' => $file->basename,
'mimetype' => $file->mimetype,
'folder_path' => implode('/', $path),

View File

@@ -335,7 +335,6 @@ class SignFlowTest extends TestCase
*/
public function it_create_user_from_register_form_with_reCaptcha()
{
Setting::updateOrCreate([
'name' => 'allowed_recaptcha',
], [
@@ -351,7 +350,7 @@ class SignFlowTest extends TestCase
'password' => 'SecretPassword',
'password_confirmation' => 'SecretPassword',
'name' => 'John Doe',
'reCaptcha' => 'fakeToken'
'reCaptcha' => 'fakeToken',
])->assertStatus(201);
$this

View File

@@ -174,7 +174,7 @@ class SettingsTest extends TestCase
])->assertStatus(204);
$this->assertDatabaseHas('settings', [
'name' => 'allowed_facebook_login',
'name' => 'allowed_facebook',
'value' => 1,
]);
}

View File

@@ -0,0 +1,110 @@
<?php
namespace Tests\Domain\Teams;
use Tests\TestCase;
use App\Users\Models\User;
use Domain\Files\Models\File;
use Domain\Folders\Models\Folder;
use Illuminate\Http\UploadedFile;
use Domain\Teams\Models\TeamFolderMember;
class TeamFileAccessTest extends TestCase
{
/**
* @test
*/
public function team_member_download_folder_as_zip()
{
$user = User::factory()
->hasSettings()
->create();
$folder = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
]);
collect([0, 1])
->each(function ($index) use ($folder, $user) {
$file = UploadedFile::fake()
->create("fake-file-$index.pdf", 1200, 'application/pdf');
$this
->actingAs($user)
->postJson('/api/upload', [
'filename' => $file->name,
'file' => $file,
'parent_id' => $folder->id,
'path' => '/' . $file->name,
'is_last' => 'true',
])->assertStatus(201);
});
$member = User::factory()
->hasSettings()
->create();
// Attach user into members
TeamFolderMember::create([
'parent_id' => $folder->id,
'user_id' => $member->id,
'permission' => 'can-edit',
]);
$this
->actingAs($member)
->getJson("/api/zip?items=$folder->id|folder")
->assertStatus(200)
->assertHeader('content-type', 'application/x-zip');
}
/**
* @test
*/
public function team_member_download_files_as_zip()
{
$user = User::factory()
->hasSettings()
->create();
$folder = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
]);
collect([0, 1])
->each(function ($index) use ($folder, $user) {
$file = UploadedFile::fake()
->create("fake-file-$index.pdf", 1200, 'application/pdf');
$this
->actingAs($user)
->postJson('/api/upload', [
'filename' => $file->name,
'file' => $file,
'parent_id' => $folder->id,
'path' => '/' . $file->name,
'is_last' => 'true',
])->assertStatus(201);
});
$member = User::factory()
->hasSettings()
->create();
// Attach user into members
TeamFolderMember::create([
'parent_id' => $folder->id,
'user_id' => $member->id,
'permission' => 'can-edit',
]);
$files = File::all();
$this
->actingAs($member)
->getJson("/api/zip?items={$files->first()->id}|file,{$files->last()->id}|file")
->assertStatus(200)
->assertHeader('content-type', 'application/x-zip');
}
}