From 2f5aa63306ed989499a2f2003d8cfcc36061d341 Mon Sep 17 00:00:00 2001 From: Max Nuding Date: Wed, 10 Apr 2024 11:52:35 +0200 Subject: [PATCH] formatting --- .nova/Configuration.json | 4 + phpcs.xml | 4 +- src/APnutI.php | 1616 +++++++++++++++++++------------------- src/Meta.php | 74 +- 4 files changed, 847 insertions(+), 851 deletions(-) diff --git a/.nova/Configuration.json b/.nova/Configuration.json index cbf8704..7eb4613 100644 --- a/.nova/Configuration.json +++ b/.nova/Configuration.json @@ -1,8 +1,12 @@ { + "com.thorlaksson.phpcs.formatOnSave" : true, "com.thorlaksson.phpcs.runOnChange" : "onSave", "com.thorlaksson.phpcs.standard" : "phpcs.xml", "editor.default_syntax" : "php", "php.validate" : "onSave", + "prettier.format-on-save" : "Disable", + "prettier.format-on-save.ignore-remote" : "Disable", + "prettier.format-on-save.ignore-without-config" : "Disable", "workspace.color" : 1, "workspace.name" : "APnutI" } diff --git a/phpcs.xml b/phpcs.xml index 4bb20d7..97cf8eb 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -18,10 +18,10 @@ - + - + diff --git a/src/APnutI.php b/src/APnutI.php index 13d6fdf..b15d744 100644 --- a/src/APnutI.php +++ b/src/APnutI.php @@ -7,7 +7,6 @@ use APnutI\Entities\Poll; use APnutI\Entities\User; use APnutI\Entities\Channel; use APnutI\Exceptions\PnutException; -use APnutI\Exceptions\NotFoundException; use APnutI\Exceptions\NotAuthorizedException; use APnutI\Exceptions\HttpPnutException; use APnutI\Exceptions\HttpPnutRedirectException; @@ -22,30 +21,30 @@ use Psr\Log\NullLogger; class APnutI { - protected string $api_url = 'https://api.pnut.io/v1'; - protected string $auth_url = 'https://pnut.io/oauth/authenticate'; - protected string $client_secret; - protected string $client_id; - protected string $scope = ''; - protected string $redirect_uri; - protected int $rate_limit = 40; - protected int $rate_limit_remaining = 40; - protected int $rate_limit_reset = 60; - protected array $scopes = []; - protected ?string $needed_scope; - protected ?string $redirect_target = null; - protected array $headers = []; - protected ?string $server_token; - protected ?string $access_token; - protected string $token_session_key; - protected string $token_redirect_after_auth; - protected ?string $server_token_file_path = null; + protected string $api_url = 'https://api.pnut.io/v1'; + protected string $auth_url = 'https://pnut.io/oauth/authenticate'; + protected string $client_secret; + protected string $client_id; + protected string $scope = ''; + protected string $redirect_uri; + protected int $rate_limit = 40; + protected int $rate_limit_remaining = 40; + protected int $rate_limit_reset = 60; + protected array $scopes = []; + protected ?string $needed_scope; + protected ?string $redirect_target = null; + protected array $headers = []; + protected ?string $server_token; + protected ?string $access_token; + protected string $token_session_key; + protected string $token_redirect_after_auth; + protected ?string $server_token_file_path = null; - protected ?User $current_user = null; + protected ?User $current_user = null; - public ?Meta $meta = null; - public string $app_name = 'Abstract API'; - public LoggerInterface $logger; + public ?Meta $meta = null; + public string $app_name = 'Abstract API'; + public LoggerInterface $logger; /* * Error codes: @@ -58,848 +57,841 @@ class APnutI * 5XX: Generic server error */ - public static $ERROR_FETCHING_CREATOR = 300; - public static $ERROR_FETCHING_CREATOR_FIELD = 301; - public static $ERROR_MISSING_PARAMETER = 400; - public static $ERROR_NOT_FOUND = 404; - public static $ERROR_UNKNOWN_SERVER_ERROR = 500; + public static $ERROR_FETCHING_CREATOR = 300; + public static $ERROR_FETCHING_CREATOR_FIELD = 301; + public static $ERROR_MISSING_PARAMETER = 400; + public static $ERROR_NOT_FOUND = 404; + public static $ERROR_UNKNOWN_SERVER_ERROR = 500; - public static $POST_MAX_LENGTH; - public static $POST_MAX_LENGTH_REPOST; - public static $POST_SECONDS_BETWEEN_DUPLICATES; - public static $MESSAGE_MAX_LENGTH; - public static $RAW_MAX_LENGTH; - public static $USER_DESCRIPTION_MAX_LENGTH; - public static $USER_USERNAME_MAX_LENGTH; + public static $POST_MAX_LENGTH; + public static $POST_MAX_LENGTH_REPOST; + public static $POST_SECONDS_BETWEEN_DUPLICATES; + public static $MESSAGE_MAX_LENGTH; + public static $RAW_MAX_LENGTH; + public static $USER_DESCRIPTION_MAX_LENGTH; + public static $USER_USERNAME_MAX_LENGTH; - public function __construct( - ?string $client_secret = null, - ?string $client_id = null, - ?string $needed_scope = null, - ?string $app_name = null, - ?string $redirect_uri = null, - ?string $log_path = null, - $log_level = null - ) { - if (empty($log_level)) { - $log_level = Logger::INFO; - } elseif (is_string($log_level)) { - $log_level = constant('Monolog\Logger::' . $log_level); + public function __construct( + ?string $client_secret = null, + ?string $client_id = null, + ?string $needed_scope = null, + ?string $app_name = null, + ?string $redirect_uri = null, + ?string $log_path = null, + $log_level = null + ) { + if (empty($log_level)) { + $log_level = Logger::INFO; + } elseif (is_string($log_level)) { + $log_level = constant('Monolog\Logger::' . $log_level); + } + $this->logger = empty($log_path) + ? new NullLogger() + : new Logger($this->app_name); + $this->token_session_key = $this->app_name . 'access_token'; + $this->token_redirect_after_auth = $this->app_name . 'redirect_after_auth'; + $handler = new RotatingFileHandler($log_path, 5, $log_level, true); + $this->logger->pushHandler($handler); + $this->server_token = null; + $this->logger->debug('__construct API'); + if (isset($_SESSION[$this->token_session_key])) { + $this->access_token = $_SESSION[$this->token_session_key]; + $this->logger->debug('Access token in session'); + } else { + $this->logger->debug('No access token in session'); + } + if (!empty($client_secret)) { + $this->client_secret = $client_secret; + } + if (!empty($client_id)) { + $this->client_id = $client_id; + } + if (!empty($needed_scope)) { + $this->needed_scope = $needed_scope; + } + if (!empty($redirect_uri)) { + $this->redirect_uri = $redirect_uri; + } + if (!empty($app_name)) { + $this->app_name = $app_name; + } } - $this->logger = empty($log_path) - ? new NullLogger() - : new Logger($this->app_name); - $this->token_session_key = $this->app_name . 'access_token'; - $this->token_redirect_after_auth = $this->app_name . 'redirect_after_auth'; - $handler = new RotatingFileHandler($log_path, 5, $log_level, true); - $this->logger->pushHandler($handler); - $this->server_token = null; - $this->logger->debug('__construct API'); - if (isset($_SESSION[$this->token_session_key])) { - $this->access_token = $_SESSION[$this->token_session_key]; - $this->logger->debug('Access token in session'); - } else { - $this->logger->debug('No access token in session'); - } - if (!empty($client_secret)) { - $this->client_secret = $client_secret; - } - if (!empty($client_id)) { - $this->client_id = $client_id; - } - if (!empty($needed_scope)) { - $this->needed_scope = $needed_scope; - } - if (!empty($redirect_uri)) { - $this->redirect_uri = $redirect_uri; - } - if (!empty($app_name)) { - $this->app_name = $app_name; - } - } /** * Internal function, parses out important information pnut.io adds * to the headers. Mostly taken from PHPnut */ - protected function parseHeaders(string $response): string - { - // take out the headers - // set internal variables - // return the body/content - /*$this->rate_limit = null; - $this->rate_limit_remaining = null; - $this->rate_limit_reset = null;*/ - $this->scopes = []; - $this->scope = ''; - $response = explode("\r\n\r\n", $response, 2); - $headers = $response[0]; - if ($headers === 'HTTP/1.1 100 Continue') { - $response = explode("\r\n\r\n", $response[1], 2); - $headers = $response[0]; - } - if (isset($response[1])) { - $content = $response[1]; - } else { - $content = ''; - } - // this is not a good way to parse http headers - // it will not (for example) take into account multiline headers - // but what we're looking for is pretty basic, so we can ignore those shortcomings - $this->headers = explode("\r\n", $headers); - foreach ($this->headers as $header) { - $header = explode(': ', $header, 2); - if (count($header) < 2) { - continue; - } - list($k, $v) = $header; - switch ($k) { - case 'X-RateLimit-Remaining': - $this->rate_limit_remaining = (int) $v; - break; - case 'X-RateLimit-Limit': - $this->rate_limit = (int) $v; - break; - case 'X-RateLimit-Reset': - $this->rate_limit_reset = (int) $v; - break; - case 'X-OAuth-Scopes': - $this->scope = $v; - $this->scopes = explode(',', $v); - break; - case 'location': - case 'Location': - $this->logger->debug( - 'Is redirect. Headers: ' . json_encode($this->headers) - ); - $this->logger->debug('Is redirect. Target: ' . $v); - $this->redirect_target = $v; - break; - } - } - return $content; - } - - public function makeRequest( - string $method, - string $end_point, - array $parameters, - string $content_type = 'application/x-www-form-urlencoded', - bool $follow_redirect = true - ): array { - $this->redirect_target = null; - $this->meta = null; - $method = strtoupper($method); - $url = $this->api_url . $end_point; - $this->logger->info("{$method} Request to {$url}"); - $ch = curl_init($url); - $headers = []; - $use_server_token = false; - if ($method !== 'GET') { - // if they passed an array, build a list of parameters from it - curl_setopt($ch, CURLOPT_POST, true); - if (is_array($parameters) && $method !== 'POST-RAW') { - $parameters = - $content_type === 'application/json' - ? json_encode($parameters) - : http_build_query($parameters); - } - curl_setopt($ch, CURLOPT_POSTFIELDS, $parameters); - $headers[] = 'Content-Type: ' . $content_type; - } - if ($method !== 'POST' && $method !== 'POST-RAW') { - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); - } - if ($method === 'GET' && isset($parameters['access_token'])) { - $this->logger->info('Using provided token for auth'); - $headers[] = 'Authorization: Bearer ' . $params['access_token']; - } elseif (!empty($this->access_token)) { - $this->logger->info('Using access token for auth'); - $headers[] = 'Authorization: Bearer ' . $this->access_token; - } elseif (!empty($this->server_token)) { - $use_server_token = true; - $this->logger->info('Using server token for auth'); - $headers[] = 'Authorization: Bearer ' . $this->server_token; - } else { - $this->logger->info('Using no auth'); + protected function parseHeaders(string $response): string + { + // take out the headers + // set internal variables + // return the body/content + /*$this->rate_limit = null; + $this->rate_limit_remaining = null; + $this->rate_limit_reset = null;*/ + $this->scopes = []; + $this->scope = ''; + $response = explode("\r\n\r\n", $response, 2); + $headers = $response[0]; + if ($headers === 'HTTP/1.1 100 Continue') { + $response = explode("\r\n\r\n", $response[1], 2); + $headers = $response[0]; + } + if (isset($response[1])) { + $content = $response[1]; + } else { + $content = ''; + } + // this is not a good way to parse http headers + // it will not (for example) take into account multiline headers + // but what we're looking for is pretty basic, so we can ignore those shortcomings + $this->headers = explode("\r\n", $headers); + foreach ($this->headers as $header) { + $header = explode(': ', $header, 2); + if (count($header) < 2) { + continue; + } + list($k, $v) = $header; + switch ($k) { + case 'X-RateLimit-Remaining': + $this->rate_limit_remaining = (int) $v; + break; + case 'X-RateLimit-Limit': + $this->rate_limit = (int) $v; + break; + case 'X-RateLimit-Reset': + $this->rate_limit_reset = (int) $v; + break; + case 'X-OAuth-Scopes': + $this->scope = $v; + $this->scopes = explode(',', $v); + break; + case 'location': + case 'Location': + $this->logger->debug( + 'Is redirect. Headers: ' . json_encode($this->headers) + ); + $this->logger->debug('Is redirect. Target: ' . $v); + $this->redirect_target = $v; + break; + } + } + return $content; } - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLINFO_HEADER_OUT, true); - curl_setopt($ch, CURLOPT_HEADER, true); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $follow_redirect); - $response = curl_exec($ch); - $request = curl_getinfo($ch, CURLINFO_HEADER_OUT); - $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE); - $effectiveURL = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); - curl_close($ch); - $this->logger->debug( - "{$method} Request to {$url}. Received status: {$http_status}. Response: {$response}" - ); - if ($http_status === 0) { - throw new \Exception('Unable to connect to Pnut ' . $url); - } - if ($request === false) { - if (!curl_getinfo($ch, CURLINFO_SSL_VERIFYRESULT)) { - throw new \Exception( - 'SSL verification failed, connection terminated: ' . $url + public function makeRequest( + string $method, + string $end_point, + array $parameters, + string $content_type = 'application/x-www-form-urlencoded', + bool $follow_redirect = true + ): array { + $this->redirect_target = null; + $this->meta = null; + $method = strtoupper($method); + $url = $this->api_url . $end_point; + $this->logger->info("{$method} Request to {$url}"); + $ch = curl_init($url); + $headers = []; + $use_server_token = false; + if ($method !== 'GET') { + // if they passed an array, build a list of parameters from it + curl_setopt($ch, CURLOPT_POST, true); + if (is_array($parameters) && $method !== 'POST-RAW') { + $parameters = + $content_type === 'application/json' + ? json_encode($parameters) + : http_build_query($parameters); + } + curl_setopt($ch, CURLOPT_POSTFIELDS, $parameters); + $headers[] = 'Content-Type: ' . $content_type; + } + if ($method !== 'POST' && $method !== 'POST-RAW') { + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); + } + if ($method === 'GET' && isset($parameters['access_token'])) { + $this->logger->info('Using provided token for auth'); + $headers[] = 'Authorization: Bearer ' . $parameters['access_token']; + } elseif (!empty($this->access_token)) { + $this->logger->info('Using access token for auth'); + $headers[] = 'Authorization: Bearer ' . $this->access_token; + } elseif (!empty($this->server_token)) { + $use_server_token = true; + $this->logger->info('Using server token for auth'); + $headers[] = 'Authorization: Bearer ' . $this->server_token; + } else { + $this->logger->info('Using no auth'); + } + + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLINFO_HEADER_OUT, true); + curl_setopt($ch, CURLOPT_HEADER, true); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $follow_redirect); + $response = curl_exec($ch); + $request = curl_getinfo($ch, CURLINFO_HEADER_OUT); + $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + $this->logger->debug( + "{$method} Request to {$url}. Received status: {$http_status}. Response: {$response}" ); - } - } - if (!empty($response)) { - $response = $this->parseHeaders($response); - if ($http_status == 302) { - #echo json_encode(preg_match_all('/^Location:(.*)$/mi', $response, $matches)); - $this->logger->debug("302 Redirect to {$this->redirect_target}"); - throw new HttpPnutRedirectException($this->redirect_target); - } - if (!empty($response)) { - $response = json_decode($response, true); - if ($response === null && !empty($this->redirect_target)) { - $this->logger->debug("Redirect to {$this->redirect_target}"); - throw new HttpPnutRedirectException($this->redirect_target); + if ($http_status === 0) { + throw new \Exception('Unable to connect to Pnut ' . $url); } - try { - $this->meta = new Meta($response); - } catch (NotAuthorizedException $nae) { - $headers_string = print_r($this->headers, true); - $this->logger->error("Error, not authorized: {$nae->getMessage()}"); - $this->logger->error("Headers: {$headers_string}"); - # Force re-auth - if (!$use_server_token) { - $this->logout(); - } - throw $nae; - } catch (PnutException $pe) { - $response_headers_string = print_r($this->headers, true); - $request_headers_string = print_r($headers, true); - $parameters_string = print_r($parameters, true); - $this->logger->error("Error: {$pe->getMessage()}"); - $this->logger->error("Method: {$method}"); - $this->logger->error("Parameters: {$parameters_string}"); - $this->logger->error("Request headers: {$request_headers_string}"); - $this->logger->error("Response headers: {$response_headers_string}"); - throw $pe; + if ($request === false) { + if (!curl_getinfo($ch, CURLINFO_SSL_VERIFYRESULT)) { + throw new \Exception( + 'SSL verification failed, connection terminated: ' . $url + ); + } } + if (!empty($response)) { + $response = $this->parseHeaders($response); + if ($http_status == 302) { + #echo json_encode(preg_match_all('/^Location:(.*)$/mi', $response, $matches)); + $this->logger->debug("302 Redirect to {$this->redirect_target}"); + throw new HttpPnutRedirectException($this->redirect_target); + } + if (!empty($response)) { + $response = json_decode($response, true); + if ($response === null && !empty($this->redirect_target)) { + $this->logger->debug("Redirect to {$this->redirect_target}"); + throw new HttpPnutRedirectException($this->redirect_target); + } + try { + $this->meta = new Meta($response); + } catch (NotAuthorizedException $nae) { + $headers_string = print_r($this->headers, true); + $this->logger->error("Error, not authorized: {$nae->getMessage()}"); + $this->logger->error("Headers: {$headers_string}"); + # Force re-auth + if (!$use_server_token) { + $this->logout(); + } + throw $nae; + } catch (PnutException $pe) { + $response_headers_string = print_r($this->headers, true); + $request_headers_string = print_r($headers, true); + $parameters_string = print_r($parameters, true); + $this->logger->error("Error: {$pe->getMessage()}"); + $this->logger->error("Method: {$method}"); + $this->logger->error("Parameters: {$parameters_string}"); + $this->logger->error("Request headers: {$request_headers_string}"); + $this->logger->error("Response headers: {$response_headers_string}"); + throw $pe; + } - // look for errors - if (isset($response['error'])) { - if (is_array($response['error'])) { + // look for errors + if (isset($response['error'])) { + if (is_array($response['error'])) { + throw new PnutException( + $response['error']['message'], + $response['error']['code'] + ); + } else { + throw new PnutException($response['error']); + } + // look for response migration errors + } elseif (isset($response['meta'], $response['meta']['error_message'])) { + throw new PnutException( + $response['meta']['error_message'], + $response['meta']['code'] + ); + } + } + } + if ($http_status < 200 || $http_status >= 300) { + throw new HttpPnutException('HTTP error ' . $http_status); + } elseif (isset($response['meta'], $response['data'])) { + return $response['data']; + } elseif (isset($response['access_token'])) { + return $response; + } elseif (!empty($this->redirect_target)) { + return [$this->redirect_target]; + } else { throw new PnutException( - $response['error']['message'], - $response['error']['code'] + 'No response ' . + json_encode($response) . + ", http status: {$http_status}" ); - } else { - throw new PnutException($response['error']); - } - // look for response migration errors - } elseif ( - isset($response['meta'], $response['meta']['error_message']) - ) { - throw new PnutException( - $response['meta']['error_message'], - $response['meta']['code'] - ); } - } } - if ($http_status < 200 || $http_status >= 300) { - throw new HttpPnutException('HTTP error ' . $http_status); - } elseif (isset($response['meta'], $response['data'])) { - return $response['data']; - } elseif (isset($response['access_token'])) { - return $response; - } elseif (!empty($this->redirect_target)) { - return [$this->redirect_target]; - } else { - throw new PnutException( - 'No response ' . - json_encode($response) . - ", http status: ${http_status}" - ); + + public function post( + string $end_point, + array $parameters, + string $content_type = 'application/x-www-form-urlencoded' + ): array { + $method = $content_type === 'multipart/form-data' ? 'POST-RAW' : 'POST'; + return $this->makeRequest($method, $end_point, $parameters, $content_type); } - } - public function post( - string $end_point, - array $parameters, - string $content_type = 'application/x-www-form-urlencoded' - ): array { - $method = $content_type === 'multipart/form-data' ? 'POST-RAW' : 'POST'; - return $this->makeRequest($method, $end_point, $parameters, $content_type); - } - - public function postJson(string $end_point, array $parameters): array - { - return $this->post($end_point, $parameters, 'application/json'); - } - - public function get( - string $end_point, - array $parameters = [], - string $content_type = 'application/json', - bool $follow_redirect = true - ): array { - if (!empty($parameters)) { - $parsed = parse_url($end_point); - $separator = empty($parsed['query']) ? '?' : '&'; - $end_point .= $separator . http_build_query($parameters); - $parameters = []; + public function postJson(string $end_point, array $parameters): array + { + return $this->post($end_point, $parameters, 'application/json'); } - return $this->makeRequest( - 'get', - $end_point, - $parameters, - $content_type, - $follow_redirect - ); - } - public function getAuthURL($append_redirect_query_string = null) - { - $redirect_uri = $this->redirect_uri; - if (!empty($append_redirect_query_string)) { - $redirect_uri .= $append_redirect_query_string; + public function get( + string $end_point, + array $parameters = [], + string $content_type = 'application/json', + bool $follow_redirect = true + ): array { + if (!empty($parameters)) { + $parsed = parse_url($end_point); + $separator = empty($parsed['query']) ? '?' : '&'; + $end_point .= $separator . http_build_query($parameters); + $parameters = []; + } + return $this->makeRequest( + 'get', + $end_point, + $parameters, + $content_type, + $follow_redirect + ); + } + + public function getAuthURL($append_redirect_query_string = null) + { + $redirect_uri = $this->redirect_uri; + if (!empty($append_redirect_query_string)) { + $redirect_uri .= $append_redirect_query_string; + } + $url = + $this->auth_url . + '?client_id=' . + $this->client_id . + '&redirect_uri=' . + urlencode($redirect_uri) . + '&scope=' . + $this->needed_scope . + '&response_type=code'; + $this->logger->debug('Auth URL: ' . $url); + return $url; } - $url = - $this->auth_url . - '?client_id=' . - $this->client_id . - '&redirect_uri=' . - urlencode($redirect_uri) . - '&scope=' . - $this->needed_scope . - '&response_type=code'; - $this->logger->debug('Auth URL: ' . $url); - return $url; - } //TODO: Ping server and validate token - public function isAuthenticated( - bool $allow_server_token = false, - bool $skip_verify_token = false - ): bool { - $is_authenticated = - ($allow_server_token && !empty($this->server_token)) || - isset($this->access_token); - $log_str = $is_authenticated ? 'Authenticated' : 'Not authenticated'; - $this->logger->info( - "Checking auth status for app: {$this->app_name}: {$log_str}" - ); - if (isset($_SERVER['HTTP_REFERER'])) { - $this->logger->info( - 'Referrer: ' . ($_SERVER['HTTP_REFERER'] ?? 'Unknown') - ); - $_SESSION[$this->token_redirect_after_auth] = $_SERVER['HTTP_REFERER']; + public function isAuthenticated( + bool $allow_server_token = false, + bool $skip_verify_token = false + ): bool { + $is_authenticated = + ($allow_server_token && !empty($this->server_token)) || + isset($this->access_token); + $log_str = $is_authenticated ? 'Authenticated' : 'Not authenticated'; + $this->logger->info( + "Checking auth status for app: {$this->app_name}: {$log_str}" + ); + if (isset($_SERVER['HTTP_REFERER'])) { + $this->logger->info( + 'Referrer: ' . ($_SERVER['HTTP_REFERER'] ?? 'Unknown') + ); + $_SESSION[$this->token_redirect_after_auth] = $_SERVER['HTTP_REFERER']; + } + return $is_authenticated; } - return $is_authenticated; - } - public function authenticate(string $auth_code): bool - { - $this->logger->debug("Authenticating: {$auth_code}"); - $parameters = [ - 'client_id' => $this->client_id, - 'client_secret' => $this->client_secret, - 'code' => $auth_code, - 'redirect_uri' => $this->redirect_uri, - 'grant_type' => 'authorization_code', - ]; - $resp = $this->post( - '/oauth/access_token', - $parameters, - 'application/x-www-form-urlencoded' - ); + public function authenticate(string $auth_code): bool + { + $this->logger->debug("Authenticating: {$auth_code}"); + $parameters = [ + 'client_id' => $this->client_id, + 'client_secret' => $this->client_secret, + 'code' => $auth_code, + 'redirect_uri' => $this->redirect_uri, + 'grant_type' => 'authorization_code', + ]; + $resp = $this->post( + '/oauth/access_token', + $parameters, + 'application/x-www-form-urlencoded' + ); - if (empty($resp['access_token'])) { - $this->logger->error('No access token ' . json_encode($resp)); - return false; - } else { - $this->logger->debug('Received access token ' . $resp['access_token']); - $_SESSION[$this->token_session_key] = $resp['access_token']; - $this->logger->debug('Saved access token'); - $this->access_token = $resp['access_token']; - return true; + if (empty($resp['access_token'])) { + $this->logger->error('No access token ' . json_encode($resp)); + return false; + } else { + $this->logger->debug('Received access token ' . $resp['access_token']); + $_SESSION[$this->token_session_key] = $resp['access_token']; + $this->logger->debug('Saved access token'); + $this->access_token = $resp['access_token']; + return true; + } } - } - public function logout() - { - unset($_SESSION[$this->token_session_key]); - $this->access_token = null; - $this->current_user = null; - } + public function logout() + { + unset($_SESSION[$this->token_session_key]); + $this->access_token = null; + $this->current_user = null; + } // TODO - public function getPostsForUser(User $user, $count = null) - { - } + public function getPostsForUser(User $user, $count = null) + { + } // TODO - public function getPostsForUsername(string $username, int $count = 0) - { - /* - if(!$this->isAuthenticated()) { - throw new NotAuthorizedException("Cannot retrieve posts, "); + public function getPostsForUsername(string $username, int $count = 0) + { + /* + if(!$this->isAuthenticated()) { + throw new NotAuthorizedException("Cannot retrieve posts, "); + } + */ + if (mb_substr($username, 0, 1) !== '@') { + $username = '@' . $username; + } + $params = []; + if ($count > 0) { + $params['count'] = $count; + } + $posts = $this->get('/users/' . $username . '/posts', $params); + $p = []; + foreach ($posts as $post) { + $p[] = new Post($post, $this); + } + var_dump($p); } - */ - if (mb_substr($username, 0, 1) !== '@') { - $username = '@' . $username; - } - $params = []; - if ($count > 0) { - $params['count'] = $count; - } - $posts = $this->get('/users/' . $username . '/posts', $params); - $p = []; - foreach ($posts as $post) { - $p[] = new Post($post, $this); - } - var_dump($p); - } - public function searchPosts( - array $args, - bool $order_by_id = true, - int $count = 0 - ): array { - if ($order_by_id) { - $args['order'] = 'id'; + public function searchPosts( + array $args, + bool $order_by_id = true, + int $count = 0 + ): array { + if ($order_by_id) { + $args['order'] = 'id'; + } + if ($count > 0) { + $args['count'] = $count; + } + $post_obj = []; + /* + * Stop fetching if: + * - count($posts) >= $count and $count != 0 + * - OR: meta['more'] is false + */ + do { + $posts = $this->get('/posts/search', $args); + if ($this->meta->more) { + $args['before_id'] = $this->meta->min_id; + } + foreach ($posts as $post) { + $post_obj[] = new Post($post, $this); + } + } while ($this->meta != null && $this->meta->more && (count($post_obj) < $count || $count !== 0)); + return $post_obj; } - if ($count > 0) { - $args['count'] = $count; - } - $post_obj = []; - /* - * Stop fetching if: - * - count($posts) >= $count and $count != 0 - * - OR: meta['more'] is false - */ - do { - $posts = $this->get('/posts/search', $args); - if ($this->meta->more) { - $args['before_id'] = $this->meta->min_id; - } - foreach ($posts as $post) { - $post_obj[] = new Post($post, $this); - } - } while ( - $this->meta != null && - $this->meta->more && - (count($post_obj) < $count || $count !== 0) - ); - return $post_obj; - } // TODO Maybe support additional polls? - public function getPollsFromUser(int $user_id, array $params = []): array - { - $parameters = [ - 'raw_types' => 'io.pnut.core.poll-notice', - 'creator_id' => $user_id, - 'include_deleted' => false, - 'include_client' => false, - 'include_counts' => false, - 'include_html' => false, - 'include_mention_posts' => false, - 'include_copy_mentions' => false, - 'include_post_raw' => true, - ]; - foreach ($params as $param => $value) { - $parameters[$param] = $value; - } - $response = $this->get('posts/search', $parameters); - if (count($response) === 0) { - return []; - } - $polls = []; - foreach ($response as $post) { - if (!empty($post['raw'])) { - foreach ($post['raw'] as $raw) { - if (Poll::$notice_type === $raw['type']) { - $polls[] = $this->getPoll($raw['value']['poll_id']); - } + public function getPollsFromUser(int $user_id, array $params = []): array + { + $parameters = [ + 'raw_types' => 'io.pnut.core.poll-notice', + 'creator_id' => $user_id, + 'include_deleted' => false, + 'include_client' => false, + 'include_counts' => false, + 'include_html' => false, + 'include_mention_posts' => false, + 'include_copy_mentions' => false, + 'include_post_raw' => true, + ]; + foreach ($params as $param => $value) { + $parameters[$param] = $value; } - } - } - return $polls; - } - - private function getPollFromEndpoint(string $endpoint, array $args = []): Poll - { - try { - $res = $this->get($endpoint, $args); - return new Poll($res, $this); - } catch (NotSupportedPollException $e) { - $this->logger->error('Poll not supported: ' . json_encode($res)); - throw $e; - } catch (HttpPnutForbiddenException $fe) { - $this->logger->error('Poll token required and not provided!'); - throw new PollAccessRestrictedException(); - } catch (NotAuthorizedException $nauth) { - $this->logger->error('Not authorized when fetching poll'); - throw new PollAccessRestrictedException(); - } - } - - public function getPollFromToken( - int $poll_id, - ?string $poll_token = null - ): Poll { - $poll_token_query = empty($poll_token) ? '' : '?poll_token=' . $poll_token; - return $this->getPollFromEndpoint('/polls/' . $poll_id . $poll_token_query); - } - - public function getPoll(int $poll_id, ?string $poll_token = null): Poll - { - if (empty($poll_token)) { - return $this->getPollFromToken($poll_id, $poll_token); + $response = $this->get('posts/search', $parameters); + if (count($response) === 0) { + return []; + } + $polls = []; + foreach ($response as $post) { + if (!empty($post['raw'])) { + foreach ($post['raw'] as $raw) { + if (Poll::$notice_type === $raw['type']) { + $polls[] = $this->getPoll($raw['value']['poll_id']); + } + } + } + } + return $polls; } - $this->logger->debug('Poll token provided'); - $re = - '/((http(s)?:\/\/)?((posts)|(beta))\.pnut\.io\/(@.*\/)?)?(?(1)|^)(?\d+)/$'; - preg_match($re, $poll_token, $matches); - if (!empty($matches['postid'])) { - $this->logger->debug('Poll token is post ' . $matches['postid']); - $post_id = (int) $matches['postid']; - $args = [ - 'include_raw' => true, - 'include_counts' => false, - 'include_html' => false, - 'include_post_raw' => true, - ]; - return $this->getPollFromEndpoint('/posts/' . $post_id, $arg); - } else { - $this->logger->debug('Poll token seems to be an actual poll token'); - return $this->getPollFromToken($poll_id, $poll_token); - } - } - - public function getPolls(array $ids = []): array - { - $this->logger->debug('getPolls'); - $endpoint = ''; - $params = []; - if (!empty($ids)) { - $endpoint = '/polls?ids=' . implode(',', $ids); - } else { - $poll_types = Poll::$poll_types; - $poll_types[] = Poll::$notice_type; - $poll_types_param = implode(',', $poll_types); - $this->logger->info( - 'No list of polls provided, using post search for poll types: ' . - $poll_types_param - ); - $endpoint = '/posts/search?raw_types=' . $poll_types_param; - $params = [ - 'include_raw' => true, - 'include_counts' => false, - 'include_html' => false, - 'include_post_raw' => true, - ]; - } - try { - $res = $this->get($endpoint, $params); - $this->logger->debug(json_encode($res)); - $polls = []; - foreach ($res as $poll_resp) { - $polls[] = new Poll($poll_resp, $this); - } - return $polls; - } catch (NotSupportedPollException $e) { - $this->logger->error('Poll not supported: ' . json_encode($res)); - throw $e; - } catch (HttpPnutForbiddenException $fe) { - $this->logger->error('Poll token required and not provided!'); - throw new PollAccessRestrictedException(); - } catch (NotAuthorizedException $nauth) { - $this->logger->error('Not authorized when fetching poll'); - throw new PollAccessRestrictedException(); - } - } - - public function voteInPoll( - int $poll_id, - array $options, - ?string $poll_token - ): Poll { - $params = [ - 'positions' => $options, - ]; - if (!empty($poll_token)) { - $params['poll_token'] = $poll_token; - } - $this->logger->debug(json_encode($params)); - $resp = $this->makeRequest( - 'PUT', - "/polls/$poll_id/response", - $params, - 'application/json' - ); - #TODO: Use getPollFromEndpoint - return new Poll($resp, $this); - } - - public function getAuthorizedUser(): User - { - $this->current_user ??= new User($this->get('/users/me'), $this); - return $this->current_user; - } - - public function getUser(int $user_id, array $args = []) - { - return new User($this->get('/users/' . $user_id, $args), $this); - } - - public function getPost(int $post_id, array $args = []) - { - if (!empty($this->access_token)) { - #$this->logger->info("AT:".$this->access_token); - } else { - $this->logger->info('No AT'); + private function getPollFromEndpoint(string $endpoint, array $args = []): Poll + { + try { + $res = $this->get($endpoint, $args); + return new Poll($res, $this); + } catch (NotSupportedPollException $e) { + $this->logger->error('Poll not supported: ' . json_encode($res)); + throw $e; + } catch (HttpPnutForbiddenException $fe) { + $this->logger->error('Poll token required and not provided!'); + throw new PollAccessRestrictedException(); + } catch (NotAuthorizedException $nauth) { + $this->logger->error('Not authorized when fetching poll'); + throw new PollAccessRestrictedException(); + } } - // Remove in production again - try { - $p = new Post($this->get('/posts/' . $post_id, $args), $this); - $this->logger->debug(json_encode($p)); - return $p; - } catch (NotAuthorizedException $nae) { - $this->logger->warning( - 'NotAuthorizedException when getting post, trying without access token' - ); - //try again not authorized - $r = $this->makeRequest( - '/get', - '/posts/' . $post_id, - $args, - 'application/json', - true - ); - return new Post($r, $this); - } - } - - public function getAvatar(int $user_id, array $args = []): string - { - //get returns an array with the url at idx 0 - $r = null; - try { - $r = $this->get( - '/users/' . $user_id . '/avatar', - $args, - 'application/json', - false - ); - } catch (HttpPnutRedirectException $re) { - return $re->response; - } - $this->logger->error( - 'Could not fetch avatar: No redirection! ' . json_encode($r) - ); - throw new PnutException('Could not fetch avatar: No redirection!'); - } - - public function getAvatarUrl( - int $user_id, - ?int $width = null, - ?int $height = null - ): string { - //get returns an array with the url at idx 0 - $args = []; - if (!empty($width)) { - $args['w'] = $width; - } - if (!empty($height)) { - $args['h'] = $height; - } - return $this->getAvatar($user_id, $args); - } - - public function updateAvatar( - string $file_path, - ?string $filename = null, - ?string $content_type = null - ): User { - if (empty($content_type)) { - $content_type = mime_content_type($file_path); - } - if (empty($filename)) { - $filename = basename($file_path); + public function getPollFromToken( + int $poll_id, + ?string $poll_token = null + ): Poll { + $poll_token_query = empty($poll_token) ? '' : '?poll_token=' . $poll_token; + return $this->getPollFromEndpoint('/polls/' . $poll_id . $poll_token_query); } - $cf = new \CURLFile($file_path, $content_type, $filename); - $parameters = ['avatar' => $cf]; - return new User( - $this->post('/users/me/avatar', $parameters, 'multipart/form-data'), - $this - ); - } + public function getPoll(int $poll_id, ?string $poll_token = null): Poll + { + if (empty($poll_token)) { + return $this->getPollFromToken($poll_id, $poll_token); + } - public function updateAvatarFromUploaded($uploaded_file): User - { - $filename = $uploaded_file['name']; - $filedata = $uploaded_file['tmp_name']; - $filetype = $uploaded_file['type']; - return $this->updateAvatar($filedata, $filename, $filetype); - } - - public function replyToPost( - string $text, - int $reply_to, - bool $is_nsfw = false, - bool $auto_crop = false, - array $raw = [] - ): Post { - return createPost($text, $reply_to, $is_nsfw, $auto_crop, $raw); - } - - public function createPost( - string $text, - bool $is_nsfw = false, - bool $auto_crop = false, - ?int $reply_to = null, - array $raw = [] - ): Post { - $text = $auto_crop ? substr($text, 0, $this->getMaxPostLength()) : $text; - $parameters = [ - 'text' => $text, - 'reply_to' => $reply_to, - 'is_nsfw' => $is_nsfw, - ]; - if (!empty($raw)) { - $parameters['raw'] = $parameters; - } - return new Post( - $this->post('/posts', $parameters, 'application/json'), - $this - ); - } - - public function createPostWithParameters( - string $text, - array $params = [], - bool $auto_crop = false - ): Post { - $text = $auto_crop ? substr($text, 0, $this->getMaxPostLength()) : $text; - $parameters = [ - 'text' => $text, - ]; - $parameters = array_merge($parameters, $params); - $this->logger->debug('Post with params'); - $this->logger->debug(json_encode($parameters)); - return new Post( - $this->post('/posts', $parameters, 'application/json'), - $this - ); - } - - public function getChannel(int $channel_id): Channel - { - # Always include channel raw, it contains the channel name - $parameters = [ - 'include_channel_raw' => true, - ]; - return new Channel( - $this->get('/channels/' . $channel_id, $parameters), - $this - ); - } - - public function getSubscribedChannels( - bool $include_pms = true, - bool $include_channels = true - ): array { - # Always include channel raw, it contains the channel name - $channel_types = []; - if ($include_pms) { - $channel_types[] = 'io.pnut.core.pm'; - } - if ($include_channels) { - $channel_types[] = 'io.pnut.core.chat'; + $this->logger->debug('Poll token provided'); + $re = + '/((http(s)?:\/\/)?((posts)|(beta))\.pnut\.io\/(@.*\/)?)?(?(1)|^)(?\d+)/$'; + preg_match($re, $poll_token, $matches); + if (!empty($matches['postid'])) { + $this->logger->debug('Poll token is post ' . $matches['postid']); + $post_id = (int) $matches['postid']; + $args = [ + 'include_raw' => true, + 'include_counts' => false, + 'include_html' => false, + 'include_post_raw' => true, + ]; + return $this->getPollFromEndpoint('/posts/' . $post_id, $args); + } else { + $this->logger->debug('Poll token seems to be an actual poll token'); + return $this->getPollFromToken($poll_id, $poll_token); + } } - $parameters = [ - 'include_channel_raw' => true, - 'channel_types' => implode(',', $channel_types), - ]; - $channels = []; - $resp = $this->get('/users/me/channels/subscribed', $parameters); - foreach ($resp as $r) { - $channels[] = new Channel($r, $this); + public function getPolls(array $ids = []): array + { + $this->logger->debug('getPolls'); + $endpoint = ''; + $params = []; + if (!empty($ids)) { + $endpoint = '/polls?ids=' . implode(',', $ids); + } else { + $poll_types = Poll::$poll_types; + $poll_types[] = Poll::$notice_type; + $poll_types_param = implode(',', $poll_types); + $this->logger->info( + 'No list of polls provided, using post search for poll types: ' . + $poll_types_param + ); + $endpoint = '/posts/search?raw_types=' . $poll_types_param; + $params = [ + 'include_raw' => true, + 'include_counts' => false, + 'include_html' => false, + 'include_post_raw' => true, + ]; + } + try { + $res = $this->get($endpoint, $params); + $this->logger->debug(json_encode($res)); + $polls = []; + foreach ($res as $poll_resp) { + $polls[] = new Poll($poll_resp, $this); + } + return $polls; + } catch (NotSupportedPollException $e) { + $this->logger->error('Poll not supported: ' . json_encode($res)); + throw $e; + } catch (HttpPnutForbiddenException) { + $this->logger->error('Poll token required and not provided!'); + throw new PollAccessRestrictedException(); + } catch (NotAuthorizedException) { + $this->logger->error('Not authorized when fetching poll'); + throw new PollAccessRestrictedException(); + } } - return $channels; - } - protected function fetchPnutSystemConfig() - { - $config = $this->get('/sys/config'); - self::$POST_MAX_LENGTH = $config['post']['max_length']; - //self::$POST_MAX_LENGTH_REPOST = $config['post']['repost_max_length']; - self::$POST_MAX_LENGTH_REPOST = self::$POST_MAX_LENGTH; - self::$POST_SECONDS_BETWEEN_DUPLICATES = - $config['post']['seconds_between_duplicates']; - self::$MESSAGE_MAX_LENGTH = $config['message']['max_length']; - self::$RAW_MAX_LENGTH = $config['raw']['max_length']; - self::$USER_DESCRIPTION_MAX_LENGTH = - $config['user']['description_max_length']; - self::$USER_USERNAME_MAX_LENGTH = $config['user']['username_max_length']; - $this->logger->info('-----------Pnut API config-----------'); - $this->logger->info(''); - $this->logger->info('Max post length: ' . self::$POST_MAX_LENGTH); - $this->logger->info('Max repost length: ' . self::$POST_MAX_LENGTH_REPOST); - $this->logger->info( - 'Seconds between post duplicates: ' . - self::$POST_SECONDS_BETWEEN_DUPLICATES - ); - $this->logger->info('Max raw length: ' . self::$RAW_MAX_LENGTH); - $this->logger->info( - 'Max user description length: ' . self::$USER_DESCRIPTION_MAX_LENGTH - ); - $this->logger->info( - 'Max username length: ' . self::$USER_USERNAME_MAX_LENGTH - ); - $this->logger->info('--------------------------------------'); - } - - public function getMaxPostLength(): int - { - if (empty(self::$POST_MAX_LENGTH)) { - $this->fetchPnutSystemConfig(); + public function voteInPoll( + int $poll_id, + array $options, + ?string $poll_token + ): Poll { + $params = [ + 'positions' => $options, + ]; + if (!empty($poll_token)) { + $params['poll_token'] = $poll_token; + } + $this->logger->debug(json_encode($params)); + $resp = $this->makeRequest( + 'PUT', + "/polls/$poll_id/response", + $params, + 'application/json' + ); + #TODO: Use getPollFromEndpoint + return new Poll($resp, $this); } - return self::$POST_MAX_LENGTH; - } - public function authenticateServerToken() - { - $token = $this->getServerToken(); - $this->server_token = $token; - $this->logger->info('ST:' . $this->server_token); - } - - protected function getServerToken(): string - { - $this->logger->info('Requesting server access token from pnut'); - $params = [ - 'client_id' => $this->client_id, - 'client_secret' => $this->client_secret, - 'grant_type' => 'client_credentials', - ]; - $resp = $this->post('/oauth/access_token', $params); - if (!empty($resp['access_token'])) { - $this->logger->info(json_encode($resp)); - return $resp['access_token']; - } else { - throw new PnutException( - 'Error retrieving app access token: ' . json_encode($resp) - ); + public function getAuthorizedUser(): User + { + $this->current_user ??= new User($this->get('/users/me'), $this); + return $this->current_user; } - } - public function getAccessToken(): string - { - return $this->access_token; - } + public function getUser(int $user_id, array $args = []) + { + return new User($this->get('/users/' . $user_id, $args), $this); + } + + public function getPost(int $post_id, array $args = []) + { + if (!empty($this->access_token)) { + #$this->logger->info("AT:".$this->access_token); + } else { + $this->logger->info('No AT'); + } + + // Remove in production again + try { + $p = new Post($this->get('/posts/' . $post_id, $args), $this); + $this->logger->debug(json_encode($p)); + return $p; + } catch (NotAuthorizedException) { + $this->logger->warning( + 'NotAuthorizedException when getting post, trying without access token' + ); + //try again not authorized + $r = $this->makeRequest( + '/get', + '/posts/' . $post_id, + $args, + 'application/json', + true + ); + return new Post($r, $this); + } + } + + public function getAvatar(int $user_id, array $args = []): string + { + //get returns an array with the url at idx 0 + $r = null; + try { + $r = $this->get( + '/users/' . $user_id . '/avatar', + $args, + 'application/json', + false + ); + } catch (HttpPnutRedirectException $re) { + return $re->response; + } + $this->logger->error( + 'Could not fetch avatar: No redirection! ' . json_encode($r) + ); + throw new PnutException('Could not fetch avatar: No redirection!'); + } + + public function getAvatarUrl( + int $user_id, + ?int $width = null, + ?int $height = null + ): string { + //get returns an array with the url at idx 0 + $args = []; + if (!empty($width)) { + $args['w'] = $width; + } + if (!empty($height)) { + $args['h'] = $height; + } + return $this->getAvatar($user_id, $args); + } + + public function updateAvatar( + string $file_path, + ?string $filename = null, + ?string $content_type = null + ): User { + if (empty($content_type)) { + $content_type = mime_content_type($file_path); + } + if (empty($filename)) { + $filename = basename($file_path); + } + + $cf = new \CURLFile($file_path, $content_type, $filename); + $parameters = ['avatar' => $cf]; + return new User( + $this->post('/users/me/avatar', $parameters, 'multipart/form-data'), + $this + ); + } + + public function updateAvatarFromUploaded($uploaded_file): User + { + $filename = $uploaded_file['name']; + $filedata = $uploaded_file['tmp_name']; + $filetype = $uploaded_file['type']; + return $this->updateAvatar($filedata, $filename, $filetype); + } + + public function replyToPost( + string $text, + int $reply_to, + bool $is_nsfw = false, + bool $auto_crop = false, + array $raw = [] + ): Post { + return $this->createPost($text, $reply_to, $is_nsfw, $auto_crop, $raw); + } + + public function createPost( + string $text, + bool $is_nsfw = false, + bool $auto_crop = false, + ?int $reply_to = null, + array $raw = [] + ): Post { + $text = $auto_crop ? substr($text, 0, $this->getMaxPostLength()) : $text; + $parameters = [ + 'text' => $text, + 'reply_to' => $reply_to, + 'is_nsfw' => $is_nsfw, + ]; + if (!empty($raw)) { + $parameters['raw'] = $parameters; + } + return new Post( + $this->post('/posts', $parameters, 'application/json'), + $this + ); + } + + public function createPostWithParameters( + string $text, + array $params = [], + bool $auto_crop = false + ): Post { + $text = $auto_crop ? substr($text, 0, $this->getMaxPostLength()) : $text; + $parameters = [ + 'text' => $text, + ]; + $parameters = array_merge($parameters, $params); + $this->logger->debug('Post with params'); + $this->logger->debug(json_encode($parameters)); + return new Post( + $this->post('/posts', $parameters, 'application/json'), + $this + ); + } + + public function getChannel(int $channel_id): Channel + { + # Always include channel raw, it contains the channel name + $parameters = [ + 'include_channel_raw' => true, + ]; + return new Channel( + $this->get('/channels/' . $channel_id, $parameters), + $this + ); + } + + public function getSubscribedChannels( + bool $include_pms = true, + bool $include_channels = true + ): array { + # Always include channel raw, it contains the channel name + $channel_types = []; + if ($include_pms) { + $channel_types[] = 'io.pnut.core.pm'; + } + if ($include_channels) { + $channel_types[] = 'io.pnut.core.chat'; + } + + $parameters = [ + 'include_channel_raw' => true, + 'channel_types' => implode(',', $channel_types), + ]; + $channels = []; + $resp = $this->get('/users/me/channels/subscribed', $parameters); + foreach ($resp as $r) { + $channels[] = new Channel($r, $this); + } + return $channels; + } + + protected function fetchPnutSystemConfig() + { + $config = $this->get('/sys/config'); + self::$POST_MAX_LENGTH = $config['post']['max_length']; + //self::$POST_MAX_LENGTH_REPOST = $config['post']['repost_max_length']; + self::$POST_MAX_LENGTH_REPOST = self::$POST_MAX_LENGTH; + self::$POST_SECONDS_BETWEEN_DUPLICATES = + $config['post']['seconds_between_duplicates']; + self::$MESSAGE_MAX_LENGTH = $config['message']['max_length']; + self::$RAW_MAX_LENGTH = $config['raw']['max_length']; + self::$USER_DESCRIPTION_MAX_LENGTH = + $config['user']['description_max_length']; + self::$USER_USERNAME_MAX_LENGTH = $config['user']['username_max_length']; + $this->logger->info('-----------Pnut API config-----------'); + $this->logger->info(''); + $this->logger->info('Max post length: ' . self::$POST_MAX_LENGTH); + $this->logger->info('Max repost length: ' . self::$POST_MAX_LENGTH_REPOST); + $this->logger->info( + 'Seconds between post duplicates: ' . + self::$POST_SECONDS_BETWEEN_DUPLICATES + ); + $this->logger->info('Max raw length: ' . self::$RAW_MAX_LENGTH); + $this->logger->info( + 'Max user description length: ' . self::$USER_DESCRIPTION_MAX_LENGTH + ); + $this->logger->info( + 'Max username length: ' . self::$USER_USERNAME_MAX_LENGTH + ); + $this->logger->info('--------------------------------------'); + } + + public function getMaxPostLength(): int + { + if (empty(self::$POST_MAX_LENGTH)) { + $this->fetchPnutSystemConfig(); + } + return self::$POST_MAX_LENGTH; + } + + public function authenticateServerToken() + { + $token = $this->getServerToken(); + $this->server_token = $token; + $this->logger->info('ST:' . $this->server_token); + } + + protected function getServerToken(): string + { + $this->logger->info('Requesting server access token from pnut'); + $params = [ + 'client_id' => $this->client_id, + 'client_secret' => $this->client_secret, + 'grant_type' => 'client_credentials', + ]; + $resp = $this->post('/oauth/access_token', $params); + if (!empty($resp['access_token'])) { + $this->logger->info(json_encode($resp)); + return $resp['access_token']; + } else { + throw new PnutException( + 'Error retrieving app access token: ' . json_encode($resp) + ); + } + } + + public function getAccessToken(): string + { + return $this->access_token; + } } diff --git a/src/Meta.php b/src/Meta.php index d6a3032..fe99bc8 100644 --- a/src/Meta.php +++ b/src/Meta.php @@ -9,43 +9,43 @@ use APnutI\Exceptions\HttpPnutForbiddenException; class Meta { - public bool $more = false; - public ?int $max_id = null; - public ?int $min_id = null; - public ?int $code = -1; + public bool $more = false; + public ?int $max_id = null; + public ?int $min_id = null; + public ?int $code = -1; - public function __construct(array $json) - { - if (empty($json['meta'])) { - return; + public function __construct(array $json) + { + if (empty($json['meta'])) { + return; + } + $meta = (array)$json['meta']; + if (!empty($meta['more'])) { + $this->more = (bool)$meta['more']; + } + if (!empty($meta['max_id'])) { + $this->max_id = (int)$meta['max_id']; + } + if (!empty($meta['min_id'])) { + $this->min_id = (int)$meta['min_id']; + } + if (!empty($meta['code'])) { + $this->code = $meta['code']; + if ($this->code === 400) { + throw new PnutException($meta['error_message']); + } + if ($this->code === 401) { + throw new NotAuthorizedException($meta['error_message']); + } + if ($this->code === 403) { + throw new HttpPnutForbiddenException(); + } + if ($this->code === 404) { + throw new NotFoundException(); + } + if ($meta['code'] < 200 || $meta['code'] >= 300) { + throw new PnutException($meta['error_message']); + } + } } - $meta = (array)$json['meta']; - if (!empty($meta['more'])) { - $this->more = (bool)$meta['more']; - } - if (!empty($meta['max_id'])) { - $this->max_id = (int)$meta['max_id']; - } - if (!empty($meta['min_id'])) { - $this->min_id = (int)$meta['min_id']; - } - if (!empty($meta['code'])) { - $this->code = $meta['code']; - if ($this->code === 400) { - throw new PnutException($meta['error_message']); - } - if ($this->code === 401) { - throw new NotAuthorizedException($meta['error_message']); - } - if ($this->code === 403) { - throw new HttpPnutForbiddenException(); - } - if ($this->code === 404) { - throw new NotFoundException(); - } - if ($meta['code'] < 200 || $meta['code'] >= 300) { - throw new PnutException($meta['error_message']); - } - } - } }