mirror of
https://github.com/filegator/filegator.git
synced 2025-08-06 07:47:44 +02:00
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:
@@ -144,6 +144,20 @@ class FileController
|
||||
return $response->json('Done');
|
||||
}
|
||||
|
||||
public function chmodItems(Request $request, Response $response)
|
||||
{
|
||||
$items = $request->input('items', []);
|
||||
$permissions = $request->input('permissions', 0);
|
||||
/** @var null|'all'|'folders'|'files' */
|
||||
$recursive = $request->input('recursive', null);
|
||||
|
||||
foreach ($items as $item) {
|
||||
$this->storage->chmod($item->path, $permissions, $recursive);
|
||||
}
|
||||
|
||||
return $response->json('Done');
|
||||
}
|
||||
|
||||
public function renameItem(Request $request, Response $response)
|
||||
{
|
||||
$destination = $request->input('destination', $this->separator);
|
||||
|
@@ -138,6 +138,17 @@ return [
|
||||
'read', 'write', 'zip',
|
||||
],
|
||||
],
|
||||
[
|
||||
'route' => [
|
||||
'POST', '/chmoditems', '\Filegator\Controllers\FileController@chmodItems',
|
||||
],
|
||||
'roles' => [
|
||||
'guest', 'user', 'admin',
|
||||
],
|
||||
'permissions' => [
|
||||
'read', 'write', 'chmod',
|
||||
],
|
||||
],
|
||||
[
|
||||
'route' => [
|
||||
'POST', '/deleteitems', '\Filegator\Controllers\FileController@deleteItems',
|
||||
|
@@ -218,7 +218,7 @@ class LDAP implements Service, AuthInterface
|
||||
// ...but not for admins
|
||||
if ($user['role'] == 'admin'){
|
||||
$user['homedir'] = '/';
|
||||
$user['permissions'] = 'read|write|upload|download|batchdownload|zip';
|
||||
$user['permissions'] = 'read|write|upload|download|batchdownload|zip|chmod';
|
||||
}
|
||||
|
||||
if(is_array($user) && !empty($user)) $users[] = $user;
|
||||
|
@@ -24,7 +24,7 @@ class User implements \JsonSerializable
|
||||
|
||||
protected $available_roles = ['guest', 'user', 'admin'];
|
||||
|
||||
protected $available_permissions = ['read', 'write', 'upload', 'download', 'batchdownload', 'zip'];
|
||||
protected $available_permissions = ['read', 'write', 'upload', 'download', 'batchdownload', 'zip', 'chmod'];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
91
backend/Services/Storage/Adapters/FilegatorFtp.php
Normal file
91
backend/Services/Storage/Adapters/FilegatorFtp.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the FileGator package.
|
||||
*
|
||||
* (c) Milos Stojanovic <alcalbg@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE file
|
||||
*/
|
||||
|
||||
namespace Filegator\Services\Storage\Adapters;
|
||||
|
||||
use League\Flysystem\Adapter\Ftp;
|
||||
use League\Flysystem\NotSupportedException;
|
||||
|
||||
class FilegatorFtp extends Ftp
|
||||
{
|
||||
|
||||
/**
|
||||
* Normalize a file entry.
|
||||
*
|
||||
* @param string $item
|
||||
* @param string $base
|
||||
*
|
||||
* @return array normalized file array
|
||||
*
|
||||
* @throws NotSupportedException
|
||||
*/
|
||||
protected function normalizeObject($item, $base)
|
||||
{
|
||||
$systemType = $this->systemType ?: $this->detectSystemType($item);
|
||||
|
||||
if ($systemType === 'unix') {
|
||||
$result = $this->normalizeUnixObject($item, $base);
|
||||
return $this->afterNormalizeUnixObject($result, $item, $base);
|
||||
} elseif ($systemType === 'windows') {
|
||||
$result = $this->normalizeWindowsObject($item, $base);
|
||||
return $this->afterNormalizeWindowsObject($result, $item, $base);
|
||||
}
|
||||
|
||||
throw NotSupportedException::forFtpSystemType($systemType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a Unix file entry, with permissions.
|
||||
*
|
||||
* Given $item contains:
|
||||
* '-rw-r--r-- 1 ftp ftp 409 Aug 19 09:01 file1.txt'
|
||||
*
|
||||
* This function will return:
|
||||
* [
|
||||
* 'type' => 'file',
|
||||
* 'path' => 'file1.txt',
|
||||
* 'visibility' => 'public',
|
||||
* 'size' => 409,
|
||||
* 'timestamp' => 1566205260,
|
||||
* 'permissions' => 644
|
||||
* ]
|
||||
*
|
||||
* @param array $result original normalized file array
|
||||
* @param string $item
|
||||
* @param string $base
|
||||
*
|
||||
* @return array normalized file array
|
||||
*/
|
||||
protected function afterNormalizeUnixObject($result, $item, $base)
|
||||
{
|
||||
$item = preg_replace('#\s+#', ' ', trim($item), 7);
|
||||
list($permissions, /* $number */, /* $owner */, /* $group */, $size, $month, $day, $timeOrYear, $name) = explode(' ', $item, 9);
|
||||
$permissions = $this->normalizePermissions($permissions);
|
||||
|
||||
$result['permissions'] = decoct($permissions);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a Windows/DOS file entry, with permissions.
|
||||
*
|
||||
* @param array $result original normalized file array
|
||||
* @param string $item
|
||||
* @param string $base
|
||||
*
|
||||
* @return array normalized file array
|
||||
*/
|
||||
protected function afterNormalizeWindowsObject($result, $item, $base)
|
||||
{
|
||||
$result['permissions'] = 777;
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
@@ -23,7 +23,7 @@ class DirectoryCollection implements \JsonSerializable
|
||||
$this->location = $location;
|
||||
}
|
||||
|
||||
public function addFile(string $type, string $path, string $name, int $size, int $timestamp)
|
||||
public function addFile(string $type, string $path, string $name, int $size, int $timestamp, int $permissions)
|
||||
{
|
||||
if (! in_array($type, ['dir', 'file', 'back'])) {
|
||||
throw new \Exception('Invalid file type.');
|
||||
@@ -35,6 +35,7 @@ class DirectoryCollection implements \JsonSerializable
|
||||
'name' => $name,
|
||||
'size' => $size,
|
||||
'time' => $timestamp,
|
||||
'permissions' => $permissions,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@@ -12,6 +12,7 @@ namespace Filegator\Services\Storage;
|
||||
|
||||
use Filegator\Services\Service;
|
||||
use League\Flysystem\Filesystem as Flysystem;
|
||||
use League\Flysystem\Util;
|
||||
|
||||
class Filesystem implements Service
|
||||
{
|
||||
@@ -177,6 +178,72 @@ class Filesystem implements Service
|
||||
return $this->storage->putStream($destination, $resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change file permissions one item, with optional recursion
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $permissions
|
||||
* @param null|'all'|'folders'|'files' $recursive
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function chmod(string $path, int $permissions, string $recursive = null)
|
||||
{
|
||||
$path = $this->applyPathPrefix($path);
|
||||
$path = Util::normalizePath($path);
|
||||
$adapter = $this->storage->getAdapter();
|
||||
|
||||
$mainResult = $this->chmodItem($path, $permissions);
|
||||
if ($recursive !== null) {
|
||||
if (method_exists($adapter, 'setRecurseManually')) {
|
||||
$adapter->setRecurseManually(true); // this is needed for ftp driver
|
||||
}
|
||||
$contents = $this->storage->listContents($path, true);
|
||||
foreach ($contents as $item) {
|
||||
try {
|
||||
if ($item['type'] == 'dir' && ($recursive == 'all' || $recursive == 'folders')) {
|
||||
$this->chmodItem($item['path'], $permissions);
|
||||
}
|
||||
if ($item['type'] == 'file' && ($recursive == 'all' || $recursive == 'files')) {
|
||||
$this->chmodItem($item['path'], $permissions);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $mainResult;
|
||||
}
|
||||
/**
|
||||
* Change file permissions for a single item
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $permissions
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function chmodItem(string $path, int $permissions)
|
||||
{
|
||||
$adapter = $this->storage->getAdapter();
|
||||
|
||||
switch (get_class($adapter)) {
|
||||
case 'League\Flysystem\Adapter\Local':
|
||||
$absolutePath = $adapter->applyPathPrefix($path);
|
||||
return chmod($absolutePath, octdec($permissions));
|
||||
break;
|
||||
case 'League\Flysystem\Sftp\SftpAdapter':
|
||||
return $adapter->getConnection()->chmod($path, octdec($permissions));
|
||||
break;
|
||||
case 'Filegator\Services\Storage\Adapters\FilegatorFtp':
|
||||
return ftp_chmod($adapter->getConnection(), octdec($permissions), $path) !== false;
|
||||
break;
|
||||
default:
|
||||
throw new \Exception('Selected adapter does not support unix permissions');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function setPathPrefix(string $path_prefix)
|
||||
{
|
||||
$this->path_prefix = $this->addSeparators($path_prefix);
|
||||
@@ -204,17 +271,40 @@ class Filesystem implements Service
|
||||
$dirname = isset($entry['dirname']) ? $entry['dirname'] : $path;
|
||||
$size = isset($entry['size']) ? $entry['size'] : 0;
|
||||
$timestamp = isset($entry['timestamp']) ? $entry['timestamp'] : 0;
|
||||
$permissions = $this->getPermissions($entry);
|
||||
|
||||
$collection->addFile($entry['type'], $userpath, $name, $size, $timestamp);
|
||||
$collection->addFile($entry['type'], $userpath, $name, $size, $timestamp, $permissions);
|
||||
}
|
||||
|
||||
if (! $recursive && $this->addSeparators($path) !== $this->separator) {
|
||||
$collection->addFile('back', $this->getParent($path), '..', 0, 0);
|
||||
$collection->addFile('back', $this->getParent($path), '..', 0, 0, -1);
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
protected function getPermissions(array $entry): int
|
||||
{
|
||||
$adapter = $this->storage->getAdapter();
|
||||
$path = $entry['path'];
|
||||
|
||||
switch (get_class($adapter)) {
|
||||
case 'League\Flysystem\Adapter\Local':
|
||||
$path = $adapter->applyPathPrefix($path); // get the full path
|
||||
$permissions = substr(sprintf('%o', fileperms($path)), -3);
|
||||
return $permissions;
|
||||
break;
|
||||
case 'League\Flysystem\Sftp\SftpAdapter':
|
||||
$stat = $adapter->getConnection()->stat($path);
|
||||
return $stat && isset($stat['permissions']) ? substr(decoct($stat['permissions']), -3) : -1;
|
||||
break;
|
||||
case 'Filegator\Services\Storage\Adapters\FilegatorFtp':
|
||||
return isset($entry['permissions']) ? $entry['permissions'] : -1;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected function upcountCallback($matches)
|
||||
{
|
||||
$index = isset($matches[1]) ? intval($matches[1]) + 1 : 1;
|
||||
|
@@ -43,7 +43,7 @@ Sample configuration:
|
||||
'separator' => '/',
|
||||
'config' => [],
|
||||
'adapter' => function () {
|
||||
return new \League\Flysystem\Adapter\Ftp([
|
||||
return new \Filegator\Services\Storage\Adapters\FilegatorFtp([
|
||||
'host' => 'example.com',
|
||||
'username' => 'demo',
|
||||
'password' => 'password',
|
||||
|
@@ -119,6 +119,17 @@ const api = {
|
||||
.catch(error => reject(error))
|
||||
})
|
||||
},
|
||||
chmodItems(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.post('chmoditems', {
|
||||
permissions: params.permissions,
|
||||
items: params.items,
|
||||
recursive: params.recursive,
|
||||
})
|
||||
.then(res => resolve(res.data.data))
|
||||
.catch(error => reject(error))
|
||||
})
|
||||
},
|
||||
removeItems(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.post('deleteitems', {
|
||||
|
@@ -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'),
|
||||
|
143
frontend/views/partials/Permissions.vue
Normal file
143
frontend/views/partials/Permissions.vue
Normal 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>
|
@@ -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() {
|
||||
|
@@ -1 +1 @@
|
||||
{"1":{"username":"admin","name":"Admin","role":"admin","homedir":"\/","permissions":"read|write|upload|download|batchdownload|zip","password":"$2y$10$Nu35w4pteLfc7BDCIkDPkecjw8wsH8Y2GMfIewUbXLT7zzW6WOxwq"},"2":{"username":"guest","name":"Guest","role":"guest","homedir":"\/","permissions":"","password":""}}
|
||||
{"1":{"username":"admin","name":"Admin","role":"admin","homedir":"\/","permissions":"read|write|upload|download|batchdownload|zip|chmod","password":"$2y$10$Nu35w4pteLfc7BDCIkDPkecjw8wsH8Y2GMfIewUbXLT7zzW6WOxwq"},"2":{"username":"guest","name":"Guest","role":"guest","homedir":"\/","permissions":"","password":""}}
|
||||
|
@@ -89,17 +89,17 @@ class CollectionTest extends TestCase
|
||||
{
|
||||
$dir = new DirectoryCollection('/sub1/sub2');
|
||||
|
||||
$dir->addFile('back', '/sub1', '..', 0, 1558942228);
|
||||
$dir->addFile('file', '/sub1/sub2/test.txt', 'test.txt', 30000, 1558942228);
|
||||
$dir->addFile('file', '/sub1/sub2/test2.txt', 'test.txt', 30000, 1558942228);
|
||||
$dir->addFile('dir', '/sub1/sub2/sub3', 'sub3', 0, 1558942228);
|
||||
$dir->addFile('back', '/sub1', '..', 0, 1558942228, 644);
|
||||
$dir->addFile('file', '/sub1/sub2/test.txt', 'test.txt', 30000, 1558942228, 644);
|
||||
$dir->addFile('file', '/sub1/sub2/test2.txt', 'test.txt', 30000, 1558942228, 644);
|
||||
$dir->addFile('dir', '/sub1/sub2/sub3', 'sub3', 0, 1558942228, 644);
|
||||
|
||||
$json = json_encode($dir);
|
||||
|
||||
$this->assertEquals('{"location":"\/sub1\/sub2","files":[{"type":"back","path":"\/sub1","name":"..","size":0,"time":1558942228},{"type":"dir","path":"\/sub1\/sub2\/sub3","name":"sub3","size":0,"time":1558942228},{"type":"file","path":"\/sub1\/sub2\/test.txt","name":"test.txt","size":30000,"time":1558942228},{"type":"file","path":"\/sub1\/sub2\/test2.txt","name":"test.txt","size":30000,"time":1558942228}]}', $json);
|
||||
$this->assertEquals('{"location":"\/sub1\/sub2","files":[{"type":"back","path":"\/sub1","name":"..","size":0,"time":1558942228,"permissions":644},{"type":"dir","path":"\/sub1\/sub2\/sub3","name":"sub3","size":0,"time":1558942228,"permissions":644},{"type":"file","path":"\/sub1\/sub2\/test.txt","name":"test.txt","size":30000,"time":1558942228,"permissions":644},{"type":"file","path":"\/sub1\/sub2\/test2.txt","name":"test.txt","size":30000,"time":1558942228,"permissions":644}]}', $json);
|
||||
|
||||
$this->expectException(Exception::class);
|
||||
$dir->addFile('badType', 'aaa', 'aa', 0, 1558942228);
|
||||
$dir->addFile('badType', 'aaa', 'aa', 0, 1558942228, 644);
|
||||
}
|
||||
|
||||
public function testUserCollection()
|
||||
|
@@ -102,6 +102,7 @@ class FilesystemTest extends TestCase
|
||||
'name' => '..',
|
||||
'size' => 0,
|
||||
'time' => 0,
|
||||
'permissions' => -1
|
||||
],
|
||||
],
|
||||
]));
|
||||
@@ -123,6 +124,7 @@ class FilesystemTest extends TestCase
|
||||
'type' => 'back',
|
||||
'path' => '/john',
|
||||
'name' => '..',
|
||||
'permissions' => -1,
|
||||
'size' => 0,
|
||||
'time' => 0,
|
||||
],
|
||||
@@ -130,6 +132,7 @@ class FilesystemTest extends TestCase
|
||||
'type' => 'file',
|
||||
'path' => '/john/johnsub/john2.txt',
|
||||
'name' => 'john2.txt',
|
||||
'permissions' => 644,
|
||||
'size' => 0,
|
||||
'time' => 0,
|
||||
],
|
||||
@@ -153,6 +156,7 @@ class FilesystemTest extends TestCase
|
||||
'type' => 'dir',
|
||||
'path' => '/johnsub',
|
||||
'name' => 'johnsub',
|
||||
'permissions' => 755,
|
||||
'size' => 0,
|
||||
'time' => -1,
|
||||
],
|
||||
@@ -160,6 +164,7 @@ class FilesystemTest extends TestCase
|
||||
'type' => 'file',
|
||||
'path' => '/john.txt',
|
||||
'name' => 'john.txt',
|
||||
'permissions' => 644,
|
||||
'size' => 0,
|
||||
'time' => -1,
|
||||
],
|
||||
@@ -184,6 +189,7 @@ class FilesystemTest extends TestCase
|
||||
'type' => 'back',
|
||||
'path' => '/',
|
||||
'name' => '..',
|
||||
'permissions' => -1,
|
||||
'size' => 0,
|
||||
'time' => 0,
|
||||
],
|
||||
@@ -191,6 +197,7 @@ class FilesystemTest extends TestCase
|
||||
'type' => 'file',
|
||||
'path' => '/johnsub/john2.txt',
|
||||
'name' => 'john2.txt',
|
||||
'permissions' => 644,
|
||||
'size' => 0,
|
||||
'time' => 0,
|
||||
],
|
||||
@@ -859,6 +866,7 @@ class FilesystemTest extends TestCase
|
||||
'type' => 'file',
|
||||
'path' => '/john.txt',
|
||||
'name' => 'john.txt',
|
||||
'permissions' => 644,
|
||||
'size' => 0,
|
||||
'time' => -1,
|
||||
],
|
||||
@@ -874,6 +882,7 @@ class FilesystemTest extends TestCase
|
||||
'type' => 'back',
|
||||
'path' => '/',
|
||||
'name' => '..',
|
||||
'permissions' => -1,
|
||||
'size' => 0,
|
||||
'time' => -1,
|
||||
],
|
||||
@@ -881,6 +890,7 @@ class FilesystemTest extends TestCase
|
||||
'type' => 'file',
|
||||
'path' => '/john.txt',
|
||||
'name' => 'john.txt',
|
||||
'permissions' => 644,
|
||||
'size' => 0,
|
||||
'time' => -1,
|
||||
],
|
||||
|
Reference in New Issue
Block a user