From dbf231865d1156e1b4bcfc6e88deedaf21bf3938 Mon Sep 17 00:00:00 2001
From: Dessalines <dessalines@users.noreply.github.com>
Date: Thu, 20 Aug 2020 08:44:22 -0400
Subject: [PATCH] Adding a few more apub tests. (#1096)

* Adding a few more apub tests.

* Fixing travis build, adding a get_post function.
---
 docker/federation-test/run-tests.sh        |  6 +-
 docker/federation-test/servers.sh          |  4 +-
 docker/federation-test/tests.sh            |  2 +
 docker/federation/docker-compose.yml       | 76 ++++++++++++++++++++--
 docker/federation/nginx.conf               | 62 ++++++++++++++++++
 docker/federation/run-federation-test.bash |  2 +-
 docker/travis/docker-compose.yml           | 76 ++++++++++++++++++++--
 docker/travis/run-tests.sh                 |  6 +-
 server/src/api/comment.rs                  | 11 ++--
 server/src/api/mod.rs                      |  8 +++
 ui/src/api_tests/comment.spec.ts           |  5 ++
 ui/src/api_tests/post.spec.ts              | 50 +++++++++++++-
 ui/src/api_tests/shared.ts                 | 66 ++++++++++++++++---
 13 files changed, 341 insertions(+), 33 deletions(-)

diff --git a/docker/federation-test/run-tests.sh b/docker/federation-test/run-tests.sh
index 3848414b..f166d490 100755
--- a/docker/federation-test/run-tests.sh
+++ b/docker/federation-test/run-tests.sh
@@ -13,8 +13,8 @@ pushd ../../ui
 yarn
 popd
 
-mkdir -p volumes/pictrs_{alpha,beta,gamma}
-sudo chown -R 991:991 volumes/pictrs_{alpha,beta,gamma}
+mkdir -p volumes/pictrs_{alpha,beta,gamma,delta,epsilon}
+sudo chown -R 991:991 volumes/pictrs_{alpha,beta,gamma,delta,epsilon}
 
 sudo docker build ../../ --file ../federation/Dockerfile --tag lemmy-federation:latest
 
@@ -28,6 +28,8 @@ echo "Waiting for Lemmy to start..."
 while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8540/api/v1/site')" != "200" ]]; do sleep 1; done
 while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8550/api/v1/site')" != "200" ]]; do sleep 1; done
 while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8560/api/v1/site')" != "200" ]]; do sleep 1; done
+while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8570/api/v1/site')" != "200" ]]; do sleep 1; done
+while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8580/api/v1/site')" != "200" ]]; do sleep 1; done
 yarn api-test || true
 popd
 
diff --git a/docker/federation-test/servers.sh b/docker/federation-test/servers.sh
index b34e8c4e..5b09bc95 100755
--- a/docker/federation-test/servers.sh
+++ b/docker/federation-test/servers.sh
@@ -12,8 +12,8 @@ pushd ../../ui
 yarn
 popd
 
-mkdir -p volumes/pictrs_{alpha,beta,gamma}
-sudo chown -R 991:991 volumes/pictrs_{alpha,beta,gamma}
+mkdir -p volumes/pictrs_{alpha,beta,gamma,delta,epsilon}
+sudo chown -R 991:991 volumes/pictrs_{alpha,beta,gamma,delta,epsilon}
 
 sudo docker build ../../ --file ../federation/Dockerfile --tag lemmy-federation:latest
 
diff --git a/docker/federation-test/tests.sh b/docker/federation-test/tests.sh
index 2e88ffb2..58472e95 100755
--- a/docker/federation-test/tests.sh
+++ b/docker/federation-test/tests.sh
@@ -6,5 +6,7 @@ echo "Waiting for Lemmy to start..."
 while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8540/api/v1/site')" != "200" ]]; do sleep 1; done
 while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8550/api/v1/site')" != "200" ]]; do sleep 1; done
 while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8560/api/v1/site')" != "200" ]]; do sleep 1; done
+while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8570/api/v1/site')" != "200" ]]; do sleep 1; done
+while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8580/api/v1/site')" != "200" ]]; do sleep 1; done
 yarn api-test || true
 popd
diff --git a/docker/federation/docker-compose.yml b/docker/federation/docker-compose.yml
index a3d0cf43..32fee74a 100644
--- a/docker/federation/docker-compose.yml
+++ b/docker/federation/docker-compose.yml
@@ -7,16 +7,20 @@ services:
       - "8540:8540"
       - "8550:8550"
       - "8560:8560"
+      - "8570:8570"
+      - "8580:8580"
     volumes:
       # Hack to make this work from both docker/federation/ and docker/federation-test/
       - ../federation/nginx.conf:/etc/nginx/nginx.conf
     restart: on-failure
     depends_on:
-      - lemmy-alpha
       - pictrs
+      - iframely
+      - lemmy-alpha
       - lemmy-beta
       - lemmy-gamma
-      - iframely
+      - lemmy-delta
+      - lemmy-epsilon
 
   pictrs:
     restart: always
@@ -34,7 +38,7 @@ services:
       - LEMMY_FRONT_END_DIR=/app/dist
       - LEMMY_FEDERATION__ENABLED=true
       - LEMMY_FEDERATION__TLS_ENABLED=false
-      - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta,lemmy-gamma
+      - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta,lemmy-gamma,lemmy-delta,lemmy-epsilon
       - LEMMY_PORT=8540
       - LEMMY_SETUP__ADMIN_USERNAME=lemmy_alpha
       - LEMMY_SETUP__ADMIN_PASSWORD=lemmy
@@ -64,7 +68,7 @@ services:
       - LEMMY_FRONT_END_DIR=/app/dist
       - LEMMY_FEDERATION__ENABLED=true
       - LEMMY_FEDERATION__TLS_ENABLED=false
-      - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-gamma
+      - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-gamma,lemmy-delta,lemmy-epsilon
       - LEMMY_PORT=8550
       - LEMMY_SETUP__ADMIN_USERNAME=lemmy_beta
       - LEMMY_SETUP__ADMIN_PASSWORD=lemmy
@@ -94,7 +98,7 @@ services:
       - LEMMY_FRONT_END_DIR=/app/dist
       - LEMMY_FEDERATION__ENABLED=true
       - LEMMY_FEDERATION__TLS_ENABLED=false
-      - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-beta
+      - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-beta,lemmy-delta,lemmy-epsilon
       - LEMMY_PORT=8560
       - LEMMY_SETUP__ADMIN_USERNAME=lemmy_gamma
       - LEMMY_SETUP__ADMIN_PASSWORD=lemmy
@@ -115,6 +119,68 @@ services:
     volumes:
       - ./volumes/postgres_gamma:/var/lib/postgresql/data
 
+  # An instance with only an allowlist for beta
+  lemmy-delta:
+    image: lemmy-federation:latest
+    environment:
+      - LEMMY_HOSTNAME=lemmy-delta:8570
+      - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_delta:5432/lemmy
+      - LEMMY_JWT_SECRET=changeme
+      - LEMMY_FRONT_END_DIR=/app/dist
+      - LEMMY_FEDERATION__ENABLED=true
+      - LEMMY_FEDERATION__TLS_ENABLED=false
+      - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta
+      - LEMMY_PORT=8570
+      - LEMMY_SETUP__ADMIN_USERNAME=lemmy_delta
+      - LEMMY_SETUP__ADMIN_PASSWORD=lemmy
+      - LEMMY_SETUP__SITE_NAME=lemmy-delta
+      - LEMMY_RATE_LIMIT__POST=99999
+      - LEMMY_RATE_LIMIT__REGISTER=99999
+      - LEMMY_CAPTCHA__ENABLED=false
+      - RUST_BACKTRACE=1
+      - RUST_LOG=debug
+    depends_on:
+      - postgres_delta
+  postgres_delta:
+    image: postgres:12-alpine
+    environment:
+      - POSTGRES_USER=lemmy
+      - POSTGRES_PASSWORD=password
+      - POSTGRES_DB=lemmy
+    volumes:
+      - ./volumes/postgres_delta:/var/lib/postgresql/data
+
+  # An instance who has a blocklist, with lemmy-alpha blocked
+  lemmy-epsilon:
+    image: lemmy-federation:latest
+    environment:
+      - LEMMY_HOSTNAME=lemmy-epsilon:8580
+      - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_epsilon:5432/lemmy
+      - LEMMY_JWT_SECRET=changeme
+      - LEMMY_FRONT_END_DIR=/app/dist
+      - LEMMY_FEDERATION__ENABLED=true
+      - LEMMY_FEDERATION__TLS_ENABLED=false
+      - LEMMY_FEDERATION__BLOCKED_INSTANCES=lemmy-alpha
+      - LEMMY_PORT=8580
+      - LEMMY_SETUP__ADMIN_USERNAME=lemmy_epsilon
+      - LEMMY_SETUP__ADMIN_PASSWORD=lemmy
+      - LEMMY_SETUP__SITE_NAME=lemmy-epsilon
+      - LEMMY_RATE_LIMIT__POST=99999
+      - LEMMY_RATE_LIMIT__REGISTER=99999
+      - LEMMY_CAPTCHA__ENABLED=false
+      - RUST_BACKTRACE=1
+      - RUST_LOG=debug
+    depends_on:
+      - postgres_epsilon
+  postgres_epsilon:
+    image: postgres:12-alpine
+    environment:
+      - POSTGRES_USER=lemmy
+      - POSTGRES_PASSWORD=password
+      - POSTGRES_DB=lemmy
+    volumes:
+      - ./volumes/postgres_epsilon:/var/lib/postgresql/data
+
   iframely:
     image: dogbin/iframely:latest
     volumes:
diff --git a/docker/federation/nginx.conf b/docker/federation/nginx.conf
index b7901c19..6d062f70 100644
--- a/docker/federation/nginx.conf
+++ b/docker/federation/nginx.conf
@@ -95,4 +95,66 @@ http {
             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         }
     }
