mirror of
https://github.com/koel/koel
synced 2024-11-12 23:47:09 +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;
|
||||
|
||||
use App\Attributes\DisabledInDemo;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\API\ForgotPasswordRequest;
|
||||
use App\Services\AuthenticationService;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
#[DisabledInDemo]
|
||||
class ForgotPasswordController extends Controller
|
||||
{
|
||||
public function __invoke(ForgotPasswordRequest $request, AuthenticationService $auth)
|
||||
{
|
||||
static::disableInDemo();
|
||||
|
||||
return $auth->trySendResetPasswordLink($request->email)
|
||||
? response()->noContent()
|
||||
: response('', Response::HTTP_NOT_FOUND);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers\API\Podcast;
|
||||
|
||||
use App\Attributes\DisabledInDemo;
|
||||
use App\Exceptions\UserAlreadySubscribedToPodcast;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\API\Podcast\PodcastStoreRequest;
|
||||
|
@ -29,10 +30,9 @@ class PodcastController extends Controller
|
|||
return PodcastResourceCollection::make($this->podcastRepository->getAllByUser($this->user));
|
||||
}
|
||||
|
||||
#[DisabledInDemo]
|
||||
public function store(PodcastStoreRequest $request)
|
||||
{
|
||||
self::disableInDemo();
|
||||
|
||||
try {
|
||||
return PodcastResource::make($this->podcastService->addPodcast($request->url, $this->user));
|
||||
} catch (UserAlreadySubscribedToPodcast) {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers\API;
|
||||
|
||||
use App\Attributes\DisabledInDemo;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\API\ProfileUpdateRequest;
|
||||
use App\Http\Resources\UserResource;
|
||||
|
@ -30,10 +31,9 @@ class ProfileController extends Controller
|
|||
return UserResource::make($this->user);
|
||||
}
|
||||
|
||||
#[DisabledInDemo(Response::HTTP_NO_CONTENT)]
|
||||
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.
|
||||
throw_if(
|
||||
!$this->user->is_sso && !$this->hash->check($request->current_password, $this->user->password),
|
||||
|
|
|
@ -2,17 +2,17 @@
|
|||
|
||||
namespace App\Http\Controllers\API;
|
||||
|
||||
use App\Attributes\DisabledInDemo;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\API\ResetPasswordRequest;
|
||||
use App\Services\AuthenticationService;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
#[DisabledInDemo]
|
||||
class ResetPasswordController extends Controller
|
||||
{
|
||||
public function __invoke(ResetPasswordRequest $request, AuthenticationService $auth)
|
||||
{
|
||||
static::disableInDemo();
|
||||
|
||||
return $auth->tryResetPasswordUsingBroker($request->email, $request->password, $request->token)
|
||||
? response()->noContent()
|
||||
: response('', Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
|
|
|
@ -5,7 +5,6 @@ namespace App\Http\Controllers;
|
|||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
|
||||
abstract class Controller extends BaseController
|
||||
|
@ -13,9 +12,4 @@ abstract class Controller extends BaseController
|
|||
use AuthorizesRequests;
|
||||
use DispatchesJobs;
|
||||
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\EncryptCookies;
|
||||
use App\Http\Middleware\ForceHttps;
|
||||
use App\Http\Middleware\HandleDemoMode;
|
||||
use App\Http\Middleware\ObjectStorageAuthenticate;
|
||||
use App\Http\Middleware\ThrottleRequests;
|
||||
use App\Http\Middleware\TrimStrings;
|
||||
|
@ -48,10 +49,12 @@ class Kernel extends HttpKernel
|
|||
StartSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
SubstituteBindings::class,
|
||||
HandleDemoMode::class,
|
||||
],
|
||||
'api' => [
|
||||
'throttle:60,1',
|
||||
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));
|
||||
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'));
|
||||
}
|
||||
|
||||
#[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