Files
SocialPub/tools/pasture/scenarios/friendica.sh
T

103 lines
9.3 KiB
Bash
Raw Normal View History

# Friendica 2026.05: follows both ways; posts both ways, a titled one as an Article; comments both ways; likes both
# ways, Friendica's dislike as a downvote, a boost; edits, deletes and unfollows both ways; statistics. Friendica keeps every
# activity (a like, a dislike, a boost) as an item of its own with a verb, so what it holds is read from its MySQL
# (database friendica) by `thr-parent`, never fetched. Its API takes HTTP Basic authentication. An edit made through its
# Mastodon API never federates (Statuses::put leaves `edited` alone, and only a changed `edited` notifies), so fruser
# edits through the web editor, signed in with a cookie.
FR=https://friendica.test:6443
frc() { curl -sk --resolve friendica.test:6443:127.0.0.1 -u "$(cat "$here/.state/friendica.token" 2>/dev/null)" -H 'Accept: application/json' "$@"; }
fr_sql() { podman exec pasture-mysql mysql -upasture -ppasture friendica -Nse "$1" 2>/dev/null; }
# fr_count <uri> <verb>: the live activities of a verb on a post Friendica holds, by the verb's last part ("/like",
# "/dislike", "#Announce": a boost that arrives keeps ActivityStreams' name, where Friendica's own are "/share")
fr_count() { fr_sql "select count(*) from \`post-view\` where \`thr-parent\` = '$1' and verb like '%$2' and deleted = 0"; }
# fr_web_edit <status id> <text>: fruser edits a post through the web editor (the API's status id is the uri-id)
fr_web_edit() {
local jar="$here/.state/friendica.cookies" credentials item
credentials=$(cat "$here/.state/friendica.token")
curl -sk --resolve friendica.test:6443:127.0.0.1 -c "$jar" -o /dev/null -X POST "$FR/login" -d auth-params=login -d username=fruser \
--data-urlencode "password=${credentials#*:}"
item=$(fr_sql "select id from \`post-user\` where \`uri-id\` = $1 and uid = (select uid from user where nickname = 'fruser')")
curl -sk --resolve friendica.test:6443:127.0.0.1 -b "$jar" -o /dev/null -X POST "$FR/item" -d "post_id=$item" --data-urlencode "body=$2"
}
p_home_id() { curl -s -H "$PH" "$P/api/v1/timelines/home?limit=40" | j "print(next((o['id'] for o in ((s.get('reblog') or s) for s in d) if '$1' in (o['content'] or '') or '$1' in ((o.get('privapub') or {}).get('title') or '')), ''))"; }
echo "friendica"
[ -s "$here/.state/friendica.token" ] && ok "Friendica credentials for fruser" || { ko "Friendica credentials"; return 1; }
PT=$(privapub_token alice_friendica)
PH="Authorization: Bearer $PT"
[ -n "$PT" ] && ok "PrivaPub token for alice_friendica" || { ko "PrivaPub token for alice_friendica"; return 1; }
echo " discovery and follows"
alice_on_fr=$(frc "$FR/api/v2/search?q=@alice_friendica@privapub.test&resolve=true&type=accounts" | j "print(d['accounts'][0]['id'])")
[ -n "$alice_on_fr" ] && ok "Friendica resolves @alice_friendica@privapub.test" || ko "Friendica cannot resolve alice_friendica"
fr_on_p=$(curl -s -H "$PH" "$P/api/v2/search?q=fruser@friendica.test&resolve=true&type=accounts" | j "print(d['accounts'][0]['id'])")
[ -n "$fr_on_p" ] && ok "PrivaPub resolves @fruser@friendica.test" || ko "PrivaPub cannot resolve fruser"
# a run cut short, or a Friendica made anew, leaves follows behind on one side only: unfollow first, so both follows
# below are new requests
frc -o /dev/null -X POST "$FR/api/v1/accounts/$alice_on_fr/unfollow"
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/accounts/$fr_on_p/unfollow"
sleep 3
frc -o /dev/null -X POST "$FR/api/v1/accounts/$alice_on_fr/follow"
until_true 45 '[ "$(frc "$FR/api/v1/accounts/relationships?id[]=$alice_on_fr" | j "print(d[0][\"following\"])")" = "True" ]' \
&& ok "fruser follows alice_friendica (Accept arrived)" || ko "Friendica's follow not accepted"
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/accounts/$fr_on_p/follow"
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/accounts/relationships?id[]=$fr_on_p" | j "print(d[0][\"following\"])")" = "True" ]' \
&& ok "alice_friendica follows fruser (Accept arrived)" || ko "PrivaPub's follow not accepted"
echo " posts"
p_post=$(curl -s -X POST -H "$PH" "$P/api/v1/statuses" -d 'status=Hello Friendica from PrivaPub&visibility=public')
p_post_id=$(echo "$p_post" | j "print(d['id'])"); p_post_uri=$(echo "$p_post" | j "print(d['uri'])")
until_true 45 '[ "$(fr_sql "select count(*) from \`post-view\` where uri = '"'$p_post_uri'"' and deleted = 0")" -ge 1 ]' \
&& ok "alice_friendica's post reaches Friendica" || ko "alice_friendica's post missing on Friendica"
fr_post=$(frc -X POST "$FR/api/v1/statuses" -d 'status=Hello PrivaPub from Friendica&visibility=public' | j "print(d['id'])")
until_true 45 '[ -n "$(p_home_id "Hello PrivaPub from Friendica")" ]' && ok "fruser's post reaches alice_friendica's home" || ko "fruser's post never arrived"
fr_on_p_post=$(p_home_id "Hello PrivaPub from Friendica")
fr_post_uri=$(curl -s -H "$PH" "$P/api/v1/statuses/$fr_on_p_post" | j "print(d['uri'])")
frc -o /dev/null -X POST "$FR/api/v1/statuses" -d 'status=An article with paragraphs.&friendica[title]=A Friendica article&visibility=public'
until_true 45 '[ -n "$(p_home_id "A Friendica article")" ]' && ok "fruser's titled post arrives with its title" || ko "the titled post never arrived, or lost its title"
echo " comments"
frc -o /dev/null -X POST "$FR/api/v1/statuses" -d "status=@alice_friendica@privapub.test a Friendica comment&in_reply_to_id=$(frc "$FR/api/v2/search?q=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))" "$p_post_uri")&resolve=true&type=statuses" | j "print(d['statuses'][0]['id'])")&visibility=public"
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$p_post_id/context" | j "print(any(\"a Friendica comment\" in s[\"content\"] for s in d[\"descendants\"]))")" = "True" ]' \
&& ok "fruser's comment threads under alice_friendica's post" || ko "Friendica's comment missing on PrivaPub"
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses" -d "status=@fruser@friendica.test a PrivaPub comment&in_reply_to_id=$fr_on_p_post&visibility=public"
until_true 45 '[ "$(fr_sql "select count(*) from \`post-view\` where \`thr-parent\` = '"'$fr_post_uri'"' and body like '"'%a PrivaPub comment%'"'")" -ge 1 ]' \
&& ok "alice_friendica's comment threads under fruser's post on Friendica" || ko "alice_friendica's comment missing on Friendica"
echo " likes, dislikes and boosts"
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses/$fr_on_p_post/favourite"
until_true 45 '[ "$(fr_count "$fr_post_uri" /like)" = "1" ]' && ok "alice_friendica's like counts on Friendica" || ko "like not counted on Friendica"
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses/$fr_on_p_post/reblog"
until_true 45 '[ "$(fr_count "$fr_post_uri" "#Announce")" = "1" ]' && ok "alice_friendica's boost counts on Friendica" || ko "boost not counted on Friendica"
p_on_fr=$(frc "$FR/api/v2/search?q=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))" "$p_post_uri")&resolve=true&type=statuses" | j "print(d['statuses'][0]['id'])")
frc -o /dev/null -X POST "$FR/api/v1/statuses/$p_on_fr/favourite"
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$p_post_id" | j "print(d[\"favourites_count\"])")" = "1" ]' && ok "fruser's like counts on PrivaPub" || ko "Friendica's like not counted"
frc -o /dev/null -X POST "$FR/api/v1/statuses/$p_on_fr/unfavourite"
frc -o /dev/null -X POST "$FR/api/friendica/activity/dislike" -d "id=$p_on_fr"
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$p_post_id" | j "print(d[\"favourites_count\"], ((d.get(\"privapub\") or {}).get(\"votes\") or {}).get(\"down\"))")" = "0 1" ]' \
&& ok "fruser's dislike counts as a downvote on PrivaPub" || ko "Friendica's dislike not counted"
echo " edits and deletes"
curl -s -o /dev/null -X PUT -H "$PH" "$P/api/v1/statuses/$p_post_id" -d 'status=Hello Friendica from PrivaPub, edited'
until_true 45 '[ "$(fr_sql "select count(*) from \`post-view\` where uri = '"'$p_post_uri'"' and body like '"'%edited%'"'")" = "1" ]' \
&& ok "alice_friendica's edit reaches Friendica" || ko "PrivaPub's edit not applied on Friendica"
fr_web_edit "$fr_post" 'Hello PrivaPub from Friendica, edited'
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$fr_on_p_post" | j "print(\"edited\" in d[\"content\"])")" = "True" ]' \
&& ok "fruser's edit reaches PrivaPub" || ko "Friendica's edit not applied"
curl -s -o /dev/null -X DELETE -H "$PH" "$P/api/v1/statuses/$p_post_id"
until_true 45 '[ "$(fr_sql "select count(*) from \`post-view\` where uri = '"'$p_post_uri'"' and deleted = 0")" = "0" ]' \
&& ok "alice_friendica's delete reaches Friendica" || ko "delete not applied on Friendica"
frc -o /dev/null -X DELETE "$FR/api/v1/statuses/$fr_post"
until_true 45 '[ "$(curl -s -o /dev/null -w "%{http_code}" -H "$PH" "$P/api/v1/statuses/$fr_on_p_post")" = "404" ]' \
&& ok "fruser's delete reaches PrivaPub" || ko "Friendica's delete not applied"
echo " unfollows"
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/accounts/$fr_on_p/unfollow"
until_true 45 '[ "$(frc "$FR/api/v1/accounts/relationships?id[]=$alice_on_fr" | j "print(d[0][\"followed_by\"])")" = "False" ]' \
&& ok "alice_friendica's unfollow reaches Friendica" || ko "PrivaPub's unfollow not applied on Friendica"
frc -o /dev/null -X POST "$FR/api/v1/accounts/$alice_on_fr/unfollow"
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/accounts/relationships?id[]=$fr_on_p" | j "print(d[0][\"followed_by\"])")" = "False" ]' \
&& ok "fruser's unfollow reaches PrivaPub" || ko "Friendica's unfollow not applied"
echo " statistics"
stats_check friendica.test friendica