diff --git a/.editorconfig b/.editorconfig
index 96f12c245..900affc07 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -112,8 +112,8 @@ ij_twig_spaces_inside_delimiters = true
ij_twig_spaces_inside_variable_delimiters = true
[*.vue]
-indent_size = 2
-tab_width = 2
+indent_size = 4
+tab_width = 4
ij_continuation_indent_size = 4
ij_vue_indent_children_of_top_level = template
ij_vue_interpolation_new_line_after_start_delimiter = true
diff --git a/composer.json b/composer.json
index d9baed66a..170de2f0b 100644
--- a/composer.json
+++ b/composer.json
@@ -61,6 +61,7 @@
"rlanvin/php-ip": "^2.0",
"slim/http": "^1.1",
"slim/slim": "^4.2",
+ "spatie/flysystem-dropbox": "^1.2",
"spomky-labs/otphp": "^10.0",
"studio24/rotate": "^1.0",
"supervisorphp/supervisor": "^4.0",
diff --git a/composer.lock b/composer.lock
index da06688c3..05733b5ca 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "4263a5e17fbc52e04124cf01942ac114",
+ "content-hash": "2b94440b6187319760f97ecc2633bfc4",
"packages": [
{
"name": "aws/aws-sdk-php",
@@ -2422,6 +2422,69 @@
},
"time": "2019-11-13T10:30:21+00:00"
},
+ {
+ "name": "graham-campbell/guzzle-factory",
+ "version": "v4.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/GrahamCampbell/Guzzle-Factory.git",
+ "reference": "1f4d65962051284c4ecf6e29b710178f5d7ce75a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/GrahamCampbell/Guzzle-Factory/zipball/1f4d65962051284c4ecf6e29b710178f5d7ce75a",
+ "reference": "1f4d65962051284c4ecf6e29b710178f5d7ce75a",
+ "shasum": ""
+ },
+ "require": {
+ "guzzlehttp/guzzle": "^7.2",
+ "php": "^7.2.5 || ^8.0"
+ },
+ "require-dev": {
+ "graham-campbell/analyzer": "^3.0.4",
+ "phpunit/phpunit": "^8.5.8 || ^9.3.7"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "GrahamCampbell\\GuzzleFactory\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "graham@alt-three.com"
+ }
+ ],
+ "description": "Provides A Simple Guzzle Factory With Good Defaults",
+ "keywords": [
+ "Graham Campbell",
+ "GrahamCampbell",
+ "Guzzle",
+ "Guzzle Factory",
+ "Guzzle-Factory",
+ "http"
+ ],
+ "support": {
+ "issues": "https://github.com/GrahamCampbell/Guzzle-Factory/issues",
+ "source": "https://github.com/GrahamCampbell/Guzzle-Factory/tree/v4.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/graham-campbell/guzzle-factory",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-10-21T19:51:51+00:00"
+ },
{
"name": "guzzlehttp/guzzle",
"version": "7.2.0",
@@ -5965,6 +6028,123 @@
],
"time": "2020-12-01T19:41:22+00:00"
},
+ {
+ "name": "spatie/dropbox-api",
+ "version": "1.16.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/spatie/dropbox-api.git",
+ "reference": "35e5f546bc4c29df34afa7363086dfcfa3448367"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/spatie/dropbox-api/zipball/35e5f546bc4c29df34afa7363086dfcfa3448367",
+ "reference": "35e5f546bc4c29df34afa7363086dfcfa3448367",
+ "shasum": ""
+ },
+ "require": {
+ "graham-campbell/guzzle-factory": "^3.0||^4.0",
+ "guzzlehttp/guzzle": "^6.2||^7.0",
+ "php": "^7.1||^8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.5.15|^8.5|^9.3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Spatie\\Dropbox\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Alex Vanderbist",
+ "email": "alex.vanderbist@gmail.com",
+ "homepage": "https://spatie.be",
+ "role": "Developer"
+ },
+ {
+ "name": "Freek Van der Herten",
+ "email": "freek@spatie.be",
+ "homepage": "https://spatie.be",
+ "role": "Developer"
+ }
+ ],
+ "description": "A minimal implementation of Dropbox API v2",
+ "homepage": "https://github.com/spatie/dropbox-api",
+ "keywords": [
+ "Dropbox-API",
+ "api",
+ "dropbox",
+ "spatie",
+ "v2"
+ ],
+ "support": {
+ "issues": "https://github.com/spatie/dropbox-api/issues",
+ "source": "https://github.com/spatie/dropbox-api/tree/1.16.1"
+ },
+ "time": "2020-11-27T14:48:37+00:00"
+ },
+ {
+ "name": "spatie/flysystem-dropbox",
+ "version": "1.2.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/spatie/flysystem-dropbox.git",
+ "reference": "8b6b072f217343b875316ca6a4203dd59f04207a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/spatie/flysystem-dropbox/zipball/8b6b072f217343b875316ca6a4203dd59f04207a",
+ "reference": "8b6b072f217343b875316ca6a4203dd59f04207a",
+ "shasum": ""
+ },
+ "require": {
+ "league/flysystem": "^1.0.20",
+ "php": "^7.0 || ^8.0",
+ "spatie/dropbox-api": "^1.1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.11 || ^9.4.3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Spatie\\FlysystemDropbox\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Alex Vanderbist",
+ "email": "alex.vanderbist@gmail.com",
+ "homepage": "https://spatie.be",
+ "role": "Developer"
+ }
+ ],
+ "description": "Flysystem Adapter for the Dropbox v2 API",
+ "homepage": "https://github.com/spatie/flysystem-dropbox",
+ "keywords": [
+ "Flysystem",
+ "api",
+ "dropbox",
+ "flysystem-dropbox",
+ "spatie",
+ "v2"
+ ],
+ "support": {
+ "issues": "https://github.com/spatie/flysystem-dropbox/issues",
+ "source": "https://github.com/spatie/flysystem-dropbox/tree/1.2.3"
+ },
+ "time": "2020-11-28T22:17:09+00:00"
+ },
{
"name": "spomky-labs/otphp",
"version": "v10.0.1",
diff --git a/frontend/vue/admin_storage_locations/StorageLocationEditModal.vue b/frontend/vue/admin_storage_locations/StorageLocationEditModal.vue
index d452a9d3e..b0721e3b1 100644
--- a/frontend/vue/admin_storage_locations/StorageLocationEditModal.vue
+++ b/frontend/vue/admin_storage_locations/StorageLocationEditModal.vue
@@ -69,6 +69,18 @@ export default {
validations.form.s3Version = {};
validations.form.s3Bucket = {};
validations.form.s3Endpoint = {};
+ validations.form.dropboxAuthToken = {};
+ break;
+
+ case 'dropbox':
+ validations.form.path = {};
+ validations.form.s3CredentialKey = {};
+ validations.form.s3CredentialSecret = {};
+ validations.form.s3Region = {};
+ validations.form.s3Version = {};
+ validations.form.s3Bucket = {};
+ validations.form.s3Endpoint = {};
+ validations.form.dropboxAuthToken = { required };
break;
case 's3':
@@ -79,6 +91,7 @@ export default {
validations.form.s3Version = { required };
validations.form.s3Bucket = { required };
validations.form.s3Endpoint = { required };
+ validations.form.dropboxAuthToken = {};
break;
}
@@ -95,6 +108,7 @@ export default {
's3Version': 'latest',
's3Bucket': null,
's3Endpoint': null,
+ 'dropboxAuthToken': null,
'storageQuota': ''
};
},
@@ -126,6 +140,7 @@ export default {
's3Version': d.s3Version,
's3Bucket': d.s3Bucket,
's3Endpoint': d.s3Endpoint,
+ 'dropboxAuthToken': d.dropboxAuthToken,
'storageQuota': d.storageQuota
};
diff --git a/frontend/vue/admin_storage_locations/form/StorageLocationForm.vue b/frontend/vue/admin_storage_locations/form/StorageLocationForm.vue
index 731c0b9ce..bdf79ab9e 100644
--- a/frontend/vue/admin_storage_locations/form/StorageLocationForm.vue
+++ b/frontend/vue/admin_storage_locations/form/StorageLocationForm.vue
@@ -14,6 +14,9 @@
Remote: S3 Compatible
+
+ Remote: Dropbox
+
@@ -133,6 +136,31 @@
+
+
+
+
+
+
+
+
+ Dropbox Auth Token
+
+
+
+
+ This field is required.
+
+
+
+
+
+
diff --git a/src/Entity/Migration/Version20201208185538.php b/src/Entity/Migration/Version20201208185538.php
new file mode 100644
index 000000000..14efd9a7b
--- /dev/null
+++ b/src/Entity/Migration/Version20201208185538.php
@@ -0,0 +1,30 @@
+addSql('ALTER TABLE api_keys CHANGE user_id user_id INT DEFAULT NULL');
+ $this->addSql('ALTER TABLE storage_location ADD dropbox_auth_token VARCHAR(255) DEFAULT NULL');
+ }
+
+ public function down(Schema $schema): void
+ {
+ // this down() migration is auto-generated, please modify it to your needs
+ $this->addSql('ALTER TABLE api_keys CHANGE user_id user_id INT NOT NULL');
+ $this->addSql('ALTER TABLE storage_location DROP dropbox_auth_token');
+ }
+}
diff --git a/src/Entity/StorageLocation.php b/src/Entity/StorageLocation.php
index 2a500191d..74a4e3324 100644
--- a/src/Entity/StorageLocation.php
+++ b/src/Entity/StorageLocation.php
@@ -17,6 +17,9 @@ use League\Flysystem\Adapter\Local;
use League\Flysystem\AdapterInterface;
use League\Flysystem\AwsS3v3\AwsS3Adapter;
use League\Flysystem\Config;
+use League\Flysystem\Util;
+use Spatie\Dropbox\Client;
+use Spatie\FlysystemDropbox\DropboxAdapter;
use Symfony\Component\Validator\Constraints as Assert;
/**
@@ -36,6 +39,7 @@ class StorageLocation
public const ADAPTER_LOCAL = 'local';
public const ADAPTER_S3 = 's3';
+ public const ADAPTER_DROPBOX = 'dropbox';
/**
* @ORM\Column(name="id", type="integer")
@@ -115,6 +119,13 @@ class StorageLocation
*/
protected $s3Endpoint = null;
+ /**
+ * @ORM\Column(name="dropbox_auth_token", type="string", length=255, nullable=true)
+ *
+ * @var string|null The optional custom S3 endpoint S3 adapters.
+ */
+ protected $dropboxAuthToken = null;
+
/**
* @ORM\Column(name="storage_quota", type="bigint", nullable=true)
*
@@ -249,6 +260,16 @@ class StorageLocation
$this->s3Endpoint = $this->truncateString($s3Endpoint, 255);
}
+ public function getDropboxAuthToken(): ?string
+ {
+ return $this->dropboxAuthToken;
+ }
+
+ public function setDropboxAuthToken(?string $dropboxAuthToken): void
+ {
+ $this->dropboxAuthToken = $dropboxAuthToken;
+ }
+
public function isLocal(): bool
{
return self::ADAPTER_LOCAL === $this->adapter;
@@ -420,6 +441,10 @@ class StorageLocation
}
break;
+ case self::ADAPTER_DROPBOX:
+ return 'dropbox://' . ltrim($path, '/');
+ break;
+
case self::ADAPTER_LOCAL:
default:
return $path;
@@ -449,6 +474,9 @@ class StorageLocation
$client = $this->getS3Client();
return new AwsS3Adapter($client, $this->s3Bucket, $this->path);
+ case self::ADAPTER_DROPBOX:
+ return new DropboxAdapter($this->getDropboxClient(), $this->path);
+
case self::ADAPTER_LOCAL:
default:
return new Local($this->path);
@@ -475,12 +503,26 @@ class StorageLocation
return new S3Client($s3Options);
}
+ protected function getDropboxClient(): Client
+ {
+ if (self::ADAPTER_DROPBOX !== $this->adapter) {
+ throw new \InvalidArgumentException('This storage location is not using the Dropbox adapter.');
+ }
+
+ return new Client($this->dropboxAuthToken);
+ }
+
/**
* @param Config|array|null $config
*
*/
public function getFilesystem($config = null): Filesystem
{
+ $config = Util::ensureConfig($config);
+ if (self::ADAPTER_DROPBOX === $this->adapter) {
+ $config->set('case_sensitive', false);
+ }
+
return new Filesystem($this->getStorageAdapter(), $config);
}
diff --git a/src/Flysystem/FilesystemManager.php b/src/Flysystem/FilesystemManager.php
index a118dff95..5ea68189f 100644
--- a/src/Flysystem/FilesystemManager.php
+++ b/src/Flysystem/FilesystemManager.php
@@ -9,7 +9,9 @@ use League\Flysystem\Adapter\AbstractAdapter;
use League\Flysystem\AdapterInterface;
use League\Flysystem\AwsS3v3\AwsS3Adapter;
use League\Flysystem\Cached\CachedAdapter;
+use League\Flysystem\Config;
use Psr\Cache\CacheItemPoolInterface;
+use Spatie\FlysystemDropbox\DropboxAdapter;
/**
* A wrapper and manager class for accessing assets on the filesystem.
@@ -86,12 +88,17 @@ class FilesystemManager
public function getFilesystemForAdapter(AdapterInterface $adapter, bool $cached = false): Filesystem
{
+ $config = new Config();
+ if ($adapter instanceof DropboxAdapter) {
+ $config->set('case_sensitive', false);
+ }
+
if ($cached) {
$cachedClient = new Psr6Cache($this->cachePool, $this->getCacheKey($adapter), 3600);
$adapter = new CachedAdapter($adapter, $cachedClient);
}
- return new Filesystem($adapter);
+ return new Filesystem($adapter, $config);
}
public function flushCacheForAdapter(AdapterInterface $adapter, bool $inMemoryOnly = false): void