+
+    server {
+        listen 8570;
+        server_name 127.0.0.1;
+        access_log off;
+
+        # Upload limit for pictshare
+        client_max_body_size 50M;
+
+        location / {
+            proxy_pass http://lemmy-delta:8570;
+            proxy_set_header X-Real-IP $remote_addr;
+            proxy_set_header Host $host;
+            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+
+            # Cuts off the trailing slash on URLs to make them valid
+            rewrite ^(.+)/+$ $1 permanent;
+
+            # WebSocket support
+            proxy_http_version 1.1;
+            proxy_set_header Upgrade $http_upgrade;
+            proxy_set_header Connection "upgrade";
+        }
+
+        location /iframely/ {
+            proxy_pass http://iframely:80/;
+            proxy_set_header X-Real-IP $remote_addr;
+            proxy_set_header Host $host;
+            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        }
+    }
+
+    server {
+        listen 8580;
+        server_name 127.0.0.1;
+        access_log off;
+
+        # Upload limit for pictshare
+        client_max_body_size 50M;
+
+        location / {
+            proxy_pass http://lemmy-epsilon:8580;
+            proxy_set_header X-Real-IP $remote_addr;
+            proxy_set_header Host $host;
+            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+
+            # Cuts off the trailing slash on URLs to make them valid
+            rewrite ^(.+)/+$ $1 permanent;
+
+            # WebSocket support
+            proxy_http_version 1.1;
+            proxy_set_header Upgrade $http_upgrade;
+            proxy_set_header Connection "upgrade";
+        }
+
+        location /iframely/ {
+            proxy_pass http://iframely:80/;
+            proxy_set_header X-Real-IP $remote_addr;
+            proxy_set_header Host $host;
+            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        }
+    }
 }
