Add check for authentication

This commit is contained in:
philipp lang 2022-02-19 13:37:53 +01:00
parent 15a6bcc70e
commit 798f7222e9
10 changed files with 139 additions and 40 deletions

View File

@ -15,6 +15,7 @@ use Log;
use Zoomyboy\LaravelNami\Authentication\Authenticator; use Zoomyboy\LaravelNami\Authentication\Authenticator;
use Zoomyboy\LaravelNami\Backend\Backend; use Zoomyboy\LaravelNami\Backend\Backend;
use Zoomyboy\LaravelNami\Concerns\IsNamiMember; use Zoomyboy\LaravelNami\Concerns\IsNamiMember;
use Zoomyboy\LaravelNami\Exceptions\NotAuthenticatedException;
use Zoomyboy\LaravelNami\Exceptions\RightException; use Zoomyboy\LaravelNami\Exceptions\RightException;
use Zoomyboy\LaravelNami\NamiException; use Zoomyboy\LaravelNami\NamiException;
@ -92,6 +93,11 @@ class Api {
return $this; return $this;
} }
public function isLoggedIn(): bool
{
return $this->authenticator->isLoggedIn();
}
public function membersOf($groupId): Collection { public function membersOf($groupId): Collection {
return collect($this->http()->get($this->url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$groupId.'/flist')->json()['data']); return collect($this->http()->get($this->url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$groupId.'/flist')->json()['data']);
} }
@ -186,6 +192,7 @@ class Api {
public function coursesFor(int $memberId): Collection public function coursesFor(int $memberId): Collection
{ {
$this->assertLoggedIn();
$url = $this->url."/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/flist"; $url = $this->url."/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/flist";
$response = $this->http()->get($url); $response = $this->http()->get($url);
@ -382,5 +389,12 @@ class Api {
throw (new NamiException($message))->response($response)->request($request); throw (new NamiException($message))->response($response)->request($request);
} }
private function assertLoggedIn(): void
{
if (!$this->isLoggedIn()) {
throw new NotAuthenticatedException('You need to login first');
}
}
} }

View File

@ -8,5 +8,6 @@ abstract class Authenticator {
abstract public function login(int $mglnr, string $password): self; abstract public function login(int $mglnr, string $password): self;
abstract public function http(): PendingRequest; abstract public function http(): PendingRequest;
abstract public function isLoggedIn(): bool;
} }

View File

