Add SFTP adapter storage location support (#5307)
This commit is contained in:
parent
ab0fee4f78
commit
15f8fffc52
|
@ -14248,5 +14248,5 @@
|
|||
"ext-xmlwriter": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.3.0"
|
||||
"plugin-api-version": "2.1.0"
|
||||
}
|
||||
|
|
|
@ -116,6 +116,9 @@ export default {
|
|||
|
||||
case 'dropbox':
|
||||
return this.$gettext('Remote: Dropbox');
|
||||
|
||||
case 'sftp':
|
||||
return this.$gettext('Remote: SFTP');
|
||||
}
|
||||
},
|
||||
getSpaceUsed(item) {
|
||||
|
|
|
@ -31,42 +31,46 @@ export default {
|
|||
let validations = {
|
||||
form: {
|
||||
'adapter': {required},
|
||||
'storageQuota': {}
|
||||
'storageQuota': {},
|
||||
'path': {},
|
||||
's3CredentialKey': {},
|
||||
's3CredentialSecret': {},
|
||||
's3Region': {},
|
||||
's3Version': {},
|
||||
's3Bucket': {},
|
||||
's3Endpoint': {},
|
||||
'dropboxAuthToken': {},
|
||||
'sftpHost': {},
|
||||
'sftpPort': {},
|
||||
'sftpUsername': {},
|
||||
'sftpPassword': {},
|
||||
'sftpPrivateKey': {},
|
||||
'sftpPrivateKeyPassPhrase': {}
|
||||
}
|
||||
};
|
||||
|
||||
switch (this.form.adapter) {
|
||||
case 'local':
|
||||
validations.form.path = {required};
|
||||
validations.form.s3CredentialKey = {};
|
||||
validations.form.s3CredentialSecret = {};
|
||||
validations.form.s3Region = {};
|
||||
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':
|
||||
validations.form.path = {};
|
||||
validations.form.s3CredentialKey = { required };
|
||||
validations.form.s3CredentialSecret = { required };
|
||||
validations.form.s3Region = { required };
|
||||
validations.form.s3Version = { required };
|
||||
validations.form.s3Bucket = { required };
|
||||
validations.form.s3Endpoint = { required };
|
||||
validations.form.dropboxAuthToken = {};
|
||||
break;
|
||||
|
||||
case 'sftp':
|
||||
validations.form.sftpHost = { required };
|
||||
validations.form.sftpPort = { required };
|
||||
validations.form.sftpUsername = { required };
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -84,6 +88,12 @@ export default {
|
|||
's3Bucket': null,
|
||||
's3Endpoint': null,
|
||||
'dropboxAuthToken': null,
|
||||
'sftpHost': null,
|
||||
'sftpPort': '22',
|
||||
'sftpUsername': null,
|
||||
'sftpPassword': null,
|
||||
'sftpPrivateKey': null,
|
||||
'sftpPrivateKeyPassPhrase': null,
|
||||
'storageQuota': ''
|
||||
};
|
||||
},
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
<b-form-radio value="dropbox">
|
||||
<translate key="lang_form_adapter_dropbox">Remote: Dropbox</translate>
|
||||
</b-form-radio>
|
||||
<b-form-radio value="sftp">
|
||||
<translate key="lang_form_adapter_sftp">Remote: SFTP</translate>
|
||||
</b-form-radio>
|
||||
</b-form-radio-group>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
@ -117,6 +120,61 @@
|
|||
</b-form-group>
|
||||
</b-card-body>
|
||||
</b-card>
|
||||
|
||||
<b-card v-show="form.adapter.$model === 'sftp'" class="mb-3" no-body>
|
||||
<div class="card-header bg-primary-dark">
|
||||
<h2 class="card-title">
|
||||
<translate key="lang_form_adapter_sftp">Remote: SFTP</translate>
|
||||
</h2>
|
||||
</div>
|
||||
<b-card-body>
|
||||
<b-form-group>
|
||||
<b-form-row>
|
||||
<b-wrapped-form-group class="col-md-12 col-lg-6" id="form_edit_sftpHost"
|
||||
:field="form.sftpHost">
|
||||
<template #label="{lang}">
|
||||
<translate :key="lang">SFTP Host</translate>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12 col-lg-6" id="form_edit_sftpPort" input-type="number" min="1" step="1"
|
||||
:field="form.sftpPort">
|
||||
<template #label="{lang}">
|
||||
<translate :key="lang">SFTP Port</translate>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12 col-lg-6" id="form_edit_sftpUsername"
|
||||
:field="form.sftpUsername">
|
||||
<template #label="{lang}">
|
||||
<translate :key="lang">SFTP Username</translate>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12 col-lg-6" id="form_edit_sftpPassword"
|
||||
:field="form.sftpPassword">
|
||||
<template #label="{lang}">
|
||||
<translate :key="lang">SFTP Password</translate>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="form_edit_sftpPrivateKeyPassPhrase"
|
||||
:field="form.sftpPrivateKeyPassPhrase">
|
||||
<template #label="{lang}">
|
||||
<translate :key="lang">SFTP Private Key Pass Phrase</translate>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="form_edit_sftpPrivateKey" input-type="textarea"
|
||||
:field="form.sftpPrivateKey">
|
||||
<template #label="{lang}">
|
||||
<translate :key="lang">SFTP Private Key</translate>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</b-form-row>
|
||||
</b-form-group>
|
||||
</b-card-body>
|
||||
</b-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -74,6 +74,40 @@ class StorageLocation
|
|||
)]
|
||||
public ?string $s3Endpoint = null;
|
||||
|
||||
#[OA\Property(
|
||||
description: 'The host for SFTP adapters',
|
||||
example: '127.0.0.1'
|
||||
)]
|
||||
public ?string $sftpHost = null;
|
||||
|
||||
#[OA\Property(
|
||||
description: 'The username for SFTP adapters',
|
||||
example: 'root'
|
||||
)]
|
||||
public ?string $sftpUsername = null;
|
||||
|
||||
#[OA\Property(
|
||||
description: 'The password for SFTP adapters',
|
||||
example: 'abc123'
|
||||
)]
|
||||
public ?string $sftpPassword = null;
|
||||
|
||||
#[OA\Property(
|
||||
description: 'The port for SFTP adapters',
|
||||
example: 20
|
||||
)]
|
||||
public ?int $sftpPort = null;
|
||||
|
||||
#[OA\Property(
|
||||
description: 'The private key for SFTP adapters'
|
||||
)]
|
||||
public ?string $sftpPrivateKey = null;
|
||||
|
||||
#[OA\Property(
|
||||
description: 'The private key pass phrase for SFTP adapters'
|
||||
)]
|
||||
public ?string $sftpPrivateKeyPassPhrase = null;
|
||||
|
||||
#[OA\Property(example: '50 GB')]
|
||||
public ?string $storageQuota = null;
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ enum StorageLocationAdapters: string
|
|||
case Local = 'local';
|
||||
case S3 = 's3';
|
||||
case Dropbox = 'dropbox';
|
||||
case Sftp = 'sftp';
|
||||
|
||||
public function isLocal(): bool
|
||||
{
|
||||
|
@ -23,6 +24,7 @@ enum StorageLocationAdapters: string
|
|||
self::Local => 'Local',
|
||||
self::S3 => 'S3',
|
||||
self::Dropbox => 'Dropbox',
|
||||
self::Sftp => 'SFTP',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Migration;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20220414214828 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add SFTP details to storage_location table.';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE storage_location ADD sftp_host VARCHAR(255) DEFAULT NULL, ADD sftp_username VARCHAR(255) DEFAULT NULL, ADD sftp_password VARCHAR(255) DEFAULT NULL, ADD sftp_port INT DEFAULT NULL, ADD sftp_private_key LONGTEXT DEFAULT NULL, ADD sftp_private_key_pass_phrase VARCHAR(255) DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE storage_location DROP sftp_host, DROP sftp_username, DROP sftp_password, DROP sftp_port, DROP sftp_private_key, DROP sftp_private_key_pass_phrase');
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ use Azura\Files\Adapter\Dropbox\DropboxAdapter;
|
|||
use Azura\Files\Adapter\ExtendedAdapterInterface;
|
||||
use Azura\Files\Adapter\Local\LocalFilesystemAdapter;
|
||||
use Azura\Files\Adapter\LocalAdapterInterface;
|
||||
use Azura\Files\Adapter\Sftp\SftpAdapter;
|
||||
use Azura\Files\ExtendedFilesystemInterface;
|
||||
use Azura\Files\LocalFilesystem;
|
||||
use Azura\Files\RemoteFilesystem;
|
||||
|
@ -24,6 +25,7 @@ use Doctrine\Common\Collections\ArrayCollection;
|
|||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use InvalidArgumentException;
|
||||
use League\Flysystem\PhpseclibV3\SftpConnectionProvider;
|
||||
use League\Flysystem\UnixVisibility\PortableVisibilityConverter;
|
||||
use League\Flysystem\Visibility;
|
||||
use RuntimeException;
|
||||
|
@ -73,6 +75,24 @@ class StorageLocation implements Stringable, IdentifiableEntityInterface
|
|||
#[ORM\Column(name: 'dropbox_auth_token', length: 255, nullable: true)]
|
||||
protected ?string $dropboxAuthToken = null;
|
||||
|
||||
#[ORM\Column(name: 'sftp_host', length: 255, nullable: true)]
|
||||
protected ?string $sftpHost = null;
|
||||
|
||||
#[ORM\Column(name: 'sftp_username', length: 255, nullable: true)]
|
||||
protected ?string $sftpUsername = null;
|
||||
|
||||
#[ORM\Column(name: 'sftp_password', length: 255, nullable: true)]
|
||||
protected ?string $sftpPassword = null;
|
||||
|
||||
#[ORM\Column(name: 'sftp_port', nullable: true)]
|
||||
protected ?int $sftpPort = null;
|
||||
|
||||
#[ORM\Column(name: 'sftp_private_key', type: 'text', nullable: true)]
|
||||
protected ?string $sftpPrivateKey = null;
|
||||
|
||||
#[ORM\Column(name: 'sftp_private_key_pass_phrase', length: 255, nullable: true)]
|
||||
protected ?string $sftpPrivateKeyPassPhrase = null;
|
||||
|
||||
#[ORM\Column(name: 'storage_quota', type: 'bigint', nullable: true)]
|
||||
protected ?string $storageQuota = null;
|
||||
|
||||
|
@ -217,6 +237,66 @@ class StorageLocation implements Stringable, IdentifiableEntityInterface
|
|||
$this->dropboxAuthToken = $dropboxAuthToken;
|
||||
}
|
||||
|
||||
public function getSftpHost(): ?string
|
||||
{
|
||||
return $this->sftpHost;
|
||||
}
|
||||
|
||||
public function setSftpHost(?string $sftpHost): void
|
||||
{
|
||||
$this->sftpHost = $sftpHost;
|
||||
}
|
||||
|
||||
public function getSftpUsername(): ?string
|
||||
{
|
||||
return $this->sftpUsername;
|
||||
}
|
||||
|
||||
public function setSftpUsername(?string $sftpUsername): void
|
||||
{
|
||||
$this->sftpUsername = $sftpUsername;
|
||||
}
|
||||
|
||||
public function getSftpPassword(): ?string
|
||||
{
|
||||
return $this->sftpPassword;
|
||||
}
|
||||
|
||||
public function setSftpPassword(?string $sftpPassword): void
|
||||
{
|
||||
$this->sftpPassword = $sftpPassword;
|
||||
}
|
||||
|
||||
public function getSftpPort(): ?int
|
||||
{
|
||||
return $this->sftpPort;
|
||||
}
|
||||
|
||||
public function setSftpPort(?int $sftpPort): void
|
||||
{
|
||||
$this->sftpPort = $sftpPort;
|
||||
}
|
||||
|
||||
public function getSftpPrivateKey(): ?string
|
||||
{
|
||||
return $this->sftpPrivateKey;
|
||||
}
|
||||
|
||||
public function setSftpPrivateKey(?string $sftpPrivateKey): void
|
||||
{
|
||||
$this->sftpPrivateKey = $sftpPrivateKey;
|
||||
}
|
||||
|
||||
public function getSftpPrivateKeyPassPhrase(): ?string
|
||||
{
|
||||
return $this->sftpPrivateKeyPassPhrase;
|
||||
}
|
||||
|
||||
public function setSftpPrivateKeyPassPhrase(?string $sftpPrivateKeyPassPhrase): void
|
||||
{
|
||||
$this->sftpPrivateKeyPassPhrase = $sftpPrivateKeyPassPhrase;
|
||||
}
|
||||
|
||||
public function isLocal(): bool
|
||||
{
|
||||
return $this->getAdapterEnum()->isLocal();
|
||||
|
@ -453,6 +533,9 @@ class StorageLocation implements Stringable, IdentifiableEntityInterface
|
|||
case StorageLocationAdapters::Dropbox:
|
||||
return new DropboxAdapter($this->getDropboxClient(), $filteredPath);
|
||||
|
||||
case StorageLocationAdapters::Sftp:
|
||||
return new SftpAdapter($this->getSftpConnectionProvider(), $filteredPath);
|
||||
|
||||
default:
|
||||
return new LocalFilesystemAdapter($filteredPath);
|
||||
}
|
||||
|
@ -487,6 +570,22 @@ class StorageLocation implements Stringable, IdentifiableEntityInterface
|
|||
return new Client($this->dropboxAuthToken);
|
||||
}
|
||||
|
||||
protected function getSftpConnectionProvider(): SftpConnectionProvider
|
||||
{
|
||||
if (StorageLocationAdapters::Sftp !== $this->getAdapterEnum()) {
|
||||
throw new InvalidArgumentException('This storage location is not using the SFTP adapter.');
|
||||
}
|
||||
|
||||
return new SftpConnectionProvider(
|
||||
$this->sftpHost ?? '',
|
||||
$this->sftpUsername ?? '',
|
||||
$this->sftpPassword,
|
||||
$this->sftpPrivateKey,
|
||||
$this->sftpPrivateKeyPassPhrase,
|
||||
$this->sftpPort ?? 22
|
||||
);
|
||||
}
|
||||
|
||||
public function getFilesystem(): ExtendedFilesystemInterface
|
||||
{
|
||||
$adapter = $this->getStorageAdapter();
|
||||
|
|
Loading…
Reference in New Issue