generated from Nodarx/template
feat: implement message create and update
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -11,6 +11,7 @@ namespace KTXM\ProviderImap\Providers;
|
||||
|
||||
use KTXM\ProviderImap\Client\Message;
|
||||
use KTXF\Mail\Entity\EntityMutableAbstract;
|
||||
use KTXF\Mail\Object\MessagePropertiesMutableInterface;
|
||||
|
||||
/**
|
||||
* Mail Entity Resource Implementation
|
||||
@@ -42,6 +43,26 @@ class EntityResource extends EntityMutableAbstract {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate an entity returned by a create or replacement operation.
|
||||
*/
|
||||
public function fromMutation(
|
||||
string $mailbox,
|
||||
string|int $identifier,
|
||||
MessagePropertiesMutableInterface $properties,
|
||||
): static {
|
||||
$this->data['collection'] = $mailbox;
|
||||
$this->data['identifier'] = $identifier;
|
||||
|
||||
if ($properties instanceof MessageProperties) {
|
||||
$this->setProperties($properties);
|
||||
} else {
|
||||
$this->getProperties()->jsonDeserialize($properties->jsonSerialize());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
@@ -102,8 +102,8 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
||||
],
|
||||
self::CAPABILITY_ENTITY_FETCH => true,
|
||||
self::CAPABILITY_ENTITY_EXTANT => true,
|
||||
self::CAPABILITY_ENTITY_CREATE => false,
|
||||
self::CAPABILITY_ENTITY_MODIFY => false,
|
||||
self::CAPABILITY_ENTITY_CREATE => true,
|
||||
self::CAPABILITY_ENTITY_MODIFY => true,
|
||||
self::CAPABILITY_ENTITY_PATCH => true,
|
||||
self::CAPABILITY_ENTITY_DELETE => true,
|
||||
self::CAPABILITY_ENTITY_MOVE => true,
|
||||
@@ -701,12 +701,45 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
||||
|
||||
public function entityCreate(CollectionIdentifier $target, MessagePropertiesMutableInterface $properties, array $options = []): EntityResource
|
||||
{
|
||||
throw new \RuntimeException('Entity creation is not supported in this service');
|
||||
if ($target->provider() !== $this->provider() || (string)$target->service() !== (string)$this->identifier()) {
|
||||
throw new \InvalidArgumentException('Target collection does not belong to this service: ' . (string)$target);
|
||||
}
|
||||
|
||||
$this->initialize();
|
||||
|
||||
[$nativeMessage, $nativeFlags] = $this->messagePayload($properties, $options);
|
||||
$created = $this->remoteService->entityCreate(
|
||||
(string)$target->collection(),
|
||||
$nativeMessage,
|
||||
$nativeFlags,
|
||||
);
|
||||
if ($created === null || $created <= 0) {
|
||||
throw new \RuntimeException('IMAP APPEND did not return a valid UID');
|
||||
}
|
||||
|
||||
return $this->entityFresh()->fromMutation((string)$target->collection(), $created, $properties);
|
||||
}
|
||||
|
||||
public function entityModify(EntityIdentifier $target, MessagePropertiesMutableInterface $properties): EntityResource
|
||||
{
|
||||
throw new \RuntimeException('Entity modification is not supported in this service');
|
||||
if ($target->provider() !== $this->provider() || (string)$target->service() !== (string)$this->identifier()) {
|
||||
throw new \InvalidArgumentException('Target entity does not belong to this service: ' . (string)$target);
|
||||
}
|
||||
|
||||
$this->initialize();
|
||||
|
||||
[$nativeMessage, $nativeFlags] = $this->messagePayload($properties);
|
||||
$modified = $this->remoteService->entityReplace(
|
||||
(string)$target->collection(),
|
||||
(int)$target->entity(),
|
||||
$nativeMessage,
|
||||
$nativeFlags,
|
||||
);
|
||||
if ($modified === null || $modified <= 0) {
|
||||
throw new \RuntimeException('IMAP replacement did not return a valid UID');
|
||||
}
|
||||
|
||||
return $this->entityFresh()->fromMutation((string)$target->collection(), $modified, $properties);
|
||||
}
|
||||
|
||||
public function entityPatch(MessagePropertiesMutableInterface $properties, EntityIdentifier ...$targets): array
|
||||
@@ -891,5 +924,46 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert canonical message flags to IMAP system flags.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function messageFlags(MessagePropertiesMutableInterface $properties): array
|
||||
{
|
||||
$flags = [];
|
||||
foreach ($properties->getFlags() as $flag => $enabled) {
|
||||
if ($enabled !== true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$flags[] = match (strtolower((string)$flag)) {
|
||||
'seen' => '\\Seen',
|
||||
'flagged' => '\\Flagged',
|
||||
'answered' => '\\Answered',
|
||||
'draft' => '\\Draft',
|
||||
'deleted' => '\\Deleted',
|
||||
default => (string)$flag,
|
||||
};
|
||||
}
|
||||
|
||||
return array_values(array_unique($flags));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert message properties into the native IMAP append payload.
|
||||
*
|
||||
* @return array{0: string, 1: string[]}
|
||||
*/
|
||||
private function messagePayload(MessagePropertiesMutableInterface $properties, array $options = []): array
|
||||
{
|
||||
$flags = $this->messageFlags($properties);
|
||||
if (isset($options['flags']) && is_array($options['flags'])) {
|
||||
$flags = array_values(array_unique([...$flags, ...$options['flags']]));
|
||||
}
|
||||
|
||||
return [(new MessageBuilder())->build($properties), $flags];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ class RemoteMailService
|
||||
return null;
|
||||
}
|
||||
|
||||
$logDir = dirname(__DIR__, 5) . '/var/log';
|
||||
$logDir = dirname(__DIR__, 5) . '/var/logs/provider_imap';
|
||||
|
||||
return new PlainFileLogger($logDir . '/' . $channel, $this->service->identifier());
|
||||
}
|
||||
@@ -490,6 +490,44 @@ class RemoteMailService
|
||||
return $this->imapClient()->perform(new AppendCommand($collection, $rawMessage, $flags));
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a replacement message, then permanently remove the superseded UID.
|
||||
* The replacement is removed on cleanup failure so the old UID remains
|
||||
* authoritative for a later retry.
|
||||
*
|
||||
* @param string[] $flags
|
||||
*/
|
||||
public function entityReplace(
|
||||
string $collection,
|
||||
int $identifier,
|
||||
string $rawMessage,
|
||||
array $flags = [],
|
||||
): ?int {
|
||||
if ($identifier <= 0) {
|
||||
throw new RuntimeException('A valid IMAP UID is required for replacement');
|
||||
}
|
||||
|
||||
$replacement = $this->entityCreate($collection, $rawMessage, $flags);
|
||||
if ($replacement === null || $replacement <= 0) {
|
||||
throw new RuntimeException('IMAP replacement append did not return a valid UID');
|
||||
}
|
||||
|
||||
try {
|
||||
$deleted = $this->entityDestroy($collection, $identifier);
|
||||
if (($deleted[$identifier] ?? false) !== true) {
|
||||
throw new RuntimeException('Failed to delete the superseded IMAP entity');
|
||||
}
|
||||
} catch (\Throwable $error) {
|
||||
try {
|
||||
$this->entityDestroy($collection, $replacement);
|
||||
} catch (\Throwable) {
|
||||
}
|
||||
throw $error;
|
||||
}
|
||||
|
||||
return $replacement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify message flags for one or more messages.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user