Merge pull request #7904 from MrPetovan/task/7887-api-followers-request
Add GET /api/v1/follow_requests Mastodon API endpoint
This commit is contained in:
commit
d0b20fb499
17 changed files with 3765 additions and 2214 deletions
86
src/Api/Mastodon/Account.php
Normal file
86
src/Api/Mastodon/Account.php
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Api\Mastodon;
|
||||
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
||||
/**
|
||||
* Class Account
|
||||
*
|
||||
* @see https://docs.joinmastodon.org/api/entities/#account
|
||||
*/
|
||||
class Account
|
||||
{
|
||||
/** @var string */
|
||||
var $id;
|
||||
/** @var string */
|
||||
var $username;
|
||||
/** @var string */
|
||||
var $acct;
|
||||
/** @var string */
|
||||
var $display_name;
|
||||
/** @var bool */
|
||||
var $locked;
|
||||
/** @var string (Datetime) */
|
||||
var $created_at;
|
||||
/** @var int */
|
||||
var $followers_count;
|
||||
/** @var int */
|
||||
var $following_count;
|
||||
/** @var int */
|
||||
var $statuses_count;
|
||||
/** @var string */
|
||||
var $note;
|
||||
/** @var string (URL)*/
|
||||
var $url;
|
||||
/** @var string (URL) */
|
||||
var $avatar;
|
||||
/** @var string (URL) */
|
||||
var $avatar_static;
|
||||
/** @var string (URL) */
|
||||
var $header;
|
||||
/** @var string (URL) */
|
||||
var $header_static;
|
||||
/** @var Emoji[] */
|
||||
var $emojis;
|
||||
/** @var Account|null */
|
||||
var $moved = null;
|
||||
/** @var Field[]|null */
|
||||
var $fields = null;
|
||||
/** @var bool|null */
|
||||
var $bot = null;
|
||||
|
||||
/**
|
||||
* Creates an account record from a contact record. Expects all contact table fields to be set
|
||||
*
|
||||
* @param array $contact
|
||||
* @return Account
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function createFromContact(array $contact) {
|
||||
$account = new Account();
|
||||
$account->id = $contact['id'];
|
||||
$account->username = $contact['nick'];
|
||||
$account->acct = $contact['nick'];
|
||||
$account->display_name = $contact['name'];
|
||||
$account->locked = $contact['blocked'];
|
||||
$account->created_at = DateTimeFormat::utc($contact['created'], DateTimeFormat::ATOM);
|
||||
// No data is available from contact
|
||||
$account->followers_count = 0;
|
||||
$account->following_count = 0;
|
||||
$account->statuses_count = 0;
|
||||
$account->note = BBCode::convert($contact['about']);
|
||||
$account->url = $contact['url'];
|
||||
$account->avatar = $contact['avatar'];
|
||||
$account->avatar_static = $contact['avatar'];
|
||||
// No header picture in Friendica
|
||||
$account->header = '';
|
||||
$account->header_static = '';
|
||||
// No custom emojis per account in Friendica
|
||||
$account->emojis = [];
|
||||
|
||||
return $account;
|
||||
}
|
||||
}
|
20
src/Api/Mastodon/Emoji.php
Normal file
20
src/Api/Mastodon/Emoji.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Api\Mastodon;
|
||||
|
||||
/**
|
||||
* Class Emoji
|
||||
*
|
||||
* @see https://docs.joinmastodon.org/api/entities/#emoji
|
||||
*/
|
||||
class Emoji
|
||||
{
|
||||
/** @var string */
|
||||
var $shortcode;
|
||||
/** @var string (URL)*/
|
||||
var $static_url;
|
||||
/** @var string (URL)*/
|
||||
var $url;
|
||||
/** @var bool */
|
||||
var $visible_in_picker;
|
||||
}
|
18
src/Api/Mastodon/Field.php
Normal file
18
src/Api/Mastodon/Field.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Api\Mastodon;
|
||||
|
||||
/**
|
||||
* Class Field
|
||||
*
|
||||
* @see https://docs.joinmastodon.org/api/entities/#field
|
||||
*/
|
||||
class Field
|
||||
{
|
||||
/** @var string */
|
||||
var $name;
|
||||
/** @var string (HTML) */
|
||||
var $value;
|
||||
/** @var string (Datetime)*/
|
||||
var $verified_at;
|
||||
}
|
79
src/Module/Api/Mastodon/FollowRequests.php
Normal file
79
src/Module/Api/Mastodon/FollowRequests.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Module\Api\Mastodon;
|
||||
|
||||
use Friendica\Api\Mastodon\Account;
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Module\Base\Api;
|
||||
use Friendica\Network\HTTPException;
|
||||
|
||||
/**
|
||||
* @see https://docs.joinmastodon.org/api/rest/follow-requests/
|
||||
*/
|
||||
class FollowRequests extends Api
|
||||
{
|
||||
public static function init(array $parameters = [])
|
||||
{
|
||||
parent::init($parameters);
|
||||
|
||||
self::login();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $parameters
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @see https://docs.joinmastodon.org/api/rest/follow-requests/#get-api-v1-follow-requests
|
||||
*/
|
||||
public static function rawContent(array $parameters = [])
|
||||
{
|
||||
$since_id = $_GET['since_id'] ?? null;
|
||||
$max_id = $_GET['max_id'] ?? null;
|
||||
$limit = intval($_GET['limit'] ?? 40);
|
||||
|
||||
if (isset($since_id) && isset($max_id)) {
|
||||
$condition = ['`uid` = ? AND NOT `self` AND `pending` AND `id` > ? AND `id` < ?', self::$current_user_id, $since_id, $max_id];
|
||||
} elseif (isset($since_id)) {
|
||||
$condition = ['`uid` = ? AND NOT `self` AND `pending` AND `id` > ?', self::$current_user_id, $since_id];
|
||||
} elseif (isset($max_id)) {
|
||||
$condition = ['`uid` = ? AND NOT `self` AND `pending` AND `id` < ?', self::$current_user_id, $max_id];
|
||||
} else {
|
||||
$condition = ['`uid` = ? AND NOT `self` AND `pending`', self::$current_user_id];
|
||||
}
|
||||
|
||||
$count = DBA::count('contact', $condition);
|
||||
|
||||
$contacts = Contact::selectToArray(
|
||||
[],
|
||||
$condition,
|
||||
['order' => ['id' => 'DESC'], 'limit' => $limit]
|
||||
);
|
||||
|
||||
$return = [];
|
||||
foreach ($contacts as $contact) {
|
||||
$account = Account::createFromContact($contact);
|
||||
|
||||
$return[] = $account;
|
||||
}
|
||||
|
||||
$base_query = [];
|
||||
if (isset($_GET['limit'])) {
|
||||
$base_query['limit'] = $limit;
|
||||
}
|
||||
|
||||
/** @var BaseURL $BaseURL */
|
||||
$BaseURL = self::getClass(BaseURL::class);
|
||||
|
||||
$links = [];
|
||||
if ($count > $limit) {
|
||||
$links[] = '<' . $BaseURL->get() . '/api/v1/follow_requests?' . http_build_query($base_query + ['max_id' => $contacts[count($contacts) - 1]['id']]) . '>; rel="next"';
|
||||
}
|
||||
$links[] = '<' . $BaseURL->get() . '/api/v1/follow_requests?' . http_build_query($base_query + ['since_id' => $contacts[0]['id']]) . '>; rel="prev"';
|
||||
|
||||
header('Link: ' . implode(', ', $links));
|
||||
|
||||
System::jsonExit($return);
|
||||
}
|
||||
}
|
105
src/Module/Base/Api.php
Normal file
105
src/Module/Base/Api.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Module\Base;
|
||||
|
||||
use Friendica\App\Arguments;
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Network\HTTPException;
|
||||
|
||||
require_once __DIR__ . '/../../../include/api.php';
|
||||
|
||||
class Api extends BaseModule
|
||||
{
|
||||
/**
|
||||
* @var string json|xml|rss|atom
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
/**
|
||||
* @var bool|int
|
||||
*/
|
||||
protected static $current_user_id;
|
||||
|
||||
public static function init(array $parameters = [])
|
||||
{
|
||||
$Arguments = self::getClass(Arguments::class);
|
||||
|
||||
if (substr($Arguments->getQueryString(), -4) === '.xml') {
|
||||
self::$format = 'xml';
|
||||
}
|
||||
if (substr($Arguments->getQueryString(), -4) === '.rss') {
|
||||
self::$format = 'rss';
|
||||
}
|
||||
if (substr($Arguments->getQueryString(), -4) === '.atom') {
|
||||
self::$format = 'atom';
|
||||
}
|
||||
}
|
||||
|
||||
public static function post(array $parameters = [])
|
||||
{
|
||||
if (!api_user()) {
|
||||
throw new HTTPException\UnauthorizedException(L10n::t('Permission denied.'));
|
||||
}
|
||||
|
||||
$a = self::getApp();
|
||||
|
||||
if (!empty($a->user['uid']) && $a->user['uid'] != api_user()) {
|
||||
throw new HTTPException\ForbiddenException(L10n::t('Permission denied.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log in user via OAuth1 or Simple HTTP Auth.
|
||||
* Simple Auth allow username in form of <pre>user@server</pre>, ignoring server part
|
||||
*
|
||||
* @brief Login API user
|
||||
*
|
||||
* @throws HTTPException\ForbiddenException
|
||||
* @throws HTTPException\UnauthorizedException
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @hook 'authenticate'
|
||||
* array $addon_auth
|
||||
* 'username' => username from login form
|
||||
* 'password' => password from login form
|
||||
* 'authenticated' => return status,
|
||||
* 'user_record' => return authenticated user record
|
||||
*/
|
||||
protected static function login()
|
||||
{
|
||||
api_login(self::getApp());
|
||||
|
||||
self::$current_user_id = api_user();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get user info array.
|
||||
*
|
||||
* @param int|string $contact_id Contact ID or URL
|
||||
* @return array|bool
|
||||
* @throws HTTPException\BadRequestException
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws HTTPException\UnauthorizedException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
protected static function getUser($contact_id = null)
|
||||
{
|
||||
return api_get_user(self::getApp(), $contact_id);
|
||||
}
|
||||
|
||||
protected static function format($root_element, $data)
|
||||
{
|
||||
switch (self::$format) {
|
||||
case "atom":
|
||||
case "rss":
|
||||
case "xml":
|
||||
$ret = api_create_xml($data, $root_element);
|
||||
break;
|
||||
case "json":
|
||||
default:
|
||||
$ret = $data;
|
||||
break;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
|
@ -65,10 +65,11 @@ class Help extends BaseModule
|
|||
$lastLevel = 1;
|
||||
$idNum = [0, 0, 0, 0, 0, 0, 0];
|
||||
foreach ($lines as &$line) {
|
||||
if (substr($line, 0, 2) == "<h") {
|
||||
$level = substr($line, 2, 1);
|
||||
if ($level != "r") {
|
||||
$level = intval($level);
|
||||
$matches = [];
|
||||
foreach ($lines as &$line) {
|
||||
if (preg_match('#<h([1-6])>([^<]+?)</h\1>#i', $line, $matches)) {
|
||||
$level = $matches[1];
|
||||
$anchor = urlencode($matches[2]);
|
||||
if ($level < $lastLevel) {
|
||||
for ($k = $level; $k < $lastLevel; $k++) {
|
||||
$toc .= "</ul></li>";
|
||||
|
@ -84,10 +85,13 @@ class Help extends BaseModule
|
|||
}
|
||||
|
||||
$idNum[$level] ++;
|
||||
|
||||
$href = $a->getBaseURL() . "/help/{$filename}#{$anchor}";
|
||||
$toc .= "<li><a href=\"{$href}\">" . strip_tags($line) . "</a></li>";
|
||||
$id = implode("_", array_slice($idNum, 1, $level));
|
||||
$href = $a->getBaseURL() . "/help/{$filename}#{$id}";
|
||||
$toc .= "<li><a href='{$href}'>" . strip_tags($line) . "</a></li>";
|
||||
$line = "<a name='{$id}'></a>" . $line;
|
||||
$line = "<a name=\"{$id}\"></a>" . $line;
|
||||
$line = "<a name=\"{$anchor}\"></a>" . $line;
|
||||
|
||||
$lastLevel = $level;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace Friendica\Network;
|
|||
use Friendica\Core\Config;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Util\Strings;
|
||||
use OAuthConsumer;
|
||||
use OAuthDataStore;
|
||||
use OAuthToken;
|
||||
|
@ -26,15 +27,16 @@ class FKOAuthDataStore extends OAuthDataStore
|
|||
{
|
||||
/**
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
private static function genToken()
|
||||
{
|
||||
return Friendica\Util\Strings::getRandomHex(32);
|
||||
return Strings::getRandomHex(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $consumer_key key
|
||||
* @return mixed
|
||||
* @return OAuthConsumer|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function lookup_consumer($consumer_key)
|
||||
|
@ -52,17 +54,17 @@ class FKOAuthDataStore extends OAuthDataStore
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string $consumer consumer
|
||||
* @param string $token_type type
|
||||
* @param string $token token
|
||||
* @return mixed
|
||||
* @param OAuthConsumer $consumer
|
||||
* @param string $token_type
|
||||
* @param string $token_id
|
||||
* @return OAuthToken|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function lookup_token($consumer, $token_type, $token)
|
||||
public function lookup_token(OAuthConsumer $consumer, $token_type, $token_id)
|
||||
{
|
||||
Logger::log(__function__ . ":" . $consumer . ", " . $token_type . ", " . $token);
|
||||
Logger::log(__function__ . ":" . $consumer . ", " . $token_type . ", " . $token_id);
|
||||
|
||||
$s = DBA::select('tokens', ['id', 'secret', 'scope', 'expires', 'uid'], ['client_id' => $consumer->key, 'scope' => $token_type, 'id' => $token]);
|
||||
$s = DBA::select('tokens', ['id', 'secret', 'scope', 'expires', 'uid'], ['client_id' => $consumer->key, 'scope' => $token_type, 'id' => $token_id]);
|
||||
$r = DBA::toArray($s);
|
||||
|
||||
if (DBA::isResult($r)) {
|
||||
|
@ -77,14 +79,14 @@ class FKOAuthDataStore extends OAuthDataStore
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string $consumer consumer
|
||||
* @param string $token token
|
||||
* @param string $nonce nonce
|
||||
* @param string $timestamp timestamp
|
||||
* @param OAuthConsumer $consumer
|
||||
* @param OAuthToken $token
|
||||
* @param string $nonce
|
||||
* @param int $timestamp
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function lookup_nonce($consumer, $token, $nonce, $timestamp)
|
||||
public function lookup_nonce(OAuthConsumer $consumer, OAuthToken $token, $nonce, int $timestamp)
|
||||
{
|
||||
$token = DBA::selectFirst('tokens', ['id', 'secret'], ['client_id' => $consumer->key, 'id' => $nonce, 'expires' => $timestamp]);
|
||||
if (DBA::isResult($token)) {
|
||||
|
@ -95,12 +97,12 @@ class FKOAuthDataStore extends OAuthDataStore
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string $consumer consumer
|
||||
* @param string $callback optional, default null
|
||||
* @return mixed
|
||||
* @param OAuthConsumer $consumer
|
||||
* @param string $callback
|
||||
* @return OAuthToken|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function new_request_token($consumer, $callback = null)
|
||||
public function new_request_token(OAuthConsumer $consumer, $callback = null)
|
||||
{
|
||||
Logger::log(__function__ . ":" . $consumer . ", " . $callback);
|
||||
$key = self::genToken();
|
||||
|
@ -131,13 +133,13 @@ class FKOAuthDataStore extends OAuthDataStore
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string $token token
|
||||
* @param string $consumer consumer
|
||||
* @param string $verifier optional, defult null
|
||||
* @return object
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @param OAuthToken $token token
|
||||
* @param OAuthConsumer $consumer consumer
|
||||
* @param string $verifier optional, defult null
|
||||
* @return OAuthToken
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function new_access_token($token, $consumer, $verifier = null)
|
||||
public function new_access_token(OAuthToken $token, OAuthConsumer $consumer, $verifier = null)
|
||||
{
|
||||
Logger::log(__function__ . ":" . $token . ", " . $consumer . ", " . $verifier);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue