Skip to content

Commit

Permalink
Merge branch 'release/5.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
lindyhopchris committed Dec 1, 2024
2 parents 5ef2e85 + b2edf37 commit f21276a
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 51 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. This projec

## Unreleased

## [5.0.0] - 2025-12-01

### Changed

- [#298](https://github.com/laravel-json-api/laravel/pull/298)
and [#70](https://github.com/laravel-json-api/laravel/issues/70) The authorizer implementation now allows methods to
return either `bool` or an Illuminate Auth `Response`.
- **BREAKING** The return type for the `authorizeResource()` method on both resource and query request classes has
changed to `bool|Response` (where response is the Illuminate Auth response). If you are manually calling this method
and relying on the return value being a boolean, this change is breaking. However, the vast majority of applications
should be able to upgrade without any changes.

## [4.1.1] - 2024-11-30

### Fixed
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"require": {
"php": "^8.2",
"ext-json": "*",
"laravel-json-api/core": "^4.3.2",
"laravel-json-api/core": "^5.0.1",
"laravel-json-api/eloquent": "^4.4",
"laravel-json-api/encoder-neomerx": "^4.1",
"laravel-json-api/exceptions": "^3.1",
Expand Down Expand Up @@ -53,7 +53,7 @@
},
"extra": {
"branch-alias": {
"dev-develop": "4.x-dev"
"dev-develop": "5.x-dev"
},
"laravel": {
"aliases": {
Expand Down
62 changes: 38 additions & 24 deletions src/Http/Requests/FormRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace LaravelJsonApi\Laravel\Http\Requests;

use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\Access\Response;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Foundation\Http\FormRequest as BaseFormRequest;
Expand Down Expand Up @@ -226,42 +228,54 @@ public function schema(): Schema
*/
protected function passesAuthorization()
{
/**
* If the developer has implemented the `authorize` method, we
* will return the result if it is a boolean. This allows
* the developer to return a null value to indicate they want
* the default authorization to run.
*/
if (method_exists($this, 'authorize')) {
if (is_bool($passes = $this->container->call([$this, 'authorize']))) {
return $passes;
try {
/**
* If the developer has implemented the `authorize` method, we
* will return the result if it is a boolean. This allows
* the developer to return a null value to indicate they want
* the default authorization to run.
*/
if (method_exists($this, 'authorize')) {
$result = $this->container->call([$this, 'authorize']);
if ($result !== null) {
return $result instanceof Response ? $result->authorize() : $result;
}
}
}

/**
* If the developer has not authorized the request themselves,
* we run our default authorization as long as authorization is
* enabled for both the server and the schema (checked via the
* `mustAuthorize()` method).
*/
if (method_exists($this, 'authorizeResource')) {
return $this->container->call([$this, 'authorizeResource']);
}
/**
* If the developer has not authorized the request themselves,
* we run our default authorization as long as authorization is
* enabled for both the server and the schema (checked via the
* `mustAuthorize()` method).
*/
if (method_exists($this, 'authorizeResource')) {
$result = $this->container->call([$this, 'authorizeResource']);
return $result instanceof Response ? $result->authorize() : $result;
}

} catch (AuthorizationException $ex) {
$this->failIfUnauthenticated();
throw $ex;
}
return true;
}

/**
* @inheritDoc
*/
protected function failedAuthorization()
protected function failIfUnauthenticated()
{
/** @var Guard $auth */
/** @var Guard $auth */
$auth = $this->container->make(Guard::class);

if ($auth->guest()) {
throw new AuthenticationException();
}
}

/**
* @inheritDoc
*/
protected function failedAuthorization()
{
$this->failIfUnauthenticated();

parent::failedAuthorization();
}
Expand Down
5 changes: 3 additions & 2 deletions src/Http/Requests/ResourceQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace LaravelJsonApi\Laravel\Http\Requests;

use Illuminate\Auth\Access\Response;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Database\Eloquent\Model;
use LaravelJsonApi\Contracts\Auth\Authorizer;
Expand Down Expand Up @@ -104,9 +105,9 @@ public static function queryOne(string $resourceType): QueryParameters
* Perform resource authorization.
*
* @param Authorizer $authorizer
* @return bool
* @return bool|Response
*/
public function authorizeResource(Authorizer $authorizer): bool
public function authorizeResource(Authorizer $authorizer): bool|Response
{
if ($this->isViewingAny()) {
return $authorizer->index(
Expand Down
5 changes: 3 additions & 2 deletions src/Http/Requests/ResourceRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace LaravelJsonApi\Laravel\Http\Requests;

use Illuminate\Auth\Access\Response;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Database\Eloquent\Model;
Expand Down Expand Up @@ -150,9 +151,9 @@ public function toMany(): Collection
* Perform resource authorization.
*
* @param Authorizer $authorizer
* @return bool
* @return bool|Response
*/
public function authorizeResource(Authorizer $authorizer): bool
public function authorizeResource(Authorizer $authorizer): bool|Response
{
if ($this->isCreating()) {
return $authorizer->store(
Expand Down
41 changes: 21 additions & 20 deletions stubs/authorizer.stub
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace {{ namespace }};

use Illuminate\Auth\Access\Response;
use Illuminate\Http\Request;
use LaravelJsonApi\Contracts\Auth\Authorizer;

Expand All @@ -13,9 +14,9 @@ class {{ class }} implements Authorizer
*
* @param Request $request
* @param string $modelClass
* @return bool
* @return bool|Response
*/
public function index(Request $request, string $modelClass): bool
public function index(Request $request, string $modelClass): bool|Response
{
// TODO: Implement index() method.
}
Expand All @@ -25,9 +26,9 @@ class {{ class }} implements Authorizer
*
* @param Request $request
* @param string $modelClass
* @return bool
* @return bool|Response
*/
public function store(Request $request, string $modelClass): bool
public function store(Request $request, string $modelClass): bool|Response
{
// TODO: Implement store() method.
}
Expand All @@ -37,9 +38,9 @@ class {{ class }} implements Authorizer
*
* @param Request $request
* @param object $model
* @return bool
* @return bool|Response
*/
public function show(Request $request, object $model): bool
public function show(Request $request, object $model): bool|Response
{
// TODO: Implement show() method.
}
Expand All @@ -49,9 +50,9 @@ class {{ class }} implements Authorizer
*
* @param object $model
* @param Request $request
* @return bool
* @return bool|Response
*/
public function update(Request $request, object $model): bool
public function update(Request $request, object $model): bool|Response
{
// TODO: Implement update() method.
}
Expand All @@ -61,9 +62,9 @@ class {{ class }} implements Authorizer
*
* @param Request $request
* @param object $model
* @return bool
* @return bool|Response
*/
public function destroy(Request $request, object $model): bool
public function destroy(Request $request, object $model): bool|Response
{
// TODO: Implement destroy() method.
}
Expand All @@ -74,9 +75,9 @@ class {{ class }} implements Authorizer
* @param Request $request
* @param object $model
* @param string $fieldName
* @return bool
* @return bool|Response
*/
public function showRelated(Request $request, object $model, string $fieldName): bool
public function showRelated(Request $request, object $model, string $fieldName): bool|Response
{
// TODO: Implement showRelated() method.
}
Expand All @@ -87,9 +88,9 @@ class {{ class }} implements Authorizer
* @param Request $request
* @param object $model
* @param string $fieldName
* @return bool
* @return bool|Response
*/
public function showRelationship(Request $request, object $model, string $fieldName): bool
public function showRelationship(Request $request, object $model, string $fieldName): bool|Response
{
// TODO: Implement showRelationship() method.
}
Expand All @@ -100,9 +101,9 @@ class {{ class }} implements Authorizer
* @param Request $request
* @param object $model
* @param string $fieldName
* @return bool
* @return bool|Response
*/
public function updateRelationship(Request $request, object $model, string $fieldName): bool
public function updateRelationship(Request $request, object $model, string $fieldName): bool|Response
{
// TODO: Implement updateRelationship() method.
}
Expand All @@ -113,9 +114,9 @@ class {{ class }} implements Authorizer
* @param Request $request
* @param object $model
* @param string $fieldName
* @return bool
* @return bool|Response
*/
public function attachRelationship(Request $request, object $model, string $fieldName): bool
public function attachRelationship(Request $request, object $model, string $fieldName): bool|Response
{
// TODO: Implement attachRelationship() method.
}
Expand All @@ -126,9 +127,9 @@ class {{ class }} implements Authorizer
* @param Request $request
* @param object $model
* @param string $fieldName
* @return bool
* @return bool|Response
*/
public function detachRelationship(Request $request, object $model, string $fieldName): bool
public function detachRelationship(Request $request, object $model, string $fieldName): bool|Response
{
// TODO: Implement detachRelationship() method.
}
Expand Down
1 change: 1 addition & 0 deletions tests/dummy/app/Http/Controllers/Api/V1/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
class UserController extends Controller
{
use Actions\FetchOne;
use Actions\Destroy;
use Actions\FetchRelated;
use Actions\FetchRelationship;
use Actions\UpdateRelationship;
Expand Down
14 changes: 14 additions & 0 deletions tests/dummy/app/Policies/UserPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace App\Policies;

use App\Models\User;
use Illuminate\Auth\Access\Response;

class UserPolicy
{
Expand Down Expand Up @@ -50,4 +51,17 @@ public function updatePhone(User $user, User $other): bool
{
return $user->is($other);
}

/**
* Determine if the user can delete the other user.
*
* @param User $user
* @param User $other
* @return bool|Response
*/
public function delete(User $user, User $other)
{
return $user->is($other) ? true : Response::denyAsNotFound('not found message');
}

}
2 changes: 1 addition & 1 deletion tests/dummy/routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
});

/** Users */
$server->resource('users')->only('show')->relationships(function ($relationships) {
$server->resource('users')->only('show','destroy')->relationships(function ($relationships) {
$relationships->hasOne('phone');
})->actions(function ($actions) {
$actions->get('me');
Expand Down
38 changes: 38 additions & 0 deletions tests/dummy/tests/Api/V1/Users/DeleteTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php
/*
* Copyright 2024 Cloud Creativity Limited
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/

declare(strict_types=1);

namespace App\Tests\Api\V1\Users;

use App\Models\User;
use App\Tests\Api\V1\TestCase;

class DeleteTest extends TestCase
{

public function test(): void
{
$user = User::factory()->createOne();

$expected = $this->serializer
->user($user);
$response = $this
->actingAs(User::factory()->createOne())
->jsonApi('users')
->delete(url('/api/v1/users', $expected['id']));

$response->assertNotFound()
->assertHasError(404, [
'detail' => 'not found message',
'status' => '404',
'title' => 'Not Found',
]);
}
}

0 comments on commit f21276a

Please sign in to comment.