@ -33,6 +33,11 @@ class FakeCookie extends Authenticator {
return $this; return $this;
} }
public function isLoggedIn(): bool
{
return $this->authenticated !== null;
}
public function http(): PendingRequest public function http(): PendingRequest
{ {
return Http::withOptions([]); return Http::withOptions([]);
@ -82,15 +87,15 @@ class FakeCookie extends Authenticator {
public function assertNotLoggedIn(): void public function assertNotLoggedIn(): void
{ {
Assert::assertNull( Assert::assertFalse(
$this->authenticated, $this->isLoggedIn(),
'Failed asserting that noone is logged in. Found login with '.data_get($this->authenticated, 'mglnr') 'Failed asserting that noone is logged in. Found login with '.data_get($this->authenticated, 'mglnr')
); );
} }
public function assertLoggedIn(): void public function assertLoggedIn(): void
{ {
Assert::assertTrue($this->isLoggedIn());
} }
} }

View File

@ -43,12 +43,7 @@ class MainCookie extends Authenticator {
return $this; return $this;
} }
public function http(): PendingRequest public function isLoggedIn(): bool
{
return Http::withOptions(['cookies' => $this->load()]);
}
private function isLoggedIn(): bool
{ {
if ($this->file() === null) { if ($this->file() === null) {
return false; return false;
@ -57,6 +52,11 @@ class MainCookie extends Authenticator {
return ! $this->isExpired(); return ! $this->isExpired();
} }
public function http(): PendingRequest
{
return Http::withOptions(['cookies' => $this->load()]);
}
private function newFileName(): string private function newFileName(): string
{ {
return $this->path.'/'.time().'.txt'; return $this->path.'/'.time().'.txt';

View File

@ -8,19 +8,13 @@ use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Zoomyboy\LaravelNami\Fakes\CourseFake;
use Zoomyboy\LaravelNami\Fakes\Fake; use Zoomyboy\LaravelNami\Fakes\Fake;
use Zoomyboy\LaravelNami\Fakes\FakeInstance; use Zoomyboy\LaravelNami\Fakes\FakeInstance;
use Zoomyboy\LaravelNami\Fakes\LoginFake; use Zoomyboy\LaravelNami\Fakes\LoginFake;
class FakeBackend { class FakeBackend {
public function fakeLogin(string $mglnr): self
{
app(LoginFake::class)->succeeds($mglnr);
return $this;
}
/** /**
* @param int $mitgliedsNr * @param int $mitgliedsNr
* @param array <string, mixed> $data * @param array <string, mixed> $data
@ -116,27 +110,12 @@ class FakeBackend {
]) ?: '{}', 200); ]) ?: '{}', 200);
} }
} }
});
foreach ($data as $member) { foreach ($data as $member) {
if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$member['id']}/flist") { app(CourseFake::class)->forMember($member['id'], $member['courses'] ?? []);
return Http::response(json_encode([
'success' => true,
'totalEntries' => collect($member['courses'] ?? [])->count(),
'data' => collect($member['courses'] ?? [])->map(fn ($course) => ['id' => $course['id']]),
]) ?: '{}', 200);
} }
foreach ($member['courses'] ?? [] as $course) {
if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$member['id']}/{$course['id']}") {
return Http::response(json_encode([
'success' => true,
'data' => $course,
]) ?: '{}', 200);
}
}
}
});
return $this; return $this;
} }

View File

@ -0,0 +1,9 @@
<?php
namespace Zoomyboy\LaravelNami\Exceptions;
use Exception;
class NotAuthenticatedException extends Exception {
}

View File

@ -7,6 +7,28 @@ use Illuminate\Support\Facades\Http;
class CourseFake extends Fake { class CourseFake extends Fake {
public function forMember(int $memberId, array $data): void
{
Http::fake(function($request) use ($memberId, $data) {
if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/flist") {
return Http::response(json_encode([
'success' => true,
'totalEntries' => collect($data)->count(),
'data' => collect($data)->map(fn ($course) => ['id' => $course['id']]),
]) ?: '{}', 200);
}
foreach ($data as $course) {
if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$course['id']}") {
return Http::response(json_encode([
'success' => true,
'data' => $course,
]) ?: '{}', 200);
}
}
});
}
public function createsSuccessful(int $memberId, int $courseId): void public function createsSuccessful(int $memberId, int $courseId): void
{ {
Http::fake(function($request) use ($memberId, $courseId) { Http::fake(function($request) use ($memberId, $courseId) {

View File

@ -6,15 +6,11 @@ use Illuminate\Support\Facades\Facade;
/** /**
* @method static \Zoomyboy\LaravelNami\Api login(int $mglnr, string $password) * @method static \Zoomyboy\LaravelNami\Api login(int $mglnr, string $password)
* @method static bool isLoggedIn()
* @method static \Zoomyboy\LaravelNami\Api fake() * @method static \Zoomyboy\LaravelNami\Api fake()
*/ */
class Nami extends Facade { class Nami extends Facade {
protected static function getFacadeAccessor() { return 'nami.api'; } protected static function getFacadeAccessor() { return 'nami.api'; }
protected static function fake(): void
{
static::swap(ApiFake::class);
}
} }

62
tests/Unit/CourseTest.php Normal file
View File

@ -0,0 +1,62 @@
<?php
namespace Zoomyboy\LaravelNami\Tests\Unit;
use Illuminate\Support\Facades\Http;
use Zoomyboy\LaravelNami\Authentication\Auth;
use Zoomyboy\LaravelNami\Exceptions\NotAuthenticatedException;
use Zoomyboy\LaravelNami\Fakes\CourseFake;
use Zoomyboy\LaravelNami\LoginException;
use Zoomyboy\LaravelNami\Nami;
use Zoomyboy\LaravelNami\Tests\TestCase;
class CourseTest extends TestCase
{
public function setUp(): void
{
parent::setUp();
Auth::fake();
}
public function test_get_courses_of_member(): void
{
Auth::success(12345, 'secret');
app(CourseFake::class)->forMember(11111, [
['bausteinId' => 506, 'id' => 788, 'veranstalter' => 'KJA', 'vstgName' => 'eventname', 'vstgTag' => '2021-11-12 00:00:00']
]);
$courses = Nami::login(12345, 'secret')->coursesFor(11111);
$this->assertEquals(788, $courses->first()->id);
$this->assertEquals('KJA', $courses->first()->organizer);
$this->assertEquals(506, $courses->first()->course_id);
$this->assertEquals('eventname', $courses->first()->event_name);
$this->assertEquals('2021-11-12 00:00:00', $courses->first()->completed_at);
Http::assertSent(function($request) {
return $request->url() == 'https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/11111/flist';
});
Http::assertSent(function($request) {
return $request->url() == 'https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/11111/788';
});
Http::assertSentCount(2);
}
public function test_needs_login(): void
{
$this->expectException(NotAuthenticatedException::class);
$courses = Nami::coursesFor(11111);
}
public function test_parses_failed_login(): void
{
Auth::failed(12345, 'secret');
$this->expectException(LoginException::class);
Nami::login(12345, 'secret')->coursesFor(11111);
}
}

View File

@ -119,6 +119,17 @@ class LoginTest extends TestCase
Auth::assertNotLoggedIn(); Auth::assertNotLoggedIn();
} }
public function test_it_fakes_login_state(): void
{
Auth::fake();
Auth::success(12345, 'secret');
$this->assertFalse(Nami::isLoggedIn());
Nami::login(12345, 'secret');
$this->assertTrue(Nami::isLoggedIn());
}
private function fakeSuccessfulLogin(): array private function fakeSuccessfulLogin(): array
{ {
return [ return [