1
0
Fork 0
mirror of https://codeberg.org/demostf/api.git synced 2026-06-03 18:04:08 +02:00
This commit is contained in:
Robin Appelman 2019-04-12 14:00:20 +02:00
commit 73469d2aa1
29 changed files with 140 additions and 149 deletions

View file

@ -35,7 +35,7 @@ before_script:
- echo "error_reporting = E_ALL & ~E_DEPRECATED" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini #random-lib complains about mcrypt - echo "error_reporting = E_ALL & ~E_DEPRECATED" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini #random-lib complains about mcrypt
script: script:
- phpunit --coverage-clover coverage.xml --configuration test/phpunit.xml - vendor/bin/phpunit --coverage-clover coverage.xml --configuration test/phpunit.xml
- IFS=$'\n'; COMMIT_SCA_FILES=($(git diff --name-only --diff-filter=ACMRTUXB "${$TRAVIS_COMMIT_RANGE}")); unset IFS - IFS=$'\n'; COMMIT_SCA_FILES=($(git diff --name-only --diff-filter=ACMRTUXB "${$TRAVIS_COMMIT_RANGE}")); unset IFS
- vendor/bin/php-cs-fixer fix --config=.php_cs.dist -v --dry-run --allow-risky yes --stop-on-violation --using-cache=no --path-mode=intersection -- "${COMMIT_SCA_FILES[@]}" - vendor/bin/php-cs-fixer fix --config=.php_cs.dist -v --dry-run --allow-risky yes --stop-on-violation --using-cache=no --path-mode=intersection -- "${COMMIT_SCA_FILES[@]}"
- phpenv config-rm xdebug.ini - phpenv config-rm xdebug.ini

View file

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Demostf\API; namespace Demostf\API;
use Demostf\API\Controllers\TempController;
use Demostf\API\Demo\DemoSaver; use Demostf\API\Demo\DemoSaver;
use Demostf\API\Demo\DemoStore; use Demostf\API\Demo\DemoStore;
use Demostf\API\Demo\HeaderParser; use Demostf\API\Demo\HeaderParser;
@ -92,7 +91,7 @@ class Container {
} }
public function getRawParser(): RawParser { public function getRawParser(): RawParser {
return new RawParser($this->getParserPath(), new TempController($this->getApiRoot() . '/temp/')); return new RawParser($this->getParserPath());
} }
public function getUploadProvider(): UploadProvider { public function getUploadProvider(): UploadProvider {

View file

@ -7,8 +7,10 @@ namespace Demostf\API\Controllers;
use Ehesp\SteamLogin\SteamLogin; use Ehesp\SteamLogin\SteamLogin;
use Demostf\API\Providers\AuthProvider; use Demostf\API\Providers\AuthProvider;
use Demostf\API\Providers\UserProvider; use Demostf\API\Providers\UserProvider;
use Flight;
use flight\net\Request; use flight\net\Request;
use flight\net\Response; use flight\net\Response;
use SteamId;
class AuthController extends BaseController { class AuthController extends BaseController {
/** /**
@ -47,7 +49,7 @@ class AuthController extends BaseController {
public function get($token) { public function get($token) {
$userData = $this->authProvider->getUser($token); $userData = $this->authProvider->getUser($token);
\Flight::json([ Flight::json([
'token' => $token, 'token' => $token,
'steamid' => $userData['steamid'], 'steamid' => $userData['steamid'],
'name' => $userData['name'], 'name' => $userData['name'],
@ -59,12 +61,12 @@ class AuthController extends BaseController {
$_SESSION['return'] = $this->query('return', 'https://' . $this->host); $_SESSION['return'] = $this->query('return', 'https://' . $this->host);
$steam = new SteamLogin(); $steam = new SteamLogin();
$url = $steam->url($this->apiRoot . '/auth/handle/' . urlencode($token), $this->apiRoot); $url = $steam->url($this->apiRoot . '/auth/handle/' . urlencode($token), $this->apiRoot);
\Flight::redirect(str_replace('&', '&', $url)); // headers make no sense Flight::redirect(str_replace('&', '&', $url)); // headers make no sense
} }
public function logout($token) { public function logout($token) {
$this->authProvider->logout($token); $this->authProvider->logout($token);
\Flight::json([ Flight::json([
'token' => $token, 'token' => $token,
'steamid' => null, 'steamid' => null,
'name' => null, 'name' => null,
@ -78,10 +80,10 @@ class AuthController extends BaseController {
$steam = new SteamLogin(); $steam = new SteamLogin();
$steamId = $steam->validate(); $steamId = $steam->validate();
if ($steamId) { if ($steamId) {
$steamIdObject = new \SteamId($steamId); $steamIdObject = new SteamId($steamId);
$key = $this->userProvider->store($steamIdObject); $key = $this->userProvider->store($steamIdObject);
$this->authProvider->setUser($token, $steamIdObject, $key); $this->authProvider->setUser($token, $steamIdObject, $key);
} }
\Flight::redirect($return); Flight::redirect($return);
} }
} }

View file

@ -10,6 +10,9 @@ use Demostf\API\Providers\DemoListProvider;
use Demostf\API\Providers\DemoProvider; use Demostf\API\Providers\DemoProvider;
use flight\net\Request; use flight\net\Request;
use flight\net\Response; use flight\net\Response;
use function intval;
use InvalidArgumentException;
use function is_array;
class DemoController extends BaseController { class DemoController extends BaseController {
/** @var DemoProvider */ /** @var DemoProvider */
@ -45,7 +48,7 @@ class DemoController extends BaseController {
* @param string $id * @param string $id
*/ */
public function get($id) { public function get($id) {
$this->json($this->demoProvider->get(\intval($id, 10))); $this->json($this->demoProvider->get(intval($id, 10)));
} }
protected function getFilter() { protected function getFilter() {
@ -61,7 +64,7 @@ class DemoController extends BaseController {
$filter['backend'] = $backend; $filter['backend'] = $backend;
} }
if ($players) { if ($players) {
if (!\is_array($players)) { if (!is_array($players)) {
$players = explode(',', $players); $players = explode(',', $players);
} }
$players = array_filter($players); $players = array_filter($players);
@ -123,7 +126,7 @@ class DemoController extends BaseController {
$url = (string) $this->post('url', ''); $url = (string) $this->post('url', '');
$editKey = (string) $this->post('key', ''); $editKey = (string) $this->post('key', '');
if ($editKey !== $this->editKey || '' === $editKey) { if ($editKey !== $this->editKey || '' === $editKey) {
throw new \InvalidArgumentException('Invalid key'); throw new InvalidArgumentException('Invalid key');
} }
$demo = $this->demoProvider->get((int) $id); $demo = $this->demoProvider->get((int) $id);
@ -135,7 +138,7 @@ class DemoController extends BaseController {
$this->store->remove($demo); $this->store->remove($demo);
} }
} else { } else {
throw new \InvalidArgumentException('Invalid demo hash'); throw new InvalidArgumentException('Invalid demo hash');
} }
} }
} }

View file

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Demostf\API\Controllers; namespace Demostf\API\Controllers;
use Demostf\API\Providers\InfoProvider; use Demostf\API\Providers\InfoProvider;
use Flight;
use flight\net\Request; use flight\net\Request;
use flight\net\Response; use flight\net\Response;
@ -18,10 +19,10 @@ class InfoController extends BaseController {
} }
public function listMaps() { public function listMaps() {
\Flight::json($this->infoProvider->listMaps()); Flight::json($this->infoProvider->listMaps());
} }
public function stats() { public function stats() {
\Flight::json($this->infoProvider->getStats()); Flight::json($this->infoProvider->getStats());
} }
} }

