im profil kann ein nutzer nun seine daten exportieren. man kann seinen account löschen. nach 2 jahren werden inaktive accounts gelöscht, 1 monat vorher wird eine email geschickt. Hilfetexte und Legal Pages in der Guest PWA korrigiert und vom layout her optimiert (dark mode).
This commit is contained in:
151
app/Services/Compliance/AccountAnonymizer.php
Normal file
151
app/Services/Compliance/AccountAnonymizer.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?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();
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use League\CommonMark\Environment\Environment;
|
||||
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
|
||||
use League\CommonMark\Extension\Table\TableExtension;
|
||||
use League\CommonMark\MarkdownConverter;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
@@ -22,6 +23,7 @@ class HelpSyncService
|
||||
{
|
||||
$environment = new Environment;
|
||||
$environment->addExtension(new CommonMarkCoreExtension);
|
||||
$environment->addExtension(new TableExtension);
|
||||
$this->converter = new MarkdownConverter($environment);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user