Added polls and additional network functions
This commit is contained in:
parent
d651feb33d
commit
ce35f3e036
184
src/APnutI.php
184
src/APnutI.php
@ -3,6 +3,7 @@
|
||||
namespace APnutI;
|
||||
|
||||
use APnutI\Entities\Post;
|
||||
use APnutI\Entities\Poll;
|
||||
use APnutI\Entities\User;
|
||||
use APnutI\Exceptions\PnutException;
|
||||
use APnutI\Exceptions\NotFoundException;
|
||||
@ -17,7 +18,7 @@ use Psr\Log\NullLogger;
|
||||
|
||||
class APnutI
|
||||
{
|
||||
protected string $api_url = 'https://api.pnut.io/v1/';
|
||||
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;
|
||||
@ -35,6 +36,7 @@ class APnutI
|
||||
protected ?string $access_token;
|
||||
protected LoggerInterface $logger;
|
||||
protected string $token_session_key;
|
||||
protected string $token_redirect_after_auth;
|
||||
protected ?string $server_token_file_path = null;
|
||||
|
||||
public ?Meta $meta = null;
|
||||
@ -68,6 +70,8 @@ class APnutI
|
||||
{
|
||||
$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, Logger::DEBUG, true);
|
||||
$this->logger->pushHandler($handler);
|
||||
$this->server_token = null;
|
||||
@ -297,7 +301,183 @@ class APnutI
|
||||
"Checking auth status for app: {$this->app_name}: {$log_str}"
|
||||
);
|
||||
$this->logger->info('Referrer: '.($_SERVER['HTTP_REFERER'] ?? 'Unknown'));
|
||||
$_SESSION['redirect_after_auth'] = $_SERVER['HTTP_REFERER'];
|
||||
$_SESSION[$this->token_redirect_after_auth] = $_SERVER['HTTP_REFERER'];
|
||||
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'
|
||||
);
|
||||
|
||||
if ($resp === null || !isset($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;
|
||||
}
|
||||
|
||||
// TODO
|
||||
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, ");
|
||||
}
|
||||
*/
|
||||
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);
|
||||
}
|
||||
var_dump($p);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
} 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']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $polls;
|
||||
}
|
||||
|
||||
public function getPoll(int $poll_id): Poll
|
||||
{
|
||||
return new Poll($this->get('/polls/' . $poll_id));
|
||||
}
|
||||
|
||||
public function getAuthorizedUser(): User
|
||||
{
|
||||
return $this->getUser('/me');
|
||||
}
|
||||
|
||||
public function getUser(int $user_id, array $args = [])
|
||||
{
|
||||
return new User($this->get('/users/'.$user_id, $args));
|
||||
}
|
||||
|
||||
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 p roduction again
|
||||
try {
|
||||
$p = new Post($this->get('/posts/'.$post_id, $args));
|
||||
$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->make_request(
|
||||
'/get',
|
||||
'/posts/' . $post_id,
|
||||
$args,
|
||||
'application/json',
|
||||
true
|
||||
);
|
||||
return new Post($r);
|
||||
}
|
||||
}
|
||||
|
||||
public function getAvatar(int $user_id, array $args = []): string
|
||||
{
|
||||
return $this->get('/users/'.$user_id.'/avatar', $args);
|
||||
}
|
||||
}
|
||||
|
110
src/Entities/Poll.php
Normal file
110
src/Entities/Poll.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
namespace APnutI\Entities;
|
||||
|
||||
use APnutI\Entities\PollOption;
|
||||
use APnutI\Entities\User;
|
||||
use APnutI\Entities\Source;
|
||||
use APnutI\Exceptions\NotSupportedPollException;
|
||||
|
||||
class Poll
|
||||
{
|
||||
public \DateTime $created_at;
|
||||
public \DateTime $closed_at;
|
||||
public int $id = 0;
|
||||
public bool $is_anonymous = false;
|
||||
public bool $is_public = false;
|
||||
public array $options = [];
|
||||
public ?string $token = null;
|
||||
public string $prompt = "";
|
||||
public ?User $user = null;
|
||||
public ?Source $source = null;
|
||||
public string $type;
|
||||
|
||||
public static string $notice_type = 'io.pnut.core.poll-notice';
|
||||
protected static array $poll_types = [
|
||||
'general.poll',
|
||||
'net.unsweets.beta',
|
||||
'io.pnut.core.poll'
|
||||
];
|
||||
|
||||
public function __construct(array $data)
|
||||
{
|
||||
$this->options = [];
|
||||
$this->type = $data['type'];
|
||||
if ($data['type'] === Poll::$notice_type) {
|
||||
$val = $data['value'];
|
||||
$this->closed_at = new \DateTime($val['closed_at']);
|
||||
foreach ($val['options'] as $option) {
|
||||
$this->options[] = new PollOption($option);
|
||||
}
|
||||
$this->id = (int)$val['poll_id'];
|
||||
$this->token = $val['poll_token'];
|
||||
$this->prompt = $val['prompt'];
|
||||
} elseif (in_array($data['type'], Poll::$poll_types)) {
|
||||
$this->created_at = new \DateTime($data['created_at']);
|
||||
$this->closed_at = new \DateTime($data['closed_at']);
|
||||
$this->id = (int)$data['id'];
|
||||
$this->is_anonymous = (bool)$data['is_anonymous'];
|
||||
$this->is_public = (bool)$data['is_public'];
|
||||
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']);
|
||||
}
|
||||
if (!empty($data['source'])) {
|
||||
$this->source = new Source($data['source']);
|
||||
}
|
||||
} else {
|
||||
throw new NotSupportedPollException($data['type']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most voted option. If multiple options have the same amount
|
||||
* of voted, return all of them. Always returns an array!
|
||||
*/
|
||||
public function getMostVotedOption(): array
|
||||
{
|
||||
if (count($this->options) === 0) {
|
||||
return [];
|
||||
}
|
||||
$optns = [];
|
||||
//$most_voted_option = $this->options[0];
|
||||
$most_voted_option = null;
|
||||
foreach ($this->options as $option) {
|
||||
if ($option->greaterThan($most_voted_option)) {
|
||||
$optns = [];
|
||||
$most_voted_option = $option;
|
||||
$optns[] = $option;
|
||||
} elseif ($option->greaterThanOrSame($most_voted_option)) {
|
||||
$optns[] = $option;
|
||||
}
|
||||
}
|
||||
return $optns;
|
||||
}
|
||||
|
||||
public static function isValidPoll(string $type): bool
|
||||
{
|
||||
return $type === Poll::$notice_type || in_array($type, Poll::$poll_types);
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
if (!empty($this->user)) {
|
||||
$str = $this->user->username;
|
||||
#$str = 'Unknown user';
|
||||
} else {
|
||||
$str = 'Unknown user';
|
||||
}
|
||||
return $str
|
||||
. " asked: '"
|
||||
. $this->prompt
|
||||
. "', closed at "
|
||||
. $this->closed_at->format('Y-m-d H:i:s T');
|
||||
}
|
||||
}
|
65
src/Entities/PollOption.php
Normal file
65
src/Entities/PollOption.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
namespace APnutI\Entities;
|
||||
|
||||
class PollOption
|
||||
{
|
||||
public string $text;
|
||||
public int $position;
|
||||
public bool $is_your_response = false;
|
||||
public int $respondents = 0;
|
||||
public array $respondent_ids = [];
|
||||
|
||||
public function __construct($data)
|
||||
{
|
||||
$this->text = $data['text'];
|
||||
$this->position = (int)$data['position'];
|
||||
if (!empty($data['is_your_response'])) {
|
||||
$this->is_your_response = (bool)$data['is_your_response'];
|
||||
}
|
||||
if (!empty($data['respondents'])) {
|
||||
$this->respondents = (int)$data['respondents'];
|
||||
}
|
||||
if (!empty($data['respondent_ids'])) {
|
||||
$this->respondent_ids = $data['respondent_ids'];
|
||||
}
|
||||
}
|
||||
|
||||
public function greaterThan(?PollOption $option): bool
|
||||
{
|
||||
return empty($option)
|
||||
|| ($this->text != $option->text
|
||||
&& $this->respondents > $option->respondents);
|
||||
}
|
||||
|
||||
public function greaterThanOrSame(?PollOption $option): bool
|
||||
{
|
||||
return empty($option)
|
||||
|| ($this->text != $option->text
|
||||
&& $this->respondents >= $option->respondents);
|
||||
}
|
||||
|
||||
public function smallerThan(?PollOption $option): bool
|
||||
{
|
||||
return empty($option)
|
||||
|| ($this->text != $option->text
|
||||
&& $this->respondents < $option->respondents);
|
||||
}
|
||||
|
||||
public function smallerThanOrSame(?PollOption $option): bool
|
||||
{
|
||||
return empty($option)
|
||||
|| ($this->text != $option->text
|
||||
&& $this->respondents <= $option->respondents);
|
||||
}
|
||||
|
||||
public function equals(?PollOption $option): bool
|
||||
{
|
||||
return $this->text == $option->text
|
||||
&& $this->respondents == $option->respondents;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->text . ' with ' . $this->respondents .' respondents';
|
||||
}
|
||||
}
|
7
src/Exceptions/NotSupportedPollException.php
Normal file
7
src/Exceptions/NotSupportedPollException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace APnutI\Exceptions;
|
||||
|
||||
class NotSupportedPollException extends Exception
|
||||
{
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user