diff --git a/docker/federation/run-federation-test.bash b/docker/federation/run-federation-test.bash
index 77cc981f..0fe03aa1 100755
--- a/docker/federation/run-federation-test.bash
+++ b/docker/federation/run-federation-test.bash
@@ -20,7 +20,7 @@ popd || exit
 
 sudo docker build ../../ --file Dockerfile -t lemmy-federation:latest
 
-for Item in alpha beta gamma ; do
+for Item in alpha beta gamma delta epsilon ; do
   sudo mkdir -p volumes/pictrs_$Item
   sudo chown -R 991:991 volumes/pictrs_$Item
 done
diff --git a/docker/travis/docker-compose.yml b/docker/travis/docker-compose.yml
index 7314e495..9aa7750c 100644
--- a/docker/travis/docker-compose.yml
+++ b/docker/travis/docker-compose.yml
@@ -7,16 +7,20 @@ services:
       - "8540:8540"
       - "8550:8550"
       - "8560:8560"
+      - "8570:8570"
+      - "8580:8580"
     volumes:
       # Hack to make this work from both docker/federation/ and docker/federation-test/
       - ../federation/nginx.conf:/etc/nginx/nginx.conf
     restart: on-failure
     depends_on:
-      - lemmy-alpha
       - pictrs
+      - iframely
+      - lemmy-alpha
       - lemmy-beta
       - lemmy-gamma
