# Ghost 6.67 and its ActivityPub service 1.2.14: alice follows the publication and its post reaches her as a titled # Article, edited and deleted; the publication follows alice, and from its Network screen likes, reposts and answers her # post and posts a note; alice's like and boost count there; both unfollows; statistics. Driven through Ghost's admin # API and the service's own API (peers/ghost.sh). . "$here/peers/ghost.sh" p_home_has() { curl -s -H "$PH" "$P/api/v1/timelines/home?limit=40" | j "print(next(((s.get('reblog') or s)['id'] for s in d if '$1' in ((s.get('reblog') or s)['content'] or '') or '$1' in (((s.get('reblog') or s).get('privapub') or {}).get('title') or '')), ''))"; } p_status() { curl -s -H "$PH" "$P/api/v1/statuses/$1" | j "print(d.get('$2'))"; } enc() { python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$1"; } echo "ghost" ghost_settle >/dev/null 2>&1 [ "$(ghost_ap GET v1/account/me | j "print(d['handle'])")" = "@index@ghost.test" ] && ok "Ghost's ActivityPub service knows the publication" || { ko "Ghost's ActivityPub service"; return 1; } PT=$(privapub_token alice_ghost) PH="Authorization: Bearer $PT" [ -n "$PT" ] && ok "PrivaPub token for alice_ghost" || { ko "PrivaPub token for alice_ghost"; return 1; } run=$(date +%s) echo " following the publication" pub_on_p=$(curl -s -H "$PH" "$P/api/v2/search?q=index@ghost.test&resolve=true&type=accounts" | j "print(d['accounts'][0]['id'])") [ -n "$pub_on_p" ] && ok "PrivaPub resolves the publication" || ko "PrivaPub cannot resolve the publication" curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/accounts/$pub_on_p/follow" until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/accounts/relationships?id[]=$pub_on_p" | j "print(d[0][\"following\"])")" = "True" ]' \ && ok "alice follows the publication (Accept arrived)" || ko "the publication's Accept never arrived" echo " articles" post=$(ghost_api POST "posts/?source=html" "{\"posts\":[{\"title\":\"A Ghost article $run\",\"html\":\"

Published on Ghost, $run.

\",\"status\":\"published\"}]}") post_id=$(echo "$post" | j "print(d['posts'][0]['id'])"); updated_at=$(echo "$post" | j "print(d['posts'][0]['updated_at'])") until_true 60 '[ -n "$(p_home_has "A Ghost article $run")" ]' && ok "the publication's post reaches alice's home" || ko "the publication's post never reached alice" art_on_p=$(p_home_has "A Ghost article $run") [ "$(curl -s -H "$PH" "$P/api/v1/statuses/$art_on_p" | j "print((d.get('privapub') or {}).get('title'))")" = "A Ghost article $run" ] \ && ok "as an Article with its title" || ko "the article arrived without its title ($(curl -s -H "$PH" "$P/api/v1/statuses/$art_on_p" | j "print((d.get('privapub') or {}).get('title'))"))" curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses/$art_on_p/favourite" art_uri=$(curl -s -H "$PH" "$P/api/v1/statuses/$art_on_p" | j "print(d['uri'])") until_true 45 '[ "$(ghost_ap GET "v1/post/$(enc "$art_uri")" | j "print(d.get(\"likeCount\"))")" = "1" ]' \ && ok "alice's like counts on Ghost" || ko "alice's like never counted on Ghost ($(ghost_ap GET "v1/post/$(enc "$art_uri")" | j "print(d.get('likeCount'))"))" curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses/$art_on_p/reblog" until_true 45 '[ "$(ghost_ap GET "v1/post/$(enc "$art_uri")" | j "print(d.get(\"repostCount\"))")" = "1" ]' \ && ok "alice's boost counts on Ghost" || ko "alice's boost never counted on Ghost" ghost_api PUT "posts/$post_id/?source=html" "{\"posts\":[{\"title\":\"A Ghost article $run\",\"html\":\"

Published on Ghost, $run, then edited.

\",\"updated_at\":\"$updated_at\"}]}" >/dev/null until_true 60 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$art_on_p" | j "print(\"then edited\" in d[\"content\"])")" = "True" ]' \ && ok "its edit reaches PrivaPub" || ko "its edit never reached PrivaPub" echo " the publication follows alice" ghost_ap POST "v1/actions/follow/$(enc "@alice_ghost@privapub.test")" >/dev/null until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/accounts/verify_credentials" | j "print(d[\"followers_count\"])")" -ge 1 ]' \ && ok "the publication follows alice" || ko "Ghost's follow never reached alice" p_post=$(curl -s -X POST -H "$PH" $P/api/v1/statuses -d "status=a PrivaPub post for Ghost $run&visibility=public") p_uri=$(echo "$p_post" | j "print(d['uri'])"); p_post_id=$(echo "$p_post" | j "print(d['id'])") until_true 45 'ghost_ap GET v1/feed/notes | grep -q "a PrivaPub post for Ghost $run"' && ok "alice's post reaches the publication's Network feed" || ko "alice's post never reached Ghost" ghost_ap POST "v1/actions/like/$(enc "$p_uri")" >/dev/null until_true 45 '[ "$(p_status $p_post_id favourites_count)" = "1" ]' && ok "Ghost's like counts on PrivaPub" || ko "Ghost's like never counted" ghost_ap POST "v1/actions/repost/$(enc "$p_uri")" >/dev/null until_true 45 '[ "$(p_status $p_post_id reblogs_count)" = "1" ]' && ok "Ghost's repost is a boost on PrivaPub" || ko "Ghost's repost never counted" ghost_ap POST "v1/actions/reply/$(enc "$p_uri")" "{\"content\":\"a Ghost reply $run\"}" >/dev/null until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$p_post_id/context" | j "print(any(\"a Ghost reply $run\" in s[\"content\"] for s in d[\"descendants\"]))")" = "True" ]' \ && ok "Ghost's reply threads under alice's post" || ko "Ghost's reply missing on PrivaPub" ghost_ap POST v1/actions/note "{\"content\":\"a Ghost note $run\"}" >/dev/null until_true 45 '[ -n "$(p_home_has "a Ghost note $run")" ]' && ok "the publication's note reaches alice's home" || ko "the publication's note never reached alice" echo " deletions" ghost_api DELETE "posts/$post_id/" >/dev/null until_true 60 '[ "$(curl -s -o /dev/null -w "%{http_code}" -H "$PH" "$P/api/v1/statuses/$art_on_p")" = "404" ]' \ && ok "the article's deletion reaches PrivaPub" || ko "the deleted article still shows on PrivaPub" echo " unfollows" ghost_ap POST "v1/actions/unfollow/$(enc "@alice_ghost@privapub.test")" >/dev/null until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/accounts/verify_credentials" | j "print(d[\"followers_count\"])")" = "0" ]' \ && ok "the publication's unfollow reaches alice" || ko "alice still counts the publication" curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/accounts/$pub_on_p/unfollow" until_true 45 '[ "$(ghost_ap GET v1/account/me | j "print(d[\"followerCount\"])")" = "0" ]' \ && ok "alice's unfollow reaches the publication" || ko "Ghost still counts alice" echo " statistics" stats_check ghost.test ghost