Both speak Lemmy's shapes and joined the servers that get reports in that shape only once the pasture showed each keeps one with its reason. By their source, PieFed dropped the instance actor's report (it makes a user only of a Person or a Service) and Mbin kept it without the persona's words (it reads the reason from `summary` alone). With them in `ServiceReportTakers`, each keeps the reports of a thread and of a comment from "Reports from privapub.test" with alice's words, and none names her (piefed.sh and mbin.sh, 65 checks with the full sweep's 876). A report of a PieFed account alone, which PieFed would take from the reporter, is not sent yet; INTEROP says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
140 lines
13 KiB
Bash
140 lines
13 KiB
Bash
# PieFed 1.7.17: the threadiverse in Flask. Communities both ways (FEP-1b12), threads with titles, comments both ways,
|
|
# votes up and down both ways, a community poll, private messages both ways, a moderator's lock and removal,
|
|
# statistics. PieFed is driven through its Lemmy-style API (/api/alpha) as pfuser.
|
|
PF=https://piefed.test:6443
|
|
PFT=$(cat "$here/.state/piefed.token" 2>/dev/null)
|
|
# pf <method> <path> [json]: a PieFed API call as pfuser
|
|
pf() {
|
|
local method=$1 path=$2 body=${3:-}
|
|
if [ -n "$body" ]; then
|
|
site piefed.test -s -X "$method" "$PF/api/alpha/$path" -H "Authorization: Bearer $PFT" -H 'Content-Type: application/json' -d "$body"
|
|
else
|
|
site piefed.test -s -X "$method" "$PF/api/alpha/$path" -H "Authorization: Bearer $PFT"
|
|
fi
|
|
}
|
|
# the posts PieFed holds in a community, and the one whose ap_id is given
|
|
pf_posts() { pf GET "post/list?community_id=$1&sort=New&limit=50" | j "print(json.dumps([p['post'] for p in d.get('posts', [])]))"; }
|
|
pf_post_by_ap() { pf_posts "$1" | j "print(json.dumps(next((p for p in d if p['ap_id']=='$2'), None)))"; }
|
|
pf_comments() { pf GET "comment/list?post_id=$1&limit=50" | j "print(json.dumps([c['comment'] for c in d.get('comments', [])]))"; }
|
|
|
|
echo "piefed"
|
|
[ -n "$PFT" ] && ok "PieFed token for pfuser" || { ko "PieFed token"; return 1; }
|
|
PT=$(privapub_token alice_piefed)
|
|
PH="Authorization: Bearer $PT"
|
|
[ -n "$PT" ] && ok "PrivaPub token for alice_piefed" || { ko "PrivaPub token for alice_piefed"; return 1; }
|
|
jwt=$(privapub_root)
|
|
alice_id=$(curl -s -H "$PH" "$P/api/v1/accounts/verify_credentials" | j "print(d['id'])")
|
|
run=$(date +%s)
|
|
dogs="pfdogs$run"
|
|
pies="pies$run"
|
|
|
|
echo " communities"
|
|
dogs_gid=$(curl -s -X POST $P/clientapi/group/insert -H 'Content-Type: application/json' -H "Authorization: Bearer $jwt" \
|
|
-d "{\"avatarId\":\"$alice_id\",\"userName\":\"$dogs\",\"name\":\"Pasture dogs\",\"description\":\"a PrivaPub community\",\"isCommunity\":true}" | j "print(d['id'])")
|
|
dogs_on_pf=$(pf GET "resolve_object?q=!$dogs@privapub.test" | j "print(d['community']['community']['id'])")
|
|
[ -n "$dogs_on_pf" ] && ok "PieFed resolves a PrivaPub community" || ko "PieFed cannot resolve the PrivaPub community"
|
|
pf POST community/follow "{\"community_id\":$dogs_on_pf,\"follow\":true}" >/dev/null
|
|
until_true 45 '[ "$(pf GET "community?id=$dogs_on_pf" | j "print(d[\"community_view\"][\"subscribed\"])")" = "Subscribed" ]' \
|
|
&& ok "pfuser follows the PrivaPub community (Accept arrived)" || ko "PieFed's community follow not accepted ($(pf GET "community?id=$dogs_on_pf" | j "print(d[\"community_view\"][\"subscribed\"])"))"
|
|
pies_on_pf=$(pf POST community "{\"name\":\"$pies\",\"title\":\"Pasture pies\",\"description\":\"pies of the pasture\"}" | j "print(d['community_view']['community']['id'])")
|
|
pies_on_p=$(curl -s -H "$PH" "$P/api/v2/search?q=@$pies@piefed.test&resolve=true&type=accounts" | j "print(d['accounts'][0]['id'])")
|
|
[ -n "$pies_on_p" ] && ok "PrivaPub resolves a PieFed community" || ko "PrivaPub cannot resolve the PieFed community"
|
|
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/accounts/$pies_on_p/follow"
|
|
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/accounts/relationships?id[]=$pies_on_p" | j "print(d[0][\"following\"])")" = "True" ]' \
|
|
&& ok "alice follows the PieFed community (Accept arrived)" || ko "PrivaPub's community follow not accepted"
|
|
|
|
echo " threads"
|
|
pf_thread=$(pf POST post "{\"title\":\"A PieFed thread\",\"body\":\"posted from PieFed into PrivaPub\",\"community_id\":$dogs_on_pf}" | j "print(d['post_view']['post']['ap_id'])")
|
|
dogs_on_p=$(curl -s -H "$PH" "$P/api/v1/accounts/lookup?acct=$dogs" | j "print(d['id'])")
|
|
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/accounts/$dogs_on_p/statuses" | j "print(any(s[\"uri\"]==\"$pf_thread\" and (s.get(\"privapub\") or {}).get(\"title\")==\"A PieFed thread\" for s in d))")" = "True" ]' \
|
|
&& ok "a PieFed thread in the PrivaPub community arrives with its title" || ko "PieFed's thread missing or untitled on PrivaPub"
|
|
curl -s -o /dev/null -X POST $P/clientapi/post/insert -H 'Content-Type: application/json' -H "Authorization: Bearer $jwt" \
|
|
-d "{\"avatarId\":\"$alice_id\",\"title\":\"A PrivaPub community thread $run\",\"text\":\"posted into our own community for PieFed\",\"groupId\":\"$dogs_gid\"}"
|
|
dogs_post=$(podman exec pasture-mongo mongosh --quiet PrivaPub --eval 'print(db.Post.findOne({Text:/posted into our own community for PieFed/}, {}, {sort:{_id:-1}}).ObjectURI)')
|
|
until_true 45 '[ "$(pf_post_by_ap "$dogs_on_pf" "$dogs_post" | j "print(d and d[\"title\"])")" = "A PrivaPub community thread $run" ]' \
|
|
&& ok "a titled post in the PrivaPub community reaches PieFed through its announce" || ko "PrivaPub community post missing on PieFed"
|
|
pf_pies_thread=$(pf POST post "{\"title\":\"Pies only $run\",\"body\":\"a PieFed community post\",\"community_id\":$pies_on_pf}" | j "print(d['post_view']['post']['ap_id'])")
|
|
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 (s.get('reblog') or s)['uri']=='$1'), ''))"; }
|
|
until_true 45 '[ -n "$(p_home_has "$pf_pies_thread")" ]' \
|
|
&& ok "the PieFed community's announce brings its thread to alice's home" || ko "PieFed community thread missing from alice's home"
|
|
pies_thread_on_p=$(p_home_has "$pf_pies_thread")
|
|
p_thread=$(curl -s -X POST -H "$PH" $P/api/v1/statuses --data-urlencode "status=A PrivaPub thread
|
|
@$pies@piefed.test posted from PrivaPub" -d 'visibility=public')
|
|
p_thread_id=$(echo "$p_thread" | j "print(d['id'])"); p_thread_uri=$(echo "$p_thread" | j "print(d['uri'])")
|
|
until_true 45 '[ "$(pf_post_by_ap "$pies_on_pf" "$p_thread_uri")" != "null" ]' && ok "alice's thread lands in the PieFed community" || ko "PrivaPub thread missing from the PieFed community"
|
|
p_thread_on_pf=$(pf_post_by_ap "$pies_on_pf" "$p_thread_uri" | j "print(d['id'])")
|
|
|
|
echo " comments"
|
|
pf POST comment "{\"post_id\":$p_thread_on_pf,\"body\":\"a PieFed comment on PrivaPub\"}" >/dev/null
|
|
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$p_thread_id/context" | j "print(any(\"a PieFed comment on PrivaPub\" in s[\"content\"] for s in d[\"descendants\"]))")" = "True" ]' \
|
|
&& ok "PieFed's comment threads under alice's post" || ko "PieFed's comment missing on PrivaPub"
|
|
curl -s -o /dev/null -X POST -H "$PH" $P/api/v1/statuses -d "status=a PrivaPub comment on PieFed&in_reply_to_id=$pies_thread_on_p&visibility=public"
|
|
pies_thread_id=$(pf GET "resolve_object?q=$pf_pies_thread" | j "print(d['post']['post']['id'])")
|
|
until_true 45 '[ "$(pf_comments "$pies_thread_id" | j "print(any(\"a PrivaPub comment on PieFed\" in c[\"body\"] for c in d))")" = "True" ]' \
|
|
&& ok "alice's reply becomes a comment on PieFed" || ko "PrivaPub reply missing as a PieFed comment"
|
|
|
|
echo " votes"
|
|
pf POST post/like "{\"post_id\":$p_thread_on_pf,\"score\":1}" >/dev/null
|
|
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$p_thread_id" | j "print(d[\"favourites_count\"])")" = "1" ]' \
|
|
&& ok "PieFed's upvote counts as a like on PrivaPub" || ko "PieFed's upvote not counted"
|
|
pf POST post/like "{\"post_id\":$p_thread_on_pf,\"score\":-1}" >/dev/null
|
|
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$p_thread_id" | j "print(d[\"favourites_count\"], ((d.get(\"privapub\") or {}).get(\"votes\") or {}).get(\"down\"))")" = "0 1" ]' \
|
|
&& ok "PieFed's change to a downvote reaches PrivaPub" || ko "PieFed's change to a downvote not applied ($(curl -s -H "$PH" "$P/api/v1/statuses/$p_thread_id" | j "print(d[\"favourites_count\"], (d.get(\"privapub\") or {}).get(\"votes\"))"))"
|
|
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses/$pies_thread_on_p/favourite"
|
|
until_true 45 '[ "$(pf GET "post?id=$pies_thread_id" | j "print(d[\"post_view\"][\"counts\"][\"upvotes\"])")" = "2" ]' \
|
|
&& ok "alice's like is an upvote on PieFed" || ko "like not counted as an upvote on PieFed ($(pf GET "post?id=$pies_thread_id" | j "print(d[\"post_view\"][\"counts\"])"))"
|
|
|
|
echo " polls"
|
|
ends=$(date -u -d '+2 days' +%Y-%m-%dT%H:%M:%S.000000Z)
|
|
pf_poll=$(pf POST post "{\"title\":\"Which pie $run\",\"body\":\"vote for one\",\"community_id\":$pies_on_pf,\"poll\":{\"mode\":\"single\",\"end_poll\":\"$ends\",\"choices\":[{\"id\":1,\"choice_text\":\"apple\",\"sort_order\":0},{\"id\":2,\"choice_text\":\"cherry\",\"sort_order\":1}]}}")
|
|
pf_poll_uri=$(echo "$pf_poll" | j "print(d['post_view']['post']['ap_id'])")
|
|
until_true 45 '[ -n "$(p_home_has "$pf_poll_uri")" ]' && ok "a PieFed poll reaches alice's home" || ko "the PieFed poll never arrived ($(echo "$pf_poll" | cut -c1-200))"
|
|
poll_on_p=$(p_home_has "$pf_poll_uri")
|
|
poll=$(curl -s -H "$PH" "$P/api/v1/statuses/$poll_on_p" | j "print(json.dumps(d.get('poll')))")
|
|
[ "$(echo "$poll" | j "print([o['title'] for o in d['options']])")" = "['apple', 'cherry']" ] && ok "as a poll with its choices" || ko "the PieFed poll is no poll on PrivaPub ($poll)"
|
|
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/polls/$(echo "$poll" | j "print(d['id'])")/votes" -H 'Content-Type: application/json' -d '{"choices":[1]}'
|
|
pf_poll_id=$(echo "$pf_poll" | j "print(d['post_view']['post']['id'])")
|
|
until_true 60 '[ "$(pf GET "post?id=$pf_poll_id" | j "print(sum(c.get(\"num_votes\", 0) for c in d[\"post_view\"][\"post\"][\"poll\"][\"choices\"] if c[\"choice_text\"]==\"cherry\"))")" = "1" ]' \
|
|
&& ok "alice's vote counts on PieFed" || ko "alice's vote not counted on PieFed ($(pf GET "post?id=$pf_poll_id" | j "print(d[\"post_view\"][\"post\"].get(\"poll\"))"))"
|
|
|
|
echo " private messages"
|
|
alice_on_pf=$(pf GET "resolve_object?q=@alice_piefed@privapub.test" | j "print(d['person']['person']['id'])")
|
|
pf POST private_message "{\"content\":\"a secret from PieFed\",\"recipient_id\":$alice_on_pf}" >/dev/null
|
|
until_true 45 'curl -s -H "$PH" "$P/api/v1/conversations" | grep -q "a secret from PieFed"' && ok "PieFed's private message arrives as a DM" || ko "PieFed's private message missing on PrivaPub"
|
|
curl -s -o /dev/null -X POST -H "$PH" $P/api/v1/statuses -d 'status=@pfuser@piefed.test a secret from PrivaPub&visibility=direct'
|
|
until_true 45 'pf GET "private_message/list?limit=50" | grep -q "a secret from PrivaPub"' && ok "alice's DM arrives as a PieFed private message" || ko "DM missing on PieFed"
|
|
|
|
echo " moderation"
|
|
p_locked() { curl -s -H "$PH" "$P/api/v1/statuses/$pies_thread_on_p" | j "print((d.get('privapub') or {}).get('locked'))"; }
|
|
pf POST post/lock "{\"post_id\":$pies_thread_id,\"locked\":true}" >/dev/null
|
|
until_true 45 '[ "$(p_locked)" = "True" ]' && ok "a moderator's lock reaches PrivaPub" || ko "a moderator's lock did not reach PrivaPub"
|
|
[ "$(curl -s -o /dev/null -w '%{http_code}' -X POST -H "$PH" $P/api/v1/statuses -d "status=too late&in_reply_to_id=$pies_thread_on_p&visibility=public")" = "422" ] \
|
|
&& ok "a reply to the locked thread is refused" || ko "a reply to the locked thread was taken"
|
|
pf POST post/lock "{\"post_id\":$pies_thread_id,\"locked\":false}" >/dev/null
|
|
until_true 45 '[ "$(p_locked)" = "False" ]' && ok "a moderator's unlock reaches PrivaPub" || ko "a moderator's unlock did not reach PrivaPub"
|
|
echo " reports"
|
|
# PieFed takes a report only from a person or a service, as Lemmy does (owner decision 2026-10-06): alice's report of
|
|
# pfuser's thread and comment leaves from PrivaPub's reporter, one Flag each, and never names her
|
|
pf POST comment "{\"post_id\":$pies_thread_id,\"body\":\"a PieFed comment to report $run\"}" >/dev/null
|
|
pf_comment_on_p() { curl -s -H "$PH" "$P/api/v1/statuses/$pies_thread_on_p/context" | j "print(next((s['id'] for s in d['descendants'] if 'a PieFed comment to report $run' in s['content']), ''))"; }
|
|
until_true 45 '[ -n "$(pf_comment_on_p)" ]' && ok "pfuser's comment to report reaches PrivaPub" || ko "pfuser's comment never reached PrivaPub"
|
|
pf_author_on_p=$(curl -s -H "$PH" "$P/api/v1/statuses/$pies_thread_on_p" | j "print(d['account']['id'])")
|
|
reason="a pasture report $run"
|
|
[ "$(p_report "$PH" "$pf_author_on_p" "$reason" "$pies_thread_on_p" "$(pf_comment_on_p)")" = "True" ] \
|
|
&& ok "PrivaPub says alice's report was forwarded" || ko "PrivaPub did not forward alice's report"
|
|
pf_reports() { podman exec pasture-postgres psql -U pasture -d piefed -tAc "select count(*) from report r join \"user\" u on u.id = r.reporter_id where r.reasons = '$reason' and u.ap_profile_id = '$P_REPORTER' and r.$1"; }
|
|
until_true 45 '[ "$(pf_reports "suspect_post_id is not null and r.suspect_post_reply_id is null")" = "1" ]' && ok "PieFed keeps the thread's report from PrivaPub's reporter, with alice's words" || ko "PieFed kept no report of the thread"
|
|
until_true 45 '[ "$(pf_reports "suspect_post_reply_id is not null")" = "1" ]' && ok "PieFed keeps the comment's report from PrivaPub's reporter, with alice's words" || ko "PieFed kept no report of the comment"
|
|
[ "$(podman exec pasture-postgres psql -U pasture -d piefed -tAc "select count(*) from report r join \"user\" u on u.id = r.reporter_id where u.ap_profile_id like '%alice_piefed%'")" = "0" ] \
|
|
&& ok "no report on PieFed names alice" || ko "a report on PieFed names alice"
|
|
pf POST post/remove "{\"post_id\":$pies_thread_id,\"removed\":true,\"reason\":\"pasture\"}" >/dev/null
|
|
until_true 45 '[ -z "$(p_home_has "$pf_pies_thread")" ]' && ok "a moderator's removal reaches PrivaPub" || ko "a moderator's removal did not reach PrivaPub"
|
|
|
|
echo " unfollow"
|
|
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/accounts/$pies_on_p/unfollow"
|
|
until_true 45 '[ "$(podman exec pasture-postgres psql -U pasture -d piefed -tAc "select count(*) from community_member m join \"user\" u on u.id = m.user_id where u.ap_profile_id like '"'%alice_piefed%'"' and m.community_id = $pies_on_pf")" = "0" ]' \
|
|
&& ok "alice's unfollow reaches the PieFed community" || ko "the PieFed community still counts alice"
|
|
|
|
echo " statistics"
|
|
stats_check piefed.test piefed
|