-      - iframely
+      - lemmy-delta
+      - lemmy-epsilon
 
   pictrs:
     restart: always
@@ -34,7 +38,7 @@ services:
       - LEMMY_FRONT_END_DIR=/app/dist
       - LEMMY_FEDERATION__ENABLED=true
       - LEMMY_FEDERATION__TLS_ENABLED=false
-      - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta,lemmy-gamma
+      - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta,lemmy-gamma,lemmy-delta,lemmy-epsilon
       - LEMMY_PORT=8540
       - LEMMY_SETUP__ADMIN_USERNAME=lemmy_alpha
       - LEMMY_SETUP__ADMIN_PASSWORD=lemmy
@@ -64,7 +68,7 @@ services:
       - LEMMY_FRONT_END_DIR=/app/dist
       - LEMMY_FEDERATION__ENABLED=true
       - LEMMY_FEDERATION__TLS_ENABLED=false
-      - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-gamma
+      - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-gamma,lemmy-delta,lemmy-epsilon
       - LEMMY_PORT=8550
       - LEMMY_SETUP__ADMIN_USERNAME=lemmy_beta
       - LEMMY_SETUP__ADMIN_PASSWORD=lemmy
@@ -94,7 +98,7 @@ services:
       - LEMMY_FRONT_END_DIR=/app/dist
       - LEMMY_FEDERATION__ENABLED=true
       - LEMMY_FEDERATION__TLS_ENABLED=false
-      - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-beta
+      - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-beta,lemmy-delta,lemmy-epsilon
       - LEMMY_PORT=8560
       - LEMMY_SETUP__ADMIN_USERNAME=lemmy_gamma
       - LEMMY_SETUP__ADMIN_PASSWORD=lemmy
@@ -115,6 +119,68 @@ services:
     volumes:
       - ./volumes/postgres_gamma:/var/lib/postgresql/data
 
