* strict type fixes

* news action added
This commit is contained in:
Danyi Dávid 2018-07-26 09:02:48 +02:00
parent 22fe49d4ca
commit 6fa6c1ae89
8 changed files with 405 additions and 10 deletions

View File

@ -39,4 +39,6 @@ return function (Application $app, MiddlewareFactory $factory, ContainerInterfac
$app->get('/api/activity[/{id:\d+}]', App\Action\ActivityAction::class, 'api.activity.get'); $app->get('/api/activity[/{id:\d+}]', App\Action\ActivityAction::class, 'api.activity.get');
$app->get('/api/activity/signup/{id:\d+}', App\Action\ActivitySignupAction::class, 'api.activity.signup'); $app->get('/api/activity/signup/{id:\d+}', App\Action\ActivitySignupAction::class, 'api.activity.signup');
$app->get('/api/activity/signoff/{id:\d+}', App\Action\ActivitySignoffAction::class, 'api.activity.signoff'); $app->get('/api/activity/signoff/{id:\d+}', App\Action\ActivitySignoffAction::class, 'api.activity.signoff');
$app->get('/api/news[/{id:\d+}]', App\Action\NewsAction::class, 'api.news.get');
}; };

View File

@ -9,6 +9,8 @@ set('ssh_multiplexing', true);
set('repository', 'ssh://gogs@gogs.ragnarok.yvan.hu:2206/yvan/skies-api.git'); set('repository', 'ssh://gogs@gogs.ragnarok.yvan.hu:2206/yvan/skies-api.git');
set('shared_dirs', [ set('shared_dirs', [
'data/tmp', 'data/tmp',
'data/logs',
'data/cache',
]); ]);
set('shared_files', [ set('shared_files', [
// 'config/autoload/doctrine.local.php', // 'config/autoload/doctrine.local.php',
@ -22,7 +24,7 @@ host('alfheim.ragnarok.yvan.hu')
->stage('production') ->stage('production')
->user('yvan') ->user('yvan')
->forwardAgent() ->forwardAgent()
->set('php_service_name', 'php7.1-fpm') ->set('php_service_name', 'php7.2-fpm')
->set('deploy_path', '/mnt/apps/skies-proxy-api'); ->set('deploy_path', '/mnt/apps/skies-proxy-api');
desc('Restart PHP-FPM service'); desc('Restart PHP-FPM service');

View File

@ -40,7 +40,7 @@ class ActivityAction extends AbstractAction
*/ */
public function get(ServerRequestInterface $request) : ResponseInterface public function get(ServerRequestInterface $request) : ResponseInterface
{ {
$id = $request->getAttribute(self::IDENTIFIER_NAME); $id = (int)$request->getAttribute(self::IDENTIFIER_NAME);
$authHeader = $request->getHeaderLine("x-passthru-auth"); $authHeader = $request->getHeaderLine("x-passthru-auth");
return new JsonResponse($this->skiesClient->setAuthHeader($authHeader)->getActivity($id)); return new JsonResponse($this->skiesClient->setAuthHeader($authHeader)->getActivity($id));
} }

View File

@ -27,7 +27,7 @@ class ActivitySignoffAction implements RequestHandlerInterface
*/ */
public function handle(ServerRequestInterface $request) : ResponseInterface public function handle(ServerRequestInterface $request) : ResponseInterface
{ {
$authHeader = $request->getHeaderLine("x-passthru-auth"); $authHeader = (int)$request->getHeaderLine("x-passthru-auth");
$id = $request->getAttribute("id"); $id = $request->getAttribute("id");
return new JsonResponse($this->skiesClient->setAuthHeader($authHeader)->signOffActivity($id)); return new JsonResponse($this->skiesClient->setAuthHeader($authHeader)->signOffActivity($id));
} }

View File

@ -27,7 +27,7 @@ class ActivitySignupAction implements RequestHandlerInterface
*/ */
public function handle(ServerRequestInterface $request) : ResponseInterface public function handle(ServerRequestInterface $request) : ResponseInterface
{ {
$authHeader = $request->getHeaderLine("x-passthru-auth"); $authHeader = (int)$request->getHeaderLine("x-passthru-auth");
$id = $request->getAttribute("id"); $id = $request->getAttribute("id");
return new JsonResponse($this->skiesClient->setAuthHeader($authHeader)->signUpActivity($id)); return new JsonResponse($this->skiesClient->setAuthHeader($authHeader)->signUpActivity($id));
} }

View File

@ -3,8 +3,12 @@
namespace App\Action; namespace App\Action;
use App\Service\SkiesClientService; use App\Service\SkiesClientService;
use GuzzleHttp\Exception\GuzzleException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Diactoros\Response\JsonResponse;
class NewsAction class NewsAction extends AbstractAction
{ {
/** /**
* @var SkiesClientService * @var SkiesClientService
@ -15,4 +19,27 @@ class NewsAction
{ {
$this->skiesClient = $skiesClient; $this->skiesClient = $skiesClient;
} }
/**
* @param ServerRequestInterface $request
* @return ResponseInterface
* @throws GuzzleException
*/
public function getList(ServerRequestInterface $request) : ResponseInterface
{
$authHeader = $request->getHeaderLine("x-passthru-auth");
return new JsonResponse($this->skiesClient->setAuthHeader($authHeader)->getNews());
}
/**
* @param ServerRequestInterface $request
* @return ResponseInterface
* @throws GuzzleException
*/
public function get(ServerRequestInterface $request) : ResponseInterface
{
$id = (int)$request->getAttribute(self::IDENTIFIER_NAME);
$authHeader = $request->getHeaderLine("x-passthru-auth");
return new JsonResponse($this->skiesClient->setAuthHeader($authHeader)->getNewsItem($id), 200, [], 0);
}
} }

View File

@ -2,7 +2,211 @@
namespace App\Entity; namespace App\Entity;
class News use Doctrine\Common\Collections\ArrayCollection;
{
class News implements \JsonSerializable
{
/**
* @var int
*/
private $id;
/**
* @var string
*/
private $name;
/**
* @var \DateTime
*/
private $date;
/**
* @var string
*/
private $description;
/**
* @var \DateTime
*/
private $finalEntry;
/**
* @var string
*/
private $accountable;
/**
* @var ArrayCollection|Comment[]
*/
private $comments;
public function __construct()
{
$this->comments = new ArrayCollection();
}
/**
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* @param int $id
* @return News
*/
public function setId(int $id): News
{
$this->id = $id;
return $this;
}
/**
* @return string
*/
public function getName(): ?string
{
return $this->name;
}
/**
* @param string $name
* @return News
*/
public function setName(?string $name): News
{
$this->name = $name;
return $this;
}
/**
* @return \DateTime
*/
public function getDate(): ?\DateTime
{
return $this->date;
}
/**
* @param \DateTime $date
* @return News
*/
public function setDate(?\DateTime $date): News
{
$this->date = $date;
return $this;
}
/**
* @return string
*/
public function getDescription(): ?string
{
return $this->description;
}
/**
* @param string $description
* @return News
*/
public function setDescription(?string $description): News
{
$this->description = $description;
return $this;
}
/**
* @return \DateTime
*/
public function getFinalEntry(): ?\DateTime
{
return $this->finalEntry;
}
/**
* @param \DateTime $finalEntry
* @return News
*/
public function setFinalEntry(\DateTime $finalEntry): News
{
$this->finalEntry = $finalEntry;
return $this;
}
/**
* @return string
*/
public function getAccountable(): ?string
{
return $this->accountable;
}
/**
* @param string $accountable
* @return News
*/
public function setAccountable(string $accountable): News
{
$this->accountable = $accountable;
return $this;
}
/**
* @return Comment[]|ArrayCollection
*/
public function getComments()
{
return $this->comments;
}
/**
* @param Comment[]|ArrayCollection $comments
* @return News
*/
public function setComments($comments): News
{
$this->comments = $comments;
return $this;
}
/**
* @param Comment $comment
* @return News
*/
public function addComment(Comment $comment): News
{
if (!$this->comments->contains($comment)) {
$this->comments->add($comment);
}
return $this;
}
/**
* @param Comment $comment
* @return News
*/
public function removeComment(Comment $comment): News
{
if ($this->comments->contains($comment)) {
$this->comments->removeElement($comment);
}
return $this;
}
public function jsonSerialize()
{
return [
'id' => $this->getId(),
'name' => $this->getName(),
'date' => $this->getDate()
? $this->getDate()->format("Y-m-d H:i:s")
: null,
'description' => $this->getDescription(),
'accountable' => $this->getAccountable(),
'comments' => $this->getComments()->getValues(),
];
}
} }

View File

@ -4,6 +4,7 @@ namespace App\Service;
use App\Entity\Activity; use App\Entity\Activity;
use App\Entity\Comment; use App\Entity\Comment;
use App\Entity\News;
use App\Entity\User; use App\Entity\User;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJarInterface; use GuzzleHttp\Cookie\CookieJarInterface;
@ -25,6 +26,7 @@ class SkiesClientService
const SKIES_ACTIVITY_URL = "https://skies.sigmatechnology.se/main.asp?rID=2&alt=1&aktID=%s"; const SKIES_ACTIVITY_URL = "https://skies.sigmatechnology.se/main.asp?rID=2&alt=1&aktID=%s";
const SKIES_ACTIVITY_SIGNUP_URL = "https://skies.sigmatechnology.se/main.asp?rID=2&alt=1&aktID=%s&doJoin=1"; const SKIES_ACTIVITY_SIGNUP_URL = "https://skies.sigmatechnology.se/main.asp?rID=2&alt=1&aktID=%s&doJoin=1";
const SKIES_ACTIVITY_SIGNOFF_URL = "https://skies.sigmatechnology.se/main.asp?rID=2&alt=1&aktID=%s&doCancel=1&user=%s"; const SKIES_ACTIVITY_SIGNOFF_URL = "https://skies.sigmatechnology.se/main.asp?rID=2&alt=1&aktID=%s&doCancel=1&user=%s";
const SKIES_NEWS_URL = "https://skies.sigmatechnology.se/main.asp?rID=200&coreID=%s";
/** @var Client */ /** @var Client */
private $client; private $client;
@ -90,13 +92,16 @@ class SkiesClientService
*/ */
public function setAuthHeader(string $authHeader): SkiesClientService public function setAuthHeader(string $authHeader): SkiesClientService
{ {
if ($authHeader == '') {
throw new \InvalidArgumentException("Empty auth header", 500);
}
list($this->authUser, $this->authPass) = explode(':', base64_decode($authHeader)); list($this->authUser, $this->authPass) = explode(':', base64_decode($authHeader));
$this->cookieJar = new FileCookieJar("data/cache/".$this->authUser, true); $this->cookieJar = new FileCookieJar("data/cache/".$this->authUser, true);
return $this; return $this;
} }
/** /**
* @return bool * @return News[]
* @throws \GuzzleHttp\Exception\GuzzleException * @throws \GuzzleHttp\Exception\GuzzleException
*/ */
public function getNews() public function getNews()
@ -389,9 +394,161 @@ class SkiesClientService
return $formNodes->count() == 1; return $formNodes->count() == 1;
} }
/**
* @param string $htmlBody
* @return News[]
* @throws \GuzzleHttp\Exception\GuzzleException
*/
private function parseMainPage(string $htmlBody) private function parseMainPage(string $htmlBody)
{ {
return false; $domDocument = new Document($htmlBody);
$newsNodes = Document\Query::execute(
"div.container div.row div.box div.one_block > a",
$domDocument,
Document\Query::TYPE_CSS
);
$news = [];
for ($i = 1; $i < $newsNodes->count(); $i++) {
$href = $newsNodes[$i]->attributes->getNamedItem("href")->textContent;
$queryString = parse_url($href, PHP_URL_QUERY);
parse_str($queryString, $queryParams);
if ($queryParams['rID'] == 200 && isset($queryParams['coreID'])) {
$news[] = $this->getNewsItem($queryParams["coreID"]);
}
}
return $news;
}
/**
* @param int $id
* @return News
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function getNewsItem(int $id): News
{
$response = $this->doSkiesRequest('GET', sprintf(self::SKIES_NEWS_URL, $id));
$htmlBody = $response->getBody();
return $this->parseNewsPage($htmlBody, $id);
}
/**
* @param string $htmlBody
* @param int $id
* @return News
*/
private function parseNewsPage(string $htmlBody, int $id): News
{
$domDocument = new Document($htmlBody);
/** News body */
$activityNode = Document\Query::execute(
"div.col-md-10 div.box",
$domDocument,
Document\Query::TYPE_CSS
);
/** News name */
$h5Nodes = Document\Query::execute(
"./h5",
$domDocument,
Document\Query::TYPE_XPATH,
$activityNode[0]
);
/** Creator */
$aNodes = Document\Query::execute(
"./a",
$domDocument,
Document\Query::TYPE_XPATH,
$activityNode[0]
);
$textNodes = Document\Query::execute(
"./a/following::text()",
$domDocument,
Document\Query::TYPE_XPATH,
$activityNode[0]
);
preg_match("#\(Published: ([0-9]{4}-[0-9]{2}-[0-9]{2})\)#msi", $this->clearTextNode($textNodes[0]->textContent), $matches);
$contentDivNodes = Document\Query::execute(
'.//div[@class="row"]/div[@class="col-md-12"]',
$domDocument,
Document\Query::TYPE_XPATH,
$activityNode[0]
);
/** Comment block */
$commentNodes = Document\Query::execute(
'.//div[@class="onecomment"]',
$domDocument,
Document\Query::TYPE_XPATH,
$activityNode[0]
);
$news = new News();
$news->setId($id)
->setName($this->clearTextNode($h5Nodes[0]->textContent))
->setDescription($this->parseNewsDescription($contentDivNodes[0]))
->setDate(isset($matches[1]) ? new \DateTime($matches[1]) : null)
->setAccountable($this->clearTextNode($aNodes[0]->textContent));
// $this->parseNewsComments($commentNodes, $news);
return $news;
}
/**
* @param \DOMNode $element
* @return null|string
*/
private function parseNewsDescription(\DOMNode $element): ?string
{
$description = "";
/** @var \DOMElement $childNode */
foreach ($element->childNodes as $childNode) {
$description .= $childNode->nodeName == "br"
? "\n"
: rtrim($childNode->textContent);
}
return $this->clearTextNode($description);
}
/**
* @param Document\NodeList $commentElements
* @param News $news
*/
private function parseNewsComments(Document\NodeList $commentElements, News $news)
{
/** @var \DOMElement $commentElement */
foreach ($commentElements as $commentElement) {
$divElements = $commentElement->getElementsByTagName("div");
$queryString = parse_url(
$commentElement->getElementsByTagName("a")->item(0)->getAttribute("href"),
PHP_URL_QUERY
);
parse_str($queryString, $queryParams);
preg_match(
"#(.*)\s/\s([0-9]{4}-[0-9]{2}-[0-9]{2})\s([0-9]{1,2}:[0-9]{1,2})#msi",
str_replace(" ", " ", $divElements->item(2)->textContent),
$matches
);
$user = new User();
$user->setDisplayName($matches[1])
->setUsername($queryParams['username']);
$comment = new Comment();
$comment
->setText($divElements->item(1)->textContent)
->setUser($user)
->setCreatedAt(new \DateTime(sprintf(
"%s %s",
$matches[2],
$matches[3]
)));
$news->addComment($comment);
}
} }
/** /**
@ -421,10 +578,13 @@ class SkiesClientService
*/ */
private function clearTextNode(string $text): string private function clearTextNode(string $text): string
{ {
$text = str_replace("\r", "", $text);
$text = str_replace(" ", " ", $text); $text = str_replace(" ", " ", $text);
$text = str_replace("–", "-", $text); $text = str_replace("–", "-", $text);
// $text = str_replace(chr(0xC2).chr(0x95), "-", $text);
$text = str_replace([chr(0xC2).chr(0x93), chr(0xC2).chr(0x94)], '"', $text);
$text = preg_replace("#[ \t]+#msiu", " ", $text); $text = preg_replace("#[ \t]+#msiu", " ", $text);
return trim($text, " \t\n\r\0\x0B" . chr(0xC2) . chr(0xA0)); return trim($text, " \t\n\r\0\x0B " . chr(0xC2) . chr(0xA0));
} }
/** /**