From c1dbcc9a7d6ab674242537cc1d1e6fb0621be838 Mon Sep 17 00:00:00 2001 From: Sebastian Krupinski Date: Thu, 7 May 2026 23:53:21 -0400 Subject: [PATCH] recator: entity move and delete Signed-off-by: Sebastian Krupinski --- lib/Manager.php | 63 ++---------------------------------- src/stores/entitiesStore.ts | 64 ++++++++++++++++++++++++++++++------- src/types/entity.ts | 33 +++++++------------ 3 files changed, 67 insertions(+), 93 deletions(-) diff --git a/lib/Manager.php b/lib/Manager.php index 249236e..b5c4c0c 100644 --- a/lib/Manager.php +++ b/lib/Manager.php @@ -1033,13 +1033,7 @@ class Manager { } if ($service === null) { - foreach ($serviceSources as $identifier) { - $operationOutcome[(string)$identifier] = [ - 'success' => false, - 'error' => 'serviceNotFound', - ]; - } - continue; + throw new InvalidArgumentException("Service not found: $providerName/$serviceName"); } // Temporarily disabled check until all methods are properly implemented from ServiceEntityMutableInterface @@ -1065,34 +1059,7 @@ class Manager { } */ - try { - $operationResult = $service->entityDelete(...$serviceSources->all()); - - foreach ($serviceSources as $identifier) { - $sourceIdentifier = (string)$identifier; - $entityIdentifier = $identifier->entity(); - $result = $operationResult[$entityIdentifier] ?? null; - - if ($result === true) { - $operationOutcome[$sourceIdentifier] = [ - 'success' => true, - ]; - continue; - } - - $operationOutcome[$sourceIdentifier] = [ - 'success' => false, - 'error' => is_string($result) && $result !== '' ? $result : 'unknownError', - ]; - } - } catch (\Throwable $e) { - foreach ($serviceSources as $identifier) { - $operationOutcome[(string)$identifier] = [ - 'success' => false, - 'error' => $e->getMessage(), - ]; - } - } + return $service->entityDelete(...$serviceSources->all()); } } @@ -1115,31 +1082,7 @@ class Manager { $destinationSources = $sources->byProvider($targetService->provider())->byService((string)$targetService->identifier()); if (!$destinationSources->isEmpty()) { - $operationResult = $targetService->entityMove($target, ...$destinationSources->all()); - - foreach ($destinationSources as $identifier) { - $sourceIdentifier = (string)$identifier; - $entityIdentifier = $identifier->entity(); - $result = $operationResult[$entityIdentifier] ?? null; - - if ($result === true) { - $operationOutcome[$sourceIdentifier] = [ - 'success' => true, - 'identifier' => (string)new EntityIdentifier( - $target->provider(), - $target->service(), - $target->collection(), - $entityIdentifier, - ), - ]; - continue; - } - - $operationOutcome[$sourceIdentifier] = [ - 'success' => false, - 'error' => is_string($result) && $result !== '' ? $result : 'unknownError', - ]; - } + $operationOutcome = $targetService->entityMove($target, ...$destinationSources->all()); } // TODO: Handle moving entities across different services/providers by fetching each entity and re-creating it in the target collection, diff --git a/src/stores/entitiesStore.ts b/src/stores/entitiesStore.ts index f3661c0..7be7ad5 100644 --- a/src/stores/entitiesStore.ts +++ b/src/stores/entitiesStore.ts @@ -359,17 +359,46 @@ export const useEntitiesStore = defineStore('mailEntitiesStore', () => { transceiving.value = true try { const response = await entityService.delete({ sources }) + const successes: EntityIdentifier[] = [] + const failures: EntityIdentifier[] = [] Object.entries(response).forEach(([sourceIdentifier, result]) => { - if (!result.success) { + if (!result.disposition || result.disposition === 'error') { + console.warn(`[Mail Manager][Store] - Entity move on "${sourceIdentifier}" returned an error: ${result.error})`) + failures.push(sourceIdentifier) return } + if (!result.disposition || (result.disposition !== 'moved' && result.disposition !== 'deleted')) { + console.warn(`[Mail Manager][Store] - Entity move on "${sourceIdentifier}" returned invalid disposition: ${result.disposition})`) + failures.push(sourceIdentifier) + return + } + + const cachedEntity = _entities.value[sourceIdentifier] + if (!cachedEntity) { + return + } + + if (result.disposition === 'moved') { + const mutation = parseEntityIdentifier(result.mutation?.identifier || sourceIdentifier) + const movedEntity = cachedEntity.clone().fromJson({ + ...cachedEntity.toJson(), + provider: mutation.provider, + service: mutation.service, + collection: mutation.collection, + identifier: mutation.identifier, + }) + const key = identifierKey(mutation.provider, mutation.service, mutation.collection, mutation.identifier) + _entities.value[key] = movedEntity + } + delete _entities.value[sourceIdentifier] + successes.push(sourceIdentifier) }) console.debug('[Mail Manager][Store] - Successfully deleted', Object.keys(response).length, 'entities') - return response + return [successes, failures] } catch (error: any) { console.error('[Mail Manager][Store] - Failed to delete entities:', error) throw error @@ -389,13 +418,23 @@ export const useEntitiesStore = defineStore('mailEntitiesStore', () => { * * @returns Promise with move results keyed by source identifier */ - async function move(target: CollectionIdentifier, sources: EntityIdentifier[]): Promise { + async function move(target: CollectionIdentifier, sources: EntityIdentifier[]): Promise { transceiving.value = true try { const response = await entityService.move({ target, sources }) + const successes: EntityIdentifier[] = [] + const failures: EntityIdentifier[] = [] Object.entries(response).forEach(([sourceIdentifier, result]) => { - if (!result.success) { + if (!result.disposition || result.disposition === 'error') { + console.warn(`[Mail Manager][Store] - Entity move on "${sourceIdentifier}" returned an error: ${result.error})`) + failures.push(sourceIdentifier) + return + } + + if (!result.disposition || result.disposition !== 'moved') { + console.warn(`[Mail Manager][Store] - Entity move on "${sourceIdentifier}" returned invalid disposition: ${result.disposition})`) + failures.push(sourceIdentifier) return } @@ -404,22 +443,23 @@ export const useEntitiesStore = defineStore('mailEntitiesStore', () => { return } - const destination = parseEntityIdentifier(result.identifier) + const mutation = parseEntityIdentifier(result.mutation?.identifier || sourceIdentifier) const movedEntity = cachedEntity.clone().fromJson({ ...cachedEntity.toJson(), - provider: destination.provider, - service: destination.service, - collection: destination.collection, - identifier: destination.identifier, + provider: mutation.provider, + service: mutation.service, + collection: mutation.collection, + identifier: mutation.identifier, }) + const movedKey = identifierKey(mutation.provider, mutation.service, mutation.collection, mutation.identifier) + _entities.value[movedKey] = movedEntity delete _entities.value[sourceIdentifier] - - _entities.value[result.identifier] = movedEntity + successes.push(sourceIdentifier) }) console.debug('[Mail Manager][Store] - Successfully moved', Object.keys(response).length, 'entities') - return response + return [successes, failures] } catch (error: any) { console.error('[Mail Manager][Store] - Failed to move entities:', error) throw error diff --git a/src/types/entity.ts b/src/types/entity.ts index a16e165..ba8e207 100644 --- a/src/types/entity.ts +++ b/src/types/entity.ts @@ -132,17 +132,13 @@ export interface EntityDeleteRequest { sources: EntityIdentifier[]; } -export interface EntityDeleteResultSuccess { - success: boolean; -} - -export interface EntityDeleteResultFailure { - success: boolean; - error: string; -} - export interface EntityDeleteResponse { - [sourceIdentifier: EntityIdentifier]: EntityDeleteResultSuccess | EntityDeleteResultFailure; + [sourceIdentifier: EntityIdentifier]: { + disposition: 'deleted' | 'moved' | 'error'; + destination: CollectionIdentifier | null; + mutation: EntityIdentifier | null; + error?: string; + }; } /** @@ -153,18 +149,13 @@ export interface EntityMoveRequest { sources: EntityIdentifier[]; } -export interface EntityMoveResultSuccess { - success: boolean; - identifier: EntityIdentifier; -} - -export interface EntityMoveResultFailure { - success: boolean; - error: string; -} - export interface EntityMoveResponse { - [sourceIdentifier: EntityIdentifier]: EntityMoveResultSuccess | EntityMoveResultFailure; + [sourceIdentifier: EntityIdentifier]: { + disposition: 'moved' | 'error'; + destination: CollectionIdentifier| null; + mutation: EntityIdentifier | null; + error?: string; + }; } /**