View file

@ -1,53 +0,0 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Demostf\API\Controllers;
class TempController extends BaseController {
private $webRoot;
public function __construct(string $webRoot) {
$this->webRoot = $webRoot;
}
public function register(string $key, string $path): string {
apcu_store($key, $path);
return $this->webRoot . $key;
}
public function unregister(string $key) {
apcu_dec($key);
}
public function serve(string $key) {
$path = apcu_fetch($key);
if ($path) {
$handle = fopen($path, 'r');
fpassthru($handle);
fclose($handle);
} else {
\Flight::response()
->status(404)
->send();
}
}
}

View file

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace Demostf\API\Controllers; namespace Demostf\API\Controllers;
use Demostf\API\Providers\UploadProvider; use Demostf\API\Providers\UploadProvider;
use Exception;
use Flight;
use flight\net\Request; use flight\net\Request;
use flight\net\Response; use flight\net\Response;
@ -32,12 +34,12 @@ class UploadController extends BaseController {
try { try {
$result = $this->uploadProvider->upload($key, $red, $blu, $name, $demoFile); $result = $this->uploadProvider->upload($key, $red, $blu, $name, $demoFile);
if ('Invalid key' === $result) { if ('Invalid key' === $result) {
\Flight::response()->status(401)->write($result)->send(); Flight::response()->status(401)->write($result)->send();
} else { } else {
echo $result; echo $result;
} }
} catch (\Exception $e) { } catch (Exception $e) {
\Flight::response() Flight::response()
->status(500) ->status(500)
->write($e->getMessage()) ->write($e->getMessage())
->send(); ->send();

View file

@ -6,8 +6,10 @@ namespace Demostf\API\Controllers;
use Demostf\API\Demo\Parser; use Demostf\API\Demo\Parser;
use Demostf\API\Providers\UserProvider; use Demostf\API\Providers\UserProvider;
use Flight;
use flight\net\Request; use flight\net\Request;
use flight\net\Response; use flight\net\Response;
use InvalidArgumentException;
class UserController extends BaseController { class UserController extends BaseController {
/** /**
@ -24,14 +26,14 @@ class UserController extends BaseController {
if (!is_numeric($steamId)) { if (!is_numeric($steamId)) {
try { try {
$steamId = Parser::convertSteamIdToCommunityId($steamId); $steamId = Parser::convertSteamIdToCommunityId($steamId);
} catch (\InvalidArgumentException $e) { } catch (InvalidArgumentException $e) {
} }
} }
\Flight::json($this->userProvider->get($steamId)); Flight::json($this->userProvider->get($steamId));
} }
public function search() { public function search() {
$query = $this->query('query', ''); $query = $this->query('query', '');
\Flight::json($this->userProvider->search($query)); Flight::json($this->userProvider->search($query));
} }
} }

View file

@ -4,7 +4,9 @@ declare(strict_types=1);
namespace Demostf\API\Data; namespace Demostf\API\Data;
class DemoPlayer implements \JsonSerializable { use JsonSerializable;
class DemoPlayer implements JsonSerializable {
/** @var int */ /** @var int */
private $id; private $id;
/** @var int */ /** @var int */

View file

@ -4,7 +4,9 @@ declare(strict_types=1);
namespace Demostf\API\Data; namespace Demostf\API\Data;
class SteamUser implements \JsonSerializable { use JsonSerializable;
class SteamUser implements JsonSerializable {
/** @var int */ /** @var int */
private $id; private $id;
/** @var string */ /** @var string */

View file

@ -4,7 +4,9 @@ declare(strict_types=1);
namespace Demostf\API\Data; namespace Demostf\API\Data;
class User implements \JsonSerializable { use JsonSerializable;
class User implements JsonSerializable {
/** @var int */ /** @var int */
private $id; private $id;
/** @var string */ /** @var string */

View file

@ -4,7 +4,9 @@ declare(strict_types=1);
namespace Demostf\API\Demo; namespace Demostf\API\Demo;
class ChatMessage implements \JsonSerializable { use JsonSerializable;
class ChatMessage implements JsonSerializable {
/** @var string */ /** @var string */
private $user; private $user;

View file

@ -4,10 +4,12 @@ declare(strict_types=1);
namespace Demostf\API\Demo; namespace Demostf\API\Demo;
use DateTime;
use Demostf\API\Data\DemoPlayer; use Demostf\API\Data\DemoPlayer;
use Demostf\API\Data\User; use Demostf\API\Data\User;
use JsonSerializable;
class Demo implements \JsonSerializable { class Demo implements JsonSerializable {
/** @var int */ /** @var int */
private $id; private $id;
/** @var string */ /** @var string */
@ -22,7 +24,7 @@ class Demo implements \JsonSerializable {
private $nick; private $nick;
/** @var string */ /** @var string */
private $map; private $map;
/** @var \DateTime */ /** @var DateTime */
private $time; private $time;
/** @var string */ /** @var string */
private $red; private $red;
@ -55,7 +57,7 @@ class Demo implements \JsonSerializable {
float $duration, float $duration,
string $nick, string $nick,
string $map, string $map,
\DateTime $time, DateTime $time,
string $red, string $red,
string $blue, string $blue,
int $redScore, int $redScore,
@ -113,7 +115,7 @@ class Demo implements \JsonSerializable {
return $this->map; return $this->map;
} }
public function getTime(): \DateTime { public function getTime(): DateTime {
return $this->time; return $this->time;
} }
@ -158,7 +160,7 @@ class Demo implements \JsonSerializable {
(int) $row['duration'], (int) $row['duration'],
$row['nick'], $row['nick'],
$row['map'], $row['map'],
\DateTime::createFromFormat('U', '' . strtotime($row['created_at'])), DateTime::createFromFormat('U', '' . strtotime($row['created_at'])),
$row['red'], $row['red'],
$row['blu'], $row['blu'],
(int) $row['scoreRed'], (int) $row['scoreRed'],

View file

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Demostf\API\Demo; namespace Demostf\API\Demo;
use function count;
use DateTime;
use Demostf\API\Data\Kill; use Demostf\API\Data\Kill;
use Demostf\API\Data\ParsedDemo; use Demostf\API\Data\ParsedDemo;
use Demostf\API\Data\Player; use Demostf\API\Data\Player;
@ -59,12 +61,12 @@ class DemoSaver {
$header->getDuration(), $header->getDuration(),
$header->getNick(), $header->getNick(),
$header->getMap(), $header->getMap(),
new \DateTime(), new DateTime(),
$upload->getRed(), $upload->getRed(),
$upload->getBlue(), $upload->getBlue(),
$demo->getRedScore(), $demo->getRedScore(),
$demo->getBlueScore(), $demo->getBlueScore(),
\count($demo->getPlayers()), count($demo->getPlayers()),
$upload->getUploaderId(), $upload->getUploaderId(),
$upload->getHash(), $upload->getHash(),
$storedDemo->getBackend(), $storedDemo->getBackend(),

View file

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Demostf\API\Demo; namespace Demostf\API\Demo;
use Demostf\API\Data\StoredDemo; use Demostf\API\Data\StoredDemo;
use function dirname;
class DemoStore { class DemoStore {
/** @var string */ /** @var string */
@ -19,8 +20,8 @@ class DemoStore {
public function store(string $sourcePath, string $name): StoredDemo { public function store(string $sourcePath, string $name): StoredDemo {
$target = $this->generatePath($name); $target = $this->generatePath($name);
if (!is_dir(\dirname($target))) { if (!is_dir(dirname($target))) {
mkdir(\dirname($target), 0777, true); mkdir(dirname($target), 0777, true);
} }
rename($sourcePath, $target); rename($sourcePath, $target);
chmod($target, 0755); chmod($target, 0755);

View file

@ -4,11 +4,13 @@ declare(strict_types=1);
namespace Demostf\API\Demo; namespace Demostf\API\Demo;
use InvalidArgumentException;
class HeaderParser { class HeaderParser {
/** /**
* @param string $head string containing the demo header binary data * @param string $head string containing the demo header binary data
* *
* @throws \InvalidArgumentException * @throws InvalidArgumentException
* *
* @return Header * @return Header
*/ */
@ -18,7 +20,7 @@ class HeaderParser {
$head $head
); );
if (!isset($info['type']) || 'HL2DEMO' !== $info['type']) { if (!isset($info['type']) || 'HL2DEMO' !== $info['type']) {
throw new \InvalidArgumentException('Not an HL2 demo'); throw new InvalidArgumentException('Not an HL2 demo');
} }
return Header::fromArray($info); return Header::fromArray($info);
@ -29,7 +31,7 @@ class HeaderParser {
* *
* @param resource $stream * @param resource $stream
* *
* @throws \InvalidArgumentException * @throws InvalidArgumentException
* *
* @return Header * @return Header
*/ */
@ -44,13 +46,13 @@ class HeaderParser {
* *
* @param string $path * @param string $path
* *
* @throws \InvalidArgumentException * @throws InvalidArgumentException
* *
* @return Header * @return Header
*/ */
public function parseHeader(string $path): Header { public function parseHeader(string $path): Header {
if (!is_readable($path)) { if (!is_readable($path)) {
throw new \InvalidArgumentException('Unable to open demo: ' . $path); throw new InvalidArgumentException('Unable to open demo: ' . $path);
} }
$fh = fopen($path, 'r'); $fh = fopen($path, 'r');

View file

@ -7,6 +7,9 @@ namespace Demostf\API\Demo;
use Demostf\API\Data\ParsedDemo; use Demostf\API\Data\ParsedDemo;
use Demostf\API\Data\ParsedKill; use Demostf\API\Data\ParsedKill;
use Demostf\API\Data\ParsedPlayer; use Demostf\API\Data\ParsedPlayer;
use Exception;
use InvalidArgumentException;
use function is_array;
/** /**
* Higher level parser. * Higher level parser.
@ -35,10 +38,10 @@ class Parser {
public function analyse(string $path): ParsedDemo { public function analyse(string $path): ParsedDemo {
$data = $this->rawParser->parse($path); $data = $this->rawParser->parse($path);
if (\is_array($data) && isset($data['intervalPerTick'])) { if (is_array($data) && isset($data['intervalPerTick'])) {
return $this->handleData($data); return $this->handleData($data);
} else { } else {
throw new \InvalidArgumentException('Error parsing demo'); throw new InvalidArgumentException('Error parsing demo');
} }
} }
@ -52,7 +55,7 @@ class Parser {
$players = []; $players = [];
if (!isset($data['rounds'])) { if (!isset($data['rounds'])) {
throw new \Exception("Error while parsing demo, no rounds field found\n" . json_encode($data)); throw new Exception("Error while parsing demo, no rounds field found\n" . json_encode($data));
} }
foreach ($data['rounds'] as $round) { foreach ($data['rounds'] as $round) {
if ('red' === $round['winner']) { if ('red' === $round['winner']) {
@ -63,7 +66,7 @@ class Parser {
} }
if (!isset($data['chat'])) { if (!isset($data['chat'])) {
throw new \Exception('Error while parsing demo, no chat field found'); throw new Exception('Error while parsing demo, no chat field found');
} }
foreach ($data['chat'] as $message) { foreach ($data['chat'] as $message) {
if (isset($message['from'])) { if (isset($message['from'])) {
@ -73,7 +76,7 @@ class Parser {
} }
if (!isset($data['users'])) { if (!isset($data['users'])) {
throw new \Exception('Error while parsing demo, no users field found'); throw new Exception('Error while parsing demo, no users field found');
} }
$deaths = array_filter($data['deaths'], function ($death) { $deaths = array_filter($data['deaths'], function ($death) {
@ -146,14 +149,14 @@ class Parser {
* @param string $steamId The SteamID string as used on servers, like * @param string $steamId The SteamID string as used on servers, like
* <var>STEAM_0:0:12345</var> * <var>STEAM_0:0:12345</var>
* *
* @throws \InvalidArgumentException if the SteamID doesn't have the correct * @throws InvalidArgumentException if the SteamID doesn't have the correct
* format * format
* *
* @return string The converted 64bit numeric SteamID * @return string The converted 64bit numeric SteamID
*/ */
public static function convertSteamIdToCommunityId(string $steamId): string { public static function convertSteamIdToCommunityId(string $steamId): string {
if ('STEAM_ID_LAN' === $steamId || 'BOT' === $steamId) { if ('STEAM_ID_LAN' === $steamId || 'BOT' === $steamId) {
throw new \InvalidArgumentException("Cannot convert SteamID \"$steamId\" to a community ID."); throw new InvalidArgumentException("Cannot convert SteamID \"$steamId\" to a community ID.");
} }
if (preg_match('/^STEAM_[0-1]:[0-1]:[0-9]+$/', $steamId)) { if (preg_match('/^STEAM_[0-1]:[0-1]:[0-9]+$/', $steamId)) {
$steamParts = explode(':', substr($steamId, 8)); $steamParts = explode(':', substr($steamId, 8));
@ -166,7 +169,7 @@ class Parser {
return '7656' . $steamId; return '7656' . $steamId;
} else { } else {
throw new \InvalidArgumentException("SteamID \"$steamId\" doesn't have the correct format."); throw new InvalidArgumentException("SteamID \"$steamId\" doesn't have the correct format.");
} }
} }
} }

View file

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace Demostf\API\Demo; namespace Demostf\API\Demo;
use Demostf\API\Controllers\TempController; use Exception;
use GuzzleHttp\Exception\RequestException; use GuzzleHttp\Exception\RequestException;
/** /**
@ -16,25 +16,27 @@ class RawParser {
/** @var string */ /** @var string */
private $parserPath; private $parserPath;
private $tempController; public function __construct(string $parserPath) {
public function __construct(string $parserPath, TempController $tempController) {
$this->parserPath = $parserPath; $this->parserPath = $parserPath;
$this->tempController = $tempController;
} }
/**
* @param string $path
* @return array|null
* @throws Exception
*/
public function parse(string $path): ?array { public function parse(string $path): ?array {
try { try {
$command = $this->parserPath . ' ' . escapeshellarg($path); $command = $this->parserPath . ' ' . escapeshellarg($path);
$output = shell_exec($command); $output = shell_exec($command);
$result = \GuzzleHttp\json_decode($output, true); $result = \GuzzleHttp\json_decode($output, true);
if (null === $result) { if (null === $result) {
throw new \Exception('Failed to parse demo, unexpected result from parser'); throw new Exception('Failed to parse demo, unexpected result from parser');
} else { } else {
return $result; return $result;
} }
} catch (RequestException $e) { } catch (RequestException $e) {
throw new \Exception('Failed to parse demo, ' . $e->getMessage() . ' ' . $url); throw new Exception('Failed to parse demo, ' . $e->getMessage());
} }
} }
} }

View file

@ -6,6 +6,7 @@ namespace Demostf\API\Providers;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use RandomLib\Generator; use RandomLib\Generator;
use SteamId;
class AuthProvider extends BaseProvider { class AuthProvider extends BaseProvider {
/** /**
@ -22,7 +23,7 @@ class AuthProvider extends BaseProvider {
return $this->generator->generateString(32, Generator::CHAR_ALNUM); return $this->generator->generateString(32, Generator::CHAR_ALNUM);
} }
public function setUser(string $token, \SteamId $steamid, string $key) { public function setUser(string $token, SteamId $steamid, string $key) {
apcu_store($token, [ apcu_store($token, [
'name' => $steamid->getNickname(), 'name' => $steamid->getNickname(),
'steamid' => $steamid->getSteamId64(), 'steamid' => $steamid->getSteamId64(),

View file

@ -17,7 +17,7 @@ class BaseProvider {
protected $connection; protected $connection;
/** /**
* @var \LessQL\Database * @var Database
*/ */
protected $db; protected $db;

View file

@ -5,13 +5,14 @@ declare(strict_types=1);
namespace Demostf\API\Providers; namespace Demostf\API\Providers;
use Demostf\API\Demo\ChatMessage; use Demostf\API\Demo\ChatMessage;
use PDO;
class ChatProvider extends BaseProvider { class ChatProvider extends BaseProvider {
public function getChat(int $demoId) { public function getChat(int $demoId) {
$query = $this->getQueryBuilder(); $query = $this->getQueryBuilder();
$query->select('text', '"from"', 'time') $query->select('text', '"from"', 'time')
->from('chat') ->from('chat')
->where($query->expr()->eq('demo_id', $query->createNamedParameter($demoId, \PDO::PARAM_INT))); ->where($query->expr()->eq('demo_id', $query->createNamedParameter($demoId, PDO::PARAM_INT)));
$result = $query->execute(); $result = $query->execute();
@ -28,10 +29,10 @@ class ChatProvider extends BaseProvider {
$query = $this->getQueryBuilder(); $query = $this->getQueryBuilder();
$query->insert('chat') $query->insert('chat')
->values([ ->values([
'demo_id' => $query->createNamedParameter($demoId, \PDO::PARAM_INT), 'demo_id' => $query->createNamedParameter($demoId, PDO::PARAM_INT),
'text' => $query->createNamedParameter($message->getMessage()), 'text' => $query->createNamedParameter($message->getMessage()),
'"from"' => $query->createNamedParameter($message->getUser()), '"from"' => $query->createNamedParameter($message->getUser()),
'time' => $query->createNamedParameter($message->getTime(), \PDO::PARAM_INT), 'time' => $query->createNamedParameter($message->getTime(), PDO::PARAM_INT),
'created_at' => 'now()', 'created_at' => 'now()',
'updated_at' => 'now()', 'updated_at' => 'now()',
]); ]);

View file

@ -4,8 +4,11 @@ declare(strict_types=1);
namespace Demostf\API\Providers; namespace Demostf\API\Providers;
use function count;
use Demostf\API\Demo\Demo; use Demostf\API\Demo\Demo;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use function is_array;
use PDO;
class DemoListProvider extends BaseProvider { class DemoListProvider extends BaseProvider {
public function listUploads(string $steamId, int $page, array $where = []) { public function listUploads(string $steamId, int $page, array $where = []) {
@ -30,14 +33,14 @@ class DemoListProvider extends BaseProvider {
->groupBy('demo_id') ->groupBy('demo_id')
->having($query->expr()->eq( ->having($query->expr()->eq(
'COUNT(user_id)', 'COUNT(user_id)',
$query->createNamedParameter(\count($userIds, \PDO::PARAM_INT)) $query->createNamedParameter(count($userIds, PDO::PARAM_INT))
)) ))
->orderBy('demo_id', 'desc') ->orderBy('demo_id', 'desc')
->setMaxResults(50) ->setMaxResults(50)
->setFirstResult(((int) $page - 1) * 50); ->setFirstResult(((int) $page - 1) * 50);
$result = $query->execute(); $result = $query->execute();
$demoIds = $result->fetchAll(\PDO::FETCH_COLUMN); $demoIds = $result->fetchAll(PDO::FETCH_COLUMN);
$demos = $this->db->demo()->where('id', $demoIds) $demos = $this->db->demo()->where('id', $demoIds)
->where($where) ->where($where)
@ -54,7 +57,7 @@ class DemoListProvider extends BaseProvider {
* @return Demo[] * @return Demo[]
*/ */
public function listDemos(int $page, array $where = [], string $order = 'DESC') { public function listDemos(int $page, array $where = [], string $order = 'DESC') {
if (isset($where['players']) and \is_array($where['players']) and \count($where['players']) > 0) { if (isset($where['players']) and is_array($where['players']) and count($where['players']) > 0) {
return $this->listProfile($page, $where); return $this->listProfile($page, $where);
} }
@ -77,7 +80,7 @@ class DemoListProvider extends BaseProvider {
} }
if (isset($where['uploader'])) { if (isset($where['uploader'])) {
$query->andWhere($query->expr()->in('uploader', $query->andWhere($query->expr()->in('uploader',
$query->createNamedParameter($where['uploader'], \PDO::PARAM_INT))); $query->createNamedParameter($where['uploader'], PDO::PARAM_INT)));
} }
if (isset($where['backend'])) { if (isset($where['backend'])) {
$query->andWhere($query->expr()->eq('backend', $query->andWhere($query->expr()->eq('backend',
@ -87,7 +90,7 @@ class DemoListProvider extends BaseProvider {
->setMaxResults(50) ->setMaxResults(50)
->setFirstResult($offset); ->setFirstResult($offset);
$demos = $query->execute()->fetchAll(\PDO::FETCH_ASSOC); $demos = $query->execute()->fetchAll(PDO::FETCH_ASSOC);
return $this->formatList($demos); return $this->formatList($demos);
} }

View file

@ -4,9 +4,11 @@ declare(strict_types=1);
namespace Demostf\API\Providers; namespace Demostf\API\Providers;
use const DATE_ATOM;
use Demostf\API\Data\DemoPlayer; use Demostf\API\Data\DemoPlayer;
use Demostf\API\Data\User; use Demostf\API\Data\User;
use Demostf\API\Demo\Demo; use Demostf\API\Demo\Demo;
use PDO;
class DemoProvider extends BaseProvider { class DemoProvider extends BaseProvider {
const VERSION = 4; const VERSION = 4;
@ -33,7 +35,7 @@ class DemoProvider extends BaseProvider {
if ($fetchDetails) { if ($fetchDetails) {
$uploader = $demo->user()->via('uploader')->fetch(); $uploader = $demo->user()->via('uploader')->fetch();
$playerQuery = $this->query($sql, [$formattedDemo->getId(), $formattedDemo->getId()]); $playerQuery = $this->query($sql, [$formattedDemo->getId(), $formattedDemo->getId()]);
$players = $playerQuery->fetchAll(\PDO::FETCH_ASSOC); $players = $playerQuery->fetchAll(PDO::FETCH_ASSOC);
$formattedDemo->setUploaderUser(User::fromRow([ $formattedDemo->setUploaderUser(User::fromRow([
'id' => $uploader['id'], 'id' => $uploader['id'],
@ -74,18 +76,18 @@ class DemoProvider extends BaseProvider {
'map' => $query->createNamedParameter($demo->getMap()), 'map' => $query->createNamedParameter($demo->getMap()),
'red' => $query->createNamedParameter($demo->getRed()), 'red' => $query->createNamedParameter($demo->getRed()),
'blu' => $query->createNamedParameter($demo->getBlue()), 'blu' => $query->createNamedParameter($demo->getBlue()),
'uploader' => $query->createNamedParameter($demo->getUploader(), \PDO::PARAM_INT), 'uploader' => $query->createNamedParameter($demo->getUploader(), PDO::PARAM_INT),
'duration' => $query->createNamedParameter((int) $demo->getDuration(), \PDO::PARAM_INT), 'duration' => $query->createNamedParameter((int) $demo->getDuration(), PDO::PARAM_INT),
'created_at' => $query->createNamedParameter($demo->getTime()->format(\DATE_ATOM)), 'created_at' => $query->createNamedParameter($demo->getTime()->format(DATE_ATOM)),
'updated_at' => 'now()', 'updated_at' => 'now()',
'backend' => $query->createNamedParameter($backend), 'backend' => $query->createNamedParameter($backend),
'path' => $query->createNamedParameter($path), 'path' => $query->createNamedParameter($path),
'"scoreBlue"' => $query->createNamedParameter($demo->getBlueScore(), \PDO::PARAM_INT), '"scoreBlue"' => $query->createNamedParameter($demo->getBlueScore(), PDO::PARAM_INT),
'"scoreRed"' => $query->createNamedParameter($demo->getRedScore(), \PDO::PARAM_INT), '"scoreRed"' => $query->createNamedParameter($demo->getRedScore(), PDO::PARAM_INT),
'version' => $query->createNamedParameter(self::VERSION, \PDO::PARAM_INT), 'version' => $query->createNamedParameter(self::VERSION, PDO::PARAM_INT),
'server' => $query->createNamedParameter($demo->getServer()), 'server' => $query->createNamedParameter($demo->getServer()),
'nick' => $query->createNamedParameter($demo->getNick()), 'nick' => $query->createNamedParameter($demo->getNick()),
'"playerCount"' => $query->createNamedParameter($demo->getPlayerCount(), \PDO::PARAM_INT), '"playerCount"' => $query->createNamedParameter($demo->getPlayerCount(), PDO::PARAM_INT),
'hash' => $query->createNamedParameter($demo->getHash()), 'hash' => $query->createNamedParameter($demo->getHash()),
]) ])
->execute(); ->execute();
@ -99,7 +101,7 @@ class DemoProvider extends BaseProvider {
->set('backend', $query->createNamedParameter($backend)) ->set('backend', $query->createNamedParameter($backend))
->set('url', $query->createNamedParameter($url)) ->set('url', $query->createNamedParameter($url))
->set('path', $query->createNamedParameter($path)) ->set('path', $query->createNamedParameter($path))
->where($query->expr()->eq('id', $query->createNamedParameter($id, \PDO::PARAM_INT))) ->where($query->expr()->eq('id', $query->createNamedParameter($id, PDO::PARAM_INT)))
->execute(); ->execute();
} }
} }

View file

@ -4,12 +4,14 @@ declare(strict_types=1);
namespace Demostf\API\Providers; namespace Demostf\API\Providers;
use PDO;
class InfoProvider extends BaseProvider { class InfoProvider extends BaseProvider {
public function listMaps() { public function listMaps() {
$sql = 'SELECT map, count FROM map_list'; $sql = 'SELECT map, count FROM map_list';
$result = $this->query($sql); $result = $this->query($sql);
return $result->fetchAll(\PDO::FETCH_COLUMN); return $result->fetchAll(PDO::FETCH_COLUMN);
} }
public function getStats() { public function getStats() {

View file

@ -7,7 +7,10 @@ namespace Demostf\API\Providers;
use Demostf\API\Data\SteamUser; use Demostf\API\Data\SteamUser;
use Demostf\API\Data\User; use Demostf\API\Data\User;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use function is_array;
use PDO;
use RandomLib\Generator; use RandomLib\Generator;
use SteamId;
class UserProvider extends BaseProvider { class UserProvider extends BaseProvider {
/** /**
@ -20,7 +23,7 @@ class UserProvider extends BaseProvider {
$this->generator = $generator; $this->generator = $generator;
} }
public function store(\SteamId $steamId): string { public function store(SteamId $steamId): string {
$token = $this->generator->generateString(64, Generator::EASY_TO_READ); $token = $this->generator->generateString(64, Generator::EASY_TO_READ);
$user = $this->get($steamId->getSteamId64()); $user = $this->get($steamId->getSteamId64());
@ -65,7 +68,7 @@ class UserProvider extends BaseProvider {
->setMaxResults(1); ->setMaxResults(1);
$result = $query->execute()->fetch(); $result = $query->execute()->fetch();
if (\is_array($result)) { if (is_array($result)) {
return $result; return $result;
} else { } else {
return null; return null;
@ -86,7 +89,7 @@ class UserProvider extends BaseProvider {
} }
$query = $this->getQueryBuilder(); $query = $this->getQueryBuilder();
$nameParameter = $query->createNamedParameter($search, \PDO::PARAM_STR, ':query'); $nameParameter = $query->createNamedParameter($search, PDO::PARAM_STR, ':query');
$query->select('user_id', 'name', 'count', 'steamid', "1 - (name <-> $nameParameter) AS sim") $query->select('user_id', 'name', 'count', 'steamid', "1 - (name <-> $nameParameter) AS sim")
->from('name_list') ->from('name_list')
->where($query->expr()->comparison('name', '%', $nameParameter)) ->where($query->expr()->comparison('name', '%', $nameParameter))
@ -94,7 +97,7 @@ class UserProvider extends BaseProvider {
->orderBy('count', 'DESC') ->orderBy('count', 'DESC')
->setMaxResults(100); ->setMaxResults(100);
$result = $query->execute(); $result = $query->execute();
$players = $result->fetchAll(\PDO::FETCH_ASSOC); $players = $result->fetchAll(PDO::FETCH_ASSOC);
usort($players, function ($b, $a) use ($query) { usort($players, function ($b, $a) use ($query) {
if ($a['steamid'] === $query && $a['steamid'] !== $query) { if ($a['steamid'] === $query && $a['steamid'] !== $query) {
@ -138,7 +141,7 @@ class UserProvider extends BaseProvider {
return $existing->getId(); return $existing->getId();
} }
$this->store(new \SteamId($steamId)); $this->store(new SteamId($steamId));
return $this->get($steamId)->getId(); return $this->get($steamId)->getId();
} }

View file

@ -30,7 +30,6 @@ $userController = new Controllers\UserController($container->getRequest(), $cont
$container->getUserProvider()); $container->getUserProvider());
$infoController = new Controllers\InfoController($container->getRequest(), $container->getResponse(), $infoController = new Controllers\InfoController($container->getRequest(), $container->getResponse(),
$container->getInfoProvider()); $container->getInfoProvider());
$tempController = new Controllers\TempController($container->getApiRoot() . '/temp/');
Flight::route('/*', function () { Flight::route('/*', function () {
header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Origin: *');
@ -67,6 +66,4 @@ Flight::route('/auth/handle/@token', [$authController, 'handle']);
Flight::route('/auth/login/@token', [$authController, 'login']); Flight::route('/auth/login/@token', [$authController, 'login']);
Flight::route('/auth/logout/@token', [$authController, 'logout']); Flight::route('/auth/logout/@token', [$authController, 'logout']);
Flight::route('/temp/@hash', [$tempController, 'serve']);
Flight::start(); Flight::start();

View file

@ -3,6 +3,7 @@
declare(strict_types=1); declare(strict_types=1);
use Demostf\API\Container; use Demostf\API\Container;
use Doctrine\DBAL\DriverManager;
$autoloader = require __DIR__ . '/../vendor/autoload.php'; $autoloader = require __DIR__ . '/../vendor/autoload.php';
@ -21,7 +22,7 @@ $connectionParams = [
if ('pgsql' === $connectionParams['driver']) { if ('pgsql' === $connectionParams['driver']) {
$connectionParams['driver'] = 'pdo_pgsql'; $connectionParams['driver'] = 'pdo_pgsql';
} }
$db = \Doctrine\DBAL\DriverManager::getConnection($connectionParams); $db = DriverManager::getConnection($connectionParams);
$host = getenv('BASE_HOST') ?: ''; $host = getenv('BASE_HOST') ?: '';
$storeRoot = getenv('DEMO_ROOT') ?: ''; $storeRoot = getenv('DEMO_ROOT') ?: '';
$storeHost = getenv('DEMO_HOST') ?: ''; $storeHost = getenv('DEMO_HOST') ?: '';

View file

@ -9,13 +9,10 @@ use Flight;
/** @var Container $container */ /** @var Container $container */
$container = require __DIR__ . '/init.php'; $container = require __DIR__ . '/init.php';
$tempController = new Controllers\TempController($container->getApiRoot() . '/temp/');
$uploadController = new Controllers\UploadController( $uploadController = new Controllers\UploadController(
$container->getRequest(), $container->getRequest(),
$container->getResponse(), $container->getResponse(),
$container->getUploadProvider(), $container->getUploadProvider()
$tempController
); );
Flight::route('/*', function () { Flight::route('/*', function () {

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Demostf\API\Test\Providers; namespace Demostf\API\Test\Providers;
use DateTime;
use Demostf\API\Data\ParsedDemo; use Demostf\API\Data\ParsedDemo;
use Demostf\API\Demo\Demo; use Demostf\API\Demo\Demo;
use Demostf\API\Demo\DemoSaver; use Demostf\API\Demo\DemoSaver;
@ -21,6 +22,10 @@ use Demostf\API\Providers\UserProvider;
use Demostf\API\Test\TestCase; use Demostf\API\Test\TestCase;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use InvalidArgumentException; use InvalidArgumentException;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use ReflectionException;
use function strlen;
class UploadProviderTest extends TestCase { class UploadProviderTest extends TestCase {
/** @var RawParser */ /** @var RawParser */
@ -42,6 +47,9 @@ class UploadProviderTest extends TestCase {
/** @var string */ /** @var string */
private $tmpDir; private $tmpDir;
/**
* @throws ReflectionException
*/
public function setUp(): void { public function setUp(): void {
parent::setUp(); parent::setUp();
@ -90,10 +98,10 @@ class UploadProviderTest extends TestCase {
} }
private function rmdirr($dir) { private function rmdirr($dir) {
$it = new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS); $it = new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS);
$files = new \RecursiveIteratorIterator( $files = new RecursiveIteratorIterator(
$it, $it,
\RecursiveIteratorIterator::CHILD_FIRST RecursiveIteratorIterator::CHILD_FIRST
); );
foreach ($files as $file) { foreach ($files as $file) {
if ($file->isDir()) { if ($file->isDir()) {
@ -209,7 +217,7 @@ class UploadProviderTest extends TestCase {
public function testUploadInvalidKey() { public function testUploadInvalidKey() {
$this->assertEquals( $this->assertEquals(
'Invalid key', 'Invalid key',
$this->uploadProvider->upload('asdasd', 'RED', 'BLU', 'asdasd', 'asdas') $this->uploadProvider->upload('dummy', 'RED', 'BLU', 'dummy', 'dummy')
); );
} }
@ -222,7 +230,7 @@ class UploadProviderTest extends TestCase {
$steamId = $this->getSteamId('123', 'a'); $steamId = $this->getSteamId('123', 'a');
$token = $this->userProvider->store($steamId); $token = $this->userProvider->store($steamId);
$this->uploadProvider->upload($token, 'RED', 'BLU', 'asdasd', $this->tmpDir . '/foo.dem'); $this->uploadProvider->upload($token, 'RED', 'BLU', 'dummy', $this->tmpDir . '/foo.dem');
} }
public function testUploadExisting() { public function testUploadExisting() {
@ -240,7 +248,7 @@ class UploadProviderTest extends TestCase {
12, 12,
'n', 'n',
'm', 'm',
new \DateTime(), new DateTime(),
'r', 'r',
'b', 'b',
1, 1,
@ -260,7 +268,7 @@ class UploadProviderTest extends TestCase {
$this->assertEquals( $this->assertEquals(
'STV available at: http://example.com/' . $id, 'STV available at: http://example.com/' . $id,
$this->uploadProvider->upload($token, 'RED', 'BLU', 'asdasd', $this->tmpDir . '/foo.dem') $this->uploadProvider->upload($token, 'RED', 'BLU', 'dummy', $this->tmpDir . '/foo.dem')
); );
} }
@ -299,7 +307,7 @@ class UploadProviderTest extends TestCase {
$result = $this->uploadProvider->upload($token, 'RED', 'BLU', 'foodemo', $this->tmpDir . '/foo.dem'); $result = $this->uploadProvider->upload($token, 'RED', 'BLU', 'foodemo', $this->tmpDir . '/foo.dem');
$this->assertStringStartsWith('STV available at: http://example.com/', $result); $this->assertStringStartsWith('STV available at: http://example.com/', $result);
$demoId = (int) substr($result, \strlen('STV available at: http://example.com/')); $demoId = (int) substr($result, strlen('STV available at: http://example.com/'));
$demo = $this->demoProvider->get($demoId, true); $demo = $this->demoProvider->get($demoId, true);
@ -331,7 +339,7 @@ class UploadProviderTest extends TestCase {
$this->assertEquals( $this->assertEquals(
'Invalid key', 'Invalid key',
$uploadProvider->upload($token, 'RED', 'BLU', 'asdasd', 'asdas') $uploadProvider->upload($token, 'RED', 'BLU', 'dummy', 'dummy')
); );
$uploadProvider = new UploadProvider( $uploadProvider = new UploadProvider(
@ -348,6 +356,6 @@ class UploadProviderTest extends TestCase {
file_put_contents($this->tmpDir . '/foo.dem', 'asd'); file_put_contents($this->tmpDir . '/foo.dem', 'asd');
$uploadProvider->upload($token, 'RED', 'BLU', 'asdasd', $this->tmpDir . '/foo.dem'); $uploadProvider->upload($token, 'RED', 'BLU', 'dummy', $this->tmpDir . '/foo.dem');
} }
} }