|
|
|
|
@@ -11,12 +11,12 @@ namespace KTXM\ProviderImap\Providers;
|
|
|
|
|
|
|
|
|
|
use Generator;
|
|
|
|
|
use KTXF\Mail\Collection\CollectionBaseInterface;
|
|
|
|
|
use KTXF\Mail\Collection\CollectionMutableInterface;
|
|
|
|
|
use KTXF\Mail\Collection\CollectionPropertiesBaseInterface;
|
|
|
|
|
use KTXF\Mail\Object\Address;
|
|
|
|
|
use KTXF\Mail\Object\AddressInterface;
|
|
|
|
|
use KTXF\Mail\Service\ServiceBaseInterface;
|
|
|
|
|
use KTXF\Mail\Service\ServiceCollectionMutableInterface;
|
|
|
|
|
use KTXF\Mail\Service\ServiceEntityMutableInterface;
|
|
|
|
|
use KTXF\Mail\Service\ServiceConfigurableInterface;
|
|
|
|
|
use KTXF\Mail\Service\ServiceMutableInterface;
|
|
|
|
|
use KTXF\Resource\Provider\ResourceServiceIdentityInterface;
|
|
|
|
|
@@ -39,7 +39,7 @@ use KTXM\ProviderImap\Service\Remote\RemoteService;
|
|
|
|
|
use KTXM\ProviderImap\Providers\CollectionResource;
|
|
|
|
|
use KTXF\Mail\Collection\CollectionRoles;
|
|
|
|
|
use KTXF\Mail\Object\MessagePropertiesMutableInterface;
|
|
|
|
|
use KTXF\Resource\Identifier\EntityIdentifierInterface;
|
|
|
|
|
use KTXF\Mail\Service\ServiceEntityMutableInterface;
|
|
|
|
|
use KTXM\ProviderImap\Providers\EntityResource;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -498,7 +498,7 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$result = match ($deleteMode) {
|
|
|
|
|
'soft' => $this->collectionMove(new CollectionIdentifier($target->provider(), $target->service(), $deleteTarget), $target),
|
|
|
|
|
'soft' => $this->collectionMove($target, new CollectionIdentifier($target->provider(), $target->service(), $deleteTarget)),
|
|
|
|
|
'hard' => $this->mailService->collectionDestroy((string) $target->collection()),
|
|
|
|
|
};
|
|
|
|
|
return $result;
|
|
|
|
|
@@ -520,9 +520,8 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
|
|
|
|
$sourceDelimiter = $sourceMailbox->delimiter() ?? '/';
|
|
|
|
|
$targetDelimiter = $targetMailbox->delimiter() ?? '/';
|
|
|
|
|
|
|
|
|
|
$extantPath = $sourceMailbox->name();
|
|
|
|
|
$freshPath = rtrim($targetMailbox->name(), $targetDelimiter) . $targetDelimiter . end(explode($sourceDelimiter, $extantPath));
|
|
|
|
|
$mutatedMailbox = $this->mailService->collectionRename($extantPath, $freshPath);
|
|
|
|
|
$targetPath = rtrim($targetMailbox->name(), $targetDelimiter) . $targetDelimiter . end(explode($sourceDelimiter, $sourceMailbox->name()));
|
|
|
|
|
$mutatedMailbox = $this->mailService->collectionRename($sourceMailbox->name(), $targetPath);
|
|
|
|
|
|
|
|
|
|
$collection = $this->collectionFresh();
|
|
|
|
|
$collection->fromImap($mutatedMailbox, ['delimiter' => $targetDelimiter]);
|
|
|
|
|
@@ -531,9 +530,9 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
|
|
|
|
|
|
|
|
|
// ── Entity operations ─────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
public function entityListBulk(string|int $collection, ?IFilter $filter = null, ?ISort $sort = null, ?IRange $range = null, ?array $properties = null): array
|
|
|
|
|
public function entityList(string|int $collection, ?IFilter $filter = null, ?ISort $sort = null, ?IRange $range = null, ?array $properties = null): array
|
|
|
|
|
{
|
|
|
|
|
return iterator_to_array($this->entityListStream((string) $collection, $filter, $sort, $range), true);
|
|
|
|
|
return iterator_to_array($this->entityList((string) $collection, $filter, $sort, $range), true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function entityListStream(string|int $collection, ?IFilter $filter = null, ?ISort $sort = null, ?IRange $range = null, ?array $properties = null): Generator
|
|
|
|
|
@@ -543,7 +542,7 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
|
|
|
|
foreach ($this->mailService->entityList((string) $collection, $filter, $sort, $range) as $identifier => $message) {
|
|
|
|
|
$resource = $this->entityFresh();
|
|
|
|
|
$resource->fromImap($message, $collection);
|
|
|
|
|
yield $resource->urn() => $resource;
|
|
|
|
|
yield $identifier => $resource;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -565,25 +564,12 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function entityFetchBulk(EntityIdentifierInterface ...$identifiers): array
|
|
|
|
|
{
|
|
|
|
|
return iterator_to_array($this->entityFetchStream(...$identifiers), true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function entityFetchStream(EntityIdentifierInterface ...$identifiers): Generator
|
|
|
|
|
public function entityFetch(string|int $collection, string|int ...$identifiers): array
|
|
|
|
|
{
|
|
|
|
|
$this->initialize();
|
|
|
|
|
|
|
|
|
|
$identifiers = $this->groupEntitiesByCollection(...$identifiers);
|
|
|
|
|
|
|
|
|
|
foreach ($identifiers as $collection => $entities) {
|
|
|
|
|
$uids = array_keys($entities);
|
|
|
|
|
foreach ($this->mailService->entityFetch((string) $collection, ...$uids) as $uid => $message) {
|
|
|
|
|
$resource = $this->entityFresh();
|
|
|
|
|
$resource->fromImap($message, $collection);
|
|
|
|
|
yield $resource->urn() => $resource;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$uids = array_map('intval', $identifiers);
|
|
|
|
|
return $this->mailService->entityFetch((string) $collection, ...$uids);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function entityDelta(string|int $collection, string $signature, string $detail = 'ids'): Delta
|
|
|
|
|
@@ -619,33 +605,10 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
|
|
|
|
throw new \RuntimeException('Entity modification is not supported in this service');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function entityPatch(MessagePropertiesMutableInterface $properties, EntityIdentifier ...$targets): array
|
|
|
|
|
public function entityDelete(EntityIdentifier ...$identifiers): array
|
|
|
|
|
{
|
|
|
|
|
// validate identifiers and group by collection
|
|
|
|
|
$targets = $this->groupEntitiesByCollection(...$targets);
|
|
|
|
|
|
|
|
|
|
// move entities on remote store and construct result map
|
|
|
|
|
$this->initialize();
|
|
|
|
|
|
|
|
|
|
$list = [];
|
|
|
|
|
|
|
|
|
|
foreach ($targets as $targetCollection => $targetIdentifiers) {
|
|
|
|
|
$uids = array_keys($targetIdentifiers);
|
|
|
|
|
|
|
|
|
|
$mutations = $this->mailService->entityPatch($targetCollection, $properties, ...$uids);
|
|
|
|
|
|
|
|
|
|
foreach ($uids as $uid) {
|
|
|
|
|
$list[(string)$targetIdentifiers[$uid]] = ['disposition' => 'patched'];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function entityDelete(EntityIdentifier ...$targets): array
|
|
|
|
|
{
|
|
|
|
|
// validate identifiers and group by collection
|
|
|
|
|
$targets = $this->groupEntitiesByCollection(...$targets);
|
|
|
|
|
$identifiers = $this->groupEntitiesByCollection(...$identifiers);
|
|
|
|
|
|
|
|
|
|
// determine delete mode and target collection (e.g. Trash) if applicable
|
|
|
|
|
$deleteMode = $this->auxiliary['deleteMode'] ?? 'soft';
|
|
|
|
|
@@ -680,14 +643,9 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
|
|
|
|
$deleteTargetIdentifier = new CollectionIdentifier($this->provider(), (string) $this->identifier(), $deleteTargetNative);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if all targets are already in the delete target collection, we should hard delete instead of moving to avoid duplicates in the trash
|
|
|
|
|
if (array_keys($targets) === [$deleteTargetNative]) {
|
|
|
|
|
$deleteMode = 'hard';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// entities need to be moved or deleted by collection
|
|
|
|
|
$list = [];
|
|
|
|
|
foreach ($targets as $sourceCollection => $sourceEntities) {
|
|
|
|
|
foreach ($identifiers as $sourceCollection => $sourceEntities) {
|
|
|
|
|
if ($deleteMode === 'soft' && $sourceCollection === $deleteTargetNative) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
@@ -700,11 +658,11 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
foreach ($uids as $uid) {
|
|
|
|
|
$mutatedUid = !isset($mutations[$uid]) || $mutations[$uid] === true ? null : $mutations[$uid];
|
|
|
|
|
$mutatedUid = $mutations[$uid] ?? null;
|
|
|
|
|
$list[(string)$sourceEntities[$uid]] = [
|
|
|
|
|
'disposition' => $deleteMode === 'soft' ? 'moved' : 'deleted',
|
|
|
|
|
'destination' => $deleteMode === 'soft' ? $deleteTargetIdentifier : null,
|
|
|
|
|
'mutation' => $deleteMode === 'soft' && $mutatedUid !== null ? new EntityIdentifier($this->provider(), $this->identifier(), $deleteTargetIdentifier->collection(), $mutatedUid) : null,
|
|
|
|
|
'mutation' => $mutatedUid !== null ? new EntityIdentifier($this->provider(), $this->identifier(), $deleteTargetIdentifier->collection(), $mutatedUid) : null,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -712,40 +670,12 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
|
|
|
|
return $list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function entityCopy(CollectionIdentifier $target, EntityIdentifier ...$sources): array
|
|
|
|
|
public function entityPatch(MessagePropertiesMutableInterface $properties, EntityIdentifier ...$targets): array
|
|
|
|
|
{
|
|
|
|
|
// validate target belongs to this service
|
|
|
|
|
if ($target->provider() !== $this->provider() || $target->service() !== $this->identifier()) {
|
|
|
|
|
throw new \InvalidArgumentException('Target collection does not belong to this service: ' . $target);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// validate identifiers and group by collection
|
|
|
|
|
$sources = $this->groupEntitiesByCollection(...$sources);
|
|
|
|
|
|
|
|
|
|
// copy entities on remote store and construct result map
|
|
|
|
|
$this->initialize();
|
|
|
|
|
|
|
|
|
|
$list = [];
|
|
|
|
|
|
|
|
|
|
foreach ($sources as $sourceCollection => $sourceEntities) {
|
|
|
|
|
$uids = array_keys($sourceEntities);
|
|
|
|
|
|
|
|
|
|
$mutations = $this->mailService->entityCopy($target->collection(), $sourceCollection, ...$uids);
|
|
|
|
|
|
|
|
|
|
foreach ($uids as $uid) {
|
|
|
|
|
$mutatedUid = $mutations[$uid] ?? null;
|
|
|
|
|
$list[(string)$sourceEntities[$uid]] = [
|
|
|
|
|
'disposition' => $mutatedUid !== null ? 'copied' : 'error',
|
|
|
|
|
'destination' => $target,
|
|
|
|
|
'mutation' => $mutatedUid !== null ? new EntityIdentifier($this->provider(), $this->identifier(), $target->collection(), $mutatedUid) : null,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $list;
|
|
|
|
|
throw new \RuntimeException('Entity patching is not supported in this service');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function entityMove(CollectionIdentifier $target, EntityIdentifier ...$sources): array
|
|
|
|
|
public function entityMove(CollectionIdentifier $target, EntityIdentifier ...$identifiers): array
|
|
|
|
|
{
|
|
|
|
|
// validate target belongs to this service
|
|
|
|
|
if ($target->provider() !== $this->provider() || $target->service() !== $this->identifier()) {
|
|
|
|
|
@@ -753,14 +683,12 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// validate identifiers and group by collection
|
|
|
|
|
$sources = $this->groupEntitiesByCollection(...$sources);
|
|
|
|
|
$identifiers = $this->groupEntitiesByCollection(...$identifiers);
|
|
|
|
|
|
|
|
|
|
// move entities on remote store and construct result map
|
|
|
|
|
$this->initialize();
|
|
|
|
|
|
|
|
|
|
$list = [];
|
|
|
|
|
|
|
|
|
|
foreach ($sources as $sourceCollection => $sourceEntities) {
|
|
|
|
|
foreach ($identifiers as $sourceCollection => $sourceEntities) {
|
|
|
|
|
$uids = array_keys($sourceEntities);
|
|
|
|
|
|
|
|
|
|
$mutations = $this->mailService->entityMove($target->collection(), $sourceCollection, ...$uids);
|
|
|
|
|
@@ -778,6 +706,11 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
|
|
|
|
return $list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function entityCopy(CollectionIdentifier $target, EntityIdentifier ...$sources): array
|
|
|
|
|
{
|
|
|
|
|
throw new \RuntimeException('Entity copying is not supported in this service');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function groupEntitiesByCollection(EntityIdentifier ...$identifiers): array
|
|
|
|
|
{
|
|
|
|
|
$list = [];
|
|
|
|
|
|