Feature: Data Access and Data Export Admin Service

This commit introduces the data retention and data export Admin Services, accessed by the Boboko admin UI
This commit is contained in:
2026-08-25 09:33:03 +03:00
parent 59303cf25f
commit e7784364fd
13 changed files with 800 additions and 0 deletions
+56
View File
@@ -5,17 +5,28 @@ namespace Modules\Core;
use Filament\Contracts\Plugin;
use Filament\Panel;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Support\Facades\Mail;
use Lunar\Admin\Filament\Resources\CustomerResource;
use Lunar\Admin\Filament\Resources\CustomerResource\Pages\EditCustomer;
use Lunar\Admin\Filament\Resources\CustomerResource\Pages\ViewCustomer;
use Lunar\Admin\Filament\Resources\ProductResource;
use Lunar\Admin\Filament\Resources\StaffResource;
use Lunar\Admin\Models\Staff as LunarStaff;
use Lunar\Admin\Support\Facades\LunarPanel;
use Lunar\Models\Customer;
use Lunar\Models\Product;
use Lunar\Shipping\ShippingPlugin;
use Modules\Core\Auth\Extensions\StaffResourceExtension;
use Modules\Core\Auth\Filament\Pages\Login;
use Modules\Core\Auth\Mail\InviteMail;
use Modules\Core\Localization\Filament\Resources\LanguageLineResource;
use Modules\Core\Privacy\Filament\Extensions\CustomerErasureActionsExtension;
use Modules\Core\Privacy\Filament\Extensions\CustomerErasureRelationsExtension;
use Modules\Core\Privacy\Filament\Resources\DataErasureRequestResource;
use Modules\Core\Privacy\Filament\Resources\DataExportRequestResource;
use Modules\Core\Privacy\Models\DataErasureRequest;
use Modules\Core\Privacy\Models\DataExportRequest;
use Modules\Core\Review\Extensions\ProductResourceExtension;
use Modules\Core\Review\Models\ProductReview;
@@ -35,12 +46,29 @@ class CorePlugin implements Plugin
->login(Login::class)
->resources([
LanguageLineResource::class,
DataErasureRequestResource::class,
DataExportRequestResource::class,
])
->plugin(ShippingPlugin::make());
LunarPanel::extensions([
StaffResource::class => StaffResourceExtension::class,
ProductResource::class => ProductResourceExtension::class,
// headerActions() is resolved per PAGE class, not per resource class —
// unlike extendForm()/extendTable(), which really are resource-keyed
// (called statically from the Resource class itself). Registering this
// under CustomerResource::class would silently never fire; it has to be
// keyed by each concrete page it should appear on. Layered with
// whatever extension the consuming app registers for the same page —
// LunarPanel::extensions() merges per key, and this one only touches
// headerActions(), so it never conflicts with an app's own extension
// (see docs/modules.md "Layering Module and App Configuration").
EditCustomer::class => CustomerErasureActionsExtension::class,
ViewCustomer::class => CustomerErasureActionsExtension::class,
// getRelations(), unlike headerActions(), genuinely is resolved
// statically from the Resource class itself — CustomerResource::class
// is the correct key here.
CustomerResource::class => CustomerErasureRelationsExtension::class,
]);
Product::macro('reviews', function (): HasMany {
@@ -48,6 +76,34 @@ class CorePlugin implements Plugin
return $this->hasMany(ProductReview::class);
});
// Customer::erasureRequests()/exportRequests() and the User-model
// equivalents below let a relation manager scope
// DataErasureRequest/DataExportRequest to one specific subject — both
// tables use a plain subject_type/subject_id pair rather than Laravel's
// usual morphs() convention, since one column pair identifies either a
// Customer or a User (see docs/privacy.md "User-scope vs Customer-scope"),
// so this is a MorphMany built by hand rather than a bare Eloquent
// convention lookup.
Customer::macro('erasureRequests', function (): MorphMany {
/** @var Customer $this */
return $this->morphMany(DataErasureRequest::class, 'subject', 'subject_type', 'subject_id');
});
Customer::macro('exportRequests', function (): MorphMany {
/** @var Customer $this */
return $this->morphMany(DataExportRequest::class, 'subject', 'subject_type', 'subject_id');
});
$userModel = config('auth.providers.users.model');
$userModel::macro('erasureRequests', function (): MorphMany {
return $this->morphMany(DataErasureRequest::class, 'subject', 'subject_type', 'subject_id');
});
$userModel::macro('exportRequests', function (): MorphMany {
return $this->morphMany(DataExportRequest::class, 'subject', 'subject_type', 'subject_id');
});
LunarStaff::addActivitylogExcept([
'otp_code',
'otp_expires_at',