Add a rudimentary API endpoint. TODO: Add auth to the API

This commit is contained in:
Lewis Dale 2023-03-21 08:42:01 +00:00
parent ec83d67bde
commit 7dc9d0a5cb
6 changed files with 161 additions and 15 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/vendor/ /vendor/
/.phpunit.result.cache /.phpunit.result.cache
.idea .idea
/*.db

View File

@ -17,6 +17,9 @@ use Lewisdale\Webmentions\Webmention;
use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\HttpClient\HttpClient;
$router = new Router(); $router = new Router();
$gateway = new SqliteGateway("webmentions.db");
$apiController = new \Lewisdale\Webmentions\Api\WebmentionApi($gateway);
$router->post("/send", function (Request $req, Response $response) { $router->post("/send", function (Request $req, Response $response) {
$mentioner = new Webmention(); $mentioner = new Webmention();
@ -30,11 +33,11 @@ $router->post("/send", function (Request $req, Response $response) {
} }
}); });
$router->post("/endpoint", function (Request $req, Response $response) { $router->post("/endpoint", function (Request $req, Response $response) use ($gateway) {
$source = $req->post['source']; $source = $req->post['source'];
$target = $req->post['target']; $target = $req->post['target'];
$endpoint = new Endpoint(HttpClient::create(), new SqliteGateway("webmentions.db")); $endpoint = new Endpoint(HttpClient::create(), $gateway);
try { try {
$endpoint->receiveWebmention($source, $target); $endpoint->receiveWebmention($source, $target);
@ -57,4 +60,8 @@ $router->post("/endpoint", function (Request $req, Response $response) {
}); });
$router->get('/', fn($req, $res) => "<h1>Webmention server</h1>"); $router->get('/', fn($req, $res) => "<h1>Webmention server</h1>");
$router->get('/api/webmentions', [$apiController, "list"]);
$router->get('/api/webmentions/(\d+)', [$apiController, "get"]);
$router->dispatch(); $router->dispatch();

43
src/Api/WebmentionApi.php Normal file
View File

@ -0,0 +1,43 @@
<?php declare(strict_types=1);
namespace Lewisdale\Webmentions\Api;
use Lewisdale\Webmentions\Gateways\WebmentionGatewayInterface;
use Lewisdale\Webmentions\Router\Request;
use Lewisdale\Webmentions\Router\Response;
use Lewisdale\Webmentions\Router\StatusCode;
/**
* API Controller for retrieving Webmentions
*/
class WebmentionApi
{
function __construct(private readonly WebmentionGatewayInterface $gateway)
{
}
// List Webmentions. Optionally filter by target.
public function list(Request $request, Response $response)
{
$target = array_key_exists("post", $request->query) ? $request->query["post"] : null;
$mentions = !empty($target) ? $this->gateway->getByPost($target) : $this->gateway->list();
return $response->json($mentions);
}
// Get a webmention by ID
public function get(Request $request, Response $response)
{
$id = (int)$request->params[0];
if ($id) {
$mention = $this->gateway->get($id);
if ($mention) {
$response->status_code = StatusCode::Ok;
return $response->json($mention);
}
}
$response->status_code = StatusCode::NotFound;
}
}

View File

@ -100,18 +100,7 @@ class SqliteGateway extends WebmentionGatewayInterface
$statement = $this->connection->prepare($sql); $statement = $this->connection->prepare($sql);
$statement->execute(["post" => $post]); $statement->execute(["post" => $post]);
$mentions = []; $mentions = array_map([$this, 'map_row'], $statement->fetchAll(PDO::FETCH_ASSOC));
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
$mentions[] = new Webmention(
$row["id"],
$row["target"],
$row["source"],
MentionType::from($row["type"]),
$row["content"],
new Author((int)$row["author"])
);
}
$statement->closeCursor(); $statement->closeCursor();
return $mentions; return $mentions;
@ -226,7 +215,50 @@ class SqliteGateway extends WebmentionGatewayInterface
$statement = $this->connection->prepare($sql); $statement = $this->connection->prepare($sql);
$statement->execute($values); $statement->execute($values);
return $statement->fetchAll(); return array_map([$this, 'map_row'], $statement->fetchAll());
}
public function list(): array
{
$sql = <<<SQL
SELECT webmentions.id as id,
webmentions.source as source,
webmentions.target as target,
webmentions.type as type,
webmentions.content as content,
authors.id as author,
authors.name as author_name,
authors.url as author_url,
authors.photo as author_photo
FROM webmentions
LEFT JOIN
authors ON webmentions.author=authors.id
SQL;
$statement = $this->connection->query($sql);
$mentions = array_map([$this, 'map_row'], $statement->fetchAll(PDO::FETCH_ASSOC));
$statement->closeCursor();
return $mentions;
}
private function map_row(array|false $row): ?Webmention
{
if ($row) {
return new Webmention(
$row["id"],
$row["target"],
$row["source"],
MentionType::from($row["type"]),
$row["content"],
new Author(
(int)$row["author"],
$row["author_name"],
$row["author_url"],
$row["author_photo"]
)
);
}
return null;
} }
} }

View File

@ -17,4 +17,6 @@ abstract class WebmentionGatewayInterface
abstract public function get(int $id): ?Webmention; abstract public function get(int $id): ?Webmention;
abstract public function find(array $values): array; abstract public function find(array $values): array;
abstract public function list(): array;
} }

View File

@ -241,4 +241,65 @@ class SqliteGatewayTest extends TestCase
$retrieved = $this->gateway->find(["author_name" => "Carl Weathers"]); $retrieved = $this->gateway->find(["author_name" => "Carl Weathers"]);
$this->assertCount(2, $retrieved); $this->assertCount(2, $retrieved);
} }
public function testCanListAllWebmentions()
{
$this->gateway->save(new Webmention(
null,
"https://a-target-url.com",
"https://a-source-url.com",
MentionType::Like,
"Liked this post",
new \Lewisdale\Webmentions\Models\Author(
null,
"Doreen Mifah",
"https://my-homepage.com",
"https://cdn.imgserver.com/400/400"
)
));
$this->gateway->save(new Webmention(
null,
"https://a-target-url.com",
"https://a-source-url.com",
MentionType::Like,
"Liked this post",
new \Lewisdale\Webmentions\Models\Author(
null,
"Carl Weathers",
"https://carl-weathers.com",
"https://cdn.imgserver.com/400/400"
)
));
$this->gateway->save(new Webmention(
null,
"https://a-target-url.com",
"https://a-source-url.com",
MentionType::Like,
"Liked this post",
new \Lewisdale\Webmentions\Models\Author(
null,
"Barry White",
"https://barry.white.com",
"https://cdn.imgserver.com/400/400"
)
));
$this->gateway->save(new Webmention(
null,
"https://a-target-url.com",
"https://a-source-url.com",
MentionType::Reply,
"This was a cool post!",
new \Lewisdale\Webmentions\Models\Author(
null,
"Carl Weathers",
"https://carl-weathers.com",
"https://cdn.imgserver.com/400/400"
)
));
$this->assertCount(4, $this->gateway->list());
}
} }