Skip to content

Commit 05d2544

Browse files
committed
Add alternative means of changing the URL generation
1 parent 7b66ba4 commit 05d2544

File tree

3 files changed

+120
-63
lines changed

3 files changed

+120
-63
lines changed

readme.md

+22
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,28 @@ class CustomExport extends ExcelExport
411411
}
412412
```
413413

414+
## File download URL customization
415+
416+
By default, the package generates a signed URL with a default expiration time of 24 hours.
417+
The URL contains the filename including the extension. Some WAF (Web Application Firewall) solutions can block the URL due to the fact that it links to a file, which contains parameters and can cause a false positive.
418+
419+
```php
420+
// Somewhere in a ServiceProvider in the `boot()` method.
421+
use pxlrbt\FilamentExcel\FilamentExport;
422+
423+
FilamentExport::createExportUrlUsing(function ($export) {
424+
$fileInfo = pathinfo($export['filename']);
425+
$filenameWithoutExtension = $fileInfo['filename'];
426+
$extension = $fileInfo['extension'];
427+
428+
return URL::temporarySignedRoute(
429+
'your-custom-route',
430+
now()->addHours(2),
431+
['path' => $filenameWithoutExtension, 'extension' => $extension]
432+
);
433+
});
434+
```
435+
414436
## Contributing
415437

416438
If you want to contribute to this packages, you may want to test it in a real Filament project:

src/FilamentExcelServiceProvider.php

+2-63
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,8 @@
33
namespace pxlrbt\FilamentExcel;
44

55
use Filament\Facades\Filament;
6-
use Filament\Notifications\Actions\Action;
7-
use Filament\Notifications\Notification;
86
use Illuminate\Console\Scheduling\Schedule;
97
use Illuminate\Support\Facades\Event;
10-
use Illuminate\Support\Facades\Storage;
11-
use Illuminate\Support\Facades\URL;
128
use Illuminate\Support\Str;
139
use pxlrbt\FilamentExcel\Commands\PruneExportsCommand;
1410
use pxlrbt\FilamentExcel\Events\ExportFinishedEvent;
@@ -38,7 +34,7 @@ public function configurePackage(Package $package): void
3834

3935
public function bootingPackage()
4036
{
41-
Filament::serving($this->sendExportFinishedNotification(...));
37+
Filament::serving(fn () => app(FilamentExport::class)->sendNotification());
4238

4339
$this->callAfterResolving(Schedule::class, function (Schedule $schedule) {
4440
$schedule->command(PruneExportsCommand::class)->daily();
@@ -47,65 +43,13 @@ public function bootingPackage()
4743
Event::listen(ExportFinishedEvent::class, [$this, 'cacheExportFinishedNotification']);
4844
}
4945

50-
public function sendExportFinishedNotification(): void
51-
{
52-
$exports = cache()->pull($this->getNotificationCacheKey(auth()->id()));
53-
54-
if (! filled($exports)) {
55-
return;
56-
}
57-
58-
foreach ($exports as $export) {
59-
$url = URL::temporarySignedRoute(
60-
'filament-excel-download',
61-
now()->addHours(24),
62-
['path' => $export['filename']]
63-
);
64-
65-
if (! Storage::disk('filament-excel')->exists($export['filename'])) {
66-
continue;
67-
}
68-
69-
if (Filament::getCurrentPanel()->hasDatabaseNotifications()) {
70-
Notification::make(data_get($export, 'id'))
71-
->title(__('filament-excel::notifications.download_ready.title'))
72-
->body(__('filament-excel::notifications.download_ready.body'))
73-
->success()
74-
->icon('heroicon-o-arrow-down-tray')
75-
->actions([
76-
Action::make('download')
77-
->label(__('filament-excel::notifications.download_ready.download'))
78-
->url($url, shouldOpenInNewTab: true)
79-
->button()
80-
->close(),
81-
])
82-
->sendToDatabase(auth()->user());
83-
} else {
84-
Notification::make(data_get($export, 'id'))
85-
->title(__('filament-excel::notifications.download_ready.title'))
86-
->body(__('filament-excel::notifications.download_ready.body'))
87-
->success()
88-
->icon('heroicon-o-arrow-down-tray')
89-
->actions([
90-
Action::make('download')
91-
->label(__('filament-excel::notifications.download_ready.download'))
92-
->url($url, shouldOpenInNewTab: true)
93-
->button()
94-
->close(),
95-
])
96-
->persistent()
97-
->send();
98-
}
99-
}
100-
}
101-
10246
public function cacheExportFinishedNotification(ExportFinishedEvent $event): void
10347
{
10448
if ($event->userId === null) {
10549
return;
10650
}
10751

108-
$key = $this->getNotificationCacheKey($event->userId);
52+
$key = FilamentExport::getNotificationCacheKey($event->userId);
10953

11054
$exports = cache()->pull($key, []);
11155
$exports[] = [
@@ -116,9 +60,4 @@ public function cacheExportFinishedNotification(ExportFinishedEvent $event): voi
11660

11761
cache()->put($key, $exports);
11862
}
119-
120-
protected function getNotificationCacheKey($userId): string
121-
{
122-
return 'filament-excel:exports:'.$userId;
123-
}
12463
}

src/FilamentExport.php

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
namespace pxlrbt\FilamentExcel;
4+
5+
use Closure;
6+
use Filament\Facades\Filament;
7+
use Filament\Notifications\Actions\Action;
8+
use Filament\Notifications\Notification;
9+
use Illuminate\Support\Facades\Storage;
10+
use Illuminate\Support\Facades\URL;
11+
12+
class FilamentExport
13+
{
14+
public static ?Closure $createExportUrlUsing = null;
15+
16+
public static function createExportUrlUsing(Closure $closure): void
17+
{
18+
static::$createExportUrlUsing = $closure;
19+
}
20+
21+
protected function sendDatabaseNotification(array $export, string $url): void
22+
{
23+
Notification::make(data_get($export, 'id'))
24+
->title(__('filament-excel::notifications.download_ready.title'))
25+
->body(__('filament-excel::notifications.download_ready.body'))
26+
->success()
27+
->icon('heroicon-o-arrow-down-tray')
28+
->actions([
29+
Action::make('download')
30+
->label(__('filament-excel::notifications.download_ready.download'))
31+
->url($url, shouldOpenInNewTab: true)
32+
->button()
33+
->close(),
34+
])
35+
->sendToDatabase(auth()->user());
36+
}
37+
38+
protected function sendPersistentNotification(array $export, string $url): void
39+
{
40+
Notification::make(data_get($export, 'id'))
41+
->title(__('filament-excel::notifications.download_ready.title'))
42+
->body(__('filament-excel::notifications.download_ready.body'))
43+
->success()
44+
->icon('heroicon-o-arrow-down-tray')
45+
->actions([
46+
Action::make('download')
47+
->label(__('filament-excel::notifications.download_ready.download'))
48+
->url($url, shouldOpenInNewTab: true)
49+
->button()
50+
->close(),
51+
])
52+
->persistent()
53+
->send();
54+
}
55+
56+
public function sendNotification(): void
57+
{
58+
$exports = cache()->pull(static::getNotificationCacheKey(auth()->id()));
59+
60+
if (! filled($exports)) {
61+
return;
62+
}
63+
64+
foreach ($exports as $export) {
65+
$url = $this->createUrl($export);
66+
67+
if (! Storage::disk('filament-excel')->exists($export['filename'])) {
68+
continue;
69+
}
70+
71+
if (Filament::getCurrentPanel()->hasDatabaseNotifications()) {
72+
$this->sendDatabaseNotification($export, $url);
73+
} else {
74+
$this->sendPersistentNotification($export, $url);
75+
}
76+
}
77+
}
78+
79+
public static function getNotificationCacheKey($userId): string
80+
{
81+
return 'filament-excel:exports:'.$userId;
82+
}
83+
84+
protected function createUrl(array $export): string
85+
{
86+
if (is_null(static::$createExportUrlUsing)) {
87+
return URL::temporarySignedRoute(
88+
'filament-excel-download',
89+
now()->addHours(24),
90+
['path' => $export['filename']]
91+
);
92+
}
93+
94+
return call_user_func(static::$createExportUrlUsing, $export);
95+
}
96+
}

0 commit comments

Comments
 (0)