+  # An instance with only an allowlist for beta
+  lemmy-delta:
+    image: dessalines/lemmy:travis
+    environment:
+      - LEMMY_HOSTNAME=lemmy-delta:8570
+      - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_delta:5432/lemmy
+      - LEMMY_JWT_SECRET=changeme
+      - LEMMY_FRONT_END_DIR=/app/dist
+      - LEMMY_FEDERATION__ENABLED=true
+      - LEMMY_FEDERATION__TLS_ENABLED=false
+      - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta
+      - LEMMY_PORT=8570
+      - LEMMY_SETUP__ADMIN_USERNAME=lemmy_delta
+      - LEMMY_SETUP__ADMIN_PASSWORD=lemmy
+      - LEMMY_SETUP__SITE_NAME=lemmy-delta
+      - LEMMY_RATE_LIMIT__POST=99999
+      - LEMMY_RATE_LIMIT__REGISTER=99999
+      - LEMMY_CAPTCHA__ENABLED=false
+      - RUST_BACKTRACE=1
+      - RUST_LOG=debug
+    depends_on:
+      - postgres_delta
+  postgres_delta:
+    image: postgres:12-alpine
+    environment:
+      - POSTGRES_USER=lemmy
+      - POSTGRES_PASSWORD=password
+      - POSTGRES_DB=lemmy
+    volumes:
+      - ./volumes/postgres_delta:/var/lib/postgresql/data
+
+  # An instance who has a blocklist, with lemmy-alpha blocked
+  lemmy-epsilon:
+    image: dessalines/lemmy:travis
+    environment:
+      - LEMMY_HOSTNAME=lemmy-epsilon:8580
+      - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_epsilon:5432/lemmy
+      - LEMMY_JWT_SECRET=changeme
+      - LEMMY_FRONT_END_DIR=/app/dist
+      - LEMMY_FEDERATION__ENABLED=true
+      - LEMMY_FEDERATION__TLS_ENABLED=false
+      - LEMMY_FEDERATION__BLOCKED_INSTANCES=lemmy-alpha
+      - LEMMY_PORT=8580
+      - LEMMY_SETUP__ADMIN_USERNAME=lemmy_epsilon
+      - LEMMY_SETUP__ADMIN_PASSWORD=lemmy
+      - LEMMY_SETUP__SITE_NAME=lemmy-epsilon
+      - LEMMY_RATE_LIMIT__POST=99999
+      - LEMMY_RATE_LIMIT__REGISTER=99999
+      - LEMMY_CAPTCHA__ENABLED=false
+      - RUST_BACKTRACE=1
+      - RUST_LOG=debug
+    depends_on:
+      - postgres_epsilon
+  postgres_epsilon:
+    image: postgres:12-alpine
+    environment:
+      - POSTGRES_USER=lemmy
+      - POSTGRES_PASSWORD=password
+      - POSTGRES_DB=lemmy
+    volumes:
+      - ./volumes/postgres_epsilon:/var/lib/postgresql/data
+
   iframely:
     image: dogbin/iframely:latest
     volumes:
diff --git a/docker/travis/run-tests.sh b/docker/travis/run-tests.sh
index f09b73c2..658ffc0e 100755
--- a/docker/travis/run-tests.sh
+++ b/docker/travis/run-tests.sh
@@ -5,8 +5,8 @@ set -e
 sudo docker-compose down
 sudo rm -rf volumes
 
-mkdir -p volumes/pictrs_{alpha,beta,gamma}
-sudo chown -R 991:991 volumes/pictrs_{alpha,beta,gamma}
+mkdir -p volumes/pictrs_{alpha,beta,gamma,delta,epsilon}
+sudo chown -R 991:991 volumes/pictrs_{alpha,beta,gamma,delta,epsilon}
 
 sudo docker build ../../ --file ../prod/Dockerfile --tag dessalines/lemmy:travis
 
@@ -17,6 +17,8 @@ echo "Waiting for Lemmy to start..."
 while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8540/api/v1/site')" != "200" ]]; do sleep 1; done
 while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8550/api/v1/site')" != "200" ]]; do sleep 1; done
 while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8560/api/v1/site')" != "200" ]]; do sleep 1; done
+while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8570/api/v1/site')" != "200" ]]; do sleep 1; done
+while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8580/api/v1/site')" != "200" ]]; do sleep 1; done
 yarn
 yarn api-test
 popd
