# PeerTube 8.3: a persona follows a channel; the channel's video arrives as a playable post, its file streamed through # PrivaPub's media proxy with byte ranges; comments both ways thread; a comment on a video whose comments are moderated # waits for the owner's approval (FEP-5624); a like counts and its undo too; the video's edit # and its deletion reach PrivaPub; statistics. PeerTube's users follow channels and accounts of PeerTube-like servers # only, so nothing here has PeerTube following a persona. PTB=https://peertube.test:6443 # PeerTube checks the Host against its own name, without the port pcurl() { curl -sk --resolve peertube.test:6443:127.0.0.1 -H "Host: peertube.test" "$@"; } PTROOT=$(cat "$here/.state/peertube.token" 2>/dev/null) PTPASS=Peertube-Pasture-User-1 # a user's token through the instance's own OAuth client pt_token() { local client client=$(pcurl "$PTB/api/v1/oauth-clients/local") pcurl -X POST "$PTB/api/v1/users/token" \ --data-urlencode "client_id=$(echo "$client" | j "print(d['client_id'])")" \ --data-urlencode "client_secret=$(echo "$client" | j "print(d['client_secret'])")" \ --data-urlencode grant_type=password --data-urlencode "username=$1" --data-urlencode "password=$2" | j "print(d['access_token'])" } # a PrivaPub status in alice_peertube's home whose text or title has the given words; a channel shares its videos by # boosting them, so it is the boosted status 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 "peertube" [ -n "$PTROOT" ] && ok "PeerTube root token" || { ko "PeerTube root token"; return 1; } pcurl -o /dev/null -X POST -H "Authorization: Bearer $PTROOT" -H 'Content-Type: application/json' "$PTB/api/v1/users" \ -d "{\"username\":\"ptuser\",\"password\":\"$PTPASS\",\"email\":\"ptuser@peertube.test\",\"role\":2,\"videoQuota\":-1,\"videoQuotaDaily\":-1}" TT=$(pt_token ptuser "$PTPASS") TH="Authorization: Bearer $TT" [ -n "$TT" ] && ok "PeerTube token for ptuser" || { ko "PeerTube token for ptuser"; return 1; } channel=$(pcurl -H "$TH" "$PTB/api/v1/users/me" | j "print(d['videoChannels'][0]['name'])") channel_id=$(pcurl -H "$TH" "$PTB/api/v1/users/me" | j "print(d['videoChannels'][0]['id'])") PT=$(privapub_token alice_peertube) PH="Authorization: Bearer $PT" [ -n "$PT" ] && ok "PrivaPub token for alice_peertube" || { ko "PrivaPub token for alice_peertube"; return 1; } echo " discovery and follows" channel_on_p=$(curl -s -H "$PH" "$P/api/v2/search?q=$channel@peertube.test&resolve=true&type=accounts" | j "print(d['accounts'][0]['id'])") [ -n "$channel_on_p" ] && ok "PrivaPub resolves the channel @$channel@peertube.test" || ko "PrivaPub cannot resolve the channel" [ "$(curl -s -H "$PH" "$P/api/v1/accounts/$channel_on_p" | j "print(d['group'])")" = "True" ] && ok "the channel is a group account" || ko "the channel is not shown as a group" account_on_p=$(curl -s -H "$PH" "$P/api/v2/search?q=ptuser@peertube.test&resolve=true&type=accounts" | j "print(d['accounts'][0]['id'])") [ -n "$account_on_p" ] && ok "PrivaPub resolves the account @ptuser@peertube.test" || ko "PrivaPub cannot resolve the account" curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/accounts/$channel_on_p/follow" until_true 30 '[ "$(curl -s -H "$PH" "$P/api/v1/accounts/relationships?id[]=$channel_on_p" | j "print(d[0][\"following\"])")" = "True" ]' \ && ok "alice_peertube follows the channel (Accept arrived)" || ko "the channel's Accept never arrived" until_true 30 '[ "$(pcurl -H "$TH" "$PTB/api/v1/video-channels/$channel/followers" | j "print(d[\"total\"])")" -ge 1 ]' \ && ok "PeerTube lists alice_peertube among the channel's followers" || ko "PeerTube does not list the follower" echo " videos" run=$(date +%s) video=$(pcurl -X POST -H "$TH" "$PTB/api/v1/videos/upload" -F "videofile=@$here/town/media/tiny.mp4;type=video/mp4" \ -F "channelId=$channel_id" -F "name=Hello PrivaPub from PeerTube $run" -F "description=a tiny test video" -F privacy=1 -F commentsPolicy=1 -F waitTranscoding=false) video_id=$(echo "$video" | j "print(d['video']['shortUUID'])") [ -n "$video_id" ] && ok "ptuser uploads a video" || ko "upload refused: $(echo "$video" | head -c 200)" until_true 60 '[ -n "$(p_home_id "Hello PrivaPub from PeerTube $run")" ]' && ok "the video reaches alice_peertube's home, boosted by its channel" || ko "the video never arrived" v_on_p=$(p_home_id "Hello PrivaPub from PeerTube $run") v_status=$(curl -s -H "$PH" "$P/api/v1/statuses/$v_on_p") [ "$(echo "$v_status" | j "print(d['media_attachments'][0]['type'])")" = "video" ] && ok "the video is a playable attachment" || ko "no video attachment: $(echo "$v_status" | j "print(d['media_attachments'])" | head -c 200)" v_file=$(echo "$v_status" | j "print(d['media_attachments'][0]['url'])") case "$v_file" in *privapub.test/*) ok "its file is served through PrivaPub's proxy" ;; *) ko "its file is not proxied: $v_file" ;; esac range=$(pfetch -s -o /dev/null -w '%{http_code} %{size_download}' -H 'Range: bytes=0-99' "$v_file") [ "$range" = "206 100" ] && ok "the proxy answers a byte range (206, 100 bytes)" || ko "the proxy did not answer the range: $range" echo " comments" curl -s -o /dev/null -X POST -H "$PH" $P/api/v1/statuses -d "status=@ptuser@peertube.test lovely video&in_reply_to_id=$v_on_p&visibility=public" until_true 30 '[ "$(pcurl "$PTB/api/v1/videos/$video_id/comment-threads" | j "print(any(\"lovely video\" in c[\"text\"] for c in d[\"data\"]))")" = "True" ]' \ && ok "alice_peertube's reply is a comment on the video" || ko "the reply never became a comment" thread=$(pcurl "$PTB/api/v1/videos/$video_id/comment-threads" | j "print(next(c['id'] for c in d['data'] if 'lovely video' in c['text']))") pcurl -o /dev/null -X POST -H "$TH" -H 'Content-Type: application/json' "$PTB/api/v1/videos/$video_id/comments/$thread" -d '{"text":"thank you from PeerTube"}' until_true 30 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$v_on_p/context" | j "print(any(\"thank you from PeerTube\" in s[\"content\"] for s in d[\"descendants\"]))")" = "True" ]' \ && ok "ptuser's answer threads under the video on PrivaPub" || ko "PeerTube's answer missing from the thread" echo " moderated comments" # a video whose comments wait for approval (FEP-5624's canReply): alice's comment waits, goes to PeerTube alone, and is let # in by ptuser's approval (ApproveReply), after which PeerTube shows it held=$(date +%s) mvideo=$(pcurl -X POST -H "$TH" "$PTB/api/v1/videos/upload" -F "videofile=@$here/town/media/tiny.mp4;type=video/mp4" \ -F "channelId=$channel_id" -F "name=A moderated video $held" -F "description=comments wait here" -F privacy=1 -F commentsPolicy=3 -F waitTranscoding=false \ | j "print(d['video']['shortUUID'])") until_true 60 '[ -n "$(p_home_id "A moderated video $held")" ]' >/dev/null m_on_p=$(p_home_id "A moderated video $held") m_reply=$(curl -s -X POST -H "$PH" $P/api/v1/statuses -d "status=@ptuser@peertube.test a comment to approve $held&in_reply_to_id=$m_on_p&visibility=public" | j "print(d['id'])") [ "$(curl -s -H "$PH" "$P/api/v1/statuses/$m_reply" | j "print((d.get('privapub') or {}).get('approval'))")" = "pending" ] \ && ok "alice's comment on a moderated video waits for its approval" || ko "alice's comment on a moderated video does not wait" # (its owner sees it in the video's threads, held for review; PeerTube 8.3's list of held comments answers 500) pt_held() { pcurl -H "$TH" "$PTB/api/v1/videos/$mvideo/comment-threads" | j "print(next((c['id'] for c in d['data'] if c.get('heldForReview') and 'approve $held' in c['text']), ''))"; } until_true 30 '[ -n "$(pt_held)" ]' && ok "PeerTube holds it for review" || ko "PeerTube never held alice's comment" held_id=$(pt_held) pcurl -o /dev/null -X POST -H "$TH" "$PTB/api/v1/videos/$mvideo/comments/$held_id/approve" until_true 30 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$m_reply" | j "print((d.get(\"privapub\") or {}).get(\"approval\"))")" = "None" ]' \ && ok "ptuser's approval (ApproveReply) lets alice's comment in" || ko "the approval never reached PrivaPub" [ "$(pcurl "$PTB/api/v1/videos/$mvideo/comment-threads" | j "print(any('a comment to approve $held' in c['text'] for c in d['data']))")" = "True" ] \ && ok "PeerTube shows the approved comment" || ko "PeerTube does not show the approved comment" pcurl -o /dev/null -X DELETE -H "$TH" "$PTB/api/v1/videos/$mvideo" echo " likes" curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses/$v_on_p/favourite" until_true 30 '[ "$(pcurl "$PTB/api/v1/videos/$video_id" | j "print(d[\"likes\"])")" = "1" ]' && ok "alice_peertube's like counts on PeerTube" || ko "like not counted on PeerTube" curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses/$v_on_p/unfavourite" until_true 30 '[ "$(pcurl "$PTB/api/v1/videos/$video_id" | j "print(d[\"likes\"])")" = "0" ]' && ok "alice_peertube's unlike reaches PeerTube" || ko "unlike not applied on PeerTube" echo " edits and deletes" pcurl -o /dev/null -X PUT -H "$TH" -H 'Content-Type: application/json' "$PTB/api/v1/videos/$video_id" -d '{"name":"Hello again from PeerTube","description":"renamed"}' until_true 30 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$v_on_p" | j "print(\"Hello again from PeerTube\" in json.dumps(d))")" = "True" ]' \ && ok "the video's new name reaches PrivaPub" || ko "the edit never arrived" pcurl -o /dev/null -X DELETE -H "$TH" "$PTB/api/v1/videos/$video_id" until_true 30 '[ "$(curl -s -o /dev/null -w "%{http_code}" -H "$PH" "$P/api/v1/statuses/$v_on_p")" = "404" ]' \ && ok "the video's deletion reaches PrivaPub" || ko "the deleted video is still on PrivaPub" echo " unfollow" curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/accounts/$channel_on_p/unfollow" until_true 30 '[ "$(pcurl -H "$TH" "$PTB/api/v1/video-channels/$channel/followers" | j "print(d[\"total\"])")" = "0" ]' \ && ok "the unfollow reaches PeerTube" || ko "PeerTube still lists alice_peertube" echo " statistics" stats_check peertube.test peertube