Add login test
This commit is contained in:
parent
829dd01358
commit
b78b0a5b21
|
@ -3,3 +3,5 @@
|
||||||
*.swo
|
*.swo
|
||||||
*.swm
|
*.swm
|
||||||
tags
|
tags
|
||||||
|
.cookies
|
||||||
|
/.phpunit.result.cache
|
||||||
|
|
90
src/Api.php
90
src/Api.php
|
@ -5,30 +5,31 @@ namespace Zoomyboy\LaravelNami;
|
||||||
use App\Conf;
|
use App\Conf;
|
||||||
use App\Nami\Exceptions\TooManyLoginAttemptsException;
|
use App\Nami\Exceptions\TooManyLoginAttemptsException;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Http\Client\PendingRequest;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Illuminate\Support\LazyCollection;
|
use Illuminate\Support\LazyCollection;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Log;
|
use Log;
|
||||||
|
use Zoomyboy\LaravelNami\Authentication\Cookie;
|
||||||
use Zoomyboy\LaravelNami\Backend\Backend;
|
use Zoomyboy\LaravelNami\Backend\Backend;
|
||||||
use Zoomyboy\LaravelNami\Concerns\IsNamiMember;
|
use Zoomyboy\LaravelNami\Concerns\IsNamiMember;
|
||||||
use Zoomyboy\LaravelNami\Cookies\Cookie;
|
|
||||||
use Zoomyboy\LaravelNami\Exceptions\RightException;
|
use Zoomyboy\LaravelNami\Exceptions\RightException;
|
||||||
use Zoomyboy\LaravelNami\NamiException;
|
use Zoomyboy\LaravelNami\NamiException;
|
||||||
|
|
||||||
class Api {
|
class Api {
|
||||||
|
|
||||||
private $cookie;
|
public string $url = 'https://nami.dpsg.de';
|
||||||
public $loggedIn = null;
|
private Cookie $cookie;
|
||||||
public static $url = 'https://nami.dpsg.de';
|
|
||||||
|
|
||||||
public function __construct($cookieStore) {
|
public function __construct(Cookie $cookie)
|
||||||
$this->cookie = $cookieStore;
|
{
|
||||||
|
$this->cookie = $cookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function http() {
|
public function http(): PendingRequest {
|
||||||
return Backend::init($this->cookie);
|
return Http::withOptions(['cookies' => $this->cookie->load()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findNr(int $nr): Member
|
public function findNr(int $nr): Member
|
||||||
|
@ -54,7 +55,7 @@ class Api {
|
||||||
$page = 1;
|
$page = 1;
|
||||||
while (!isset ($totalEntries) || ($page-1) * 100 + 1 <= $totalEntries) {
|
while (!isset ($totalEntries) || ($page-1) * 100 + 1 <= $totalEntries) {
|
||||||
$start = ($page-1) * 100;
|
$start = ($page-1) * 100;
|
||||||
$url = self::$url.'/ica/rest/nami/search-multi/result-list?searchedValues='.rawurlencode(json_encode((object) $payload) ?: '{}').'&page='.$page.'&start='.$start.'&limit=100';
|
$url = $this->url.'/ica/rest/nami/search-multi/result-list?searchedValues='.rawurlencode(json_encode((object) $payload) ?: '{}').'&page='.$page.'&start='.$start.'&limit=100';
|
||||||
$response = $this->http()->get($url);
|
$response = $this->http()->get($url);
|
||||||
$totalEntries = $response->json()['totalEntries'];
|
$totalEntries = $response->json()['totalEntries'];
|
||||||
if ($response->json()['success'] !== true) {
|
if ($response->json()['success'] !== true) {
|
||||||
|
@ -70,12 +71,8 @@ class Api {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function loggedInAlready(): bool {
|
|
||||||
return $this->loggedIn !== null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function deleteMember($id) {
|
public function deleteMember($id) {
|
||||||
$url = self::$url.'/ica/rest/nami/mitglied/filtered-for-navigation/mglschaft-beenden';
|
$url = $this->url.'/ica/rest/nami/mitglied/filtered-for-navigation/mglschaft-beenden';
|
||||||
$payload = [
|
$payload = [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'isConfirmed' => 'true',
|
'isConfirmed' => 'true',
|
||||||
|
@ -88,19 +85,18 @@ class Api {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function login($mglnr = null, $password = null, $groupid = null): self {
|
public function login($mglnr = null, $password = null): self {
|
||||||
$resolved = $this->cookie->resolve($mglnr);
|
if ($this->cookie->isLoggedIn()) {
|
||||||
|
|
||||||
if ($resolved && !$this->cookie->isExpired()) {
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->cookie->beforeLogin();
|
||||||
|
|
||||||
$mglnr = $mglnr ?: config('nami.auth.mglnr');
|
$mglnr = $mglnr ?: config('nami.auth.mglnr');
|
||||||
$password = $password ?: config('nami.auth.password');
|
$password = $password ?: config('nami.auth.password');
|
||||||
$groupid = $groupid ?: config('nami.auth.groupid');
|
|
||||||
|
|
||||||
$this->http()->get(self::$url.'/ica/pages/login.jsp');
|
$this->http()->get($this->url.'/ica/pages/login.jsp');
|
||||||
$response = $this->http()->asForm()->post(self::$url.'/ica/rest/nami/auth/manual/sessionStartup', [
|
$response = $this->http()->asForm()->post($this->url.'/ica/rest/nami/auth/manual/sessionStartup', [
|
||||||
'Login' => 'API',
|
'Login' => 'API',
|
||||||
'redirectTo' => './app.jsp',
|
'redirectTo' => './app.jsp',
|
||||||
'username' => $mglnr,
|
'username' => $mglnr,
|
||||||
|
@ -113,14 +109,14 @@ class Api {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->cookie->store($mglnr);
|
|
||||||
$this->loggedIn = $mglnr;
|
$this->loggedIn = $mglnr;
|
||||||
|
$this->cookie->afterLogin();
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function membersOf($groupId): Collection {
|
public function membersOf($groupId): Collection {
|
||||||
return collect($this->http()->get(self::$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']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function putMember(array $attributes) {
|
public function putMember(array $attributes) {
|
||||||
|
@ -130,14 +126,14 @@ class Api {
|
||||||
$payload = array_merge($existing, $member->toNami());
|
$payload = array_merge($existing, $member->toNami());
|
||||||
$payload['kontoverbindung'] = json_encode(data_get($payload, 'kontoverbindung', []));
|
$payload['kontoverbindung'] = json_encode(data_get($payload, 'kontoverbindung', []));
|
||||||
$response = $this->http()->put(
|
$response = $this->http()->put(
|
||||||
self::$url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$member->group_id.'/'.$member->id,
|
$this->url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$member->group_id.'/'.$member->id,
|
||||||
$payload
|
$payload
|
||||||
);
|
);
|
||||||
if (data_get($response->json(), 'success') !== true) {
|
if (data_get($response->json(), 'success') !== true) {
|
||||||
$this->exception('Update failed', $member->toNami(), $response->json());
|
$this->exception('Update failed', $member->toNami(), $response->json());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$response = $this->http()->post(self::$url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$member->group_id, $member->toNami());
|
$response = $this->http()->post($this->url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$member->group_id, $member->toNami());
|
||||||
if (data_get($response->json(), 'success') !== true) {
|
if (data_get($response->json(), 'success') !== true) {
|
||||||
$this->exception('Update failed', $member->toNami(), $response->json());
|
$this->exception('Update failed', $member->toNami(), $response->json());
|
||||||
}
|
}
|
||||||
|
@ -151,10 +147,10 @@ class Api {
|
||||||
public function putMembership(int $memberId, array $data): int
|
public function putMembership(int $memberId, array $data): int
|
||||||
{
|
{
|
||||||
if (data_get($data, 'id')) {
|
if (data_get($data, 'id')) {
|
||||||
$url = self::$url."/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/{$memberId}/{$data['id']}";
|
$url = $this->url."/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/{$memberId}/{$data['id']}";
|
||||||
$response = $this->http()->put($url, $data);
|
$response = $this->http()->put($url, $data);
|
||||||
} else {
|
} else {
|
||||||
$url = self::$url."/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/{$memberId}";
|
$url = $this->url."/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/{$memberId}";
|
||||||
$response = $this->http()->post($url, $data);
|
$response = $this->http()->post($url, $data);
|
||||||
}
|
}
|
||||||
if (data_get($response->json(), 'success') !== true) {
|
if (data_get($response->json(), 'success') !== true) {
|
||||||
|
@ -169,7 +165,7 @@ class Api {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function membershipsOf($memberId): Collection {
|
public function membershipsOf($memberId): Collection {
|
||||||
$url = self::$url.'/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/'.$memberId.'/flist';
|
$url = $this->url.'/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/'.$memberId.'/flist';
|
||||||
|
|
||||||
$r = $this->http()->get($url);
|
$r = $this->http()->get($url);
|
||||||
|
|
||||||
|
@ -183,13 +179,13 @@ class Api {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function subactivitiesOf($activityId) {
|
public function subactivitiesOf($activityId) {
|
||||||
return collect($this->http()->get(self::$url.'/ica/rest/nami/untergliederungauftaetigkeit/filtered/untergliederung/taetigkeit/'.$activityId)->json()['data'])->map(function($subactivity) {
|
return collect($this->http()->get($this->url.'/ica/rest/nami/untergliederungauftaetigkeit/filtered/untergliederung/taetigkeit/'.$activityId)->json()['data'])->map(function($subactivity) {
|
||||||
return Subactivity::fromNami($subactivity);
|
return Subactivity::fromNami($subactivity);
|
||||||
});;
|
});;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function membership($memberId, $membershipId) {
|
public function membership($memberId, $membershipId) {
|
||||||
$url = self::$url.'/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/'.$memberId.'/'.$membershipId;
|
$url = $this->url.'/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/'.$memberId.'/'.$membershipId;
|
||||||
$response = $this->http()->get($url);
|
$response = $this->http()->get($url);
|
||||||
|
|
||||||
Logger::http($url, $response, 'Single Membership '.$membershipId.' from '.$memberId, ['memberId' => $memberId]);
|
Logger::http($url, $response, 'Single Membership '.$membershipId.' from '.$memberId, ['memberId' => $memberId]);
|
||||||
|
@ -203,7 +199,7 @@ class Api {
|
||||||
|
|
||||||
public function courses(): Collection
|
public function courses(): Collection
|
||||||
{
|
{
|
||||||
$url = self::$url.'/ica/rest/module/baustein';
|
$url = $this->url.'/ica/rest/module/baustein';
|
||||||
$response = $this->http()->get($url);
|
$response = $this->http()->get($url);
|
||||||
|
|
||||||
return collect($response->json()['data'])->map(function($course) {
|
return collect($response->json()['data'])->map(function($course) {
|
||||||
|
@ -213,7 +209,7 @@ class Api {
|
||||||
|
|
||||||
public function coursesFor(int $memberId): Collection
|
public function coursesFor(int $memberId): Collection
|
||||||
{
|
{
|
||||||
$url = self::$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);
|
||||||
|
|
||||||
if (!$response->ok() || $response->json()['success'] === false) {
|
if (!$response->ok() || $response->json()['success'] === false) {
|
||||||
|
@ -221,7 +217,7 @@ class Api {
|
||||||
}
|
}
|
||||||
|
|
||||||
return collect($response->json()['data'])->map(function($course) use ($memberId) {
|
return collect($response->json()['data'])->map(function($course) use ($memberId) {
|
||||||
$single = $this->http()->get(self::$url."/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$course['id']}")['data'];
|
$single = $this->http()->get($this->url."/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$course['id']}")['data'];
|
||||||
|
|
||||||
return (object) [
|
return (object) [
|
||||||
'id' => $single['id'],
|
'id' => $single['id'],
|
||||||
|
@ -240,7 +236,7 @@ class Api {
|
||||||
*/
|
*/
|
||||||
public function createCourse(int $memberId, array $payload): int
|
public function createCourse(int $memberId, array $payload): int
|
||||||
{
|
{
|
||||||
$response = $this->http()->post(self::$url."/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}", [
|
$response = $this->http()->post($this->url."/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}", [
|
||||||
'bausteinId' => $payload['course_id'],
|
'bausteinId' => $payload['course_id'],
|
||||||
'vstgName' => $payload['event_name'],
|
'vstgName' => $payload['event_name'],
|
||||||
'vstgTag' => Carbon::parse($payload['completed_at'])->format('Y-m-d').'T00:00:00',
|
'vstgTag' => Carbon::parse($payload['completed_at'])->format('Y-m-d').'T00:00:00',
|
||||||
|
@ -262,7 +258,7 @@ class Api {
|
||||||
*/
|
*/
|
||||||
public function updateCourse(int $memberId, int $courseId, array $payload): void
|
public function updateCourse(int $memberId, int $courseId, array $payload): void
|
||||||
{
|
{
|
||||||
$response = $this->http()->put(self::$url."/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$courseId}", [
|
$response = $this->http()->put($this->url."/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$courseId}", [
|
||||||
'bausteinId' => $payload['course_id'],
|
'bausteinId' => $payload['course_id'],
|
||||||
'vstgName' => $payload['event_name'],
|
'vstgName' => $payload['event_name'],
|
||||||
'vstgTag' => Carbon::parse($payload['completed_at'])->format('Y-m-d').'T00:00:00',
|
'vstgTag' => Carbon::parse($payload['completed_at'])->format('Y-m-d').'T00:00:00',
|
||||||
|
@ -276,7 +272,7 @@ class Api {
|
||||||
|
|
||||||
public function deleteCourse(int $memberId, int $courseId): void
|
public function deleteCourse(int $memberId, int $courseId): void
|
||||||
{
|
{
|
||||||
$response = $this->http()->delete(self::$url."/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$courseId}");
|
$response = $this->http()->delete($this->url."/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$courseId}");
|
||||||
|
|
||||||
if ($response->json() !== null && data_get($response->json(), 'success') !== true) {
|
if ($response->json() !== null && data_get($response->json(), 'success') !== true) {
|
||||||
$this->exception('Course deletion failed', [], $response->json());
|
$this->exception('Course deletion failed', [], $response->json());
|
||||||
|
@ -284,7 +280,7 @@ class Api {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function member($groupId, $memberId) {
|
public function member($groupId, $memberId) {
|
||||||
$url = self::$url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$groupId.'/'.$memberId;
|
$url = $this->url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$groupId.'/'.$memberId;
|
||||||
$response = $this->http()->get($url);
|
$response = $this->http()->get($url);
|
||||||
|
|
||||||
Logger::http($url, $response, 'Show member '.$memberId, ['memberId' => $memberId]);
|
Logger::http($url, $response, 'Show member '.$memberId, ['memberId' => $memberId]);
|
||||||
|
@ -316,7 +312,7 @@ class Api {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function groups($parentGroupId = null): Collection {
|
public function groups($parentGroupId = null): Collection {
|
||||||
return collect($this->http()->get(self::$url.'/ica/rest/nami/gruppierungen/filtered-for-navigation/gruppierung/node/'.($parentGroupId ?: 'root'))->json()['data'])->map(function($group) use ($parentGroupId) {
|
return collect($this->http()->get($this->url.'/ica/rest/nami/gruppierungen/filtered-for-navigation/gruppierung/node/'.($parentGroupId ?: 'root'))->json()['data'])->map(function($group) use ($parentGroupId) {
|
||||||
return Group::fromResponse($group, $parentGroupId);
|
return Group::fromResponse($group, $parentGroupId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -332,51 +328,51 @@ class Api {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function genders(): Collection {
|
public function genders(): Collection {
|
||||||
return collect($this->http()->get(self::$url."/ica/rest/baseadmin/geschlecht")['data'])->map(function($gender) {
|
return collect($this->http()->get($this->url."/ica/rest/baseadmin/geschlecht")['data'])->map(function($gender) {
|
||||||
return Gender::fromNami($gender);
|
return Gender::fromNami($gender);
|
||||||
})->filter(fn($gender) => !$gender->isNull);
|
})->filter(fn($gender) => !$gender->isNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function nationalities(): Collection {
|
public function nationalities(): Collection {
|
||||||
return collect($this->http()->get(self::$url."/ica/rest/baseadmin/staatsangehoerigkeit")['data'])->map(function($gender) {
|
return collect($this->http()->get($this->url."/ica/rest/baseadmin/staatsangehoerigkeit")['data'])->map(function($gender) {
|
||||||
return Nationality::fromNami($gender);
|
return Nationality::fromNami($gender);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function countries() {
|
public function countries() {
|
||||||
return collect($this->http()->get(self::$url."/ica/rest/baseadmin/land")['data'])->map(function($country) {
|
return collect($this->http()->get($this->url."/ica/rest/baseadmin/land")['data'])->map(function($country) {
|
||||||
return Country::fromNami($country);
|
return Country::fromNami($country);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function regions() {
|
public function regions() {
|
||||||
return collect($this->http()->get(self::$url."/ica/rest/baseadmin/region")['data'])->map(function($region) {
|
return collect($this->http()->get($this->url."/ica/rest/baseadmin/region")['data'])->map(function($region) {
|
||||||
return Region::fromNami($region);
|
return Region::fromNami($region);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function feesOf($groupid) {
|
public function feesOf($groupid) {
|
||||||
return collect($this->http()->get(self::$url."/ica/rest/namiBeitrag/beitragsartmgl/gruppierung/{$groupid}")['data'])->map(function($fee) {
|
return collect($this->http()->get($this->url."/ica/rest/namiBeitrag/beitragsartmgl/gruppierung/{$groupid}")['data'])->map(function($fee) {
|
||||||
return Fee::fromNami($fee);
|
return Fee::fromNami($fee);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function confessions(): Collection {
|
public function confessions(): Collection {
|
||||||
return collect($this->http()->get(self::$url."/ica/rest/baseadmin/konfession")['data'])->map(function($gender) {
|
return collect($this->http()->get($this->url."/ica/rest/baseadmin/konfession")['data'])->map(function($gender) {
|
||||||
return Confession::fromNami($gender);
|
return Confession::fromNami($gender);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function activities($groupId) {
|
public function activities($groupId) {
|
||||||
return collect($this->http()->get(self::$url."/ica/rest/nami/taetigkeitaufgruppierung/filtered/gruppierung/gruppierung/".$groupId)['data'])->map(function($activity) {
|
return collect($this->http()->get($this->url."/ica/rest/nami/taetigkeitaufgruppierung/filtered/gruppierung/gruppierung/".$groupId)['data'])->map(function($activity) {
|
||||||
return Activity::fromNami($activity);
|
return Activity::fromNami($activity);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function memberOverviewOf(int $groupId): Collection
|
public function memberOverviewOf(int $groupId): Collection
|
||||||
{
|
{
|
||||||
$url = self::$url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$groupId.'/flist';
|
$url = $this->url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$groupId.'/flist';
|
||||||
$response = $this->http()->get($url);
|
$response = $this->http()->get($url);
|
||||||
|
|
||||||
return collect($response['data'])->map(function($member) use ($groupId) {
|
return collect($response['data'])->map(function($member) use ($groupId) {
|
||||||
|
@ -390,7 +386,7 @@ class Api {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function singleMemberFallback($groupId, $memberId) {
|
private function singleMemberFallback($groupId, $memberId) {
|
||||||
$url = self::$url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$groupId.'/flist';
|
$url = $this->url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$groupId.'/flist';
|
||||||
$response = $this->http()->get($url);
|
$response = $this->http()->get($url);
|
||||||
|
|
||||||
$member = collect($response['data'])->first(function($member) use ($memberId) {
|
$member = collect($response['data'])->first(function($member) use ($memberId) {
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Zoomyboy\LaravelNami\Authentication;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use GuzzleHttp\Cookie\FileCookieJar;
|
||||||
|
|
||||||
|
class Cookie {
|
||||||
|
|
||||||
|
public string $path = __DIR__.'/../../.cookies';
|
||||||
|
private FileCookieJar $cookie;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the cookie for a new request
|
||||||
|
*
|
||||||
|
* @return FileCookieJar
|
||||||
|
*/
|
||||||
|
public function load(): FileCookieJar
|
||||||
|
{
|
||||||
|
$cookieFile = $this->file() ?: $this->newFileName();
|
||||||
|
|
||||||
|
return $this->cookie = new FileCookieJar($cookieFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all cookies before logging in
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function beforeLogin(): void
|
||||||
|
{
|
||||||
|
while ($file = $this->file()) {
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set last login to now after login
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function afterLogin(): void
|
||||||
|
{
|
||||||
|
$this->cookie->save($this->newFileName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isLoggedIn(): bool
|
||||||
|
{
|
||||||
|
if ($this->file() === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ! $this->isExpired();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newFileName(): string
|
||||||
|
{
|
||||||
|
return $this->path.'/'.time().'.txt';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isExpired(): bool
|
||||||
|
{
|
||||||
|
$lastLoginTime = Carbon::createFromTimestamp(pathinfo($this->file(), PATHINFO_FILENAME));
|
||||||
|
|
||||||
|
return $lastLoginTime->addMinutes(50)->isPast();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the cookie file if it exists
|
||||||
|
*
|
||||||
|
* @return ?string
|
||||||
|
*/
|
||||||
|
private function file(): ?string
|
||||||
|
{
|
||||||
|
$files = glob($this->path.'/*');
|
||||||
|
|
||||||
|
if (!count($files)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $files[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,9 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Zoomyboy\LaravelNami\Backend;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Facade;
|
|
||||||
|
|
||||||
class Backend extends Facade {
|
|
||||||
protected static function getFacadeAccessor() { return 'nami.backend'; }
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Zoomyboy\LaravelNami\Backend;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Http;
|
|
||||||
use Zoomyboy\LaravelNami\Cookies\Cookie;
|
|
||||||
|
|
||||||
class LiveBackend {
|
|
||||||
|
|
||||||
public static function init($cookie) {
|
|
||||||
return Http::withOptions(['cookies' => $cookie->forBackend()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Zoomyboy\LaravelNami\Cookies;
|
|
||||||
|
|
||||||
use GuzzleHttp\Cookie\SetCookie;
|
|
||||||
use Illuminate\Support\Facades\Cache;
|
|
||||||
|
|
||||||
class CacheCookie {
|
|
||||||
|
|
||||||
private $store;
|
|
||||||
private $createdAt;
|
|
||||||
|
|
||||||
public function __construct() {
|
|
||||||
$this->store = new \GuzzleHttp\Cookie\CookieJar();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function forBackend() {
|
|
||||||
return $this->store;
|
|
||||||
return \GuzzleHttp\Cookie\CookieJar::fromArray(['JSESSIONID' => Cache::get("namicookie-{$mglnr}")], 'nami.dpsg.de');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store the current cookie in the cache
|
|
||||||
*/
|
|
||||||
public function store($mglnr) {
|
|
||||||
Cache::forever("namicookie-{$mglnr}", [
|
|
||||||
'cookie' => $this->store->getCookieByName('JSESSIONID')->getValue(),
|
|
||||||
'created_at' => now(),
|
|
||||||
]);
|
|
||||||
$this->createdAt = now();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isExpired() {
|
|
||||||
return $this->createdAt->addHour(1)->isPast();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a cookie by string
|
|
||||||
*/
|
|
||||||
public function set($mglnr, $cookie) {
|
|
||||||
$this->store->setCookie(tap(SetCookie::fromString('JSESSIONID='.$cookie.'; path=/ica'), function($cookie) {
|
|
||||||
$cookie->setDomain('nami.dpsg.de');
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the stored cookie from the cache
|
|
||||||
*/
|
|
||||||
public function resolve($mglnr) {
|
|
||||||
$cookie = Cache::get("namicookie-{$mglnr}");
|
|
||||||
if ($cookie === null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->set($mglnr, $cookie['cookie']);
|
|
||||||
$this->createdAt = $cookie['created_at'];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Zoomyboy\LaravelNami\Providers;
|
namespace Zoomyboy\LaravelNami\Providers;
|
||||||
|
|
||||||
use GuzzleHttp\Client as GuzzleClient;
|
use GuzzleHttp\Client as GuzzleClient;
|
||||||
|
use GuzzleHttp\Cookie\CookieJarInterface;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
use Zoomyboy\LaravelNami\Api;
|
use Zoomyboy\LaravelNami\Api;
|
||||||
|
@ -21,14 +22,8 @@ class NamiServiceProvider extends ServiceProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
public function register() {
|
public function register() {
|
||||||
$this->app->singleton('nami.api', function() {
|
$this->app->bind('nami.api', function() {
|
||||||
return new Api($this->app['nami.cookie']);
|
return app(Api::class);
|
||||||
});
|
|
||||||
$this->app->bind('nami.backend', function() {
|
|
||||||
return new LiveBackend();
|
|
||||||
});
|
|
||||||
$this->app->singleton('nami.cookie', function() {
|
|
||||||
return new CacheCookie();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ class TestCase extends \Orchestra\Testbench\TestCase
|
||||||
public function setUp(): void {
|
public function setUp(): void {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
Cookie::swap(new FakeCookie());
|
$this->clearCookies();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getPackageProviders($app)
|
protected function getPackageProviders($app)
|
||||||
|
@ -30,19 +30,6 @@ class TestCase extends \Orchestra\Testbench\TestCase
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function setCredentials() {
|
|
||||||
Config::set('nami.auth.mglnr', '11223');
|
|
||||||
Config::set('nami.auth.password', 'secret');
|
|
||||||
Config::set('nami.auth.groupid', '55555');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function login() {
|
|
||||||
return [
|
|
||||||
'https://nami.dpsg.de/ica/pages/login.jsp' => Http::response('<html></html>', 200),
|
|
||||||
'https://nami.dpsg.de/ica/rest/nami/auth/manual/sessionStartup' => Http::response($this->successJson, 200)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fakeJson(string $file, array $data = []): string {
|
public function fakeJson(string $file, array $data = []): string {
|
||||||
ob_start();
|
ob_start();
|
||||||
include(__DIR__.'/json/'.$file);
|
include(__DIR__.'/json/'.$file);
|
||||||
|
@ -55,4 +42,11 @@ class TestCase extends \Orchestra\Testbench\TestCase
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function clearCookies(): void
|
||||||
|
{
|
||||||
|
foreach (glob(__DIR__.'/../.cookies/*') as $file) {
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,80 +10,106 @@ use Zoomyboy\LaravelNami\Tests\TestCase;
|
||||||
class LoginTest extends TestCase
|
class LoginTest extends TestCase
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
public function test_first_successful_login(): void
|
||||||
* A basic unit test example.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function test_first_successful_login()
|
|
||||||
{
|
{
|
||||||
Http::fake($this->login());
|
Http::fake($this->fakeSuccessfulLogin());
|
||||||
$this->setCredentials();
|
|
||||||
Nami::login();
|
Nami::login(12345, 'secret');
|
||||||
|
|
||||||
Http::assertSent(function($request) {
|
|
||||||
return $request->url() == 'https://nami.dpsg.de/ica/pages/login.jsp';
|
|
||||||
});
|
|
||||||
Http::assertSent(function($request) {
|
|
||||||
return $request->url() == 'https://nami.dpsg.de/ica/rest/nami/auth/manual/sessionStartup'
|
|
||||||
&& $request['username'] == '11223' && $request['password'] == 'secret' && $request['redirectTo'] == './app.jsp' && $request['Login'] == 'API';
|
|
||||||
});
|
|
||||||
Http::assertSentCount(2);
|
Http::assertSentCount(2);
|
||||||
|
Http::assertSent(fn ($request) => $request->url() == 'https://nami.dpsg.de/ica/pages/login.jsp');
|
||||||
|
Http::assertSent(fn ($request) => $request->url() == 'https://nami.dpsg.de/ica/rest/nami/auth/manual/sessionStartup'
|
||||||
|
&& $request['username'] == '12345' && $request['password'] == 'secret'
|
||||||
|
&& $request['redirectTo'] == './app.jsp' && $request['Login'] == 'API'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_first_login_fails_because_of_bruteforce_protection()
|
public function test_it_throws_exception_when_login_failed(): void
|
||||||
{
|
{
|
||||||
Http::fake([
|
Http::fake($this->fakeFailedLogin());
|
||||||
'https://nami.dpsg.de/ica/pages/login.jsp' => Http::response('<html></html>', 200),
|
|
||||||
'https://nami.dpsg.de/ica/rest/nami/auth/manual/sessionStartup' => Http::response($this->bruteJson, 200)
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->setCredentials();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Nami::login();
|
Nami::login(12345, 'wrongpassword');
|
||||||
|
} catch (LoginException $e) {
|
||||||
|
$this->assertEquals(LoginException::WRONG_CREDENTIALS, $e->reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_first_login_fails_because_of_bruteforce_protection(): void
|
||||||
|
{
|
||||||
|
Http::fake($this->fakeBruteforceFailure());
|
||||||
|
|
||||||
|
try {
|
||||||
|
Nami::login(12345, 'secret');
|
||||||
} catch (LoginException $e) {
|
} catch (LoginException $e) {
|
||||||
$this->assertEquals(LoginException::TOO_MANY_FAILED_LOGINS, $e->reason);
|
$this->assertEquals(LoginException::TOO_MANY_FAILED_LOGINS, $e->reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_login_once_on_second_login()
|
public function test_store_cookie_after_login(): void
|
||||||
{
|
{
|
||||||
Http::fake([
|
Http::fake($this->fakeSuccessfulLogin());
|
||||||
'https://nami.dpsg.de/ica/pages/login.jsp' => Http::response('<html></html>', 200),
|
|
||||||
'https://nami.dpsg.de/ica/rest/nami/auth/manual/sessionStartup' => Http::response($this->successJson, 200)
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->setCredentials();
|
Nami::login(12345, 'secret');
|
||||||
|
|
||||||
Nami::login();
|
$this->assertFileExists(__DIR__.'/../../.cookies/'.time().'.txt');
|
||||||
Nami::login();
|
}
|
||||||
|
|
||||||
|
public function test_dont_login_if_cookie_exists(): void
|
||||||
|
{
|
||||||
|
touch(__DIR__.'/../../.cookies/'.time().'.txt');
|
||||||
|
|
||||||
|
Nami::login(12345, 'secret');
|
||||||
|
|
||||||
|
Http::assertSentCount(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_delete_expired_cookie_before_login(): void
|
||||||
|
{
|
||||||
|
$lastLogin = now()->subHour(2)->timestamp;
|
||||||
|
touch(__DIR__."/../../.cookies/{$lastLogin}.txt");
|
||||||
|
Http::fake($this->fakeSuccessfulLogin());
|
||||||
|
|
||||||
|
Nami::login(12345, 'secret');
|
||||||
|
|
||||||
|
Http::assertSentCount(2);
|
||||||
|
$this->assertFileDoesNotExist(__DIR__."/../../.cookies/{$lastLogin}.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_login_once_if_cookie_is_expired(): void
|
||||||
|
{
|
||||||
|
$lastLogin = now()->subHour()->subMinutes(10)->timestamp;
|
||||||
|
touch(__DIR__."/../../.cookies/{$lastLogin}.txt");
|
||||||
|
Http::fake($this->fakeSuccessfulLogin());
|
||||||
|
|
||||||
|
Nami::login(12345, 'secret');
|
||||||
|
Nami::login(12345, 'secret');
|
||||||
|
|
||||||
Http::assertSent(function($request) {
|
|
||||||
return $request->url() == 'https://nami.dpsg.de/ica/pages/login.jsp';
|
|
||||||
});
|
|
||||||
Http::assertSent(function($request) {
|
|
||||||
return $request->url() == 'https://nami.dpsg.de/ica/rest/nami/auth/manual/sessionStartup'
|
|
||||||
&& $request['username'] == '11223' && $request['password'] == 'secret' && $request['redirectTo'] == './app.jsp' && $request['Login'] == 'API';
|
|
||||||
});
|
|
||||||
Http::assertSentCount(2);
|
Http::assertSentCount(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_login_check()
|
private function fakeSuccessfulLogin(): array
|
||||||
{
|
{
|
||||||
Http::fake([
|
return [
|
||||||
'https://nami.dpsg.de/ica/pages/login.jsp' => Http::response('<html></html>', 200),
|
'https://nami.dpsg.de/ica/pages/login.jsp' => Http::sequence()->push('<html></html>', 200),
|
||||||
|
'https://nami.dpsg.de/ica/rest/nami/auth/manual/sessionStartup' => Http::sequence()->push($this->successJson, 200),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function fakeFailedLogin(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'https://nami.dpsg.de/ica/pages/login.jsp' => Http::sequence()->push('<html></html>', 200),
|
||||||
'https://nami.dpsg.de/ica/rest/nami/auth/manual/sessionStartup' => Http::sequence()->push($this->wrongCredentialsJson, 200)
|
'https://nami.dpsg.de/ica/rest/nami/auth/manual/sessionStartup' => Http::sequence()->push($this->wrongCredentialsJson, 200)
|
||||||
]);
|
];
|
||||||
|
|
||||||
$this->setCredentials();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Nami::login();
|
|
||||||
} catch(LoginException $e) {
|
|
||||||
$this->assertEquals(LoginException::WRONG_CREDENTIALS, $e->reason);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Http::assertSentCount(2);
|
private function fakeBruteforceFailure(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'https://nami.dpsg.de/ica/pages/login.jsp' => Http::sequence()->push('<html></html>', 200),
|
||||||
|
'https://nami.dpsg.de/ica/rest/nami/auth/manual/sessionStartup' => Http::sequence()->push($this->bruteJson, 200)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue