Skip to content

Commit 662ce79

Browse files
authored
Merge pull request #19 from alkrauss48/issue-18
Extract Thumbnail Generation to Job
2 parents 6c6c9f4 + 9542e3a commit 662ce79

File tree

6 files changed

+149
-62
lines changed

6 files changed

+149
-62
lines changed

README.md

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Simple Slides
22

3-
[Simple Slides](https://simpleslides.dev) is a response and text-first
3+
[Simple Slides](https://simpleslides.dev) is a responsive and text-first
44
presentation tool that keeps your audience engaged, and is built with:
55

66
* Laravel
@@ -33,23 +33,43 @@ alias.
3333

3434
## To Run
3535
```sh
36-
# In one terminal:
36+
# In one terminal, to run the app:
3737
sail up
3838

39-
# Then, in another
39+
# Then, in another to run the migrations and seeders (this command will end)
40+
sail artisan migrate:fresh --seed
41+
42+
# Then, build, watch, and hot reload for front-end changes
4043
sail npm run dev
4144

4245
```
4346

47+
To log in, use any of the following credentials (found in
48+
database/Seeders/DatabaseSeeder.php):
49+
50+
- Email: `[email protected]` for an admin user, or `[email protected]` for a
51+
non-admin user.
52+
- Password: Both accounts use `password`.
53+
4454
## Autoformatting
45-
Via [Laravel pint](https://laravel.com/docs/10.x/pint)
55+
Via [Laravel pint](https://laravel.com/docs/10.x/pint), which is a
56+
code-formatter following Laravel's best practices. **Note:** This is not a
57+
linter.
4658
```
4759
# Laravel
4860
4961
sail pint
5062
```
5163

5264
## Linting
65+
Linting on the back-end (e.g. Laravel) is done via
66+
[larastan](https://github.com/larastan/larastan), which is a
67+
[PHPStan](https://phpstan.org/) wrapper for Laravel.
68+
69+
Linting on the front-end (e.g. Vue w/ Typescript) is done with `vue-tsc`, which
70+
is a first-party wrapper for Vue around `tsc`. See more here:
71+
https://vuejs.org/guide/typescript/overview
72+
5373
```
5474
# Back-end (Laravel)
5575
sail bin phpstan analyse
@@ -59,6 +79,16 @@ sail npx vue-tsc
5979
```
6080

6181
## Running the Tests
82+
Tests on the back-end (e.g. Laravel) are written using
83+
[Pest](https://pestphp.com/), and are a
84+
mostly integration and end-to-end tests, with some unit tests sprinkled in.
85+
Currently there are no browser tests.
86+
87+
Tests on the front-end (e.g. Vue w/ Typescript) are written using
88+
[vitest](https://vitest.dev/), along with some other test utilities like [Vue
89+
Test Utils](https://test-utils.vuejs.org/) and [Mock Service
90+
Worker](https://mswjs.io/).
91+
6292
```sh
6393
# Back-end (Laravel)
6494
sail artisan test
@@ -69,12 +99,11 @@ sail npx vitest
6999

70100
## To Generate Thumbnails for Presentations
71101
This uses puppeteer and Browsershot, which requires some extra config on top of
72-
Laravel Sail. To configure this, you need to attach to the container and run the
73-
`./docker/sail-extra.sh` command:
102+
Laravel Sail. To configure this, you need to run the following commands:
74103

75104
```
76-
docker compose exec laravel.test sh
77-
> ./docker/sail-extra.sh
105+
sail root-shell ./docker/sail-extra.sh
106+
sail npx puppeteer browsers install chrome
78107
```
79108

80109
## Recommended IDE Setup

app/Filament/Resources/PresentationResource/Pages/EditPresentation.php

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
namespace App\Filament\Resources\PresentationResource\Pages;
44

55
use App\Filament\Resources\PresentationResource;
6+
use App\Jobs\GenerateThumbnail;
67
use App\Models\Presentation;
78
use Filament\Actions;
89
use Filament\Notifications\Notification;
910
use Filament\Resources\Pages\EditRecord;
1011
use Illuminate\Support\HtmlString;
11-
use Spatie\Browsershot\Browsershot;
1212
use Webbingbrasil\FilamentCopyActions\Pages\Actions\CopyAction;
1313

1414
class EditPresentation extends EditRecord
@@ -55,30 +55,18 @@ protected function getHeaderActions(): array
5555
return;
5656
}
5757

58-
$tempPath = storage_path("temp/{$record->slug}-{$record->user->username}.jpg");
58+
// Note: If in the future we implement a websocket server,
59+
// then we can implement an initial notification like this.
60+
//
61+
// Notification::make()
62+
// ->title('Hang tight for just a sec, your thumbnail is being generated.')
63+
// ->info()
64+
// ->send();
5965

60-
Browsershot::url(route('presentations.show', [
61-
'user' => $record->user->username,
62-
'slug' => $record->slug,
63-
]))
64-
->setChromePath('/usr/bin/chromium-browser')
65-
->waitUntilNetworkIdle()
66-
->windowSize(1200, 630)
67-
->setOption('args', ['--disable-web-security'])
68-
->setOption('addStyleTag', json_encode([
69-
'content' => '.slide-view { height: 100vh !important; } '
70-
.'.browsershot-hide { display: none !important; }',
71-
]))->noSandbox()
72-
->setScreenshotType('jpeg', 90)
73-
->save($tempPath);
74-
75-
$record->clearMediaCollection('thumbnail');
76-
$record->addMedia($tempPath)->toMediaCollection('thumbnail');
77-
78-
Notification::make()
79-
->title('Thumbnail successfully generated. Refresh your page to view the new thumbnail.')
80-
->success()
81-
->send();
66+
GenerateThumbnail::dispatch(
67+
presentation: $record,
68+
user: auth()->user(),
69+
);
8270
}),
8371
Actions\Action::make('save')
8472
->label('Save changes')

app/Jobs/GenerateThumbnail.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace App\Jobs;
4+
5+
use App\Models\Presentation;
6+
use App\Models\User;
7+
use Filament\Notifications\Notification;
8+
use Illuminate\Bus\Queueable;
9+
use Illuminate\Contracts\Queue\ShouldQueue;
10+
use Illuminate\Foundation\Bus\Dispatchable;
11+
use Illuminate\Queue\InteractsWithQueue;
12+
use Illuminate\Queue\SerializesModels;
13+
use Illuminate\Support\Facades\App;
14+
use Spatie\Browsershot\Browsershot;
15+
16+
class GenerateThumbnail implements ShouldQueue
17+
{
18+
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
19+
20+
/**
21+
* Create a new job instance.
22+
*/
23+
public function __construct(
24+
public Presentation $presentation,
25+
public User $user,
26+
) {
27+
}
28+
29+
/**
30+
* Execute the job.
31+
*/
32+
public function handle(): void
33+
{
34+
$tempPath = storage_path("temp/{$this->presentation->slug}-{$this->presentation->user->username}.jpg");
35+
36+
$browsershot = Browsershot::url(route('presentations.show', [
37+
'user' => $this->presentation->user->username,
38+
'slug' => $this->presentation->slug,
39+
]))
40+
->waitUntilNetworkIdle()
41+
->windowSize(1200, 630)
42+
->newHeadless()
43+
->setOption('args', ['--disable-web-security'])
44+
->setScreenshotType('jpeg', 90)
45+
->noSandbox()
46+
->setOption('addStyleTag', json_encode([
47+
'content' => '.slide-view { height: 100vh !important; } '
48+
.'.browsershot-hide { display: none !important; }',
49+
]));
50+
51+
if (! App::environment('local')) {
52+
$browsershot->setChromePath('/usr/bin/chromium-browser');
53+
}
54+
55+
$browsershot->save($tempPath);
56+
57+
$this->presentation->clearMediaCollection('thumbnail');
58+
$this->presentation->addMedia($tempPath)->toMediaCollection('thumbnail');
59+
60+
Notification::make()
61+
->title('Thumbnail successfully generated. Refresh your page to view the new thumbnail.')
62+
->broadcast($this->user)
63+
->success()
64+
->send();
65+
}
66+
}

docker/sail-extra.sh

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
#!/bin/bash
22

33
apt-get update
4-
npm install --global --unsafe-perm puppeteer@^17
54
apt-get install -y gconf-service libasound2 libappindicator3-1 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget libgbm-dev libatk-bridge2.0-
6-
chmod -R o+rx /usr/lib/node_modules/puppeteer/.local-chromium
7-
85
apt-get install -y ca-certificates fonts-liberation libappindicator3-1 libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils

docker/sail-prod/Dockerfile

Lines changed: 0 additions & 27 deletions
This file was deleted.

tests/Filament/PresentationResourceTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
use App\Filament\Resources\PresentationResource\Pages\CreatePresentation as CreateResource;
66
use App\Filament\Resources\PresentationResource\Pages\EditPresentation as EditResource;
77
use App\Filament\Resources\PresentationResource\Pages\ListPresentations as ListResource;
8+
use App\Jobs\GenerateThumbnail;
89
use App\Models\Presentation as Model;
910
// End
1011
use App\Models\User;
1112
use Illuminate\Http\UploadedFile;
13+
use Illuminate\Support\Facades\Queue;
1214

1315
use function Pest\Livewire\livewire;
1416

@@ -393,4 +395,36 @@
393395
expect($record->refresh())
394396
->deleted_at->toBe(null);
395397
});
398+
399+
it('can dispatch a thumbnail generation job', function () {
400+
Queue::fake();
401+
402+
$record = Model::factory()->create([
403+
'user_id' => $this->nonAdmin->id,
404+
'is_published' => true,
405+
]);
406+
407+
livewire(EditResource::class, [
408+
'record' => $record->getRouteKey(),
409+
])
410+
->callAction('Generate Thumbnail');
411+
412+
Queue::assertPushed(GenerateThumbnail::class);
413+
});
414+
415+
it('will not dispatch a thumbnail generation job for unpublished presentation', function () {
416+
Queue::fake();
417+
418+
$record = Model::factory()->create([
419+
'user_id' => $this->nonAdmin->id,
420+
'is_published' => false,
421+
]);
422+
423+
livewire(EditResource::class, [
424+
'record' => $record->getRouteKey(),
425+
])
426+
->callAction('Generate Thumbnail');
427+
428+
Queue::assertNotPushed(GenerateThumbnail::class);
429+
});
396430
});

0 commit comments

Comments
 (0)