From e00b0c9da21b9c130933c9c6d44a13725da1f9a4 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 9 Nov 2023 06:03:25 -0500 Subject: [PATCH] Dont send comment reply to user who has community blocked. Fixes #3684 (#4096) * Dont send comment reply to user who has community blocked. Fixes #3684 * Adding source instance block check. * Adding api test. * Addressing PR comments. --- api_tests/package.json | 17 +- api_tests/src/comment.spec.ts | 49 +++++- api_tests/src/shared.ts | 15 ++ api_tests/yarn.lock | 154 +++++++++--------- crates/api_common/src/build_response.rs | 40 +++-- crates/api_common/src/utils.rs | 53 +++++- crates/db_schema/src/impls/community_block.rs | 26 ++- crates/db_schema/src/impls/instance_block.rs | 26 ++- crates/db_schema/src/impls/person_block.rs | 22 ++- crates/utils/src/error.rs | 2 + 10 files changed, 294 insertions(+), 110 deletions(-) diff --git a/api_tests/package.json b/api_tests/package.json index 92e00b81b..17ac9f7be 100644 --- a/api_tests/package.json +++ b/api_tests/package.json @@ -9,14 +9,19 @@ "scripts": { "lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src && prettier --check 'src/**/*.ts'", "fix": "prettier --write src && eslint --fix src", - "api-test": "jest -i follow.spec.ts && jest -i post.spec.ts && jest -i comment.spec.ts && jest -i private_message.spec.ts && jest -i user.spec.ts && jest -i community.spec.ts" + "api-test": "jest -i follow.spec.ts && jest -i post.spec.ts && jest -i comment.spec.ts && jest -i private_message.spec.ts && jest -i user.spec.ts && jest -i community.spec.ts", + "api-test-comment": "jest -i comment.spec.ts", + "api-test-post": "jest -i post.spec.ts", + "api-test-user": "jest -i user.spec.ts", + "api-test-community": "jest -i community.spec.ts", + "api-test-private-message": "jest -i private_message.spec.ts" }, "devDependencies": { - "@types/jest": "^29.5.6", - "@types/node": "^20.8.7", - "@typescript-eslint/eslint-plugin": "^6.8.0", - "@typescript-eslint/parser": "^6.8.0", - "eslint": "^8.52.0", + "@types/jest": "^29.5.8", + "@types/node": "^20.9.0", + "@typescript-eslint/eslint-plugin": "^6.10.0", + "@typescript-eslint/parser": "^6.10.0", + "eslint": "^8.53.0", "eslint-plugin-prettier": "^5.0.1", "jest": "^29.5.0", "lemmy-js-client": "0.19.0-rc.12", diff --git a/api_tests/src/comment.spec.ts b/api_tests/src/comment.spec.ts index 6522a472e..951641d78 100644 --- a/api_tests/src/comment.spec.ts +++ b/api_tests/src/comment.spec.ts @@ -35,9 +35,10 @@ import { waitForPost, alphaUrl, followCommunity, + blockCommunity, + delay, } from "./shared"; -import { CommentView } from "lemmy-js-client/dist/types/CommentView"; -import { CommunityView } from "lemmy-js-client"; +import { CommentView, CommunityView } from "lemmy-js-client"; import { LemmyHttp } from "lemmy-js-client"; let betaCommunity: CommunityView | undefined; @@ -740,3 +741,47 @@ test("Report a comment", async () => { ); expect(betaReport.reason).toBe(alphaReport.reason); }); + +test("Dont send a comment reply to a blocked community", async () => { + let newCommunity = await createCommunity(beta); + let newCommunityId = newCommunity.community_view.community.id; + + // Create a post on beta + let betaPost = await createPost(beta, newCommunityId); + + let alphaPost = (await resolvePost(alpha, betaPost.post_view.post))!.post; + if (!alphaPost) { + throw "unable to locate post on alpha"; + } + + // Check beta's inbox count + let unreadCount = await getUnreadCount(beta); + expect(unreadCount.replies).toBe(1); + + // Beta blocks the new beta community + let blockRes = await blockCommunity(beta, newCommunityId, true); + expect(blockRes.blocked).toBe(true); + delay(); + + // Alpha creates a comment + let commentRes = await createComment(alpha, alphaPost.post.id); + expect(commentRes.comment_view.comment.content).toBeDefined(); + let alphaComment = await resolveComment( + beta, + commentRes.comment_view.comment, + ); + if (!alphaComment) { + throw "Missing alpha comment before block"; + } + + // Check beta's inbox count, make sure it stays the same + unreadCount = await getUnreadCount(beta); + expect(unreadCount.replies).toBe(1); + + let replies = await getReplies(beta); + expect(replies.replies.length).toBe(1); + + // Unblock the community + blockRes = await blockCommunity(beta, newCommunityId, false); + expect(blockRes.blocked).toBe(false); +}); diff --git a/api_tests/src/shared.ts b/api_tests/src/shared.ts index e4dabb1d4..8d1a4744c 100644 --- a/api_tests/src/shared.ts +++ b/api_tests/src/shared.ts @@ -1,6 +1,9 @@ import { + BlockCommunity, + BlockCommunityResponse, BlockInstance, BlockInstanceResponse, + CommunityId, GetReplies, GetRepliesResponse, GetUnreadCountResponse, @@ -796,6 +799,18 @@ export function blockInstance( return api.blockInstance(form); } +export function blockCommunity( + api: LemmyHttp, + community_id: CommunityId, + block: boolean, +): Promise { + let form: BlockCommunity = { + community_id, + block, + }; + return api.blockCommunity(form); +} + export function delay(millis = 500) { return new Promise(resolve => setTimeout(resolve, millis)); } diff --git a/api_tests/yarn.lock b/api_tests/yarn.lock index ca73cf9fc..d00a78380 100644 --- a/api_tests/yarn.lock +++ b/api_tests/yarn.lock @@ -314,10 +314,10 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.1.tgz#449dfa81a57a1d755b09aa58d826c1262e4283b4" integrity sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA== -"@eslint/eslintrc@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" - integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== +"@eslint/eslintrc@^2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.3.tgz#797470a75fe0fbd5a53350ee715e85e87baff22d" + integrity sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -329,10 +329,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.52.0": - version "8.52.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.52.0.tgz#78fe5f117840f69dc4a353adf9b9cd926353378c" - integrity sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA== +"@eslint/js@8.53.0": + version "8.53.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.53.0.tgz#bea56f2ed2b5baea164348ff4d5a879f6f81f20d" + integrity sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w== "@humanwhocodes/config-array@^0.11.13": version "0.11.13" @@ -704,10 +704,10 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^29.5.6": - version "29.5.6" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.6.tgz#f4cf7ef1b5b0bfc1aa744e41b24d9cc52533130b" - integrity sha512-/t9NnzkOpXb4Nfvg17ieHE6EeSjDS2SGSpNYfoLbUAeL/EOueU/RSdOWFpfQTXBEM7BguYW1XQ0EbM+6RlIh6w== +"@types/jest@^29.5.8": + version "29.5.8" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.8.tgz#ed5c256fe2bc7c38b1915ee5ef1ff24a3427e120" + integrity sha512-fXEFTxMV2Co8ZF5aYFJv+YeA08RTYJfhtN5c9JSv/mFEMe+xxjufCb+PHL+bJcMs/ebPUsBu+UNTEz+ydXrR6g== dependencies: expect "^29.0.0" pretty-format "^29.0.0" @@ -722,12 +722,12 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.0.tgz#10ddf0119cf20028781c06d7115562934e53f745" integrity sha512-LzcWltT83s1bthcvjBmiBvGJiiUe84NWRHkw+ZV6Fr41z2FbIzvc815dk2nQ3RAKMuN2fkenM/z3Xv2QzEpYxQ== -"@types/node@^20.8.7": - version "20.8.7" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.7.tgz#ad23827850843de973096edfc5abc9e922492a25" - integrity sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ== +"@types/node@^20.9.0": + version "20.9.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.9.0.tgz#bfcdc230583aeb891cf51e73cfdaacdd8deae298" + integrity sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw== dependencies: - undici-types "~5.25.1" + undici-types "~5.26.4" "@types/semver@^7.5.0": version "7.5.3" @@ -751,16 +751,16 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz#06abe4265e7c82f20ade2dcc0e3403c32d4f148b" - integrity sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw== +"@typescript-eslint/eslint-plugin@^6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.10.0.tgz#cfe2bd34e26d2289212946b96ab19dcad64b661a" + integrity sha512-uoLj4g2OTL8rfUQVx2AFO1hp/zja1wABJq77P6IclQs6I/m9GLrm7jCdgzZkvWdDCQf1uEvoa8s8CupsgWQgVg== dependencies: "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.8.0" - "@typescript-eslint/type-utils" "6.8.0" - "@typescript-eslint/utils" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + "@typescript-eslint/scope-manager" "6.10.0" + "@typescript-eslint/type-utils" "6.10.0" + "@typescript-eslint/utils" "6.10.0" + "@typescript-eslint/visitor-keys" "6.10.0" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.2.4" @@ -768,72 +768,72 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/parser@^6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.8.0.tgz#bb2a969d583db242f1ee64467542f8b05c2e28cb" - integrity sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg== +"@typescript-eslint/parser@^6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.10.0.tgz#578af79ae7273193b0b6b61a742a2bc8e02f875a" + integrity sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog== dependencies: - "@typescript-eslint/scope-manager" "6.8.0" - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/typescript-estree" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + "@typescript-eslint/scope-manager" "6.10.0" + "@typescript-eslint/types" "6.10.0" + "@typescript-eslint/typescript-estree" "6.10.0" + "@typescript-eslint/visitor-keys" "6.10.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.8.0.tgz#5cac7977385cde068ab30686889dd59879811efd" - integrity sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g== +"@typescript-eslint/scope-manager@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz#b0276118b13d16f72809e3cecc86a72c93708540" + integrity sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg== dependencies: - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + "@typescript-eslint/types" "6.10.0" + "@typescript-eslint/visitor-keys" "6.10.0" -"@typescript-eslint/type-utils@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.8.0.tgz#50365e44918ca0fd159844b5d6ea96789731e11f" - integrity sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g== +"@typescript-eslint/type-utils@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.10.0.tgz#1007faede067c78bdbcef2e8abb31437e163e2e1" + integrity sha512-wYpPs3hgTFblMYwbYWPT3eZtaDOjbLyIYuqpwuLBBqhLiuvJ+9sEp2gNRJEtR5N/c9G1uTtQQL5AhV0fEPJYcg== dependencies: - "@typescript-eslint/typescript-estree" "6.8.0" - "@typescript-eslint/utils" "6.8.0" + "@typescript-eslint/typescript-estree" "6.10.0" + "@typescript-eslint/utils" "6.10.0" debug "^4.3.4" ts-api-utils "^1.0.1" -"@typescript-eslint/types@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.8.0.tgz#1ab5d4fe1d613e3f65f6684026ade6b94f7e3ded" - integrity sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ== +"@typescript-eslint/types@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.10.0.tgz#f4f0a84aeb2ac546f21a66c6e0da92420e921367" + integrity sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg== -"@typescript-eslint/typescript-estree@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.8.0.tgz#9565f15e0cd12f55cf5aa0dfb130a6cb0d436ba1" - integrity sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg== +"@typescript-eslint/typescript-estree@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz#667381eed6f723a1a8ad7590a31f312e31e07697" + integrity sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg== dependencies: - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + "@typescript-eslint/types" "6.10.0" + "@typescript-eslint/visitor-keys" "6.10.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/utils@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.8.0.tgz#d42939c2074c6b59844d0982ce26a51d136c4029" - integrity sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q== +"@typescript-eslint/utils@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.10.0.tgz#4d76062d94413c30e402c9b0df8c14aef8d77336" + integrity sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.8.0" - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/typescript-estree" "6.8.0" + "@typescript-eslint/scope-manager" "6.10.0" + "@typescript-eslint/types" "6.10.0" + "@typescript-eslint/typescript-estree" "6.10.0" semver "^7.5.4" -"@typescript-eslint/visitor-keys@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.8.0.tgz#cffebed56ae99c45eba901c378a6447b06be58b8" - integrity sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg== +"@typescript-eslint/visitor-keys@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz#b9eaf855a1ac7e95633ae1073af43d451e8f84e3" + integrity sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg== dependencies: - "@typescript-eslint/types" "6.8.0" + "@typescript-eslint/types" "6.10.0" eslint-visitor-keys "^3.4.1" "@ungap/structured-clone@^1.2.0": @@ -1333,15 +1333,15 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^8.52.0: - version "8.52.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.52.0.tgz#d0cd4a1fac06427a61ef9242b9353f36ea7062fc" - integrity sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg== +eslint@^8.53.0: + version "8.53.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.53.0.tgz#14f2c8244298fcae1f46945459577413ba2697ce" + integrity sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.52.0" + "@eslint/eslintrc" "^2.1.3" + "@eslint/js" "8.53.0" "@humanwhocodes/config-array" "^0.11.13" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" @@ -2952,10 +2952,10 @@ typescript@^5.0.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== -undici-types@~5.25.1: - version "5.25.3" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.25.3.tgz#e044115914c85f0bcbb229f346ab739f064998c3" - integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA== +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== untildify@^4.0.0: version "4.0.0" diff --git a/crates/api_common/src/build_response.rs b/crates/api_common/src/build_response.rs index a85e29765..5ca819334 100644 --- a/crates/api_common/src/build_response.rs +++ b/crates/api_common/src/build_response.rs @@ -3,7 +3,12 @@ use crate::{ community::CommunityResponse, context::LemmyContext, post::PostResponse, - utils::{check_person_block, get_interface_language, is_mod_or_admin, send_email_to_user}, + utils::{ + check_person_instance_community_block, + get_interface_language, + is_mod_or_admin, + send_email_to_user, + }, }; use actix_web::web::Json; use lemmy_db_schema::{ @@ -95,6 +100,8 @@ pub async fn send_local_notifs( let mut recipient_ids = Vec::new(); let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname()); + let community_id = post.community_id; + // Send the local mentions for mention in mentions .iter() @@ -142,13 +149,18 @@ pub async fn send_local_notifs( // Get the parent commenter local_user let parent_creator_id = parent_comment.creator_id; - // Only add to recipients if that person isn't blocked - let creator_blocked = check_person_block(person.id, parent_creator_id, &mut context.pool()) - .await - .is_err(); + let check_blocks = check_person_instance_community_block( + person.id, + parent_creator_id, + person.instance_id, + community_id, + &mut context.pool(), + ) + .await + .is_err(); // Don't send a notif to yourself - if parent_comment.creator_id != person.id && !creator_blocked { + if parent_comment.creator_id != person.id && !check_blocks { let user_view = LocalUserView::read_person(&mut context.pool(), parent_creator_id).await; if let Ok(parent_user_view) = user_view { recipient_ids.push(parent_user_view.local_user.id); @@ -179,13 +191,17 @@ pub async fn send_local_notifs( } } } else { - // If there's no parent, its the post creator - // Only add to recipients if that person isn't blocked - let creator_blocked = check_person_block(person.id, post.creator_id, &mut context.pool()) - .await - .is_err(); + let check_blocks = check_person_instance_community_block( + person.id, + post.creator_id, + person.instance_id, + community_id, + &mut context.pool(), + ) + .await + .is_err(); - if post.creator_id != person.id && !creator_blocked { + if post.creator_id != person.id && !check_blocks { let creator_id = post.creator_id; let parent_user = LocalUserView::read_person(&mut context.pool(), creator_id).await; if let Ok(parent_user_view) = parent_user { diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index c4417e0e1..83530b722 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -7,12 +7,14 @@ use anyhow::Context; use chrono::{DateTime, Days, Local, TimeZone, Utc}; use enum_map::{enum_map, EnumMap}; use lemmy_db_schema::{ - newtypes::{CommunityId, DbUrl, PersonId, PostId}, + newtypes::{CommunityId, DbUrl, InstanceId, PersonId, PostId}, source::{ comment::{Comment, CommentUpdateForm}, community::{Community, CommunityModerator, CommunityUpdateForm}, + community_block::CommunityBlock, email_verification::{EmailVerification, EmailVerificationForm}, instance::Instance, + instance_block::InstanceBlock, local_site::LocalSite, local_site_rate_limit::LocalSiteRateLimit, password_reset_request::PasswordResetRequest, @@ -220,15 +222,14 @@ pub fn check_post_deleted_or_removed(post: &Post) -> Result<(), LemmyError> { } } +/// Throws an error if a recipient has blocked a person. #[tracing::instrument(skip_all)] pub async fn check_person_block( my_id: PersonId, potential_blocker_id: PersonId, pool: &mut DbPool<'_>, ) -> Result<(), LemmyError> { - let is_blocked = PersonBlock::read(pool, potential_blocker_id, my_id) - .await - .is_ok(); + let is_blocked = PersonBlock::read(pool, potential_blocker_id, my_id).await?; if is_blocked { Err(LemmyErrorType::PersonIsBlocked)? } else { @@ -236,6 +237,50 @@ pub async fn check_person_block( } } +/// Throws an error if a recipient has blocked a community. +#[tracing::instrument(skip_all)] +async fn check_community_block( + community_id: CommunityId, + person_id: PersonId, + pool: &mut DbPool<'_>, +) -> Result<(), LemmyError> { + let is_blocked = CommunityBlock::read(pool, person_id, community_id).await?; + if is_blocked { + Err(LemmyErrorType::CommunityIsBlocked)? + } else { + Ok(()) + } +} + +/// Throws an error if a recipient has blocked an instance. +#[tracing::instrument(skip_all)] +async fn check_instance_block( + instance_id: InstanceId, + person_id: PersonId, + pool: &mut DbPool<'_>, +) -> Result<(), LemmyError> { + let is_blocked = InstanceBlock::read(pool, person_id, instance_id).await?; + if is_blocked { + Err(LemmyErrorType::InstanceIsBlocked)? + } else { + Ok(()) + } +} + +#[tracing::instrument(skip_all)] +pub async fn check_person_instance_community_block( + my_id: PersonId, + potential_blocker_id: PersonId, + instance_id: InstanceId, + community_id: CommunityId, + pool: &mut DbPool<'_>, +) -> Result<(), LemmyError> { + check_person_block(my_id, potential_blocker_id, pool).await?; + check_instance_block(instance_id, potential_blocker_id, pool).await?; + check_community_block(community_id, potential_blocker_id, pool).await?; + Ok(()) +} + #[tracing::instrument(skip_all)] pub fn check_downvotes_enabled(score: i16, local_site: &LocalSite) -> Result<(), LemmyError> { if score == -1 && !local_site.enable_downvotes { diff --git a/crates/db_schema/src/impls/community_block.rs b/crates/db_schema/src/impls/community_block.rs index 9dc21bf2f..997985a5b 100644 --- a/crates/db_schema/src/impls/community_block.rs +++ b/crates/db_schema/src/impls/community_block.rs @@ -1,12 +1,36 @@ use crate::{ + newtypes::{CommunityId, PersonId}, schema::community_block::dsl::{community_block, community_id, person_id}, source::community_block::{CommunityBlock, CommunityBlockForm}, traits::Blockable, utils::{get_conn, DbPool}, }; -use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl}; +use diesel::{ + dsl::{exists, insert_into}, + result::Error, + select, + ExpressionMethods, + QueryDsl, +}; use diesel_async::RunQueryDsl; +impl CommunityBlock { + pub async fn read( + pool: &mut DbPool<'_>, + for_person_id: PersonId, + for_community_id: CommunityId, + ) -> Result { + let conn = &mut get_conn(pool).await?; + select(exists( + community_block + .filter(community_id.eq(for_community_id)) + .filter(person_id.eq(for_person_id)), + )) + .get_result(conn) + .await + } +} + #[async_trait] impl Blockable for CommunityBlock { type Form = CommunityBlockForm; diff --git a/crates/db_schema/src/impls/instance_block.rs b/crates/db_schema/src/impls/instance_block.rs index f7f81a234..f024f2636 100644 --- a/crates/db_schema/src/impls/instance_block.rs +++ b/crates/db_schema/src/impls/instance_block.rs @@ -1,12 +1,36 @@ use crate::{ + newtypes::{InstanceId, PersonId}, schema::instance_block::dsl::{instance_block, instance_id, person_id}, source::instance_block::{InstanceBlock, InstanceBlockForm}, traits::Blockable, utils::{get_conn, DbPool}, }; -use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl}; +use diesel::{ + dsl::{exists, insert_into}, + result::Error, + select, + ExpressionMethods, + QueryDsl, +}; use diesel_async::RunQueryDsl; +impl InstanceBlock { + pub async fn read( + pool: &mut DbPool<'_>, + for_person_id: PersonId, + for_instance_id: InstanceId, + ) -> Result { + let conn = &mut get_conn(pool).await?; + select(exists( + instance_block + .filter(instance_id.eq(for_instance_id)) + .filter(person_id.eq(for_person_id)), + )) + .get_result(conn) + .await + } +} + #[async_trait] impl Blockable for InstanceBlock { type Form = InstanceBlockForm; diff --git a/crates/db_schema/src/impls/person_block.rs b/crates/db_schema/src/impls/person_block.rs index 0d125cd51..a616375e1 100644 --- a/crates/db_schema/src/impls/person_block.rs +++ b/crates/db_schema/src/impls/person_block.rs @@ -5,7 +5,13 @@ use crate::{ traits::Blockable, utils::{get_conn, DbPool}, }; -use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl}; +use diesel::{ + dsl::{exists, insert_into}, + result::Error, + select, + ExpressionMethods, + QueryDsl, +}; use diesel_async::RunQueryDsl; impl PersonBlock { @@ -13,13 +19,15 @@ impl PersonBlock { pool: &mut DbPool<'_>, for_person_id: PersonId, for_recipient_id: PersonId, - ) -> Result { + ) -> Result { let conn = &mut get_conn(pool).await?; - person_block - .filter(person_id.eq(for_person_id)) - .filter(target_id.eq(for_recipient_id)) - .first::(conn) - .await + select(exists( + person_block + .filter(person_id.eq(for_person_id)) + .filter(target_id.eq(for_recipient_id)), + )) + .get_result(conn) + .await } } diff --git a/crates/utils/src/error.rs b/crates/utils/src/error.rs index 9eddb67e8..c5cbaa07e 100644 --- a/crates/utils/src/error.rs +++ b/crates/utils/src/error.rs @@ -110,6 +110,8 @@ pub enum LemmyErrorType { CouldntFindCommunity, CouldntFindPerson, PersonIsBlocked, + CommunityIsBlocked, + InstanceIsBlocked, DownvotesAreDisabled, InstanceIsPrivate, /// Password must be between 10 and 60 characters