diff --git a/Cargo.lock b/Cargo.lock index b22858a62..87b537173 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2894,6 +2894,7 @@ dependencies = [ "rustls 0.21.3", "serde", "serde_json", + "serial_test", "tokio", "tokio-postgres", "tokio-postgres-rustls", diff --git a/Cargo.toml b/Cargo.toml index 02210e6c0..f0c987121 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -166,5 +166,6 @@ tokio-postgres-rustls = { workspace = true } chrono = { workspace = true } prometheus = { version = "0.13.3", features = ["process"], optional = true } actix-web-prom = { version = "0.6.0", optional = true } +serial_test = { workspace = true } clap = { version = "4.3.19", features = ["derive"] } lemmy_federate = { version = "0.18.4", path = "crates/federate" } diff --git a/api_tests/package.json b/api_tests/package.json index e57d37d08..56624f9e2 100644 --- a/api_tests/package.json +++ b/api_tests/package.json @@ -19,7 +19,7 @@ "eslint": "^8.40.0", "eslint-plugin-prettier": "^4.0.0", "jest": "^29.5.0", - "lemmy-js-client": "0.19.0-rc.5", + "lemmy-js-client": "0.19.0-rc.12", "prettier": "^3.0.0", "ts-jest": "^29.1.0", "typescript": "^5.0.4" diff --git a/api_tests/prepare-drone-federation-test.sh b/api_tests/prepare-drone-federation-test.sh index ba6dd324b..4044ba0dd 100755 --- a/api_tests/prepare-drone-federation-test.sh +++ b/api_tests/prepare-drone-federation-test.sh @@ -6,6 +6,8 @@ set -e export RUST_BACKTRACE=1 export RUST_LOG="warn,lemmy_server=debug,lemmy_federate=debug,lemmy_api=debug,lemmy_api_common=debug,lemmy_api_crud=debug,lemmy_apub=debug,lemmy_db_schema=debug,lemmy_db_views=debug,lemmy_db_views_actor=debug,lemmy_db_views_moderator=debug,lemmy_routes=debug,lemmy_utils=debug,lemmy_websocket=debug" +export LEMMY_TEST_FAST_FEDERATION=1 # by default, the persistent federation queue has delays in the scale of 30s-5min + for INSTANCE in lemmy_alpha lemmy_beta lemmy_gamma lemmy_delta lemmy_epsilon; do echo "DB URL: ${LEMMY_DATABASE_URL} INSTANCE: $INSTANCE" psql "${LEMMY_DATABASE_URL}/lemmy" -c "DROP DATABASE IF EXISTS $INSTANCE" @@ -34,30 +36,30 @@ echo "$PWD" echo "start alpha" LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_alpha.hjson \ -LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_alpha" \ -target/lemmy_server >/tmp/lemmy_alpha.out 2>&1 & + LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_alpha" \ + target/lemmy_server >/tmp/lemmy_alpha.out 2>&1 & echo "start beta" LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_beta.hjson \ -LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_beta" \ -target/lemmy_server >/tmp/lemmy_beta.out 2>&1 & + LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_beta" \ + target/lemmy_server >/tmp/lemmy_beta.out 2>&1 & echo "start gamma" LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_gamma.hjson \ -LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_gamma" \ -target/lemmy_server >/tmp/lemmy_gamma.out 2>&1 & + LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_gamma" \ + target/lemmy_server >/tmp/lemmy_gamma.out 2>&1 & echo "start delta" # An instance with only an allowlist for beta LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_delta.hjson \ -LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_delta" \ -target/lemmy_server >/tmp/lemmy_delta.out 2>&1 & + LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_delta" \ + target/lemmy_server >/tmp/lemmy_delta.out 2>&1 & echo "start epsilon" # An instance who has a blocklist, with lemmy-alpha blocked LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_epsilon.hjson \ -LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_epsilon" \ -target/lemmy_server >/tmp/lemmy_epsilon.out 2>&1 & + LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_epsilon" \ + target/lemmy_server >/tmp/lemmy_epsilon.out 2>&1 & echo "wait for all instances to start" while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'lemmy-alpha:8541/api/v3/site')" != "200" ]]; do sleep 1; done diff --git a/api_tests/src/comment.spec.ts b/api_tests/src/comment.spec.ts index 000c0b0ab..6ced2bf33 100644 --- a/api_tests/src/comment.spec.ts +++ b/api_tests/src/comment.spec.ts @@ -24,7 +24,6 @@ import { reportComment, listCommentReports, randomString, - API, unfollows, getComments, getCommentParentId, @@ -34,19 +33,21 @@ import { getUnreadCount, waitUntil, delay, + waitForPost, + alphaUrl, } from "./shared"; import { CommentView } from "lemmy-js-client/dist/types/CommentView"; +import { CommunityView } from "lemmy-js-client"; +import { LemmyHttp } from "lemmy-js-client"; +let betaCommunity: CommunityView | undefined; let postOnAlphaRes: PostResponse; beforeAll(async () => { await setupLogins(); await unfollows(); - await followBeta(alpha); - await followBeta(gamma); - // wait for FOLLOW_ADDITIONS_RECHECK_DELAY - await delay(2000); - let betaCommunity = (await resolveBetaCommunity(alpha)).community; + await Promise.all([followBeta(alpha), followBeta(gamma)]); + betaCommunity = (await resolveBetaCommunity(alpha)).community; if (betaCommunity) { postOnAlphaRes = await createPost(alpha, betaCommunity.community.id); } @@ -227,10 +228,9 @@ test.skip("Remove a comment from admin and community on the same instance", asyn test("Remove a comment from admin and community on different instance", async () => { let alpha_user = await registerUser(alpha); - let newAlphaApi: API = { - client: alpha.client, - auth: alpha_user.jwt ?? "", - }; + let newAlphaApi = new LemmyHttp(alphaUrl, { + headers: { auth: alpha_user.jwt ?? "" }, + }); // New alpha user creates a community, post, and comment. let newCommunity = await createCommunity(newAlphaApi); @@ -343,6 +343,8 @@ test("Federated comment like", async () => { }); test("Reply to a comment from another instance, get notification", async () => { + await alpha.markAllAsRead(); + let betaCommunity = (await resolveBetaCommunity(alpha)).community; if (!betaCommunity) { throw "Missing beta community"; @@ -375,16 +377,17 @@ test("Reply to a comment from another instance, get notification", async () => { expect(replyRes.comment_view.counts.score).toBe(1); // Make sure that reply comment is seen on alpha - // TODO not sure why, but a searchComment back to alpha, for the ap_id of betas - // comment, isn't working. - // let searchAlpha = await searchComment(alpha, replyRes.comment); + let commentSearch = await waitUntil( + () => resolveComment(alpha, replyRes.comment_view.comment), + c => c.comment?.counts.score === 1, + ); + let alphaComment = commentSearch.comment!; let postComments = await waitUntil( () => getComments(alpha, postOnAlphaRes.post_view.post.id), pc => pc.comments.length >= 2, ); // Note: this test fails when run twice and this count will differ expect(postComments.comments.length).toBeGreaterThanOrEqual(2); - let alphaComment = postComments.comments[0]; expect(alphaComment.comment.content).toBeDefined(); expect(getCommentParentId(alphaComment.comment)).toBe( @@ -400,23 +403,29 @@ test("Reply to a comment from another instance, get notification", async () => { () => getUnreadCount(alpha), e => e.replies >= 1, ); - expect(alphaUnreadCountRes.replies).toBe(1); + expect(alphaUnreadCountRes.replies).toBeGreaterThanOrEqual(1); // check inbox of replies on alpha, fetching read/unread both let alphaRepliesRes = await getReplies(alpha); - expect(alphaRepliesRes.replies.length).toBe(1); - expect(alphaRepliesRes.replies[0].comment.content).toBeDefined(); - expect(alphaRepliesRes.replies[0].community.local).toBe(false); - expect(alphaRepliesRes.replies[0].creator.local).toBe(false); - expect(alphaRepliesRes.replies[0].counts.score).toBe(1); + const alphaReply = alphaRepliesRes.replies.find( + r => r.comment.id === alphaComment.comment.id, + ); + expect(alphaReply).toBeDefined(); + if (!alphaReply) throw Error(); + expect(alphaReply.comment.content).toBeDefined(); + expect(alphaReply.community.local).toBe(false); + expect(alphaReply.creator.local).toBe(false); + expect(alphaReply.counts.score).toBe(1); // ToDo: interesting alphaRepliesRes.replies[0].comment_reply.id is 1, meaning? how did that come about? - expect(alphaRepliesRes.replies[0].comment.id).toBe(alphaComment.comment.id); + expect(alphaReply.comment.id).toBe(alphaComment.comment.id); // this is a new notification, getReplies fetch was for read/unread both, confirm it is unread. - expect(alphaRepliesRes.replies[0].comment_reply.read).toBe(false); - assertCommentFederation(alphaRepliesRes.replies[0], replyRes.comment_view); + expect(alphaReply.comment_reply.read).toBe(false); + assertCommentFederation(alphaReply, replyRes.comment_view); }); test("Mention beta from alpha", async () => { + if (!betaCommunity) throw Error("no community"); + const postOnAlphaRes = await createPost(alpha, betaCommunity.community.id); // Create a new branch, trunk-level comment branch, from alpha instance let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id); // Create a reply comment to previous comment, this has a mention in body @@ -433,7 +442,7 @@ test("Mention beta from alpha", async () => { expect(mentionRes.comment_view.counts.score).toBe(1); // get beta's localized copy of the alpha post - let betaPost = (await resolvePost(beta, postOnAlphaRes.post_view.post)).post; + let betaPost = await waitForPost(beta, postOnAlphaRes.post_view.post); if (!betaPost) { throw "unable to locate post on beta"; } @@ -443,9 +452,9 @@ test("Mention beta from alpha", async () => { // Make sure that both new comments are seen on beta and have parent/child relationship let betaPostComments = await waitUntil( () => getComments(beta, betaPost!.post.id), - c => c.comments[1].counts.score === 1, + c => c.comments[1]?.counts.score === 1, ); - expect(betaPostComments.comments.length).toBeGreaterThanOrEqual(2); + expect(betaPostComments.comments.length).toEqual(2); // the trunk-branch root comment will be older than the mention reply comment, so index 1 let betaRootComment = betaPostComments.comments[1]; // the trunk-branch root comment should not have a parent @@ -460,7 +469,10 @@ test("Mention beta from alpha", async () => { expect(betaRootComment.counts.score).toBe(1); assertCommentFederation(betaRootComment, commentRes.comment_view); - let mentionsRes = await getMentions(beta); + let mentionsRes = await waitUntil( + () => getMentions(beta), + m => !!m.mentions[0], + ); expect(mentionsRes.mentions[0].comment.content).toBeDefined(); expect(mentionsRes.mentions[0].community.local).toBe(true); expect(mentionsRes.mentions[0].creator.local).toBe(false); @@ -492,7 +504,7 @@ test("A and G subscribe to B (center) A posts, G mentions B, it gets announced t expect(alphaPost.post_view.community.local).toBe(true); // Make sure gamma sees it - let gammaPost = (await resolvePost(gamma, alphaPost.post_view.post)).post; + let gammaPost = (await resolvePost(gamma, alphaPost.post_view.post))!.post; if (!gammaPost) { throw "Missing gamma post"; @@ -514,7 +526,7 @@ test("A and G subscribe to B (center) A posts, G mentions B, it gets announced t // Make sure alpha sees it let alphaPostComments2 = await waitUntil( () => getComments(alpha, alphaPost.post_view.post.id), - e => !!e.comments[0], + e => e.comments[0]?.counts.score === 1, ); expect(alphaPostComments2.comments[0].comment.content).toBe(commentContent); expect(alphaPostComments2.comments[0].community.local).toBe(true); @@ -560,21 +572,19 @@ test("Check that activity from another instance is sent to third instance", asyn () => resolveBetaCommunity(gamma), c => c.community?.subscribed === "Subscribed", ); - // FOLLOW_ADDITIONS_RECHECK_DELAY - await delay(2000); // Create a post on beta let betaPost = await createPost(beta, 2); expect(betaPost.post_view.community.local).toBe(true); // Make sure gamma and alpha see it - let gammaPost = (await resolvePost(gamma, betaPost.post_view.post)).post; + let gammaPost = await waitForPost(gamma, betaPost.post_view.post); if (!gammaPost) { throw "Missing gamma post"; } expect(gammaPost.post).toBeDefined(); - let alphaPost = (await resolvePost(alpha, betaPost.post_view.post)).post; + let alphaPost = await waitForPost(alpha, betaPost.post_view.post); if (!alphaPost) { throw "Missing alpha post"; } @@ -596,7 +606,7 @@ test("Check that activity from another instance is sent to third instance", asyn // Make sure alpha sees it let alphaPostComments2 = await waitUntil( () => getComments(alpha, alphaPost!.post.id), - e => !!e.comments[0], + e => e.comments[0]?.counts.score === 1, ); expect(alphaPostComments2.comments[0].comment.content).toBe(commentContent); expect(alphaPostComments2.comments[0].community.local).toBe(false); @@ -607,8 +617,7 @@ test("Check that activity from another instance is sent to third instance", asyn commentRes.comment_view, ); - await unfollowRemotes(alpha); - await unfollowRemotes(gamma); + await Promise.all([unfollowRemotes(alpha), unfollowRemotes(gamma)]); }); test("Fetch in_reply_tos: A is unsubbed from B, B makes a post, and some embedded comments, A subs to B, B updates the lowest level comment, A fetches both the post and all the inreplyto comments for that post.", async () => { @@ -660,8 +669,8 @@ test("Fetch in_reply_tos: A is unsubbed from B, B makes a post, and some embedde expect(updateRes.comment_view.comment.content).toBe(updatedCommentContent); // Get the post from alpha - let alphaPostB = (await resolvePost(alpha, postOnBetaRes.post_view.post)) - .post; + let alphaPostB = await waitForPost(alpha, postOnBetaRes.post_view.post); + if (!alphaPostB) { throw "Missing alpha post B"; } @@ -671,7 +680,8 @@ test("Fetch in_reply_tos: A is unsubbed from B, B makes a post, and some embedde () => getComments(alpha, alphaPostB!.post.id), c => c.comments[1]?.comment.content === - parentCommentRes.comment_view.comment.content, + parentCommentRes.comment_view.comment.content && + c.comments[0]?.comment.content === updateRes.comment_view.comment.content, ); expect(alphaPost.post_view.post.name).toBeDefined(); assertCommentFederation( @@ -705,16 +715,17 @@ test("Report a comment", async () => { throw "Missing alpha comment"; } - let alphaReport = ( - await reportComment(alpha, alphaComment.id, randomString(10)) - ).comment_report_view.comment_report; + const reason = randomString(10); + let alphaReport = (await reportComment(alpha, alphaComment.id, reason)) + .comment_report_view.comment_report; - let betaReport = ( - await waitUntil( - () => listCommentReports(beta), - e => !!e.comment_reports[0], - ) - ).comment_reports[0].comment_report; + let betaReport = (await waitUntil( + () => + listCommentReports(beta).then(r => + r.comment_reports.find(rep => rep.comment_report.reason === reason), + ), + e => !!e, + ))!.comment_report; expect(betaReport).toBeDefined(); expect(betaReport.resolved).toBe(false); expect(betaReport.original_comment_text).toBe( diff --git a/api_tests/src/community.spec.ts b/api_tests/src/community.spec.ts index effd2169e..b81dd900c 100644 --- a/api_tests/src/community.spec.ts +++ b/api_tests/src/community.spec.ts @@ -19,7 +19,6 @@ import { getPost, resolvePost, registerUser, - API, getPosts, getComments, createComment, @@ -27,7 +26,10 @@ import { blockInstance, waitUntil, delay, + waitForPost, + alphaUrl, } from "./shared"; +import { LemmyHttp } from "lemmy-js-client"; beforeAll(async () => { await setupLogins(); @@ -88,12 +90,6 @@ test("Delete community", async () => { // Make sure the follow response went through expect(follow.community_view.community.local).toBe(false); - await waitUntil( - () => resolveCommunity(alpha, searchShort), - g => g.community?.subscribed === "Subscribed", - ); - // wait FOLLOW_ADDITIONS_RECHECK_DELAY - await delay(2000); let deleteCommunityRes = await deleteCommunity( beta, true, @@ -146,10 +142,6 @@ test("Remove community", async () => { // Make sure the follow response went through expect(follow.community_view.community.local).toBe(false); - await waitUntil( - () => resolveCommunity(alpha, searchShort), - g => g.community?.subscribed === "Subscribed", - ); let removeCommunityRes = await removeCommunity( beta, true, @@ -258,11 +250,10 @@ test("Admin actions in remote community are not federated to origin", async () = test("moderator view", async () => { // register a new user with their own community on alpha and post to it - let otherUser: API = { - auth: (await registerUser(alpha)).jwt ?? "", - client: alpha.client, - }; - expect(otherUser.auth).not.toBe(""); + let registerUserRes = await registerUser(alpha); + let otherUser = new LemmyHttp(alphaUrl, { + headers: { auth: registerUserRes.jwt ?? "" }, + }); let otherCommunity = (await createCommunity(otherUser)).community_view; expect(otherCommunity.community.name).toBeDefined(); @@ -361,8 +352,8 @@ test("User blocks instance, communities are hidden", async () => { expect(postRes.post_view.post.id).toBeDefined(); // fetch post to alpha - let alphaPost = await resolvePost(alpha, postRes.post_view.post); - expect(alphaPost.post?.post).toBeDefined(); + let alphaPost = (await resolvePost(alpha, postRes.post_view.post)).post!; + expect(alphaPost.post).toBeDefined(); // post should be included in listing let listing = await getPosts(alpha, "All"); @@ -370,7 +361,7 @@ test("User blocks instance, communities are hidden", async () => { expect(listing_ids).toContain(postRes.post_view.post.ap_id); // block the beta instance - await blockInstance(alpha, alphaPost.post!.community.instance_id, true); + await blockInstance(alpha, alphaPost.community.instance_id, true); // after blocking, post should not be in listing let listing2 = await getPosts(alpha, "All"); @@ -378,7 +369,7 @@ test("User blocks instance, communities are hidden", async () => { expect(listing_ids2.indexOf(postRes.post_view.post.ap_id)).toBe(-1); // unblock instance again - await blockInstance(alpha, alphaPost.post!.community.instance_id, false); + await blockInstance(alpha, alphaPost.community.instance_id, false); // post should be included in listing let listing3 = await getPosts(alpha, "All"); diff --git a/api_tests/src/post.spec.ts b/api_tests/src/post.spec.ts index cd3eec71b..51a10293b 100644 --- a/api_tests/src/post.spec.ts +++ b/api_tests/src/post.spec.ts @@ -30,15 +30,16 @@ import { listPostReports, randomString, registerUser, - API, getSite, unfollows, resolveCommunity, waitUntil, - delay, + waitForPost, + alphaUrl, } from "./shared"; import { PostView } from "lemmy-js-client/dist/types/PostView"; import { CreatePost } from "lemmy-js-client/dist/types/CreatePost"; +import { LemmyHttp } from "lemmy-js-client"; let betaCommunity: CommunityView | undefined; @@ -82,11 +83,11 @@ test("Create a post", async () => { expect(postRes.post_view.counts.score).toBe(1); // Make sure that post is liked on beta - const res = await waitUntil( - () => resolvePost(beta, postRes.post_view.post), - res => res.post?.counts.score === 1, + const betaPost = await waitForPost( + beta, + postRes.post_view.post, + res => res?.counts.score === 1, ); - let betaPost = res.post; expect(betaPost).toBeDefined(); expect(betaPost?.community.local).toBe(true); @@ -122,12 +123,12 @@ test("Unlike a post", async () => { expect(unlike2.post_view.counts.score).toBe(0); // Make sure that post is unliked on beta - const betaPost = ( - await waitUntil( - () => resolvePost(beta, postRes.post_view.post), - b => b.post?.counts.score === 0, - ) - ).post; + const betaPost = await waitForPost( + beta, + postRes.post_view.post, + post => post?.counts.score === 0, + ); + expect(betaPost).toBeDefined(); expect(betaPost?.community.local).toBe(true); expect(betaPost?.creator.local).toBe(false); @@ -140,26 +141,16 @@ test("Update a post", async () => { throw "Missing beta community"; } let postRes = await createPost(alpha, betaCommunity.community.id); - await waitUntil( - () => resolvePost(beta, postRes.post_view.post), - res => !!res.post, - ); + await waitForPost(beta, postRes.post_view.post); let updatedName = "A jest test federated post, updated"; let updatedPost = await editPost(alpha, postRes.post_view.post); - await waitUntil( - () => resolvePost(beta, postRes.post_view.post), - res => res.post?.post.name === updatedName, - ); expect(updatedPost.post_view.post.name).toBe(updatedName); expect(updatedPost.post_view.community.local).toBe(false); expect(updatedPost.post_view.creator.local).toBe(true); // Make sure that post is updated on beta - let betaPost = (await resolvePost(beta, postRes.post_view.post)).post; - if (!betaPost) { - throw "Missing beta post"; - } + let betaPost = await waitForPost(beta, updatedPost.post_view.post); expect(betaPost.community.local).toBe(true); expect(betaPost.creator.local).toBe(false); expect(betaPost.post.name).toBe(updatedName); @@ -177,7 +168,7 @@ test("Sticky a post", async () => { } let postRes = await createPost(alpha, betaCommunity.community.id); - let betaPost1 = (await resolvePost(beta, postRes.post_view.post)).post; + let betaPost1 = await waitForPost(beta, postRes.post_view.post); if (!betaPost1) { throw "Missing beta post1"; } @@ -220,30 +211,19 @@ test("Lock a post", async () => { () => resolveBetaCommunity(alpha), c => c.community?.subscribed === "Subscribed", ); - // wait FOLLOW_ADDITIONS_RECHECK_DELAY (there's no API to wait for this currently) - await delay(2_000); let postRes = await createPost(alpha, betaCommunity.community.id); - // wait for federation - await waitUntil( - () => searchPostLocal(beta, postRes.post_view.post), - res => !!res.posts[0], - ); + let betaPost1 = await waitForPost(beta, postRes.post_view.post); // Lock the post - let betaPost1 = (await resolvePost(beta, postRes.post_view.post)).post; - if (!betaPost1) { - throw "Missing beta post1"; - } let lockedPostRes = await lockPost(beta, true, betaPost1.post); expect(lockedPostRes.post_view.post.locked).toBe(true); // Make sure that post is locked on alpha - let searchAlpha = await waitUntil( - () => searchPostLocal(alpha, postRes.post_view.post), - res => res.posts[0]?.post.locked, + let alphaPost1 = await waitForPost( + alpha, + postRes.post_view.post, + post => !!post && post.post.locked, ); - let alphaPost1 = searchAlpha.posts[0]; - expect(alphaPost1.post.locked).toBe(true); // Try to make a new comment there, on alpha await expect(createComment(alpha, alphaPost1.post.id)).rejects.toBe("locked"); @@ -253,11 +233,11 @@ test("Lock a post", async () => { expect(unlockedPost.post_view.post.locked).toBe(false); // Make sure that post is unlocked on alpha - let searchAlpha2 = await waitUntil( - () => searchPostLocal(alpha, postRes.post_view.post), - res => !res.posts[0]?.post.locked, + let alphaPost2 = await waitForPost( + alpha, + postRes.post_view.post, + post => !!post && !post.post.locked, ); - let alphaPost2 = searchAlpha2.posts[0]; expect(alphaPost2.community.local).toBe(false); expect(alphaPost2.creator.local).toBe(true); expect(alphaPost2.post.locked).toBe(false); @@ -274,6 +254,7 @@ test("Delete a post", async () => { let postRes = await createPost(alpha, betaCommunity.community.id); expect(postRes.post_view.post).toBeDefined(); + await waitForPost(beta, postRes.post_view.post); let deletedPost = await deletePost(alpha, true, postRes.post_view.post); expect(deletedPost.post_view.post.deleted).toBe(true); @@ -281,16 +262,18 @@ test("Delete a post", async () => { // Make sure lemmy beta sees post is deleted // This will be undefined because of the tombstone - await expect(resolvePost(beta, postRes.post_view.post)).rejects.toBe( - "couldnt_find_object", - ); + await waitForPost(beta, postRes.post_view.post, p => !p || p.post.deleted); // Undelete let undeletedPost = await deletePost(alpha, false, postRes.post_view.post); - expect(undeletedPost.post_view.post.deleted).toBe(false); // Make sure lemmy beta sees post is undeleted - let betaPost2 = (await resolvePost(beta, postRes.post_view.post)).post; + let betaPost2 = await waitForPost( + beta, + postRes.post_view.post, + p => !!p && !p.post.deleted, + ); + if (!betaPost2) { throw "Missing beta post 2"; } @@ -349,11 +332,7 @@ test("Remove a post from admin and community on same instance", async () => { let postRes = await createPost(alpha, betaCommunity.community.id); expect(postRes.post_view.post).toBeDefined(); // Get the id for beta - let searchBeta = await waitUntil( - () => searchPostLocal(beta, postRes.post_view.post), - res => !!res.posts[0], - ); - let betaPost = searchBeta.posts[0]; + let betaPost = await waitForPost(beta, postRes.post_view.post); expect(betaPost).toBeDefined(); // The beta admin removes it (the community lives on beta) @@ -361,18 +340,25 @@ test("Remove a post from admin and community on same instance", async () => { expect(removePostRes.post_view.post.removed).toBe(true); // Make sure lemmy alpha sees post is removed - // let alphaPost = await getPost(alpha, postRes.post_view.post.id); - // expect(alphaPost.post_view.post.removed).toBe(true); // TODO this shouldn't be commented - // assertPostFederation(alphaPost.post_view, removePostRes.post_view); + let alphaPost = await waitUntil( + () => getPost(alpha, postRes.post_view.post.id), + p => p?.post_view.post.removed ?? false, + ); + expect(alphaPost.post_view?.post.removed).toBe(true); + assertPostFederation(alphaPost.post_view, removePostRes.post_view); // Undelete let undeletedPost = await removePost(beta, false, betaPost.post); expect(undeletedPost.post_view.post.removed).toBe(false); // Make sure lemmy alpha sees post is undeleted - let alphaPost2 = await getPost(alpha, postRes.post_view.post.id); - expect(alphaPost2.post_view.post.removed).toBe(false); - assertPostFederation(alphaPost2.post_view, undeletedPost.post_view); + let alphaPost2 = await waitForPost( + alpha, + postRes.post_view.post, + p => !!p && !p.post.removed, + ); + expect(alphaPost2.post.removed).toBe(false); + assertPostFederation(alphaPost2, undeletedPost.post_view); await unfollowRemotes(alpha); }); @@ -384,7 +370,7 @@ test("Search for a post", async () => { let postRes = await createPost(alpha, betaCommunity.community.id); expect(postRes.post_view.post).toBeDefined(); - let betaPost = (await resolvePost(beta, postRes.post_view.post)).post; + let betaPost = await waitForPost(beta, postRes.post_view.post); expect(betaPost?.post.name).toBeDefined(); }); @@ -395,17 +381,16 @@ test("Enforce site ban for federated user", async () => { // create a test user let alphaUserJwt = await registerUser(alpha); expect(alphaUserJwt).toBeDefined(); - let alpha_user: API = { - client: alpha.client, - auth: alphaUserJwt.jwt ?? "", - }; - const alphaUserActorId = (await getSite(alpha_user)).my_user?.local_user_view + let alpha_user = new LemmyHttp(alphaUrl, { + headers: { auth: alphaUserJwt.jwt ?? "" }, + }); + let alphaUserActorId = (await getSite(alpha_user)).my_user?.local_user_view .person.actor_id; if (!alphaUserActorId) { throw "Missing alpha user actor id"; } expect(alphaUserActorId).toBeDefined(); - let alphaPerson = (await resolvePerson(alpha_user, alphaUserActorId)).person; + let alphaPerson = (await resolvePerson(alpha_user, alphaUserActorId!)).person; if (!alphaPerson) { throw "Missing alpha person"; } @@ -413,11 +398,7 @@ test("Enforce site ban for federated user", async () => { // alpha makes post in beta community, it federates to beta instance let postRes1 = await createPost(alpha_user, betaCommunity.community.id); - let searchBeta1 = await waitUntil( - () => searchPostLocal(beta, postRes1.post_view.post), - res => !!res.posts[0], - ); - expect(searchBeta1.posts[0]).toBeDefined(); + let searchBeta1 = await waitForPost(beta, postRes1.post_view.post); // ban alpha from its instance let banAlpha = await banPersonFromSite( @@ -430,14 +411,16 @@ test("Enforce site ban for federated user", async () => { // alpha ban should be federated to beta let alphaUserOnBeta1 = await waitUntil( - () => resolvePerson(beta, alphaUserActorId), + () => resolvePerson(beta, alphaUserActorId!), res => res.person?.person.banned ?? false, ); expect(alphaUserOnBeta1.person?.person.banned).toBe(true); // existing alpha post should be removed on beta - let searchBeta2 = await getPost(beta, searchBeta1.posts[0].post.id); - expect(searchBeta2.post_view.post.removed).toBe(true); + let searchBeta2 = await waitUntil( + () => getPost(beta, searchBeta1.post.id), + s => s.post_view.post.removed, + ); // Unban alpha let unBanAlpha = await banPersonFromSite( @@ -450,13 +433,9 @@ test("Enforce site ban for federated user", async () => { // alpha makes new post in beta community, it federates let postRes2 = await createPost(alpha_user, betaCommunity.community.id); - let searchBeta3 = await waitUntil( - () => searchPostLocal(beta, postRes2.post_view.post), - e => !!e.posts[0], - ); - expect(searchBeta3.posts[0]).toBeDefined(); + let searchBeta3 = await waitForPost(beta, postRes2.post_view.post); - let alphaUserOnBeta2 = await resolvePerson(beta, alphaUserActorId); + let alphaUserOnBeta2 = await resolvePerson(beta, alphaUserActorId!); expect(alphaUserOnBeta2.person?.person.banned).toBe(false); }); @@ -544,12 +523,16 @@ test("Report a post", async () => { await reportPost(alpha, alphaPost.post.id, randomString(10)) ).post_report_view.post_report; - let betaReport = ( - await waitUntil( - () => listPostReports(beta), - res => !!res.post_reports[0], - ) - ).post_reports[0].post_report; + let betaReport = (await waitUntil( + () => + listPostReports(beta).then(p => + p.post_reports.find( + r => + r.post_report.original_post_name === alphaReport.original_post_name, + ), + ), + res => !!res, + ))!.post_report; expect(betaReport).toBeDefined(); expect(betaReport.resolved).toBe(false); expect(betaReport.original_post_name).toBe(alphaReport.original_post_name); @@ -569,10 +552,9 @@ test("Sanitize HTML", async () => { let form: CreatePost = { name, body, - auth: beta.auth, community_id: betaCommunity.community.id, }; - let post = await beta.client.createPost(form); + let post = await beta.createPost(form); // first escaping for the api expect(post.post_view.post.body).toBe( "<script>alert('xss');</script> hello &"'", diff --git a/api_tests/src/shared.ts b/api_tests/src/shared.ts index f7039942d..a1868f8f2 100644 --- a/api_tests/src/shared.ts +++ b/api_tests/src/shared.ts @@ -3,10 +3,10 @@ import { BlockInstanceResponse, GetReplies, GetRepliesResponse, - GetUnreadCount, GetUnreadCountResponse, InstanceId, LemmyHttp, + PostView, } from "lemmy-js-client"; import { CreatePost } from "lemmy-js-client/dist/types/CreatePost"; import { DeletePost } from "lemmy-js-client/dist/types/DeletePost"; @@ -56,7 +56,6 @@ import { SaveUserSettings } from "lemmy-js-client/dist/types/SaveUserSettings"; import { DeleteAccount } from "lemmy-js-client/dist/types/DeleteAccount"; import { GetSiteResponse } from "lemmy-js-client/dist/types/GetSiteResponse"; import { DeleteAccountResponse } from "lemmy-js-client/dist/types/DeleteAccountResponse"; -import { GetSite } from "lemmy-js-client/dist/types/GetSite"; import { PrivateMessagesResponse } from "lemmy-js-client/dist/types/PrivateMessagesResponse"; import { GetPrivateMessages } from "lemmy-js-client/dist/types/GetPrivateMessages"; import { PostReportResponse } from "lemmy-js-client/dist/types/PostReportResponse"; @@ -73,35 +72,17 @@ import { GetPersonDetailsResponse } from "lemmy-js-client/dist/types/GetPersonDe import { GetPersonDetails } from "lemmy-js-client/dist/types/GetPersonDetails"; import { ListingType } from "lemmy-js-client/dist/types/ListingType"; -export interface API { - client: LemmyHttp; - auth: string; -} +export let alphaUrl = "http://127.0.0.1:8541"; +export let betaUrl = "http://127.0.0.1:8551"; +export let gammaUrl = "http://127.0.0.1:8561"; +export let deltaUrl = "http://127.0.0.1:8571"; +export let epsilonUrl = "http://127.0.0.1:8581"; -export let alpha: API = { - client: new LemmyHttp("http://127.0.0.1:8541"), - auth: "", -}; - -export let beta: API = { - client: new LemmyHttp("http://127.0.0.1:8551"), - auth: "", -}; - -export let gamma: API = { - client: new LemmyHttp("http://127.0.0.1:8561"), - auth: "", -}; - -export let delta: API = { - client: new LemmyHttp("http://127.0.0.1:8571"), - auth: "", -}; - -export let epsilon: API = { - client: new LemmyHttp("http://127.0.0.1:8581"), - auth: "", -}; +export let alpha = new LemmyHttp(alphaUrl); +export let beta = new LemmyHttp(betaUrl); +export let gamma = new LemmyHttp(gammaUrl); +export let delta = new LemmyHttp(deltaUrl); +export let epsilon = new LemmyHttp(epsilonUrl); const password = "lemmylemmy"; @@ -110,31 +91,31 @@ export async function setupLogins() { username_or_email: "lemmy_alpha", password, }; - let resAlpha = alpha.client.login(formAlpha); + let resAlpha = alpha.login(formAlpha); let formBeta: Login = { username_or_email: "lemmy_beta", password, }; - let resBeta = beta.client.login(formBeta); + let resBeta = beta.login(formBeta); let formGamma: Login = { username_or_email: "lemmy_gamma", password, }; - let resGamma = gamma.client.login(formGamma); + let resGamma = gamma.login(formGamma); let formDelta: Login = { username_or_email: "lemmy_delta", password, }; - let resDelta = delta.client.login(formDelta); + let resDelta = delta.login(formDelta); let formEpsilon: Login = { username_or_email: "lemmy_epsilon", password, }; - let resEpsilon = epsilon.client.login(formEpsilon); + let resEpsilon = epsilon.login(formEpsilon); let res = await Promise.all([ resAlpha, @@ -143,12 +124,11 @@ export async function setupLogins() { 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 ?? ""; + alpha.setHeaders({ auth: res[0].jwt ?? "" }); + beta.setHeaders({ auth: res[1].jwt ?? "" }); + gamma.setHeaders({ auth: res[2].jwt ?? "" }); + delta.setHeaders({ auth: res[3].jwt ?? "" }); + epsilon.setHeaders({ auth: res[4].jwt ?? "" }); // Registration applications are now enabled by default, need to disable them let editSiteForm: EditSite = { @@ -159,45 +139,39 @@ export async function setupLogins() { rate_limit_image: 999, rate_limit_comment: 999, rate_limit_search: 999, - auth: "", }; // Set the blocks and auths for each - editSiteForm.auth = alpha.auth; editSiteForm.allowed_instances = [ "lemmy-beta", "lemmy-gamma", "lemmy-delta", "lemmy-epsilon", ]; - await alpha.client.editSite(editSiteForm); + await alpha.editSite(editSiteForm); - editSiteForm.auth = beta.auth; editSiteForm.allowed_instances = [ "lemmy-alpha", "lemmy-gamma", "lemmy-delta", "lemmy-epsilon", ]; - await beta.client.editSite(editSiteForm); + await beta.editSite(editSiteForm); - editSiteForm.auth = gamma.auth; editSiteForm.allowed_instances = [ "lemmy-alpha", "lemmy-beta", "lemmy-delta", "lemmy-epsilon", ]; - await gamma.client.editSite(editSiteForm); + await gamma.editSite(editSiteForm); editSiteForm.allowed_instances = ["lemmy-beta"]; - editSiteForm.auth = delta.auth; - await delta.client.editSite(editSiteForm); + await delta.editSite(editSiteForm); - editSiteForm.auth = epsilon.auth; editSiteForm.allowed_instances = []; editSiteForm.blocked_instances = ["lemmy-alpha"]; - await epsilon.client.editSite(editSiteForm); + await epsilon.editSite(editSiteForm); // Create the main alpha/beta communities // Ignore thrown errors of duplicates @@ -208,14 +182,14 @@ export async function setupLogins() { // otherwise the first few federated events may be missed // (because last_successful_id is set to current id when federation to an instance is first started) // only needed the first time so do in this try - await delay(6_000); + await delay(10_000); } catch (_) { console.log("Communities already exist"); } } export async function createPost( - api: API, + api: LemmyHttp, community_id: number, ): Promise { let name = randomString(5); @@ -227,50 +201,49 @@ export async function createPost( name, url, body, - auth: api.auth, community_id, }; - return api.client.createPost(form); + return api.createPost(form); } -export async function editPost(api: API, post: Post): Promise { +export async function editPost( + api: LemmyHttp, + post: Post, +): Promise { let name = "A jest test federated post, updated"; let form: EditPost = { name, post_id: post.id, - auth: api.auth, }; - return api.client.editPost(form); + return api.editPost(form); } export async function deletePost( - api: API, + api: LemmyHttp, deleted: boolean, post: Post, ): Promise { let form: DeletePost = { post_id: post.id, deleted: deleted, - auth: api.auth, }; - return api.client.deletePost(form); + return api.deletePost(form); } export async function removePost( - api: API, + api: LemmyHttp, removed: boolean, post: Post, ): Promise { let form: RemovePost = { post_id: post.id, removed, - auth: api.auth, }; - return api.client.removePost(form); + return api.removePost(form); } export async function featurePost( - api: API, + api: LemmyHttp, featured: boolean, post: Post, ): Promise { @@ -278,61 +251,68 @@ export async function featurePost( post_id: post.id, featured, feature_type: "Community", - auth: api.auth, }; - return api.client.featurePost(form); + return api.featurePost(form); } export async function lockPost( - api: API, + api: LemmyHttp, locked: boolean, post: Post, ): Promise { let form: LockPost = { post_id: post.id, locked, - auth: api.auth, }; - return api.client.lockPost(form); + return api.lockPost(form); } export async function resolvePost( - api: API, + api: LemmyHttp, post: Post, ): Promise { let form: ResolveObject = { q: post.ap_id, - auth: api.auth, }; - return api.client.resolveObject(form); + return api.resolveObject(form); } export async function searchPostLocal( - api: API, + api: LemmyHttp, post: Post, ): Promise { let form: Search = { q: post.name, type_: "Posts", sort: "TopAll", - auth: api.auth, }; - return api.client.search(form); + return api.search(form); +} + +/// wait for a post to appear locally without pulling it +export async function waitForPost( + api: LemmyHttp, + post: Post, + checker: (t: PostView | undefined) => boolean = p => !!p, +) { + return waitUntil( + () => searchPostLocal(api, post).then(p => p.posts[0]), + checker, + ); } export async function getPost( - api: API, + api: LemmyHttp, post_id: number, ): Promise { let form: GetPost = { id: post_id, - auth: api.auth, }; - return api.client.getPost(form); + return api.getPost(form); } export async function getComments( - api: API, + api: LemmyHttp, post_id?: number, listingType: ListingType = "All", ): Promise { @@ -340,75 +320,66 @@ export async function getComments( post_id: post_id, type_: listingType, sort: "New", - auth: api.auth, }; - return api.client.getComments(form); + return api.getComments(form); } export async function getUnreadCount( - api: API, + api: LemmyHttp, ): Promise { - let form: GetUnreadCount = { - auth: api.auth, - }; - return api.client.getUnreadCount(form); + return api.getUnreadCount(); } -export async function getReplies(api: API): Promise { +export async function getReplies(api: LemmyHttp): Promise { let form: GetReplies = { sort: "New", unread_only: false, - auth: api.auth, }; - return api.client.getReplies(form); + return api.getReplies(form); } export async function resolveComment( - api: API, + api: LemmyHttp, comment: Comment, ): Promise { let form: ResolveObject = { q: comment.ap_id, - auth: api.auth, }; - return api.client.resolveObject(form); + return api.resolveObject(form); } export async function resolveBetaCommunity( - api: API, + api: LemmyHttp, ): Promise { // Use short-hand search url let form: ResolveObject = { q: "!main@lemmy-beta:8551", - auth: api.auth, }; - return api.client.resolveObject(form); + return api.resolveObject(form); } export async function resolveCommunity( - api: API, + api: LemmyHttp, q: string, ): Promise { let form: ResolveObject = { q, - auth: api.auth, }; - return api.client.resolveObject(form); + return api.resolveObject(form); } export async function resolvePerson( - api: API, + api: LemmyHttp, apShortname: string, ): Promise { let form: ResolveObject = { q: apShortname, - auth: api.auth, }; - return api.client.resolveObject(form); + return api.resolveObject(form); } export async function banPersonFromSite( - api: API, + api: LemmyHttp, person_id: number, ban: boolean, remove_data: boolean, @@ -418,13 +389,12 @@ export async function banPersonFromSite( person_id, ban, remove_data: remove_data, - auth: api.auth, }; - return api.client.banPerson(form); + return api.banPerson(form); } export async function banPersonFromCommunity( - api: API, + api: LemmyHttp, person_id: number, community_id: number, remove_data: boolean, @@ -435,40 +405,44 @@ export async function banPersonFromCommunity( community_id, remove_data: remove_data, ban, - auth: api.auth, }; - return api.client.banFromCommunity(form); + return api.banFromCommunity(form); } export async function followCommunity( - api: API, + api: LemmyHttp, follow: boolean, community_id: number, ): Promise { let form: FollowCommunity = { community_id, follow, - auth: api.auth, }; - return api.client.followCommunity(form); + const res = await api.followCommunity(form); + await waitUntil( + () => resolveCommunity(api, res.community_view.community.actor_id), + g => g.community?.subscribed === (follow ? "Subscribed" : "NotSubscribed"), + ); + // wait FOLLOW_ADDITIONS_RECHECK_DELAY (there's no API to wait for this currently) + await delay(2000); + return res; } export async function likePost( - api: API, + api: LemmyHttp, score: number, post: Post, ): Promise { let form: CreatePostLike = { post_id: post.id, score: score, - auth: api.auth, }; - return api.client.likePost(form); + return api.likePost(form); } export async function createComment( - api: API, + api: LemmyHttp, post_id: number, parent_id?: number, content = "a jest test comment", @@ -477,76 +451,70 @@ export async function createComment( content, post_id, parent_id, - auth: api.auth, }; - return api.client.createComment(form); + return api.createComment(form); } export async function editComment( - api: API, + api: LemmyHttp, comment_id: number, content = "A jest test federated comment update", ): Promise { let form: EditComment = { content, comment_id, - auth: api.auth, }; - return api.client.editComment(form); + return api.editComment(form); } export async function deleteComment( - api: API, + api: LemmyHttp, deleted: boolean, comment_id: number, ): Promise { let form: DeleteComment = { comment_id, deleted, - auth: api.auth, }; - return api.client.deleteComment(form); + return api.deleteComment(form); } export async function removeComment( - api: API, + api: LemmyHttp, removed: boolean, comment_id: number, ): Promise { let form: RemoveComment = { comment_id, removed, - auth: api.auth, }; - return api.client.removeComment(form); + return api.removeComment(form); } export async function getMentions( - api: API, + api: LemmyHttp, ): Promise { let form: GetPersonMentions = { sort: "New", unread_only: false, - auth: api.auth, }; - return api.client.getPersonMentions(form); + return api.getPersonMentions(form); } export async function likeComment( - api: API, + api: LemmyHttp, score: number, comment: Comment, ): Promise { let form: CreateCommentLike = { comment_id: comment.id, score, - auth: api.auth, }; - return api.client.likeComment(form); + return api.likeComment(form); } export async function createCommunity( - api: API, + api: LemmyHttp, name_: string = randomString(5), ): Promise { let description = "a sample description"; @@ -554,100 +522,92 @@ export async function createCommunity( name: name_, title: name_, description, - auth: api.auth, }; - return api.client.createCommunity(form); + return api.createCommunity(form); } export async function getCommunity( - api: API, + api: LemmyHttp, id: number, ): Promise { let form: GetCommunity = { id, - auth: api.auth, }; - return api.client.getCommunity(form); + return api.getCommunity(form); } export async function getCommunityByName( - api: API, + api: LemmyHttp, name: string, ): Promise { let form: GetCommunity = { name, - auth: api.auth, }; - return api.client.getCommunity(form); + return api.getCommunity(form); } export async function deleteCommunity( - api: API, + api: LemmyHttp, deleted: boolean, community_id: number, ): Promise { let form: DeleteCommunity = { community_id, deleted, - auth: api.auth, }; - return api.client.deleteCommunity(form); + return api.deleteCommunity(form); } export async function removeCommunity( - api: API, + api: LemmyHttp, removed: boolean, community_id: number, ): Promise { let form: RemoveCommunity = { community_id, removed, - auth: api.auth, }; - return api.client.removeCommunity(form); + return api.removeCommunity(form); } export async function createPrivateMessage( - api: API, + api: LemmyHttp, recipient_id: number, ): Promise { let content = "A jest test federated private message"; let form: CreatePrivateMessage = { content, recipient_id, - auth: api.auth, }; - return api.client.createPrivateMessage(form); + return api.createPrivateMessage(form); } export async function editPrivateMessage( - api: API, + api: LemmyHttp, private_message_id: number, ): Promise { let updatedContent = "A jest test federated private message edited"; let form: EditPrivateMessage = { content: updatedContent, private_message_id, - auth: api.auth, }; - return api.client.editPrivateMessage(form); + return api.editPrivateMessage(form); } export async function deletePrivateMessage( - api: API, + api: LemmyHttp, deleted: boolean, private_message_id: number, ): Promise { let form: DeletePrivateMessage = { deleted, private_message_id, - auth: api.auth, }; - return api.client.deletePrivateMessage(form); + return api.deletePrivateMessage(form); } export async function registerUser( - api: API, + api: LemmyHttp, username: string = randomString(5), ): Promise { let form: Register = { @@ -656,10 +616,12 @@ export async function registerUser( password_verify: password, show_nsfw: true, }; - return api.client.register(form); + return api.register(form); } -export async function saveUserSettingsBio(api: API): Promise { +export async function saveUserSettingsBio( + api: LemmyHttp, +): Promise { let form: SaveUserSettings = { show_nsfw: true, blur_nsfw: false, @@ -671,13 +633,12 @@ export async function saveUserSettingsBio(api: API): Promise { show_avatars: true, send_notifications_to_email: false, bio: "a changed bio", - auth: api.auth, }; return saveUserSettings(api, form); } export async function saveUserSettingsFederated( - api: API, + api: LemmyHttp, ): Promise { let avatar = "https://image.flaticon.com/icons/png/512/35/35896.png"; let banner = "https://image.flaticon.com/icons/png/512/36/35896.png"; @@ -695,67 +656,64 @@ export async function saveUserSettingsFederated( show_avatars: false, send_notifications_to_email: false, bio, - auth: api.auth, }; - return await saveUserSettings(alpha, form); + return await saveUserSettings(api, form); } export async function saveUserSettings( - api: API, + api: LemmyHttp, form: SaveUserSettings, ): Promise { - return api.client.saveUserSettings(form); + return api.saveUserSettings(form); } export async function getPersonDetails( - api: API, + api: LemmyHttp, person_id: number, ): Promise { let form: GetPersonDetails = { - auth: api.auth, person_id: person_id, }; - return api.client.getPersonDetails(form); + return api.getPersonDetails(form); } -export async function deleteUser(api: API): Promise { +export async function deleteUser( + api: LemmyHttp, +): Promise { let form: DeleteAccount = { - auth: api.auth, delete_content: true, password, }; - return api.client.deleteAccount(form); + return api.deleteAccount(form); } -export async function getSite(api: API): Promise { - let form: GetSite = { - auth: api.auth, - }; - return api.client.getSite(form); +export async function getSite(api: LemmyHttp): Promise { + return api.getSite(); } export async function listPrivateMessages( - api: API, + api: LemmyHttp, ): Promise { let form: GetPrivateMessages = { - auth: api.auth, unread_only: false, }; - return api.client.getPrivateMessages(form); + return api.getPrivateMessages(form); } -export async function unfollowRemotes(api: API): Promise { +export async function unfollowRemotes( + api: LemmyHttp, +): Promise { // Unfollow all remote communities let site = await getSite(api); let remoteFollowed = site.my_user?.follows.filter(c => c.community.local == false) ?? []; - for (let cu of remoteFollowed) { - await followCommunity(api, false, cu.community.id); - } + await Promise.all( + remoteFollowed.map(cu => followCommunity(api, false, cu.community.id)), + ); let siteRes = await getSite(api); return siteRes; } -export async function followBeta(api: API): Promise { +export async function followBeta(api: LemmyHttp): Promise { let betaCommunity = (await resolveBetaCommunity(api)).community; if (betaCommunity) { let follow = await followCommunity(api, true, betaCommunity.community.id); @@ -766,71 +724,63 @@ export async function followBeta(api: API): Promise { } export async function reportPost( - api: API, + api: LemmyHttp, post_id: number, reason: string, ): Promise { let form: CreatePostReport = { post_id, reason, - auth: api.auth, }; - return api.client.createPostReport(form); + return api.createPostReport(form); } export async function listPostReports( - api: API, + api: LemmyHttp, ): Promise { - let form: ListPostReports = { - auth: api.auth, - }; - return api.client.listPostReports(form); + let form: ListPostReports = {}; + return api.listPostReports(form); } export async function reportComment( - api: API, + api: LemmyHttp, comment_id: number, reason: string, ): Promise { let form: CreateCommentReport = { comment_id, reason, - auth: api.auth, }; - return api.client.createCommentReport(form); + return api.createCommentReport(form); } export async function listCommentReports( - api: API, + api: LemmyHttp, ): Promise { - let form: ListCommentReports = { - auth: api.auth, - }; - return api.client.listCommentReports(form); + let form: ListCommentReports = {}; + return api.listCommentReports(form); } export function getPosts( - api: API, + api: LemmyHttp, listingType?: ListingType, ): Promise { let form: GetPosts = { - auth: api.auth, type_: listingType, }; - return api.client.getPosts(form); + return api.getPosts(form); } export function blockInstance( - api: API, + api: LemmyHttp, instance_id: InstanceId, block: boolean, ): Promise { let form: BlockInstance = { instance_id, block, - auth: api.auth, }; - return api.client.blockInstance(form); + return api.blockInstance(form); } export function delay(millis = 500) { @@ -857,10 +807,12 @@ export function randomString(length: number): string { } export async function unfollows() { - await unfollowRemotes(alpha); - await unfollowRemotes(gamma); - await unfollowRemotes(delta); - await unfollowRemotes(epsilon); + await Promise.all([ + unfollowRemotes(alpha), + unfollowRemotes(gamma), + unfollowRemotes(delta), + unfollowRemotes(epsilon), + ]); } export function getCommentParentId(comment: Comment): number | undefined { @@ -879,14 +831,18 @@ export async function waitUntil( fetcher: () => Promise, checker: (t: T) => boolean, retries = 10, - delaySeconds = 2, + delaySeconds = [0.2, 0.5, 1, 2, 3], ) { let retry = 0; + let result; while (retry++ < retries) { - const result = await fetcher(); + result = await fetcher(); if (checker(result)) return result; - await delay(delaySeconds * 1000); + await delay( + delaySeconds[Math.min(retry - 1, delaySeconds.length - 1)] * 1000, + ); } + console.error("result", result); throw Error( `Failed "${fetcher}": "${checker}" did not return true after ${retries} retries (delayed ${delaySeconds}s each)`, ); diff --git a/api_tests/src/user.spec.ts b/api_tests/src/user.spec.ts index f488ebe1e..e679e8053 100644 --- a/api_tests/src/user.spec.ts +++ b/api_tests/src/user.spec.ts @@ -13,10 +13,10 @@ import { resolveBetaCommunity, deleteUser, resolvePost, - API, resolveComment, saveUserSettingsFederated, setupLogins, + alphaUrl, } from "./shared"; import { LemmyHttp } from "lemmy-js-client"; import { GetPosts } from "lemmy-js-client/dist/types/GetPosts"; @@ -40,9 +40,11 @@ function assertUserFederation(userOne?: PersonView, userTwo?: PersonView) { test("Create user", async () => { let userRes = await registerUser(alpha); expect(userRes.jwt).toBeDefined(); - alpha.auth = userRes.jwt ?? ""; + let user = new LemmyHttp(alphaUrl, { + headers: { auth: userRes.jwt ?? "" }, + }); - let site = await getSite(alpha); + let site = await getSite(user); expect(site.my_user).toBeDefined(); if (!site.my_user) { throw "Missing site user"; @@ -60,10 +62,9 @@ test("Set some user settings, check that they are federated", async () => { test("Delete user", async () => { let userRes = await registerUser(alpha); expect(userRes.jwt).toBeDefined(); - let user: API = { - client: alpha.client, - auth: userRes.jwt ?? "", - }; + let user = new LemmyHttp(alphaUrl, { + headers: { auth: userRes.jwt ?? "" }, + }); // make a local post and comment let alphaCommunity = (await resolveCommunity(user, "!main@lemmy-alpha:8541")) @@ -107,17 +108,14 @@ test("Delete user", async () => { }); test("Requests with invalid auth should be treated as unauthenticated", async () => { - let invalid_auth: API = { - client: new LemmyHttp("http://127.0.0.1:8541"), - auth: "invalid", - }; + let invalid_auth = new LemmyHttp(alphaUrl, { + headers: { auth: "" }, + }); let site = await getSite(invalid_auth); expect(site.my_user).toBeUndefined(); expect(site.site_view).toBeDefined(); - let form: GetPosts = { - auth: "invalid", - }; - let posts = invalid_auth.client.getPosts(form); + let form: GetPosts = {}; + let posts = invalid_auth.getPosts(form); expect((await posts).posts).toBeDefined(); }); diff --git a/api_tests/yarn.lock b/api_tests/yarn.lock index 3b6a85146..eb9859b8d 100644 --- a/api_tests/yarn.lock +++ b/api_tests/yarn.lock @@ -2174,10 +2174,10 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -lemmy-js-client@0.19.0-rc.5: - version "0.19.0-rc.5" - resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.19.0-rc.5.tgz#a0d3e0ac829b1e46124edcf3a0343ae04317d51a" - integrity sha512-Z1T95Ht1VZNvWlLH9XpVnO2oC7LhMT81jTiU5BhYPIkEtGhOwN91jk5uI1oyI6/d4v9lwbrsyzFYPsiuMmXTFQ== +lemmy-js-client@0.19.0-rc.12: + version "0.19.0-rc.12" + resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.19.0-rc.12.tgz#e3bd4e21b1966d583ab790ef70ece8394b012b48" + integrity sha512-1iu2fW9vlb3TrI+QR/ODP3+5pWZB0rUqL1wH09IzomDXohCqoQvfmXpwArmgF4Eq8GZgjkcfeMDC2gMrfw/i7Q== dependencies: cross-fetch "^3.1.5" form-data "^4.0.0" diff --git a/crates/api/src/comment/distinguish.rs b/crates/api/src/comment/distinguish.rs index a378e51b9..5059e2db7 100644 --- a/crates/api/src/comment/distinguish.rs +++ b/crates/api/src/comment/distinguish.rs @@ -2,22 +2,21 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ comment::{CommentResponse, DistinguishComment}, context::LemmyContext, - utils::{check_community_ban, is_mod_or_admin, local_user_view_from_jwt}, + utils::{check_community_ban, is_mod_or_admin}, }; use lemmy_db_schema::{ source::comment::{Comment, CommentUpdateForm}, traits::Crud, }; -use lemmy_db_views::structs::CommentView; +use lemmy_db_views::structs::{CommentView, LocalUserView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn distinguish_comment( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let orig_comment = CommentView::read(&mut context.pool(), data.comment_id, None).await?; check_community_ban( diff --git a/crates/api/src/comment/like.rs b/crates/api/src/comment/like.rs index af013f283..ee0a0bd7e 100644 --- a/crates/api/src/comment/like.rs +++ b/crates/api/src/comment/like.rs @@ -5,7 +5,7 @@ use lemmy_api_common::{ comment::{CommentResponse, CreateCommentLike}, context::LemmyContext, send_activity::{ActivityChannel, SendActivityData}, - utils::{check_community_ban, check_downvotes_enabled, local_user_view_from_jwt}, + utils::{check_community_ban, check_downvotes_enabled}, }; use lemmy_db_schema::{ newtypes::LocalUserId, @@ -24,9 +24,9 @@ use std::ops::Deref; pub async fn like_comment( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { let local_site = LocalSite::read(&mut context.pool()).await?; - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let mut recipient_ids = Vec::::new(); diff --git a/crates/api/src/comment/save.rs b/crates/api/src/comment/save.rs index f2c926f17..95c08e701 100644 --- a/crates/api/src/comment/save.rs +++ b/crates/api/src/comment/save.rs @@ -2,22 +2,20 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ comment::{CommentResponse, SaveComment}, context::LemmyContext, - utils::local_user_view_from_jwt, }; use lemmy_db_schema::{ source::comment::{CommentSaved, CommentSavedForm}, traits::Saveable, }; -use lemmy_db_views::structs::CommentView; +use lemmy_db_views::structs::{CommentView, LocalUserView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn save_comment( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let comment_saved_form = CommentSavedForm { comment_id: data.comment_id, person_id: local_user_view.person.id, diff --git a/crates/api/src/comment_report/create.rs b/crates/api/src/comment_report/create.rs index e493d60a3..3c1304674 100644 --- a/crates/api/src/comment_report/create.rs +++ b/crates/api/src/comment_report/create.rs @@ -5,12 +5,7 @@ use lemmy_api_common::{ comment::{CommentReportResponse, CreateCommentReport}, context::LemmyContext, send_activity::{ActivityChannel, SendActivityData}, - utils::{ - check_community_ban, - local_user_view_from_jwt, - sanitize_html_api, - send_new_report_email_to_admins, - }, + utils::{check_community_ban, sanitize_html_api, send_new_report_email_to_admins}, }; use lemmy_db_schema::{ source::{ @@ -19,7 +14,7 @@ use lemmy_db_schema::{ }, traits::Reportable, }; -use lemmy_db_views::structs::{CommentReportView, CommentView}; +use lemmy_db_views::structs::{CommentReportView, CommentView, LocalUserView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; /// Creates a comment report and notifies the moderators of the community @@ -27,8 +22,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; pub async fn create_comment_report( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let local_site = LocalSite::read(&mut context.pool()).await?; let reason = sanitize_html_api(data.reason.trim()); diff --git a/crates/api/src/comment_report/list.rs b/crates/api/src/comment_report/list.rs index 839288521..bc8dd2677 100644 --- a/crates/api/src/comment_report/list.rs +++ b/crates/api/src/comment_report/list.rs @@ -2,9 +2,8 @@ use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ comment::{ListCommentReports, ListCommentReportsResponse}, context::LemmyContext, - utils::local_user_view_from_jwt, }; -use lemmy_db_views::comment_report_view::CommentReportQuery; +use lemmy_db_views::{comment_report_view::CommentReportQuery, structs::LocalUserView}; use lemmy_utils::error::LemmyError; /// Lists comment reports for a community if an id is supplied @@ -13,9 +12,8 @@ use lemmy_utils::error::LemmyError; pub async fn list_comment_reports( data: Query, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let community_id = data.community_id; let unresolved_only = data.unresolved_only.unwrap_or_default(); diff --git a/crates/api/src/comment_report/resolve.rs b/crates/api/src/comment_report/resolve.rs index 8e03484e8..8296f068b 100644 --- a/crates/api/src/comment_report/resolve.rs +++ b/crates/api/src/comment_report/resolve.rs @@ -2,10 +2,10 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ comment::{CommentReportResponse, ResolveCommentReport}, context::LemmyContext, - utils::{is_mod_or_admin, local_user_view_from_jwt}, + utils::is_mod_or_admin, }; use lemmy_db_schema::{source::comment_report::CommentReport, traits::Reportable}; -use lemmy_db_views::structs::CommentReportView; +use lemmy_db_views::structs::{CommentReportView, LocalUserView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; /// Resolves or unresolves a comment report and notifies the moderators of the community @@ -13,9 +13,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; pub async fn resolve_comment_report( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let report_id = data.report_id; let person_id = local_user_view.person.id; let report = CommentReportView::read(&mut context.pool(), report_id, person_id).await?; diff --git a/crates/api/src/community/add_mod.rs b/crates/api/src/community/add_mod.rs index f5fac1503..e08686361 100644 --- a/crates/api/src/community/add_mod.rs +++ b/crates/api/src/community/add_mod.rs @@ -4,7 +4,7 @@ use lemmy_api_common::{ community::{AddModToCommunity, AddModToCommunityResponse}, context::LemmyContext, send_activity::{ActivityChannel, SendActivityData}, - utils::{is_mod_or_admin, local_user_view_from_jwt}, + utils::is_mod_or_admin, }; use lemmy_db_schema::{ source::{ @@ -13,6 +13,7 @@ use lemmy_db_schema::{ }, traits::{Crud, Joinable}, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::CommunityModeratorView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; @@ -20,9 +21,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; pub async fn add_mod_to_community( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let community_id = data.community_id; // Verify that only mods or admins can add mod diff --git a/crates/api/src/community/ban.rs b/crates/api/src/community/ban.rs index e969e9b78..c2f70b7c0 100644 --- a/crates/api/src/community/ban.rs +++ b/crates/api/src/community/ban.rs @@ -4,12 +4,7 @@ use lemmy_api_common::{ community::{BanFromCommunity, BanFromCommunityResponse}, context::LemmyContext, send_activity::{ActivityChannel, SendActivityData}, - utils::{ - is_mod_or_admin, - local_user_view_from_jwt, - remove_user_data_in_community, - sanitize_html_api_opt, - }, + utils::{is_mod_or_admin, remove_user_data_in_community, sanitize_html_api_opt}, }; use lemmy_db_schema::{ source::{ @@ -23,6 +18,7 @@ use lemmy_db_schema::{ }, traits::{Bannable, Crud, Followable}, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::PersonView; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, @@ -33,9 +29,8 @@ use lemmy_utils::{ pub async fn ban_from_community( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let banned_person_id = data.person_id; let remove_data = data.remove_data.unwrap_or(false); let expires = data.expires.map(naive_from_unix); diff --git a/crates/api/src/community/block.rs b/crates/api/src/community/block.rs index f27b7c01b..fd4a5a01b 100644 --- a/crates/api/src/community/block.rs +++ b/crates/api/src/community/block.rs @@ -4,7 +4,6 @@ use lemmy_api_common::{ community::{BlockCommunity, BlockCommunityResponse}, context::LemmyContext, send_activity::{ActivityChannel, SendActivityData}, - utils::local_user_view_from_jwt, }; use lemmy_db_schema::{ source::{ @@ -13,6 +12,7 @@ use lemmy_db_schema::{ }, traits::{Blockable, Followable}, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::CommunityView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; @@ -20,9 +20,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; pub async fn block_community( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let community_id = data.community_id; let person_id = local_user_view.person.id; let community_block_form = CommunityBlockForm { diff --git a/crates/api/src/community/follow.rs b/crates/api/src/community/follow.rs index 2a50a94ed..91ffce714 100644 --- a/crates/api/src/community/follow.rs +++ b/crates/api/src/community/follow.rs @@ -4,7 +4,7 @@ use lemmy_api_common::{ community::{CommunityResponse, FollowCommunity}, context::LemmyContext, send_activity::{ActivityChannel, SendActivityData}, - utils::{check_community_ban, check_community_deleted_or_removed, local_user_view_from_jwt}, + utils::{check_community_ban, check_community_deleted_or_removed}, }; use lemmy_db_schema::{ source::{ @@ -13,6 +13,7 @@ use lemmy_db_schema::{ }, traits::{Crud, Followable}, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::CommunityView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; @@ -20,9 +21,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; pub async fn follow_community( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let community = Community::read(&mut context.pool(), data.community_id).await?; let mut community_follower_form = CommunityFollowerForm { community_id: community.id, diff --git a/crates/api/src/community/hide.rs b/crates/api/src/community/hide.rs index 8fd270181..5f2b9d6fb 100644 --- a/crates/api/src/community/hide.rs +++ b/crates/api/src/community/hide.rs @@ -5,7 +5,7 @@ use lemmy_api_common::{ community::{CommunityResponse, HideCommunity}, context::LemmyContext, send_activity::{ActivityChannel, SendActivityData}, - utils::{is_admin, local_user_view_from_jwt, sanitize_html_api_opt}, + utils::{is_admin, sanitize_html_api_opt}, }; use lemmy_db_schema::{ source::{ @@ -14,15 +14,16 @@ use lemmy_db_schema::{ }, traits::Crud, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn hide_community( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { // Verify its a admin (only admin can hide or unhide it) - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; is_admin(&local_user_view)?; let community_form = CommunityUpdateForm { diff --git a/crates/api/src/community/transfer.rs b/crates/api/src/community/transfer.rs index 1dc5a96e0..fd2e293f8 100644 --- a/crates/api/src/community/transfer.rs +++ b/crates/api/src/community/transfer.rs @@ -3,7 +3,7 @@ use anyhow::Context; use lemmy_api_common::{ community::{GetCommunityResponse, TransferCommunity}, context::LemmyContext, - utils::{is_admin, is_top_mod, local_user_view_from_jwt}, + utils::{is_admin, is_top_mod}, }; use lemmy_db_schema::{ source::{ @@ -12,6 +12,7 @@ use lemmy_db_schema::{ }, traits::{Crud, Joinable}, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView}; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, @@ -24,9 +25,8 @@ use lemmy_utils::{ pub async fn transfer_community( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - // Fetch the community mods let community_id = data.community_id; let mut community_mods = diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index 22a021970..04df09308 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -126,68 +126,6 @@ mod tests { #![allow(clippy::indexing_slicing)] use super::*; - use lemmy_api_common::utils::check_validator_time; - use lemmy_db_schema::{ - source::{ - instance::Instance, - local_user::{LocalUser, LocalUserInsertForm}, - person::{Person, PersonInsertForm}, - secret::Secret, - }, - traits::Crud, - utils::build_db_pool_for_tests, - }; - use lemmy_utils::{claims::Claims, settings::SETTINGS}; - use serial_test::serial; - - #[tokio::test] - #[serial] - async fn test_should_not_validate_user_token_after_password_change() { - let pool = &build_db_pool_for_tests().await; - let pool = &mut pool.into(); - let secret = Secret::init(pool).await.unwrap(); - let settings = &SETTINGS.to_owned(); - - let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()) - .await - .unwrap(); - - let new_person = PersonInsertForm::builder() - .name("Gerry9812".into()) - .public_key("pubkey".to_string()) - .instance_id(inserted_instance.id) - .build(); - - let inserted_person = Person::create(pool, &new_person).await.unwrap(); - - let local_user_form = LocalUserInsertForm::builder() - .person_id(inserted_person.id) - .password_encrypted("123456".to_string()) - .build(); - - let inserted_local_user = LocalUser::create(pool, &local_user_form).await.unwrap(); - - let jwt = Claims::jwt( - inserted_local_user.id.0, - &secret.jwt_secret, - &settings.hostname, - ) - .unwrap(); - let claims = Claims::decode(&jwt, &secret.jwt_secret).unwrap().claims; - let check = check_validator_time(&inserted_local_user.validator_time, &claims); - assert!(check.is_ok()); - - // The check should fail, since the validator time is now newer than the jwt issue time - let updated_local_user = - LocalUser::update_password(pool, inserted_local_user.id, "password111") - .await - .unwrap(); - let check_after = check_validator_time(&updated_local_user.validator_time, &claims); - assert!(check_after.is_err()); - - let num_deleted = Person::delete(pool, inserted_person.id).await.unwrap(); - assert_eq!(1, num_deleted); - } #[test] fn test_build_totp() { diff --git a/crates/api/src/local_user/add_admin.rs b/crates/api/src/local_user/add_admin.rs index 8e50147a4..502335876 100644 --- a/crates/api/src/local_user/add_admin.rs +++ b/crates/api/src/local_user/add_admin.rs @@ -2,7 +2,7 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, person::{AddAdmin, AddAdminResponse}, - utils::{is_admin, local_user_view_from_jwt}, + utils::is_admin, }; use lemmy_db_schema::{ source::{ @@ -19,9 +19,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; pub async fn add_admin( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - // Make sure user is an admin is_admin(&local_user_view)?; diff --git a/crates/api/src/local_user/ban_person.rs b/crates/api/src/local_user/ban_person.rs index 3a83d6c6e..ecc09220d 100644 --- a/crates/api/src/local_user/ban_person.rs +++ b/crates/api/src/local_user/ban_person.rs @@ -4,7 +4,7 @@ use lemmy_api_common::{ context::LemmyContext, person::{BanPerson, BanPersonResponse}, send_activity::{ActivityChannel, SendActivityData}, - utils::{is_admin, local_user_view_from_jwt, remove_user_data, sanitize_html_api_opt}, + utils::{is_admin, remove_user_data, sanitize_html_api_opt}, }; use lemmy_db_schema::{ source::{ @@ -13,6 +13,7 @@ use lemmy_db_schema::{ }, traits::Crud, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::PersonView; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, @@ -22,9 +23,8 @@ use lemmy_utils::{ pub async fn ban_from_site( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - // Make sure user is an admin is_admin(&local_user_view)?; diff --git a/crates/api/src/local_user/block.rs b/crates/api/src/local_user/block.rs index 77a23aef3..cb345616b 100644 --- a/crates/api/src/local_user/block.rs +++ b/crates/api/src/local_user/block.rs @@ -2,7 +2,6 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, person::{BlockPerson, BlockPersonResponse}, - utils::local_user_view_from_jwt, }; use lemmy_db_schema::{ source::person_block::{PersonBlock, PersonBlockForm}, @@ -16,9 +15,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; pub async fn block_person( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let target_id = data.person_id; let person_id = local_user_view.person.id; diff --git a/crates/api/src/local_user/change_password.rs b/crates/api/src/local_user/change_password.rs index 532c8ed7c..9b491d821 100644 --- a/crates/api/src/local_user/change_password.rs +++ b/crates/api/src/local_user/change_password.rs @@ -3,9 +3,10 @@ use bcrypt::verify; use lemmy_api_common::{ context::LemmyContext, person::{ChangePassword, LoginResponse}, - utils::{local_user_view_from_jwt, password_length_check}, + utils::password_length_check, }; use lemmy_db_schema::source::local_user::LocalUser; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::{ claims::Claims, error::{LemmyError, LemmyErrorType}, @@ -15,9 +16,8 @@ use lemmy_utils::{ pub async fn change_password( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(data.auth.as_ref(), &context).await?; - password_length_check(&data.new_password)?; // Make sure passwords match diff --git a/crates/api/src/local_user/list_banned.rs b/crates/api/src/local_user/list_banned.rs index c4c0a98ae..5c76d89a8 100644 --- a/crates/api/src/local_user/list_banned.rs +++ b/crates/api/src/local_user/list_banned.rs @@ -1,18 +1,13 @@ -use actix_web::web::{Data, Json, Query}; -use lemmy_api_common::{ - context::LemmyContext, - person::{BannedPersonsResponse, GetBannedPersons}, - utils::{is_admin, local_user_view_from_jwt}, -}; +use actix_web::web::{Data, Json}; +use lemmy_api_common::{context::LemmyContext, person::BannedPersonsResponse, utils::is_admin}; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::PersonView; use lemmy_utils::error::LemmyError; pub async fn list_banned_users( - data: Query, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - // Make sure user is an admin is_admin(&local_user_view)?; diff --git a/crates/api/src/local_user/login.rs b/crates/api/src/local_user/login.rs index 5dd3e29d8..11a5c6b01 100644 --- a/crates/api/src/local_user/login.rs +++ b/crates/api/src/local_user/login.rs @@ -4,7 +4,13 @@ use bcrypt::verify; use lemmy_api_common::{ context::LemmyContext, person::{Login, LoginResponse}, - utils::{check_registration_application, check_user_valid}, + utils, + utils::check_user_valid, +}; +use lemmy_db_schema::{ + source::{local_site::LocalSite, registration_application::RegistrationApplication}, + utils::DbPool, + RegistrationMode, }; use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_utils::{ @@ -72,3 +78,29 @@ pub async fn login( registration_created: false, })) } + +async fn check_registration_application( + local_user_view: &LocalUserView, + local_site: &LocalSite, + pool: &mut DbPool<'_>, +) -> Result<(), LemmyError> { + if (local_site.registration_mode == RegistrationMode::RequireApplication + || local_site.registration_mode == RegistrationMode::Closed) + && !local_user_view.local_user.accepted_application + && !local_user_view.local_user.admin + { + // Fetch the registration, see if its denied + let local_user_id = local_user_view.local_user.id; + let registration = RegistrationApplication::find_by_local_user_id(pool, local_user_id).await?; + if let Some(deny_reason) = registration.deny_reason { + let lang = utils::get_interface_language(local_user_view); + let registration_denied_message = format!("{}: {}", lang.registration_denied(), deny_reason); + Err(LemmyErrorType::RegistrationDenied( + registration_denied_message, + ))? + } else { + Err(LemmyErrorType::RegistrationApplicationIsPending)? + } + } + Ok(()) +} diff --git a/crates/api/src/local_user/notifications/list_mentions.rs b/crates/api/src/local_user/notifications/list_mentions.rs index af32e31a8..9f9ee3ae8 100644 --- a/crates/api/src/local_user/notifications/list_mentions.rs +++ b/crates/api/src/local_user/notifications/list_mentions.rs @@ -2,8 +2,8 @@ use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, person::{GetPersonMentions, GetPersonMentionsResponse}, - utils::local_user_view_from_jwt, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::person_mention_view::PersonMentionQuery; use lemmy_utils::error::LemmyError; @@ -11,9 +11,8 @@ use lemmy_utils::error::LemmyError; pub async fn list_mentions( data: Query, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let sort = data.sort; let page = data.page; let limit = data.limit; diff --git a/crates/api/src/local_user/notifications/list_replies.rs b/crates/api/src/local_user/notifications/list_replies.rs index 8a7658d72..555989721 100644 --- a/crates/api/src/local_user/notifications/list_replies.rs +++ b/crates/api/src/local_user/notifications/list_replies.rs @@ -2,8 +2,8 @@ use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, person::{GetReplies, GetRepliesResponse}, - utils::local_user_view_from_jwt, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::comment_reply_view::CommentReplyQuery; use lemmy_utils::error::LemmyError; @@ -11,9 +11,8 @@ use lemmy_utils::error::LemmyError; pub async fn list_replies( data: Query, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let sort = data.sort; let page = data.page; let limit = data.limit; diff --git a/crates/api/src/local_user/notifications/mark_all_read.rs b/crates/api/src/local_user/notifications/mark_all_read.rs index a38b23c53..d3667460b 100644 --- a/crates/api/src/local_user/notifications/mark_all_read.rs +++ b/crates/api/src/local_user/notifications/mark_all_read.rs @@ -1,22 +1,18 @@ use actix_web::web::{Data, Json}; -use lemmy_api_common::{ - context::LemmyContext, - person::{GetRepliesResponse, MarkAllAsRead}, - utils::local_user_view_from_jwt, -}; +use lemmy_api_common::{context::LemmyContext, person::GetRepliesResponse}; use lemmy_db_schema::source::{ comment_reply::CommentReply, person_mention::PersonMention, private_message::PrivateMessage, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn mark_all_notifications_read( - data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let person_id = local_user_view.person.id; // Mark all comment_replies as read diff --git a/crates/api/src/local_user/notifications/mark_mention_read.rs b/crates/api/src/local_user/notifications/mark_mention_read.rs index f4529015d..4cce598ac 100644 --- a/crates/api/src/local_user/notifications/mark_mention_read.rs +++ b/crates/api/src/local_user/notifications/mark_mention_read.rs @@ -2,12 +2,12 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, person::{MarkPersonMentionAsRead, PersonMentionResponse}, - utils::local_user_view_from_jwt, }; use lemmy_db_schema::{ source::person_mention::{PersonMention, PersonMentionUpdateForm}, traits::Crud, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::PersonMentionView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; @@ -15,9 +15,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; pub async fn mark_person_mention_as_read( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let person_mention_id = data.person_mention_id; let read_person_mention = PersonMention::read(&mut context.pool(), person_mention_id).await?; diff --git a/crates/api/src/local_user/notifications/mark_reply_read.rs b/crates/api/src/local_user/notifications/mark_reply_read.rs index 4439a6cfb..f7b259c94 100644 --- a/crates/api/src/local_user/notifications/mark_reply_read.rs +++ b/crates/api/src/local_user/notifications/mark_reply_read.rs @@ -2,12 +2,12 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, person::{CommentReplyResponse, MarkCommentReplyAsRead}, - utils::local_user_view_from_jwt, }; use lemmy_db_schema::{ source::comment_reply::{CommentReply, CommentReplyUpdateForm}, traits::Crud, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::CommentReplyView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; @@ -15,9 +15,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; pub async fn mark_reply_as_read( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let comment_reply_id = data.comment_reply_id; let read_comment_reply = CommentReply::read(&mut context.pool(), comment_reply_id).await?; diff --git a/crates/api/src/local_user/notifications/unread_count.rs b/crates/api/src/local_user/notifications/unread_count.rs index 0315609dd..c0b1f0f2e 100644 --- a/crates/api/src/local_user/notifications/unread_count.rs +++ b/crates/api/src/local_user/notifications/unread_count.rs @@ -1,20 +1,14 @@ -use actix_web::web::{Data, Json, Query}; -use lemmy_api_common::{ - context::LemmyContext, - person::{GetUnreadCount, GetUnreadCountResponse}, - utils::local_user_view_from_jwt, -}; -use lemmy_db_views::structs::PrivateMessageView; +use actix_web::web::{Data, Json}; +use lemmy_api_common::{context::LemmyContext, person::GetUnreadCountResponse}; +use lemmy_db_views::structs::{LocalUserView, PrivateMessageView}; use lemmy_db_views_actor::structs::{CommentReplyView, PersonMentionView}; use lemmy_utils::error::LemmyError; #[tracing::instrument(skip(context))] pub async fn unread_count( - data: Query, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let person_id = local_user_view.person.id; let replies = CommentReplyView::get_unread_replies(&mut context.pool(), person_id).await?; diff --git a/crates/api/src/local_user/report_count.rs b/crates/api/src/local_user/report_count.rs index 08be9c948..3bfa1559b 100644 --- a/crates/api/src/local_user/report_count.rs +++ b/crates/api/src/local_user/report_count.rs @@ -2,18 +2,21 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, person::{GetReportCount, GetReportCountResponse}, - utils::local_user_view_from_jwt, }; -use lemmy_db_views::structs::{CommentReportView, PostReportView, PrivateMessageReportView}; +use lemmy_db_views::structs::{ + CommentReportView, + LocalUserView, + PostReportView, + PrivateMessageReportView, +}; use lemmy_utils::error::LemmyError; #[tracing::instrument(skip(context))] pub async fn report_count( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let person_id = local_user_view.person.id; let admin = local_user_view.local_user.admin; let community_id = data.community_id; diff --git a/crates/api/src/local_user/save_settings.rs b/crates/api/src/local_user/save_settings.rs index 045a3c2f7..7d3b675f6 100644 --- a/crates/api/src/local_user/save_settings.rs +++ b/crates/api/src/local_user/save_settings.rs @@ -2,7 +2,7 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, person::{LoginResponse, SaveUserSettings}, - utils::{local_user_view_from_jwt, sanitize_html_api_opt, send_verification_email}, + utils::{sanitize_html_api_opt, send_verification_email}, }; use lemmy_db_schema::{ source::{ @@ -13,7 +13,7 @@ use lemmy_db_schema::{ traits::Crud, utils::{diesel_option_overwrite, diesel_option_overwrite_to_url}, }; -use lemmy_db_views::structs::SiteView; +use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_utils::{ claims::Claims, error::{LemmyError, LemmyErrorExt, LemmyErrorType}, @@ -24,8 +24,8 @@ use lemmy_utils::{ pub async fn save_user_settings( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let site_view = SiteView::read_local(&mut context.pool()).await?; let bio = sanitize_html_api_opt(&data.bio); diff --git a/crates/api/src/post/feature.rs b/crates/api/src/post/feature.rs index 02b9551a9..8c2d2fced 100644 --- a/crates/api/src/post/feature.rs +++ b/crates/api/src/post/feature.rs @@ -5,13 +5,7 @@ use lemmy_api_common::{ context::LemmyContext, post::{FeaturePost, PostResponse}, send_activity::{ActivityChannel, SendActivityData}, - utils::{ - check_community_ban, - check_community_deleted_or_removed, - is_admin, - is_mod_or_admin, - local_user_view_from_jwt, - }, + utils::{check_community_ban, check_community_deleted_or_removed, is_admin, is_mod_or_admin}, }; use lemmy_db_schema::{ source::{ @@ -21,15 +15,15 @@ use lemmy_db_schema::{ traits::Crud, PostFeatureType, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::error::LemmyError; #[tracing::instrument(skip(context))] pub async fn feature_post( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let post_id = data.post_id; let orig_post = Post::read(&mut context.pool(), post_id).await?; diff --git a/crates/api/src/post/like.rs b/crates/api/src/post/like.rs index b9b2bede0..d4f9d644d 100644 --- a/crates/api/src/post/like.rs +++ b/crates/api/src/post/like.rs @@ -9,7 +9,6 @@ use lemmy_api_common::{ check_community_ban, check_community_deleted_or_removed, check_downvotes_enabled, - local_user_view_from_jwt, mark_post_as_read, }, }; @@ -21,6 +20,7 @@ use lemmy_db_schema::{ }, traits::{Crud, Likeable}, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; use std::ops::Deref; @@ -28,8 +28,8 @@ use std::ops::Deref; pub async fn like_post( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let local_site = LocalSite::read(&mut context.pool()).await?; // Don't do a downvote if site has downvotes disabled diff --git a/crates/api/src/post/lock.rs b/crates/api/src/post/lock.rs index b2ba9b3d1..ecd206156 100644 --- a/crates/api/src/post/lock.rs +++ b/crates/api/src/post/lock.rs @@ -5,12 +5,7 @@ use lemmy_api_common::{ context::LemmyContext, post::{LockPost, PostResponse}, send_activity::{ActivityChannel, SendActivityData}, - utils::{ - check_community_ban, - check_community_deleted_or_removed, - is_mod_or_admin, - local_user_view_from_jwt, - }, + utils::{check_community_ban, check_community_deleted_or_removed, is_mod_or_admin}, }; use lemmy_db_schema::{ source::{ @@ -19,15 +14,15 @@ use lemmy_db_schema::{ }, traits::Crud, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::error::LemmyError; #[tracing::instrument(skip(context))] pub async fn lock_post( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let post_id = data.post_id; let orig_post = Post::read(&mut context.pool(), post_id).await?; diff --git a/crates/api/src/post/mark_read.rs b/crates/api/src/post/mark_read.rs index ecb1b3448..a248b0196 100644 --- a/crates/api/src/post/mark_read.rs +++ b/crates/api/src/post/mark_read.rs @@ -3,18 +3,16 @@ use lemmy_api_common::{ context::LemmyContext, post::{MarkPostAsRead, PostResponse}, utils, - utils::local_user_view_from_jwt, }; -use lemmy_db_views::structs::PostView; +use lemmy_db_views::structs::{LocalUserView, PostView}; use lemmy_utils::error::LemmyError; #[tracing::instrument(skip(context))] pub async fn mark_post_as_read( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let post_id = data.post_id; let person_id = local_user_view.person.id; diff --git a/crates/api/src/post/save.rs b/crates/api/src/post/save.rs index ddad6ede4..164840770 100644 --- a/crates/api/src/post/save.rs +++ b/crates/api/src/post/save.rs @@ -2,22 +2,21 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, post::{PostResponse, SavePost}, - utils::{local_user_view_from_jwt, mark_post_as_read}, + utils::mark_post_as_read, }; use lemmy_db_schema::{ source::post::{PostSaved, PostSavedForm}, traits::Saveable, }; -use lemmy_db_views::structs::PostView; +use lemmy_db_views::structs::{LocalUserView, PostView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn save_post( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let post_saved_form = PostSavedForm { post_id: data.post_id, person_id: local_user_view.person.id, diff --git a/crates/api/src/post_report/create.rs b/crates/api/src/post_report/create.rs index 8a5162a60..6a32d505b 100644 --- a/crates/api/src/post_report/create.rs +++ b/crates/api/src/post_report/create.rs @@ -5,12 +5,7 @@ use lemmy_api_common::{ context::LemmyContext, post::{CreatePostReport, PostReportResponse}, send_activity::{ActivityChannel, SendActivityData}, - utils::{ - check_community_ban, - local_user_view_from_jwt, - sanitize_html_api, - send_new_report_email_to_admins, - }, + utils::{check_community_ban, sanitize_html_api, send_new_report_email_to_admins}, }; use lemmy_db_schema::{ source::{ @@ -19,7 +14,7 @@ use lemmy_db_schema::{ }, traits::Reportable, }; -use lemmy_db_views::structs::{PostReportView, PostView}; +use lemmy_db_views::structs::{LocalUserView, PostReportView, PostView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; /// Creates a post report and notifies the moderators of the community @@ -27,8 +22,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; pub async fn create_post_report( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let local_site = LocalSite::read(&mut context.pool()).await?; let reason = sanitize_html_api(data.reason.trim()); diff --git a/crates/api/src/post_report/list.rs b/crates/api/src/post_report/list.rs index e6509fe00..5cf2889ea 100644 --- a/crates/api/src/post_report/list.rs +++ b/crates/api/src/post_report/list.rs @@ -2,9 +2,8 @@ use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, post::{ListPostReports, ListPostReportsResponse}, - utils::local_user_view_from_jwt, }; -use lemmy_db_views::post_report_view::PostReportQuery; +use lemmy_db_views::{post_report_view::PostReportQuery, structs::LocalUserView}; use lemmy_utils::error::LemmyError; /// Lists post reports for a community if an id is supplied @@ -13,9 +12,8 @@ use lemmy_utils::error::LemmyError; pub async fn list_post_reports( data: Query, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let community_id = data.community_id; let unresolved_only = data.unresolved_only.unwrap_or_default(); diff --git a/crates/api/src/post_report/resolve.rs b/crates/api/src/post_report/resolve.rs index 94e841e08..fe01c748c 100644 --- a/crates/api/src/post_report/resolve.rs +++ b/crates/api/src/post_report/resolve.rs @@ -2,10 +2,10 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, post::{PostReportResponse, ResolvePostReport}, - utils::{is_mod_or_admin, local_user_view_from_jwt}, + utils::is_mod_or_admin, }; use lemmy_db_schema::{source::post_report::PostReport, traits::Reportable}; -use lemmy_db_views::structs::PostReportView; +use lemmy_db_views::structs::{LocalUserView, PostReportView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; /// Resolves or unresolves a post report and notifies the moderators of the community @@ -13,9 +13,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; pub async fn resolve_post_report( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let report_id = data.report_id; let person_id = local_user_view.person.id; let report = PostReportView::read(&mut context.pool(), report_id, person_id).await?; diff --git a/crates/api/src/private_message/mark_read.rs b/crates/api/src/private_message/mark_read.rs index 6b6f7a51d..6b089c0ab 100644 --- a/crates/api/src/private_message/mark_read.rs +++ b/crates/api/src/private_message/mark_read.rs @@ -2,22 +2,20 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, private_message::{MarkPrivateMessageAsRead, PrivateMessageResponse}, - utils::local_user_view_from_jwt, }; use lemmy_db_schema::{ source::private_message::{PrivateMessage, PrivateMessageUpdateForm}, traits::Crud, }; -use lemmy_db_views::structs::PrivateMessageView; +use lemmy_db_views::structs::{LocalUserView, PrivateMessageView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn mark_pm_as_read( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - // Checking permissions let private_message_id = data.private_message_id; let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?; diff --git a/crates/api/src/private_message_report/create.rs b/crates/api/src/private_message_report/create.rs index ed19fdc35..2c4291581 100644 --- a/crates/api/src/private_message_report/create.rs +++ b/crates/api/src/private_message_report/create.rs @@ -3,7 +3,7 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, private_message::{CreatePrivateMessageReport, PrivateMessageReportResponse}, - utils::{local_user_view_from_jwt, sanitize_html_api, send_new_report_email_to_admins}, + utils::{sanitize_html_api, send_new_report_email_to_admins}, }; use lemmy_db_schema::{ source::{ @@ -13,15 +13,15 @@ use lemmy_db_schema::{ }, traits::{Crud, Reportable}, }; -use lemmy_db_views::structs::PrivateMessageReportView; +use lemmy_db_views::structs::{LocalUserView, PrivateMessageReportView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn create_pm_report( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let local_site = LocalSite::read(&mut context.pool()).await?; let reason = sanitize_html_api(data.reason.trim()); diff --git a/crates/api/src/private_message_report/list.rs b/crates/api/src/private_message_report/list.rs index 21e0cab21..2dc3e6efc 100644 --- a/crates/api/src/private_message_report/list.rs +++ b/crates/api/src/private_message_report/list.rs @@ -2,18 +2,20 @@ use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, private_message::{ListPrivateMessageReports, ListPrivateMessageReportsResponse}, - utils::{is_admin, local_user_view_from_jwt}, + utils::is_admin, +}; +use lemmy_db_views::{ + private_message_report_view::PrivateMessageReportQuery, + structs::LocalUserView, }; -use lemmy_db_views::private_message_report_view::PrivateMessageReportQuery; use lemmy_utils::error::LemmyError; #[tracing::instrument(skip(context))] pub async fn list_pm_reports( data: Query, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - is_admin(&local_user_view)?; let unresolved_only = data.unresolved_only.unwrap_or_default(); diff --git a/crates/api/src/private_message_report/resolve.rs b/crates/api/src/private_message_report/resolve.rs index 7f3f0647a..202fdcd29 100644 --- a/crates/api/src/private_message_report/resolve.rs +++ b/crates/api/src/private_message_report/resolve.rs @@ -2,19 +2,18 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, private_message::{PrivateMessageReportResponse, ResolvePrivateMessageReport}, - utils::{is_admin, local_user_view_from_jwt}, + utils::is_admin, }; use lemmy_db_schema::{source::private_message_report::PrivateMessageReport, traits::Reportable}; -use lemmy_db_views::structs::PrivateMessageReportView; +use lemmy_db_views::structs::{LocalUserView, PrivateMessageReportView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn resolve_pm_report( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - is_admin(&local_user_view)?; let report_id = data.report_id; diff --git a/crates/api/src/site/block.rs b/crates/api/src/site/block.rs index 3278767cf..be48e8ce8 100644 --- a/crates/api/src/site/block.rs +++ b/crates/api/src/site/block.rs @@ -3,21 +3,20 @@ use actix_web::web::Json; use lemmy_api_common::{ context::LemmyContext, site::{BlockInstance, BlockInstanceResponse}, - utils::local_user_view_from_jwt, }; use lemmy_db_schema::{ source::instance_block::{InstanceBlock, InstanceBlockForm}, traits::Blockable, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn block_instance( data: Json, + local_user_view: LocalUserView, context: Data, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let instance_id = data.instance_id; let person_id = local_user_view.person.id; let instance_block_form = InstanceBlockForm { diff --git a/crates/api/src/site/leave_admin.rs b/crates/api/src/site/leave_admin.rs index 24b7184ae..f25747ef3 100644 --- a/crates/api/src/site/leave_admin.rs +++ b/crates/api/src/site/leave_admin.rs @@ -1,9 +1,5 @@ use actix_web::web::{Data, Json}; -use lemmy_api_common::{ - context::LemmyContext, - site::{GetSiteResponse, LeaveAdmin}, - utils::{is_admin, local_user_view_from_jwt}, -}; +use lemmy_api_common::{context::LemmyContext, site::GetSiteResponse, utils::is_admin}; use lemmy_db_schema::{ source::{ actor_language::SiteLanguage, @@ -14,7 +10,7 @@ use lemmy_db_schema::{ }, traits::Crud, }; -use lemmy_db_views::structs::{CustomEmojiView, SiteView}; +use lemmy_db_views::structs::{CustomEmojiView, LocalUserView, SiteView}; use lemmy_db_views_actor::structs::PersonView; use lemmy_utils::{ error::{LemmyError, LemmyErrorType}, @@ -23,11 +19,9 @@ use lemmy_utils::{ #[tracing::instrument(skip(context))] pub async fn leave_admin( - data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - is_admin(&local_user_view)?; // Make sure there isn't just one admin (so if one leaves, there will still be one left) diff --git a/crates/api/src/site/mod_log.rs b/crates/api/src/site/mod_log.rs index 6743469b7..9c66c72a1 100644 --- a/crates/api/src/site/mod_log.rs +++ b/crates/api/src/site/mod_log.rs @@ -2,13 +2,14 @@ use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, site::{GetModlog, GetModlogResponse}, - utils::{check_private_instance, is_admin, is_mod_or_admin, local_user_view_from_jwt_opt}, + utils::{check_private_instance, is_admin, is_mod_or_admin}, }; use lemmy_db_schema::{ newtypes::{CommunityId, PersonId}, source::local_site::LocalSite, ModlogActionType, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_moderator::structs::{ AdminPurgeCommentView, AdminPurgeCommunityView, @@ -34,8 +35,8 @@ use ModlogActionType::*; pub async fn get_mod_log( data: Query, context: Data, + local_user_view: Option, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await; let local_site = LocalSite::read(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site)?; diff --git a/crates/api/src/site/purge/comment.rs b/crates/api/src/site/purge/comment.rs index fa0973cf1..ec4ef02af 100644 --- a/crates/api/src/site/purge/comment.rs +++ b/crates/api/src/site/purge/comment.rs @@ -2,7 +2,7 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, site::{PurgeComment, PurgeItemResponse}, - utils::{is_admin, local_user_view_from_jwt, sanitize_html_api_opt}, + utils::{is_admin, sanitize_html_api_opt}, }; use lemmy_db_schema::{ source::{ @@ -11,15 +11,15 @@ use lemmy_db_schema::{ }, traits::Crud, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::error::LemmyError; #[tracing::instrument(skip(context))] pub async fn purge_comment( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - // Only let admin purge an item is_admin(&local_user_view)?; diff --git a/crates/api/src/site/purge/community.rs b/crates/api/src/site/purge/community.rs index 8e609501a..8e731fa29 100644 --- a/crates/api/src/site/purge/community.rs +++ b/crates/api/src/site/purge/community.rs @@ -3,12 +3,7 @@ use lemmy_api_common::{ context::LemmyContext, request::purge_image_from_pictrs, site::{PurgeCommunity, PurgeItemResponse}, - utils::{ - is_admin, - local_user_view_from_jwt, - purge_image_posts_for_community, - sanitize_html_api_opt, - }, + utils::{is_admin, purge_image_posts_for_community, sanitize_html_api_opt}, }; use lemmy_db_schema::{ source::{ @@ -17,15 +12,15 @@ use lemmy_db_schema::{ }, traits::Crud, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::error::LemmyError; #[tracing::instrument(skip(context))] pub async fn purge_community( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - // Only let admin purge an item is_admin(&local_user_view)?; diff --git a/crates/api/src/site/purge/person.rs b/crates/api/src/site/purge/person.rs index b2968ec31..1e68db88f 100644 --- a/crates/api/src/site/purge/person.rs +++ b/crates/api/src/site/purge/person.rs @@ -3,7 +3,7 @@ use lemmy_api_common::{ context::LemmyContext, request::delete_image_from_pictrs, site::{PurgeItemResponse, PurgePerson}, - utils::{is_admin, local_user_view_from_jwt, sanitize_html_api_opt}, + utils::{is_admin, sanitize_html_api_opt}, }; use lemmy_db_schema::{ source::{ @@ -20,9 +20,8 @@ use lemmy_utils::error::LemmyError; pub async fn purge_person( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - // Only let admin purge an item is_admin(&local_user_view)?; diff --git a/crates/api/src/site/purge/post.rs b/crates/api/src/site/purge/post.rs index 53dbf44e3..5e1ff4ea5 100644 --- a/crates/api/src/site/purge/post.rs +++ b/crates/api/src/site/purge/post.rs @@ -3,7 +3,7 @@ use lemmy_api_common::{ context::LemmyContext, request::purge_image_from_pictrs, site::{PurgeItemResponse, PurgePost}, - utils::{is_admin, local_user_view_from_jwt, sanitize_html_api_opt}, + utils::{is_admin, sanitize_html_api_opt}, }; use lemmy_db_schema::{ source::{ @@ -12,15 +12,15 @@ use lemmy_db_schema::{ }, traits::Crud, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::error::LemmyError; #[tracing::instrument(skip(context))] pub async fn purge_post( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - // Only let admin purge an item is_admin(&local_user_view)?; diff --git a/crates/api/src/site/registration_applications/approve.rs b/crates/api/src/site/registration_applications/approve.rs index 344fa82c8..036a60e00 100644 --- a/crates/api/src/site/registration_applications/approve.rs +++ b/crates/api/src/site/registration_applications/approve.rs @@ -2,7 +2,7 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, site::{ApproveRegistrationApplication, RegistrationApplicationResponse}, - utils::{is_admin, local_user_view_from_jwt, send_application_approved_email}, + utils::{is_admin, send_application_approved_email}, }; use lemmy_db_schema::{ source::{ @@ -18,9 +18,8 @@ use lemmy_utils::error::LemmyError; pub async fn approve_registration_application( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let app_id = data.id; // Only let admins do this diff --git a/crates/api/src/site/registration_applications/list.rs b/crates/api/src/site/registration_applications/list.rs index 0690f50fb..30ce9aaf2 100644 --- a/crates/api/src/site/registration_applications/list.rs +++ b/crates/api/src/site/registration_applications/list.rs @@ -2,18 +2,21 @@ use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, site::{ListRegistrationApplications, ListRegistrationApplicationsResponse}, - utils::{is_admin, local_user_view_from_jwt}, + utils::is_admin, }; use lemmy_db_schema::source::local_site::LocalSite; -use lemmy_db_views::registration_application_view::RegistrationApplicationQuery; +use lemmy_db_views::{ + registration_application_view::RegistrationApplicationQuery, + structs::LocalUserView, +}; use lemmy_utils::error::LemmyError; /// Lists registration applications, filterable by undenied only. pub async fn list_registration_applications( data: Query, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let local_site = LocalSite::read(&mut context.pool()).await?; // Make sure user is an admin diff --git a/crates/api/src/site/registration_applications/unread_count.rs b/crates/api/src/site/registration_applications/unread_count.rs index 49929c070..255859198 100644 --- a/crates/api/src/site/registration_applications/unread_count.rs +++ b/crates/api/src/site/registration_applications/unread_count.rs @@ -1,18 +1,17 @@ -use actix_web::web::{Data, Json, Query}; +use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, - site::{GetUnreadRegistrationApplicationCount, GetUnreadRegistrationApplicationCountResponse}, - utils::{is_admin, local_user_view_from_jwt}, + site::GetUnreadRegistrationApplicationCountResponse, + utils::is_admin, }; use lemmy_db_schema::source::local_site::LocalSite; -use lemmy_db_views::structs::RegistrationApplicationView; +use lemmy_db_views::structs::{LocalUserView, RegistrationApplicationView}; use lemmy_utils::error::LemmyError; pub async fn get_unread_registration_application_count( - data: Query, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let local_site = LocalSite::read(&mut context.pool()).await?; // Only let admins do this diff --git a/crates/api_common/src/comment.rs b/crates/api_common/src/comment.rs index ec9ca1328..c2589fb2a 100644 --- a/crates/api_common/src/comment.rs +++ b/crates/api_common/src/comment.rs @@ -1,4 +1,3 @@ -use crate::sensitive::Sensitive; use lemmy_db_schema::{ newtypes::{CommentId, CommentReportId, CommunityId, LanguageId, LocalUserId, PostId}, CommentSortType, @@ -20,7 +19,6 @@ pub struct CreateComment { pub post_id: PostId, pub parent_id: Option, pub language_id: Option, - pub auth: Sensitive, } #[skip_serializing_none] @@ -30,7 +28,6 @@ pub struct CreateComment { /// Fetch an individual comment. pub struct GetComment { pub id: CommentId, - pub auth: Option>, } #[skip_serializing_none] @@ -42,7 +39,6 @@ pub struct EditComment { pub comment_id: CommentId, pub content: Option, pub language_id: Option, - pub auth: Sensitive, } #[skip_serializing_none] @@ -53,7 +49,6 @@ pub struct EditComment { pub struct DistinguishComment { pub comment_id: CommentId, pub distinguished: bool, - pub auth: Sensitive, } #[skip_serializing_none] @@ -64,7 +59,6 @@ pub struct DistinguishComment { pub struct DeleteComment { pub comment_id: CommentId, pub deleted: bool, - pub auth: Sensitive, } #[skip_serializing_none] @@ -76,7 +70,6 @@ pub struct RemoveComment { pub comment_id: CommentId, pub removed: bool, pub reason: Option, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -86,7 +79,6 @@ pub struct RemoveComment { pub struct SaveComment { pub comment_id: CommentId, pub save: bool, - pub auth: Sensitive, } #[skip_serializing_none] @@ -107,7 +99,6 @@ pub struct CreateCommentLike { pub comment_id: CommentId, /// Must be -1, 0, or 1 . pub score: i16, - pub auth: Sensitive, } #[skip_serializing_none] @@ -128,7 +119,6 @@ pub struct GetComments { pub saved_only: Option, pub liked_only: Option, pub disliked_only: Option, - pub auth: Option>, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -146,7 +136,6 @@ pub struct GetCommentsResponse { pub struct CreateCommentReport { pub comment_id: CommentId, pub reason: String, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -164,7 +153,6 @@ pub struct CommentReportResponse { pub struct ResolveCommentReport { pub report_id: CommentReportId, pub resolved: bool, - pub auth: Sensitive, } #[skip_serializing_none] @@ -179,7 +167,6 @@ pub struct ListCommentReports { pub unresolved_only: Option, /// if no community is given, it returns reports for all communities moderated by the auth user pub community_id: Option, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] diff --git a/crates/api_common/src/community.rs b/crates/api_common/src/community.rs index ff6ed1271..7c96344b5 100644 --- a/crates/api_common/src/community.rs +++ b/crates/api_common/src/community.rs @@ -1,4 +1,3 @@ -use crate::sensitive::Sensitive; use lemmy_db_schema::{ newtypes::{CommunityId, LanguageId, PersonId}, source::site::Site, @@ -20,7 +19,6 @@ pub struct GetCommunity { pub id: Option, /// Example: star_trek , or star_trek@xyz.tld pub name: Option, - pub auth: Option>, } #[skip_serializing_none] @@ -56,7 +54,6 @@ pub struct CreateCommunity { /// Whether to restrict posting only to moderators. pub posting_restricted_to_mods: Option, pub discussion_languages: Option>, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -79,7 +76,6 @@ pub struct ListCommunities { pub show_nsfw: Option, pub page: Option, pub limit: Option, - pub auth: Option>, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -102,7 +98,6 @@ pub struct BanFromCommunity { pub remove_data: Option, pub reason: Option, pub expires: Option, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -122,7 +117,6 @@ pub struct AddModToCommunity { pub community_id: CommunityId, pub person_id: PersonId, pub added: bool, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -153,7 +147,6 @@ pub struct EditCommunity { /// Whether to restrict posting only to moderators. pub posting_restricted_to_mods: Option, pub discussion_languages: Option>, - pub auth: Sensitive, } #[skip_serializing_none] @@ -166,7 +159,6 @@ pub struct HideCommunity { pub community_id: CommunityId, pub hidden: bool, pub reason: Option, - pub auth: Sensitive, } #[skip_serializing_none] @@ -177,7 +169,6 @@ pub struct HideCommunity { pub struct DeleteCommunity { pub community_id: CommunityId, pub deleted: bool, - pub auth: Sensitive, } #[skip_serializing_none] @@ -190,7 +181,6 @@ pub struct RemoveCommunity { pub removed: bool, pub reason: Option, pub expires: Option, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -200,7 +190,6 @@ pub struct RemoveCommunity { pub struct FollowCommunity { pub community_id: CommunityId, pub follow: bool, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -210,7 +199,6 @@ pub struct FollowCommunity { pub struct BlockCommunity { pub community_id: CommunityId, pub block: bool, - pub auth: Sensitive, } #[skip_serializing_none] @@ -230,5 +218,4 @@ pub struct BlockCommunityResponse { pub struct TransferCommunity { pub community_id: CommunityId, pub person_id: PersonId, - pub auth: Sensitive, } diff --git a/crates/api_common/src/custom_emoji.rs b/crates/api_common/src/custom_emoji.rs index 7f3461ca7..83248dc91 100644 --- a/crates/api_common/src/custom_emoji.rs +++ b/crates/api_common/src/custom_emoji.rs @@ -1,4 +1,3 @@ -use crate::sensitive::Sensitive; use lemmy_db_schema::newtypes::CustomEmojiId; use lemmy_db_views::structs::CustomEmojiView; use serde::{Deserialize, Serialize}; @@ -17,7 +16,6 @@ pub struct CreateCustomEmoji { pub image_url: Url, pub alt_text: String, pub keywords: Vec, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -31,7 +29,6 @@ pub struct EditCustomEmoji { pub image_url: Url, pub alt_text: String, pub keywords: Vec, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -40,7 +37,6 @@ pub struct EditCustomEmoji { /// Delete a custom emoji. pub struct DeleteCustomEmoji { pub id: CustomEmojiId, - pub auth: Sensitive, } #[derive(Serialize, Deserialize, Clone)] diff --git a/crates/api_common/src/person.rs b/crates/api_common/src/person.rs index 3f43f30df..feb945b17 100644 --- a/crates/api_common/src/person.rs +++ b/crates/api_common/src/person.rs @@ -119,7 +119,6 @@ pub struct SaveUserSettings { pub show_new_post_notifs: Option, /// A list of languages you are able to see discussion in. pub discussion_languages: Option>, - pub auth: Sensitive, /// Open links in a new tab pub open_links_in_new_tab: Option, /// Enable infinite scroll @@ -134,7 +133,6 @@ pub struct ChangePassword { pub new_password: Sensitive, pub new_password_verify: Sensitive, pub old_password: Sensitive, - pub auth: Sensitive, } #[skip_serializing_none] @@ -167,7 +165,6 @@ pub struct GetPersonDetails { pub limit: Option, pub community_id: Option, pub saved_only: Option, - pub auth: Option>, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -181,14 +178,6 @@ pub struct GetPersonDetailsResponse { pub moderates: Vec, } -#[derive(Debug, Serialize, Deserialize, Clone, Default)] -#[cfg_attr(feature = "full", derive(TS))] -#[cfg_attr(feature = "full", ts(export))] -/// Marks all notifications as read. -pub struct MarkAllAsRead { - pub auth: Sensitive, -} - #[derive(Debug, Serialize, Deserialize, Clone, Default)] #[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", ts(export))] @@ -196,7 +185,6 @@ pub struct MarkAllAsRead { pub struct AddAdmin { pub person_id: PersonId, pub added: bool, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -219,18 +207,9 @@ pub struct BanPerson { pub remove_data: Option, pub reason: Option, pub expires: Option, - pub auth: Sensitive, } -#[derive(Debug, Serialize, Deserialize, Clone, Default)] -#[cfg_attr(feature = "full", derive(TS))] -#[cfg_attr(feature = "full", ts(export))] -/// Get a list of banned persons. // TODO, this should be paged, since the list can be quite long. -pub struct GetBannedPersons { - pub auth: Sensitive, -} - #[derive(Debug, Serialize, Deserialize, Clone)] #[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", ts(export))] @@ -255,7 +234,6 @@ pub struct BanPersonResponse { pub struct BlockPerson { pub person_id: PersonId, pub block: bool, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -277,7 +255,6 @@ pub struct GetReplies { pub page: Option, pub limit: Option, pub unread_only: Option, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -299,7 +276,6 @@ pub struct GetPersonMentions { pub page: Option, pub limit: Option, pub unread_only: Option, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -317,7 +293,6 @@ pub struct GetPersonMentionsResponse { pub struct MarkPersonMentionAsRead { pub person_mention_id: PersonMentionId, pub read: bool, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -335,7 +310,6 @@ pub struct PersonMentionResponse { pub struct MarkCommentReplyAsRead { pub comment_reply_id: CommentReplyId, pub read: bool, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -353,7 +327,6 @@ pub struct CommentReplyResponse { pub struct DeleteAccount { pub password: Sensitive, pub delete_content: bool, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -393,7 +366,6 @@ pub struct PasswordChangeAfterReset { /// Get a count of the number of reports. pub struct GetReportCount { pub community_id: Option, - pub auth: Sensitive, } #[skip_serializing_none] @@ -408,14 +380,6 @@ pub struct GetReportCountResponse { pub private_message_reports: Option, } -#[derive(Debug, Serialize, Deserialize, Clone, Default)] -#[cfg_attr(feature = "full", derive(TS))] -#[cfg_attr(feature = "full", ts(export))] -/// Get a count of unread notifications. -pub struct GetUnreadCount { - pub auth: Sensitive, -} - #[derive(Debug, Serialize, Deserialize, Clone)] #[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", ts(export))] diff --git a/crates/api_common/src/post.rs b/crates/api_common/src/post.rs index bb5c1cccc..86f721701 100644 --- a/crates/api_common/src/post.rs +++ b/crates/api_common/src/post.rs @@ -1,4 +1,3 @@ -use crate::sensitive::Sensitive; use lemmy_db_schema::{ newtypes::{CommentId, CommunityId, DbUrl, LanguageId, PostId, PostReportId}, ListingType, @@ -29,7 +28,6 @@ pub struct CreatePost { pub honeypot: Option, pub nsfw: Option, pub language_id: Option, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -47,7 +45,6 @@ pub struct PostResponse { pub struct GetPost { pub id: Option, pub comment_id: Option, - pub auth: Option>, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -78,7 +75,6 @@ pub struct GetPosts { pub saved_only: Option, pub liked_only: Option, pub disliked_only: Option, - pub auth: Option>, pub page_cursor: Option, } @@ -101,7 +97,6 @@ pub struct CreatePostLike { pub post_id: PostId, /// Score must be -1, 0, or 1. pub score: i16, - pub auth: Sensitive, } #[skip_serializing_none] @@ -118,7 +113,6 @@ pub struct EditPost { pub body: Option, pub nsfw: Option, pub language_id: Option, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -128,7 +122,6 @@ pub struct EditPost { pub struct DeletePost { pub post_id: PostId, pub deleted: bool, - pub auth: Sensitive, } #[skip_serializing_none] @@ -140,7 +133,6 @@ pub struct RemovePost { pub post_id: PostId, pub removed: bool, pub reason: Option, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -150,7 +142,6 @@ pub struct RemovePost { pub struct MarkPostAsRead { pub post_id: PostId, pub read: bool, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -160,7 +151,6 @@ pub struct MarkPostAsRead { pub struct LockPost { pub post_id: PostId, pub locked: bool, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -171,7 +161,6 @@ pub struct FeaturePost { pub post_id: PostId, pub featured: bool, pub feature_type: PostFeatureType, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -181,7 +170,6 @@ pub struct FeaturePost { pub struct SavePost { pub post_id: PostId, pub save: bool, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -191,7 +179,6 @@ pub struct SavePost { pub struct CreatePostReport { pub post_id: PostId, pub reason: String, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -209,7 +196,6 @@ pub struct PostReportResponse { pub struct ResolvePostReport { pub report_id: PostReportId, pub resolved: bool, - pub auth: Sensitive, } #[skip_serializing_none] @@ -224,7 +210,6 @@ pub struct ListPostReports { pub unresolved_only: Option, /// if no community is given, it returns reports for all communities moderated by the auth user pub community_id: Option, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] diff --git a/crates/api_common/src/private_message.rs b/crates/api_common/src/private_message.rs index d27c4f659..8d469127d 100644 --- a/crates/api_common/src/private_message.rs +++ b/crates/api_common/src/private_message.rs @@ -1,4 +1,3 @@ -use crate::sensitive::Sensitive; use lemmy_db_schema::newtypes::{PersonId, PrivateMessageId, PrivateMessageReportId}; use lemmy_db_views::structs::{PrivateMessageReportView, PrivateMessageView}; use serde::{Deserialize, Serialize}; @@ -13,7 +12,6 @@ use ts_rs::TS; pub struct CreatePrivateMessage { pub content: String, pub recipient_id: PersonId, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -23,7 +21,6 @@ pub struct CreatePrivateMessage { pub struct EditPrivateMessage { pub private_message_id: PrivateMessageId, pub content: String, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -33,7 +30,6 @@ pub struct EditPrivateMessage { pub struct DeletePrivateMessage { pub private_message_id: PrivateMessageId, pub deleted: bool, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -43,7 +39,6 @@ pub struct DeletePrivateMessage { pub struct MarkPrivateMessageAsRead { pub private_message_id: PrivateMessageId, pub read: bool, - pub auth: Sensitive, } #[skip_serializing_none] @@ -56,7 +51,6 @@ pub struct GetPrivateMessages { pub page: Option, pub limit: Option, pub creator_id: Option, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -82,7 +76,6 @@ pub struct PrivateMessageResponse { pub struct CreatePrivateMessageReport { pub private_message_id: PrivateMessageId, pub reason: String, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -100,7 +93,6 @@ pub struct PrivateMessageReportResponse { pub struct ResolvePrivateMessageReport { pub report_id: PrivateMessageReportId, pub resolved: bool, - pub auth: Sensitive, } #[skip_serializing_none] @@ -114,7 +106,6 @@ pub struct ListPrivateMessageReports { pub limit: Option, /// Only shows the unresolved reports pub unresolved_only: Option, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] diff --git a/crates/api_common/src/send_activity.rs b/crates/api_common/src/send_activity.rs index 84b2efb2d..6d9c722a1 100644 --- a/crates/api_common/src/send_activity.rs +++ b/crates/api_common/src/send_activity.rs @@ -18,7 +18,15 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::PrivateMessageView; use lemmy_utils::error::LemmyResult; -use once_cell::sync::OnceCell; +use once_cell::sync::{Lazy, OnceCell}; +use tokio::{ + sync::{ + mpsc, + mpsc::{UnboundedReceiver, UnboundedSender, WeakUnboundedSender}, + Mutex, + }, + task::JoinHandle, +}; use url::Url; type MatchOutgoingActivitiesBoxed = @@ -54,16 +62,45 @@ pub enum SendActivityData { CreateReport(Url, Person, Community, String), } -pub struct ActivityChannel; +// TODO: instead of static, move this into LemmyContext. make sure that stopping the process with +// ctrl+c still works. +static ACTIVITY_CHANNEL: Lazy = Lazy::new(|| { + let (sender, receiver) = mpsc::unbounded_channel(); + let weak_sender = sender.downgrade(); + ActivityChannel { + weak_sender, + receiver: Mutex::new(receiver), + keepalive_sender: Mutex::new(Some(sender)), + } +}); + +pub struct ActivityChannel { + weak_sender: WeakUnboundedSender, + receiver: Mutex>, + keepalive_sender: Mutex>>, +} impl ActivityChannel { + pub async fn retrieve_activity() -> Option { + let mut lock = ACTIVITY_CHANNEL.receiver.lock().await; + lock.recv().await + } + pub async fn submit_activity( data: SendActivityData, - context: &Data, + _context: &Data, ) -> LemmyResult<()> { - MATCH_OUTGOING_ACTIVITIES - .get() - .expect("retrieve function pointer")(data, context) - .await + // could do `ACTIVITY_CHANNEL.keepalive_sender.lock()` instead and get rid of weak_sender, + // not sure which way is more efficient + if let Some(sender) = ACTIVITY_CHANNEL.weak_sender.upgrade() { + sender.send(data)?; + } + Ok(()) + } + + pub async fn close(outgoing_activities_task: JoinHandle>) -> LemmyResult<()> { + ACTIVITY_CHANNEL.keepalive_sender.lock().await.take(); + outgoing_activities_task.await??; + Ok(()) } } diff --git a/crates/api_common/src/site.rs b/crates/api_common/src/site.rs index 7ed94f2de..b047c6dd0 100644 --- a/crates/api_common/src/site.rs +++ b/crates/api_common/src/site.rs @@ -1,4 +1,3 @@ -use crate::sensitive::Sensitive; use lemmy_db_schema::{ newtypes::{CommentId, CommunityId, InstanceId, LanguageId, PersonId, PostId}, source::{instance::Instance, language::Language, tagline::Tagline}, @@ -62,7 +61,6 @@ pub struct Search { pub listing_type: Option, pub page: Option, pub limit: Option, - pub auth: Option>, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -85,7 +83,6 @@ pub struct SearchResponse { pub struct ResolveObject { /// Can be the full url, or a shortened version like: !fediverse@lemmy.ml pub q: String, - pub auth: Option>, } #[skip_serializing_none] @@ -113,7 +110,6 @@ pub struct GetModlog { pub limit: Option, pub type_: Option, pub other_person_id: Option, - pub auth: Option>, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -184,7 +180,6 @@ pub struct CreateSite { pub blocked_instances: Option>, pub taglines: Option>, pub registration_mode: Option, - pub auth: Sensitive, } #[skip_serializing_none] @@ -263,16 +258,6 @@ pub struct EditSite { pub registration_mode: Option, /// Whether to email admins for new reports. pub reports_email_admins: Option, - pub auth: Sensitive, -} - -#[skip_serializing_none] -#[derive(Debug, Serialize, Deserialize, Clone, Default)] -#[cfg_attr(feature = "full", derive(TS))] -#[cfg_attr(feature = "full", ts(export))] -/// Fetches the site. -pub struct GetSite { - pub auth: Option>, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -326,14 +311,6 @@ pub struct MyUserInfo { pub discussion_languages: Vec, } -#[derive(Debug, Serialize, Deserialize, Clone)] -#[cfg_attr(feature = "full", derive(TS))] -#[cfg_attr(feature = "full", ts(export))] -/// Leaves the admin team. -pub struct LeaveAdmin { - pub auth: Sensitive, -} - #[derive(Debug, Serialize, Deserialize, Clone)] #[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", ts(export))] @@ -352,7 +329,6 @@ pub struct FederatedInstances { pub struct PurgePerson { pub person_id: PersonId, pub reason: Option, - pub auth: Sensitive, } #[skip_serializing_none] @@ -363,7 +339,6 @@ pub struct PurgePerson { pub struct PurgeCommunity { pub community_id: CommunityId, pub reason: Option, - pub auth: Sensitive, } #[skip_serializing_none] @@ -374,7 +349,6 @@ pub struct PurgeCommunity { pub struct PurgePost { pub post_id: PostId, pub reason: Option, - pub auth: Sensitive, } #[skip_serializing_none] @@ -385,7 +359,6 @@ pub struct PurgePost { pub struct PurgeComment { pub comment_id: CommentId, pub reason: Option, - pub auth: Sensitive, } #[derive(Serialize, Deserialize, Clone)] @@ -406,7 +379,6 @@ pub struct ListRegistrationApplications { pub unread_only: Option, pub page: Option, pub limit: Option, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -426,7 +398,6 @@ pub struct ApproveRegistrationApplication { pub id: i32, pub approve: bool, pub deny_reason: Option, - pub auth: Sensitive, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -437,14 +408,6 @@ pub struct RegistrationApplicationResponse { pub registration_application: RegistrationApplicationView, } -#[derive(Debug, Serialize, Deserialize, Clone)] -#[cfg_attr(feature = "full", derive(TS))] -#[cfg_attr(feature = "full", ts(export))] -/// Gets a count of unread registration applications. -pub struct GetUnreadRegistrationApplicationCount { - pub auth: Sensitive, -} - #[derive(Debug, Serialize, Deserialize, Clone)] #[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", ts(export))] @@ -460,7 +423,6 @@ pub struct GetUnreadRegistrationApplicationCountResponse { pub struct BlockInstance { pub instance_id: InstanceId, pub block: bool, - pub auth: Sensitive, } #[skip_serializing_none] diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index 9d8181a2e..26ef18c9e 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -1,14 +1,9 @@ -use crate::{ - context::LemmyContext, - request::purge_image_from_pictrs, - sensitive::Sensitive, - site::FederatedInstances, -}; +use crate::{context::LemmyContext, request::purge_image_from_pictrs, site::FederatedInstances}; use anyhow::Context; use chrono::{DateTime, Utc}; use lemmy_db_schema::{ impls::person::is_banned, - newtypes::{CommunityId, DbUrl, LocalUserId, PersonId, PostId}, + newtypes::{CommunityId, DbUrl, PersonId, PostId}, source::{ comment::{Comment, CommentUpdateForm}, community::{Community, CommunityModerator, CommunityUpdateForm}, @@ -20,11 +15,9 @@ use lemmy_db_schema::{ person::{Person, PersonUpdateForm}, person_block::PersonBlock, post::{Post, PostRead, PostReadForm}, - registration_application::RegistrationApplication, }, traits::{Crud, Readable}, utils::DbPool, - RegistrationMode, }; use lemmy_db_views::{comment_view::CommentQuery, structs::LocalUserView}; use lemmy_db_views_actor::structs::{ @@ -33,9 +26,8 @@ use lemmy_db_views_actor::structs::{ CommunityView, }; use lemmy_utils::{ - claims::Claims, email::{send_email, translations::Lang}, - error::{LemmyError, LemmyErrorExt, LemmyErrorExt2, LemmyErrorType}, + error::{LemmyError, LemmyErrorExt, LemmyErrorType}, location_info, rate_limit::RateLimitConfig, settings::structs::Settings, @@ -134,58 +126,6 @@ pub async fn mark_post_as_unread( .with_lemmy_type(LemmyErrorType::CouldntMarkPostAsRead) } -#[tracing::instrument(skip_all)] -pub async fn local_user_view_from_jwt( - jwt: &str, - context: &LemmyContext, -) -> Result { - let claims = Claims::decode(jwt, &context.secret().jwt_secret) - .with_lemmy_type(LemmyErrorType::NotLoggedIn)? - .claims; - let local_user_id = LocalUserId(claims.sub); - let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id).await?; - check_user_valid( - local_user_view.person.banned, - local_user_view.person.ban_expires, - local_user_view.person.deleted, - )?; - - check_validator_time(&local_user_view.local_user.validator_time, &claims)?; - - Ok(local_user_view) -} - -#[tracing::instrument(skip_all)] -pub async fn local_user_view_from_jwt_opt( - jwt: Option<&Sensitive>, - context: &LemmyContext, -) -> Option { - local_user_view_from_jwt(jwt?, context).await.ok() -} -#[tracing::instrument(skip_all)] -pub async fn local_user_view_from_jwt_opt_new( - local_user_view: &mut Option, - jwt: Option<&Sensitive>, - context: &LemmyContext, -) { - if local_user_view.is_none() { - *local_user_view = local_user_view_from_jwt_opt(jwt, context).await; - } -} - -/// Checks if user's token was issued before user's password reset. -pub fn check_validator_time( - validator_time: &DateTime, - claims: &Claims, -) -> Result<(), LemmyError> { - let user_validation_time = validator_time.timestamp(); - if user_validation_time > claims.iat { - Err(LemmyErrorType::NotLoggedIn)? - } else { - Ok(()) - } -} - pub fn check_user_valid( banned: bool, ban_expires: Option>, @@ -505,32 +445,6 @@ pub async fn send_new_report_email_to_admins( Ok(()) } -pub async fn check_registration_application( - local_user_view: &LocalUserView, - local_site: &LocalSite, - pool: &mut DbPool<'_>, -) -> Result<(), LemmyError> { - if (local_site.registration_mode == RegistrationMode::RequireApplication - || local_site.registration_mode == RegistrationMode::Closed) - && !local_user_view.local_user.accepted_application - && !local_user_view.local_user.admin - { - // Fetch the registration, see if its denied - let local_user_id = local_user_view.local_user.id; - let registration = RegistrationApplication::find_by_local_user_id(pool, local_user_id).await?; - if let Some(deny_reason) = registration.deny_reason { - let lang = get_interface_language(local_user_view); - let registration_denied_message = format!("{}: {}", lang.registration_denied(), deny_reason); - Err(LemmyErrorType::RegistrationDenied( - registration_denied_message, - ))? - } else { - Err(LemmyErrorType::RegistrationApplicationIsPending)? - } - } - Ok(()) -} - pub fn check_private_instance_and_federation_enabled( local_site: &LocalSite, ) -> Result<(), LemmyError> { diff --git a/crates/api_crud/src/comment/create.rs b/crates/api_crud/src/comment/create.rs index 3ba19d1b9..c9aa4f774 100644 --- a/crates/api_crud/src/comment/create.rs +++ b/crates/api_crud/src/comment/create.rs @@ -12,7 +12,6 @@ use lemmy_api_common::{ generate_local_apub_endpoint, get_post, local_site_to_slur_regex, - local_user_view_from_jwt, sanitize_html_api, EndpointType, }, @@ -28,6 +27,7 @@ use lemmy_db_schema::{ }, traits::{Crud, Likeable}, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, utils::{ @@ -43,8 +43,8 @@ const MAX_COMMENT_DEPTH_LIMIT: usize = 100; pub async fn create_comment( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let local_site = LocalSite::read(&mut context.pool()).await?; let content = remove_slurs( diff --git a/crates/api_crud/src/comment/delete.rs b/crates/api_crud/src/comment/delete.rs index 5f5db905e..1c986d03c 100644 --- a/crates/api_crud/src/comment/delete.rs +++ b/crates/api_crud/src/comment/delete.rs @@ -5,7 +5,7 @@ use lemmy_api_common::{ comment::{CommentResponse, DeleteComment}, context::LemmyContext, send_activity::{ActivityChannel, SendActivityData}, - utils::{check_community_ban, local_user_view_from_jwt}, + utils::check_community_ban, }; use lemmy_db_schema::{ source::{ @@ -14,16 +14,15 @@ use lemmy_db_schema::{ }, traits::Crud, }; -use lemmy_db_views::structs::CommentView; +use lemmy_db_views::structs::{CommentView, LocalUserView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn delete_comment( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let comment_id = data.comment_id; let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; diff --git a/crates/api_crud/src/comment/read.rs b/crates/api_crud/src/comment/read.rs index 5f07f7496..733d08682 100644 --- a/crates/api_crud/src/comment/read.rs +++ b/crates/api_crud/src/comment/read.rs @@ -3,17 +3,18 @@ use lemmy_api_common::{ build_response::build_comment_response, comment::{CommentResponse, GetComment}, context::LemmyContext, - utils::{check_private_instance, local_user_view_from_jwt_opt}, + utils::check_private_instance, }; use lemmy_db_schema::source::local_site::LocalSite; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::error::LemmyError; #[tracing::instrument(skip(context))] pub async fn get_comment( data: Query, context: Data, + local_user_view: Option, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await; let local_site = LocalSite::read(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site)?; diff --git a/crates/api_crud/src/comment/remove.rs b/crates/api_crud/src/comment/remove.rs index 2bb5c75f2..601101bb8 100644 --- a/crates/api_crud/src/comment/remove.rs +++ b/crates/api_crud/src/comment/remove.rs @@ -5,7 +5,7 @@ use lemmy_api_common::{ comment::{CommentResponse, RemoveComment}, context::LemmyContext, send_activity::{ActivityChannel, SendActivityData}, - utils::{check_community_ban, is_mod_or_admin, local_user_view_from_jwt}, + utils::{check_community_ban, is_mod_or_admin}, }; use lemmy_db_schema::{ source::{ @@ -15,16 +15,15 @@ use lemmy_db_schema::{ }, traits::Crud, }; -use lemmy_db_views::structs::CommentView; +use lemmy_db_views::structs::{CommentView, LocalUserView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn remove_comment( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let comment_id = data.comment_id; let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; diff --git a/crates/api_crud/src/comment/update.rs b/crates/api_crud/src/comment/update.rs index bf6bdff84..2d966d0fa 100644 --- a/crates/api_crud/src/comment/update.rs +++ b/crates/api_crud/src/comment/update.rs @@ -5,12 +5,7 @@ use lemmy_api_common::{ comment::{CommentResponse, EditComment}, context::LemmyContext, send_activity::{ActivityChannel, SendActivityData}, - utils::{ - check_community_ban, - local_site_to_slur_regex, - local_user_view_from_jwt, - sanitize_html_api_opt, - }, + utils::{check_community_ban, local_site_to_slur_regex, sanitize_html_api_opt}, }; use lemmy_db_schema::{ source::{ @@ -21,7 +16,7 @@ use lemmy_db_schema::{ traits::Crud, utils::naive_now, }; -use lemmy_db_views::structs::CommentView; +use lemmy_db_views::structs::{CommentView, LocalUserView}; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, utils::{ @@ -35,8 +30,8 @@ use lemmy_utils::{ pub async fn update_comment( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let local_site = LocalSite::read(&mut context.pool()).await?; let comment_id = data.comment_id; diff --git a/crates/api_crud/src/community/create.rs b/crates/api_crud/src/community/create.rs index d6c07c128..633fa81a9 100644 --- a/crates/api_crud/src/community/create.rs +++ b/crates/api_crud/src/community/create.rs @@ -11,7 +11,6 @@ use lemmy_api_common::{ generate_shared_inbox_url, is_admin, local_site_to_slur_regex, - local_user_view_from_jwt, sanitize_html_api, sanitize_html_api_opt, EndpointType, @@ -32,7 +31,7 @@ use lemmy_db_schema::{ traits::{ApubActor, Crud, Followable, Joinable}, utils::diesel_option_overwrite_to_url_create, }; -use lemmy_db_views::structs::SiteView; +use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, utils::{ @@ -45,8 +44,8 @@ use lemmy_utils::{ pub async fn create_community( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let site_view = SiteView::read_local(&mut context.pool()).await?; let local_site = site_view.local_site; diff --git a/crates/api_crud/src/community/delete.rs b/crates/api_crud/src/community/delete.rs index 9c8db512d..7c94e0ccc 100644 --- a/crates/api_crud/src/community/delete.rs +++ b/crates/api_crud/src/community/delete.rs @@ -5,12 +5,13 @@ use lemmy_api_common::{ community::{CommunityResponse, DeleteCommunity}, context::LemmyContext, send_activity::{ActivityChannel, SendActivityData}, - utils::{is_top_mod, local_user_view_from_jwt}, + utils::is_top_mod, }; use lemmy_db_schema::{ source::community::{Community, CommunityUpdateForm}, traits::Crud, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::CommunityModeratorView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; @@ -18,9 +19,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; pub async fn delete_community( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - // Fetch the community mods let community_id = data.community_id; let community_mods = diff --git a/crates/api_crud/src/community/list.rs b/crates/api_crud/src/community/list.rs index 1f620dd9c..0879421ba 100644 --- a/crates/api_crud/src/community/list.rs +++ b/crates/api_crud/src/community/list.rs @@ -2,9 +2,10 @@ use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ community::{ListCommunities, ListCommunitiesResponse}, context::LemmyContext, - utils::{check_private_instance, is_admin, local_user_view_from_jwt_opt}, + utils::{check_private_instance, is_admin}, }; use lemmy_db_schema::source::local_site::LocalSite; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::community_view::CommunityQuery; use lemmy_utils::error::LemmyError; @@ -12,8 +13,8 @@ use lemmy_utils::error::LemmyError; pub async fn list_communities( data: Query, context: Data, + local_user_view: Option, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await; let local_site = LocalSite::read(&mut context.pool()).await?; let is_admin = local_user_view .as_ref() diff --git a/crates/api_crud/src/community/remove.rs b/crates/api_crud/src/community/remove.rs index f0bee639d..3a2cc654a 100644 --- a/crates/api_crud/src/community/remove.rs +++ b/crates/api_crud/src/community/remove.rs @@ -5,7 +5,7 @@ use lemmy_api_common::{ community::{CommunityResponse, RemoveCommunity}, context::LemmyContext, send_activity::{ActivityChannel, SendActivityData}, - utils::{is_admin, local_user_view_from_jwt}, + utils::is_admin, }; use lemmy_db_schema::{ source::{ @@ -14,6 +14,7 @@ use lemmy_db_schema::{ }, traits::Crud, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, utils::time::naive_from_unix, @@ -23,9 +24,8 @@ use lemmy_utils::{ pub async fn remove_community( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - // Verify its an admin (only an admin can remove a community) is_admin(&local_user_view)?; diff --git a/crates/api_crud/src/community/update.rs b/crates/api_crud/src/community/update.rs index 122cab94e..893128d8c 100644 --- a/crates/api_crud/src/community/update.rs +++ b/crates/api_crud/src/community/update.rs @@ -5,7 +5,7 @@ use lemmy_api_common::{ community::{CommunityResponse, EditCommunity}, context::LemmyContext, send_activity::{ActivityChannel, SendActivityData}, - utils::{local_site_to_slur_regex, local_user_view_from_jwt, sanitize_html_api_opt}, + utils::{local_site_to_slur_regex, sanitize_html_api_opt}, }; use lemmy_db_schema::{ newtypes::PersonId, @@ -17,6 +17,7 @@ use lemmy_db_schema::{ traits::Crud, utils::{diesel_option_overwrite, diesel_option_overwrite_to_url, naive_now}, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::CommunityModeratorView; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, @@ -27,8 +28,8 @@ use lemmy_utils::{ pub async fn update_community( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let local_site = LocalSite::read(&mut context.pool()).await?; let slur_regex = local_site_to_slur_regex(&local_site); diff --git a/crates/api_crud/src/custom_emoji/create.rs b/crates/api_crud/src/custom_emoji/create.rs index 046003627..7a2ae9b2d 100644 --- a/crates/api_crud/src/custom_emoji/create.rs +++ b/crates/api_crud/src/custom_emoji/create.rs @@ -3,23 +3,22 @@ use actix_web::web::Json; use lemmy_api_common::{ context::LemmyContext, custom_emoji::{CreateCustomEmoji, CustomEmojiResponse}, - utils::{is_admin, local_user_view_from_jwt, sanitize_html_api}, + utils::{is_admin, sanitize_html_api}, }; use lemmy_db_schema::source::{ custom_emoji::{CustomEmoji, CustomEmojiInsertForm}, custom_emoji_keyword::{CustomEmojiKeyword, CustomEmojiKeywordInsertForm}, local_site::LocalSite, }; -use lemmy_db_views::structs::CustomEmojiView; +use lemmy_db_views::structs::{CustomEmojiView, LocalUserView}; use lemmy_utils::error::LemmyError; #[tracing::instrument(skip(context))] pub async fn create_custom_emoji( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let local_site = LocalSite::read(&mut context.pool()).await?; // Make sure user is an admin is_admin(&local_user_view)?; diff --git a/crates/api_crud/src/custom_emoji/delete.rs b/crates/api_crud/src/custom_emoji/delete.rs index be88d310f..44cddd520 100644 --- a/crates/api_crud/src/custom_emoji/delete.rs +++ b/crates/api_crud/src/custom_emoji/delete.rs @@ -3,18 +3,18 @@ use actix_web::web::Json; use lemmy_api_common::{ context::LemmyContext, custom_emoji::{DeleteCustomEmoji, DeleteCustomEmojiResponse}, - utils::{is_admin, local_user_view_from_jwt}, + utils::is_admin, }; use lemmy_db_schema::source::custom_emoji::CustomEmoji; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::error::LemmyError; #[tracing::instrument(skip(context))] pub async fn delete_custom_emoji( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - // Make sure user is an admin is_admin(&local_user_view)?; CustomEmoji::delete(&mut context.pool(), data.id).await?; diff --git a/crates/api_crud/src/custom_emoji/update.rs b/crates/api_crud/src/custom_emoji/update.rs index 965250feb..5c115d5c1 100644 --- a/crates/api_crud/src/custom_emoji/update.rs +++ b/crates/api_crud/src/custom_emoji/update.rs @@ -3,23 +3,22 @@ use actix_web::web::Json; use lemmy_api_common::{ context::LemmyContext, custom_emoji::{CustomEmojiResponse, EditCustomEmoji}, - utils::{is_admin, local_user_view_from_jwt, sanitize_html_api}, + utils::{is_admin, sanitize_html_api}, }; use lemmy_db_schema::source::{ custom_emoji::{CustomEmoji, CustomEmojiUpdateForm}, custom_emoji_keyword::{CustomEmojiKeyword, CustomEmojiKeywordInsertForm}, local_site::LocalSite, }; -use lemmy_db_views::structs::CustomEmojiView; +use lemmy_db_views::structs::{CustomEmojiView, LocalUserView}; use lemmy_utils::error::LemmyError; #[tracing::instrument(skip(context))] pub async fn update_custom_emoji( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let local_site = LocalSite::read(&mut context.pool()).await?; // Make sure user is an admin is_admin(&local_user_view)?; diff --git a/crates/api_crud/src/post/create.rs b/crates/api_crud/src/post/create.rs index 8cc6ffe62..4fb97c1c7 100644 --- a/crates/api_crud/src/post/create.rs +++ b/crates/api_crud/src/post/create.rs @@ -12,7 +12,6 @@ use lemmy_api_common::{ generate_local_apub_endpoint, honeypot_check, local_site_to_slur_regex, - local_user_view_from_jwt, mark_post_as_read, sanitize_html_api, sanitize_html_api_opt, @@ -29,6 +28,7 @@ use lemmy_db_schema::{ }, traits::{Crud, Likeable}, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::CommunityView; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, @@ -46,8 +46,8 @@ use webmention::{Webmention, WebmentionError}; pub async fn create_post( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let local_site = LocalSite::read(&mut context.pool()).await?; let slur_regex = local_site_to_slur_regex(&local_site); @@ -175,7 +175,7 @@ pub async fn create_post( mark_post_as_read(person_id, post_id, &mut context.pool()).await?; if let Some(url) = updated_post.url.clone() { - let task = async move { + spawn_try_task(async move { let mut webmention = Webmention::new::(updated_post.ap_id.clone().into(), url.clone().into())?; webmention.set_checked(true); @@ -188,8 +188,7 @@ pub async fn create_post( Ok(_) => Ok(()), Err(e) => Err(e).with_lemmy_type(LemmyErrorType::CouldntSendWebmention), } - }; - spawn_try_task(task); + }); }; build_post_response(&context, community_id, person_id, post_id).await diff --git a/crates/api_crud/src/post/delete.rs b/crates/api_crud/src/post/delete.rs index 0f471a527..90c95c6b2 100644 --- a/crates/api_crud/src/post/delete.rs +++ b/crates/api_crud/src/post/delete.rs @@ -5,21 +5,21 @@ use lemmy_api_common::{ context::LemmyContext, post::{DeletePost, PostResponse}, send_activity::{ActivityChannel, SendActivityData}, - utils::{check_community_ban, check_community_deleted_or_removed, local_user_view_from_jwt}, + utils::{check_community_ban, check_community_deleted_or_removed}, }; use lemmy_db_schema::{ source::post::{Post, PostUpdateForm}, traits::Crud, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::error::{LemmyError, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn delete_post( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let post_id = data.post_id; let orig_post = Post::read(&mut context.pool(), post_id).await?; diff --git a/crates/api_crud/src/post/read.rs b/crates/api_crud/src/post/read.rs index d37b1a582..352f97fe1 100644 --- a/crates/api_crud/src/post/read.rs +++ b/crates/api_crud/src/post/read.rs @@ -2,19 +2,17 @@ use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, post::{GetPost, GetPostResponse}, - utils::{ - check_private_instance, - is_mod_or_admin_opt, - local_user_view_from_jwt_opt, - mark_post_as_read, - }, + utils::{check_private_instance, is_mod_or_admin_opt, mark_post_as_read}, }; use lemmy_db_schema::{ aggregates::structs::{PersonPostAggregates, PersonPostAggregatesForm}, source::{comment::Comment, local_site::LocalSite, post::Post}, traits::Crud, }; -use lemmy_db_views::{post_view::PostQuery, structs::PostView}; +use lemmy_db_views::{ + post_view::PostQuery, + structs::{LocalUserView, PostView}, +}; use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; @@ -22,8 +20,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; pub async fn get_post( data: Query, context: Data, + local_user_view: Option, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await; let local_site = LocalSite::read(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site)?; diff --git a/crates/api_crud/src/post/remove.rs b/crates/api_crud/src/post/remove.rs index ee100cfdc..52f380d88 100644 --- a/crates/api_crud/src/post/remove.rs +++ b/crates/api_crud/src/post/remove.rs @@ -5,7 +5,7 @@ use lemmy_api_common::{ context::LemmyContext, post::{PostResponse, RemovePost}, send_activity::{ActivityChannel, SendActivityData}, - utils::{check_community_ban, is_mod_or_admin, local_user_view_from_jwt}, + utils::{check_community_ban, is_mod_or_admin}, }; use lemmy_db_schema::{ source::{ @@ -14,15 +14,15 @@ use lemmy_db_schema::{ }, traits::Crud, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::error::LemmyError; #[tracing::instrument(skip(context))] pub async fn remove_post( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - let post_id = data.post_id; let orig_post = Post::read(&mut context.pool(), post_id).await?; diff --git a/crates/api_crud/src/post/update.rs b/crates/api_crud/src/post/update.rs index 880991b8e..04e6191a8 100644 --- a/crates/api_crud/src/post/update.rs +++ b/crates/api_crud/src/post/update.rs @@ -6,12 +6,7 @@ use lemmy_api_common::{ post::{EditPost, PostResponse}, request::fetch_site_data, send_activity::{ActivityChannel, SendActivityData}, - utils::{ - check_community_ban, - local_site_to_slur_regex, - local_user_view_from_jwt, - sanitize_html_api_opt, - }, + utils::{check_community_ban, local_site_to_slur_regex, sanitize_html_api_opt}, }; use lemmy_db_schema::{ source::{ @@ -22,6 +17,7 @@ use lemmy_db_schema::{ traits::Crud, utils::{diesel_option_overwrite, naive_now}, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, utils::{ @@ -35,8 +31,8 @@ use std::ops::Deref; pub async fn update_post( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let local_site = LocalSite::read(&mut context.pool()).await?; let data_url = data.url.as_ref(); diff --git a/crates/api_crud/src/private_message/create.rs b/crates/api_crud/src/private_message/create.rs index 1e22935ce..c0bdb8ed1 100644 --- a/crates/api_crud/src/private_message/create.rs +++ b/crates/api_crud/src/private_message/create.rs @@ -9,7 +9,6 @@ use lemmy_api_common::{ generate_local_apub_endpoint, get_interface_language, local_site_to_slur_regex, - local_user_view_from_jwt, sanitize_html_api, send_email_to_user, EndpointType, @@ -32,8 +31,8 @@ use lemmy_utils::{ pub async fn create_private_message( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let local_site = LocalSite::read(&mut context.pool()).await?; let content = sanitize_html_api(&data.content); diff --git a/crates/api_crud/src/private_message/delete.rs b/crates/api_crud/src/private_message/delete.rs index 65db3b1c1..ef0864d70 100644 --- a/crates/api_crud/src/private_message/delete.rs +++ b/crates/api_crud/src/private_message/delete.rs @@ -4,22 +4,20 @@ use lemmy_api_common::{ context::LemmyContext, private_message::{DeletePrivateMessage, PrivateMessageResponse}, send_activity::{ActivityChannel, SendActivityData}, - utils::local_user_view_from_jwt, }; use lemmy_db_schema::{ source::private_message::{PrivateMessage, PrivateMessageUpdateForm}, traits::Crud, }; -use lemmy_db_views::structs::PrivateMessageView; +use lemmy_db_views::structs::{LocalUserView, PrivateMessageView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn delete_private_message( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - // Checking permissions let private_message_id = data.private_message_id; let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?; diff --git a/crates/api_crud/src/private_message/read.rs b/crates/api_crud/src/private_message/read.rs index 0d3ba8620..933d410f1 100644 --- a/crates/api_crud/src/private_message/read.rs +++ b/crates/api_crud/src/private_message/read.rs @@ -2,17 +2,16 @@ use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, private_message::{GetPrivateMessages, PrivateMessagesResponse}, - utils::local_user_view_from_jwt, }; -use lemmy_db_views::private_message_view::PrivateMessageQuery; +use lemmy_db_views::{private_message_view::PrivateMessageQuery, structs::LocalUserView}; use lemmy_utils::error::LemmyError; #[tracing::instrument(skip(context))] pub async fn get_private_message( data: Query, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(data.auth.as_ref(), &context).await?; let person_id = local_user_view.person.id; let page = data.page; diff --git a/crates/api_crud/src/private_message/update.rs b/crates/api_crud/src/private_message/update.rs index 258dd8bcb..7e55c6416 100644 --- a/crates/api_crud/src/private_message/update.rs +++ b/crates/api_crud/src/private_message/update.rs @@ -4,7 +4,7 @@ use lemmy_api_common::{ context::LemmyContext, private_message::{EditPrivateMessage, PrivateMessageResponse}, send_activity::{ActivityChannel, SendActivityData}, - utils::{local_site_to_slur_regex, local_user_view_from_jwt, sanitize_html_api}, + utils::{local_site_to_slur_regex, sanitize_html_api}, }; use lemmy_db_schema::{ source::{ @@ -14,7 +14,7 @@ use lemmy_db_schema::{ traits::Crud, utils::naive_now, }; -use lemmy_db_views::structs::PrivateMessageView; +use lemmy_db_views::structs::{LocalUserView, PrivateMessageView}; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, utils::{slurs::remove_slurs, validation::is_valid_body_field}, @@ -24,8 +24,8 @@ use lemmy_utils::{ pub async fn update_private_message( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let local_site = LocalSite::read(&mut context.pool()).await?; // Checking permissions diff --git a/crates/api_crud/src/site/create.rs b/crates/api_crud/src/site/create.rs index 5cf9a04a7..136a187f2 100644 --- a/crates/api_crud/src/site/create.rs +++ b/crates/api_crud/src/site/create.rs @@ -8,7 +8,6 @@ use lemmy_api_common::{ generate_site_inbox_url, is_admin, local_site_rate_limit_to_rate_limit_config, - local_user_view_from_jwt, sanitize_html_api, sanitize_html_api_opt, }, @@ -24,7 +23,7 @@ use lemmy_db_schema::{ traits::Crud, utils::{diesel_option_overwrite, diesel_option_overwrite_to_url, naive_now}, }; -use lemmy_db_views::structs::SiteView; +use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_utils::{ error::{LemmyError, LemmyErrorType, LemmyResult}, utils::{ @@ -44,8 +43,8 @@ use url::Url; pub async fn create_site( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let local_site = LocalSite::read(&mut context.pool()).await?; // Make sure user is an admin; other types of users should not create site data... @@ -589,7 +588,6 @@ mod tests { blocked_instances: None, taglines: None, registration_mode: site_registration_mode, - auth: Default::default(), } } } diff --git a/crates/api_crud/src/site/read.rs b/crates/api_crud/src/site/read.rs index d435b8684..2f16b8696 100644 --- a/crates/api_crud/src/site/read.rs +++ b/crates/api_crud/src/site/read.rs @@ -1,17 +1,12 @@ -use actix_web::web::{Data, Json, Query}; +use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, - sensitive::Sensitive, - site::{GetSite, GetSiteResponse, MyUserInfo}, - utils::{check_user_valid, check_validator_time}, + site::{GetSiteResponse, MyUserInfo}, }; -use lemmy_db_schema::{ - newtypes::LocalUserId, - source::{ - actor_language::{LocalUserLanguage, SiteLanguage}, - language::Language, - tagline::Tagline, - }, +use lemmy_db_schema::source::{ + actor_language::{LocalUserLanguage, SiteLanguage}, + language::Language, + tagline::Tagline, }; use lemmy_db_views::structs::{CustomEmojiView, LocalUserView, SiteView}; use lemmy_db_views_actor::structs::{ @@ -23,24 +18,21 @@ use lemmy_db_views_actor::structs::{ PersonView, }; use lemmy_utils::{ - claims::Claims, error::{LemmyError, LemmyErrorExt, LemmyErrorType}, version, }; #[tracing::instrument(skip(context))] pub async fn get_site( - data: Query, context: Data, + local_user_view: Option, ) -> Result, LemmyError> { let site_view = SiteView::read_local(&mut context.pool()).await?; let admins = PersonView::admins(&mut context.pool()).await?; // Build the local user - let my_user = if let Some(local_user_view) = - local_user_settings_view_from_jwt_opt(data.auth.as_ref(), &context).await - { + let my_user = if let Some(local_user_view) = local_user_view { let person_id = local_user_view.person.id; let local_user_id = local_user_view.local_user.id; @@ -100,32 +92,3 @@ pub async fn get_site( custom_emojis, })) } - -#[tracing::instrument(skip_all)] -async fn local_user_settings_view_from_jwt_opt( - jwt: Option<&Sensitive>, - context: &LemmyContext, -) -> Option { - match jwt { - Some(jwt) => { - let claims = Claims::decode(jwt.as_ref(), &context.secret().jwt_secret) - .ok()? - .claims; - let local_user_id = LocalUserId(claims.sub); - let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id) - .await - .ok()?; - check_user_valid( - local_user_view.person.banned, - local_user_view.person.ban_expires, - local_user_view.person.deleted, - ) - .ok()?; - - check_validator_time(&local_user_view.local_user.validator_time, &claims).ok()?; - - Some(local_user_view) - } - None => None, - } -} diff --git a/crates/api_crud/src/site/update.rs b/crates/api_crud/src/site/update.rs index 4d1fbd4d9..792faa785 100644 --- a/crates/api_crud/src/site/update.rs +++ b/crates/api_crud/src/site/update.rs @@ -3,12 +3,7 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, site::{EditSite, SiteResponse}, - utils::{ - is_admin, - local_site_rate_limit_to_rate_limit_config, - local_user_view_from_jwt, - sanitize_html_api_opt, - }, + utils::{is_admin, local_site_rate_limit_to_rate_limit_config, sanitize_html_api_opt}, }; use lemmy_db_schema::{ source::{ @@ -25,7 +20,7 @@ use lemmy_db_schema::{ utils::{diesel_option_overwrite, diesel_option_overwrite_to_url, naive_now}, RegistrationMode, }; -use lemmy_db_views::structs::SiteView; +use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult}, utils::{ @@ -44,8 +39,8 @@ use lemmy_utils::{ pub async fn update_site( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; let site_view = SiteView::read_local(&mut context.pool()).await?; let local_site = site_view.local_site; let site = site_view.site; @@ -588,7 +583,6 @@ mod tests { taglines: None, registration_mode: site_registration_mode, reports_email_admins: None, - auth: Default::default(), } } } diff --git a/crates/api_crud/src/user/delete.rs b/crates/api_crud/src/user/delete.rs index bf1dcdab1..b3abb532f 100644 --- a/crates/api_crud/src/user/delete.rs +++ b/crates/api_crud/src/user/delete.rs @@ -5,18 +5,18 @@ use lemmy_api_common::{ context::LemmyContext, person::{DeleteAccount, DeleteAccountResponse}, send_activity::{ActivityChannel, SendActivityData}, - utils::{local_user_view_from_jwt, purge_user_account}, + utils::purge_user_account, }; use lemmy_db_schema::source::person::Person; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::error::{LemmyError, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn delete_account( data: Json, context: Data, + local_user_view: LocalUserView, ) -> Result, LemmyError> { - let local_user_view = local_user_view_from_jwt(data.auth.as_ref(), &context).await?; - // Verify the password let valid: bool = verify( &data.password, diff --git a/crates/apub/src/activities/community/announce.rs b/crates/apub/src/activities/community/announce.rs index 5939c023a..e84a970f3 100644 --- a/crates/apub/src/activities/community/announce.rs +++ b/crates/apub/src/activities/community/announce.rs @@ -1,6 +1,7 @@ use crate::{ activities::{ generate_activity_id, + generate_announce_activity_id, send_lemmy_activity, verify_is_public, verify_person_in_community, @@ -75,16 +76,20 @@ impl AnnounceActivity { community: &ApubCommunity, context: &Data, ) -> Result { + let inner_kind = object + .other + .get("type") + .and_then(serde_json::Value::as_str) + .unwrap_or("other"); + let id = + generate_announce_activity_id(inner_kind, &context.settings().get_protocol_and_hostname())?; Ok(AnnounceActivity { actor: community.id().into(), to: vec![public()], object: IdOrNestedObject::NestedObject(object), cc: vec![community.followers_url.clone().into()], kind: AnnounceType::Announce, - id: generate_activity_id( - &AnnounceType::Announce, - &context.settings().get_protocol_and_hostname(), - )?, + id, }) } diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index 29ec5bd30..958065ffa 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -28,12 +28,15 @@ use crate::{ use activitypub_federation::{ config::Data, fetch::object_id::ObjectId, - kinds::public, + kinds::{activity::AnnounceType, public}, protocol::context::WithContext, traits::{ActivityHandler, Actor}, }; use anyhow::anyhow; -use lemmy_api_common::{context::LemmyContext, send_activity::SendActivityData}; +use lemmy_api_common::{ + context::LemmyContext, + send_activity::{ActivityChannel, SendActivityData}, +}; use lemmy_db_schema::{ newtypes::CommunityId, source::{ @@ -42,10 +45,7 @@ use lemmy_db_schema::{ }, }; use lemmy_db_views_actor::structs::{CommunityPersonBanView, CommunityView}; -use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult}, - spawn_try_task, -}; +use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult}; use serde::Serialize; use std::{ops::Deref, time::Duration}; use tracing::info; @@ -181,6 +181,21 @@ where Url::parse(&id) } +/// like generate_activity_id but also add the inner kind for easier debugging +fn generate_announce_activity_id( + inner_kind: &str, + protocol_and_hostname: &str, +) -> Result { + let id = format!( + "{}/activities/{}/{}/{}", + protocol_and_hostname, + AnnounceType::Announce.to_string().to_lowercase(), + inner_kind.to_lowercase(), + Uuid::new_v4() + ); + Url::parse(&id) +} + pub(crate) trait GetActorType { fn actor_type(&self) -> ActorType; } @@ -198,12 +213,12 @@ where ActorT: Actor + GetActorType, Activity: ActivityHandler, { - info!("Sending activity {}", activity.id().to_string()); + info!("Saving outgoing activity to queue {}", activity.id()); let activity = WithContext::new(activity, CONTEXT.deref().clone()); let form = SentActivityForm { ap_id: activity.id().clone().into(), - data: serde_json::to_value(activity.clone())?, + data: serde_json::to_value(activity)?, sensitive, send_inboxes: send_targets .inboxes @@ -220,6 +235,13 @@ where Ok(()) } +pub async fn handle_outgoing_activities(context: Data) -> LemmyResult<()> { + while let Some(data) = ActivityChannel::retrieve_activity().await { + match_outgoing_activities(data, &context.reset_request_count()).await? + } + Ok(()) +} + pub async fn match_outgoing_activities( data: SendActivityData, context: &Data, @@ -324,6 +346,6 @@ pub async fn match_outgoing_activities( } } }; - spawn_try_task(fed_task); + fed_task.await?; Ok(()) } diff --git a/crates/apub/src/api/list_comments.rs b/crates/apub/src/api/list_comments.rs index cec2ed9c5..7d1de019e 100644 --- a/crates/apub/src/api/list_comments.rs +++ b/crates/apub/src/api/list_comments.rs @@ -8,7 +8,7 @@ use actix_web::web::{Json, Query}; use lemmy_api_common::{ comment::{GetComments, GetCommentsResponse}, context::LemmyContext, - utils::{check_private_instance, local_user_view_from_jwt_opt_new}, + utils::check_private_instance, }; use lemmy_db_schema::{ source::{comment::Comment, community::Community, local_site::LocalSite}, @@ -21,9 +21,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; pub async fn list_comments( data: Query, context: Data, - mut local_user_view: Option, + local_user_view: Option, ) -> Result, LemmyError> { - local_user_view_from_jwt_opt_new(&mut local_user_view, data.auth.as_ref(), &context).await; let local_site = LocalSite::read(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site)?; diff --git a/crates/apub/src/api/list_posts.rs b/crates/apub/src/api/list_posts.rs index 425e2adf2..dc3618c50 100644 --- a/crates/apub/src/api/list_posts.rs +++ b/crates/apub/src/api/list_posts.rs @@ -8,7 +8,7 @@ use actix_web::web::{Json, Query}; use lemmy_api_common::{ context::LemmyContext, post::{GetPosts, GetPostsResponse}, - utils::{check_private_instance, local_user_view_from_jwt_opt_new}, + utils::check_private_instance, }; use lemmy_db_schema::source::{community::Community, local_site::LocalSite}; use lemmy_db_views::{ @@ -21,9 +21,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; pub async fn list_posts( data: Query, context: Data, - mut local_user_view: Option, + local_user_view: Option, ) -> Result, LemmyError> { - local_user_view_from_jwt_opt_new(&mut local_user_view, data.auth.as_ref(), &context).await; let local_site = LocalSite::read(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site)?; diff --git a/crates/apub/src/api/read_community.rs b/crates/apub/src/api/read_community.rs index 76f7f580d..afa6fb829 100644 --- a/crates/apub/src/api/read_community.rs +++ b/crates/apub/src/api/read_community.rs @@ -4,7 +4,7 @@ use actix_web::web::{Json, Query}; use lemmy_api_common::{ community::{GetCommunity, GetCommunityResponse}, context::LemmyContext, - utils::{check_private_instance, is_mod_or_admin_opt, local_user_view_from_jwt_opt_new}, + utils::{check_private_instance, is_mod_or_admin_opt}, }; use lemmy_db_schema::source::{ actor_language::CommunityLanguage, @@ -20,9 +20,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorExt2, LemmyErrorTy pub async fn get_community( data: Query, context: Data, - mut local_user_view: Option, + local_user_view: Option, ) -> Result, LemmyError> { - local_user_view_from_jwt_opt_new(&mut local_user_view, data.auth.as_ref(), &context).await; let local_site = LocalSite::read(&mut context.pool()).await?; if data.name.is_none() && data.id.is_none() { diff --git a/crates/apub/src/api/read_person.rs b/crates/apub/src/api/read_person.rs index 754a942f1..26ad287f1 100644 --- a/crates/apub/src/api/read_person.rs +++ b/crates/apub/src/api/read_person.rs @@ -4,7 +4,7 @@ use actix_web::web::{Json, Query}; use lemmy_api_common::{ context::LemmyContext, person::{GetPersonDetails, GetPersonDetailsResponse}, - utils::{check_private_instance, local_user_view_from_jwt_opt_new}, + utils::check_private_instance, }; use lemmy_db_schema::{ source::{local_site::LocalSite, person::Person}, @@ -18,14 +18,13 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt2, LemmyErrorType}; pub async fn read_person( data: Query, context: Data, - mut local_user_view: Option, + local_user_view: Option, ) -> Result, LemmyError> { // Check to make sure a person name or an id is given if data.username.is_none() && data.person_id.is_none() { Err(LemmyErrorType::NoIdGiven)? } - local_user_view_from_jwt_opt_new(&mut local_user_view, data.auth.as_ref(), &context).await; let local_site = LocalSite::read(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site)?; diff --git a/crates/apub/src/api/resolve_object.rs b/crates/apub/src/api/resolve_object.rs index b8c0cef14..e081377f6 100644 --- a/crates/apub/src/api/resolve_object.rs +++ b/crates/apub/src/api/resolve_object.rs @@ -9,7 +9,7 @@ use diesel::NotFound; use lemmy_api_common::{ context::LemmyContext, site::{ResolveObject, ResolveObjectResponse}, - utils::{check_private_instance, local_user_view_from_jwt_opt_new}, + utils::check_private_instance, }; use lemmy_db_schema::{newtypes::PersonId, source::local_site::LocalSite, utils::DbPool}; use lemmy_db_views::structs::{CommentView, LocalUserView, PostView}; @@ -20,9 +20,8 @@ use lemmy_utils::error::{LemmyError, LemmyErrorExt2, LemmyErrorType}; pub async fn resolve_object( data: Query, context: Data, - mut local_user_view: Option, + local_user_view: Option, ) -> Result, LemmyError> { - local_user_view_from_jwt_opt_new(&mut local_user_view, data.auth.as_ref(), &context).await; let local_site = LocalSite::read(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site)?; let person_id = local_user_view.map(|v| v.person.id); diff --git a/crates/apub/src/api/search.rs b/crates/apub/src/api/search.rs index 262f91681..0c7231e8f 100644 --- a/crates/apub/src/api/search.rs +++ b/crates/apub/src/api/search.rs @@ -4,7 +4,7 @@ use actix_web::web::{Json, Query}; use lemmy_api_common::{ context::LemmyContext, site::{Search, SearchResponse}, - utils::{check_private_instance, is_admin, local_user_view_from_jwt_opt_new}, + utils::{check_private_instance, is_admin}, }; use lemmy_db_schema::{ source::{community::Community, local_site::LocalSite}, @@ -19,9 +19,8 @@ use lemmy_utils::error::LemmyError; pub async fn search( data: Query, context: Data, - mut local_user_view: Option, + local_user_view: Option, ) -> Result, LemmyError> { - local_user_view_from_jwt_opt_new(&mut local_user_view, data.auth.as_ref(), &context).await; let local_site = LocalSite::read(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site)?; diff --git a/crates/federate/src/util.rs b/crates/federate/src/util.rs index 4f260708d..f744d45f4 100644 --- a/crates/federate/src/util.rs +++ b/crates/federate/src/util.rs @@ -1,8 +1,5 @@ use anyhow::{anyhow, Context, Result}; -use diesel::{ - prelude::*, - sql_types::{Bool, Int8}, -}; +use diesel::prelude::*; use diesel_async::RunQueryDsl; use lemmy_apub::{ activity_lists::SharedInboxActivities, @@ -31,6 +28,26 @@ use std::{ use tokio::{task::JoinHandle, time::sleep}; use tokio_util::sync::CancellationToken; +/// Decrease the delays of the federation queue. +/// Should only be used for federation tests since it significantly increases CPU and DB load of the federation queue. +pub(crate) static LEMMY_TEST_FAST_FEDERATION: Lazy = Lazy::new(|| { + std::env::var("LEMMY_TEST_FAST_FEDERATION") + .map(|s| !s.is_empty()) + .unwrap_or(false) +}); +/// Recheck for new federation work every n seconds. +/// +/// When the queue is processed faster than new activities are added and it reaches the current time with an empty batch, +/// this is the delay the queue waits before it checks if new activities have been added to the sent_activities table. +/// This delay is only applied if no federated activity happens during sending activities of the last batch. +pub(crate) static WORK_FINISHED_RECHECK_DELAY: Lazy = Lazy::new(|| { + if *LEMMY_TEST_FAST_FEDERATION { + Duration::from_millis(100) + } else { + Duration::from_secs(30) + } +}); + pub struct CancellableTask { f: Pin> + Send + 'static>>, ended: Arc>, @@ -162,22 +179,20 @@ pub(crate) async fn get_activity_cached( pub(crate) async fn get_latest_activity_id(pool: &mut DbPool<'_>) -> Result { static CACHE: Lazy> = Lazy::new(|| { Cache::builder() - .time_to_live(Duration::from_secs(1)) + .time_to_live(if *LEMMY_TEST_FAST_FEDERATION { + *WORK_FINISHED_RECHECK_DELAY + } else { + Duration::from_secs(1) + }) .build() }); CACHE .try_get_with((), async { + use diesel::dsl::max; + use lemmy_db_schema::schema::sent_activity::dsl::{id, sent_activity}; let conn = &mut get_conn(pool).await?; - let seq: Sequence = - diesel::sql_query("select last_value, is_called from sent_activity_id_seq") - .get_result(conn) - .await?; - let latest_id = if seq.is_called { - seq.last_value as ActivityId - } else { - // if a PG sequence has never been used, last_value will actually be next_value - (seq.last_value - 1) as ActivityId - }; + let seq: Option = sent_activity.select(max(id)).get_result(conn).await?; + let latest_id = seq.unwrap_or(0); anyhow::Result::<_, anyhow::Error>::Ok(latest_id as ActivityId) }) .await @@ -188,11 +203,3 @@ pub(crate) async fn get_latest_activity_id(pool: &mut DbPool<'_>) -> Result Duration { Duration::from_secs_f64(10.0 * 2.0_f64.powf(f64::from(retry_count))) } - -#[derive(QueryableByName)] -struct Sequence { - #[diesel(sql_type = Int8)] - last_value: i64, // this value is bigint for some reason even if sequence is int4 - #[diesel(sql_type = Bool)] - is_called: bool, -} diff --git a/crates/federate/src/worker.rs b/crates/federate/src/worker.rs index a2bdf33c2..3eda2e746 100644 --- a/crates/federate/src/worker.rs +++ b/crates/federate/src/worker.rs @@ -1,6 +1,13 @@ use crate::{ federation_queue_state::FederationQueueState, - util::{get_activity_cached, get_actor_cached, get_latest_activity_id, retry_sleep_duration}, + util::{ + get_activity_cached, + get_actor_cached, + get_latest_activity_id, + retry_sleep_duration, + LEMMY_TEST_FAST_FEDERATION, + WORK_FINISHED_RECHECK_DELAY, + }, }; use activitypub_federation::{activity_sending::SendActivityTask, config::Data}; use anyhow::{Context, Result}; @@ -22,20 +29,27 @@ use std::{ }; use tokio::{sync::mpsc::UnboundedSender, time::sleep}; use tokio_util::sync::CancellationToken; -/// save state to db every n sends if there's no failures (otherwise state is saved after every attempt) + +/// Check whether to save state to db every n sends if there's no failures (during failures state is saved after every attempt) +/// This determines the batch size for loop_batch. After a batch ends and SAVE_STATE_EVERY_TIME has passed, the federation_queue_state is updated in the DB. static CHECK_SAVE_STATE_EVERY_IT: i64 = 100; +/// Save state to db after this time has passed since the last state (so if the server crashes or is SIGKILLed, less than X seconds of activities are resent) static SAVE_STATE_EVERY_TIME: Duration = Duration::from_secs(60); -/// recheck for new federation work every n seconds -#[cfg(debug_assertions)] -static WORK_FINISHED_RECHECK_DELAY: Duration = Duration::from_secs(1); -#[cfg(not(debug_assertions))] -static WORK_FINISHED_RECHECK_DELAY: Duration = Duration::from_secs(30); -#[cfg(debug_assertions)] -static FOLLOW_ADDITIONS_RECHECK_DELAY: Lazy = - Lazy::new(|| chrono::Duration::seconds(1)); -#[cfg(not(debug_assertions))] -static FOLLOW_ADDITIONS_RECHECK_DELAY: Lazy = - Lazy::new(|| chrono::Duration::minutes(1)); +/// interval with which new additions to community_followers are queried. +/// +/// The first time some user on an instance follows a specific remote community (or, more precisely: the first time a (followed_community_id, follower_inbox_url) tuple appears), +/// this delay limits the maximum time until the follow actually results in activities from that community id being sent to that inbox url. +/// This delay currently needs to not be too small because the DB load is currently fairly high because of the current structure of storing inboxes for every person, not having a separate list of shared_inboxes, and the architecture of having every instance queue be fully separate. +/// (see https://github.com/LemmyNet/lemmy/issues/3958) +static FOLLOW_ADDITIONS_RECHECK_DELAY: Lazy = Lazy::new(|| { + if *LEMMY_TEST_FAST_FEDERATION { + chrono::Duration::seconds(1) + } else { + chrono::Duration::minutes(2) + } +}); +/// The same as FOLLOW_ADDITIONS_RECHECK_DELAY, but triggering when the last person on an instance unfollows a specific remote community. +/// This is expected to happen pretty rarely and updating it in a timely manner is not too important. static FOLLOW_REMOVALS_RECHECK_DELAY: Lazy = Lazy::new(|| chrono::Duration::hours(1)); pub(crate) struct InstanceWorker { @@ -121,6 +135,7 @@ impl InstanceWorker { } Ok(()) } + /// send out a batch of CHECK_SAVE_STATE_EVERY_IT activities async fn loop_batch(&mut self, pool: &mut DbPool<'_>) -> Result<()> { let latest_id = get_latest_activity_id(pool).await?; if self.state.last_successful_id == -1 { @@ -134,7 +149,7 @@ impl InstanceWorker { if id == latest_id { // no more work to be done, wait before rechecking tokio::select! { - () = sleep(WORK_FINISHED_RECHECK_DELAY) => {}, + () = sleep(*WORK_FINISHED_RECHECK_DELAY) => {}, () = self.stop.cancelled() => {} } return Ok(()); @@ -254,7 +269,8 @@ impl InstanceWorker { .send_inboxes .iter() .filter_map(std::option::Option::as_ref) - .filter_map(|u| (u.domain() == Some(&self.instance.domain)).then(|| u.inner().clone())), + .filter(|&u| (u.domain() == Some(&self.instance.domain))) + .map(|u| u.inner().clone()), ); Ok(inbox_urls) } @@ -263,7 +279,7 @@ impl InstanceWorker { if (Utc::now() - self.last_full_communities_fetch) > *FOLLOW_REMOVALS_RECHECK_DELAY { // process removals every hour (self.followed_communities, self.last_full_communities_fetch) = self - .get_communities(pool, self.instance.id, self.last_full_communities_fetch) + .get_communities(pool, self.instance.id, Utc.timestamp_nanos(0)) .await?; self.last_incremental_communities_fetch = self.last_full_communities_fetch; } @@ -289,13 +305,13 @@ impl InstanceWorker { instance_id: InstanceId, last_fetch: DateTime, ) -> Result<(HashMap>, DateTime)> { - let new_last_fetch = Utc::now(); // update to time before fetch to ensure overlap + let new_last_fetch = Utc::now() - chrono::Duration::seconds(10); // update to time before fetch to ensure overlap. subtract 10s to ensure overlap even if published date is not exact Ok(( CommunityFollowerView::get_instance_followed_community_inboxes(pool, instance_id, last_fetch) .await? .into_iter() .fold(HashMap::new(), |mut map, (c, u)| { - map.entry(c).or_insert_with(HashSet::new).insert(u.into()); + map.entry(c).or_default().insert(u.into()); map }), new_last_fetch, diff --git a/crates/routes/src/images.rs b/crates/routes/src/images.rs index 5133cfd82..db3341418 100644 --- a/crates/routes/src/images.rs +++ b/crates/routes/src/images.rs @@ -11,15 +11,13 @@ use actix_web::{ HttpResponse, }; use futures::stream::{Stream, StreamExt}; -use lemmy_api_common::{context::LemmyContext, utils::local_user_view_from_jwt}; -use lemmy_db_schema::{ - newtypes::LocalUserId, - source::{ - image_upload::{ImageUpload, ImageUploadForm}, - local_site::LocalSite, - }, +use lemmy_api_common::context::LemmyContext; +use lemmy_db_schema::source::{ + image_upload::{ImageUpload, ImageUploadForm}, + local_site::LocalSite, }; -use lemmy_utils::{claims::Claims, rate_limit::RateLimitCell, REQWEST_TIMEOUT}; +use lemmy_db_views::structs::LocalUserView; +use lemmy_utils::{rate_limit::RateLimitCell, REQWEST_TIMEOUT}; use reqwest::Body; use reqwest_middleware::{ClientWithMiddleware, RequestBuilder}; use serde::{Deserialize, Serialize}; @@ -96,15 +94,10 @@ async fn upload( body: web::Payload, client: web::Data, context: web::Data, + // require login + local_user_view: LocalUserView, ) -> Result { // TODO: check rate limit here - let jwt = req.cookie("jwt").ok_or(error::ErrorUnauthorized( - "No auth header for picture upload", - ))?; - let claims = Claims::decode(jwt.value(), &context.secret().jwt_secret); - if claims.is_err() { - return Ok(HttpResponse::Unauthorized().finish()); - }; let pictrs_config = context.settings().pictrs_config()?; let image_url = format!("{}image", pictrs_config.url); @@ -123,10 +116,9 @@ async fn upload( let status = res.status(); let images = res.json::().await.map_err(error::ErrorBadRequest)?; if let Some(images) = &images.files { - let local_user_id = LocalUserId(claims?.claims.sub); for uploaded_image in images { let form = ImageUploadForm { - local_user_id, + local_user_id: local_user_view.local_user.id, pictrs_alias: uploaded_image.file.to_string(), pictrs_delete_token: uploaded_image.delete_token.to_string(), }; @@ -145,21 +137,14 @@ async fn full_res( req: HttpRequest, client: web::Data, context: web::Data, + local_user_view: Option, ) -> Result { // block access to images if instance is private and unauthorized, public let local_site = LocalSite::read(&mut context.pool()) .await .map_err(error::ErrorBadRequest)?; - if local_site.private_instance { - let jwt = req.cookie("jwt").ok_or(error::ErrorUnauthorized( - "No auth header for picture access", - ))?; - if local_user_view_from_jwt(jwt.value(), &context) - .await - .is_err() - { - return Ok(HttpResponse::Unauthorized().finish()); - }; + if local_site.private_instance && local_user_view.is_none() { + return Ok(HttpResponse::Unauthorized().finish()); } let name = &filename.into_inner(); @@ -219,6 +204,8 @@ async fn delete( req: HttpRequest, client: web::Data, context: web::Data, + // require login + _local_user_view: LocalUserView, ) -> Result { let (token, file) = components.into_inner(); diff --git a/migrations/2023-09-12-194850_add_federation_worker_index/down.sql b/migrations/2023-09-12-194850_add_federation_worker_index/down.sql new file mode 100644 index 000000000..a203e8087 --- /dev/null +++ b/migrations/2023-09-12-194850_add_federation_worker_index/down.sql @@ -0,0 +1,2 @@ +DROP INDEX idx_person_local_instance; + diff --git a/migrations/2023-09-12-194850_add_federation_worker_index/up.sql b/migrations/2023-09-12-194850_add_federation_worker_index/up.sql new file mode 100644 index 000000000..bbbab0b1f --- /dev/null +++ b/migrations/2023-09-12-194850_add_federation_worker_index/up.sql @@ -0,0 +1,2 @@ +CREATE INDEX idx_person_local_instance ON person (local DESC, instance_id); + diff --git a/src/lib.rs b/src/lib.rs index e1c6d1fae..9ce1bfa00 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,14 +28,14 @@ use lemmy_api_common::{ context::LemmyContext, lemmy_db_views::structs::SiteView, request::build_user_agent, - send_activity::MATCH_OUTGOING_ACTIVITIES, + send_activity::{ActivityChannel, MATCH_OUTGOING_ACTIVITIES}, utils::{ check_private_instance_and_federation_enabled, local_site_rate_limit_to_rate_limit_config, }, }; use lemmy_apub::{ - activities::match_outgoing_activities, + activities::{handle_outgoing_activities, match_outgoing_activities}, VerifyUrlData, FEDERATION_HTTP_FETCH_LIMIT, }; @@ -203,6 +203,8 @@ pub async fn start_lemmy_server(args: CmdArgs) -> Result<(), LemmyError> { Box::pin(match_outgoing_activities(d, c)) })) .expect("set function pointer"); + let request_data = federation_config.to_request_data(); + let outgoing_activities_task = tokio::task::spawn(handle_outgoing_activities(request_data)); let server = if args.http_server { Some(create_http_server( @@ -245,6 +247,9 @@ pub async fn start_lemmy_server(args: CmdArgs) -> Result<(), LemmyError> { federate.cancel().await?; } + // Wait for outgoing apub sends to complete + ActivityChannel::close(outgoing_activities_task).await?; + Ok(()) } diff --git a/src/session_middleware.rs b/src/session_middleware.rs index 5824f33df..c48f6f1c7 100644 --- a/src/session_middleware.rs +++ b/src/session_middleware.rs @@ -6,10 +6,19 @@ use actix_web::{ Error, HttpMessage, }; +use chrono::{DateTime, Utc}; use core::future::Ready; use futures_util::future::LocalBoxFuture; -use lemmy_api_common::{context::LemmyContext, utils::local_user_view_from_jwt}; -use lemmy_utils::error::{LemmyError, LemmyErrorType}; +use lemmy_api_common::{ + context::LemmyContext, + lemmy_db_views::structs::LocalUserView, + utils::check_user_valid, +}; +use lemmy_db_schema::newtypes::LocalUserId; +use lemmy_utils::{ + claims::Claims, + error::{LemmyError, LemmyErrorExt2, LemmyErrorType}, +}; use reqwest::header::HeaderValue; use std::{future::ready, rc::Rc}; @@ -118,3 +127,108 @@ where }) } } + +#[tracing::instrument(skip_all)] +async fn local_user_view_from_jwt( + jwt: &str, + context: &LemmyContext, +) -> Result { + let claims = Claims::decode(jwt, &context.secret().jwt_secret) + .with_lemmy_type(LemmyErrorType::NotLoggedIn)? + .claims; + let local_user_id = LocalUserId(claims.sub); + let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id).await?; + check_user_valid( + local_user_view.person.banned, + local_user_view.person.ban_expires, + local_user_view.person.deleted, + )?; + + check_validator_time(&local_user_view.local_user.validator_time, &claims)?; + + Ok(local_user_view) +} + +/// Checks if user's token was issued before user's password reset. +fn check_validator_time(validator_time: &DateTime, claims: &Claims) -> Result<(), LemmyError> { + let user_validation_time = validator_time.timestamp(); + if user_validation_time > claims.iat { + Err(LemmyErrorType::NotLoggedIn)? + } else { + Ok(()) + } +} + +#[cfg(test)] +mod tests { + #![allow(clippy::unwrap_used)] + #![allow(clippy::indexing_slicing)] + + use super::*; + use lemmy_db_schema::{ + source::{ + instance::Instance, + local_user::{LocalUser, LocalUserInsertForm}, + person::{Person, PersonInsertForm}, + secret::Secret, + }, + traits::Crud, + utils::build_db_pool_for_tests, + }; + use lemmy_utils::{claims::Claims, settings::SETTINGS}; + use serial_test::serial; + use std::env; + + #[tokio::test] + #[serial] + async fn test_session_auth() { + let pool = &build_db_pool_for_tests().await; + let pool = &mut pool.into(); + let secret = Secret::init(pool).await.unwrap(); + + // test.sh sets `LEMMY_CONFIG_LOCATION=../../config/config.hjson` for code under crates folder. + // this results in a config not found error, so we need to unset this var and use default. + env::remove_var("LEMMY_CONFIG_LOCATION"); + let settings = &SETTINGS.to_owned(); + + let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()) + .await + .unwrap(); + + let new_person = PersonInsertForm::builder() + .name("Gerry9812".into()) + .public_key("pubkey".to_string()) + .instance_id(inserted_instance.id) + .build(); + + let inserted_person = Person::create(pool, &new_person).await.unwrap(); + + let local_user_form = LocalUserInsertForm::builder() + .person_id(inserted_person.id) + .password_encrypted("123456".to_string()) + .build(); + + let inserted_local_user = LocalUser::create(pool, &local_user_form).await.unwrap(); + + let jwt = Claims::jwt( + inserted_local_user.id.0, + &secret.jwt_secret, + &settings.hostname, + ) + .unwrap(); + let claims = Claims::decode(&jwt, &secret.jwt_secret).unwrap().claims; + let check = check_validator_time(&inserted_local_user.validator_time, &claims); + assert!(check.is_ok()); + + // The check should fail, since the validator time is now newer than the jwt issue time + let updated_local_user = + LocalUser::update_password(pool, inserted_local_user.id, "password111") + .await + .unwrap(); + let check_after = check_validator_time(&updated_local_user.validator_time, &claims); + assert!(check_after.is_err()); + + let num_deleted = Person::delete(pool, inserted_person.id).await.unwrap(); + assert_eq!(1, num_deleted); + } +}