feat: listen to user life cycle events
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KTXM\ProviderLocalDocuments\Listeners;
|
||||
|
||||
use KTXC\User\Event\UserCreatedEvent;
|
||||
use KTXC\User\Event\UserDeletingEvent;
|
||||
use KTXM\ProviderLocalDocuments\Providers\Personal\PersonalService;
|
||||
use KTXM\ProviderLocalDocuments\Providers\Provider;
|
||||
|
||||
final class UserEventListener
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Provider $provider,
|
||||
) {
|
||||
}
|
||||
|
||||
public function onUserCreated(UserCreatedEvent $event): void
|
||||
{
|
||||
// Fetching initializes the virtual root and creates its disk location.
|
||||
$this->provider->serviceFetch($event->tenantIdentifier(), $event->userIdentifier(), 'personal');
|
||||
}
|
||||
|
||||
public function onUserDeleting(UserDeletingEvent $event): void
|
||||
{
|
||||
$service = $this->provider->serviceFetch($event->tenantIdentifier(), $event->userIdentifier(), 'personal');
|
||||
if (!($service instanceof PersonalService)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$service->destroy();
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,14 @@
|
||||
namespace KTXM\ProviderLocalDocuments;
|
||||
|
||||
use KTXC\Resource\ProviderManager;
|
||||
use KTXC\User\Event\UserCreatedEvent;
|
||||
use KTXC\User\Event\UserDeletingEvent;
|
||||
use KTXF\Event\DeliveryMode;
|
||||
use KTXF\Event\EventListenerRegistrarInterface;
|
||||
use KTXF\Module\ModuleBrowserInterface;
|
||||
use KTXF\Module\ModuleInstanceAbstract;
|
||||
use KTXF\Resource\Provider\ProviderInterface;
|
||||
use KTXM\ProviderLocalDocuments\Listeners\UserEventListener;
|
||||
use KTXM\ProviderLocalDocuments\Providers\Provider;
|
||||
|
||||
class Module extends ModuleInstanceAbstract implements ModuleBrowserInterface
|
||||
@@ -19,6 +24,7 @@ class Module extends ModuleInstanceAbstract implements ModuleBrowserInterface
|
||||
|
||||
public function __construct(
|
||||
private readonly ProviderManager $providerManager,
|
||||
private readonly EventListenerRegistrarInterface $events,
|
||||
) {}
|
||||
|
||||
public function handle(): string
|
||||
@@ -59,6 +65,10 @@ class Module extends ModuleInstanceAbstract implements ModuleBrowserInterface
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
// Register listeners
|
||||
$this->events->listen($this->handle(), UserCreatedEvent::class, UserEventListener::class, 'onUserCreated', DeliveryMode::Deferred);
|
||||
$this->events->listen($this->handle(), UserDeletingEvent::class, UserEventListener::class, 'onUserDeleting', DeliveryMode::Deferred);
|
||||
// Register providers
|
||||
$this->providerManager->register(ProviderInterface::TYPE_DOCUMENT, 'default', Provider::class);
|
||||
}
|
||||
|
||||
|
||||
@@ -335,6 +335,41 @@ class PersonalService implements ServiceBaseInterface, ServiceCollectionMutableI
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanently remove all document data owned by the initialized user.
|
||||
*/
|
||||
public function destroy(): void {
|
||||
foreach ($this->entityListBulk(null) as $entity) {
|
||||
$identifier = $entity->identifier();
|
||||
if ($identifier === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->entityDelete(new EntityIdentifier(
|
||||
$entity->provider(),
|
||||
(string) $entity->service(),
|
||||
(string) $entity->collection(),
|
||||
(string) $identifier,
|
||||
));
|
||||
}
|
||||
|
||||
foreach ($this->collectionList(null) as $collection) {
|
||||
$identifier = $collection->identifier();
|
||||
if ($identifier === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->collectionDelete(new CollectionIdentifier(
|
||||
$collection->provider(),
|
||||
(string) $collection->service(),
|
||||
(string) $identifier,
|
||||
), true);
|
||||
}
|
||||
|
||||
$this->metaStore->chronicleExpungeByUser($this->serviceTenantId, $this->serviceUserId);
|
||||
$this->blobStore->rootDestroy();
|
||||
}
|
||||
|
||||
public function collectionCopy(CollectionIdentifierInterface|null $target, CollectionIdentifierInterface $source): CollectionResource {
|
||||
$identifier = $source->collection();
|
||||
// Protect root collection
|
||||
|
||||
@@ -268,6 +268,34 @@ class BlobStore {
|
||||
return $blobDeleted && $metaDeleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanently remove the configured user storage root.
|
||||
*/
|
||||
public function rootDestroy(): void {
|
||||
if ($this->rootPath === null || !is_dir($this->rootPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$root = realpath($this->rootPath);
|
||||
if ($root === false || $root === DIRECTORY_SEPARATOR) {
|
||||
throw new RuntimeException('Refusing to destroy an invalid blob root');
|
||||
}
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($root, \FilesystemIterator::SKIP_DOTS),
|
||||
\RecursiveIteratorIterator::CHILD_FIRST,
|
||||
);
|
||||
foreach ($iterator as $entry) {
|
||||
if ($entry->isDir() && !$entry->isLink()) {
|
||||
rmdir($entry->getPathname());
|
||||
} else {
|
||||
unlink($entry->getPathname());
|
||||
}
|
||||
}
|
||||
rmdir($root);
|
||||
$this->rootPath = null;
|
||||
}
|
||||
|
||||
// ========== Blob Existence Check ==========
|
||||
|
||||
/**
|
||||
|
||||
@@ -796,4 +796,14 @@ class MetaStore {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete every chronicle entry owned by a user.
|
||||
*/
|
||||
public function chronicleExpungeByUser(string $tenantId, string $userId): void {
|
||||
$this->_store->selectCollection($this->_ChronicleTable)->deleteMany([
|
||||
'tid' => $tenantId,
|
||||
'uid' => $userId,
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user