Started methods implementation, added login and check auth state methods. Added project license.
parent
c6f0c7d8f7
commit
058bbfbc03
|
@ -1,3 +1,4 @@
|
|||
.idea
|
||||
vendor/
|
||||
composer.lock
|
||||
composer.lock
|
||||
tests/
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2022 Bohdan Konkevych
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -5,9 +5,13 @@
|
|||
"homepage": "http://git.devbones.com/Toloka/php-api",
|
||||
"require": {
|
||||
"php": ">=7.4",
|
||||
"psr/simple-cache": "^3.0",
|
||||
"psr/log": "^3.0",
|
||||
"psr/http-client": "^1.0"
|
||||
"psr/http-client": "^1.0",
|
||||
"psr/simple-cache": "^1.0",
|
||||
"psr/log": "^1.0",
|
||||
"symfony/dom-crawler": "^5.4",
|
||||
"symfony/css-selector": "^5.4",
|
||||
"dflydev/fig-cookies": "^3.0",
|
||||
"symfony/polyfill-php80": "^1.26"
|
||||
},
|
||||
"license": "MIT",
|
||||
"autoload": {
|
||||
|
@ -22,6 +26,9 @@
|
|||
}
|
||||
],
|
||||
"require-dev": {
|
||||
"guzzlehttp/guzzle": "^7.5"
|
||||
"cache/array-adapter": "^1.2",
|
||||
"guzzlehttp/guzzle": "^7.5",
|
||||
"monolog/monolog": "^2.8",
|
||||
"cache/filesystem-adapter": "^1.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,24 @@
|
|||
|
||||
namespace Toloka\PhpApi;
|
||||
|
||||
use Dflydev\FigCookies\Cookie;
|
||||
use Dflydev\FigCookies\Cookies;
|
||||
use Dflydev\FigCookies\FigRequestCookies;
|
||||
use Dflydev\FigCookies\SetCookies;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use Psr\Http\Client\ClientInterface as HttpClientInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use GuzzleHttp\Psr7\Utils;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
use Toloka\PhpApi\Exception\Auth\AuthException;
|
||||
use Toloka\PhpApi\Exception\Auth\InvalidAuthCredentials;
|
||||
|
||||
class Client implements ClientInterface {
|
||||
|
||||
const CACHE_KEY_COOKIES = 'cookies';
|
||||
|
||||
/**
|
||||
* Hurtom Toloka base url.
|
||||
*
|
||||
|
@ -36,6 +48,11 @@ class Client implements ClientInterface {
|
|||
*/
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
/**
|
||||
* @var Cookies
|
||||
*/
|
||||
protected ?Cookies $cookies = NULL;
|
||||
|
||||
/**
|
||||
* Toloka client constructor.
|
||||
*
|
||||
|
@ -44,14 +61,22 @@ class Client implements ClientInterface {
|
|||
* @param LoggerInterface|NULL $logger
|
||||
*/
|
||||
public function __construct(
|
||||
string $base_url = 'https://toloka.to',
|
||||
string $base_url,
|
||||
HttpClientInterface $httpClient,
|
||||
CacheInterface $cache,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->base_url = $base_url;
|
||||
$this->httpClient = $httpClient;
|
||||
$this->cache = $cache;
|
||||
$this->logger = $logger;
|
||||
|
||||
if ($cache->has(self::CACHE_KEY_COOKIES)) {
|
||||
$persistent_cookies = $cache->get(self::CACHE_KEY_COOKIES);
|
||||
if ($persistent_cookies instanceof Cookies) {
|
||||
$this->cookies = $persistent_cookies;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,14 +90,79 @@ class Client implements ClientInterface {
|
|||
* {@inheritDoc}
|
||||
*/
|
||||
public function login(string $login, string $password): void {
|
||||
// TODO: Implement login() method.
|
||||
if ($this->isLoggedIn()) {
|
||||
return;
|
||||
}
|
||||
$body = http_build_query([
|
||||
'username' => $login,
|
||||
'password' => $password,
|
||||
'autologin' => 'on',
|
||||
'ssl' => 'on',
|
||||
'redirect' => '',
|
||||
'login' => 'Вхід',
|
||||
]);
|
||||
$request = new Request('POST', $this->getBaseUrl() . '/login.php', [
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
], Utils::streamFor($body));
|
||||
$response = $this->httpClient->sendRequest($request);
|
||||
if ($response->getStatusCode() === 302) {
|
||||
// If redirected - this means successful login, can save cookies.
|
||||
$cookies = SetCookies::fromResponse($response);
|
||||
$this->saveCookies($cookies);
|
||||
}
|
||||
elseif ($response->getStatusCode() === 200) {
|
||||
// In case of returned page - try to find an error and throw exception.
|
||||
$crawler = new Crawler($response->getBody()->getContents());
|
||||
$text = $crawler->filter('.forumline .row1 span.gen')->text(NULL, TRUE);
|
||||
if (str_contains($text, 'Такий псевдонім не існує, або не збігається пароль.')) {
|
||||
throw new InvalidAuthCredentials();
|
||||
}
|
||||
}
|
||||
throw new AuthException();
|
||||
}
|
||||
|
||||
private function saveCookies($data) {
|
||||
if ($data instanceof SetCookies) {
|
||||
$cookies = [];
|
||||
foreach ($data->getAll() as $cookie) {
|
||||
$cookies[] = Cookie::create($cookie->getName(), $cookie->getValue());
|
||||
}
|
||||
$this->cookies = new Cookies($cookies);
|
||||
}
|
||||
elseif ($data instanceof Cookies) {
|
||||
$this->cookies = $data;
|
||||
}
|
||||
$this->cache->set(self::CACHE_KEY_COOKIES, $this->cookies);
|
||||
}
|
||||
|
||||
private function applyRequestCookies(RequestInterface $request): RequestInterface {
|
||||
if (!$this->cookies) {
|
||||
return $request;
|
||||
}
|
||||
foreach ($this->cookies->getAll() as $cookie) {
|
||||
$request = FigRequestCookies::set($request, $cookie);
|
||||
}
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isLoggedIn(): bool {
|
||||
// TODO: Implement isLoggedIn() method.
|
||||
$request = new Request('GET', $this->getBaseUrl());
|
||||
$request = $this->applyRequestCookies($request);
|
||||
$response = $this->httpClient->sendRequest($request);
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$crawler = new Crawler($response->getBody()->getContents());
|
||||
$menu_links = $crawler->filter('table.navie6fix a');
|
||||
foreach ($menu_links as $menu_link) {
|
||||
// If there is a link to profile, then we authorized.
|
||||
if ($menu_link->textContent === 'Профіль') {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,7 +176,7 @@ class Client implements ClientInterface {
|
|||
* {@inheritDoc}
|
||||
*/
|
||||
public function getTopic(int $id): TopicInterface {
|
||||
// TODO: Implement getTopic() method.
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ interface ClientInterface {
|
|||
* Check if user logged in.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws \Psr\Http\Client\ClientExceptionInterface
|
||||
*/
|
||||
public function isLoggedIn(): bool;
|
||||
|
||||
|
@ -48,6 +50,8 @@ interface ClientInterface {
|
|||
*
|
||||
* @return TopicInterface
|
||||
* Object with populated topic data.
|
||||
*
|
||||
* @throws \Psr\Http\Client\ClientExceptionInterface
|
||||
*/
|
||||
public function getTopic(int $id): TopicInterface;
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
namespace Toloka\PhpApi\Exception\Auth;
|
||||
|
||||
class AuthException extends \Exception {}
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace Toloka\PhpApi\Exception\Auth;
|
||||
|
||||
use Toloka\PhpApi\Exception\AuthException;
|
||||
|
||||
class InvalidAuthCredentials extends AuthException {
|
||||
|
||||
protected $message = 'Failed to login using given credentials.';
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace Toloka\PhpApi\Exception\Auth;
|
||||
|
||||
use Toloka\PhpApi\Exception\AuthException;
|
||||
|
||||
class TooManyLoginAttempts extends AuthException {
|
||||
|
||||
protected $message = 'Too many login attempts performed. Try again later.';
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Toloka\PhpApi\Exception;
|
||||
|
||||
abstract class AuthException extends \Exception {}
|
Loading…
Reference in New Issue