mirror of
https://github.com/koel/koel
synced 2024-11-14 08:27:13 +00:00
feat: use PHP attribute to mark requests disabled in demo (#1873)
This commit is contained in:
parent
d900c9cb26
commit
22c16b996f
10 changed files with 104 additions and 14 deletions
14
app/Attributes/DisabledInDemo.php
Normal file
14
app/Attributes/DisabledInDemo.php
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Attributes;
|
||||||
|
|
||||||
|
use Attribute;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
|
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS)]
|
||||||
|
class DisabledInDemo
|
||||||
|
{
|
||||||
|
public function __construct(public int $code = Response::HTTP_FORBIDDEN)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,17 +2,17 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\API;
|
namespace App\Http\Controllers\API;
|
||||||
|
|
||||||
|
use App\Attributes\DisabledInDemo;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\API\ForgotPasswordRequest;
|
use App\Http\Requests\API\ForgotPasswordRequest;
|
||||||
use App\Services\AuthenticationService;
|
use App\Services\AuthenticationService;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
|
#[DisabledInDemo]
|
||||||
class ForgotPasswordController extends Controller
|
class ForgotPasswordController extends Controller
|
||||||
{
|
{
|
||||||
public function __invoke(ForgotPasswordRequest $request, AuthenticationService $auth)
|
public function __invoke(ForgotPasswordRequest $request, AuthenticationService $auth)
|
||||||
{
|
{
|
||||||
static::disableInDemo();
|
|
||||||
|
|
||||||
return $auth->trySendResetPasswordLink($request->email)
|
return $auth->trySendResetPasswordLink($request->email)
|
||||||
? response()->noContent()
|
? response()->noContent()
|
||||||
: response('', Response::HTTP_NOT_FOUND);
|
: response('', Response::HTTP_NOT_FOUND);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\API\Podcast;
|
namespace App\Http\Controllers\API\Podcast;
|
||||||
|
|
||||||
|
use App\Attributes\DisabledInDemo;
|
||||||
use App\Exceptions\UserAlreadySubscribedToPodcast;
|
use App\Exceptions\UserAlreadySubscribedToPodcast;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\API\Podcast\PodcastStoreRequest;
|
use App\Http\Requests\API\Podcast\PodcastStoreRequest;
|
||||||
|
@ -29,10 +30,9 @@ class PodcastController extends Controller
|
||||||
return PodcastResourceCollection::make($this->podcastRepository->getAllByUser($this->user));
|
return PodcastResourceCollection::make($this->podcastRepository->getAllByUser($this->user));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[DisabledInDemo]
|
||||||
public function store(PodcastStoreRequest $request)
|
public function store(PodcastStoreRequest $request)
|
||||||
{
|
{
|
||||||
self::disableInDemo();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return PodcastResource::make($this->podcastService->addPodcast($request->url, $this->user));
|
return PodcastResource::make($this->podcastService->addPodcast($request->url, $this->user));
|
||||||
} catch (UserAlreadySubscribedToPodcast) {
|
} catch (UserAlreadySubscribedToPodcast) {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\API;
|
namespace App\Http\Controllers\API;
|
||||||
|
|
||||||
|
use App\Attributes\DisabledInDemo;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\API\ProfileUpdateRequest;
|
use App\Http\Requests\API\ProfileUpdateRequest;
|
||||||
use App\Http\Resources\UserResource;
|
use App\Http\Resources\UserResource;
|
||||||
|
@ -30,10 +31,9 @@ class ProfileController extends Controller
|
||||||
return UserResource::make($this->user);
|
return UserResource::make($this->user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[DisabledInDemo(Response::HTTP_NO_CONTENT)]
|
||||||
public function update(ProfileUpdateRequest $request)
|
public function update(ProfileUpdateRequest $request)
|
||||||
{
|
{
|
||||||
static::disableInDemo(Response::HTTP_NO_CONTENT);
|
|
||||||
|
|
||||||
// If the user is not using SSO, we need to verify their current password.
|
// If the user is not using SSO, we need to verify their current password.
|
||||||
throw_if(
|
throw_if(
|
||||||
!$this->user->is_sso && !$this->hash->check($request->current_password, $this->user->password),
|
!$this->user->is_sso && !$this->hash->check($request->current_password, $this->user->password),
|
||||||
|
|
|
@ -2,17 +2,17 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\API;
|
namespace App\Http\Controllers\API;
|
||||||
|
|
||||||
|
use App\Attributes\DisabledInDemo;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\API\ResetPasswordRequest;
|
use App\Http\Requests\API\ResetPasswordRequest;
|
||||||
use App\Services\AuthenticationService;
|
use App\Services\AuthenticationService;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
|
#[DisabledInDemo]
|
||||||
class ResetPasswordController extends Controller
|
class ResetPasswordController extends Controller
|
||||||
{
|
{
|
||||||
public function __invoke(ResetPasswordRequest $request, AuthenticationService $auth)
|
public function __invoke(ResetPasswordRequest $request, AuthenticationService $auth)
|
||||||
{
|
{
|
||||||
static::disableInDemo();
|
|
||||||
|
|
||||||
return $auth->tryResetPasswordUsingBroker($request->email, $request->password, $request->token)
|
return $auth->tryResetPasswordUsingBroker($request->email, $request->password, $request->token)
|
||||||
? response()->noContent()
|
? response()->noContent()
|
||||||
: response('', Response::HTTP_UNPROCESSABLE_ENTITY);
|
: response('', Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||||
|
|
|
@ -5,7 +5,6 @@ namespace App\Http\Controllers;
|
||||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||||
use Illuminate\Http\Response;
|
|
||||||
use Illuminate\Routing\Controller as BaseController;
|
use Illuminate\Routing\Controller as BaseController;
|
||||||
|
|
||||||
abstract class Controller extends BaseController
|
abstract class Controller extends BaseController
|
||||||
|
@ -13,9 +12,4 @@ abstract class Controller extends BaseController
|
||||||
use AuthorizesRequests;
|
use AuthorizesRequests;
|
||||||
use DispatchesJobs;
|
use DispatchesJobs;
|
||||||
use ValidatesRequests;
|
use ValidatesRequests;
|
||||||
|
|
||||||
protected static function disableInDemo(int $code = Response::HTTP_FORBIDDEN): void
|
|
||||||
{
|
|
||||||
abort_if(config('koel.misc.demo'), $code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ use App\Http\Middleware\AudioAuthenticate;
|
||||||
use App\Http\Middleware\Authenticate;
|
use App\Http\Middleware\Authenticate;
|
||||||
use App\Http\Middleware\EncryptCookies;
|
use App\Http\Middleware\EncryptCookies;
|
||||||
use App\Http\Middleware\ForceHttps;
|
use App\Http\Middleware\ForceHttps;
|
||||||
|
use App\Http\Middleware\HandleDemoMode;
|
||||||
use App\Http\Middleware\ObjectStorageAuthenticate;
|
use App\Http\Middleware\ObjectStorageAuthenticate;
|
||||||
use App\Http\Middleware\ThrottleRequests;
|
use App\Http\Middleware\ThrottleRequests;
|
||||||
use App\Http\Middleware\TrimStrings;
|
use App\Http\Middleware\TrimStrings;
|
||||||
|
@ -48,10 +49,12 @@ class Kernel extends HttpKernel
|
||||||
StartSession::class,
|
StartSession::class,
|
||||||
VerifyCsrfToken::class,
|
VerifyCsrfToken::class,
|
||||||
SubstituteBindings::class,
|
SubstituteBindings::class,
|
||||||
|
HandleDemoMode::class,
|
||||||
],
|
],
|
||||||
'api' => [
|
'api' => [
|
||||||
'throttle:60,1',
|
'throttle:60,1',
|
||||||
SubstituteBindings::class,
|
SubstituteBindings::class,
|
||||||
|
HandleDemoMode::class,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
44
app/Http/Middleware/HandleDemoMode.php
Normal file
44
app/Http/Middleware/HandleDemoMode.php
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Attributes\DisabledInDemo;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use ReflectionClass;
|
||||||
|
use ReflectionMethod;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class HandleDemoMode
|
||||||
|
{
|
||||||
|
private static function ensureRequestIsAllowedInDemoMode(Request $request): void
|
||||||
|
{
|
||||||
|
$route = $request->route();
|
||||||
|
$class = $route->getControllerClass();
|
||||||
|
$method = $route->getActionMethod();
|
||||||
|
|
||||||
|
$controllerReflection = new ReflectionClass($class);
|
||||||
|
|
||||||
|
foreach ($controllerReflection->getAttributes(DisabledInDemo::class) as $attribute) {
|
||||||
|
abort($attribute->newInstance()->code);
|
||||||
|
}
|
||||||
|
|
||||||
|
$methodReflection = new ReflectionMethod($class, $method);
|
||||||
|
|
||||||
|
foreach ($methodReflection->getAttributes(DisabledInDemo::class) as $attribute) {
|
||||||
|
abort($attribute->newInstance()->code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Closure(Request): Response $next
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
if (config('koel.misc.demo')) {
|
||||||
|
self::ensureRequestIsAllowedInDemoMode($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,4 +69,25 @@ class ForgotPasswordTest extends TestCase
|
||||||
self::assertTrue(Hash::check('old-password', $user->refresh()->password));
|
self::assertTrue(Hash::check('old-password', $user->refresh()->password));
|
||||||
Event::assertNotDispatched(PasswordReset::class);
|
Event::assertNotDispatched(PasswordReset::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function disabledInDemo(): void
|
||||||
|
{
|
||||||
|
config(['koel.misc.demo' => true]);
|
||||||
|
|
||||||
|
$user = create_user();
|
||||||
|
|
||||||
|
$this->post('/api/reset-password', [
|
||||||
|
'email' => $user->email,
|
||||||
|
'password' => 'new-password',
|
||||||
|
'token' => Password::createToken($user),
|
||||||
|
])->assertForbidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tearDown(): void
|
||||||
|
{
|
||||||
|
config(['koel.misc.demo' => false]);
|
||||||
|
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,4 +101,18 @@ class ProfileTest extends TestCase
|
||||||
|
|
||||||
self::assertNull($user->getRawOriginal('avatar'));
|
self::assertNull($user->getRawOriginal('avatar'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function disabledInDemo(): void
|
||||||
|
{
|
||||||
|
config(['koel.misc.demo' => true]);
|
||||||
|
$user = create_user(['password' => Hash::make('secret')]);
|
||||||
|
|
||||||
|
$this->putAs('api/me', [
|
||||||
|
'name' => 'Foo',
|
||||||
|
'email' => 'bar@baz.com',
|
||||||
|
'current_password' => 'secret',
|
||||||
|
], $user)
|
||||||
|
->assertNoContent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue