Skip to content

Commit

Permalink
Merge pull request #2197 from Wotuu/development
Browse files Browse the repository at this point in the history
Release v7.10 - Thumbnail generation now supports setting the viewport
  • Loading branch information
Wotuu authored Feb 7, 2024
2 parents 9015f0e + 742a077 commit 54a2025
Show file tree
Hide file tree
Showing 36 changed files with 667 additions and 309 deletions.
47 changes: 35 additions & 12 deletions app/Exceptions/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Teapot\StatusCode;
use Throwable;

class Handler extends ExceptionHandler
Expand All @@ -34,45 +35,67 @@ class Handler extends ExceptionHandler
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param Throwable $exception
* @param Throwable $e
* @return void
* @throws Throwable
*/
public function report(Throwable $exception)
public function report(Throwable $e)
{
parent::report($exception);
parent::report($e);
}

/**
* Render an exception into an HTTP response.
*
* @param Request $request
* @param Throwable $exception
* @param Throwable $e
* @return mixed
* @throws Throwable
*/
public function render($request, Throwable $exception)
public function render($request, Throwable $e)
{
if ($exception instanceof ModelNotFoundException && $request->wantsJson()) {
return response()->json(['message' => sprintf('%s not found for %s', implode($exception->getIds()), $exception->getModel())], 404);
if ($request->isJson() || $this->isApiRequest($request)) {
if ($e instanceof ModelNotFoundException) {
return response()->json([
'message' => __('exceptions.handler.api_model_not_found', [
'ids' => implode(', ', $e->getIds()),
'model' => $e->getModel(),
]),
], StatusCode::NOT_FOUND);
} else if ($e instanceof NotFoundHttpException) {
return response()->json(['message' => __('exceptions.handler.api_route_not_found')], StatusCode::NOT_FOUND);
} else if (!config('app.debug')) {
return response()->json(['message' => __('exceptions.handler.internal_server_error')], StatusCode::INTERNAL_SERVER_ERROR);
}
}

return parent::render($request, $exception);
return parent::render($request, $e);
}



/**
* Convert an authentication exception into an unauthenticated response.
*
* @param Request $request
* @param Request $request
* @param AuthenticationException $exception
* @return mixed
*/
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
if ($request->isJson() || $this->isApiRequest($request)) {
return response()->json(['error' => __('exceptions.handler.unauthenticated')], StatusCode::UNAUTHORIZED);
}

return redirect()->guest('login');
}

