Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 32 additions & 70 deletions components/ILIAS/Mail/classes/Attachments/FileDataRCHandling.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,46 +18,23 @@

declare(strict_types=1);

use ILIAS\Filesystem\Stream\Streams;
use ILIAS\Mail\Attachments\MailAttachments;
use ILIAS\ResourceStorage\Identification\ResourceCollectionIdentification;
use ILIAS\ResourceStorage\Collection\ResourceCollection;

trait FileDataRCHandling
{
/**
* @param list<string> $path_to_files
*/
protected function getCurrentCollection(
array $path_to_files,
ilMailAttachmentStakeholder $stakeholder
array $path_to_files
): \ILIAS\ResourceStorage\Collection\ResourceCollection {
set_error_handler(static function ($severity, $message, $file, $line): void {
throw new ErrorException($message, $severity, 0, $file, $line);
});

try {
global $DIC;
$file_system = $DIC->filesystem()->storage();
$rcid = $this->storage->collection()->id();
$collection = $this->storage->collection()->get($rcid);
foreach ($path_to_files as $path_to_file) {
$base_dir = (new \ILIAS\FileDelivery\Setup\BaseDirObjective())::get();
$path_to_file = str_replace($base_dir, '/', $path_to_file);
$rid = $this->storage->manage()->stream(
$file_system->readStream($path_to_file),
$stakeholder,
md5(basename($path_to_file))
);
$collection->add($rid);
}
$this->storage->collection()->store($collection);
} catch (Exception $e) {
throw new Exception("Storing file into collection failed: " . $e->getMessage());
} finally {
restore_error_handler();
$rcid = $this->fdm->createCollectionFromPaths($path_to_files);
if ($rcid === null) {
throw new Exception('Storing file into collection failed: no files found');
}

return $collection;
return $this->fdm->getCollection($rcid);
}

/**
Expand All @@ -66,73 +43,58 @@ protected function getCurrentCollection(
*/
public function filesFromLegacyToIRSS(array $mail_data): array
{
$files = [];
$attachments = $mail_data['attachments'] ?? null;
if (!$attachments instanceof MailAttachments || !$attachments->isLegacy()) {
throw new InvalidArgumentException('Legacy mail attachments expected.');
}

$path_to_files = [];
foreach ($mail_data['attachments'] as $file) {
foreach ($attachments->legacyFilenames() as $file) {
$path_to_files[] = $this->fdm->getAbsoluteAttachmentPoolPathByFilename($file);
}
$collection = $this->getCurrentCollection($path_to_files, new ilMailAttachmentStakeholder());
foreach ($collection->getResourceIdentifications() as $rcid) {
$files[] = $rcid->serialize();
}
$collection = $this->getCurrentCollection($path_to_files);

return $files;
return $this->fdm->getRidsFromCollection($collection->getIdentification());
}

/**
* @param array<string, mixed> $mail_data
* @param list<string> $filenames
*/
public function getIdforCollection(array $mail_data): ?ResourceCollectionIdentification
public function getIdforCollection(array $filenames): ?ResourceCollectionIdentification
{
$files = [];
$path_to_files = [];
foreach ($mail_data as $attachment) {
$path_to_files[] = $this->fdm->getAbsoluteAttachmentPoolPathByFilename($attachment);
}
$collection = $this->getCurrentCollection($path_to_files, new ilMailAttachmentStakeholder());
$rcid = $collection->getIdentification();

return $rcid;
return $this->fdm->createCollectionFromPoolFilenames($filenames);
}

/**
* @return list<string>
*/
public function FilesFromIRSSToLegacy(ResourceCollectionIdentification $identification): array
{
$files = [];
$collection = $this->storage->collection()->get($identification);
$all_ids = $collection->getResourceIdentifications();
foreach ($all_ids as $id) {
$files[] = $id->serialize();
}

return $files;
return $this->fdm->getRidsFromCollection($identification);
}

/**
* @param array<string, mixed> $attachments
* @return list<string>
*/
protected function handleAttachments(array $attachments): array
protected function handleAttachments(array $attachments): ResourceCollectionIdentification
{
$files = [];
$resource_identifications = [];
foreach ($attachments as $attachment) {
$info = $this->upload_handler->getInfoResult($attachment);
if ($info->getFileIdentifier() !== 'unknown') {
$src = $this->upload_handler->getStreamConsumer($attachment);
$stored = $this->fdm->storeAsAttachment(
$info->getName(),
(string) $src->getStream()
);
if ($stored === false) {
throw new Exception("File '" . $info->getName() . "' could not be stored");
}
$files[] = ilFileUtils::_sanitizeFilemame($info->getName());
$this->upload_handler->removeFileForIdentifier($attachment);
if ($info->getFileIdentifier() === 'unknown') {
continue;
}
$found = $this->storage->manage()->find($attachment);
if ($found === null) {
throw new Exception("File '" . $info->getName() . "' could not be found in IRSS");
}
$resource_identifications[] = $found;
}

if ($resource_identifications === []) {
throw new Exception('No attachments could be stored');
}

return $files;
return $this->fdm->createCollectionFromResourceIdentifications($resource_identifications);
}
}
157 changes: 157 additions & 0 deletions components/ILIAS/Mail/classes/Attachments/MailAttachments.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<?php

/**
* This file is part of ILIAS, a powerful learning management system
* published by ILIAS open source e-Learning e.V.
*
* ILIAS is licensed with the GPL-3.0,
* see https://www.gnu.org/licenses/gpl-3.0.en.html
* You should have received a copy of said license along with the
* source code, too.
*
* If this is not the case or you just want to try ILIAS, you'll find
* us at:
* https://www.ilias.de
* https://github.com/ILIAS-eLearning
*
*********************************************************************/

declare(strict_types=1);

namespace ILIAS\Mail\Attachments;

use InvalidArgumentException;
use ILIAS\ResourceStorage\Identification\ResourceCollectionIdentification;

final class MailAttachments
{
public const string SERIALIZED_RCID_KEY = '__irss_rcid';

private function __construct(
private readonly ?ResourceCollectionIdentification $rcid,
/** @var list<string> */
private readonly array $legacy_filenames,
) {
}

public static function empty(): self
{
return new self(null, []);
}

public static function fromIrss(ResourceCollectionIdentification $rcid): self
{
return new self($rcid, []);
}

/**
* @param list<string> $filenames
*/
public static function fromLegacyFilenames(array $filenames): self
{
if ($filenames === []) {
return self::empty();
}

return new self(null, array_values($filenames));
}

public static function fromDb(?string $raw): ?self
{
if ($raw === null || $raw === '') {
return null;
}

if (str_contains($raw, 'a:')) {
$unserialized = unserialize($raw, ['allowed_classes' => false]);
if (!is_array($unserialized)) {
return null;
}

if (isset($unserialized[self::SERIALIZED_RCID_KEY])) {
return self::fromIrss(
new ResourceCollectionIdentification((string) $unserialized[self::SERIALIZED_RCID_KEY])
);
}

return self::fromLegacyFilenames($unserialized);
}

return self::fromIrss(new ResourceCollectionIdentification($raw));
}

public static function fromBackgroundTask(string $serialized): self
{
$parsed = unserialize($serialized, ['allowed_classes' => false]);
if (!is_array($parsed)) {
return self::empty();
}

if (isset($parsed[self::SERIALIZED_RCID_KEY])) {
return self::fromIrss(
new ResourceCollectionIdentification((string) $parsed[self::SERIALIZED_RCID_KEY])
);
}

return self::fromLegacyFilenames($parsed);
}

public function isEmpty(): bool
{
return $this->rcid === null && $this->legacy_filenames === [];
}

public function isIrss(): bool
{
return $this->rcid !== null;
}

public function isLegacy(): bool
{
return $this->rcid === null && $this->legacy_filenames !== [];
}

public function rcid(): ResourceCollectionIdentification
{
if ($this->rcid === null) {
throw new InvalidArgumentException('Mail attachments are not stored in IRSS.');
}

return $this->rcid;
}

/**
* @return list<string>
*/
public function legacyFilenames(): array
{
if ($this->isIrss()) {
throw new InvalidArgumentException('Mail attachments are not legacy filenames.');
}

return $this->legacy_filenames;
}

public function toDb(): string
{
if ($this->isIrss()) {
return $this->rcid->serialize();
}

return serialize($this->legacy_filenames);
}

public function toBackgroundTask(): string
{
if ($this->isIrss()) {
return serialize([self::SERIALIZED_RCID_KEY => $this->rcid->serialize()]);
}

return serialize($this->legacy_filenames);
}

public function stageRcidOrNull(): ?ResourceCollectionIdentification
{
return $this->rcid;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use ILIAS\BackgroundTasks\Types\SingleType;
use ILIAS\BackgroundTasks\Types\Type;
use ILIAS\BackgroundTasks\Value;
use ILIAS\Mail\Attachments\MailAttachments;

class ilMailDeliveryJob extends AbstractJob
{
Expand Down Expand Up @@ -69,7 +70,7 @@ public function run(array $input, Observer $observer): Value
(string) $input[3]->getValue(), // Bcc
(string) $input[4]->getValue(), // Subject
(string) $input[5]->getValue(), // Message
(array) unserialize($input[6]->getValue(), ['allowed_classes' => false]), // Attachments
MailAttachments::fromBackgroundTask($input[6]->getValue()), // Attachments
(bool) $input[7]->getValue() // Use Placeholders
);
$mail->sendMail($mail_data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use ILIAS\BackgroundTasks\Types\SingleType;
use ILIAS\BackgroundTasks\Types\Type;
use ILIAS\BackgroundTasks\Value;
use ILIAS\Mail\Attachments\MailAttachments;

class ilMassMailDeliveryJob extends AbstractJob
{
Expand Down Expand Up @@ -73,7 +74,7 @@ public function run(array $input, Observer $observer): Value
$recipients_bcc,
$value_object->getSubject(),
$value_object->getBody(),
$value_object->getAttachments(),
MailAttachments::fromLegacyFilenames($value_object->getAttachments()),
$value_object->isUsingPlaceholders()
);
$mail->sendMail($mail_data);
Expand Down
Loading
Loading