Skip to content

Commit

Permalink
Merge pull request #19 from alkrauss48/issue-18
Browse files Browse the repository at this point in the history
Extract Thumbnail Generation to Job
  • Loading branch information
alkrauss48 authored Apr 8, 2024
2 parents 6c6c9f4 + 9542e3a commit 662ce79
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 62 deletions.
45 changes: 37 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Simple Slides

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

* Laravel
Expand Down Expand Up @@ -33,23 +33,43 @@ alias.

## To Run
```sh
# In one terminal:
# In one terminal, to run the app:
sail up

# Then, in another
# Then, in another to run the migrations and seeders (this command will end)
sail artisan migrate:fresh --seed

# Then, build, watch, and hot reload for front-end changes
sail npm run dev

```

To log in, use any of the following credentials (found in
database/Seeders/DatabaseSeeder.php):

- Email: `[email protected]` for an admin user, or `[email protected]` for a
non-admin user.
- Password: Both accounts use `password`.

## Autoformatting
Via [Laravel pint](https://laravel.com/docs/10.x/pint)
Via [Laravel pint](https://laravel.com/docs/10.x/pint), which is a
code-formatter following Laravel's best practices. **Note:** This is not a
linter.
```
# Laravel
sail pint
```

## Linting
Linting on the back-end (e.g. Laravel) is done via
[larastan](https://github.com/larastan/larastan), which is a
[PHPStan](https://phpstan.org/) wrapper for Laravel.

Linting on the front-end (e.g. Vue w/ Typescript) is done with `vue-tsc`, which
is a first-party wrapper for Vue around `tsc`. See more here:
https://vuejs.org/guide/typescript/overview

```
# Back-end (Laravel)
sail bin phpstan analyse
Expand All @@ -59,6 +79,16 @@ sail npx vue-tsc
```

## Running the Tests
Tests on the back-end (e.g. Laravel) are written using
[Pest](https://pestphp.com/), and are a
mostly integration and end-to-end tests, with some unit tests sprinkled in.
Currently there are no browser tests.

Tests on the front-end (e.g. Vue w/ Typescript) are written using
[vitest](https://vitest.dev/), along with some other test utilities like [Vue
Test Utils](https://test-utils.vuejs.org/) and [Mock Service
Worker](https://mswjs.io/).

```sh
# Back-end (Laravel)
sail artisan test
Expand All @@ -69,12 +99,11 @@ sail npx vitest

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

```
docker compose exec laravel.test sh
> ./docker/sail-extra.sh
sail root-shell ./docker/sail-extra.sh
sail npx puppeteer browsers install chrome
```

## Recommended IDE Setup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
namespace App\Filament\Resources\PresentationResource\Pages;

use App\Filament\Resources\PresentationResource;
use App\Jobs\GenerateThumbnail;
use App\Models\Presentation;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord;
use Illuminate\Support\HtmlString;
use Spatie\Browsershot\Browsershot;
use Webbingbrasil\FilamentCopyActions\Pages\Actions\CopyAction;

class EditPresentation extends EditRecord
Expand Down Expand Up @@ -55,30 +55,18 @@ protected function getHeaderActions(): array
return;
}

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

Browsershot::url(route('presentations.show', [
'user' => $record->user->username,
'slug' => $record->slug,
]))
->setChromePath('/usr/bin/chromium-browser')
->waitUntilNetworkIdle()
->windowSize(1200, 630)
->setOption('args', ['--disable-web-security'])
->setOption('addStyleTag', json_encode([
'content' => '.slide-view { height: 100vh !important; } '
.'.browsershot-hide { display: none !important; }',
]))->noSandbox()
->setScreenshotType('jpeg', 90)
->save($tempPath);

$record->clearMediaCollection('thumbnail');
$record->addMedia($tempPath)->toMediaCollection('thumbnail');

Notification::make()
->title('Thumbnail successfully generated. Refresh your page to view the new thumbnail.')
->success()
->send();
GenerateThumbnail::dispatch(
presentation: $record,
user: auth()->user(),
);
}),
Actions\Action::make('save')
->label('Save changes')
Expand Down
66 changes: 66 additions & 0 deletions app/Jobs/GenerateThumbnail.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace App\Jobs;

use App\Models\Presentation;
use App\Models\User;
use Filament\Notifications\Notification;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\App;
use Spatie\Browsershot\Browsershot;

class GenerateThumbnail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

/**
* Create a new job instance.
*/
public function __construct(
public Presentation $presentation,
public User $user,
) {
}

/**
* Execute the job.
*/
public function handle(): void
{
$tempPath = storage_path("temp/{$this->presentation->slug}-{$this->presentation->user->username}.jpg");

$browsershot = Browsershot::url(route('presentations.show', [
'user' => $this->presentation->user->username,
'slug' => $this->presentation->slug,
]))
->waitUntilNetworkIdle()
->windowSize(1200, 630)
->newHeadless()
->setOption('args', ['--disable-web-security'])
->setScreenshotType('jpeg', 90)
->noSandbox()
->setOption('addStyleTag', json_encode([
'content' => '.slide-view { height: 100vh !important; } '
.'.browsershot-hide { display: none !important; }',
]));

if (! App::environment('local')) {
$browsershot->setChromePath('/usr/bin/chromium-browser');
}

$browsershot->save($tempPath);

$this->presentation->clearMediaCollection('thumbnail');
$this->presentation->addMedia($tempPath)->toMediaCollection('thumbnail');

Notification::make()
->title('Thumbnail successfully generated. Refresh your page to view the new thumbnail.')
->broadcast($this->user)
->success()
->send();
}
}
3 changes: 0 additions & 3 deletions docker/sail-extra.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
#!/bin/bash

apt-get update
npm install --global --unsafe-perm puppeteer@^17
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-
chmod -R o+rx /usr/lib/node_modules/puppeteer/.local-chromium

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
27 changes: 0 additions & 27 deletions docker/sail-prod/Dockerfile

This file was deleted.

34 changes: 34 additions & 0 deletions tests/Filament/PresentationResourceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
use App\Filament\Resources\PresentationResource\Pages\CreatePresentation as CreateResource;
use App\Filament\Resources\PresentationResource\Pages\EditPresentation as EditResource;
use App\Filament\Resources\PresentationResource\Pages\ListPresentations as ListResource;
use App\Jobs\GenerateThumbnail;
use App\Models\Presentation as Model;
// End
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Queue;

use function Pest\Livewire\livewire;

Expand Down Expand Up @@ -393,4 +395,36 @@
expect($record->refresh())
->deleted_at->toBe(null);
});

it('can dispatch a thumbnail generation job', function () {
Queue::fake();

$record = Model::factory()->create([
'user_id' => $this->nonAdmin->id,
'is_published' => true,
]);

livewire(EditResource::class, [
'record' => $record->getRouteKey(),
])
->callAction('Generate Thumbnail');

Queue::assertPushed(GenerateThumbnail::class);
});

it('will not dispatch a thumbnail generation job for unpublished presentation', function () {
Queue::fake();

$record = Model::factory()->create([
'user_id' => $this->nonAdmin->id,
'is_published' => false,
]);

livewire(EditResource::class, [
'record' => $record->getRouteKey(),
])
->callAction('Generate Thumbnail');

Queue::assertNotPushed(GenerateThumbnail::class);
});
});

0 comments on commit 662ce79

Please sign in to comment.