Added chmod perm, modal to change, api with local/ftp/sftp (#399)

Read a fill current permissions for local driver

Finished permissions for ftp driver, read and change

Read permissions for sftp adapter

Created FilegatorFtp for a cleaner permissions integration

Implemented recursive chmod options for files/folders

Modified tests to cover permissions

Lint frontend permissions component
This commit is contained in:
Andrei Telteu
2024-04-17 18:23:21 +03:00
committed by GitHub
parent 42e50b93da
commit 27310f9d48
15 changed files with 431 additions and 13 deletions

View File

@@ -135,6 +135,9 @@
<b-dropdown-item v-if="can(['write', 'zip']) && ! isArchive(props.row)" aria-role="listitem" @click="zip($event, props.row)">
<b-icon icon="file-archive" size="is-small" /> {{ lang('Zip') }}
</b-dropdown-item>
<b-dropdown-item v-if="can(['write', 'chmod']) && props.row.permissions !== -1" aria-role="listitem" @click="chmod($event, props.row)">
<b-icon icon="lock" size="is-small" /> {{ lang('Permissions') }} ({{ props.row.permissions }})
</b-dropdown-item>
<b-dropdown-item v-if="can('write')" aria-role="listitem" @click="remove($event, props.row)">
<b-icon icon="trash-alt" size="is-small" /> {{ lang('Delete') }}
</b-dropdown-item>
@@ -164,6 +167,7 @@
import Vue from 'vue'
import Menu from './partials/Menu'
import Tree from './partials/Tree'
import Permissions from './partials/Permissions'
import Editor from './partials/Editor'
import Gallery from './partials/Gallery'
import Search from './partials/Search'
@@ -491,6 +495,37 @@ export default {
}
})
},
chmod(event, item) {
this.$modal.open({
parent: this,
hasModalCard: true,
component: Permissions,
props: {
name: item.name,
permissions: item.permissions,
isDir: item.type == 'dir',
},
events: {
saved: (permissions, recursive = null) => {
this.isLoading = true
api.chmodItems({
items: item ? [item] : this.getSelected(),
permissions: permissions,
recursive: recursive,
})
.then(() => {
this.isLoading = false
this.loadFiles()
})
.catch(error => {
this.isLoading = false
this.handleError(error)
})
this.checked = []
}
},
})
},
rename(event, item) {
this.$dialog.prompt({
message: this.lang('New name'),

View File

@@ -0,0 +1,143 @@
<template>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">
{{ lang('Change permissions for') }} {{ name }}
</p>
</header>
<section class="modal-card-body">
<div class="columns permission-item" v-for="(typePermissions, type) in table" :key="type">
<div class="column permission-type is-3">
{{ type }}
</div>
<div class="column permission-name is-3" v-for="(value, permission) in typePermissions" :key="permission">
<b-checkbox :value="value" @input="changePermission(type, permission, !value)">
{{ permission }}
</b-checkbox>
</div>
</div>
<div class="columns permission-item">
<div class="column permission-type is-3">
{{ lang('Permissions') }}
</div>
<div class="column permission-type is-3 manual-permission-cell">
<b-field>
<b-input
:value="String(newPermissions).padStart(3, '0')"
@input="v => newPermissions = parseInt(v.slice(-3))"
maxlength="4"
required
/>
</b-field>
</div>
</div>
<div class="columns permission-item" v-if="isDir">
<div class="column permission-type is-3">
{{ lang('Recursive') }}
</div>
<div class="column permission-type is-9">
<b-field>
<b-select v-model="recursive" expanded>
<option :value="null">
{{ lang('No') }}
</option>
<option value="all">
{{ lang('Both folders and files') }}
</option>
<option value="folders">
{{ lang('Apply only for folders') }}
</option>
<option value="files">
{{ lang('Apply only for files') }}
</option>
</b-select>
</b-field>
</div>
</div>
</section>
<footer class="modal-card-foot">
<button class="button" type="button" @click="$parent.close()">
{{ lang('Cancel') }}
</button>
<button class="button is-primary" type="button" @click="$emit('saved', newPermissions, recursive) && $parent.close()">
{{ lang('Save') }}
</button>
</footer>
</div>
</template>
<script>
export default {
name: 'Permissions',
props: ['name', 'permissions', 'isDir'],
data() {
return {
newPermissions: 700,
/** @type {null | 'all' | 'folders' | 'files'} */
recursive: null,
}
},
computed: {
table() {
// credits to ChatGPT for this function
const binary = parseInt(this.newPermissions, 8).toString(2).padStart(9, '0') // Convert octal to binary and pad to 9 digits
return {
owner: {
read: binary[0] === '1',
write: binary[1] === '1',
execute: binary[2] === '1'
},
group: {
read: binary[3] === '1',
write: binary[4] === '1',
execute: binary[5] === '1'
},
other: {
read: binary[6] === '1',
write: binary[7] === '1',
execute: binary[8] === '1'
}
}
}
},
mounted() {
if (this.permissions && this.permissions !== -1) {
this.newPermissions = this.permissions
}
},
methods: {
changePermission(type, permission, on) {
// credits to ChatGPT for this function
let permissionsObject = this.table
permissionsObject[type][permission] = on
let permissions = 0
// Calculate owner permissions
if (permissionsObject.owner.read) permissions += 400
if (permissionsObject.owner.write) permissions += 200
if (permissionsObject.owner.execute) permissions += 100
// Calculate group permissions
if (permissionsObject.group.read) permissions += 40
if (permissionsObject.group.write) permissions += 20
if (permissionsObject.group.execute) permissions += 10
// Calculate other permissions
if (permissionsObject.other.read) permissions += 4
if (permissionsObject.other.write) permissions += 2
if (permissionsObject.other.execute) permissions += 1
this.newPermissions = permissions
return permissions
},
}
}
</script>
<style>
.permission-type {
text-transform: capitalize;
}
.permission-name {
text-transform: capitalize;
}
.manual-permission-cell .help.counter {
display: none;
}
</style>

View File

@@ -56,6 +56,9 @@
<b-checkbox v-model="permissions.zip">
{{ lang('Zip') }}
</b-checkbox>
<b-checkbox v-model="permissions.chmod">
{{ lang('Chmod') }}
</b-checkbox>
</div>
</b-field>
</form>
@@ -96,6 +99,7 @@ export default {
download: _.find(this.user.permissions, p => p == 'download') ? true : false,
batchdownload: _.find(this.user.permissions, p => p == 'batchdownload') ? true : false,
zip: _.find(this.user.permissions, p => p == 'zip') ? true : false,
chmod: _.find(this.user.permissions, p => p == 'chmod') ? true : false,
}
}
},
@@ -107,6 +111,7 @@ export default {
this.permissions.write = false
this.permissions.batchdownload = false
this.permissions.zip = false
this.permissions.chmod = false
}
},
'permissions.write' (val) {
@@ -114,6 +119,7 @@ export default {
this.permissions.read = true
} else {
this.permissions.zip = false
this.permissions.chmod = false
}
},
'permissions.download' (val) {
@@ -133,6 +139,12 @@ export default {
this.permissions.write = true
}
},
'permissions.chmod' (val) {
if (val) {
this.permissions.read = true
this.permissions.write = true
}
},
},
methods: {
selectDir() {