他のサーバーのアクターが我々が作成したアクターをフォローした後、再び解除するとどうなるでしょうか?ActivityPub.Academyで試してみましょう。先ほどと同様に、ActivityPub.Academyの検索ボックスに我々が作成したアクターのフェディバースハンドルを入力して検索します:
よく見ると、アクター名の右側にあったフォローボタンの場所にフォロー解除(unfollow)ボタンがあります。このボタンを押してフォローを解除した後、Activity Logに入ってどのようなアクティビティが送信されるか確認してみましょう:
上のようにUndo(Follow)
アクティビティが送信されました。右下のshow sourceを押すとアクティビティの詳細な内容を見ることができます:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://activitypub.academy/users/dobussia_dovornath#follows/3283/undo",
"type": "Undo",
"actor": "https://activitypub.academy/users/dobussia_dovornath",
"object": {
"id": "https://activitypub.academy/98b131b8-89ea-49ba-b2bd-3ee0f5a87694",
"type": "Follow",
"actor": "https://activitypub.academy/users/dobussia_dovornath",
"object": "https://temp-address.serveo.net/users/johndoe"
}
}
上のJSONオブジェクトを見ると、Undo(Follow)
アクティビティの中に先ほどインボックスに入ってきたFollow
アクティビティが含まれていることがわかります。しかし、インボックスでUndo(Follow)
アクティビティを受信した時の動作を何も定義していないため、何も起こりませんでした。
Undo(Follow)
アクティビティの受信
フォロー解除を実装するためにsrc/federation.tsファイルを開き、Fedifyが提供するUndo
クラスをimport
します:
import {
Accept,
Endpoints,
Follow,
Person,
Undo, // 追加
createFederation,
exportJwk,
generateCryptoKeyPair,
getActorHandle,
importJwk,
} from "@fedify/fedify";
そしてon(Follow, ...)
の後に続けてon(Undo, ...)
を追加します:
federation
.setInboxListeners("/users/{identifier}/inbox", "/inbox")
.on(Follow, async (ctx, follow) => {
// ... 省略 ...
})
.on(Undo, async (ctx, undo) => {
const object = await undo.getObject();
if (!(object instanceof Follow)) return;
if (undo.actorId == null || object.objectId == null) return;
const parsed = ctx.parseUri(object.objectId);
if (parsed == null || parsed.type !== "actor") return;
db.prepare(
`
DELETE FROM follows
WHERE following_id = (
SELECT actors.id
FROM actors
JOIN users ON actors.user_id = users.id
WHERE users.username = ?
) AND follower_id = (SELECT id FROM actors WHERE uri = ?)
`,
).run(parsed.identifier, undo.actorId.href);
});
今回はフォローリクエストを処理する時よりもコードが短くなっています。Undo(Follow)
アクティビティの中に入っているのがFollow
アクティビティかどうか確認した後、parseUri()
メソッドを使って取り消そうとしているFollow
アクティビティのフォロー対象が我々が作成したアクターかどうか確認し、follows
テーブルから該当するレコードを削除します。
テスト
先ほどActivityPub.Academyでフォロー解除ボタンを押してしまったので、もう一度フォロー解除をすることはできません。仕方がないので再度フォローした後、フォロー解除してテストする必要があります。しかしその前に、follows
テーブルを空にする必要があります。そうしないと、フォローリクエストが来た時に既にレコードが存在するためエラーが発生してしまいます。
sqlite3
コマンドを使用してfollows
テーブルを空にしましょう:
echo "DELETE FROM follows;" | sqlite3 microblog.sqlite3
そして再度フォローボタンを押した後、データベースを確認します:
echo "SELECT * FROM follows;" | sqlite3 -table microblog.sqlite3
フォローリクエストがきちんと処理されていれば、次のような結果が出力されるはずです:
following_id |
follower_id |
created |
---|---|---|
1 |
2 |
2024-09-02 01:05:17 |
そして再度フォロー解除ボタンを押した後、データベースをもう一度確認します:
echo "SELECT count(*) FROM follows;" | sqlite3 -table microblog.sqlite3
フォロー解除リクエストがきちんと処理されていれば、レコードが消えているので次のような結果が出力されるはずです:
count(*) |
---|
0 |