updated poll parsing
This commit is contained in:
parent
7f0f8ac95b
commit
4ceeba7f4b
195
src/APnutI.php
195
src/APnutI.php
@ -48,7 +48,7 @@ class APnutI
|
|||||||
public string $app_name = 'Abstract API';
|
public string $app_name = 'Abstract API';
|
||||||
public LoggerInterface $logger;
|
public LoggerInterface $logger;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Error codes:
|
* Error codes:
|
||||||
* 3XX: Pnut error
|
* 3XX: Pnut error
|
||||||
* - 300: Cannot fetch post creator
|
* - 300: Cannot fetch post creator
|
||||||
@ -94,8 +94,8 @@ class APnutI
|
|||||||
$log_level = constant('Monolog\Logger::' . $log_level);
|
$log_level = constant('Monolog\Logger::' . $log_level);
|
||||||
}
|
}
|
||||||
$this->logger = empty($log_path)
|
$this->logger = empty($log_path)
|
||||||
? new NullLogger()
|
? new NullLogger()
|
||||||
: new Logger($this->app_name);
|
: new Logger($this->app_name);
|
||||||
$this->token_session_key = $this->app_name . 'access_token';
|
$this->token_session_key = $this->app_name . 'access_token';
|
||||||
$this->token_redirect_after_auth = $this->app_name . 'redirect_after_auth';
|
$this->token_redirect_after_auth = $this->app_name . 'redirect_after_auth';
|
||||||
if ($use_rotating_file_handler) {
|
if ($use_rotating_file_handler) {
|
||||||
@ -132,16 +132,16 @@ class APnutI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal function, parses out important information pnut.io adds
|
* Internal function, parses out important information pnut.io adds
|
||||||
* to the headers. Mostly taken from PHPnut
|
* to the headers. Mostly taken from PHPnut
|
||||||
*/
|
*/
|
||||||
protected function parseHeaders(string $response): string
|
protected function parseHeaders(string $response): string
|
||||||
{
|
{
|
||||||
// take out the headers
|
// take out the headers
|
||||||
// set internal variables
|
// set internal variables
|
||||||
// return the body/content
|
// return the body/content
|
||||||
/*$this->rate_limit = null;
|
/*$this->rate_limit = null;
|
||||||
$this->rate_limit_remaining = null;
|
$this->rate_limit_remaining = null;
|
||||||
$this->rate_limit_reset = null;*/
|
$this->rate_limit_reset = null;*/
|
||||||
$this->scopes = [];
|
$this->scopes = [];
|
||||||
@ -157,9 +157,9 @@ class APnutI
|
|||||||
} else {
|
} else {
|
||||||
$content = '';
|
$content = '';
|
||||||
}
|
}
|
||||||
// this is not a good way to parse http headers
|
// this is not a good way to parse http headers
|
||||||
// it will not (for example) take into account multiline 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
|
// but what we're looking for is pretty basic, so we can ignore those shortcomings
|
||||||
$this->headers = explode("\r\n", $headers);
|
$this->headers = explode("\r\n", $headers);
|
||||||
foreach ($this->headers as $header) {
|
foreach ($this->headers as $header) {
|
||||||
$header = explode(': ', $header, 2);
|
$header = explode(': ', $header, 2);
|
||||||
@ -210,13 +210,13 @@ class APnutI
|
|||||||
$headers = [];
|
$headers = [];
|
||||||
$use_server_token = false;
|
$use_server_token = false;
|
||||||
if ($method !== 'GET') {
|
if ($method !== 'GET') {
|
||||||
// if they passed an array, build a list of parameters from it
|
// if they passed an array, build a list of parameters from it
|
||||||
curl_setopt($ch, CURLOPT_POST, true);
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
if (is_array($parameters) && $method !== 'POST-RAW') {
|
if (is_array($parameters) && $method !== 'POST-RAW') {
|
||||||
$parameters =
|
$parameters =
|
||||||
$content_type === 'application/json'
|
$content_type === 'application/json'
|
||||||
? json_encode($parameters)
|
? json_encode($parameters)
|
||||||
: http_build_query($parameters);
|
: http_build_query($parameters);
|
||||||
}
|
}
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $parameters);
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $parameters);
|
||||||
$headers[] = 'Content-Type: ' . $content_type;
|
$headers[] = 'Content-Type: ' . $content_type;
|
||||||
@ -263,7 +263,7 @@ class APnutI
|
|||||||
if (!empty($response)) {
|
if (!empty($response)) {
|
||||||
$response = $this->parseHeaders($response);
|
$response = $this->parseHeaders($response);
|
||||||
if ($http_status == 302) {
|
if ($http_status == 302) {
|
||||||
#echo json_encode(preg_match_all('/^Location:(.*)$/mi', $response, $matches));
|
#echo json_encode(preg_match_all('/^Location:(.*)$/mi', $response, $matches));
|
||||||
$this->logger->debug("302 Redirect to {$this->redirect_target}");
|
$this->logger->debug("302 Redirect to {$this->redirect_target}");
|
||||||
throw new HttpPnutRedirectException($this->redirect_target);
|
throw new HttpPnutRedirectException($this->redirect_target);
|
||||||
}
|
}
|
||||||
@ -279,7 +279,7 @@ class APnutI
|
|||||||
$headers_string = print_r($this->headers, true);
|
$headers_string = print_r($this->headers, true);
|
||||||
$this->logger->error("Error, not authorized: {$nae->getMessage()}");
|
$this->logger->error("Error, not authorized: {$nae->getMessage()}");
|
||||||
$this->logger->error("Headers: {$headers_string}");
|
$this->logger->error("Headers: {$headers_string}");
|
||||||
# Force re-auth
|
# Force re-auth
|
||||||
if (!$use_server_token) {
|
if (!$use_server_token) {
|
||||||
$this->logout();
|
$this->logout();
|
||||||
}
|
}
|
||||||
@ -296,7 +296,7 @@ class APnutI
|
|||||||
throw $pe;
|
throw $pe;
|
||||||
}
|
}
|
||||||
|
|
||||||
// look for errors
|
// look for errors
|
||||||
if (isset($response['error'])) {
|
if (isset($response['error'])) {
|
||||||
if (is_array($response['error'])) {
|
if (is_array($response['error'])) {
|
||||||
throw new PnutException(
|
throw new PnutException(
|
||||||
@ -306,7 +306,7 @@ class APnutI
|
|||||||
} else {
|
} else {
|
||||||
throw new PnutException($response['error']);
|
throw new PnutException($response['error']);
|
||||||
}
|
}
|
||||||
// look for response migration errors
|
// look for response migration errors
|
||||||
} elseif (isset($response['meta'], $response['meta']['error_message'])) {
|
} elseif (isset($response['meta'], $response['meta']['error_message'])) {
|
||||||
throw new PnutException(
|
throw new PnutException(
|
||||||
$response['meta']['error_message'],
|
$response['meta']['error_message'],
|
||||||
@ -326,8 +326,8 @@ class APnutI
|
|||||||
} else {
|
} else {
|
||||||
throw new PnutException(
|
throw new PnutException(
|
||||||
'No response ' .
|
'No response ' .
|
||||||
json_encode($response) .
|
json_encode($response) .
|
||||||
", http status: {$http_status}"
|
", http status: {$http_status}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -374,26 +374,26 @@ class APnutI
|
|||||||
$redirect_uri .= $append_redirect_query_string;
|
$redirect_uri .= $append_redirect_query_string;
|
||||||
}
|
}
|
||||||
$url =
|
$url =
|
||||||
$this->auth_url .
|
$this->auth_url .
|
||||||
'?client_id=' .
|
'?client_id=' .
|
||||||
$this->client_id .
|
$this->client_id .
|
||||||
'&redirect_uri=' .
|
'&redirect_uri=' .
|
||||||
urlencode($redirect_uri) .
|
urlencode($redirect_uri) .
|
||||||
'&scope=' .
|
'&scope=' .
|
||||||
$this->needed_scope .
|
$this->needed_scope .
|
||||||
'&response_type=code';
|
'&response_type=code';
|
||||||
$this->logger->debug('Auth URL: ' . $url);
|
$this->logger->debug('Auth URL: ' . $url);
|
||||||
return $url;
|
return $url;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Ping server and validate token
|
//TODO: Ping server and validate token
|
||||||
public function isAuthenticated(
|
public function isAuthenticated(
|
||||||
bool $allow_server_token = false,
|
bool $allow_server_token = false,
|
||||||
bool $skip_verify_token = false
|
bool $skip_verify_token = false
|
||||||
): bool {
|
): bool {
|
||||||
$is_authenticated =
|
$is_authenticated =
|
||||||
($allow_server_token && !empty($this->server_token)) ||
|
($allow_server_token && !empty($this->server_token)) ||
|
||||||
isset($this->access_token);
|
isset($this->access_token);
|
||||||
$log_str = $is_authenticated ? 'Authenticated' : 'Not authenticated';
|
$log_str = $is_authenticated ? 'Authenticated' : 'Not authenticated';
|
||||||
$this->logger->info(
|
$this->logger->info(
|
||||||
"Checking auth status for app: {$this->app_name}: {$log_str}"
|
"Checking auth status for app: {$this->app_name}: {$log_str}"
|
||||||
@ -411,11 +411,11 @@ class APnutI
|
|||||||
{
|
{
|
||||||
$this->logger->debug("Authenticating: {$auth_code}");
|
$this->logger->debug("Authenticating: {$auth_code}");
|
||||||
$parameters = [
|
$parameters = [
|
||||||
'client_id' => $this->client_id,
|
'client_id' => $this->client_id,
|
||||||
'client_secret' => $this->client_secret,
|
'client_secret' => $this->client_secret,
|
||||||
'code' => $auth_code,
|
'code' => $auth_code,
|
||||||
'redirect_uri' => $this->redirect_uri,
|
'redirect_uri' => $this->redirect_uri,
|
||||||
'grant_type' => 'authorization_code',
|
'grant_type' => 'authorization_code',
|
||||||
];
|
];
|
||||||
$resp = $this->post(
|
$resp = $this->post(
|
||||||
'/oauth/access_token',
|
'/oauth/access_token',
|
||||||
@ -442,15 +442,15 @@ class APnutI
|
|||||||
$this->current_user = null;
|
$this->current_user = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
public function getPostsForUser(User $user, $count = null)
|
public function getPostsForUser(User $user, $count = null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
public function getPostsForUsername(string $username, int $count = 0)
|
public function getPostsForUsername(string $username, int $count = 0)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
if(!$this->isAuthenticated()) {
|
if(!$this->isAuthenticated()) {
|
||||||
throw new NotAuthorizedException("Cannot retrieve posts, ");
|
throw new NotAuthorizedException("Cannot retrieve posts, ");
|
||||||
}
|
}
|
||||||
@ -482,7 +482,7 @@ class APnutI
|
|||||||
$args['count'] = $count;
|
$args['count'] = $count;
|
||||||
}
|
}
|
||||||
$post_obj = [];
|
$post_obj = [];
|
||||||
/*
|
/*
|
||||||
* Stop fetching if:
|
* Stop fetching if:
|
||||||
* - count($posts) >= $count and $count != 0
|
* - count($posts) >= $count and $count != 0
|
||||||
* - OR: meta['more'] is false
|
* - OR: meta['more'] is false
|
||||||
@ -499,19 +499,19 @@ class APnutI
|
|||||||
return $post_obj;
|
return $post_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Maybe support additional polls?
|
// TODO Maybe support additional polls?
|
||||||
public function getPollsFromUser(int $user_id, array $params = []): array
|
public function getPollsFromUser(int $user_id, array $params = []): array
|
||||||
{
|
{
|
||||||
$parameters = [
|
$parameters = [
|
||||||
'raw_types' => 'io.pnut.core.poll-notice',
|
'raw_types' => 'io.pnut.core.poll-notice',
|
||||||
'creator_id' => $user_id,
|
'creator_id' => $user_id,
|
||||||
'include_deleted' => false,
|
'include_deleted' => false,
|
||||||
'include_client' => false,
|
'include_client' => false,
|
||||||
'include_counts' => false,
|
'include_counts' => false,
|
||||||
'include_html' => false,
|
'include_html' => false,
|
||||||
'include_mention_posts' => false,
|
'include_mention_posts' => false,
|
||||||
'include_copy_mentions' => false,
|
'include_copy_mentions' => false,
|
||||||
'include_post_raw' => true,
|
'include_post_raw' => true,
|
||||||
];
|
];
|
||||||
foreach ($params as $param => $value) {
|
foreach ($params as $param => $value) {
|
||||||
$parameters[$param] = $value;
|
$parameters[$param] = $value;
|
||||||
@ -524,8 +524,23 @@ class APnutI
|
|||||||
foreach ($response as $post) {
|
foreach ($response as $post) {
|
||||||
if (!empty($post['raw'])) {
|
if (!empty($post['raw'])) {
|
||||||
foreach ($post['raw'] as $raw) {
|
foreach ($post['raw'] as $raw) {
|
||||||
if (Poll::$notice_type === $raw['type']) {
|
if (!empty($raw[Poll::$notice_type])) {
|
||||||
$polls[] = $this->getPoll($raw['value']['poll_id']);
|
try {
|
||||||
|
$this->logger->debug('Parsing poll from raw');
|
||||||
|
$polls[] = new Poll($raw, $this);
|
||||||
|
} catch (NotSupportedPollException) {
|
||||||
|
$this->logger->warning('Parsing poll from raw failed. Loading from poll id');
|
||||||
|
$polls[] = $this->getPoll($raw[Poll::$notice_type]['poll_id']);
|
||||||
|
}
|
||||||
|
// if (empty($raw[Poll::$notice_type]['prompt'])) {
|
||||||
|
// $polls[] = $this->getPoll($raw[Poll::$notice_type]['poll_id']);
|
||||||
|
// } else {
|
||||||
|
// /*$poll_parsing_data = [
|
||||||
|
// 'type' => Poll::$notice_type,
|
||||||
|
// 'value' => $raw[Poll::$notice_type]
|
||||||
|
// ];*/
|
||||||
|
// $polls[] = new Poll($raw, $this);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -542,10 +557,10 @@ class APnutI
|
|||||||
$this->logger->error('Poll not supported: ' . json_encode($res));
|
$this->logger->error('Poll not supported: ' . json_encode($res));
|
||||||
throw $e;
|
throw $e;
|
||||||
} catch (HttpPnutForbiddenException $fe) {
|
} catch (HttpPnutForbiddenException $fe) {
|
||||||
$this->logger->error('Poll token required and not provided!');
|
$this->logger->error('Poll token required and not provided!', ['ex' => $fe]);
|
||||||
throw new PollAccessRestrictedException();
|
throw new PollAccessRestrictedException();
|
||||||
} catch (NotAuthorizedException $nauth) {
|
} catch (NotAuthorizedException $nauth) {
|
||||||
$this->logger->error('Not authorized when fetching poll');
|
$this->logger->error('Not authorized when fetching poll', ['ex' => $nauth]);
|
||||||
throw new PollAccessRestrictedException();
|
throw new PollAccessRestrictedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -566,16 +581,16 @@ class APnutI
|
|||||||
|
|
||||||
$this->logger->debug('Poll token provided');
|
$this->logger->debug('Poll token provided');
|
||||||
$re =
|
$re =
|
||||||
'/((http(s)?:\/\/)?((posts)|(beta))\.pnut\.io\/(@.*\/)?)?(?(1)|^)(?<postid>\d+)/$';
|
'/((http(s)?:\/\/)?((posts)|(beta))\.pnut\.io\/(@.*\/)?)?(?(1)|^)(?<postid>\d+)/$';
|
||||||
preg_match($re, $poll_token, $matches);
|
preg_match($re, $poll_token, $matches);
|
||||||
if (!empty($matches['postid'])) {
|
if (!empty($matches['postid'])) {
|
||||||
$this->logger->debug('Poll token is post ' . $matches['postid']);
|
$this->logger->debug('Poll token is post ' . $matches['postid']);
|
||||||
$post_id = (int) $matches['postid'];
|
$post_id = (int) $matches['postid'];
|
||||||
$args = [
|
$args = [
|
||||||
'include_raw' => true,
|
'include_raw' => true,
|
||||||
'include_counts' => false,
|
'include_counts' => false,
|
||||||
'include_html' => false,
|
'include_html' => false,
|
||||||
'include_post_raw' => true,
|
'include_post_raw' => true,
|
||||||
];
|
];
|
||||||
return $this->getPollFromEndpoint('/posts/' . $post_id, $args);
|
return $this->getPollFromEndpoint('/posts/' . $post_id, $args);
|
||||||
} else {
|
} else {
|
||||||
@ -597,14 +612,14 @@ class APnutI
|
|||||||
$poll_types_param = implode(',', $poll_types);
|
$poll_types_param = implode(',', $poll_types);
|
||||||
$this->logger->info(
|
$this->logger->info(
|
||||||
'No list of polls provided, using post search for poll types: ' .
|
'No list of polls provided, using post search for poll types: ' .
|
||||||
$poll_types_param
|
$poll_types_param
|
||||||
);
|
);
|
||||||
$endpoint = '/posts/search?raw_types=' . $poll_types_param;
|
$endpoint = '/posts/search?raw_types=' . $poll_types_param;
|
||||||
$params = [
|
$params = [
|
||||||
'include_raw' => true,
|
'include_raw' => true,
|
||||||
'include_counts' => false,
|
'include_counts' => false,
|
||||||
'include_html' => false,
|
'include_html' => false,
|
||||||
'include_post_raw' => true,
|
'include_post_raw' => true,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -633,7 +648,7 @@ class APnutI
|
|||||||
?string $poll_token
|
?string $poll_token
|
||||||
): Poll {
|
): Poll {
|
||||||
$params = [
|
$params = [
|
||||||
'positions' => $options,
|
'positions' => $options,
|
||||||
];
|
];
|
||||||
if (!empty($poll_token)) {
|
if (!empty($poll_token)) {
|
||||||
$params['poll_token'] = $poll_token;
|
$params['poll_token'] = $poll_token;
|
||||||
@ -663,12 +678,12 @@ class APnutI
|
|||||||
public function getPost(int $post_id, array $args = [])
|
public function getPost(int $post_id, array $args = [])
|
||||||
{
|
{
|
||||||
if (!empty($this->access_token)) {
|
if (!empty($this->access_token)) {
|
||||||
#$this->logger->info("AT:".$this->access_token);
|
#$this->logger->info("AT:".$this->access_token);
|
||||||
} else {
|
} else {
|
||||||
$this->logger->info('No AT');
|
$this->logger->info('No AT');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove in production again
|
// Remove in production again
|
||||||
try {
|
try {
|
||||||
$p = new Post($this->get('/posts/' . $post_id, $args), $this);
|
$p = new Post($this->get('/posts/' . $post_id, $args), $this);
|
||||||
$this->logger->debug(json_encode($p));
|
$this->logger->debug(json_encode($p));
|
||||||
@ -677,7 +692,7 @@ class APnutI
|
|||||||
$this->logger->warning(
|
$this->logger->warning(
|
||||||
'NotAuthorizedException when getting post, trying without access token'
|
'NotAuthorizedException when getting post, trying without access token'
|
||||||
);
|
);
|
||||||
//try again not authorized
|
//try again not authorized
|
||||||
$r = $this->makeRequest(
|
$r = $this->makeRequest(
|
||||||
'/get',
|
'/get',
|
||||||
'/posts/' . $post_id,
|
'/posts/' . $post_id,
|
||||||
@ -691,7 +706,7 @@ class APnutI
|
|||||||
|
|
||||||
public function getAvatar(int $user_id, array $args = []): string
|
public function getAvatar(int $user_id, array $args = []): string
|
||||||
{
|
{
|
||||||
//get returns an array with the url at idx 0
|
//get returns an array with the url at idx 0
|
||||||
$r = null;
|
$r = null;
|
||||||
try {
|
try {
|
||||||
$r = $this->get(
|
$r = $this->get(
|
||||||
@ -714,7 +729,7 @@ class APnutI
|
|||||||
?int $width = null,
|
?int $width = null,
|
||||||
?int $height = null
|
?int $height = null
|
||||||
): string {
|
): string {
|
||||||
//get returns an array with the url at idx 0
|
//get returns an array with the url at idx 0
|
||||||
$args = [];
|
$args = [];
|
||||||
if (!empty($width)) {
|
if (!empty($width)) {
|
||||||
$args['w'] = $width;
|
$args['w'] = $width;
|
||||||
@ -772,9 +787,9 @@ class APnutI
|
|||||||
): Post {
|
): Post {
|
||||||
$text = $auto_crop ? substr($text, 0, $this->getMaxPostLength()) : $text;
|
$text = $auto_crop ? substr($text, 0, $this->getMaxPostLength()) : $text;
|
||||||
$parameters = [
|
$parameters = [
|
||||||
'text' => $text,
|
'text' => $text,
|
||||||
'reply_to' => $reply_to,
|
'reply_to' => $reply_to,
|
||||||
'is_nsfw' => $is_nsfw,
|
'is_nsfw' => $is_nsfw,
|
||||||
];
|
];
|
||||||
if (!empty($raw)) {
|
if (!empty($raw)) {
|
||||||
$parameters['raw'] = $parameters;
|
$parameters['raw'] = $parameters;
|
||||||
@ -792,7 +807,7 @@ class APnutI
|
|||||||
): Post {
|
): Post {
|
||||||
$text = $auto_crop ? substr($text, 0, $this->getMaxPostLength()) : $text;
|
$text = $auto_crop ? substr($text, 0, $this->getMaxPostLength()) : $text;
|
||||||
$parameters = [
|
$parameters = [
|
||||||
'text' => $text,
|
'text' => $text,
|
||||||
];
|
];
|
||||||
$parameters = array_merge($parameters, $params);
|
$parameters = array_merge($parameters, $params);
|
||||||
$this->logger->debug('Post with params');
|
$this->logger->debug('Post with params');
|
||||||
@ -805,9 +820,9 @@ class APnutI
|
|||||||
|
|
||||||
public function getChannel(int $channel_id): Channel
|
public function getChannel(int $channel_id): Channel
|
||||||
{
|
{
|
||||||
# Always include channel raw, it contains the channel name
|
# Always include channel raw, it contains the channel name
|
||||||
$parameters = [
|
$parameters = [
|
||||||
'include_channel_raw' => true,
|
'include_channel_raw' => true,
|
||||||
];
|
];
|
||||||
return new Channel(
|
return new Channel(
|
||||||
$this->get('/channels/' . $channel_id, $parameters),
|
$this->get('/channels/' . $channel_id, $parameters),
|
||||||
@ -819,7 +834,7 @@ class APnutI
|
|||||||
bool $include_pms = true,
|
bool $include_pms = true,
|
||||||
bool $include_channels = true
|
bool $include_channels = true
|
||||||
): array {
|
): array {
|
||||||
# Always include channel raw, it contains the channel name
|
# Always include channel raw, it contains the channel name
|
||||||
$channel_types = [];
|
$channel_types = [];
|
||||||
if ($include_pms) {
|
if ($include_pms) {
|
||||||
$channel_types[] = 'io.pnut.core.pm';
|
$channel_types[] = 'io.pnut.core.pm';
|
||||||
@ -829,8 +844,8 @@ class APnutI
|
|||||||
}
|
}
|
||||||
|
|
||||||
$parameters = [
|
$parameters = [
|
||||||
'include_channel_raw' => true,
|
'include_channel_raw' => true,
|
||||||
'channel_types' => implode(',', $channel_types),
|
'channel_types' => implode(',', $channel_types),
|
||||||
];
|
];
|
||||||
$channels = [];
|
$channels = [];
|
||||||
$resp = $this->get('/users/me/channels/subscribed', $parameters);
|
$resp = $this->get('/users/me/channels/subscribed', $parameters);
|
||||||
@ -844,14 +859,14 @@ class APnutI
|
|||||||
{
|
{
|
||||||
$config = $this->get('/sys/config');
|
$config = $this->get('/sys/config');
|
||||||
self::$POST_MAX_LENGTH = $config['post']['max_length'];
|
self::$POST_MAX_LENGTH = $config['post']['max_length'];
|
||||||
//self::$POST_MAX_LENGTH_REPOST = $config['post']['repost_max_length'];
|
//self::$POST_MAX_LENGTH_REPOST = $config['post']['repost_max_length'];
|
||||||
self::$POST_MAX_LENGTH_REPOST = self::$POST_MAX_LENGTH;
|
self::$POST_MAX_LENGTH_REPOST = self::$POST_MAX_LENGTH;
|
||||||
self::$POST_SECONDS_BETWEEN_DUPLICATES =
|
self::$POST_SECONDS_BETWEEN_DUPLICATES =
|
||||||
$config['post']['seconds_between_duplicates'];
|
$config['post']['seconds_between_duplicates'];
|
||||||
self::$MESSAGE_MAX_LENGTH = $config['message']['max_length'];
|
self::$MESSAGE_MAX_LENGTH = $config['message']['max_length'];
|
||||||
self::$RAW_MAX_LENGTH = $config['raw']['max_length'];
|
self::$RAW_MAX_LENGTH = $config['raw']['max_length'];
|
||||||
self::$USER_DESCRIPTION_MAX_LENGTH =
|
self::$USER_DESCRIPTION_MAX_LENGTH =
|
||||||
$config['user']['description_max_length'];
|
$config['user']['description_max_length'];
|
||||||
self::$USER_USERNAME_MAX_LENGTH = $config['user']['username_max_length'];
|
self::$USER_USERNAME_MAX_LENGTH = $config['user']['username_max_length'];
|
||||||
$this->logger->info('-----------Pnut API config-----------');
|
$this->logger->info('-----------Pnut API config-----------');
|
||||||
$this->logger->info('');
|
$this->logger->info('');
|
||||||
@ -859,7 +874,7 @@ class APnutI
|
|||||||
$this->logger->info('Max repost length: ' . self::$POST_MAX_LENGTH_REPOST);
|
$this->logger->info('Max repost length: ' . self::$POST_MAX_LENGTH_REPOST);
|
||||||
$this->logger->info(
|
$this->logger->info(
|
||||||
'Seconds between post duplicates: ' .
|
'Seconds between post duplicates: ' .
|
||||||
self::$POST_SECONDS_BETWEEN_DUPLICATES
|
self::$POST_SECONDS_BETWEEN_DUPLICATES
|
||||||
);
|
);
|
||||||
$this->logger->info('Max raw length: ' . self::$RAW_MAX_LENGTH);
|
$this->logger->info('Max raw length: ' . self::$RAW_MAX_LENGTH);
|
||||||
$this->logger->info(
|
$this->logger->info(
|
||||||
@ -890,9 +905,9 @@ class APnutI
|
|||||||
{
|
{
|
||||||
$this->logger->info('Requesting server access token from pnut');
|
$this->logger->info('Requesting server access token from pnut');
|
||||||
$params = [
|
$params = [
|
||||||
'client_id' => $this->client_id,
|
'client_id' => $this->client_id,
|
||||||
'client_secret' => $this->client_secret,
|
'client_secret' => $this->client_secret,
|
||||||
'grant_type' => 'client_credentials',
|
'grant_type' => 'client_credentials',
|
||||||
];
|
];
|
||||||
$resp = $this->post('/oauth/access_token', $params);
|
$resp = $this->post('/oauth/access_token', $params);
|
||||||
if (!empty($resp['access_token'])) {
|
if (!empty($resp['access_token'])) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace APnutI\Entities;
|
namespace APnutI\Entities;
|
||||||
|
|
||||||
use APnutI\Entities\PollOption;
|
use APnutI\Entities\PollOption;
|
||||||
@ -9,216 +10,227 @@ use APnutI\Exceptions\NotSupportedPollException;
|
|||||||
|
|
||||||
class Poll
|
class Poll
|
||||||
{
|
{
|
||||||
public \DateTime $created_at;
|
public \DateTime $created_at;
|
||||||
public \DateTime $closed_at;
|
public \DateTime $closed_at;
|
||||||
public int $id = 0;
|
public int $id = 0;
|
||||||
public int $max_options = 0;
|
public int $max_options = 0;
|
||||||
public bool $is_anonymous = false;
|
public bool $is_anonymous = false;
|
||||||
public bool $is_public = false;
|
public bool $is_public = false;
|
||||||
public array $options = [];
|
public array $options = [];
|
||||||
public ?string $token = null;
|
public ?string $token = null;
|
||||||
public string $prompt = "";
|
public string $prompt = '';
|
||||||
public ?User $user = null;
|
public ?User $user = null;
|
||||||
public ?Source $source = null;
|
public ?Source $source = null;
|
||||||
public string $type;
|
public string $type;
|
||||||
|
|
||||||
private APnutI $api;
|
private APnutI $api;
|
||||||
|
|
||||||
public static string $notice_type = 'io.pnut.core.poll-notice';
|
public static string $notice_type = 'io.pnut.core.poll-notice';
|
||||||
public static array $poll_types = [
|
public static array $poll_types = [
|
||||||
'general.poll',
|
'general.poll',
|
||||||
'net.unsweets.beta',
|
'net.unsweets.beta',
|
||||||
'io.pnut.core.poll',
|
'io.pnut.core.poll',
|
||||||
'io.broadsword.poll',
|
'io.broadsword.poll',
|
||||||
'nl.chimpnut.quizbot.attachment.poll'
|
'nl.chimpnut.quizbot.attachment.poll',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct(array $data, APnutI $api)
|
public function __construct(array $data, APnutI $api)
|
||||||
{
|
{
|
||||||
$this->api = $api;
|
$this->api = $api;
|
||||||
$this->options = [];
|
$this->options = [];
|
||||||
$type = '';
|
$type = '';
|
||||||
if (array_key_exists('type', $data) && $data['type'] === Poll::$notice_type) {
|
if (array_key_exists('type', $data) &&
|
||||||
$val = $data['value'];
|
$data['type'] === Poll::$notice_type
|
||||||
$this->closed_at = new \DateTime($val['closed_at']);
|
) {
|
||||||
foreach ($val['options'] as $option) {
|
$val = $data['value'];
|
||||||
$this->options[] = new PollOption($option);
|
$this->closed_at = new \DateTime($val['closed_at']);
|
||||||
}
|
foreach ($val['options'] as $option) {
|
||||||
$this->id = (int)$val['poll_id'];
|
$this->options[] = new PollOption($option);
|
||||||
$this->token = $val['poll_token'];
|
}
|
||||||
$this->prompt = $val['prompt'];
|
$this->id = (int) $val['poll_id'];
|
||||||
} elseif (array_key_exists('type', $data) &&in_array($data['type'], Poll::$poll_types)) {
|
$this->token = $val['poll_token'];
|
||||||
$this->parsePoll($data);
|
$this->prompt = $val['prompt'];
|
||||||
} elseif (array_key_exists('type', $data) &&strpos($data['type'], '.poll') !== false) {
|
} elseif (array_key_exists('type', $data) &&
|
||||||
// Try parsing unknown types if they *might* be a poll
|
in_array($data['type'], Poll::$poll_types)
|
||||||
try {
|
) {
|
||||||
$this->parsePoll($data);
|
$this->parsePoll($data);
|
||||||
} catch (\Exception $e) {
|
} elseif (array_key_exists('type', $data) &&
|
||||||
throw new NotSupportedPollException($data['type']);
|
strpos($data['type'], '.poll') !== false
|
||||||
}
|
) {
|
||||||
} elseif (array_key_exists('raw', $data) && #Polls included in posts
|
// Try parsing unknown types if they *might* be a poll
|
||||||
array_key_exists(Poll::$notice_type, $data['raw']) &&
|
try {
|
||||||
count($data['raw'][Poll::$notice_type]) > 0
|
$this->parsePoll($data);
|
||||||
) {
|
} catch (\Exception $e) {
|
||||||
$poll_data = $data['raw'][Poll::$notice_type][0];
|
throw new NotSupportedPollException($data['type']);
|
||||||
if (!empty($data['source'])) { #Source is attached to post, not to poll raw
|
}
|
||||||
$poll_data['source'] = $data['source'];
|
} elseif (array_key_exists('raw', $data) && #Polls included in posts
|
||||||
}
|
array_key_exists(Poll::$notice_type, $data['raw']) &&
|
||||||
if (!empty($data['user'])) { #User is attached to post, not to poll raw
|
count($data['raw'][Poll::$notice_type]) > 0
|
||||||
$poll_data['user'] = $data['user'];
|
) {
|
||||||
}
|
$poll_data = $data['raw'][Poll::$notice_type][0];
|
||||||
$type = Poll::$notice_type;
|
if (!empty($data['source'])) {
|
||||||
$this->parsePoll($poll_data);
|
#Source is attached to post, not to poll raw
|
||||||
} else {
|
$poll_data['source'] = $data['source'];
|
||||||
throw new NotSupportedPollException($data['type']);
|
}
|
||||||
|
if (!empty($data['user'])) {
|
||||||
|
#User is attached to post, not to poll raw
|
||||||
|
$poll_data['user'] = $data['user'];
|
||||||
|
}
|
||||||
|
$type = Poll::$notice_type;
|
||||||
|
$this->parsePoll($poll_data);
|
||||||
|
} else {
|
||||||
|
throw new NotSupportedPollException($data['type']);
|
||||||
|
}
|
||||||
|
$this->type = empty($type) ? $data['type'] : $type;
|
||||||
}
|
}
|
||||||
$this->type = empty($type) ? $data['type'] : $type;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function parsePoll(array $data)
|
private function parsePoll(array $data)
|
||||||
{
|
{
|
||||||
$this->created_at = new \DateTime($data['created_at']);
|
$this->created_at = new \DateTime($data['created_at']);
|
||||||
$this->closed_at = new \DateTime($data['closed_at']);
|
$this->closed_at = new \DateTime($data['closed_at']);
|
||||||
$this->id = (int)$data['id'];
|
$this->id = (int) $data['id'];
|
||||||
$this->is_anonymous = array_key_exists('is_anonymous', $data) ? (bool)$data['is_anonymous'] : false;
|
$this->is_anonymous = array_key_exists('is_anonymous', $data)
|
||||||
$this->max_options = array_key_exists('max_options', $data) ? (int)$data['max_options'] : 1;
|
? (bool) $data['is_anonymous']
|
||||||
$this->is_public = array_key_exists('is_public', $data) ? (bool)$data['is_public'] : false;
|
: false;
|
||||||
foreach ($data['options'] as $option) {
|
$this->max_options = array_key_exists('max_options', $data)
|
||||||
$this->options[] = new PollOption($option);
|
? (int) $data['max_options']
|
||||||
|
: 1;
|
||||||
|
$this->is_public = array_key_exists('is_public', $data)
|
||||||
|
? (bool) $data['is_public']
|
||||||
|
: false;
|
||||||
|
foreach ($data['options'] as $option) {
|
||||||
|
$this->options[] = new PollOption($option);
|
||||||
|
}
|
||||||
|
if (!empty($data['poll_token'])) {
|
||||||
|
$this->token = $data['poll_token'];
|
||||||
|
}
|
||||||
|
$this->prompt = $data['prompt'];
|
||||||
|
if (!empty($data['user'])) {
|
||||||
|
$this->user = new User($data['user'], $this->api);
|
||||||
|
}
|
||||||
|
if (!empty($data['source'])) {
|
||||||
|
$this->source = new Source($data['source']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!empty($data['poll_token'])) {
|
|
||||||
$this->token = $data['poll_token'];
|
|
||||||
}
|
|
||||||
$this->prompt = $data['prompt'];
|
|
||||||
if (!empty($data['user'])) {
|
|
||||||
$this->user = new User($data['user'], $this->api);
|
|
||||||
}
|
|
||||||
if (!empty($data['source'])) {
|
|
||||||
$this->source = new Source($data['source']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the most voted option. If multiple options have the same amount
|
* Returns the most voted option. If multiple options have the same amount
|
||||||
* of voted, return all of them. Always returns an array!
|
* of voted, return all of them. Always returns an array!
|
||||||
*/
|
*/
|
||||||
public function getMostVotedOption(): array
|
public function getMostVotedOption(): array
|
||||||
{
|
{
|
||||||
if (count($this->options) === 0) {
|
if (count($this->options) === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
$optns = [];
|
|
||||||
//$most_voted_option = $this->options[0];
|
|
||||||
$most_voted_option = null;
|
|
||||||
foreach ($this->options as $option) {
|
|
||||||
if ($option->greaterThan($most_voted_option)) {
|
|
||||||
$optns = [];
|
$optns = [];
|
||||||
$most_voted_option = $option;
|
//$most_voted_option = $this->options[0];
|
||||||
$optns[] = $option;
|
$most_voted_option = null;
|
||||||
} elseif ($option->greaterThanOrSame($most_voted_option)) {
|
foreach ($this->options as $option) {
|
||||||
$optns[] = $option;
|
if ($option->greaterThan($most_voted_option)) {
|
||||||
}
|
$optns = [];
|
||||||
|
$most_voted_option = $option;
|
||||||
|
$optns[] = $option;
|
||||||
|
} elseif ($option->greaterThanOrSame($most_voted_option)) {
|
||||||
|
$optns[] = $option;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $optns;
|
||||||
}
|
}
|
||||||
return $optns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMyVotes(): array
|
public function getMyVotes(): array
|
||||||
{
|
{
|
||||||
$optns = [];
|
$optns = [];
|
||||||
foreach ($this->options as $option) {
|
foreach ($this->options as $option) {
|
||||||
if ($option->is_your_response) {
|
if ($option->is_your_response) {
|
||||||
$optns[] = $option;
|
$optns[] = $option;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return $optns;
|
||||||
}
|
}
|
||||||
return $optns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function isValidPoll(string $type): bool
|
public static function isValidPoll(string $type): bool
|
||||||
{
|
{
|
||||||
return $type === Poll::$notice_type || in_array($type, Poll::$poll_types);
|
return $type === Poll::$notice_type || in_array($type, Poll::$poll_types);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canVote()
|
public function canVote()
|
||||||
{
|
{
|
||||||
$is_authenticated = $this->api->isAuthenticated(false, true);
|
$is_authenticated = $this->api->isAuthenticated(false, true);
|
||||||
return $is_authenticated && !$this->isClosed();
|
return $is_authenticated && !$this->isClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isClosed()
|
public function isClosed()
|
||||||
{
|
{
|
||||||
return $this->closed_at <= new \DateTime();
|
return $this->closed_at <= new \DateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function vote(array $options): Poll
|
public function vote(array $options): Poll
|
||||||
{
|
{
|
||||||
return $this->api->voteInPoll($this->id, $options, $this->token);
|
return $this->api->voteInPoll($this->id, $options, $this->token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is inconsistend with most other functions (which are provided directly by the API object.
|
* This is inconsistend with most other functions (which are provided directly by the API object.
|
||||||
* I should probably settle on one of the two styles.
|
* I should probably settle on one of the two styles.
|
||||||
* I prefer having the methods in here, but having to pass the API object along is not so great,
|
* I prefer having the methods in here, but having to pass the API object along is not so great,
|
||||||
* neither is having to make the API's logger public
|
* neither is having to make the API's logger public
|
||||||
* TODO for v2 I guess
|
* TODO for v2 I guess
|
||||||
*/
|
*/
|
||||||
public static function create(
|
public static function create(
|
||||||
APnutI $api,
|
APnutI $api,
|
||||||
string $prompt,
|
string $prompt,
|
||||||
array $options,
|
array $options,
|
||||||
int $max_options,
|
int $max_options,
|
||||||
int $duration_minutes,
|
int $duration_minutes,
|
||||||
bool $is_anonymous,
|
bool $is_anonymous,
|
||||||
bool $is_public
|
bool $is_public
|
||||||
): Poll {
|
): Poll {
|
||||||
$options = array_filter($options);
|
$options = array_filter($options);
|
||||||
$options = array_map(
|
$options = array_map(function ($v) {
|
||||||
function ($v) {
|
return ['text' => $v];
|
||||||
return ['text' => $v];
|
}, $options);
|
||||||
},
|
$params = [
|
||||||
$options
|
'duration' => $duration_minutes,
|
||||||
);
|
'options' => array_filter($options), #filters empty options
|
||||||
$params = [
|
'prompt' => $prompt,
|
||||||
'duration' => $duration_minutes,
|
'type' => 'io.pnut.core.poll',
|
||||||
'options' => array_filter($options), #filters empty options
|
'is_anonymous' => $is_anonymous,
|
||||||
'prompt' => $prompt,
|
'is_public' => $is_public,
|
||||||
'type' => 'io.pnut.core.poll',
|
'max_options' => $max_options,
|
||||||
'is_anonymous' => $is_anonymous,
|
];
|
||||||
'is_public' => $is_public,
|
$api->logger->debug('Creating poll');
|
||||||
'max_options' => $max_options
|
$api->logger->debug(json_encode($params));
|
||||||
];
|
$resp = $api->post('/polls', $params, 'application/json');
|
||||||
$api->logger->debug('Creating poll');
|
#TODO: Use getPollFromEndpoint
|
||||||
$api->logger->debug(json_encode($params));
|
return new Poll($resp, $api);
|
||||||
$resp = $api->post('/polls', $params, 'application/json');
|
}
|
||||||
#TODO: Use getPollFromEndpoint
|
|
||||||
return new Poll($resp, $api);
|
public static function makePollNoticeRaw(int $poll_id, string $poll_token)
|
||||||
}
|
{
|
||||||
|
return [
|
||||||
public static function makePollNoticeRaw(int $poll_id, string $poll_token)
|
'io.pnut.core.poll-notice' => [
|
||||||
{
|
[
|
||||||
return [
|
'+io.pnut.core.poll' => [
|
||||||
'io.pnut.core.poll-notice' => [
|
'poll_id' => $poll_id,
|
||||||
[
|
'poll_token' => $poll_token,
|
||||||
'+io.pnut.core.poll' => [
|
],
|
||||||
'poll_id' => $poll_id,
|
],
|
||||||
'poll_token' => $poll_token
|
],
|
||||||
]
|
];
|
||||||
]
|
}
|
||||||
]
|
|
||||||
];
|
public function __toString(): string
|
||||||
}
|
{
|
||||||
|
if (!empty($this->user)) {
|
||||||
public function __toString(): string
|
$str = $this->user->username;
|
||||||
{
|
#$str = 'Unknown user';
|
||||||
if (!empty($this->user)) {
|
} else {
|
||||||
$str = $this->user->username;
|
$str = 'Unknown user';
|
||||||
#$str = 'Unknown user';
|
}
|
||||||
} else {
|
return $str .
|
||||||
$str = 'Unknown user';
|
" asked: '" .
|
||||||
|
$this->prompt .
|
||||||
|
"', closed at " .
|
||||||
|
$this->closed_at->format('Y-m-d H:i:s T');
|
||||||
}
|
}
|
||||||
return $str
|
|
||||||
. " asked: '"
|
|
||||||
. $this->prompt
|
|
||||||
. "', closed at "
|
|
||||||
. $this->closed_at->format('Y-m-d H:i:s T');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user