From dbf231865d1156e1b4bcfc6e88deedaf21bf3938 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 20 Aug 2020 08:44:22 -0400 Subject: [PATCH 1/3] 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 3848414b9..f166d4903 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 b34e8c4ef..5b09bc952 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 2e88ffb25..58472e95c 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 a3d0cf431..32fee74ab 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 b7901c19c..6d062f70b 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 77cc981f4..0fe03aa17 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 7314e495d..9aa7750c0 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 f09b73c2b..658ffc0e4 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 63f53a4d7..24055d4d7 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 6fed9d05d..c64707f94 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 { + 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 02cc683c4..24aca55f9 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 5da72e5a1..ab9c63fb1 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 31530ef7e..29aaff25f 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 = fetch(`${apiUrl(alpha)}/user/login`, { + let resAlpha: Promise = 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 = fetch(`${apiUrl(beta)}/user/login`, { + let resBeta: Promise = 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 = fetch(`${apiUrl(gamma)}/user/login`, { + let resGamma: Promise = fetch(`${apiUrl(gamma)}/user/login`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, - body: wrapper(formC), + body: wrapper(formGamma), }).then(d => d.json()); - let res = await Promise.all([resA, resB, resG]); + let formDelta = { + username_or_email: 'lemmy_delta', + password: 'lemmy', + }; + + let resDelta: Promise = fetch(`${apiUrl(delta)}/user/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: wrapper(formDelta), + }).then(d => d.json()); + + let formEpsilon = { + username_or_email: 'lemmy_epsilon', + password: 'lemmy', + }; + + let resEpsilon: Promise = 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( From 2080534744f6a2c7d760ea066c17ab4337d7e3d0 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 20 Aug 2020 10:50:26 -0400 Subject: [PATCH 2/3] Switch front end to use lemmy-js-client. Fixes #1090 (#1097) * Switch front end to use lemmy-js-client. Fixes #1090 * Adding an HTTP client. Cleaning up Websocket client. --- README.md | 1 + server/src/routes/api.rs | 4 +- ui/package.json | 1 + ui/src/api_tests/comment.spec.ts | 4 +- ui/src/api_tests/shared.ts | 489 ++------ ui/src/components/admin-settings.tsx | 2 +- ui/src/components/comment-form.tsx | 2 +- ui/src/components/comment-node.tsx | 5 +- ui/src/components/comment-nodes.tsx | 4 +- ui/src/components/communities.tsx | 4 +- ui/src/components/community-form.tsx | 4 +- ui/src/components/community-link.tsx | 2 +- ui/src/components/community.tsx | 28 +- ui/src/components/create-community.tsx | 2 +- ui/src/components/create-post.tsx | 2 +- ui/src/components/create-private-message.tsx | 2 +- ui/src/components/footer.tsx | 2 +- ui/src/components/iframely-card.tsx | 2 +- ui/src/components/inbox.tsx | 6 +- ui/src/components/instances.tsx | 2 +- ui/src/components/listing-type-select.tsx | 10 +- ui/src/components/login.tsx | 2 +- ui/src/components/main.tsx | 40 +- ui/src/components/modlog.tsx | 2 +- ui/src/components/navbar.tsx | 8 +- ui/src/components/password_change.tsx | 2 +- ui/src/components/post-form.tsx | 12 +- ui/src/components/post-listing.tsx | 4 +- ui/src/components/post-listings.tsx | 2 +- ui/src/components/post.tsx | 9 +- ui/src/components/private-message-form.tsx | 4 +- ui/src/components/private-message.tsx | 2 +- ui/src/components/search.tsx | 24 +- ui/src/components/setup.tsx | 2 +- ui/src/components/sidebar.tsx | 2 +- ui/src/components/site-form.tsx | 2 +- ui/src/components/sort-select.tsx | 9 +- ui/src/components/sponsors.tsx | 2 +- ui/src/components/user-details.tsx | 8 +- ui/src/components/user-listing.tsx | 2 +- ui/src/components/user.tsx | 52 +- ui/src/interfaces.ts | 1052 ------------------ ui/src/services/UserService.ts | 7 +- ui/src/services/WebSocketService.ts | 165 ++- ui/src/utils.ts | 38 +- ui/yarn.lock | 5 + 46 files changed, 350 insertions(+), 1685 deletions(-) diff --git a/README.md b/README.md index 8aa5fe38a..57b3d63e5 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,7 @@ Each Lemmy server can set its own moderation policy; appointing site-wide admins ### Libraries +- [lemmy-js-client](https://github.com/LemmyNet/lemmy-js-client) - [Kotlin API ( under development )](https://github.com/eiknat/lemmy-client) ## Support / Donate diff --git a/server/src/routes/api.rs b/server/src/routes/api.rs index 1c88ffa24..201908623 100644 --- a/server/src/routes/api.rs +++ b/server/src/routes/api.rs @@ -94,7 +94,8 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) { web::post().to(route_post::), ) .route("/like", web::post().to(route_post::)) - .route("/save", web::put().to(route_post::)), + .route("/save", web::put().to(route_post::)) + .route("/list", web::get().to(route_get::)), ) // Private Message .service( @@ -136,6 +137,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) { "/followed_communities", web::get().to(route_get::), ) + .route("/join", web::post().to(route_post::)) // Admin action. I don't like that it's in /user .route("/ban", web::post().to(route_post::)) // Account actions. I don't like that they're in /user maybe /accounts diff --git a/ui/package.json b/ui/package.json index 06c52807a..74740b76f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -37,6 +37,7 @@ "inferno-router": "^7.4.2", "js-cookie": "^2.2.0", "jwt-decode": "^2.2.0", + "lemmy-js-client": "^1.0.8", "markdown-it": "^11.0.0", "markdown-it-container": "^3.0.0", "markdown-it-emoji": "^1.4.0", diff --git a/ui/src/api_tests/comment.spec.ts b/ui/src/api_tests/comment.spec.ts index 24aca55f9..747ec9109 100644 --- a/ui/src/api_tests/comment.spec.ts +++ b/ui/src/api_tests/comment.spec.ts @@ -21,7 +21,7 @@ import { API, } from './shared'; -import { PostResponse } from '../interfaces'; +import { PostResponse } from 'lemmy-js-client'; let postRes: PostResponse; @@ -136,7 +136,7 @@ test('Remove a comment from admin and community on the same instance', async () test('Remove a comment from admin and community on different instance', async () => { let alphaUser = await registerUser(alpha); let newAlphaApi: API = { - url: alpha.url, + client: alpha.client, auth: alphaUser.jwt, }; diff --git a/ui/src/api_tests/shared.ts b/ui/src/api_tests/shared.ts index 29aaff25f..710671c0e 100644 --- a/ui/src/api_tests/shared.ts +++ b/ui/src/api_tests/shared.ts @@ -1,5 +1,3 @@ -import fetch from 'node-fetch'; - import { LoginForm, LoginResponse, @@ -20,15 +18,21 @@ import { CommentForm, DeleteCommentForm, RemoveCommentForm, + SearchForm, CommentResponse, CommunityForm, DeleteCommunityForm, RemoveCommunityForm, + GetUserMentionsForm, CommentLikeForm, CreatePostLikeForm, PrivateMessageForm, EditPrivateMessageForm, DeletePrivateMessageForm, + GetFollowedCommunitiesForm, + GetPrivateMessagesForm, + GetSiteForm, + GetPostForm, PrivateMessageResponse, PrivateMessagesResponse, GetUserMentionsResponse, @@ -36,35 +40,33 @@ import { SortType, ListingType, GetSiteResponse, -} from '../interfaces'; + SearchType, + LemmyHttp, +} from 'lemmy-js-client'; export interface API { - url: string; + client: LemmyHttp; auth?: string; } -function apiUrl(api: API) { - return `${api.url}/api/v1`; -} - export let alpha: API = { - url: 'http://localhost:8540', + client: new LemmyHttp('http://localhost:8540/api/v1'), }; export let beta: API = { - url: 'http://localhost:8550', + client: new LemmyHttp('http://localhost:8550/api/v1'), }; export let gamma: API = { - url: 'http://localhost:8560', + client: new LemmyHttp('http://localhost:8560/api/v1'), }; export let delta: API = { - url: 'http://localhost:8570', + client: new LemmyHttp('http://localhost:8570/api/v1'), }; export let epsilon: API = { - url: 'http://localhost:8580', + client: new LemmyHttp('http://localhost:8580/api/v1'), }; export async function setupLogins() { @@ -72,69 +74,31 @@ export async function setupLogins() { username_or_email: 'lemmy_alpha', password: 'lemmy', }; - - let resAlpha: Promise = fetch(`${apiUrl(alpha)}/user/login`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(formAlpha), - }).then(d => d.json()); + let resAlpha = alpha.client.login(formAlpha); let formBeta = { username_or_email: 'lemmy_beta', password: 'lemmy', }; - - let resBeta: Promise = fetch(`${apiUrl(beta)}/user/login`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(formBeta), - }).then(d => d.json()); + let resBeta = beta.client.login(formBeta); let formGamma = { username_or_email: 'lemmy_gamma', password: 'lemmy', }; - - let resGamma: Promise = fetch(`${apiUrl(gamma)}/user/login`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(formGamma), - }).then(d => d.json()); + let resGamma = gamma.client.login(formGamma); let formDelta = { username_or_email: 'lemmy_delta', password: 'lemmy', }; - - let resDelta: Promise = fetch(`${apiUrl(delta)}/user/login`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(formDelta), - }).then(d => d.json()); + let resDelta = delta.client.login(formDelta); let formEpsilon = { username_or_email: 'lemmy_epsilon', password: 'lemmy', }; - - let resEpsilon: Promise = fetch( - `${apiUrl(epsilon)}/user/login`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(formEpsilon), - } - ).then(d => d.json()); + let resEpsilon = epsilon.client.login(formEpsilon); let res = await Promise.all([ resAlpha, @@ -156,40 +120,24 @@ export async function createPost( community_id: number ): Promise { let name = 'A jest test post'; - let postForm: PostForm = { + let form: PostForm = { name, auth: api.auth, community_id, nsfw: false, }; - - let createPostRes: PostResponse = await fetch(`${apiUrl(api)}/post`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(postForm), - }).then(d => d.json()); - return createPostRes; + return api.client.createPost(form); } export async function updatePost(api: API, post: Post): Promise { let name = 'A jest test federated post, updated'; - let postForm: PostForm = { + let form: PostForm = { name, edit_id: post.id, auth: api.auth, nsfw: false, }; - - let updateResponse: PostResponse = await fetch(`${apiUrl(api)}/post`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(postForm), - }).then(d => d.json()); - return updateResponse; + return api.client.editPost(form); } export async function deletePost( @@ -197,20 +145,12 @@ export async function deletePost( deleted: boolean, post: Post ): Promise { - let deletePostForm: DeletePostForm = { + let form: DeletePostForm = { edit_id: post.id, deleted: deleted, auth: api.auth, }; - - let deletePostRes: PostResponse = await fetch(`${apiUrl(api)}/post/delete`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(deletePostForm), - }).then(d => d.json()); - return deletePostRes; + return api.client.deletePost(form); } export async function removePost( @@ -218,20 +158,12 @@ export async function removePost( removed: boolean, post: Post ): Promise { - let removePostForm: RemovePostForm = { + let form: RemovePostForm = { edit_id: post.id, removed, auth: api.auth, }; - - let removePostRes: PostResponse = await fetch(`${apiUrl(api)}/post/remove`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(removePostForm), - }).then(d => d.json()); - return removePostRes; + return api.client.removePost(form); } export async function stickyPost( @@ -239,21 +171,12 @@ export async function stickyPost( stickied: boolean, post: Post ): Promise { - let stickyPostForm: StickyPostForm = { + let form: StickyPostForm = { edit_id: post.id, stickied, auth: api.auth, }; - - let stickyRes: PostResponse = await fetch(`${apiUrl(api)}/post/sticky`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(stickyPostForm), - }).then(d => d.json()); - - return stickyRes; + return api.client.stickyPost(form); } export async function lockPost( @@ -261,57 +184,46 @@ export async function lockPost( locked: boolean, post: Post ): Promise { - let lockPostForm: LockPostForm = { + let form: LockPostForm = { edit_id: post.id, locked, auth: api.auth, }; - - let lockRes: PostResponse = await fetch(`${apiUrl(api)}/post/lock`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(lockPostForm), - }).then(d => d.json()); - - return lockRes; + return api.client.lockPost(form); } export async function searchPost( api: API, post: Post ): Promise { - let searchUrl = `${apiUrl(api)}/search?q=${post.ap_id}&type_=All&sort=TopAll`; - let searchResponse: SearchResponse = await fetch(searchUrl, { - method: 'GET', - }).then(d => d.json()); - return searchResponse; + let form: SearchForm = { + q: post.ap_id, + type_: SearchType.All, + sort: SortType.TopAll, + }; + return api.client.search(form); } export async function getPost( api: API, post_id: number ): Promise { - let getPostUrl = `${apiUrl(api)}/post?id=${post_id}`; - let getPostRes: GetPostResponse = await fetch(getPostUrl, { - method: 'GET', - }).then(d => d.json()); - - return getPostRes; + let form: GetPostForm = { + id: post_id, + }; + return api.client.getPost(form); } export async function searchComment( api: API, comment: Comment ): Promise { - let searchUrl = `${apiUrl(api)}/search?q=${ - comment.ap_id - }&type_=All&sort=TopAll`; - let searchResponse: SearchResponse = await fetch(searchUrl, { - method: 'GET', - }).then(d => d.json()); - return searchResponse; + let form: SearchForm = { + q: comment.ap_id, + type_: SearchType.All, + sort: SortType.TopAll, + }; + return api.client.search(form); } export async function searchForBetaCommunity( @@ -319,14 +231,12 @@ export async function searchForBetaCommunity( ): Promise { // Make sure lemmy-beta/c/main is cached on lemmy_alpha // Use short-hand search url - let searchUrl = `${apiUrl( - api - )}/search?q=!main@lemmy-beta:8550&type_=All&sort=TopAll`; - - let searchResponse: SearchResponse = await fetch(searchUrl, { - method: 'GET', - }).then(d => d.json()); - return searchResponse; + let form: SearchForm = { + q: '!main@lemmy-beta:8550', + type_: SearchType.All, + sort: SortType.TopAll, + }; + return api.client.search(form); } export async function searchForUser( @@ -335,14 +245,12 @@ export async function searchForUser( ): Promise { // Make sure lemmy-beta/c/main is cached on lemmy_alpha // Use short-hand search url - let searchUrl = `${apiUrl( - api - )}/search?q=${apShortname}&type_=All&sort=TopAll`; - - let searchResponse: SearchResponse = await fetch(searchUrl, { - method: 'GET', - }).then(d => d.json()); - return searchResponse; + let form: SearchForm = { + q: apShortname, + type_: SearchType.All, + sort: SortType.TopAll, + }; + return api.client.search(form); } export async function followCommunity( @@ -350,41 +258,21 @@ export async function followCommunity( follow: boolean, community_id: number ): Promise { - let followForm: FollowCommunityForm = { + let form: FollowCommunityForm = { community_id, follow, auth: api.auth, }; - - let followRes: CommunityResponse = await fetch( - `${apiUrl(api)}/community/follow`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(followForm), - } - ) - .then(d => d.json()) - .catch(_e => {}); - - return followRes; + return api.client.followCommunity(form); } export async function checkFollowedCommunities( api: API ): Promise { - let followedCommunitiesUrl = `${apiUrl( - api - )}/user/followed_communities?&auth=${api.auth}`; - let followedCommunitiesRes: GetFollowedCommunitiesResponse = await fetch( - followedCommunitiesUrl, - { - method: 'GET', - } - ).then(d => d.json()); - return followedCommunitiesRes; + let form: GetFollowedCommunitiesForm = { + auth: api.auth, + }; + return api.client.getFollowedCommunities(form); } export async function likePost( @@ -392,21 +280,13 @@ export async function likePost( score: number, post: Post ): Promise { - let likePostForm: CreatePostLikeForm = { + let form: CreatePostLikeForm = { post_id: post.id, score: score, auth: api.auth, }; - let likePostRes: PostResponse = await fetch(`${apiUrl(api)}/post/like`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(likePostForm), - }).then(d => d.json()); - - return likePostRes; + return api.client.likePost(form); } export async function createComment( @@ -415,21 +295,13 @@ export async function createComment( parent_id?: number, content = 'a jest test comment' ): Promise { - let commentForm: CommentForm = { + let form: CommentForm = { content, post_id, parent_id, auth: api.auth, }; - - let createResponse: CommentResponse = await fetch(`${apiUrl(api)}/comment`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(commentForm), - }).then(d => d.json()); - return createResponse; + return api.client.createComment(form); } export async function updateComment( @@ -437,20 +309,12 @@ export async function updateComment( edit_id: number, content = 'A jest test federated comment update' ): Promise { - let commentForm: CommentForm = { + let form: CommentForm = { content, edit_id, auth: api.auth, }; - - let updateResponse: CommentResponse = await fetch(`${apiUrl(api)}/comment`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(commentForm), - }).then(d => d.json()); - return updateResponse; + return api.client.editComment(form); } export async function deleteComment( @@ -458,23 +322,12 @@ export async function deleteComment( deleted: boolean, edit_id: number ): Promise { - let deleteCommentForm: DeleteCommentForm = { + let form: DeleteCommentForm = { edit_id, deleted, auth: api.auth, }; - - let deleteCommentRes: CommentResponse = await fetch( - `${apiUrl(api)}/comment/delete`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(deleteCommentForm), - } - ).then(d => d.json()); - return deleteCommentRes; + return api.client.deleteComment(form); } export async function removeComment( @@ -482,33 +335,21 @@ export async function removeComment( removed: boolean, edit_id: number ): Promise { - let removeCommentForm: RemoveCommentForm = { + let form: RemoveCommentForm = { edit_id, removed, auth: api.auth, }; - - let removeCommentRes: CommentResponse = await fetch( - `${apiUrl(api)}/comment/remove`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(removeCommentForm), - } - ).then(d => d.json()); - return removeCommentRes; + return api.client.removeComment(form); } export async function getMentions(api: API): Promise { - let getMentionUrl = `${apiUrl( - api - )}/user/mention?sort=New&unread_only=false&auth=${api.auth}`; - let getMentionsRes: GetUserMentionsResponse = await fetch(getMentionUrl, { - method: 'GET', - }).then(d => d.json()); - return getMentionsRes; + let form: GetUserMentionsForm = { + sort: SortType.New, + unread_only: false, + auth: api.auth, + }; + return api.client.getUserMentions(form); } export async function likeComment( @@ -516,48 +357,26 @@ export async function likeComment( score: number, comment: Comment ): Promise { - let likeCommentForm: CommentLikeForm = { + let form: CommentLikeForm = { comment_id: comment.id, score, auth: api.auth, }; - - let likeCommentRes: CommentResponse = await fetch( - `${apiUrl(api)}/comment/like`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(likeCommentForm), - } - ).then(d => d.json()); - return likeCommentRes; + return api.client.likeComment(form); } export async function createCommunity( api: API, name_: string = randomString(5) ): Promise { - let communityForm: CommunityForm = { + let form: CommunityForm = { name: name_, title: name_, category_id: 1, nsfw: false, auth: api.auth, }; - - let createCommunityRes: CommunityResponse = await fetch( - `${apiUrl(api)}/community`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(communityForm), - } - ).then(d => d.json()); - return createCommunityRes; + return api.client.createCommunity(form); } export async function deleteCommunity( @@ -565,23 +384,12 @@ export async function deleteCommunity( deleted: boolean, edit_id: number ): Promise { - let deleteCommunityForm: DeleteCommunityForm = { + let form: DeleteCommunityForm = { edit_id, deleted, auth: api.auth, }; - - let deleteResponse: CommunityResponse = await fetch( - `${apiUrl(api)}/community/delete`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(deleteCommunityForm), - } - ).then(d => d.json()); - return deleteResponse; + return api.client.deleteCommunity(form); } export async function removeCommunity( @@ -589,23 +397,12 @@ export async function removeCommunity( removed: boolean, edit_id: number ): Promise { - let removeCommunityForm: RemoveCommunityForm = { + let form: RemoveCommunityForm = { edit_id, removed, auth: api.auth, }; - - let removeResponse: CommunityResponse = await fetch( - `${apiUrl(api)}/community/remove`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(removeCommunityForm), - } - ).then(d => d.json()); - return removeResponse; + return api.client.removeCommunity(form); } export async function createPrivateMessage( @@ -613,23 +410,12 @@ export async function createPrivateMessage( recipient_id: number ): Promise { let content = 'A jest test federated private message'; - let privateMessageForm: PrivateMessageForm = { + let form: PrivateMessageForm = { content, recipient_id, auth: api.auth, }; - - let createRes: PrivateMessageResponse = await fetch( - `${apiUrl(api)}/private_message`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(privateMessageForm), - } - ).then(d => d.json()); - return createRes; + return api.client.createPrivateMessage(form); } export async function updatePrivateMessage( @@ -637,23 +423,12 @@ export async function updatePrivateMessage( edit_id: number ): Promise { let updatedContent = 'A jest test federated private message edited'; - let updatePrivateMessageForm: EditPrivateMessageForm = { + let form: EditPrivateMessageForm = { content: updatedContent, edit_id, auth: api.auth, }; - - let updateRes: PrivateMessageResponse = await fetch( - `${apiUrl(api)}/private_message`, - { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(updatePrivateMessageForm), - } - ).then(d => d.json()); - return updateRes; + return api.client.editPrivateMessage(form); } export async function deletePrivateMessage( @@ -661,50 +436,26 @@ export async function deletePrivateMessage( deleted: boolean, edit_id: number ): Promise { - let deletePrivateMessageForm: DeletePrivateMessageForm = { + let form: DeletePrivateMessageForm = { deleted, edit_id, auth: api.auth, }; - - let deleteRes: PrivateMessageResponse = await fetch( - `${apiUrl(api)}/private_message/delete`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(deletePrivateMessageForm), - } - ).then(d => d.json()); - - return deleteRes; + return api.client.deletePrivateMessage(form); } export async function registerUser( api: API, username: string = randomString(5) ): Promise { - let registerForm: RegisterForm = { + let form: RegisterForm = { username, password: 'test', password_verify: 'test', admin: false, show_nsfw: true, }; - - let registerRes: Promise = fetch( - `${apiUrl(api)}/user/register`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(registerForm), - } - ).then(d => d.json()); - - return registerRes; + return api.client.register(form); } export async function saveUserSettingsBio( @@ -714,54 +465,36 @@ export async function saveUserSettingsBio( let form: UserSettingsForm = { show_nsfw: true, theme: 'darkly', - default_sort_type: SortType.Active, - default_listing_type: ListingType.All, + default_sort_type: Object.keys(SortType).indexOf(SortType.Active), + default_listing_type: Object.keys(ListingType).indexOf(ListingType.All), lang: 'en', show_avatars: true, send_notifications_to_email: false, bio: 'a changed bio', auth, }; - - let res: Promise = fetch( - `${apiUrl(api)}/user/save_user_settings`, - { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(form), - } - ).then(d => d.json()); - return res; + return api.client.saveUserSettings(form); } export async function getSite( api: API, auth: string ): Promise { - let siteUrl = `${apiUrl(api)}/site?auth=${auth}`; - - let res: GetSiteResponse = await fetch(siteUrl, { - method: 'GET', - }).then(d => d.json()); - return res; + let form: GetSiteForm = { + auth, + }; + return api.client.getSite(form); } export async function listPrivateMessages( api: API ): Promise { - let getPrivateMessagesUrl = `${apiUrl(api)}/private_message/list?auth=${ - api.auth - }&unread_only=false&limit=999`; - - let getPrivateMessagesRes: PrivateMessagesResponse = await fetch( - getPrivateMessagesUrl, - { - method: 'GET', - } - ).then(d => d.json()); - return getPrivateMessagesRes; + let form: GetPrivateMessagesForm = { + auth: api.auth, + unread_only: false, + limit: 999, + }; + return api.client.getPrivateMessages(form); } export async function unfollowRemotes( diff --git a/ui/src/components/admin-settings.tsx b/ui/src/components/admin-settings.tsx index fe50b1e94..a3bfdd813 100644 --- a/ui/src/components/admin-settings.tsx +++ b/ui/src/components/admin-settings.tsx @@ -9,7 +9,7 @@ import { SiteConfigForm, GetSiteConfigResponse, WebSocketJsonResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { wsJsonToRes, capitalizeFirstLetter, toast, randomStr } from '../utils'; import autosize from 'autosize'; diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx index 5597f58ee..dbd14dc76 100644 --- a/ui/src/components/comment-form.tsx +++ b/ui/src/components/comment-form.tsx @@ -8,7 +8,7 @@ import { WebSocketJsonResponse, UserOperation, CommentResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; import { capitalizeFirstLetter, wsJsonToRes } from '../utils'; import { WebSocketService, UserService } from '../services'; import { i18n } from '../i18next'; diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx index 13263b822..1992c4fc8 100644 --- a/ui/src/components/comment-node.tsx +++ b/ui/src/components/comment-node.tsx @@ -16,10 +16,9 @@ import { AddAdminForm, TransferCommunityForm, TransferSiteForm, - BanType, - CommentSortType, SortType, -} from '../interfaces'; +} from 'lemmy-js-client'; +import { CommentSortType, BanType } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { mdToHtml, diff --git a/ui/src/components/comment-nodes.tsx b/ui/src/components/comment-nodes.tsx index 62693f766..bdb8a545e 100644 --- a/ui/src/components/comment-nodes.tsx +++ b/ui/src/components/comment-nodes.tsx @@ -1,11 +1,11 @@ import { Component } from 'inferno'; +import { CommentSortType } from '../interfaces'; import { CommentNode as CommentNodeI, CommunityUser, UserView, - CommentSortType, SortType, -} from '../interfaces'; +} from 'lemmy-js-client'; import { commentSort, commentSortSortType } from '../utils'; import { CommentNode } from './comment-node'; diff --git a/ui/src/components/communities.tsx b/ui/src/components/communities.tsx index 038e4517f..5be032c5e 100644 --- a/ui/src/components/communities.tsx +++ b/ui/src/components/communities.tsx @@ -13,7 +13,7 @@ import { WebSocketJsonResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { wsJsonToRes, toast, getPageFromProps } from '../utils'; import { CommunityLink } from './community-link'; @@ -218,7 +218,7 @@ export class Communities extends Component { refetch() { let listCommunitiesForm: ListCommunitiesForm = { - sort: SortType[SortType.TopAll], + sort: SortType.TopAll, limit: communityLimit, page: this.state.page, }; diff --git a/ui/src/components/community-form.tsx b/ui/src/components/community-form.tsx index 1ae96ac8b..7b8c379ba 100644 --- a/ui/src/components/community-form.tsx +++ b/ui/src/components/community-form.tsx @@ -9,12 +9,12 @@ import { ListCategoriesResponse, CommunityResponse, WebSocketJsonResponse, -} from '../interfaces'; + Community, +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { wsJsonToRes, capitalizeFirstLetter, toast, randomStr } from '../utils'; import { i18n } from '../i18next'; -import { Community } from '../interfaces'; import { MarkdownTextArea } from './markdown-textarea'; import { ImageUploadForm } from './image-upload-form'; diff --git a/ui/src/components/community-link.tsx b/ui/src/components/community-link.tsx index 293ded046..003f61e14 100644 --- a/ui/src/components/community-link.tsx +++ b/ui/src/components/community-link.tsx @@ -1,6 +1,6 @@ import { Component } from 'inferno'; import { Link } from 'inferno-router'; -import { Community } from '../interfaces'; +import { Community } from 'lemmy-js-client'; import { hostname, pictrsAvatarThumbnail, showAvatars } from '../utils'; interface CommunityOther { diff --git a/ui/src/components/community.tsx b/ui/src/components/community.tsx index 1fe75c598..f86562f8c 100644 --- a/ui/src/components/community.tsx +++ b/ui/src/components/community.tsx @@ -2,6 +2,7 @@ import { Component, linkEvent } from 'inferno'; import { Helmet } from 'inferno-helmet'; import { Subscription } from 'rxjs'; import { retryWhen, delay, take } from 'rxjs/operators'; +import { DataType } from '../interfaces'; import { UserOperation, Community as CommunityI, @@ -14,7 +15,6 @@ import { GetPostsForm, GetCommunityForm, ListingType, - DataType, GetPostsResponse, PostResponse, AddModToCommunityResponse, @@ -26,7 +26,7 @@ import { WebSocketJsonResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { PostListings } from './post-listings'; import { CommentNodes } from './comment-nodes'; @@ -78,7 +78,7 @@ interface CommunityProps { interface UrlParams { dataType?: string; - sort?: string; + sort?: SortType; page?: number; } @@ -287,9 +287,7 @@ export class Community extends Component { { } handleSortChange(val: SortType) { - this.updateUrl({ sort: SortType[val].toLowerCase(), page: 1 }); + this.updateUrl({ sort: val, page: 1 }); window.scrollTo(0, 0); } handleDataTypeChange(val: DataType) { - this.updateUrl({ dataType: DataType[val].toLowerCase(), page: 1 }); + this.updateUrl({ dataType: DataType[val], page: 1 }); window.scrollTo(0, 0); } updateUrl(paramUpdates: UrlParams) { - const dataTypeStr = - paramUpdates.dataType || DataType[this.state.dataType].toLowerCase(); - const sortStr = - paramUpdates.sort || SortType[this.state.sort].toLowerCase(); + const dataTypeStr = paramUpdates.dataType || DataType[this.state.dataType]; + const sortStr = paramUpdates.sort || this.state.sort; const page = paramUpdates.page || this.state.page; this.props.history.push( `/c/${this.state.community.name}/data_type/${dataTypeStr}/sort/${sortStr}/page/${page}` @@ -361,8 +357,8 @@ export class Community extends Component { let getPostsForm: GetPostsForm = { page: this.state.page, limit: fetchLimit, - sort: SortType[this.state.sort], - type_: ListingType[ListingType.Community], + sort: this.state.sort, + type_: ListingType.Community, community_id: this.state.community.id, }; WebSocketService.Instance.getPosts(getPostsForm); @@ -370,8 +366,8 @@ export class Community extends Component { let getCommentsForm: GetCommentsForm = { page: this.state.page, limit: fetchLimit, - sort: SortType[this.state.sort], - type_: ListingType[ListingType.Community], + sort: this.state.sort, + type_: ListingType.Community, community_id: this.state.community.id, }; WebSocketService.Instance.getComments(getCommentsForm); diff --git a/ui/src/components/create-community.tsx b/ui/src/components/create-community.tsx index 8317ffbe8..6f156211d 100644 --- a/ui/src/components/create-community.tsx +++ b/ui/src/components/create-community.tsx @@ -9,7 +9,7 @@ import { WebSocketJsonResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { toast, wsJsonToRes } from '../utils'; import { WebSocketService, UserService } from '../services'; import { i18n } from '../i18next'; diff --git a/ui/src/components/create-post.tsx b/ui/src/components/create-post.tsx index eb86d8f88..f4c03b653 100644 --- a/ui/src/components/create-post.tsx +++ b/ui/src/components/create-post.tsx @@ -11,7 +11,7 @@ import { WebSocketJsonResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { i18n } from '../i18next'; interface CreatePostState { diff --git a/ui/src/components/create-private-message.tsx b/ui/src/components/create-private-message.tsx index ed06a66ae..98c69d5b7 100644 --- a/ui/src/components/create-private-message.tsx +++ b/ui/src/components/create-private-message.tsx @@ -10,7 +10,7 @@ import { GetSiteResponse, Site, PrivateMessageFormParams, -} from '../interfaces'; +} from 'lemmy-js-client'; import { toast, wsJsonToRes } from '../utils'; import { i18n } from '../i18next'; diff --git a/ui/src/components/footer.tsx b/ui/src/components/footer.tsx index 6e7acb7a0..62585ff30 100644 --- a/ui/src/components/footer.tsx +++ b/ui/src/components/footer.tsx @@ -9,7 +9,7 @@ import { UserOperation, WebSocketJsonResponse, GetSiteResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; interface FooterState { version: string; diff --git a/ui/src/components/iframely-card.tsx b/ui/src/components/iframely-card.tsx index 1a47f377a..6a604f7c5 100644 --- a/ui/src/components/iframely-card.tsx +++ b/ui/src/components/iframely-card.tsx @@ -1,5 +1,5 @@ import { Component, linkEvent } from 'inferno'; -import { Post } from '../interfaces'; +import { Post } from 'lemmy-js-client'; import { mdToHtml } from '../utils'; import { i18n } from '../i18next'; diff --git a/ui/src/components/inbox.tsx b/ui/src/components/inbox.tsx index ecc9223c3..4da86e351 100644 --- a/ui/src/components/inbox.tsx +++ b/ui/src/components/inbox.tsx @@ -19,7 +19,7 @@ import { PrivateMessageResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService, UserService } from '../services'; import { wsJsonToRes, @@ -399,7 +399,7 @@ export class Inbox extends Component { refetch() { let repliesForm: GetRepliesForm = { - sort: SortType[this.state.sort], + sort: this.state.sort, unread_only: this.state.unreadOrAll == UnreadOrAll.Unread, page: this.state.page, limit: fetchLimit, @@ -407,7 +407,7 @@ export class Inbox extends Component { WebSocketService.Instance.getReplies(repliesForm); let userMentionsForm: GetUserMentionsForm = { - sort: SortType[this.state.sort], + sort: this.state.sort, unread_only: this.state.unreadOrAll == UnreadOrAll.Unread, page: this.state.page, limit: fetchLimit, diff --git a/ui/src/components/instances.tsx b/ui/src/components/instances.tsx index ae4e3f13b..bcc02480b 100644 --- a/ui/src/components/instances.tsx +++ b/ui/src/components/instances.tsx @@ -6,7 +6,7 @@ import { UserOperation, WebSocketJsonResponse, GetSiteResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { wsJsonToRes, toast } from '../utils'; import { i18n } from '../i18next'; diff --git a/ui/src/components/listing-type-select.tsx b/ui/src/components/listing-type-select.tsx index 6bdf457c4..3d12d4343 100644 --- a/ui/src/components/listing-type-select.tsx +++ b/ui/src/components/listing-type-select.tsx @@ -1,7 +1,7 @@ import { Component, linkEvent } from 'inferno'; -import { ListingType } from '../interfaces'; +import { ListingType } from 'lemmy-js-client'; import { UserService } from '../services'; - +import { randomStr } from '../utils'; import { i18n } from '../i18next'; interface ListingTypeSelectProps { @@ -17,6 +17,8 @@ export class ListingTypeSelect extends Component< ListingTypeSelectProps, ListingTypeSelectState > { + private id = `listing-type-input-${randomStr()}`; + private emptyState: ListingTypeSelectState = { type_: this.props.type_, }; @@ -42,6 +44,7 @@ export class ListingTypeSelect extends Component< `} > { } let listCommunitiesForm: ListCommunitiesForm = { - sort: SortType[SortType.Hot], + sort: SortType.Hot, limit: 6, }; @@ -334,13 +334,9 @@ export class Main extends Component { } updateUrl(paramUpdates: UrlParams) { - const listingTypeStr = - paramUpdates.listingType || - ListingType[this.state.listingType].toLowerCase(); - const dataTypeStr = - paramUpdates.dataType || DataType[this.state.dataType].toLowerCase(); - const sortStr = - paramUpdates.sort || SortType[this.state.sort].toLowerCase(); + const listingTypeStr = paramUpdates.listingType || this.state.listingType; + const dataTypeStr = paramUpdates.dataType || DataType[this.state.dataType]; + const sortStr = paramUpdates.sort || this.state.sort; const page = paramUpdates.page || this.state.page; this.props.history.push( `/home/data_type/${dataTypeStr}/listing_type/${listingTypeStr}/sort/${sortStr}/page/${page}` @@ -549,7 +545,7 @@ export class Main extends Component { {this.state.listingType == ListingType.All && ( { {UserService.Instance.user && this.state.listingType == ListingType.Subscribed && ( { } handleSortChange(val: SortType) { - this.updateUrl({ sort: SortType[val].toLowerCase(), page: 1 }); + this.updateUrl({ sort: val, page: 1 }); window.scrollTo(0, 0); } handleListingTypeChange(val: ListingType) { - this.updateUrl({ listingType: ListingType[val].toLowerCase(), page: 1 }); + this.updateUrl({ listingType: val, page: 1 }); window.scrollTo(0, 0); } handleDataTypeChange(val: DataType) { - this.updateUrl({ dataType: DataType[val].toLowerCase(), page: 1 }); + this.updateUrl({ dataType: DataType[val], page: 1 }); window.scrollTo(0, 0); } @@ -650,16 +644,16 @@ export class Main extends Component { let getPostsForm: GetPostsForm = { page: this.state.page, limit: fetchLimit, - sort: SortType[this.state.sort], - type_: ListingType[this.state.listingType], + sort: this.state.sort, + type_: this.state.listingType, }; WebSocketService.Instance.getPosts(getPostsForm); } else { let getCommentsForm: GetCommentsForm = { page: this.state.page, limit: fetchLimit, - sort: SortType[this.state.sort], - type_: ListingType[this.state.listingType], + sort: this.state.sort, + type_: this.state.listingType, }; WebSocketService.Instance.getComments(getCommentsForm); } diff --git a/ui/src/components/modlog.tsx b/ui/src/components/modlog.tsx index 0cc78da73..106015a4a 100644 --- a/ui/src/components/modlog.tsx +++ b/ui/src/components/modlog.tsx @@ -19,7 +19,7 @@ import { WebSocketJsonResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { wsJsonToRes, addTypeInfo, fetchLimit, toast } from '../utils'; import { MomentTime } from './moment-time'; diff --git a/ui/src/components/navbar.tsx b/ui/src/components/navbar.tsx index 0ddcbb4cd..4ef5276c3 100644 --- a/ui/src/components/navbar.tsx +++ b/ui/src/components/navbar.tsx @@ -18,7 +18,7 @@ import { PrivateMessage, PrivateMessageResponse, WebSocketJsonResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; import { wsJsonToRes, pictrsAvatarThumbnail, @@ -137,7 +137,7 @@ export class Navbar extends Component { this.context.router.history.push(`/search/`); } else { this.context.router.history.push( - `/search/q/${searchParam}/type/all/sort/topall/page/1` + `/search/q/${searchParam}/type/All/sort/TopAll/page/1` ); } } @@ -477,14 +477,14 @@ export class Navbar extends Component { fetchUnreads() { console.log('Fetching unreads...'); let repliesForm: GetRepliesForm = { - sort: SortType[SortType.New], + sort: SortType.New, unread_only: true, page: 1, limit: fetchLimit, }; let userMentionsForm: GetUserMentionsForm = { - sort: SortType[SortType.New], + sort: SortType.New, unread_only: true, page: 1, limit: fetchLimit, diff --git a/ui/src/components/password_change.tsx b/ui/src/components/password_change.tsx index 5b157f7f6..527f21e04 100644 --- a/ui/src/components/password_change.tsx +++ b/ui/src/components/password_change.tsx @@ -9,7 +9,7 @@ import { WebSocketJsonResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService, UserService } from '../services'; import { wsJsonToRes, capitalizeFirstLetter, toast } from '../utils'; import { i18n } from '../i18next'; diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx index 854cff6e9..97b44f5fa 100644 --- a/ui/src/components/post-form.tsx +++ b/ui/src/components/post-form.tsx @@ -18,7 +18,7 @@ import { SearchType, SearchResponse, WebSocketJsonResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService, UserService } from '../services'; import { wsJsonToRes, @@ -121,7 +121,7 @@ export class PostForm extends Component { ); let listCommunitiesForm: ListCommunitiesForm = { - sort: SortType[SortType.TopAll], + sort: SortType.TopAll, limit: 9999, }; @@ -405,8 +405,8 @@ export class PostForm extends Component { if (validURL(this.state.postForm.url)) { let form: SearchForm = { q: this.state.postForm.url, - type_: SearchType[SearchType.Url], - sort: SortType[SortType.TopAll], + type_: SearchType.Url, + sort: SortType.TopAll, page: 1, limit: 6, }; @@ -433,8 +433,8 @@ export class PostForm extends Component { fetchSimilarPosts() { let form: SearchForm = { q: this.state.postForm.name, - type_: SearchType[SearchType.Posts], - sort: SortType[SortType.TopAll], + type_: SearchType.Posts, + sort: SortType.TopAll, community_id: this.state.postForm.community_id, page: 1, limit: 6, diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx index e3e19e99c..fa4bf3911 100644 --- a/ui/src/components/post-listing.tsx +++ b/ui/src/components/post-listing.tsx @@ -11,14 +11,14 @@ import { SavePostForm, CommunityUser, UserView, - BanType, BanFromCommunityForm, BanUserForm, AddModToCommunityForm, AddAdminForm, TransferSiteForm, TransferCommunityForm, -} from '../interfaces'; +} from 'lemmy-js-client'; +import { BanType } from '../interfaces'; import { MomentTime } from './moment-time'; import { PostForm } from './post-form'; import { IFramelyCard } from './iframely-card'; diff --git a/ui/src/components/post-listings.tsx b/ui/src/components/post-listings.tsx index cd65d9340..2c9b4a882 100644 --- a/ui/src/components/post-listings.tsx +++ b/ui/src/components/post-listings.tsx @@ -1,6 +1,6 @@ import { Component } from 'inferno'; import { Link } from 'inferno-router'; -import { Post, SortType } from '../interfaces'; +import { Post, SortType } from 'lemmy-js-client'; import { postSort } from '../utils'; import { PostListing } from './post-listing'; import { i18n } from '../i18next'; diff --git a/ui/src/components/post.tsx b/ui/src/components/post.tsx index 06f461f3a..e9427a5eb 100644 --- a/ui/src/components/post.tsx +++ b/ui/src/components/post.tsx @@ -11,8 +11,6 @@ import { Comment, MarkCommentAsReadForm, CommentResponse, - CommentSortType, - CommentViewType, CommunityUser, CommunityResponse, CommentNode as CommentNodeI, @@ -28,7 +26,8 @@ import { GetSiteResponse, GetCommunityResponse, WebSocketJsonResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; +import { CommentSortType, CommentViewType } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { wsJsonToRes, @@ -439,8 +438,8 @@ export class Post extends Component { if (this.state.post.url) { let form: SearchForm = { q: this.state.post.url, - type_: SearchType[SearchType.Url], - sort: SortType[SortType.TopAll], + type_: SearchType.Url, + sort: SortType.TopAll, page: 1, limit: 6, }; diff --git a/ui/src/components/private-message-form.tsx b/ui/src/components/private-message-form.tsx index ff889c240..6d7825cd0 100644 --- a/ui/src/components/private-message-form.tsx +++ b/ui/src/components/private-message-form.tsx @@ -14,7 +14,7 @@ import { GetUserDetailsForm, SortType, WebSocketJsonResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { capitalizeFirstLetter, @@ -77,7 +77,7 @@ export class PrivateMessageForm extends Component< this.state.privateMessageForm.recipient_id = this.props.params.recipient_id; let form: GetUserDetailsForm = { user_id: this.state.privateMessageForm.recipient_id, - sort: SortType[SortType.New], + sort: SortType.New, saved_only: false, }; WebSocketService.Instance.getUserDetails(form); diff --git a/ui/src/components/private-message.tsx b/ui/src/components/private-message.tsx index bb6aca4c1..243d12e57 100644 --- a/ui/src/components/private-message.tsx +++ b/ui/src/components/private-message.tsx @@ -4,7 +4,7 @@ import { PrivateMessage as PrivateMessageI, DeletePrivateMessageForm, MarkPrivateMessageAsReadForm, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService, UserService } from '../services'; import { mdToHtml, pictrsAvatarThumbnail, showAvatars, toast } from '../utils'; import { MomentTime } from './moment-time'; diff --git a/ui/src/components/search.tsx b/ui/src/components/search.tsx index fc19cab97..a18cc2d8e 100644 --- a/ui/src/components/search.tsx +++ b/ui/src/components/search.tsx @@ -17,7 +17,7 @@ import { WebSocketJsonResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { wsJsonToRes, @@ -57,8 +57,8 @@ interface SearchProps { interface UrlParams { q?: string; - type_?: string; - sort?: string; + type_?: SearchType; + sort?: SortType; page?: number; } @@ -461,8 +461,8 @@ export class Search extends Component { search() { let form: SearchForm = { q: this.state.q, - type_: SearchType[this.state.type_], - sort: SortType[this.state.sort], + type_: this.state.type_, + sort: this.state.sort, page: this.state.page, limit: fetchLimit, }; @@ -473,12 +473,12 @@ export class Search extends Component { } handleSortChange(val: SortType) { - this.updateUrl({ sort: SortType[val].toLowerCase(), page: 1 }); + this.updateUrl({ sort: val, page: 1 }); } handleTypeChange(i: Search, event: any) { i.updateUrl({ - type_: SearchType[Number(event.target.value)].toLowerCase(), + type_: SearchType[event.target.value], page: 1, }); } @@ -487,8 +487,8 @@ export class Search extends Component { event.preventDefault(); i.updateUrl({ q: i.state.searchText, - type_: SearchType[i.state.type_].toLowerCase(), - sort: SortType[i.state.sort].toLowerCase(), + type_: i.state.type_, + sort: i.state.sort, page: i.state.page, }); } @@ -499,10 +499,8 @@ export class Search extends Component { updateUrl(paramUpdates: UrlParams) { const qStr = paramUpdates.q || this.state.q; - const typeStr = - paramUpdates.type_ || SearchType[this.state.type_].toLowerCase(); - const sortStr = - paramUpdates.sort || SortType[this.state.sort].toLowerCase(); + const typeStr = paramUpdates.type_ || this.state.type_; + const sortStr = paramUpdates.sort || this.state.sort; const page = paramUpdates.page || this.state.page; this.props.history.push( `/search/q/${qStr}/type/${typeStr}/sort/${sortStr}/page/${page}` diff --git a/ui/src/components/setup.tsx b/ui/src/components/setup.tsx index 7da143791..6360ec5a3 100644 --- a/ui/src/components/setup.tsx +++ b/ui/src/components/setup.tsx @@ -7,7 +7,7 @@ import { LoginResponse, UserOperation, WebSocketJsonResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService, UserService } from '../services'; import { wsJsonToRes, toast } from '../utils'; import { SiteForm } from './site-form'; diff --git a/ui/src/components/sidebar.tsx b/ui/src/components/sidebar.tsx index b434bb874..25cbd7972 100644 --- a/ui/src/components/sidebar.tsx +++ b/ui/src/components/sidebar.tsx @@ -8,7 +8,7 @@ import { RemoveCommunityForm, UserView, AddModToCommunityForm, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService, UserService } from '../services'; import { mdToHtml, getUnixTime } from '../utils'; import { CommunityForm } from './community-form'; diff --git a/ui/src/components/site-form.tsx b/ui/src/components/site-form.tsx index 98f1259b1..9b572f57e 100644 --- a/ui/src/components/site-form.tsx +++ b/ui/src/components/site-form.tsx @@ -2,7 +2,7 @@ import { Component, linkEvent } from 'inferno'; import { Prompt } from 'inferno-router'; import { MarkdownTextArea } from './markdown-textarea'; import { ImageUploadForm } from './image-upload-form'; -import { Site, SiteForm as SiteFormI } from '../interfaces'; +import { Site, SiteForm as SiteFormI } from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { capitalizeFirstLetter, randomStr } from '../utils'; import { i18n } from '../i18next'; diff --git a/ui/src/components/sort-select.tsx b/ui/src/components/sort-select.tsx index 778ed65ce..1f0fb0557 100644 --- a/ui/src/components/sort-select.tsx +++ b/ui/src/components/sort-select.tsx @@ -1,6 +1,6 @@ import { Component, linkEvent } from 'inferno'; -import { SortType } from '../interfaces'; -import { sortingHelpUrl } from '../utils'; +import { SortType } from 'lemmy-js-client'; +import { sortingHelpUrl, randomStr } from '../utils'; import { i18n } from '../i18next'; interface SortSelectProps { @@ -14,6 +14,7 @@ interface SortSelectState { } export class SortSelect extends Component { + private id = `sort-select-${randomStr()}`; private emptyState: SortSelectState = { sort: this.props.sort, }; @@ -33,6 +34,8 @@ export class SortSelect extends Component { return ( <>