Skip to content

Commit 63f9068

Browse files
author
a.laurowski
authored
FFWEB-2254 sftp upload
1 parent ffab944 commit 63f9068

9 files changed

Lines changed: 148 additions & 15 deletions

File tree

README.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ final chapter *Exporting Feed* describes how to use provided console command to
1414
- [Export Settings](#export-settings)
1515
- [Price Columns Format](#price-columns-format)
1616
- [Upload Settings](#upload-settings)
17+
- [Import Settings](#import-settings)
1718
- [Category Pages](#category-pages)
1819
- [Element Settings](#element-settings)
1920
- [ASN Element](#asn-element)
@@ -106,14 +107,25 @@ If `Export prices in all currencies` setting is set to true, price columns will
106107
### Upload Settings
107108

108109
![Upload Setting](docs/assets/upload-settings.png "Upload Setting")
109-
Following settings are used for uploading already exported feed to a given FTP server.
110+
Following settings are used for uploading already exported feed to a given FTP/SFTP server.
110111

111-
**Note:** The default port setting is 21. If your FTP is listening on different port, please change it accordingly.
112+
**Note:** The default port setting is 21. If your server is listening on different port, please change it accordingly.
112113

114+
* Protocol
113115
* Server URL
114116
* Port
115-
* username
116-
* password
117+
* Username
118+
* Password
119+
* Private Key Content
120+
* Passphrase
121+
122+
*Note** Fields "Private Key Content" and "Passphrase" are optional. Use them only if your SFTP server require this method of authentication.
123+
124+
125+
### Import Settings
126+
127+
![Upload Setting](docs/assets/import-settings.png "Import Setting")
128+
117129
* Enable Automatic Import for - define import types which should be triggered. Possible types are: Suggest, Search and
118130
Recommendation
119131

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"omikron/factfinder-communication-sdk": "^0.9.0",
1414
"shopware/core": "^6.4",
1515
"shopware/storefront": "^6.4",
16+
"league/flysystem-sftp": "1.0.22",
1617
"php": "^7.4 || ^8.0"
1718
},
1819
"require-dev": {

docs/assets/import-settings.png

6.93 KB
Loading

docs/assets/upload-settings.png

145 Bytes
Loading

spec/Config/FtpConfigSpec.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace spec\Omikron\FactFinder\Shopware6\Config;
4+
5+
use PhpSpec\ObjectBehavior;
6+
use Shopware\Core\System\SystemConfig\SystemConfigService;
7+
8+
class FtpConfigSpec extends ObjectBehavior
9+
{
10+
function let(SystemConfigService $configService)
11+
{
12+
$this->beConstructedWith($configService);
13+
}
14+
15+
function it_should_use_channel_name_as_part_of_uploaded_file_name(SystemConfigService $configService)
16+
{
17+
$salesChannelId = '1';
18+
$channel = 'ff_channel_name';
19+
$configService->get('OmikronFactFinder.config.channel', $salesChannelId)->willReturn($channel);
20+
21+
$this->getUploadFileName($salesChannelId)->shouldContain($channel);
22+
}
23+
}

src/Config/FtpConfig.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,21 @@ public function getUploadFileName(?string $salesChannelId = null): string
3131
return sprintf('export.%s.csv', $this->config('channel', $salesChannelId));
3232
}
3333

34+
public function getProtocol(): string
35+
{
36+
return (string) $this->config('protocol');
37+
}
38+
39+
public function getPrivateKeyFile(): string
40+
{
41+
return (string) $this->config('privateKey');
42+
}
43+
44+
public function getKeyPassphrase(): string
45+
{
46+
return (string) $this->config('keyPassphrase');
47+
}
48+
3449
public function getPushImportTypes(): array
3550
{
3651
return (array) $this->config('pushImport');

src/Export/SftpAdapterFactory.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Omikron\FactFinder\Shopware6\Export;
6+
7+
use League\Flysystem\AdapterInterface;
8+
use League\Flysystem\Sftp\SftpAdapter;
9+
use Shopware\Core\Framework\Adapter\Filesystem\Adapter\AdapterFactoryInterface;
10+
11+
class SftpAdapterFactory implements AdapterFactoryInterface
12+
{
13+
public function create(array $config): AdapterInterface
14+
{
15+
return new SftpAdapter($config);
16+
}
17+
18+
public function getType(): string
19+
{
20+
return 'sftp';
21+
}
22+
}

src/Resources/config/config.xml

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,23 @@
5959
<title>Upload Settings</title>
6060
<title lang="de-DE">FTP-Konfiguration</title>
6161

62+
<input-field type="single-select">
63+
<name>protocol</name>
64+
<label>Protocol</label>
65+
<label lang="de-DE">Protocol</label>
66+
<options>
67+
<option>
68+
<id>ftp</id>
69+
<name>FTP</name>
70+
</option>
71+
<option>
72+
<id>sftp</id>
73+
<name>SFTP</name>
74+
</option>
75+
</options>
76+
<required>true</required>
77+
</input-field>
78+
6279
<input-field>
6380
<name>ftpHost</name>
6481
<label>Server URL</label>
@@ -85,10 +102,29 @@
85102
<name>ftpPassword</name>
86103
<label>Password</label>
87104
<label lang="de-DE">Passwort</label>
88-
<required>true</required>
105+
<required>false</required>
106+
<helpText>If your authentication method does not require user password, please ignore that file</helpText>
107+
</input-field>
108+
109+
<input-field type="textarea">
110+
<name>privateKey</name>
111+
<label>Private Key Content</label>
112+
<helpText>Put the content of the received key file into the text area. If your authentication method does not require key, please ignore that file</helpText>
113+
<required>false</required>
114+
</input-field>
115+
116+
<input-field type="password">
117+
<name>keyPassphrase</name>
118+
<label>Key Passphrase</label>
119+
<helpText>If your key is not protected with a passphrase, please ignore this field</helpText>
120+
<required>false</required>
89121
</input-field>
122+
</card>
90123

91-
<input-field type="multi-select">
124+
<card>
125+
<title>Import Settings</title>
126+
<title lang="de-DE">Import-Konfiguration</title>
127+
<input-field type="multi-select">
92128
<name>pushImport</name>
93129
<label>Enable Automatic Import for</label>
94130
<label lang="de-DE">Aktivieren Sie den automatischen Import für</label>

src/Upload/UploadService.php

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Omikron\FactFinder\Shopware6\Upload;
66

7+
use Exception;
8+
use League\Flysystem\FilesystemInterface;
79
use Omikron\FactFinder\Shopware6\Config\FtpConfig;
810
use Omikron\FactFinder\Shopware6\Export\SalesChannelService;
911
use Shopware\Core\Framework\Adapter\Filesystem\FilesystemFactory;
@@ -24,24 +26,46 @@ public function __construct(
2426
$this->salesChannelService = $salesChannelService;
2527
}
2628

29+
/**
30+
* @param $fileHandle
31+
*
32+
* @throws IOException when failed to upload file
33+
*/
2734
public function upload($fileHandle): void
2835
{
2936
$connection = $this->filesystemFactory->factory($this->config());
3037
$salesChannelId = $this->salesChannelService->getSalesChannelContext()->getSalesChannel()->getId();
31-
$connection->putStream($this->config->getUploadFileName($salesChannelId), $fileHandle);
38+
39+
if (!$connection->has('export')) {
40+
$this->createExportDirectory($connection);
41+
}
42+
43+
if (!$connection->putStream('/export/' . $this->config->getUploadFileName($salesChannelId), $fileHandle)) {
44+
throw new Exception('Failed to upload file');
45+
}
3246
}
3347

3448
private function config(): array
3549
{
3650
return [
37-
'type' => 'ftp',
38-
'config' => [
39-
'host' => $this->config->getHost(),
40-
'port' => $this->config->getPort(),
41-
'username' => $this->config->getUserName(),
42-
'password' => $this->config->getPassword(),
43-
'ssl' => true,
44-
],
51+
'type' => $this->config->getAuthenticationType(),
52+
'config' => array_filter([
53+
'host' => $this->config->getHost(),
54+
'port' => $this->config->getPort(),
55+
'username' => $this->config->getUserName(),
56+
'password' => $this->config->getPassword(),
57+
'ssl' => true,
58+
'privateKey' => $this->config->getPrivateKeyFile(),
59+
'passphrase' => $this->config->getKeyPassphrase(),
60+
]),
4561
];
4662
}
63+
64+
private function createExportDirectory(FilesystemInterface $filesystem): bool
65+
{
66+
$result = $filesystem->createDir('export');
67+
if (!$result) {
68+
throw new Exception('Failed to create "export directory"');
69+
}
70+
}
4771
}

0 commit comments

Comments
 (0)