/**
* @param Request $request
* @return bool
*/
private function isApiRequest(Request $request): bool
{
return strpos($request->decodedPath(), 'api/') === 0;
}
}
13 changes: 7 additions & 6 deletions app/Http/Controllers/Ajax/AjaxBrushlineController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use App\Events\Model\ModelDeletedEvent;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Traits\SavesPolylines;
use App\Http\Controllers\Traits\ValidatesFloorId;
use App\Http\Requests\Brushline\APIBrushlineFormRequest;
use App\Http\Requests\Brushline\APIBrushlineUpdateFormRequest;
use App\Models\Brushline;
Expand All @@ -25,6 +26,7 @@
class AjaxBrushlineController extends Controller
{
use SavesPolylines;
use ValidatesFloorId;

/**
* @param APIBrushlineFormRequest $request
Expand All @@ -48,12 +50,11 @@ function store(

$validated = $request->validated();

if (Floor::findOrFail($validated['floor_id'])->dungeon_id !== $dungeonRoute->dungeon_id) {
return response(__('controller.brushline.error.floor_not_found_in_dungeon'), 422);
$result = $this->validateFloorId($validated['floor_id'], $dungeonRoute->dungeon_id);
if ($result !== null) {
return $result;
}

$result = null;

DB::transaction(function () use ($coordinatesService, $brushline, $dungeonRoute, $validated, &$result) {
if ($brushline === null) {
$brushline = Brushline::create([
Expand Down Expand Up @@ -99,7 +100,7 @@ function store(
// Touch the route so that the thumbnail gets updated
$dungeonRoute->touch();
} else {
throw new \Exception(__('controller.generic.error.unable_to_save'));
throw new \Exception(__('controller.brushline.error.unable_to_save_brushline'));
}

$result = $brushline;
Expand Down Expand Up @@ -136,7 +137,7 @@ function delete(Request $request, DungeonRoute $dungeonRoute, Brushline $brushli

$result = response()->noContent();
} else {
$result = response(__('controller.generic.error.unable_to_save'), Http::INTERNAL_SERVER_ERROR);
$result = response(__('controller.brushline.error.unable_to_delete_brushline'), Http::INTERNAL_SERVER_ERROR);
}
} catch (Exception $ex) {
$result = response(__('controller.generic.error.not_found'), Http::NOT_FOUND);
Expand Down
111 changes: 61 additions & 50 deletions app/Http/Controllers/Ajax/AjaxPathController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
use App\Events\Model\ModelDeletedEvent;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Traits\SavesPolylines;
use App\Http\Controllers\Traits\ValidatesFloorId;
use App\Http\Requests\Path\APIPathFormRequest;
use App\Models\Brushline;
use App\Models\DungeonRoute\DungeonRoute;
use App\Models\Path;
use App\Models\Polyline;
Expand All @@ -16,19 +18,21 @@
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Mockery\Exception;
use Teapot\StatusCode\Http;

class AjaxPathController extends Controller
{
use SavesPolylines;
use ValidatesFloorId;

/**
* @param APIPathFormRequest $request
* @param CoordinatesServiceInterface $coordinatesService
* @param DungeonRoute $dungeonRoute
* @param Path|null $path
* @return Path
* @return Brushline|Response
* @throws AuthorizationException
*/
function store(
Expand All @@ -44,60 +48,67 @@ function store(

$validated = $request->validated();

if ($path === null) {
$path = Path::create([
'dungeon_route_id' => $dungeonRoute->id,
'floor_id' => $validated['floor_id'],
'polyline_id' => -1,
]);
$success = $path instanceof Path;
} else {
$success = $path->update([
'dungeon_route_id' => $dungeonRoute->id,
'floor_id' => $validated['floor_id'],
]);
$result = $this->validateFloorId($validated['floor_id'], $dungeonRoute->dungeon_id);
if ($result !== null) {
return $result;
}

try {
if ($success) {
// Create a new polyline and save it
$changedFloor = null;
$polyline = $this->savePolyline(
$coordinatesService,
$dungeonRoute->mappingVersion,
Polyline::findOrNew($path->polyline_id),
$path,
$validated['polyline'],
$changedFloor
);

// Couple the path to the polyline
$path->update([
'polyline_id' => $polyline->id,
'floor_id' => optional($changedFloor)->id ?? $path->floor_id,
DB::transaction(function () use ($coordinatesService, $path, $dungeonRoute, $validated, &$result) {
if ($path === null) {
$path = Path::create([
'dungeon_route_id' => $dungeonRoute->id,
'floor_id' => $validated['floor_id'],
'polyline_id' => -1,
]);
$success = $path instanceof Path;
} else {
$success = $path->update([
'dungeon_route_id' => $dungeonRoute->id,
'floor_id' => $validated['floor_id'],
]);
}

// Load the polyline so it can be echoed back to the user
$path->load(['polyline']);

// Set or unset the linked awakened obelisks now that we have an ID
$path->setLinkedAwakenedObeliskByMapIconId($validated['linked_awakened_obelisk_id']);

// Something's updated; broadcast it
if (Auth::check()) {
broadcast(new ModelChangedEvent($dungeonRoute, Auth::user(), $path));
try {
if ($success) {
// Create a new polyline and save it
$changedFloor = null;
$polyline = $this->savePolyline(
$coordinatesService,
$dungeonRoute->mappingVersion,
Polyline::findOrNew($path->polyline_id),
$path,
$validated['polyline'],
$changedFloor
);

// Couple the path to the polyline
$path->update([
'polyline_id' => $polyline->id,
'floor_id' => optional($changedFloor)->id ?? $path->floor_id,
]);

// Load the polyline so it can be echoed back to the user
$path->load(['polyline']);

// Set or unset the linked awakened obelisks now that we have an ID
$path->setLinkedAwakenedObeliskByMapIconId($validated['linked_awakened_obelisk_id'] ?? null);

// Something's updated; broadcast it
if (Auth::check()) {
broadcast(new ModelChangedEvent($dungeonRoute, Auth::user(), $path));
}

// Touch the route so that the thumbnail gets updated
$dungeonRoute->touch();
} else {
throw new \Exception(__('controller.path.error.unable_to_save_path'));
}

// Touch the route so that the thumbnail gets updated
$dungeonRoute->touch();
} else {
throw new \Exception('Unable to save path!');
$result = $path;
} catch (Exception $ex) {
$result = response(__('controller.generic.error.not_found'), Http::NOT_FOUND);
}

$result = $path;
} catch (Exception $ex) {
$result = response('Not found', Http::NOT_FOUND);
}
});

return $result;
}
Expand Down Expand Up @@ -127,10 +138,10 @@ function delete(Request $request, DungeonRoute $dungeonRoute, Path $path)

$result = response()->noContent();
} else {
$result = response('Unable to delete Path', Http::INTERNAL_SERVER_ERROR);
$result = response(__('controller.path.error.unable_to_delete_path'), Http::INTERNAL_SERVER_ERROR);
}
} catch (\Exception $ex) {
$result = response('Not found', Http::NOT_FOUND);
$result = response(__('controller.generic.error.not_found'), Http::NOT_FOUND);
}

return $result;
Expand Down
6 changes: 4 additions & 2 deletions app/Http/Controllers/Api/V1/APIDungeonRouteController.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@ public function createThumbnails(
return new DungeonRouteThumbnailJobCollectionResource(
$apiDungeonRouteControllerService->createThumbnails(
$dungeonRoute,
$validated['width'],
$validated['height'],
$validated['viewport_width'],
$validated['viewport_height'],
$validated['image_width'],
$validated['image_height'],
$validated['zoom_level'],
$validated['quality']
)
Expand Down
23 changes: 23 additions & 0 deletions app/Http/Controllers/Traits/ValidatesFloorId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace App\Http\Controllers\Traits;

use App\Models\Floor\Floor;
use Illuminate\Http\Response;

trait ValidatesFloorId
{
/**
* @param int $floorId
* @param int $dungeonId
* @return void
*/
public function validateFloorId(int $floorId, int $dungeonId): ?Response
{
if (Floor::findOrFail($floorId)->dungeon_id !== $dungeonId) {
return response(__('controller.brushline.error.floor_not_found_in_dungeon'), 422);
}

return null;
}
}
4 changes: 2 additions & 2 deletions app/Http/Middleware/ApiAuthentication.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public function __construct(UserServiceInterface $userService)
*/
public function handle(Request $request, Closure $next)
{
if (!$this->userService->longAsUserFromAuthenticationHeader($request)) {
return response('Unauthorized.', StatusCode::UNAUTHORIZED);
if (!$this->userService->loginAsUserFromAuthenticationHeader($request)) {
return response()->json(['error' => __('exceptions.handler.unauthenticated')], StatusCode::UNAUTHORIZED);
}

return $next($request);
Expand Down
18 changes: 16 additions & 2 deletions app/Http/Models/Request/Route/RouteThumbnailRequestModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,33 @@
*/
class RouteThumbnailRequestModel
{
/**
* @OA\Property(minimum="768",maximum="1620",example="900")
*
* @var int|null
*/
public ?int $viewport_width;

/**
* @OA\Property(minimum="512",maximum="1080",example="600")
*
* @var int|null
*/
public ?int $viewport_height;

/**
* @OA\Property(minimum="192",maximum="1620",example="900")
*
* @var int|null
*/
public ?int $width;
public ?int $image_width;

/**
* @OA\Property(minimum="128",maximum="1080",example="600")
*
* @var int|null
*/
public ?int $height;
public ?int $image_height;

/**
* @OA\Property(minimum="1",maximum="5",example="2.2")
Expand Down
Loading

0 comments on commit 54a2025

Please sign in to comment.