duukkis / maphpodon
Mastodon REST api-client
1.2
2023-02-17 16:54 UTC
Requires
- php: ^8.0
- guzzlehttp/guzzle: ^7.5
- nesbot/carbon: ^2.66
- thecodingmachine/safe: ^2.4
Requires (Dev)
- phpunit/phpunit: ^10
- squizlabs/php_codesniffer: ^3.7
README
PHP client-api for Mastodon. https://docs.joinmastodon.org/ has the api-methods documented. All the entities functions have a link to corresponding documentation.
Install
composer require duukkis/maphpodon
Usage
include('../vendor/autoload.php');
use Maphpodon\Maphpodon;
$masto = new Maphpodon(
"mastobotti.eu",
"CLIENT_ID",
"CLIENT_SECRET",
"ALL_YOU_NEED_IS_AUTH_TOKEN",
);
####### Timelines
$result = $masto->timelines()->public(["limit" => 10]);
/** @var \Maphpodon\models\Status $status */
foreach ($result as $i => $status) {
print "User " . $status->account->username .
" posted at " . $status->created_at->format("Y-m-d. H:i") .
" this " .$status->content . PHP_EOL;
}
$result = $masto->timelines()->home(["limit" => 2]);
$result = $masto->timelines()->tag("fish");
####### Statuses
$result = $masto->statuses()->post(["status" => "testi"]);
$result = $masto->statuses()->get($result->id);
$result = $masto->statuses()->get("109825403503402367");
$result = $masto->statuses()->delete("109823185566762882");
$result = $masto->statuses()->reblogged_by("109825461095585733");
$result = $masto->statuses()->favourited_by("109825461095585733");
####### Poll
$result = $masto->statuses()->post(
[
"status" => "What is the best way to make a poll?",
"poll" => [
"options" => [
"This way",
"Some other way"
],
"expires_in" => 60 * 60,
"multiple" => false,
]
]
);
$result = $masto->polls()->get("5");
$result = $masto->polls()->vote("5", ["choices" => [0, 1]]);
####### Remote status favourite
// find a remote post, use resolve true! so it gets federated to local instance
$result = $masto->search()->get(["q" => "https://mas.to/@duukkis/109818862518591984", "resolve" => true]);
/** @var \Maphpodon\models\Status $status */
$status = $result->statuses[0];
$result = $masto->statuses()->favourite($status->id);
####### Media handling
$result = $masto->media()->post("./IMG_6298.jpg", "description of somesort", null]);
$result = $masto->media()->get("109825314440397270");
####### post with media
$result = $masto->statuses()->post(["status" => "dippa", "media_ids" => ["109825314440397270"]]);
####### Notifications
$result = $masto->notifications()->index();
$result = $masto->notifications()->get("1");
$masto->notifications()->dismiss("1");
$masto->notifications()->clear();
####### Instance
$result = $masto->instance()->index();
####### Accounts
$result = $masto->accounts()->get("109807809719057795");
$result = $masto->accounts()->statuses("109807809719057795", ["min_id" => "109816527054798413", "limit" => 4]);
$result = $masto->accounts()->followers("109807809719057795", ["limit" => 2]);
$result = $masto->accounts()->featured_tags("109807491887075545", []);
$result = $masto->accounts()->lists("109817168119540210", []);
$result = $masto->accounts()->follow("109817168119540210");
$result = $masto->accounts()->unfollow("109817168119540210");
$result = $masto->accounts()->pin/unpin/block/unblock/...("109817168119540210");
$result = $masto->accounts()->note("109817168119540210", ["comment" => "api test"]);
$result = $masto->accounts()->note("109817168119540210"); // remove comment
$result = $masto->accounts()->search(["q" => "päivän"]);
$result = $masto->accounts()->lookup(["acct" => "duukkis"]);
// these gave me 500, so something there or then it's just my instance
$result = $masto->accounts()->relationships(["id" => ["109817168119540210", "109813823501112312"]]);
$result = $masto->accounts()->familiar_followers(["id" => ["109817168119540210", "109813823501112312"]]);
####### Oauth token fetching
// just put in a ID and secret
$masto = new Maphpodon(
"mastobotti.eu",
"CLIENT_ID",
"CLIENT_SECRET",
);
// this will return an url where to redirect customer
$result = $masto->auth()->authorize(
"read",
"urn:ietf:wg:oauth:2.0:oob",
"false",
"en"
);
print $result . PHP_EOL;
// or header("Location: " . $result); exit();
# After user has clicked ok or returned to actual return url given above, you get authorization code in &code param
# THIS IS DIFFERENT FROM AUTH_TOKEN so we need to fetch the token with below method
$result = $masto->auth()->token(
[
"grant_type" => "authorization_code",
"code" => "AUTHORIZATION_CODE_FROM_ABOVE",
"client_id" => $masto->clientKey,
"client_secret" => $masto->clientSecret,
"redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
"scope" => "read",
]
);
/*
print_r($result);
Maphpodon\models\Token Object
(
[access_token] => HERE-IS-A-TOKEN-YOU-CAN-USE
[token_type] => Bearer
[scope] => read
[created_at] => 1675972651
)
*/
$result = $masto->auth()->revoke(
[
"client_id" => $masto->clientKey,
"client_secret" => $masto->clientSecret,
"token" => "HERE-IS-A-TOKEN-YOU-CAN-USE",
]
);
####### Apps
$result = $masto->apps()->post(
[
"client_name" => "Duukkis new Api client",
"redirect_uris" => "urn:ietf:wg:oauth:2.0:oob",
"scopes" => "read follow write:lists",
"website" => "https://github.com/duukkis/maphpodon",
]
);
$result = $masto->apps()->verify_credentials();
####### Admin
$result = $masto->admin()->accounts()->viewV1(["limit" => 2]);
$result = $masto->admin()->accounts()->viewV2(["status" => "active", "limit" => 2]);
$result = $masto->admin()->accounts()->view("109807491887075545");
$result = $masto->admin()->accounts()->approve("109807491887075545");
$masto->admin()->accounts()->action("109807491887075545", ["type" => "none"]);
// reject, delete, enable, unsilence, unsuspend, unsensitive
$result = $masto->admin()->domain_allows()->list([]);
$result = $masto->admin()->domain_blocks()->list([]);
$result = $masto->admin()->ip_blocks()->list();
$result = $masto->admin()->ip_blocks()->view("1");
$result = $masto->admin()->ip_blocks()->create(["..."]);
$result = $masto->admin()->ip_blocks()->update("1", ["..."]);
$masto->admin()->ip_blocks()->delete("1");
$result = $masto->admin()->reports()->list([]);
$result = $masto->admin()->reports()->view("2");
$result = $masto->admin()->reports()->assign_to_self("2");
$result = $masto->admin()->reports()->unassign("2");
$result = $masto->admin()->reports()->resolve("2");
$result = $masto->admin()->reports()->reopen("2");
$result = $masto->admin()->trends()->statuses([]);
$result = $masto->admin()->trends()->links([]);
$result = $masto->admin()->trends()->tags([]);
$result = $masto->admin()->canonical_email_blocks()->list();
$result = $masto->admin()->dimensions()->list(["keys" => ["languages", "sources", "servers", "space_usage", "software_versions"]]);
$result = $masto->admin()->measures()->list(
[
"keys" => ["active_users", "new_users"],
"start_at" => \Carbon\Carbon::now()->subMonth()->format("Y-m-d"),
"end_at" => \Carbon\Carbon::now()->format("Y-m-d"),
]
);
Structure of code
Instances
Methods return either Model, array or just void.
class Accounts
{
// takes in the Maphpodon wrapper with GuzzleClient
public function __construct(protected Maphpodon $maphpodon)
{
}
/**
* @link https://docs.joinmastodon.org/methods/accounts/#get
* @param string $id
* @return Account
*/
public function get(string $id): Model|Account
{
return Mapper::mapJsonObjectToClass(
$this->maphpodon->get(sprintf('v1/accounts/%s', $id), []),
new Account()
);
}
/**
* @link https://docs.joinmastodon.org/methods/accounts/#statuses
* @param string $id
* @param array $params
* @return Status[]
*/
public function statuses(string $id, array $params = []): array
{
return Mapper::mapJsonObjectToClassArray(
$this->maphpodon->get(sprintf('v1/accounts/%s/statuses', $id), ["query" => $params]),
new Status()
);
}
Models
The returning objects are mapped into models.
class Status extends Model
{
// not nullable
public string $id;
// Carbon::parse
public Carbon $created_at;
// can be null
public ?string $in_reply_to_id;
public bool $sensitive;
// this is mapped to Application model
public Application $application;
// check if we have mapper in $mapArrayToObjects and map array to those
public array $media_attachments = [];
// we have no mapper for this, just put json-objects to array
public array $emojis = [];
public array $mapArrayToObjects = [
"media_attachments" => MediaAttachment::class,
Exceptions
Created Interface ExceptionCatcher that can be overwritten with any Catcher that handles the GuzzleException. Default will just rethrow the Exception. For an example created DevelopmentExceptionCatcher into helpers dir.
Testing
There is a basic phpunit setup.
Lorem Ipsum
Naming is done according the path. /api/v1/accounts is in entities/Accounts and /api/v1/accounts/follow is a follow function.
Have Fun!