diff --git a/server/src/api/comment.rs b/server/src/api/comment.rs
index 63f53a4d..24055d4d 100644
--- a/server/src/api/comment.rs
+++ b/server/src/api/comment.rs
@@ -1,6 +1,7 @@
 use crate::{
   api::{
     check_community_ban,
+    get_post,
     get_user_from_jwt,
     get_user_from_jwt_opt,
     is_mod_or_admin,
@@ -151,7 +152,7 @@ impl Perform for CreateComment {
 
     // Check for a community ban
     let post_id = data.post_id;
-    let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
+    let post = get_post(post_id, context.pool()).await?;
 
     check_community_ban(user.id, post.community_id, context.pool()).await?;
 
@@ -283,7 +284,7 @@ impl Perform for EditComment {
 
     // Do the mentions / recipients
     let post_id = orig_comment.post_id;
-    let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
+    let post = get_post(post_id, context.pool()).await?;
 
     let updated_comment_content = updated_comment.content.to_owned();
     let mentions = scrape_text_for_mentions(&updated_comment_content);
@@ -379,7 +380,7 @@ impl Perform for DeleteComment {
 
     // Build the recipients
     let post_id = comment_view.post_id;
-    let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
+    let post = get_post(post_id, context.pool()).await?;
     let mentions = vec![];
     let recipient_ids = send_local_notifs(
       mentions,
@@ -476,7 +477,7 @@ impl Perform for RemoveComment {
 
     // Build the recipients
     let post_id = comment_view.post_id;
-    let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
+    let post = get_post(post_id, context.pool()).await?;
     let mentions = vec![];
     let recipient_ids = send_local_notifs(
       mentions,
@@ -655,7 +656,7 @@ impl Perform for CreateCommentLike {
     .await??;
 
     let post_id = orig_comment.post_id;
-    let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
+    let post = get_post(post_id, context.pool()).await?;
     check_community_ban(user.id, post.community_id, context.pool()).await?;
 
     let comment_id = data.comment_id;
diff --git a/server/src/api/mod.rs b/server/src/api/mod.rs
index 6fed9d05..c64707f9 100644
--- a/server/src/api/mod.rs
+++ b/server/src/api/mod.rs
@@ -11,6 +11,7 @@ use lemmy_db::{
   community::*,
   community_view::*,
   moderator::*,
+  post::Post,
   site::*,
   user::*,
   user_view::*,
@@ -73,6 +74,13 @@ pub async fn is_admin(pool: &DbPool, user_id: i32) -> Result<(), LemmyError> {
   Ok(())
 }
 
+pub(in crate::api) async fn get_post(post_id: i32, pool: &DbPool) -> Result<Post, LemmyError> {
+  match blocking(pool, move |conn| Post::read(conn, post_id)).await? {
+    Ok(post) => Ok(post),
+    Err(_e) => Err(APIError::err("couldnt_find_post").into()),
+  }
+}
+
 pub(in crate::api) async fn get_user_from_jwt(
   jwt: &str,
   pool: &DbPool,
diff --git a/ui/src/api_tests/comment.spec.ts b/ui/src/api_tests/comment.spec.ts
index 02cc683c..24aca55f 100644
--- a/ui/src/api_tests/comment.spec.ts
+++ b/ui/src/api_tests/comment.spec.ts
@@ -57,6 +57,11 @@ test('Create a comment', async () => {
   expect(betaComment.score).toBe(1);
 });
 
+test('Create a comment in a non-existent post', async () => {
+  let commentRes = await createComment(alpha, -1);
+  expect(commentRes).toStrictEqual({ error: 'couldnt_find_post' });
+});
+
 test('Update a comment', async () => {
   let commentRes = await createComment(alpha, postRes.post.id);
   let updateCommentRes = await updateComment(alpha, commentRes.comment.id);
diff --git a/ui/src/api_tests/post.spec.ts b/ui/src/api_tests/post.spec.ts
index 5da72e5a..ab9c63fb 100644
--- a/ui/src/api_tests/post.spec.ts
+++ b/ui/src/api_tests/post.spec.ts
@@ -2,6 +2,8 @@ import {
   alpha,
   beta,
   gamma,
+  delta,
+  epsilon,
   setupLogins,
   createPost,
   updatePost,
@@ -22,11 +24,15 @@ beforeAll(async () => {
   await setupLogins();
   await followBeta(alpha);
   await followBeta(gamma);
+  await followBeta(delta);
+  await followBeta(epsilon);
 });
 
 afterAll(async () => {
   await unfollowRemotes(alpha);
   await unfollowRemotes(gamma);
+  await unfollowRemotes(delta);
+  await unfollowRemotes(epsilon);
 });
 
 test('Create a post', async () => {
@@ -45,6 +51,19 @@ test('Create a post', async () => {
   expect(betaPost.community_local).toBe(true);
   expect(betaPost.creator_local).toBe(false);
   expect(betaPost.score).toBe(1);
+
+  // Delta only follows beta, so it should not see an alpha ap_id
+  let searchDelta = await searchPost(delta, postRes.post);
+  expect(searchDelta.posts[0]).toBeUndefined();
+
+  // Epsilon has alpha blocked, it should not see the alpha post
+  let searchEpsilon = await searchPost(epsilon, postRes.post);
+  expect(searchEpsilon.posts[0]).toBeUndefined();
+});
+
+test('Create a post in a non-existent community', async () => {
+  let postRes = await createPost(alpha, -2);
+  expect(postRes).toStrictEqual({ error: 'couldnt_create_post' });
 });
 
 test('Unlike a post', async () => {
@@ -53,6 +72,10 @@ test('Unlike a post', async () => {
   let unlike = await likePost(alpha, 0, postRes.post);
   expect(unlike.post.score).toBe(0);
 
+  // Try to unlike it again, make sure it stays at 0
+  let unlike2 = await likePost(alpha, 0, postRes.post);
+  expect(unlike2.post.score).toBe(0);
+
   // Make sure that post is unliked on beta
   let searchBeta = await searchPost(beta, postRes.post);
   let betaPost = searchBeta.posts[0];
@@ -67,10 +90,22 @@ test('Update a post', async () => {
   let search = await searchForBetaCommunity(alpha);
   let postRes = await createPost(alpha, search.communities[0].id);
 
+  let updatedName = 'A jest test federated post, updated';
   let updatedPost = await updatePost(alpha, postRes.post);
-  expect(updatedPost.post.name).toBe('A jest test federated post, updated');
+  expect(updatedPost.post.name).toBe(updatedName);
   expect(updatedPost.post.community_local).toBe(false);
   expect(updatedPost.post.creator_local).toBe(true);
+
+  // Make sure that post is updated on beta
+  let searchBeta = await searchPost(beta, postRes.post);
+  let betaPost = searchBeta.posts[0];
+  expect(betaPost.community_local).toBe(true);
+  expect(betaPost.creator_local).toBe(false);
+  expect(betaPost.name).toBe(updatedName);
+
+  // Make sure lemmy beta cannot update the post
+  let updatedPostBeta = await updatePost(beta, betaPost);
+  expect(updatedPostBeta).toStrictEqual({ error: 'no_post_edit_allowed' });
 });
 
 test('Sticky a post', async () => {
@@ -97,6 +132,15 @@ test('Sticky a post', async () => {
   expect(betaPost2.community_local).toBe(true);
   expect(betaPost2.creator_local).toBe(false);
   expect(betaPost2.stickied).toBe(false);
+
+  // Make sure that gamma cannot sticky the post on beta
+  let searchGamma = await searchPost(gamma, postRes.post);
+  let gammaPost = searchGamma.posts[0];
+  let gammaTrySticky = await stickyPost(gamma, true, gammaPost);
+  let searchBeta3 = await searchPost(beta, postRes.post);
+  let betaPost3 = searchBeta3.posts[0];
+  expect(gammaTrySticky.post.stickied).toBe(true);
+  expect(betaPost3.stickied).toBe(false);
 });
 
 test('Lock a post', async () => {
@@ -152,6 +196,10 @@ test('Delete a post', async () => {
   // Make sure lemmy beta sees post is undeleted
   let betaPost2 = await getPost(beta, createFakeBetaPostToGetId);
   expect(betaPost2.post.deleted).toBe(false);
+
+  // Make sure lemmy beta cannot delete the post
+  let deletedPostBeta = await deletePost(beta, true, betaPost2.post);
+  expect(deletedPostBeta).toStrictEqual({ error: 'no_post_edit_allowed' });
 });
 
 test('Remove a post from admin and community on different instance', async () => {
diff --git a/ui/src/api_tests/shared.ts b/ui/src/api_tests/shared.ts
index 31530ef7..29aaff25 100644
--- a/ui/src/api_tests/shared.ts
+++ b/ui/src/api_tests/shared.ts
@@ -59,50 +59,96 @@ export let gamma: API = {
   url: 'http://localhost:8560',
 };
 
+export let delta: API = {
+  url: 'http://localhost:8570',
+};
+
+export let epsilon: API = {
+  url: 'http://localhost:8580',
+};
+
 export async function setupLogins() {
-  let form: LoginForm = {
+  let formAlpha: LoginForm = {
     username_or_email: 'lemmy_alpha',
     password: 'lemmy',
   };
 
-  let resA: Promise<LoginResponse> = fetch(`${apiUrl(alpha)}/user/login`, {
+  let resAlpha: Promise<LoginResponse> = fetch(`${apiUrl(alpha)}/user/login`, {
     method: 'POST',
     headers: {
       'Content-Type': 'application/json',
     },
-    body: wrapper(form),
+    body: wrapper(formAlpha),
   }).then(d => d.json());
 
-  let formB = {
+  let formBeta = {
     username_or_email: 'lemmy_beta',
     password: 'lemmy',
   };
 
-  let resB: Promise<LoginResponse> = fetch(`${apiUrl(beta)}/user/login`, {
+  let resBeta: Promise<LoginResponse> = fetch(`${apiUrl(beta)}/user/login`, {
     method: 'POST',
     headers: {
       'Content-Type': 'application/json',
     },
-    body: wrapper(formB),
+    body: wrapper(formBeta),
   }).then(d => d.json());
 
-  let formC = {
+  let formGamma = {
     username_or_email: 'lemmy_gamma',
     password: 'lemmy',
   };
 
-  let resG: Promise<LoginResponse> = fetch(`${apiUrl(gamma)}/user/login`, {
+  let resGamma: Promise<LoginResponse> = fetch(`${apiUrl(gamma)}/user/login`, {
+    method: 'POST',
+    headers: {
+      'Content-Type': 'application/json',
+    },
+    body: wrapper(formGamma),
+  }).then(d => d.json());
+
+  let formDelta = {
+    username_or_email: 'lemmy_delta',
+    password: 'lemmy',
+  };
+
+  let resDelta: Promise<LoginResponse> = fetch(`${apiUrl(delta)}/user/login`, {
     method: 'POST',
     headers: {
       'Content-Type': 'application/json',
     },
-    body: wrapper(formC),
+    body: wrapper(formDelta),
   }).then(d => d.json());
 
-  let res = await Promise.all([resA, resB, resG]);
+  let formEpsilon = {
+    username_or_email: 'lemmy_epsilon',
+    password: 'lemmy',
+  };
+
+  let resEpsilon: Promise<LoginResponse> = fetch(
+    `${apiUrl(epsilon)}/user/login`,
+    {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json',
+      },
+      body: wrapper(formEpsilon),
+    }
+  ).then(d => d.json());
+
+  let res = await Promise.all([
+    resAlpha,
+    resBeta,
+    resGamma,
+    resDelta,
+    resEpsilon,
+  ]);
+
   alpha.auth = res[0].jwt;
   beta.auth = res[1].jwt;
   gamma.auth = res[2].jwt;
+  delta.auth = res[3].jwt;
+  epsilon.auth = res[4].jwt;
 }
 
 export async function createPost(
