Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a2daf1f7de | |||
| a5eb104bd7 | |||
| 03862ed0cf | |||
| 0c7f103353 |
@@ -440,7 +440,14 @@ class CompositionManager {
|
||||
];
|
||||
}
|
||||
|
||||
$source = null;
|
||||
// Reuse the synced remote draft (if any) so the provider can natively clean it up
|
||||
$remoteEntity = $this->remoteEntityIdentifier($composed['remote']['entity'] ?? null);
|
||||
$source = ($remoteEntity !== null
|
||||
&& $remoteEntity->provider() === $service->provider()
|
||||
&& (string)$remoteEntity->service() === (string)$service->identifier())
|
||||
? $remoteEntity
|
||||
: null;
|
||||
|
||||
$properties = $this->buildMessageProperties(
|
||||
service: $service,
|
||||
sender: $senderObject,
|
||||
@@ -465,6 +472,8 @@ class CompositionManager {
|
||||
];
|
||||
}
|
||||
|
||||
$this->compositionStore->compositionDiscard($tenantId, $userId, $identifier);
|
||||
|
||||
return [
|
||||
'identifier' => $identifier,
|
||||
'disposition' => 'sent'
|
||||
@@ -582,6 +591,7 @@ class CompositionManager {
|
||||
$deviceAttachmentsChanged = $uploads !== [];
|
||||
$documentAttachmentsChanged = count($failed) < count($documents);
|
||||
if ($deviceAttachmentsChanged || $documentAttachmentsChanged) {
|
||||
$composed['revision'] = (int)($composed['revision'] ?? 0) + 1;
|
||||
$composed = $this->markRemoteDirty($composed);
|
||||
$compositionChanged = true;
|
||||
}
|
||||
@@ -616,6 +626,7 @@ class CompositionManager {
|
||||
];
|
||||
}
|
||||
if ($compositionChanged) {
|
||||
$result['revision'] = (int)($composed['revision'] ?? 0);
|
||||
$event = new CompositionSavedEvent($tenantId, $userId, $composition, (int)($composed['revision'] ?? 0));
|
||||
$this->events->dispatch($event);
|
||||
}
|
||||
@@ -774,8 +785,10 @@ class CompositionManager {
|
||||
}
|
||||
|
||||
unset($composed['attachments'][$identifier]);
|
||||
$composed['revision'] = (int)($composed['revision'] ?? 0) + 1;
|
||||
$composed = $this->markRemoteDirty($composed);
|
||||
$result['disposition'] = 'removed';
|
||||
$result['revision'] = $composed['revision'];
|
||||
return $composed;
|
||||
};
|
||||
|
||||
|
||||
Generated
+153
-153
@@ -795,49 +795,49 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tiptap/core": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.30.2.tgz",
|
||||
"integrity": "sha512-QbZC/s1OOqcoUdkhIY16TjR/gCtR0qAk9e4bJwUqOJqZuv5ozqCL5hzWm22jjTPp6c6Ei2tPd6t30VwfIKW4lQ==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.30.3.tgz",
|
||||
"integrity": "sha512-kDD8KY99lBCKntCqTBE9eNR1ul/i/wPFw2METWT+LYZvifljXq2oiX6JaGF1Sk59efe7+sq9IISxOk47YlBiWQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/pm": "3.30.2"
|
||||
"@tiptap/pm": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-blockquote": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.30.2.tgz",
|
||||
"integrity": "sha512-BOkwhZenek7vzXBOgKppSrlx4YryBdAYu1p1MXKn0R9A9eNmE2HVhmm0gG49+E8BhsE/TG8wKVclwET42JJiIg==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.30.3.tgz",
|
||||
"integrity": "sha512-Dh8yfEqBKTqEdBKZ4Ta3DkTecP0VJxvRNA5b1LCF7gBbe54Lm3A28UuVvK/Sdhh9FJDrIVCQTDS0yHGbi6G9ew==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2",
|
||||
"@tiptap/pm": "3.30.2"
|
||||
"@tiptap/core": "3.30.3",
|
||||
"@tiptap/pm": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bold": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.30.2.tgz",
|
||||
"integrity": "sha512-MsvJhPgYejY2D9MhwYJv8AmscozvLBI8qtJ7YLdYZBWkMR4bgmxHq5+xqEfBsao9bOMMwBon9p3+P+/Tq5ReWA==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.30.3.tgz",
|
||||
"integrity": "sha512-a4BSAjWRN4mWklRTdDCIaG9R+PqyUxXNYGQ2CLtOhO51Wq6daw2qFTHR+cTqAjaiiUSuDYII86UChb2qQRq8Lg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2"
|
||||
"@tiptap/core": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bubble-menu": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.30.2.tgz",
|
||||
"integrity": "sha512-oS0WiWNXHKpiPYMkcnHm1j7iEvufTGGtLFtcJJd3olb5OS6V2acoXVDL0nNJDmRQ32K3QXut3fbRcMseMxT+lw==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.30.3.tgz",
|
||||
"integrity": "sha512-YryCf9fq+9n1XIW6f5weSCD2MbL/LhRQ7jArRToQQ/oNxc422LqYVjijQQTNuk2cZEqE9fdO3Hw27tmwEEs9UQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
@@ -848,80 +848,80 @@
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2",
|
||||
"@tiptap/pm": "3.30.2"
|
||||
"@tiptap/core": "3.30.3",
|
||||
"@tiptap/pm": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bullet-list": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.30.2.tgz",
|
||||
"integrity": "sha512-+awIL/TUz4aB3rL68igU1rWfaaoBIAkPcakkktkRq8gYf0bd9eSb48P6kHkpx/3q+JyK7g9vsnltLNHNh6twnA==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.30.3.tgz",
|
||||
"integrity": "sha512-Z/ZqUfrd3Fd8hHpHEPv3XRzqwqVLD4CP67xFMyjy0cqEgnjgvd1iR6QzJsKD79V9zyu0Agu7ab9ZBf4NktpWcw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "3.30.2"
|
||||
"@tiptap/extension-list": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-code": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.30.2.tgz",
|
||||
"integrity": "sha512-r8EZk3R9yGpF6v5xxafAU1HwrD/e+RpbfnmVi2TeB/ZHAsVO62fW96E32G0t6IdaCtOFtAd85hkDAaOfCT4yGg==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.30.3.tgz",
|
||||
"integrity": "sha512-mOV4Fg+ji6uXmFxTMuug9WK6zk0ksNQepnuvoDR4g4d+tnz2y9iEbgOXFohVxhOXOLDLdNeKdwHxbHQdi5Ivbw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2"
|
||||
"@tiptap/core": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-code-block": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.30.2.tgz",
|
||||
"integrity": "sha512-9otGKaQZmePHrLXFtCtz+BYDn5z4sSumTkUqQIQHz0gVxwPoTi7g51RedwxvViTb/zu2XV5ROXYLHIxKxypMPg==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.30.3.tgz",
|
||||
"integrity": "sha512-xT2cDil/ipy/LklPgv/JqSsXys1mjcqlIPDUetK3llB2DT7XZssYPV3qv278tqRO4pJDbrXk82I6Lh7vLwmIAg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2",
|
||||
"@tiptap/pm": "3.30.2"
|
||||
"@tiptap/core": "3.30.3",
|
||||
"@tiptap/pm": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-document": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.30.2.tgz",
|
||||
"integrity": "sha512-+xIv67V+/2L1uvz98FAT5W7kWEfHwfNV3MD7b4UsKPU0lhcCWuVOXy0JB8yYmdNExqpI7xT9g3MWzREoBvBQSg==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.30.3.tgz",
|
||||
"integrity": "sha512-B9gqrgM1uHjCKr/PSnnSl+bS+YQb5EN/PUW9KWp9nSgmIaqxXws2ufqowS65uTLJLqd7pwF4l5lUrsfhq0EKzw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2"
|
||||
"@tiptap/core": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-dropcursor": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.30.2.tgz",
|
||||
"integrity": "sha512-nyRKUmItATnKI9AiRChmjhcBbCEsNxRu+AaCz+cx8EvnAcNHsVRdNYL5PmBs3WlNA/Et4Eb2DG0hVQDnNF61eg==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.30.3.tgz",
|
||||
"integrity": "sha512-xdY66lcQakBLvWbJQHeJy/Td0f10YRXLyFeOFzt9PODsX4nqwJMju9tpqcLIGp0waaztu8PGwZ81oSCdQldIHQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extensions": "3.30.2"
|
||||
"@tiptap/extensions": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-floating-menu": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.30.2.tgz",
|
||||
"integrity": "sha512-A8PLvvh8W6PUMrqh+EpBerxm+Ucr0irGxJvwAnzYQmNGNIJ9U4OVgw4OcEU+9JH0gMmEzDcHzMPP2s/s1lIcyw==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.30.3.tgz",
|
||||
"integrity": "sha512-4l5Qee1wBk2YBFEFbWHFhUt++6hDY7Yp81BkO3wY6KFToxs+cm9JIm3xr3KF9UJ/vnUpIhBWIbZl3uKf37SJLA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"funding": {
|
||||
@@ -930,80 +930,80 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@floating-ui/dom": "^1.0.0",
|
||||
"@tiptap/core": "3.30.2",
|
||||
"@tiptap/pm": "3.30.2"
|
||||
"@tiptap/core": "3.30.3",
|
||||
"@tiptap/pm": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-gapcursor": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.30.2.tgz",
|
||||
"integrity": "sha512-7Xk0ut6FM+RAsvKxDN3bAtk7zvYZ6Aa8pawJ6s7dLAmLR9JwrZevlcL4FSrj4bR7rqKOj92RYCFxzgTEbWimag==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.30.3.tgz",
|
||||
"integrity": "sha512-+mwm64+RiArd1G8xSgtaTrvx1X5Lzz6sJ93zTmaiMVNc2N29AN77BVPTJ0e+853+/F6Bec/vOnVkIjTLg/ZBRw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extensions": "3.30.2"
|
||||
"@tiptap/extensions": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-hard-break": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.30.2.tgz",
|
||||
"integrity": "sha512-IxSNgmG3d4OZdUTeebrOI7SxdIWXXJqlcGiSNDabWqxipUitfy3mZ3gDDE6G01koKxZRbhz4KIplAZlpxnTFSg==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.30.3.tgz",
|
||||
"integrity": "sha512-/tX+IFW2C4RJltbwcn8/4zoHwj5YycRNOugb4Ul9Fl1AOJqjNwRx8xc0NpaOjuADhlMYMczEtSaOiDh5ZEOmjg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2"
|
||||
"@tiptap/core": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-heading": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.30.2.tgz",
|
||||
"integrity": "sha512-PblDvgSJ05p1t6hzyPi02xeiBjB0M2abReoGEImqSWCy79UqnAGacgsZo4EeEawtJV1NEP8chhvmX+nRtzdT1A==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.30.3.tgz",
|
||||
"integrity": "sha512-y+0u9qdrUAOGNrP52hAEiH1mvr1ZmzmkCBICICiXRH4+QNXpKkiBK3zlbDOPVQj0g0YIg6XIIU0vIaUBDPIaMQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2"
|
||||
"@tiptap/core": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-horizontal-rule": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.30.2.tgz",
|
||||
"integrity": "sha512-j8aswLTsuEdJKC62DF+kw0EgvIRL7QMUyAVp2fdjR0qgM0ZVlEwCC4qIEq3kK9tFVU4kRtQ5BSj/jn6QwrlbCA==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.30.3.tgz",
|
||||
"integrity": "sha512-J/ioKlXu5oJ+pPtybFonByx1LusbR0PUd1nkx6XsZqY9wyW6uecZQgAyI8KUWIXqOfhnAW38UTsHMBRdm2XupA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2",
|
||||
"@tiptap/pm": "3.30.2"
|
||||
"@tiptap/core": "3.30.3",
|
||||
"@tiptap/pm": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-italic": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.30.2.tgz",
|
||||
"integrity": "sha512-pp8uaiuXsUbLm5rYzR1jlWbwm1mAahRajdHwAKBtthFRB2rDvC7ZWhKaCSoKhZvfIDRmu9/B67+uAHoutL0dCA==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.30.3.tgz",
|
||||
"integrity": "sha512-dVWqJ/kDXdPHRBp4nU7bwi2G+c3oNruIgQHYVRgYlWkwW/opvnlACZLBUgEhihH7ANiSaGW1zLQ7HuUDSL3vog==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2"
|
||||
"@tiptap/core": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-link": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.30.2.tgz",
|
||||
"integrity": "sha512-jwdcymKcrbFpj5hRAuGVLCq8FieVkGFnENyroYmvkad+XAt8ZLy/MTFYRN6SK3ukH6PZMY7H4iObGtciQaC5nw==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.30.3.tgz",
|
||||
"integrity": "sha512-MAAXfLJNf6ZFiFK3w51yiLKc31HAQWJWNV+nQ1dAdRpa6WiXdjpkcrWTuxmPd/o6Qt+yNv+hoItAVxDPEox8qQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"linkifyjs": "^4.3.3"
|
||||
@@ -1013,159 +1013,159 @@
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2",
|
||||
"@tiptap/pm": "3.30.2"
|
||||
"@tiptap/core": "3.30.3",
|
||||
"@tiptap/pm": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.30.2.tgz",
|
||||
"integrity": "sha512-MIUpo1Bd9Rf1Qg+TNYNwDZ4xsfFeQahjU9Xhy6UcaszKQzbAM7KCzn5BObNytK1NdcqNHsC8Wj5vFvMKEzrXdw==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.30.3.tgz",
|
||||
"integrity": "sha512-cCX99WoVb4UyXkamSh0vlXiRFhlZnwk3WXWdnXpR1E9+auxsQewk2Q9NDW1Ra0vwgzer1gkFhlOl9TCVzH2VVg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2",
|
||||
"@tiptap/pm": "3.30.2"
|
||||
"@tiptap/core": "3.30.3",
|
||||
"@tiptap/pm": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list-item": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.30.2.tgz",
|
||||
"integrity": "sha512-HWgRCRlGxulE+hN1VUcnWD6P2NE08VBgGtcaxOfdXVqaI93BCK6AhRQZGpLsfKgajLk+5DXTBraaitwnBqzCxg==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.30.3.tgz",
|
||||
"integrity": "sha512-RhSyDlAATvXDTg/1VOw5aFTaewdCm+BAU3EG3eUCw4e5eoZ5pbhPOdOPTtaO45UR4i/AvjQNAZQ9LMDWX5WZFQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "3.30.2"
|
||||
"@tiptap/extension-list": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list-keymap": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.30.2.tgz",
|
||||
"integrity": "sha512-TTve3WOlQaYu1ahMqsQ/T0wzaxfgZvcOl3/OuPyInOi8QtxXhqGhFjmYe5jOr56G9W2QDuFWVsZecVwfDte9zg==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.30.3.tgz",
|
||||
"integrity": "sha512-u6tOpQFnE1pOyvnzI2MvhW/Yw0omAIMlMfkykYx4N4zB1JDi+16OeOuKf3rX6G3V9VUu+qeOIGpSkifkME6H9Q==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "3.30.2"
|
||||
"@tiptap/extension-list": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-ordered-list": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.30.2.tgz",
|
||||
"integrity": "sha512-Z7OO1HcF0idda1n6vodXeQ3h2ylN9JR4IfIGUYkar5Xl9JusK8PDETTBQZQn//96p49I2d+GoWsD2LXPtjHXXg==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.30.3.tgz",
|
||||
"integrity": "sha512-lct/FV8vm9Y5kZFcF5TXIM18opi6m7AAkGoChgGP/A7LYalaniX1X6Ja2j13Y22ZdGaOoPTgd8oKRZXP1/miaA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "3.30.2"
|
||||
"@tiptap/extension-list": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-paragraph": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.30.2.tgz",
|
||||
"integrity": "sha512-ulEu3LNt+kPVAWEnrhoz13Fs8Q/v/8NUxQbAeteuBchQ8joxJXuWExhpy1fUfZir5+b+W5z7/NesgPjZQfv47w==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.30.3.tgz",
|
||||
"integrity": "sha512-Z9OHCX9b2bDcMDeR3ODCFRAyHT5eNGO4AsDFeAJS/XSitffMyjFHtOkXlyyZ3+pIHxxX6xkUXAwaLMjyATRo1A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2"
|
||||
"@tiptap/core": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-placeholder": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-3.30.2.tgz",
|
||||
"integrity": "sha512-Bj1seUvPCoRrD/LpzMoKD+jQIjxuc+oq931GpPq4wobSUUbD4pF/0NMwpCLpiHO19QnTQz8+9p2dqPdlc44LHA==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-3.30.3.tgz",
|
||||
"integrity": "sha512-B7LwMzeQajQ18FWPGYv2UDh64HSUfXxh/mdIhS6ZQEDJS9NyUD0hPPnwaMQ1w870L/APgJdb2/EGqIkZqjJRSg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extensions": "3.30.2"
|
||||
"@tiptap/extensions": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-strike": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.30.2.tgz",
|
||||
"integrity": "sha512-fBLxMXz6hYIURzLOD+/L6aVATztsKham00ANWmGi13vN0hx2lQMYZffN+gR+QqiCDfMQxBXzrf5a7tJuDiQHLQ==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.30.3.tgz",
|
||||
"integrity": "sha512-e9BI8Hzei23GjmYysXxL+CHq3fIgOm29BbSUMbYXxT2cJ+TkkgJp7EvHf74gSABNME0gUN+mG0pRR5wTFoOCcg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2"
|
||||
"@tiptap/core": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-text": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.30.2.tgz",
|
||||
"integrity": "sha512-n/iZnirgRmXet6f97kolAnP3j8DsgLSiTbz/KLWc8eBYiFmkjRzkuisOm5xuGdfGIxwpB4x3tlSF4ef4DLnbRg==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.30.3.tgz",
|
||||
"integrity": "sha512-Jh8ZyI0HLOJOIPZl5a5XRJbTs4pAUakYIWCZ3Hv3lF9ouXW/C0bY67XQU7bv6Rvu8AHzDszhKklnOZ6z1NQPXQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2"
|
||||
"@tiptap/core": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-text-align": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-3.30.2.tgz",
|
||||
"integrity": "sha512-zexiz0uJlX2KzeAyYI/uEoBsl0Zw3Ua0CTV/kRKTnk7K9vCOnwvJXtXdkHA4WC12ACqUsPnyc4yMTwDR22fKFw==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-3.30.3.tgz",
|
||||
"integrity": "sha512-pwIZMn/PYoWZiUXrrD9oomV+Oh/GGhlIpa7Hr2WxdI8k3HZraweHa8S3ygvCUbodo9BWSI4zBs4KM3ic50cwlg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2"
|
||||
"@tiptap/core": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-underline": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.30.2.tgz",
|
||||
"integrity": "sha512-SZiTMnvqXcnrtJX+X25ZbYsuDO83haGOVMBD/O+mAWYNYXhaSc5Rkph5czzItxrd+Yyp/vs4PiwD7XTNbfqmpA==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.30.3.tgz",
|
||||
"integrity": "sha512-TiZ+b524Ee4PNlW+HNmkg3x4btR1K6btJy9pEjMuDf0Rx01UaTBvHpHmABR/DbbcC1CuZiQ3ylJwLL+90PaEoA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2"
|
||||
"@tiptap/core": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extensions": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.30.2.tgz",
|
||||
"integrity": "sha512-2LqAHXk26QDsryW+beECxYeBzv5Ylk4GuB3cOmfghS7/G37R2W+Te3TkUK7BT0EWoDryvBT57/5q0DEFIhfZZg==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.30.3.tgz",
|
||||
"integrity": "sha512-vig8ZjUL/NFnniEVbYDYj2UOIdkwZVha+9myFZkanShedviE3kl7c4uCY3fMl5EnqgyFIy2TQSKbg/i99xpztA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.30.2",
|
||||
"@tiptap/pm": "3.30.2"
|
||||
"@tiptap/core": "3.30.3",
|
||||
"@tiptap/pm": "3.30.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/pm": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.30.2.tgz",
|
||||
"integrity": "sha512-BJN8tUx4ppFN3R3cV/FJfrJbJkvo1lj4uciq+nwpjwzdRvFzqIuglWf+HLcJ6CwlYpLOHp7ArgkBg4Q5e60Gog==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.30.3.tgz",
|
||||
"integrity": "sha512-VheaqLAFUe+PCYEgHubM96Z1OAiluFhijQ2Cy1Ghiozoxm5OzevSaKhqm8SQ1VGfzZZko59oUjRzOmu8tB8yfA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-changeset": "^2.4.1",
|
||||
@@ -1188,35 +1188,35 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/starter-kit": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.30.2.tgz",
|
||||
"integrity": "sha512-fJSrhW1CyD4sjYA20evSP4Cp13B/HhbxCdM974K0xpHOVqvCtNU9w2s9hfq9mg2yGoU7MSNHKNYMkJjIi2/Xyw==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.30.3.tgz",
|
||||
"integrity": "sha512-hj4rAhAoQm+wRk8eLNTyK+wK81+epbuo4O9PvPRv7GJGwYycej+xUN7jGM7Tney7GuTZpHoDCuwLKD2n1oG+pg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tiptap/core": "3.30.2",
|
||||
"@tiptap/extension-blockquote": "3.30.2",
|
||||
"@tiptap/extension-bold": "3.30.2",
|
||||
"@tiptap/extension-bullet-list": "3.30.2",
|
||||
"@tiptap/extension-code": "3.30.2",
|
||||
"@tiptap/extension-code-block": "3.30.2",
|
||||
"@tiptap/extension-document": "3.30.2",
|
||||
"@tiptap/extension-dropcursor": "3.30.2",
|
||||
"@tiptap/extension-gapcursor": "3.30.2",
|
||||
"@tiptap/extension-hard-break": "3.30.2",
|
||||
"@tiptap/extension-heading": "3.30.2",
|
||||
"@tiptap/extension-horizontal-rule": "3.30.2",
|
||||
"@tiptap/extension-italic": "3.30.2",
|
||||
"@tiptap/extension-link": "3.30.2",
|
||||
"@tiptap/extension-list": "3.30.2",
|
||||
"@tiptap/extension-list-item": "3.30.2",
|
||||
"@tiptap/extension-list-keymap": "3.30.2",
|
||||
"@tiptap/extension-ordered-list": "3.30.2",
|
||||
"@tiptap/extension-paragraph": "3.30.2",
|
||||
"@tiptap/extension-strike": "3.30.2",
|
||||
"@tiptap/extension-text": "3.30.2",
|
||||
"@tiptap/extension-underline": "3.30.2",
|
||||
"@tiptap/extensions": "3.30.2",
|
||||
"@tiptap/pm": "3.30.2"
|
||||
"@tiptap/core": "3.30.3",
|
||||
"@tiptap/extension-blockquote": "3.30.3",
|
||||
"@tiptap/extension-bold": "3.30.3",
|
||||
"@tiptap/extension-bullet-list": "3.30.3",
|
||||
"@tiptap/extension-code": "3.30.3",
|
||||
"@tiptap/extension-code-block": "3.30.3",
|
||||
"@tiptap/extension-document": "3.30.3",
|
||||
"@tiptap/extension-dropcursor": "3.30.3",
|
||||
"@tiptap/extension-gapcursor": "3.30.3",
|
||||
"@tiptap/extension-hard-break": "3.30.3",
|
||||
"@tiptap/extension-heading": "3.30.3",
|
||||
"@tiptap/extension-horizontal-rule": "3.30.3",
|
||||
"@tiptap/extension-italic": "3.30.3",
|
||||
"@tiptap/extension-link": "3.30.3",
|
||||
"@tiptap/extension-list": "3.30.3",
|
||||
"@tiptap/extension-list-item": "3.30.3",
|
||||
"@tiptap/extension-list-keymap": "3.30.3",
|
||||
"@tiptap/extension-ordered-list": "3.30.3",
|
||||
"@tiptap/extension-paragraph": "3.30.3",
|
||||
"@tiptap/extension-strike": "3.30.3",
|
||||
"@tiptap/extension-text": "3.30.3",
|
||||
"@tiptap/extension-underline": "3.30.3",
|
||||
"@tiptap/extensions": "3.30.3",
|
||||
"@tiptap/pm": "3.30.3"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -1224,22 +1224,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/vue-3": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/vue-3/-/vue-3-3.30.2.tgz",
|
||||
"integrity": "sha512-7TCahsK19ChY60FvgseTuzaz67yR1tkzTbKW6s3iXx9NTiU411C6WEQAS/EtPt4dsGDv/esFjSc9EMKilRhY5g==",
|
||||
"version": "3.30.3",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/vue-3/-/vue-3-3.30.3.tgz",
|
||||
"integrity": "sha512-lmGTJgHd1CuYjRmedtKPHRFvOPGWmC/sqBPr9DVCq6Te4tECdi6q7/EiYrhfiTkCptvPxub/06JQJVnvP+lytg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tiptap/extension-bubble-menu": "^3.30.2",
|
||||
"@tiptap/extension-floating-menu": "^3.30.2"
|
||||
"@tiptap/extension-bubble-menu": "^3.30.3",
|
||||
"@tiptap/extension-floating-menu": "^3.30.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@floating-ui/dom": "^1.0.0",
|
||||
"@tiptap/core": "3.30.2",
|
||||
"@tiptap/pm": "3.30.2",
|
||||
"@tiptap/core": "3.30.3",
|
||||
"@tiptap/pm": "3.30.3",
|
||||
"vue": "^3.0.0"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -380,6 +380,10 @@ export const useMailCompositionStore = defineStore('mailCompositionStore', () =>
|
||||
source: attachment.source,
|
||||
}
|
||||
})
|
||||
|
||||
if (response.revision !== undefined) {
|
||||
activeDraft.value.revision = response.revision
|
||||
}
|
||||
}
|
||||
|
||||
async function addAttachmentsFromDocuments(items: { identifier: string; name: string; mimeType?: string; size?: number }[]) {
|
||||
@@ -432,6 +436,10 @@ export const useMailCompositionStore = defineStore('mailCompositionStore', () =>
|
||||
}
|
||||
})
|
||||
|
||||
if (response.revision !== undefined) {
|
||||
activeDraft.value.revision = response.revision
|
||||
}
|
||||
|
||||
if (response.failed?.length) {
|
||||
mailUiStore.notify(
|
||||
response.failed.length === 1
|
||||
@@ -462,8 +470,11 @@ export const useMailCompositionStore = defineStore('mailCompositionStore', () =>
|
||||
if (response.disposition === 'error') {
|
||||
console.error('[Mail][Composer] Failed to remove attachment:', response.error)
|
||||
}
|
||||
|
||||
|
||||
delete activeDraft.value.attachments[attachment.identifier]
|
||||
if (response.revision !== undefined) {
|
||||
activeDraft.value.revision = response.revision
|
||||
}
|
||||
}
|
||||
|
||||
function queueSave(immediate: boolean) {
|
||||
|
||||
@@ -111,6 +111,7 @@ export interface CompositionAttachmentAddResponse {
|
||||
message: string
|
||||
}
|
||||
composition: string
|
||||
revision?: number
|
||||
attachments: Record<string, CompositionAttachmentInterface>
|
||||
failed?: {
|
||||
identifier: string
|
||||
@@ -131,4 +132,5 @@ export interface CompositionAttachmentRemoveResponse {
|
||||
}
|
||||
composition: string
|
||||
identifier: string
|
||||
revision?: number
|
||||
}
|
||||
@@ -187,6 +187,7 @@ final class CompositionManagerTest extends TestCase {
|
||||
$this->assertSame('added', $result['disposition']);
|
||||
$this->assertCount(1, $result['attachments']);
|
||||
$this->assertSame([], $result['failed']);
|
||||
$this->assertSame(1, $result['revision']);
|
||||
|
||||
$attachment = $result['attachments']['attach-1'];
|
||||
$this->assertSame('documents', $attachment['origin']);
|
||||
@@ -196,11 +197,58 @@ final class CompositionManagerTest extends TestCase {
|
||||
$this->assertSame(strlen('hello world'), $attachment['size']);
|
||||
|
||||
$snapshot = $this->compositionStore->compositionFetch(self::TENANT_ID, self::USER_ID, $compositionId);
|
||||
$this->assertSame(1, $snapshot['revision']);
|
||||
$this->assertSame('dirty', $snapshot['remote']['status']);
|
||||
$this->assertNull($snapshot['remote']['entity']);
|
||||
$this->assertNull($snapshot['remote']['error']);
|
||||
}
|
||||
|
||||
public function testAttachmentAddIncrementsRevisionOnSubsequentAdd(): void {
|
||||
$compositionId = $this->stageEmptyComposition();
|
||||
$documentsManager = $this->createStub(\KTXM\DocumentsManager\Manager::class);
|
||||
$documentsManager->method('entityFetchBulk')->willReturn([
|
||||
$this->makeEntity('default:personal:root:doc1', 'hello.txt', 'text/plain'),
|
||||
$this->makeEntity('default:personal:root:doc2', 'world.txt', 'text/plain'),
|
||||
]);
|
||||
$documentsManager->method('entityReadStream')->willReturnCallback(
|
||||
fn(): mixed => $this->makeStream('hello world'),
|
||||
);
|
||||
$manager = $this->makeManager($documentsManager);
|
||||
|
||||
$manager->attachmentAdd(self::TENANT_ID, self::USER_ID, $compositionId, [
|
||||
'identifier' => 'attach-1',
|
||||
'origin' => 'documents',
|
||||
'source' => 'default:personal:root:doc1',
|
||||
]);
|
||||
$result = $manager->attachmentAdd(self::TENANT_ID, self::USER_ID, $compositionId, [
|
||||
'identifier' => 'attach-2',
|
||||
'origin' => 'documents',
|
||||
'source' => 'default:personal:root:doc2',
|
||||
]);
|
||||
|
||||
$this->assertSame(2, $result['revision']);
|
||||
}
|
||||
|
||||
public function testAttachmentAddDoesNotChangeRevisionWhenNothingIsAdded(): void {
|
||||
$compositionId = $this->stageEmptyComposition();
|
||||
$documentsManager = $this->createStub(\KTXM\DocumentsManager\Manager::class);
|
||||
// documents_manager unavailable means the sourced attachment fails
|
||||
// entirely, so no attachment is actually added to the composition.
|
||||
$manager = $this->makeManager($documentsManager, documentsModuleEnabled: false);
|
||||
|
||||
$result = $manager->attachmentAdd(self::TENANT_ID, self::USER_ID, $compositionId, [
|
||||
'identifier' => 'attach-1',
|
||||
'origin' => 'documents',
|
||||
'source' => 'default:personal:root:doc1',
|
||||
]);
|
||||
|
||||
$this->assertSame('error', $result['disposition']);
|
||||
$this->assertArrayNotHasKey('revision', $result);
|
||||
|
||||
$snapshot = $this->compositionStore->compositionFetch(self::TENANT_ID, self::USER_ID, $compositionId);
|
||||
$this->assertArrayNotHasKey('revision', $snapshot);
|
||||
}
|
||||
|
||||
public function testAttachmentAddFromDocumentsPartialFailure(): void {
|
||||
$compositionId = $this->stageEmptyComposition();
|
||||
$documentsManager = $this->createStub(\KTXM\DocumentsManager\Manager::class);
|
||||
@@ -285,6 +333,45 @@ final class CompositionManagerTest extends TestCase {
|
||||
$this->assertStringContainsString('not installed or enabled', $result['failed'][0]['message']);
|
||||
}
|
||||
|
||||
public function testAttachmentRemoveIncrementsRevision(): void {
|
||||
$compositionId = $this->stageEmptyComposition();
|
||||
$documentsManager = $this->createStub(\KTXM\DocumentsManager\Manager::class);
|
||||
$documentsManager->method('entityFetchBulk')->willReturn([
|
||||
$this->makeEntity('default:personal:root:doc1', 'hello.txt', 'text/plain'),
|
||||
]);
|
||||
$documentsManager->method('entityReadStream')->willReturn($this->makeStream('hello world'));
|
||||
$manager = $this->makeManager($documentsManager);
|
||||
|
||||
$added = $manager->attachmentAdd(self::TENANT_ID, self::USER_ID, $compositionId, [
|
||||
'identifier' => 'attach-1',
|
||||
'origin' => 'documents',
|
||||
'source' => 'default:personal:root:doc1',
|
||||
]);
|
||||
$this->assertSame(1, $added['revision']);
|
||||
|
||||
$result = $manager->attachmentRemove(self::TENANT_ID, self::USER_ID, $compositionId, 'attach-1');
|
||||
|
||||
$this->assertSame('removed', $result['disposition']);
|
||||
$this->assertSame(2, $result['revision']);
|
||||
|
||||
$snapshot = $this->compositionStore->compositionFetch(self::TENANT_ID, self::USER_ID, $compositionId);
|
||||
$this->assertSame(2, $snapshot['revision']);
|
||||
$this->assertArrayNotHasKey('attach-1', $snapshot['attachments']);
|
||||
$this->assertSame('dirty', $snapshot['remote']['status']);
|
||||
}
|
||||
|
||||
public function testAttachmentRemoveNotFoundDoesNotChangeRevision(): void {
|
||||
$compositionId = $this->stageEmptyComposition();
|
||||
$documentsManager = $this->createStub(\KTXM\DocumentsManager\Manager::class);
|
||||
$manager = $this->makeManager($documentsManager);
|
||||
|
||||
$result = $manager->attachmentRemove(self::TENANT_ID, self::USER_ID, $compositionId, 'missing-attachment');
|
||||
|
||||
$this->assertSame('error', $result['disposition']);
|
||||
$this->assertSame('attachment_not_found', $result['error']['type']);
|
||||
$this->assertArrayNotHasKey('revision', $result);
|
||||
}
|
||||
|
||||
private function makeManager(
|
||||
Stub $documentsManager,
|
||||
bool $documentsModuleEnabled = true,
|
||||
|
||||
@@ -12,6 +12,8 @@ use KTXF\Mail\Entity\EntityMutableInterface;
|
||||
use KTXF\Mail\Object\MessagePropertiesMutableInterface;
|
||||
use KTXF\Mail\Service\ServiceBaseInterface;
|
||||
use KTXF\Mail\Service\ServiceEntityMutableInterface;
|
||||
use KTXF\Mail\Service\ServiceEntitySubmitInterface;
|
||||
use KTXF\Mail\Submission\EntitySubmitResult;
|
||||
use KTXF\Resource\Filter\IFilter;
|
||||
use KTXF\Resource\Identifier\CollectionIdentifier;
|
||||
use KTXF\Resource\Identifier\EntityIdentifier;
|
||||
@@ -257,6 +259,133 @@ final class CompositionSynchronizationTest extends TestCase {
|
||||
));
|
||||
}
|
||||
|
||||
public function testSendPurgesLocalCompositionOnSuccess(): void {
|
||||
$this->stageComposition();
|
||||
$properties = $this->createStub(MessagePropertiesMutableInterface::class);
|
||||
$service = $this->submitService($properties);
|
||||
$service->method('entitySubmit')->willReturn(new EntitySubmitResult(EntitySubmitResult::DISPOSITION_SENT));
|
||||
|
||||
$mailManager = $this->createStub(\KTXM\MailManager\Manager::class);
|
||||
$mailManager->method('serviceFindByAddress')->willReturn($service);
|
||||
|
||||
$result = $this->compositionManager($mailManager)->send(
|
||||
self::TENANT_ID,
|
||||
self::USER_ID,
|
||||
self::COMPOSITION_ID,
|
||||
['address' => 'sender@example.com'],
|
||||
['subject' => 'Sent draft'],
|
||||
[],
|
||||
);
|
||||
|
||||
$this->assertSame('sent', $result['disposition']);
|
||||
$this->assertNull($this->compositionStore->compositionFetch(
|
||||
self::TENANT_ID,
|
||||
self::USER_ID,
|
||||
self::COMPOSITION_ID,
|
||||
));
|
||||
}
|
||||
|
||||
public function testSendReusesSyncedRemoteDraftAsSubmissionSource(): void {
|
||||
$this->stageComposition('provider:service:drafts:remote-1');
|
||||
$properties = $this->createStub(MessagePropertiesMutableInterface::class);
|
||||
$service = $this->createMockForIntersectionOfInterfaces([
|
||||
ServiceBaseInterface::class,
|
||||
ServiceEntitySubmitInterface::class,
|
||||
]);
|
||||
$entity = $this->createStub(EntityMutableInterface::class);
|
||||
$entity->method('getProperties')->willReturn($properties);
|
||||
$service->method('provider')->willReturn('provider');
|
||||
$service->method('identifier')->willReturn('service');
|
||||
$service->method('getEnabled')->willReturn(true);
|
||||
$service->method('entityFresh')->willReturn($entity);
|
||||
$service->expects($this->once())
|
||||
->method('entitySubmit')
|
||||
->with(
|
||||
$this->anything(),
|
||||
$this->callback(static fn(?EntityIdentifier $source): bool => $source !== null
|
||||
&& (string)$source === 'provider:service:drafts:remote-1'),
|
||||
$properties,
|
||||
)
|
||||
->willReturn(new EntitySubmitResult(EntitySubmitResult::DISPOSITION_SENT));
|
||||
|
||||
$mailManager = $this->createStub(\KTXM\MailManager\Manager::class);
|
||||
$mailManager->method('serviceFindByAddress')->willReturn($service);
|
||||
|
||||
$result = $this->compositionManager($mailManager)->send(
|
||||
self::TENANT_ID,
|
||||
self::USER_ID,
|
||||
self::COMPOSITION_ID,
|
||||
['address' => 'sender@example.com'],
|
||||
['subject' => 'Sent draft'],
|
||||
[],
|
||||
);
|
||||
|
||||
$this->assertSame('sent', $result['disposition']);
|
||||
}
|
||||
|
||||
public function testSendIgnoresRemoteDraftBelongingToAnotherService(): void {
|
||||
$this->stageComposition('provider:other-service:drafts:remote-1');
|
||||
$properties = $this->createStub(MessagePropertiesMutableInterface::class);
|
||||
$service = $this->createMockForIntersectionOfInterfaces([
|
||||
ServiceBaseInterface::class,
|
||||
ServiceEntitySubmitInterface::class,
|
||||
]);
|
||||
$entity = $this->createStub(EntityMutableInterface::class);
|
||||
$entity->method('getProperties')->willReturn($properties);
|
||||
$service->method('provider')->willReturn('provider');
|
||||
$service->method('identifier')->willReturn('service');
|
||||
$service->method('getEnabled')->willReturn(true);
|
||||
$service->method('entityFresh')->willReturn($entity);
|
||||
$service->expects($this->once())
|
||||
->method('entitySubmit')
|
||||
->with($this->anything(), $this->isNull(), $properties)
|
||||
->willReturn(new EntitySubmitResult(EntitySubmitResult::DISPOSITION_SENT));
|
||||
|
||||
$mailManager = $this->createStub(\KTXM\MailManager\Manager::class);
|
||||
$mailManager->method('serviceFindByAddress')->willReturn($service);
|
||||
|
||||
$result = $this->compositionManager($mailManager)->send(
|
||||
self::TENANT_ID,
|
||||
self::USER_ID,
|
||||
self::COMPOSITION_ID,
|
||||
['address' => 'sender@example.com'],
|
||||
['subject' => 'Sent draft'],
|
||||
[],
|
||||
);
|
||||
|
||||
$this->assertSame('sent', $result['disposition']);
|
||||
}
|
||||
|
||||
public function testSendFailureKeepsLocalComposition(): void {
|
||||
$this->stageComposition();
|
||||
$properties = $this->createStub(MessagePropertiesMutableInterface::class);
|
||||
$service = $this->submitService($properties);
|
||||
$service->method('entitySubmit')->willReturn(new EntitySubmitResult(
|
||||
EntitySubmitResult::DISPOSITION_ERROR,
|
||||
errorMessage: 'Transport unavailable',
|
||||
));
|
||||
|
||||
$mailManager = $this->createStub(\KTXM\MailManager\Manager::class);
|
||||
$mailManager->method('serviceFindByAddress')->willReturn($service);
|
||||
|
||||
$result = $this->compositionManager($mailManager)->send(
|
||||
self::TENANT_ID,
|
||||
self::USER_ID,
|
||||
self::COMPOSITION_ID,
|
||||
['address' => 'sender@example.com'],
|
||||
['subject' => 'Keep this draft'],
|
||||
[],
|
||||
);
|
||||
|
||||
$this->assertSame('error', $result['disposition']);
|
||||
$this->assertSame('Transport unavailable', $result['error']['message']);
|
||||
$this->assertNotNull($this->compositionStore->compositionFetch(
|
||||
self::TENANT_ID,
|
||||
self::USER_ID,
|
||||
self::COMPOSITION_ID,
|
||||
));
|
||||
}
|
||||
|
||||
private function stageComposition(?string $remoteEntity = null): void {
|
||||
$saveComposition = static fn(): array => [
|
||||
'identifier' => self::COMPOSITION_ID,
|
||||
@@ -292,6 +421,20 @@ final class CompositionSynchronizationTest extends TestCase {
|
||||
return $service;
|
||||
}
|
||||
|
||||
private function submitService(MessagePropertiesMutableInterface $properties): ServiceBaseInterface&ServiceEntitySubmitInterface&Stub {
|
||||
$service = $this->createStubForIntersectionOfInterfaces([
|
||||
ServiceBaseInterface::class,
|
||||
ServiceEntitySubmitInterface::class,
|
||||
]);
|
||||
$entity = $this->createStub(EntityMutableInterface::class);
|
||||
$entity->method('getProperties')->willReturn($properties);
|
||||
$service->method('provider')->willReturn('provider');
|
||||
$service->method('identifier')->willReturn('service');
|
||||
$service->method('getEnabled')->willReturn(true);
|
||||
$service->method('entityFresh')->willReturn($entity);
|
||||
return $service;
|
||||
}
|
||||
|
||||
private function compositionManager(\KTXM\MailManager\Manager $mailManager): CompositionManager {
|
||||
return new CompositionManager(
|
||||
container: $this->createStub(ContainerInterface::class),
|
||||
|
||||
Reference in New Issue
Block a user