Files
fotospiel-app/app/Services/Compliance/AccountAnonymizer.php

152 lines
4.7 KiB
PHP

<?php
namespace App\Services\Compliance;
use App\Models\CheckoutSession;
use App\Models\Event;
use App\Models\EventJoinToken;
use App\Models\EventMediaAsset;
use App\Models\EventMember;
use App\Models\PackagePurchase;
use App\Models\Photo;
use App\Models\Tenant;
use App\Models\TenantPackage;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class AccountAnonymizer
{
public function anonymize(User $user): void
{
DB::transaction(function () use ($user) {
$tenant = $user->tenant;
if ($tenant) {
$this->purgeTenantMedia($tenant);
$this->scrubTenantData($tenant);
}
$this->scrubUser($user);
});
}
public function anonymizeTenantOnly(Tenant $tenant): void
{
DB::transaction(function () use ($tenant) {
$this->purgeTenantMedia($tenant);
$this->scrubTenantData($tenant);
});
}
protected function purgeTenantMedia(Tenant $tenant): void
{
EventMediaAsset::query()
->whereHas('event', fn ($query) => $query->where('tenant_id', $tenant->id))
->chunkById(100, function ($assets) {
foreach ($assets as $asset) {
if ($asset->disk && $asset->path) {
Storage::disk($asset->disk)->delete($asset->path);
}
$asset->delete();
}
});
Photo::query()
->where(function ($query) use ($tenant) {
$query->where('tenant_id', $tenant->id)
->orWhereHas('event', fn ($inner) => $inner->where('tenant_id', $tenant->id));
})
->chunkById(200, function ($photos) {
foreach ($photos as $photo) {
$photo->delete();
}
});
}
protected function scrubTenantData(Tenant $tenant): void
{
$eventIds = Event::query()
->where('tenant_id', $tenant->id)
->pluck('id');
EventJoinToken::query()->whereIn('event_id', $eventIds)->delete();
EventMember::query()->where('tenant_id', $tenant->id)->delete();
Event::query()
->whereIn('id', $eventIds)
->chunkById(100, function ($events) {
foreach ($events as $event) {
$event->forceFill([
'name' => ['de' => 'Anonymisiertes Event', 'en' => 'Anonymized Event'],
'description' => null,
'location' => null,
'slug' => 'anonymized-event-'.$event->id,
'status' => 'archived',
'photobooth_enabled' => false,
'photobooth_path' => null,
])->save();
}
});
PackagePurchase::query()
->where('tenant_id', $tenant->id)
->update([
'ip_address' => null,
'user_agent' => null,
]);
CheckoutSession::query()
->where('tenant_id', $tenant->id)
->update([
'tenant_id' => null,
'user_id' => null,
'provider_metadata' => [],
]);
TenantPackage::query()
->where('tenant_id', $tenant->id)
->update(['active' => false]);
$tenant->forceFill([
'name' => 'Anonymisierter Tenant #'.$tenant->id,
'slug' => 'anonymized-tenant-'.$tenant->id,
'contact_name' => null,
'contact_email' => null,
'contact_phone' => null,
'email' => null,
'domain' => null,
'custom_domain' => null,
'user_id' => null,
'anonymized_at' => now(),
'pending_deletion_at' => null,
'deletion_warning_sent_at' => null,
'subscription_status' => 'deleted',
'is_active' => 0,
'is_suspended' => 1,
])->save();
}
protected function scrubUser(User $user): void
{
$placeholderEmail = sprintf('deleted+%s@fotospiel.app', $user->id);
$user->forceFill([
'name' => 'Anonymisierter Benutzer',
'email' => $placeholderEmail,
'username' => null,
'first_name' => null,
'last_name' => null,
'address' => null,
'phone' => null,
'password' => Str::random(40),
'remember_token' => null,
'pending_purchase' => false,
'email_verified_at' => null,
'role' => 'user',
])->save();
}
}