f1cff5441a
Signed-off-by: Sebastian <krupinski01@gmail.com>
176 lines
5.4 KiB
PHP
176 lines
5.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace KTXM\Mail\Stores;
|
|
|
|
use DI\Attribute\Inject;
|
|
use KTXF\Resource\BinaryResource;
|
|
|
|
final class CompositionStore {
|
|
|
|
private const COMPOSITION_FILENAME = 'composition.json';
|
|
|
|
private string $storagePath;
|
|
|
|
public function __construct(
|
|
#[Inject('rootDir')] private readonly string $rootDir,
|
|
) {
|
|
$this->storagePath = $this->rootDir . '/var/cache/mail/composer';
|
|
}
|
|
|
|
public function compositionFetch(string $tenantId, string $userId, string $draftId): ?array {
|
|
$draftDir = $this->draftDir($tenantId, $userId, $draftId);
|
|
if (!is_dir($draftDir)) {
|
|
return null;
|
|
}
|
|
|
|
$messagePath = $draftDir . '/' . self::COMPOSITION_FILENAME;
|
|
if (!file_exists($messagePath)) {
|
|
return null;
|
|
}
|
|
|
|
$decoded = json_decode((string)file_get_contents($messagePath), true);
|
|
return is_array($decoded) ? $decoded : null;
|
|
}
|
|
|
|
public function compositionSave(string $tenantId, string $userId, string $draftId, array $snapshot): array {
|
|
$draftDir = $this->draftDir($tenantId, $userId, $draftId);
|
|
if (!is_dir($draftDir)) {
|
|
mkdir($draftDir, 0755, true);
|
|
}
|
|
|
|
file_put_contents($draftDir . '/' . self::COMPOSITION_FILENAME, json_encode($snapshot, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
|
return $snapshot;
|
|
}
|
|
|
|
public function compositionDiscard(string $tenantId, string $userId, string $draftId): bool {
|
|
$draftDir = $this->draftDir($tenantId, $userId, $draftId);
|
|
if (!is_dir($draftDir)) {
|
|
return false;
|
|
}
|
|
|
|
$this->deleteDir($draftDir);
|
|
return true;
|
|
}
|
|
|
|
public function attachmentStageFromStream(
|
|
string $tenantId,
|
|
string $userId,
|
|
string $compositionId,
|
|
string $attachmentId,
|
|
BinaryResource $data,
|
|
): array {
|
|
$attachmentDir = $this->attachmentDir($tenantId, $userId, $compositionId);
|
|
if (!is_dir($attachmentDir)) {
|
|
mkdir($attachmentDir, 0755, true);
|
|
}
|
|
|
|
$contentPath = $attachmentDir . '/' . $attachmentId . '.blob';
|
|
$handle = fopen($contentPath, 'wb');
|
|
$size = 0;
|
|
|
|
foreach ($data->stream() as $chunk) {
|
|
$chunkString = (string)$chunk;
|
|
$size += strlen($chunkString);
|
|
fwrite($handle, $chunkString);
|
|
}
|
|
|
|
fclose($handle);
|
|
|
|
$meta = [
|
|
'identifier' => $attachmentId,
|
|
'composition' => $compositionId,
|
|
'name' => $data->filename(),
|
|
'type' => $data->mimeType(),
|
|
'size' => $size,
|
|
];
|
|
|
|
file_put_contents($attachmentDir . '/' . $attachmentId . '.meta', json_encode($meta, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
|
|
|
return $meta;
|
|
}
|
|
|
|
public function attachmentStageFromBase64(
|
|
string $tenantId,
|
|
string $userId,
|
|
string $compositionId,
|
|
string $attachmentId,
|
|
string $name,
|
|
string $type,
|
|
string $data,
|
|
): array {
|
|
$decoded = base64_decode($data, true);
|
|
if ($decoded === false) {
|
|
throw new \InvalidArgumentException('Attachment payload is not valid base64');
|
|
}
|
|
|
|
$attachmentDir = $this->attachmentDir($tenantId, $userId, $compositionId);
|
|
if (!is_dir($attachmentDir)) {
|
|
mkdir($attachmentDir, 0755, true);
|
|
}
|
|
|
|
file_put_contents($attachmentDir . '/' . $attachmentId . '.blob', $decoded);
|
|
|
|
$metadata = [
|
|
'identifier' => $attachmentId,
|
|
'composition' => $compositionId,
|
|
'name' => $name,
|
|
'type' => $type,
|
|
'size' => strlen($decoded),
|
|
];
|
|
|
|
file_put_contents($attachmentDir . '/' . $attachmentId . '.meta', json_encode($metadata, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
|
|
|
return $metadata;
|
|
}
|
|
|
|
public function attachmentFetchData(string $tenantId, string $userId, string $compositionId, string $attachmentId): ?string {
|
|
$path = $this->attachmentDir($tenantId, $userId, $compositionId) . '/' . $attachmentId . '.blob';
|
|
if (!file_exists($path)) {
|
|
return null;
|
|
}
|
|
|
|
return file_get_contents($path) ?: null;
|
|
}
|
|
|
|
public function fetchAttachmentMeta(string $tenantId, string $userId, string $compositionId, string $attachmentId): ?array {
|
|
$path = $this->attachmentDir($tenantId, $userId, $compositionId) . '/' . $attachmentId . '.meta';
|
|
if (!file_exists($path)) {
|
|
return null;
|
|
}
|
|
|
|
$decoded = json_decode((string)file_get_contents($path), true);
|
|
return is_array($decoded) ? $decoded : null;
|
|
}
|
|
|
|
private function attachmentDir(string $tenantId, string $userId, string $draftId): string {
|
|
return $this->draftDir($tenantId, $userId, $draftId) . '/attachments';
|
|
}
|
|
|
|
private function draftDir(string $tenantId, string $userId, string $draftId): string {
|
|
return $this->storagePath . '/' . $tenantId . '/' . $userId . '/' . $draftId;
|
|
}
|
|
|
|
private function deleteDir(string $path): void {
|
|
if (!is_dir($path)) {
|
|
return;
|
|
}
|
|
|
|
foreach (scandir($path) ?: [] as $entry) {
|
|
if ($entry === '.' || $entry === '..') {
|
|
continue;
|
|
}
|
|
|
|
$child = $path . '/' . $entry;
|
|
if (is_dir($child)) {
|
|
$this->deleteDir($child);
|
|
continue;
|
|
}
|
|
|
|
unlink($child);
|
|
}
|
|
|
|
rmdir($path);
|
|
}
|
|
} |